Merge tag 'nfc-next-4.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo...
authorDavid S. Miller <davem@davemloft.net>
Mon, 14 Mar 2016 02:43:01 +0000 (22:43 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 14 Mar 2016 02:43:01 +0000 (22:43 -0400)
Samuel Ortiz says:

====================
NFC 4.6 pull request

This is a very small one this time, with only 5 patches.
There are a couple of big items that could not be merged/finished
on time.

We have:

- 2 LLCP fixes for a race and a potential OOM.
- 2 cleanups for the pn544 and microread drivers.
- 1 Maintainer addition for the s3fwrn5 driver.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
2196 files changed:
Documentation/ABI/obsolete/sysfs-class-rfkill [deleted file]
Documentation/ABI/removed/sysfs-class-rfkill [new file with mode: 0644]
Documentation/ABI/stable/sysfs-class-rfkill
Documentation/ABI/testing/sysfs-class-net-batman-adv
Documentation/DocBook/media/v4l/media-types.xml
Documentation/cgroup-v2.txt
Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
Documentation/devicetree/bindings/net/can/ifi_canfd.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/rcar_can.txt
Documentation/devicetree/bindings/net/can/sja1000.txt
Documentation/devicetree/bindings/net/fsl-fec.txt
Documentation/devicetree/bindings/net/macb.txt
Documentation/devicetree/bindings/net/mediatek-net.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/renesas,ravb.txt
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt
Documentation/devicetree/bindings/pci/rcar-pci.txt
Documentation/devicetree/bindings/regulator/tps65217.txt
Documentation/devicetree/bindings/rtc/s3c-rtc.txt
Documentation/devicetree/bindings/serial/fsl-imx-uart.txt
Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
Documentation/devicetree/bindings/thermal/rcar-thermal.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/filesystems/efivarfs.txt
Documentation/filesystems/proc.txt
Documentation/kernel-parameters.txt
Documentation/networking/dsa/dsa.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/kcm.txt [new file with mode: 0644]
Documentation/networking/mac80211-injection.txt
Documentation/networking/netlink_mmap.txt [deleted file]
Documentation/networking/rds.txt
Documentation/rfkill.txt
Documentation/timers/hpet.txt
Documentation/watchdog/watchdog-parameters.txt
MAINTAINERS
Makefile
arch/alpha/include/uapi/asm/socket.h
arch/arc/Kconfig
arch/arc/Makefile
arch/arc/configs/axs101_defconfig
arch/arc/configs/axs103_defconfig
arch/arc/configs/axs103_smp_defconfig
arch/arc/configs/nsim_700_defconfig
arch/arc/configs/nsim_hs_defconfig
arch/arc/configs/nsim_hs_smp_defconfig
arch/arc/configs/nsimosci_defconfig
arch/arc/configs/nsimosci_hs_defconfig
arch/arc/configs/nsimosci_hs_smp_defconfig
arch/arc/configs/tb10x_defconfig
arch/arc/configs/vdk_hs38_smp_defconfig
arch/arc/include/asm/arcregs.h
arch/arc/include/asm/irq.h
arch/arc/include/asm/irqflags-arcv2.h
arch/arc/include/asm/mcip.h
arch/arc/include/asm/pgtable.h
arch/arc/kernel/entry-arcv2.S
arch/arc/kernel/intc-arcv2.c
arch/arc/kernel/intc-compact.c
arch/arc/kernel/mcip.c
arch/arc/kernel/setup.c
arch/arc/kernel/smp.c
arch/arc/kernel/time.c
arch/arm/boot/compressed/Makefile
arch/arm/boot/dts/am335x-bone-common.dtsi
arch/arm/boot/dts/am335x-chilisom.dtsi
arch/arm/boot/dts/am335x-nano.dts
arch/arm/boot/dts/am335x-pepper.dts
arch/arm/boot/dts/am335x-shc.dts
arch/arm/boot/dts/am335x-sl50.dts
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am437x-gp-evm.dts
arch/arm/boot/dts/am43x-epos-evm.dts
arch/arm/boot/dts/am57xx-beagle-x15.dts
arch/arm/boot/dts/am57xx-cl-som-am57x.dts
arch/arm/boot/dts/am57xx-sbc-am57x.dts
arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
arch/arm/boot/dts/at91-sama5d2_xplained.dts
arch/arm/boot/dts/at91-sama5d4_xplained.dts
arch/arm/boot/dts/at91-sama5d4ek.dts
arch/arm/boot/dts/at91sam9n12ek.dts
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/kirkwood-ds112.dts
arch/arm/boot/dts/kirkwood-lswvl.dts
arch/arm/boot/dts/kirkwood-lswxl.dts
arch/arm/boot/dts/kirkwood-pogoplug-series-4.dts
arch/arm/boot/dts/logicpd-torpedo-som.dtsi
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/omap5-board-common.dtsi
arch/arm/boot/dts/orion5x-linkstation-lswtgl.dts
arch/arm/boot/dts/r8a7791-porter.dts
arch/arm/boot/dts/sama5d2-pinfunc.h
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
arch/arm/boot/dts/tps65217.dtsi [new file with mode: 0644]
arch/arm/common/icst.c
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/crypto/aes-ce-glue.c
arch/arm/include/asm/arch_gicv3.h
arch/arm/include/asm/xen/page-coherent.h
arch/arm/kernel/Makefile
arch/arm/kvm/guest.c
arch/arm/kvm/mmio.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc-onenand.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/sleep34xx.S
arch/arm/mach-omap2/sleep44xx.S
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/platsmp-dt.c
arch/arm/mach-shmobile/common.h
arch/arm/mach-shmobile/headsmp-scu.S
arch/arm/mach-shmobile/headsmp.S
arch/arm/mach-shmobile/platsmp-apmu.c
arch/arm/mach-shmobile/platsmp-scu.c
arch/arm/mach-shmobile/smp-r8a7779.c
arch/arm/mach-tango/Kconfig
arch/arm/mach-tango/platsmp.c
arch/arm/mach-tegra/board-paz00.c
arch/arm/mm/mmap.c
arch/arm/mm/pageattr.c
arch/arm64/Makefile
arch/arm64/boot/Makefile
arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
arch/arm64/boot/dts/apm/apm-storm.dtsi
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/nvidia/tegra132-norrin.dts
arch/arm64/boot/install.sh
arch/arm64/crypto/aes-glue.c
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/futex.h
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/page.h
arch/arm64/include/asm/pgtable.h
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/image.h
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/traps.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/hyp-init.S
arch/arm64/kvm/hyp/switch.c
arch/arm64/kvm/hyp/vgic-v3-sr.c
arch/arm64/kvm/inject_fault.c
arch/arm64/kvm/sys_regs.c
arch/arm64/lib/strnlen.S
arch/arm64/mm/dma-mapping.c
arch/arm64/mm/fault.c
arch/arm64/mm/init.c
arch/arm64/mm/mmap.c
arch/arm64/mm/pageattr.c
arch/avr32/include/uapi/asm/socket.h
arch/frv/include/uapi/asm/socket.h
arch/ia64/include/uapi/asm/socket.h
arch/m32r/Kconfig
arch/m32r/include/uapi/asm/socket.h
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/syscalltable.S
arch/mips/Kconfig
arch/mips/boot/dts/brcm/bcm6328.dtsi
arch/mips/boot/dts/brcm/bcm7125.dtsi
arch/mips/boot/dts/brcm/bcm7346.dtsi
arch/mips/boot/dts/brcm/bcm7358.dtsi
arch/mips/boot/dts/brcm/bcm7360.dtsi
arch/mips/boot/dts/brcm/bcm7362.dtsi
arch/mips/boot/dts/brcm/bcm7420.dtsi
arch/mips/boot/dts/brcm/bcm7425.dtsi
arch/mips/boot/dts/brcm/bcm7435.dtsi
arch/mips/include/asm/elf.h
arch/mips/include/asm/fpu.h
arch/mips/include/asm/octeon/octeon-feature.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/stackframe.h
arch/mips/include/asm/syscall.h
arch/mips/include/uapi/asm/socket.h
arch/mips/include/uapi/asm/unistd.h
arch/mips/jz4740/gpio.c
arch/mips/kernel/binfmt_elfn32.c
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/process.c
arch/mips/kernel/r2300_fpu.S
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/traps.c
arch/mips/kvm/mips.c
arch/mips/mm/mmap.c
arch/mips/mm/sc-mips.c
arch/mips/mti-malta/malta-init.c
arch/mips/pci/pci-mt7620.c
arch/mips/txx9/generic/setup_tx4939.c
arch/mn10300/include/uapi/asm/socket.h
arch/parisc/include/asm/floppy.h
arch/parisc/include/uapi/asm/socket.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/syscall_table.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/book3s/64/pgtable.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/trace.h
arch/powerpc/include/uapi/asm/socket.h
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/process.c
arch/powerpc/mm/hash64_64k.c
arch/powerpc/mm/hugepage-hash64.c
arch/powerpc/mm/hugetlbpage-book3e.c
arch/powerpc/mm/mmap.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/s390/include/asm/fpu/internal.h
arch/s390/include/asm/livepatch.h
arch/s390/include/uapi/asm/socket.h
arch/s390/kernel/compat_signal.c
arch/s390/kernel/perf_event.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/trace.c
arch/s390/mm/maccess.c
arch/s390/oprofile/backtrace.c
arch/sparc/Makefile
arch/sparc/include/uapi/asm/socket.h
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/entry.S
arch/sparc/kernel/hvcalls.S
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/sparc_ksyms_64.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/syscalls.S
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/um/include/asm/page.h
arch/um/kernel/reboot.c
arch/um/kernel/signal.c
arch/x86/Kconfig
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64_compat.S
arch/x86/include/asm/livepatch.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/stacktrace.h
arch/x86/include/asm/uaccess_32.h
arch/x86/include/asm/xen/pci.h
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd_uncore.c
arch/x86/kernel/dumpstack.c
arch/x86/kernel/stacktrace.c
arch/x86/kvm/emulate.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/copy_user_64.S
arch/x86/mm/fault.c
arch/x86/mm/gup.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/mmap.c
arch/x86/mm/mpx.c
arch/x86/mm/numa.c
arch/x86/mm/pageattr.c
arch/x86/oprofile/backtrace.c
arch/x86/pci/common.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/pci/xen.c
arch/x86/platform/intel-quark/imr.c
arch/x86/um/os-Linux/task_size.c
arch/xtensa/include/uapi/asm/socket.h
block/Kconfig
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-map.c
block/blk-merge.c
block/blk-mq.c
block/blk-settings.c
block/blk-sysfs.c
block/deadline-iosched.c
crypto/algif_skcipher.c
crypto/crypto_user.c
drivers/acpi/acpi_lpss.c
drivers/acpi/nfit.c
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/android/binder.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_brcmstb.c
drivers/ata/ahci_xgene.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/pata_rb532_cf.c
drivers/base/component.c
drivers/base/power/common.c
drivers/base/power/domain.c
drivers/base/regmap/regmap-mmio.c
drivers/bcma/Kconfig
drivers/bcma/Makefile
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_chipcommon_pflash.c [new file with mode: 0644]
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/driver_chipcommon_sflash.c
drivers/bcma/driver_gpio.c
drivers/bcma/driver_mips.c
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/bcma/scan.c
drivers/block/floppy.c
drivers/block/null_blk.c
drivers/block/xen-blkfront.c
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/ath3k.c
drivers/bluetooth/btbcm.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_ag6xx.c [new file with mode: 0644]
drivers/bluetooth/hci_bcm.c
drivers/bluetooth/hci_intel.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_uart.h
drivers/bus/Kconfig
drivers/bus/vexpress-config.c
drivers/char/hpet.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/random.c
drivers/clk/Makefile
drivers/clk/clk-gpio.c
drivers/clk/clk-scpi.c
drivers/clk/mvebu/dove-divider.c
drivers/clk/qcom/gcc-apq8084.c
drivers/clk/qcom/gcc-ipq806x.c
drivers/clk/qcom/gcc-msm8660.c
drivers/clk/qcom/gcc-msm8916.c
drivers/clk/qcom/gcc-msm8960.c
drivers/clk/qcom/gcc-msm8974.c
drivers/clk/qcom/lcc-ipq806x.c
drivers/clk/qcom/lcc-msm8960.c
drivers/clk/qcom/mmcc-apq8084.c
drivers/clk/qcom/mmcc-msm8960.c
drivers/clk/qcom/mmcc-msm8974.c
drivers/clk/rockchip/clk-rk3036.c
drivers/clk/rockchip/clk-rk3368.c
drivers/clk/tegra/clk-emc.c
drivers/clk/tegra/clk-id.h
drivers/clk/tegra/clk-pll.c
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra210.c
drivers/clk/ti/dpll3xxx.c
drivers/clk/versatile/clk-icst.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/mt8173-cpufreq.c
drivers/crypto/atmel-sha.c
drivers/crypto/marvell/cesa.c
drivers/devfreq/tegra-devfreq.c
drivers/dma/dw/core.c
drivers/dma/dw/pci.c
drivers/dma/edma.c
drivers/dma/ioat/dma.c
drivers/dma/pxa_dma.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/vars.c
drivers/gpio/gpio-altera.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-rcar.c
drivers/gpu/drm/amd/amdgpu/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c
drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/ci_dpm.c
drivers/gpu/drm/amd/amdgpu/cik.c
drivers/gpu/drm/amd/amdgpu/cik_sdma.c
drivers/gpu/drm/amd/amdgpu/cz_dpm.c
drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
drivers/gpu/drm/amd/amdgpu/iceland_smc.c
drivers/gpu/drm/amd/amdgpu/kv_dpm.c
drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c
drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/amdgpu/vce_v2_0.c
drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/gpu/drm/amd/include/cgs_common.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/eventmgr/eventactionchains.c
drivers/gpu/drm/amd/powerplay/eventmgr/eventmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c
drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/tonga_hwmgr.c
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos_dp_core.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_mic.c
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i2c/adv7511.c
drivers/gpu/drm/i2c/adv7511.h
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_userptr.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_csr.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_link_training.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c
drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_prime.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_sa.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/vc4/vc4_bo.c
drivers/gpu/drm/vc4/vc4_drv.h
drivers/gpu/drm/vc4/vc4_gem.c
drivers/gpu/drm/vc4/vc4_irq.c
drivers/gpu/drm/vc4/vc4_render_cl.c
drivers/gpu/drm/vc4/vc4_v3d.c
drivers/gpu/drm/vc4/vc4_validate.c
drivers/gpu/drm/vmwgfx/device_include/svga3d_surfacedefs.h
drivers/gpu/host1x/bus.c
drivers/gpu/host1x/dev.c
drivers/gpu/host1x/dev.h
drivers/hwmon/ads1015.c
drivers/hwmon/gpio-fan.c
drivers/hwspinlock/hwspinlock_core.c
drivers/i2c/busses/i2c-brcmstb.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-uniphier-f.c
drivers/i2c/busses/i2c-uniphier.c
drivers/iio/accel/Kconfig
drivers/iio/adc/Kconfig
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/dac/mcp4725.c
drivers/iio/humidity/dht11.c
drivers/iio/imu/inv_mpu6050/Kconfig
drivers/iio/inkern.c
drivers/iio/light/acpi-als.c
drivers/iio/light/ltr501.c
drivers/iio/pressure/mpl115.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/infiniband/core/device.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ud_header.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/hw/mlx4/Kconfig
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mlx5/srq.c
drivers/infiniband/hw/nes/Kconfig
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_hw.h
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/hw/ocrdma/ocrdma.h
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_stats.c
drivers/infiniband/hw/ocrdma/ocrdma_stats.h
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/usnic/usnic_ib_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/cap11xx.c
drivers/input/misc/Kconfig
drivers/input/misc/sirfsoc-onkey.c
drivers/input/mouse/vmmouse.c
drivers/input/serio/serio.c
drivers/input/touchscreen/colibri-vf50-ts.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel-svm.c
drivers/iommu/intel_irq_remapping.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-sun4i.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hardware/eicon/debug.c
drivers/isdn/hardware/eicon/divamnt.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/lightnvm/core.c
drivers/lightnvm/rrpc.c
drivers/lightnvm/rrpc.h
drivers/mailbox/Kconfig
drivers/mailbox/pcc.c
drivers/md/bitmap.c
drivers/md/dm.c
drivers/md/faulty.c
drivers/md/md-cluster.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/dvb-frontends/tda1004x.c
drivers/media/i2c/adp1653.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/ir-kbd-i2c.c
drivers/media/i2c/s5k6a3.c
drivers/media/pci/saa7134/saa7134-alsa.c
drivers/media/platform/Kconfig
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/media-dev.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/usb/au0828/au0828-video.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-v4l2.c
drivers/mfd/db8500-prcmu.c
drivers/misc/cxl/pci.c
drivers/misc/mei/main.c
drivers/mmc/card/block.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mtd/ubi/upd.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/ifi_canfd/Kconfig [new file with mode: 0644]
drivers/net/can/ifi_canfd/Makefile [new file with mode: 0644]
drivers/net/can/ifi_canfd/ifi_canfd.c [new file with mode: 0644]
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/sja1000_platform.c
drivers/net/can/spi/mcp251x.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/gs_usb.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/bcm_sf2.h
drivers/net/dsa/mv88e6171.c
drivers/net/dsa/mv88e6352.c
drivers/net/dsa/mv88e6xxx.c
drivers/net/dsa/mv88e6xxx.h
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/8390/pcnet_cs.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/agere/et131x.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/am79c961a.c
drivers/net/ethernet/amd/lance.c
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/apm/xgene/Makefile
drivers/net/ethernet/apm/xgene/xgene_enet_cle.c [new file with mode: 0644]
drivers/net/ethernet/apm/xgene/xgene_enet_cle.h [new file with mode: 0644]
drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/apm/xgene/xgene_enet_main.h
drivers/net/ethernet/apm/xgene/xgene_enet_ring2.c
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/aurora/nb8800.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_nvm_defs.h
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bna_tx_rx.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cavium/liquidio/lio_main.c
drivers/net/ethernet/cavium/liquidio/octeon_droq.c
drivers/net/ethernet/cavium/thunder/nic.h
drivers/net/ethernet/cavium/thunder/nic_main.c
drivers/net/ethernet/cavium/thunder/nic_reg.h
drivers/net/ethernet/cavium/thunder/nicvf_main.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.h
drivers/net/ethernet/chelsio/cxgb3/t3_hw.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_pci_id_tbl.h
drivers/net/ethernet/chelsio/cxgb4/t4_values.h
drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/vnic_cq.c
drivers/net/ethernet/cisco/enic/vnic_dev.c
drivers/net/ethernet/cisco/enic/vnic_intr.c
drivers/net/ethernet/cisco/enic/vnic_rq.c
drivers/net/ethernet/cisco/enic/vnic_wq.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/tulip/tulip_core.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_main.c
drivers/net/ethernet/ethoc.c
drivers/net/ethernet/ezchip/nps_enet.c
drivers/net/ethernet/ezchip/nps_enet.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fman/fman.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar_ptp.c
drivers/net/ethernet/fujitsu/fmvj18x_cs.c
drivers/net/ethernet/hisilicon/Kconfig
drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h
drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
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/netdev.c
drivers/net/ethernet/intel/fm10k/fm10k_main.c
drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_dcb.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_devids.h
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_fcoe.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_register.h
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/i40evf/i40e_adminq.c
drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
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_txrx.h
drivers/net/ethernet/intel/i40evf/i40evf.h
drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/e1000_defines.h
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/igb/e1000_mac.h
drivers/net/ethernet/intel/igb/e1000_mbx.c
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/igb/igb_ptp.c
drivers/net/ethernet/intel/igbvf/mbx.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/igbvf/vf.h
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_model.h [new file with mode: 0644]
drivers/net/ethernet/jme.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mediatek/Kconfig [new file with mode: 0644]
drivers/net/ethernet/mediatek/Makefile [new file with mode: 0644]
drivers/net/ethernet/mediatek/mtk_eth_soc.c [new file with mode: 0644]
drivers/net/ethernet/mediatek/mtk_eth_soc.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx4/Kconfig
drivers/net/ethernet/mellanox/mlx4/catas.c
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/cq.c
drivers/net/ethernet/mellanox/mlx4/en_clock.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_port.c
drivers/net/ethernet/mellanox/mlx4/en_resources.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/intf.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/pd.c
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_clock.c
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/port.c
drivers/net/ethernet/mellanox/mlx5/core/uar.c
drivers/net/ethernet/mellanox/mlx5/core/vxlan.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/vxlan.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlxsw/Kconfig
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/pci.h
drivers/net/ethernet/mellanox/mlxsw/port.h
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/mellanox/mlxsw/switchx2.c
drivers/net/ethernet/moxa/moxart_ether.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/pasemi/Kconfig
drivers/net/ethernet/pasemi/pasemi_mac.c
drivers/net/ethernet/pasemi/pasemi_mac.h
drivers/net/ethernet/pasemi/pasemi_mac_ethtool.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qed/qed.h
drivers/net/ethernet/qlogic/qed/qed_cxt.c
drivers/net/ethernet/qlogic/qed/qed_dev.c
drivers/net/ethernet/qlogic/qed/qed_dev_api.h
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_hw.c
drivers/net/ethernet/qlogic/qed/qed_init_fw_funcs.c
drivers/net/ethernet/qlogic/qed/qed_init_ops.c
drivers/net/ethernet/qlogic/qed/qed_int.c
drivers/net/ethernet/qlogic/qed/qed_int.h
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h
drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
drivers/net/ethernet/qlogic/qed/qed_sp.h
drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
drivers/net/ethernet/qlogic/qed/qed_spq.c
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qualcomm/qca_spi.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/Kconfig
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/rocker/Makefile
drivers/net/ethernet/rocker/rocker.c [deleted file]
drivers/net/ethernet/rocker/rocker.h
drivers/net/ethernet/rocker/rocker_hw.h [new file with mode: 0644]
drivers/net/ethernet/rocker/rocker_main.c [new file with mode: 0644]
drivers/net/ethernet/rocker/rocker_ofdpa.c [new file with mode: 0644]
drivers/net/ethernet/rocker/rocker_tlv.c [new file with mode: 0644]
drivers/net/ethernet/rocker/rocker_tlv.h [new file with mode: 0644]
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/descs.h
drivers/net/ethernet/stmicro/stmmac/descs_com.h
drivers/net/ethernet/stmicro/stmmac/dwmac100.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
drivers/net/ethernet/stmicro/stmmac/enh_desc.c
drivers/net/ethernet/stmicro/stmmac/norm_desc.c
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/synopsys/dwc_eth_qos.c
drivers/net/ethernet/ti/cpsw-phy-sel.c
drivers/net/ethernet/ti/netcp_core.c
drivers/net/geneve.c
drivers/net/hamradio/dmascc.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macsec.c [new file with mode: 0644]
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/phy/at803x.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/dp83848.c
drivers/net/phy/marvell.c
drivers/net/phy/micrel.c
drivers/net/phy/phy_device.c
drivers/net/phy/spi_ks8995.c
drivers/net/ppp/ppp_generic.c
drivers/net/ppp/pppoe.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/ax88172a.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/lan78xx.c
drivers/net/usb/lan78xx.h
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/vmxnet3/vmxnet3_defs.h
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vrf.c
drivers/net/vxlan.c
drivers/net/wan/dscc4.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wireless/ath/ath10k/Kconfig
drivers/net/wireless/ath/ath10k/Makefile
drivers/net/wireless/ath/ath10k/ahb.c [new file with mode: 0644]
drivers/net/wireless/ath/ath10k/ahb.h [new file with mode: 0644]
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/debugfs_sta.c
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.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/pci.h
drivers/net/wireless/ath/ath10k/targaddrs.h
drivers/net/wireless/ath/ath10k/trace.h
drivers/net/wireless/ath/ath10k/wmi-ops.h
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ar9003_aic.c
drivers/net/wireless/ath/ath9k/ar9003_aic.h
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar953x_initvals.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/channel.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_main.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/reg.h
drivers/net/wireless/ath/carl9170/fwcmd.h
drivers/net/wireless/ath/carl9170/fwdesc.h
drivers/net/wireless/ath/carl9170/hw.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/version.h
drivers/net/wireless/ath/wcn36xx/main.c
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/netdev.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/atmel/at76c50x-usb.c
drivers/net/wireless/broadcom/b43/main.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h
drivers/net/wireless/intel/iwlegacy/4965-mac.c
drivers/net/wireless/intel/iwlegacy/4965.h
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/dvm/led.c
drivers/net/wireless/intel/iwlwifi/dvm/lib.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/iwl-7000.c
drivers/net/wireless/intel/iwlwifi/iwl-8000.c
drivers/net/wireless/intel/iwlwifi/iwl-9000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-csr.h
drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-fh.h
drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/intel/iwlwifi/iwl-prph.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/constants.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/quota.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rx.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/intersil/hostap/hostap_hw.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/marvell/libertas/cfg.c
drivers/net/wireless/marvell/libertas/cmd.c
drivers/net/wireless/marvell/libertas/cmdresp.c
drivers/net/wireless/marvell/libertas/dev.h
drivers/net/wireless/marvell/libertas/if_sdio.c
drivers/net/wireless/marvell/libertas/if_usb.c
drivers/net/wireless/marvell/libertas/main.c
drivers/net/wireless/marvell/mwifiex/11h.c
drivers/net/wireless/marvell/mwifiex/README
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/marvell/mwifiex/cmdevt.c
drivers/net/wireless/marvell/mwifiex/debugfs.c
drivers/net/wireless/marvell/mwifiex/decl.h
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/init.c
drivers/net/wireless/marvell/mwifiex/ioctl.h
drivers/net/wireless/marvell/mwifiex/join.c
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/pcie.c
drivers/net/wireless/marvell/mwifiex/pcie.h
drivers/net/wireless/marvell/mwifiex/scan.c
drivers/net/wireless/marvell/mwifiex/sdio.c
drivers/net/wireless/marvell/mwifiex/sta_cmd.c
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_event.c
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
drivers/net/wireless/marvell/mwifiex/tdls.c
drivers/net/wireless/marvell/mwifiex/uap_cmd.c
drivers/net/wireless/marvell/mwifiex/usb.c
drivers/net/wireless/marvell/mwifiex/util.c
drivers/net/wireless/marvell/mwifiex/wmm.c
drivers/net/wireless/marvell/mwl8k.c
drivers/net/wireless/mediatek/mt7601u/main.c
drivers/net/wireless/mediatek/mt7601u/mcu.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.h
drivers/net/wireless/ralink/rt2x00/rt2800usb.c
drivers/net/wireless/ralink/rt2x00/rt2x00.h
drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
drivers/net/wireless/ralink/rt2x00/rt61pci.h
drivers/net/wireless/realtek/rtl8xxxu/Kconfig
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
drivers/net/wireless/realtek/rtlwifi/core.c
drivers/net/wireless/realtek/rtlwifi/pci.c
drivers/net/wireless/realtek/rtlwifi/rc.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h
drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.h
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.h
drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/trx.h
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.c
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/trx.h
drivers/net/wireless/realtek/rtlwifi/wifi.h
drivers/net/wireless/rsi/rsi_91x_mac80211.c
drivers/net/wireless/st/cw1200/cw1200_spi.c
drivers/net/wireless/st/cw1200/pm.h
drivers/net/wireless/st/cw1200/sta.c
drivers/net/wireless/st/cw1200/sta.h
drivers/net/wireless/ti/wlcore/Kconfig
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/io.c
drivers/net/wireless/ti/wlcore/io.h
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/xenbus.c
drivers/nvdimm/bus.c
drivers/nvdimm/pmem.c
drivers/nvme/host/Kconfig
drivers/nvme/host/core.c
drivers/nvme/host/lightnvm.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvmem/core.c
drivers/nvmem/qfprom.c
drivers/of/irq.c
drivers/of/of_mdio.c
drivers/pci/host/Kconfig
drivers/pci/host/pci-keystone-dw.c
drivers/pci/host/pci-layerscape.c
drivers/pci/host/pcie-iproc.c
drivers/pci/pcie/aer/aerdrv.c
drivers/pci/pcie/aer/aerdrv.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/xen-pcifront.c
drivers/phy/Kconfig
drivers/phy/phy-core.c
drivers/phy/phy-twl4030-usb.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/pxa/pinctrl-pxa2xx.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
drivers/platform/x86/intel-hid.c
drivers/platform/x86/intel_scu_ipcutil.c
drivers/pnp/quirks.c
drivers/power/bq27xxx_battery_i2c.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_alias.c
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/scsi/device_handler/scsi_dh_rdac.c
drivers/scsi/fcoe/fcoe_transport.c
drivers/scsi/hisi_sas/Kconfig
drivers/scsi/hisi_sas/hisi_sas_v1_hw.c
drivers/scsi/ipr.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/qla_tmpl.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/scsi/storvsc_drv.c
drivers/sh/pm_runtime.c
drivers/spi/spi-atmel.c
drivers/spi/spi-bcm2835aux.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-imx.c
drivers/spi/spi-loopback-test.c
drivers/spi/spi-omap2-mcspi.c
drivers/ssb/Kconfig
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/meter/ade7753.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/rdma/Kconfig
drivers/staging/rdma/Makefile
drivers/staging/rdma/amso1100/Kbuild [deleted file]
drivers/staging/rdma/amso1100/Kconfig [deleted file]
drivers/staging/rdma/amso1100/TODO [deleted file]
drivers/staging/rdma/amso1100/c2.c [deleted file]
drivers/staging/rdma/amso1100/c2.h [deleted file]
drivers/staging/rdma/amso1100/c2_ae.c [deleted file]
drivers/staging/rdma/amso1100/c2_ae.h [deleted file]
drivers/staging/rdma/amso1100/c2_alloc.c [deleted file]
drivers/staging/rdma/amso1100/c2_cm.c [deleted file]
drivers/staging/rdma/amso1100/c2_cq.c [deleted file]
drivers/staging/rdma/amso1100/c2_intr.c [deleted file]
drivers/staging/rdma/amso1100/c2_mm.c [deleted file]
drivers/staging/rdma/amso1100/c2_mq.c [deleted file]
drivers/staging/rdma/amso1100/c2_mq.h [deleted file]
drivers/staging/rdma/amso1100/c2_pd.c [deleted file]
drivers/staging/rdma/amso1100/c2_provider.c [deleted file]
drivers/staging/rdma/amso1100/c2_provider.h [deleted file]
drivers/staging/rdma/amso1100/c2_qp.c [deleted file]
drivers/staging/rdma/amso1100/c2_rnic.c [deleted file]
drivers/staging/rdma/amso1100/c2_status.h [deleted file]
drivers/staging/rdma/amso1100/c2_user.h [deleted file]
drivers/staging/rdma/amso1100/c2_vq.c [deleted file]
drivers/staging/rdma/amso1100/c2_vq.h [deleted file]
drivers/staging/rdma/amso1100/c2_wr.h [deleted file]
drivers/staging/rdma/ehca/Kconfig [deleted file]
drivers/staging/rdma/ehca/Makefile [deleted file]
drivers/staging/rdma/ehca/TODO [deleted file]
drivers/staging/rdma/ehca/ehca_av.c [deleted file]
drivers/staging/rdma/ehca/ehca_classes.h [deleted file]
drivers/staging/rdma/ehca/ehca_classes_pSeries.h [deleted file]
drivers/staging/rdma/ehca/ehca_cq.c [deleted file]
drivers/staging/rdma/ehca/ehca_eq.c [deleted file]
drivers/staging/rdma/ehca/ehca_hca.c [deleted file]
drivers/staging/rdma/ehca/ehca_irq.c [deleted file]
drivers/staging/rdma/ehca/ehca_irq.h [deleted file]
drivers/staging/rdma/ehca/ehca_iverbs.h [deleted file]
drivers/staging/rdma/ehca/ehca_main.c [deleted file]
drivers/staging/rdma/ehca/ehca_mcast.c [deleted file]
drivers/staging/rdma/ehca/ehca_mrmw.c [deleted file]
drivers/staging/rdma/ehca/ehca_mrmw.h [deleted file]
drivers/staging/rdma/ehca/ehca_pd.c [deleted file]
drivers/staging/rdma/ehca/ehca_qes.h [deleted file]
drivers/staging/rdma/ehca/ehca_qp.c [deleted file]
drivers/staging/rdma/ehca/ehca_reqs.c [deleted file]
drivers/staging/rdma/ehca/ehca_sqp.c [deleted file]
drivers/staging/rdma/ehca/ehca_tools.h [deleted file]
drivers/staging/rdma/ehca/ehca_uverbs.c [deleted file]
drivers/staging/rdma/ehca/hcp_if.c [deleted file]
drivers/staging/rdma/ehca/hcp_if.h [deleted file]
drivers/staging/rdma/ehca/hcp_phyp.c [deleted file]
drivers/staging/rdma/ehca/hcp_phyp.h [deleted file]
drivers/staging/rdma/ehca/hipz_fns.h [deleted file]
drivers/staging/rdma/ehca/hipz_fns_core.h [deleted file]
drivers/staging/rdma/ehca/hipz_hw.h [deleted file]
drivers/staging/rdma/ehca/ipz_pt_fn.c [deleted file]
drivers/staging/rdma/ehca/ipz_pt_fn.h [deleted file]
drivers/staging/rdma/ipath/Kconfig [deleted file]
drivers/staging/rdma/ipath/Makefile [deleted file]
drivers/staging/rdma/ipath/TODO [deleted file]
drivers/staging/rdma/ipath/ipath_common.h [deleted file]
drivers/staging/rdma/ipath/ipath_cq.c [deleted file]
drivers/staging/rdma/ipath/ipath_debug.h [deleted file]
drivers/staging/rdma/ipath/ipath_diag.c [deleted file]
drivers/staging/rdma/ipath/ipath_dma.c [deleted file]
drivers/staging/rdma/ipath/ipath_driver.c [deleted file]
drivers/staging/rdma/ipath/ipath_eeprom.c [deleted file]
drivers/staging/rdma/ipath/ipath_file_ops.c [deleted file]
drivers/staging/rdma/ipath/ipath_fs.c [deleted file]
drivers/staging/rdma/ipath/ipath_iba6110.c [deleted file]
drivers/staging/rdma/ipath/ipath_init_chip.c [deleted file]
drivers/staging/rdma/ipath/ipath_intr.c [deleted file]
drivers/staging/rdma/ipath/ipath_kernel.h [deleted file]
drivers/staging/rdma/ipath/ipath_keys.c [deleted file]
drivers/staging/rdma/ipath/ipath_mad.c [deleted file]
drivers/staging/rdma/ipath/ipath_mmap.c [deleted file]
drivers/staging/rdma/ipath/ipath_mr.c [deleted file]
drivers/staging/rdma/ipath/ipath_qp.c [deleted file]
drivers/staging/rdma/ipath/ipath_rc.c [deleted file]
drivers/staging/rdma/ipath/ipath_registers.h [deleted file]
drivers/staging/rdma/ipath/ipath_ruc.c [deleted file]
drivers/staging/rdma/ipath/ipath_sdma.c [deleted file]
drivers/staging/rdma/ipath/ipath_srq.c [deleted file]
drivers/staging/rdma/ipath/ipath_stats.c [deleted file]
drivers/staging/rdma/ipath/ipath_sysfs.c [deleted file]
drivers/staging/rdma/ipath/ipath_uc.c [deleted file]
drivers/staging/rdma/ipath/ipath_ud.c [deleted file]
drivers/staging/rdma/ipath/ipath_user_pages.c [deleted file]
drivers/staging/rdma/ipath/ipath_user_sdma.c [deleted file]
drivers/staging/rdma/ipath/ipath_user_sdma.h [deleted file]
drivers/staging/rdma/ipath/ipath_verbs.c [deleted file]
drivers/staging/rdma/ipath/ipath_verbs.h [deleted file]
drivers/staging/rdma/ipath/ipath_verbs_mcast.c [deleted file]
drivers/staging/rdma/ipath/ipath_wc_ppc64.c [deleted file]
drivers/staging/rdma/ipath/ipath_wc_x86_64.c [deleted file]
drivers/staging/speakup/Kconfig
drivers/staging/vt6655/rxtx.c
drivers/staging/vt6656/rxtx.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_tmr.c
drivers/target/target_core_transport.c
drivers/target/target_core_user.c
drivers/thermal/Kconfig
drivers/thermal/cpu_cooling.c
drivers/thermal/of-thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/spear_thermal.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/omap-serial.c
drivers/tty/tty_io.c
drivers/tty/tty_mutex.c
drivers/usb/chipidea/ci_hdrc_pci.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/otg.c
drivers/usb/core/hub.c
drivers/usb/dwc2/Kconfig
drivers/usb/dwc2/core.c
drivers/usb/dwc2/hcd_ddma.c
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/gadget/udc/net2280.h
drivers/usb/gadget/udc/udc-core.c
drivers/usb/host/xhci-ext-caps.h
drivers/usb/host/xhci-mtk-sch.c
drivers/usb/host/xhci-mtk.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/musb_host.c
drivers/usb/musb/ux500.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/cp210x.c
drivers/usb/serial/mxu11x0.c [deleted file]
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/platform/vfio_platform_common.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/vhost.c
drivers/video/console/fbcon.c
drivers/video/fbdev/da8xx-fb.c
drivers/video/fbdev/exynos/s6e8ax0.c
drivers/video/fbdev/imxfb.c
drivers/video/fbdev/mmp/hw/mmp_ctrl.c
drivers/video/fbdev/ocfb.c
drivers/virtio/virtio_pci_modern.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/max63xx_wdt.c
drivers/watchdog/pcwd_usb.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/sun4v_wdt.c [new file with mode: 0644]
drivers/xen/xen-pciback/pciback_ops.c
drivers/xen/xen-scsiback.c
drivers/xen/xenbus/xenbus_dev_frontend.c
fs/affs/file.c
fs/binfmt_elf.c
fs/block_dev.c
fs/btrfs/backref.c
fs/btrfs/compression.c
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-inode.h
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/root-tree.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/super.h
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/smb2pdu.c
fs/dax.c
fs/dcache.c
fs/devpts/inode.c
fs/direct-io.c
fs/efivarfs/file.c
fs/efivarfs/inode.c
fs/efivarfs/internal.h
fs/efivarfs/super.c
fs/eventpoll.c
fs/ext2/file.c
fs/ext2/inode.c
fs/ext4/balloc.c
fs/ext4/crypto.c
fs/ext4/dir.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/mballoc.c
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/resize.c
fs/fs-writeback.c
fs/hpfs/namei.c
fs/inode.c
fs/jffs2/README.Locking
fs/jffs2/build.c
fs/jffs2/file.c
fs/jffs2/gc.c
fs/jffs2/nodelist.h
fs/namei.c
fs/nfs/blocklayout/extent_tree.c
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/flexfilelayout/flexfilelayoutdev.c
fs/nfs/nfs42proc.c
fs/nfs/nfs4proc.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/notify/mark.c
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/dlm/dlmrecovery.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/super.c
fs/pnode.c
fs/proc/task_mmu.c
fs/proc/task_nommu.c
fs/read_write.c
fs/super.c
fs/userfaultfd.c
fs/xattr.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_aops.h
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_log_recover.c
include/acpi/cppc_acpi.h
include/asm-generic/cputime_nsecs.h
include/asm-generic/pgtable.h
include/drm/drm_cache.h
include/drm/drm_crtc.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_fixed.h
include/dt-bindings/clock/tegra210-car.h
include/linux/ata.h
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bio.h
include/linux/bitmap.h
include/linux/blkdev.h
include/linux/bpf.h
include/linux/ceph/ceph_features.h
include/linux/cgroup-defs.h
include/linux/compiler.h
include/linux/cpuset.h
include/linux/crush/crush.h
include/linux/dax.h
include/linux/dcache.h
include/linux/devpts_fs.h
include/linux/efi.h
include/linux/ethtool.h
include/linux/fsnotify_backend.h
include/linux/ftrace.h
include/linux/gfp.h
include/linux/ieee80211.h
include/linux/if_bridge.h
include/linux/inet_lro.h [deleted file]
include/linux/intel-iommu.h
include/linux/ipv6.h
include/linux/kernel.h
include/linux/libata.h
include/linux/libnvdimm.h
include/linux/lightnvm.h
include/linux/lockdep.h
include/linux/memcontrol.h
include/linux/mlx4/device.h
include/linux/mlx4/driver.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mlx5/port.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmzone.h
include/linux/module.h
include/linux/net.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/netfilter/nfnetlink.h
include/linux/netfilter/x_tables.h
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netlink.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/of.h
include/linux/pci.h
include/linux/perf_event.h
include/linux/pfn.h
include/linux/pfn_t.h
include/linux/phy.h
include/linux/platform_data/brcmfmac-sdio.h [deleted file]
include/linux/platform_data/brcmfmac.h [new file with mode: 0644]
include/linux/power/bq27xxx_battery.h
include/linux/qed/common_hsi.h
include/linux/qed/eth_common.h
include/linux/qed/qed_chain.h
include/linux/qed/qed_eth_if.h
include/linux/qed/qed_if.h
include/linux/radix-tree.h
include/linux/raid/pq.h
include/linux/random.h
include/linux/rculist.h
include/linux/rfkill-gpio.h [deleted file]
include/linux/rfkill.h
include/linux/rmap.h
include/linux/skbuff.h
include/linux/soc/ti/knav_dma.h
include/linux/socket.h
include/linux/stmmac.h
include/linux/trace_events.h
include/linux/tracepoint.h
include/linux/ucs2_string.h
include/linux/workqueue.h
include/linux/writeback.h
include/media/videobuf2-core.h
include/net/6lowpan.h
include/net/act_api.h
include/net/af_unix.h
include/net/bluetooth/hci_core.h
include/net/cfg80211.h
include/net/checksum.h
include/net/codel.h
include/net/devlink.h [new file with mode: 0644]
include/net/dsa.h
include/net/dst_cache.h [new file with mode: 0644]
include/net/dst_metadata.h
include/net/flow_dissector.h
include/net/genetlink.h
include/net/inet_connection_sock.h
include/net/inet_frag.h
include/net/ip.h
include/net/ip6_tunnel.h
include/net/ip_fib.h
include/net/ip_tunnels.h
include/net/ipv6.h
include/net/iw_handler.h
include/net/kcm.h [new file with mode: 0644]
include/net/l3mdev.h
include/net/lwtunnel.h
include/net/mac80211.h
include/net/mac802154.h
include/net/netfilter/nft_masq.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/pkt_cls.h
include/net/route.h
include/net/sch_generic.h
include/net/scm.h
include/net/sctp/sm.h
include/net/sctp/structs.h
include/net/tc_act/tc_gact.h
include/net/tc_act/tc_ife.h [new file with mode: 0644]
include/net/tc_act/tc_skbedit.h
include/net/tcp.h
include/net/udp_tunnel.h
include/net/vxlan.h
include/rdma/ib_addr.h
include/rxrpc/packet.h
include/sound/hdaudio.h
include/sound/rawmidi.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/uapi/asm-generic/socket.h
include/uapi/linux/Kbuild
include/uapi/linux/bpf.h
include/uapi/linux/devlink.h [new file with mode: 0644]
include/uapi/linux/ethtool.h
include/uapi/linux/if_bridge.h
include/uapi/linux/if_ether.h
include/uapi/linux/if_link.h
include/uapi/linux/if_macsec.h [new file with mode: 0644]
include/uapi/linux/ipv6.h
include/uapi/linux/kcm.h [new file with mode: 0644]
include/uapi/linux/kernel.h
include/uapi/linux/media.h
include/uapi/linux/mroute6.h
include/uapi/linux/ndctl.h
include/uapi/linux/netconf.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/netlink.h
include/uapi/linux/netlink_diag.h
include/uapi/linux/nl80211.h
include/uapi/linux/pkt_cls.h
include/uapi/linux/rfkill.h
include/uapi/linux/tc_act/tc_ife.h [new file with mode: 0644]
include/uapi/linux/tcp.h
include/xen/interface/io/netif.h
ipc/shm.c
kernel/bpf/Makefile
kernel/bpf/arraymap.c
kernel/bpf/hashtab.c
kernel/bpf/helpers.c
kernel/bpf/percpu_freelist.c [new file with mode: 0644]
kernel/bpf/percpu_freelist.h [new file with mode: 0644]
kernel/bpf/stackmap.c [new file with mode: 0644]
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup.c
kernel/cpuset.c
kernel/events/callchain.c
kernel/events/core.c
kernel/events/internal.h
kernel/locking/lockdep.c
kernel/memremap.c
kernel/module.c
kernel/resource.c
kernel/sched/deadline.c
kernel/signal.c
kernel/trace/bpf_trace.c
kernel/trace/ftrace.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_stack.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Kconfig.ubsan
lib/Makefile
lib/bitmap.c
lib/dump_stack.c
lib/klist.c
lib/radix-tree.c
lib/random32.c
lib/scatterlist.c
lib/test-string_helpers.c
lib/test_bitmap.c [new file with mode: 0644]
lib/ucs2_string.c
lib/vsprintf.c
mm/Kconfig
mm/backing-dev.c
mm/filemap.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/memblock.c
mm/memory.c
mm/mempolicy.c
mm/migrate.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/page_alloc.c
mm/pgtable-generic.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/util.c
mm/vmpressure.c
mm/vmscan.c
mm/vmstat.c
net/6lowpan/core.c
net/6lowpan/debugfs.c
net/6lowpan/iphc.c
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/8021q/vlanproc.c
net/8021q/vlanproc.h
net/Kconfig
net/Makefile
net/appletalk/ddp.c
net/ax25/ax25_ip.c
net/batman-adv/Kconfig
net/batman-adv/Makefile
net/batman-adv/bat_algo.h
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_v.c [new file with mode: 0644]
net/batman-adv/bat_v_elp.c [new file with mode: 0644]
net/batman-adv/bat_v_elp.h [new file with mode: 0644]
net/batman-adv/bat_v_ogm.c [new file with mode: 0644]
net/batman-adv/bat_v_ogm.h [new file with mode: 0644]
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/fragmentation.c
net/batman-adv/gateway_client.c
net/batman-adv/gateway_common.c
net/batman-adv/gateway_common.h
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.h
net/batman-adv/icmp_socket.c
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/network-coding.c
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/packet.h
net/batman-adv/routing.c
net/batman-adv/send.c
net/batman-adv/send.h
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.h
net/batman-adv/sysfs.c
net/batman-adv/translation-table.c
net/batman-adv/types.h
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/hci_core.c
net/bluetooth/leds.c [new file with mode: 0644]
net/bluetooth/leds.h [new file with mode: 0644]
net/bridge/br_fdb.c
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/bridge/br_stp_timer.c
net/bridge/br_vlan.c
net/bridge/netfilter/nft_reject_bridge.c
net/caif/cfrfml.c
net/ceph/crush/mapper.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/Makefile
net/core/dev.c
net/core/devlink.c [new file with mode: 0644]
net/core/dst.c
net/core/dst_cache.c [new file with mode: 0644]
net/core/ethtool.c
net/core/filter.c
net/core/flow_dissector.c
net/core/lwtunnel.c
net/core/net-sysfs.c
net/core/netclassid_cgroup.c
net/core/netprio_cgroup.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/scm.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dsa/dsa.c
net/dsa/slave.c
net/ethernet/eth.c
net/ieee802154/6lowpan/core.c
net/ipv4/Kconfig
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/fou.c
net/ipv4/gre_offload.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_lro.c [deleted file]
net/ipv4/ip_forward.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ipip.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_SYNPROXY.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_nat.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/iptable_security.c
net/ipv4/netfilter/nf_defrag_ipv4.c
net/ipv4/netfilter/nft_masq_ipv4.c
net/ipv4/ping.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_probe.c
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv4/udp_tunnel.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/exthdrs_core.c
net/ipv6/ila/ila_common.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_udp_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/mcast.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_nat.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/netfilter/ip6table_security.c
net/ipv6/netfilter/nf_nat_masquerade_ipv6.c
net/ipv6/netfilter/nft_masq_ipv6.c
net/ipv6/reassembly.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/udp_offload.c
net/kcm/Kconfig [new file with mode: 0644]
net/kcm/Makefile [new file with mode: 0644]
net/kcm/kcmproc.c [new file with mode: 0644]
net/kcm/kcmsock.c [new file with mode: 0644]
net/l2tp/l2tp_netlink.c
net/l3mdev/l3mdev.c
net/llc/af_llc.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/debugfs_key.c
net/mac80211/driver-ops.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tkip.c
net/mac80211/tkip.h
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/mac80211/wpa.c
net/mac802154/main.c
net/mpls/mpls_iptunnel.c
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_app.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_dup_netdev.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_cttimeout.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_counter.c
net/netfilter/nft_masq.c
net/netfilter/nft_meta.c
net/netfilter/x_tables.c
net/netfilter/xt_TEE.c
net/netfilter/xt_osf.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_unlabeled.c
net/netlink/Kconfig
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/netlink/diag.c
net/netlink/genetlink.c
net/openvswitch/Kconfig
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/flow_netlink.c
net/openvswitch/vport-internal_dev.c
net/openvswitch/vport-netdev.c
net/openvswitch/vport-vxlan.c
net/openvswitch/vport.h
net/packet/af_packet.c
net/rds/Kconfig
net/rds/Makefile
net/rds/af_rds.c
net/rds/ib.c
net/rds/ib.h
net/rds/ib_cm.c
net/rds/ib_fmr.c [new file with mode: 0644]
net/rds/ib_frmr.c [new file with mode: 0644]
net/rds/ib_mr.h [new file with mode: 0644]
net/rds/ib_rdma.c
net/rds/ib_send.c
net/rds/ib_stats.c
net/rds/iw.c [deleted file]
net/rds/iw.h [deleted file]
net/rds/iw_cm.c [deleted file]
net/rds/iw_rdma.c [deleted file]
net/rds/iw_recv.c [deleted file]
net/rds/iw_ring.c [deleted file]
net/rds/iw_send.c [deleted file]
net/rds/iw_stats.c [deleted file]
net/rds/iw_sysctl.c [deleted file]
net/rds/rdma_transport.c
net/rds/rdma_transport.h
net/rds/rds.h
net/rds/recv.c
net/rfkill/Kconfig
net/rfkill/core.c
net/rfkill/rfkill-gpio.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-accept.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-call.c
net/rxrpc/ar-connection.c
net/rxrpc/ar-connevent.c
net/rxrpc/ar-error.c
net/rxrpc/ar-input.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-local.c
net/rxrpc/ar-output.c
net/rxrpc/ar-peer.c
net/rxrpc/ar-proc.c
net/rxrpc/ar-recvmsg.c
net/rxrpc/ar-security.c
net/rxrpc/ar-skbuff.c
net/rxrpc/ar-transport.c
net/rxrpc/rxkad.c
net/rxrpc/sysctl.c
net/sched/Kconfig
net/sched/Makefile
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_connmark.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ife.c [new file with mode: 0644]
net/sched/act_ipt.c
net/sched/act_meta_mark.c [new file with mode: 0644]
net/sched/act_meta_skbprio.c [new file with mode: 0644]
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/act_vlan.c
net/sched/cls_flower.c
net/sched/cls_u32.c
net/sched/sch_api.c
net/sched/sch_cbq.c
net/sched/sch_choke.c
net/sched/sch_codel.c
net/sched/sch_drr.c
net/sched/sch_dsmark.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_generic.c
net/sched/sch_hfsc.c
net/sched/sch_hhf.c
net/sched/sch_htb.c
net/sched/sch_mq.c
net/sched/sch_mqprio.c
net/sched/sch_multiq.c
net/sched/sch_netem.c
net/sched/sch_pie.c
net/sched/sch_prio.c
net/sched/sch_qfq.c
net/sched/sch_red.c
net/sched/sch_sfb.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sctp/associola.c
net/sctp/chunk.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/probe.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/cache.c
net/sunrpc/xprtrdma/backchannel.c
net/switchdev/switchdev.c
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/link.c
net/tipc/link.h
net/tipc/name_table.c
net/tipc/net.c
net/tipc/netlink.c
net/tipc/netlink.h
net/tipc/netlink_compat.c
net/tipc/node.c
net/tipc/socket.c
net/tipc/subscr.c
net/tipc/udp_media.c
net/unix/af_unix.c
net/unix/diag.c
net/unix/garbage.c
net/vmw_vsock/af_vsock.c
net/wireless/Kconfig
net/wireless/core.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/radiotap.c
net/wireless/reg.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-core.c
samples/bpf/Makefile
samples/bpf/bpf_helpers.h
samples/bpf/bpf_load.c
samples/bpf/bpf_load.h
samples/bpf/fds_example.c
samples/bpf/libbpf.c
samples/bpf/libbpf.h
samples/bpf/map_perf_test_kern.c [new file with mode: 0644]
samples/bpf/map_perf_test_user.c [new file with mode: 0644]
samples/bpf/offwaketime_kern.c [new file with mode: 0644]
samples/bpf/offwaketime_user.c [new file with mode: 0644]
samples/bpf/sock_example.c
samples/bpf/spintest_kern.c [new file with mode: 0644]
samples/bpf/spintest_user.c [new file with mode: 0644]
samples/bpf/test_maps.c
samples/bpf/test_verifier.c
scripts/prune-kernel [new file with mode: 0755]
security/integrity/evm/evm_main.c
security/selinux/hooks.c
security/selinux/nlmsgtab.c
sound/core/control_compat.c
sound/core/oss/pcm_oss.c
sound/core/pcm_compat.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/rawmidi_compat.c
sound/core/seq/oss/seq_oss.c
sound/core/seq/oss/seq_oss_device.h
sound/core/seq/oss/seq_oss_init.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_ports.c
sound/core/seq/seq_timer.c
sound/core/seq/seq_virmidi.c
sound/core/timer.c
sound/core/timer_compat.c
sound/drivers/dummy.c
sound/firewire/digi00x/amdtp-dot.c
sound/firewire/tascam/tascam-transaction.c
sound/firewire/tascam/tascam.c
sound/firewire/tascam/tascam.h
sound/hda/hdac_controller.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_jack.c
sound/pci/hda/hda_jack.h
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/soc/amd/acp-pcm-dma.c
sound/soc/codecs/arizona.c
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5659.c
sound/soc/codecs/rt5659.h
sound/soc/codecs/sigmadsp-i2c.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8960.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-spdif.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/atom/sst-mfld-platform-pcm.c
sound/soc/intel/boards/skl_rt286.c
sound/soc/intel/common/Makefile
sound/soc/intel/common/sst-acpi.c
sound/soc/intel/common/sst-match-acpi.c
sound/soc/intel/skylake/skl-messages.c
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl-topology.c
sound/soc/intel/skylake/skl.c
sound/soc/mediatek/Kconfig
sound/soc/mxs/mxs-saif.c
sound/soc/qcom/lpass-platform.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/usb/midi.c
sound/usb/quirks.c
tools/net/bpf_exp.l
tools/net/bpf_exp.y
tools/perf/util/intel-pt.c
tools/perf/util/parse-events.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/stat.c
tools/testing/nvdimm/test/nfit.c
tools/testing/selftests/efivarfs/efivarfs.sh
tools/testing/selftests/efivarfs/open-unlink.c
tools/testing/selftests/ftrace/test.d/instances/instance.tc
tools/testing/selftests/lib/Makefile
tools/testing/selftests/lib/bitmap.sh [new file with mode: 0755]
virt/kvm/arm/arch_timer.c
virt/kvm/arm/vgic.c
virt/kvm/async_pf.c

diff --git a/Documentation/ABI/obsolete/sysfs-class-rfkill b/Documentation/ABI/obsolete/sysfs-class-rfkill
deleted file mode 100644 (file)
index ff60ad9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-rfkill - radio frequency (RF) connector kill switch support
-
-For details to this subsystem look at Documentation/rfkill.txt.
-
-What:          /sys/class/rfkill/rfkill[0-9]+/state
-Date:          09-Jul-2007
-KernelVersion  v2.6.22
-Contact:       linux-wireless@vger.kernel.org
-Description:   Current state of the transmitter.
-               This file is deprecated and scheduled to be removed in 2014,
-               because its not possible to express the 'soft and hard block'
-               state of the rfkill driver.
-Values:        A numeric value.
-               0: RFKILL_STATE_SOFT_BLOCKED
-                       transmitter is turned off by software
-               1: RFKILL_STATE_UNBLOCKED
-                       transmitter is (potentially) active
-               2: RFKILL_STATE_HARD_BLOCKED
-                       transmitter is forced off by something outside of
-                       the driver's control.
-
-What:          /sys/class/rfkill/rfkill[0-9]+/claim
-Date:          09-Jul-2007
-KernelVersion  v2.6.22
-Contact:       linux-wireless@vger.kernel.org
-Description:   This file is deprecated because there no longer is a way to
-               claim just control over a single rfkill instance.
-               This file is scheduled to be removed in 2012.
-Values:        0: Kernel handles events
diff --git a/Documentation/ABI/removed/sysfs-class-rfkill b/Documentation/ABI/removed/sysfs-class-rfkill
new file mode 100644 (file)
index 0000000..3ce6231
--- /dev/null
@@ -0,0 +1,13 @@
+rfkill - radio frequency (RF) connector kill switch support
+
+For details to this subsystem look at Documentation/rfkill.txt.
+
+What:          /sys/class/rfkill/rfkill[0-9]+/claim
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   This file was deprecated because there no longer was a way to
+               claim just control over a single rfkill instance.
+               This file was scheduled to be removed in 2012, and was removed
+               in 2016.
+Values:        0: Kernel handles events
index 097f522c33bb7b5c3632a9ca200e099fea32b2cf..e1ba4a10475364cd8fcf201b323c26de5ee8b62b 100644 (file)
@@ -2,9 +2,8 @@ rfkill - radio frequency (RF) connector kill switch support
 
 For details to this subsystem look at Documentation/rfkill.txt.
 
-For the deprecated /sys/class/rfkill/*/state and
-/sys/class/rfkill/*/claim knobs of this interface look in
-Documentation/ABI/obsolete/sysfs-class-rfkill.
+For the deprecated /sys/class/rfkill/*/claim knobs of this interface look in
+Documentation/ABI/removed/sysfs-class-rfkill.
 
 What:          /sys/class/rfkill
 Date:          09-Jul-2007
@@ -42,6 +41,28 @@ Values:      A numeric value.
                1: true
 
 
+What:          /sys/class/rfkill/rfkill[0-9]+/state
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   Current state of the transmitter.
+               This file was scheduled to be removed in 2014, but due to its
+               large number of users it will be sticking around for a bit
+               longer. Despite it being marked as stabe, the newer "hard" and
+               "soft" interfaces should be preffered, since it is not possible
+               to express the 'soft and hard block' state of the rfkill driver
+               through this interface. There will likely be another attempt to
+               remove it in the future.
+Values:        A numeric value.
+               0: RFKILL_STATE_SOFT_BLOCKED
+                       transmitter is turned off by software
+               1: RFKILL_STATE_UNBLOCKED
+                       transmitter is (potentially) active
+               2: RFKILL_STATE_HARD_BLOCKED
+                       transmitter is forced off by something outside of
+                       the driver's control.
+
+
 What:          /sys/class/rfkill/rfkill[0-9]+/hard
 Date:          12-March-2010
 KernelVersion  v2.6.34
index 7f34a95bb9634c9d8d1d9505d31b68c36bc58f76..518f6a1dbc0c0b7009fc5fbea85064b22a48b60e 100644 (file)
@@ -1,4 +1,20 @@
 
+What:          /sys/class/net/<iface>/batman-adv/throughput_override
+Date:          Feb 2014
+Contact:       Antonio Quartulli <antonio@meshcoding.com>
+description:
+               Defines the throughput value to be used by B.A.T.M.A.N. V
+               when estimating the link throughput using this interface.
+               If the value is set to 0 then batman-adv will try to
+               estimate the throughput by itself.
+
+What:           /sys/class/net/<iface>/batman-adv/elp_interval
+Date:           Feb 2014
+Contact:        Linus Lüssing <linus.luessing@web.de>
+Description:
+                Defines the interval in milliseconds in which batman
+                sends its probing packets for link quality measurements.
+
 What:           /sys/class/net/<iface>/batman-adv/iface_status
 Date:           May 2010
 Contact:        Marek Lindner <mareklindner@neomailbox.ch>
@@ -12,4 +28,3 @@ Description:
                 The /sys/class/net/<iface>/batman-adv/mesh_iface file
                 displays the batman mesh interface this <iface>
                 currently is associated with.
-
index 1af3842509105ea45fd815ad953781d901b03bfe..0ee0f3386cdf3c7881e88546c03e5347c3e5e721 100644 (file)
            <entry><constant>MEDIA_ENT_F_CONN_COMPOSITE</constant></entry>
            <entry>Connector for a RGB composite signal.</entry>
          </row>
-         <row>
-           <entry><constant>MEDIA_ENT_F_CONN_TEST</constant></entry>
-           <entry>Connector for a test generator.</entry>
-         </row>
          <row>
            <entry><constant>MEDIA_ENT_F_CAM_SENSOR</constant></entry>
            <entry>Camera video sensor entity.</entry>
index 65b3eac8856cf7ec26b341b217046a2fb9b7bf26..ff49cf901148d895b765800ec6ddb79c0e38ed53 100644 (file)
@@ -7,7 +7,7 @@ This is the authoritative documentation on the design, interface and
 conventions of cgroup v2.  It describes all userland-visible aspects
 of cgroup including core and specific controller behaviors.  All
 future changes must be reflected in this document.  Documentation for
-v1 is available under Documentation/cgroup-legacy/.
+v1 is available under Documentation/cgroup-v1/.
 
 CONTENTS
 
@@ -843,6 +843,10 @@ PAGE_SIZE multiple when read back.
                Amount of memory used to cache filesystem data,
                including tmpfs and shared memory.
 
+         sock
+
+               Amount of memory used in network transmission buffers
+
          file_mapped
 
                Amount of cached filesystem data mapped with mmap()
index ace05992a262592fb22f88db5c2e13036e20c015..20df350b9ef3d491b3e2e714f8877d74477afcd8 100644 (file)
@@ -30,7 +30,7 @@ that they are defined using standard clock bindings with following
 clock-output-names:
  - "xin24m" - crystal input - required,
  - "ext_i2s" - external I2S clock - optional,
- - "ext_gmac" - external GMAC clock - optional
+ - "rmii_clkin" - external EMAC clock - optional
 
 Example: Clock controller node:
 
index 7803e77d85cbe9d69dfcd42405ece4de0ddfe329..007a5b46256ad57effb087c5beb2eae8c7e3d1e7 100644 (file)
@@ -24,9 +24,8 @@ Main node required properties:
                1 = edge triggered
                4 = level triggered
 
-  Cells 4 and beyond are reserved for future use. When the 1st cell
-  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
-  ignored. It is recommended that padding cells have a value of 0.
+  Cells 4 and beyond are reserved for future use and must have a value
+  of 0 if present.
 
 - reg : Specifies base physical address(s) and size of the GIC
   registers, in the following order:
diff --git a/Documentation/devicetree/bindings/net/can/ifi_canfd.txt b/Documentation/devicetree/bindings/net/can/ifi_canfd.txt
new file mode 100644 (file)
index 0000000..20ea5c7
--- /dev/null
@@ -0,0 +1,15 @@
+IFI CANFD controller
+--------------------
+
+Required properties:
+  - compatible: Should be "ifi,canfd-1.0"
+  - reg: Should contain CAN controller registers location and length
+  - interrupts: Should contain IRQ line for the CAN controller
+
+Example:
+
+       canfd0: canfd@ff220000 {
+               compatible = "ifi,canfd-1.0";
+               reg = <0xff220000 0x00001000>;
+               interrupts = <0 43 0>;
+       };
index 002d8440bf66f6a00054895b75c47e724cbcd5b9..8d40ab27bc8ca0964ddf1a0f6f02b372dceb5c62 100644 (file)
@@ -6,6 +6,17 @@ Required properties:
              "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
              "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
              "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC.
+             "renesas,can-r8a7792" if CAN controller is a part of R8A7792 SoC.
+             "renesas,can-r8a7793" if CAN controller is a part of R8A7793 SoC.
+             "renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
+             "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
+             "renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device.
+             "renesas,rcar-gen2-can" for a generic R-Car Gen2 compatible device.
+             "renesas,rcar-gen3-can" for a generic R-Car Gen3 compatible device.
+             When compatible with the generic version, nodes must list the
+             SoC-specific version corresponding to the platform first
+             followed by the generic version.
+
 - reg: physical base address and size of the R-Car CAN register map.
 - interrupts: interrupt specifier for the sole interrupt.
 - clocks: phandles and clock specifiers for 3 CAN clock inputs.
@@ -13,6 +24,15 @@ Required properties:
 - pinctrl-0: pin control group to be used for this controller.
 - pinctrl-names: must be "default".
 
+Required properties for "renesas,can-r8a7795" compatible:
+In R8A7795 SoC, "clkp2" can be CANFD clock. This is a div6 clock and can be
+used by both CAN and CAN FD controller at the same time. It needs to be scaled
+to maximum frequency if any of these controllers use it. This is done using
+the below properties.
+
+- assigned-clocks: phandle of clkp2(CANFD) clock.
+- assigned-clock-rates: maximum frequency of this clock.
+
 Optional properties:
 - renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
                            <0x0> (default) : Peripheral clock (clkp1)
@@ -25,7 +45,7 @@ Example
 SoC common .dtsi file:
 
        can0: can@e6e80000 {
-               compatible = "renesas,can-r8a7791";
+               compatible = "renesas,can-r8a7791", "renesas,rcar-gen2-can";
                reg = <0 0xe6e80000 0 0x1000>;
                interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&mstp9_clks R8A7791_CLK_RCAN0>,
index b4a6d53fb01ae8827ba69b33bbc60e6db21d90a7..ac3160eca96a2dc38f085f165aee2d912e8c927c 100644 (file)
@@ -2,7 +2,7 @@ Memory mapped SJA1000 CAN controller from NXP (formerly Philips)
 
 Required properties:
 
-- compatible : should be "nxp,sja1000".
+- compatible : should be one of "nxp,sja1000", "technologic,sja1000".
 
 - reg : should specify the chip select, address offset and size required
        to map the registers of the SJA1000. The size is usually 0x80.
@@ -14,6 +14,7 @@ Optional properties:
 
 - reg-io-width : Specify the size (in bytes) of the IO accesses that
        should be performed on the device.  Valid value is 1, 2 or 4.
+       This property is ignored for technologic version.
        Default to 1 (8 bits).
 
 - nxp,external-clock-frequency : Frequency of the external oscillator
index a9eb611bee68121a01f587a9c296852d0b6a46ce..b037a9d78d931312f9f950db4e358c8e86a5c86b 100644 (file)
@@ -12,6 +12,9 @@ Optional properties:
   only if property "phy-reset-gpios" is available.  Missing the property
   will have the duration be 1 millisecond.  Numbers greater than 1000 are
   invalid and 1 millisecond will be used instead.
+- phy-reset-active-high : If present then the reset sequence using the GPIO
+  specified in the "phy-reset-gpios" property is reversed (H=reset state,
+  L=operation state).
 - phy-supply : regulator that powers the Ethernet PHY.
 - phy-handle : phandle to the PHY device connected to this device.
 - fixed-link : Assume a fixed link. See fixed-link.txt in the same directory.
index c6b1cb5ffa875c6d744b24630d5f601440016fda..b5a42df4c9281d20c27cb726b0fac57ff58187c3 100644 (file)
@@ -25,7 +25,7 @@ Required properties:
 
 Optional properties for PHY child node:
 - reset-gpios : Should specify the gpio for phy reset
-- cdns,magic-packet : If present, indicates that the hardware supports waking
+- magic-packet : If present, indicates that the hardware supports waking
   up via magic packet.
 
 Examples:
diff --git a/Documentation/devicetree/bindings/net/mediatek-net.txt b/Documentation/devicetree/bindings/net/mediatek-net.txt
new file mode 100644 (file)
index 0000000..5ca7929
--- /dev/null
@@ -0,0 +1,77 @@
+MediaTek Frame Engine Ethernet controller
+=========================================
+
+The frame engine ethernet controller can be found on MediaTek SoCs. These SoCs
+have dual GMAC each represented by a child node..
+
+* Ethernet controller node
+
+Required properties:
+- compatible: Should be "mediatek,mt7623-eth"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the frame engines interrupt
+- clocks: the clock used by the core
+- clock-names: the names of the clock listed in the clocks property. These are
+       "ethif", "esw", "gp2", "gp1"
+- power-domains: phandle to the power domain that the ethernet is part of
+- resets: Should contain a phandle to the ethsys reset signal
+- reset-names: Should contain the reset signal name "eth"
+- mediatek,ethsys: phandle to the syscon node that handles the port setup
+- mediatek,pctl: phandle to the syscon node that handles the ports slew rate
+       and driver current
+
+Optional properties:
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+
+
+* Ethernet MAC node
+
+Required properties:
+- compatible: Should be "mediatek,eth-mac"
+- reg: The number of the MAC
+- phy-handle: see ethernet.txt file in the same directory.
+
+Example:
+
+eth: ethernet@1b100000 {
+       compatible = "mediatek,mt7623-eth";
+       reg = <0 0x1b100000 0 0x20000>;
+       clocks = <&topckgen CLK_TOP_ETHIF_SEL>,
+                <&ethsys CLK_ETHSYS_ESW>,
+                <&ethsys CLK_ETHSYS_GP2>,
+                <&ethsys CLK_ETHSYS_GP1>;
+       clock-names = "ethif", "esw", "gp2", "gp1";
+       interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_LOW>;
+       power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>;
+       resets = <&ethsys MT2701_ETHSYS_ETH_RST>;
+       reset-names = "eth";
+       mediatek,ethsys = <&ethsys>;
+       mediatek,pctl = <&syscfg_pctl_a>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       gmac1: mac@0 {
+               compatible = "mediatek,eth-mac";
+               reg = <0>;
+               phy-handle = <&phy0>;
+       };
+
+       gmac2: mac@1 {
+               compatible = "mediatek,eth-mac";
+               reg = <1>;
+               phy-handle = <&phy1>;
+       };
+
+       mdio-bus {
+               phy0: ethernet-phy@0 {
+                       reg = <0>;
+                       phy-mode = "rgmii";
+               };
+
+               phy1: ethernet-phy@1 {
+                       reg = <1>;
+                       phy-mode = "rgmii";
+               };
+       };
+};
index 81a9f9e6b45ff85c83da488fbafc2c2b89839600..c8ac222eac67a0c330bec3d641d0ed65cc399281 100644 (file)
@@ -82,8 +82,8 @@ Example:
                                  "ch16", "ch17", "ch18", "ch19",
                                  "ch20", "ch21", "ch22", "ch23",
                                  "ch24";
-               clocks = <&mstp8_clks R8A7795_CLK_ETHERAVB>;
-               power-domains = <&cpg_clocks>;
+               clocks = <&cpg CPG_MOD 812>;
+               power-domains = <&cpg>;
                phy-mode = "rgmii-id";
                phy-handle = <&phy0>;
 
index e862a922bd3f957daca0989d1a94ae246afa48ca..6605d19601c2a6bcce217ef02a60f5afb42e0d55 100644 (file)
@@ -17,7 +17,25 @@ Required properties:
        The 1st cell is reset pre-delay in micro seconds.
        The 2nd cell is reset pulse in micro seconds.
        The 3rd cell is reset post-delay in micro seconds.
+
+Optional properties:
+- resets: Should contain a phandle to the STMMAC reset signal, if any
+- reset-names: Should contain the reset signal name "stmmaceth", if a
+       reset phandle is given
+- max-frame-size: See ethernet.txt file in the same directory
+- clocks: If present, the first clock should be the GMAC main clock and
+  the second clock should be peripheral's register interface clock. Further
+  clocks may be specified in derived bindings.
+- clock-names: One name for each entry in the clocks property, the
+  first one should be "stmmaceth" and the second one should be "pclk".
+- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
+  available this clock is used for programming the Timestamp Addend Register.
+  If not passed then the system clock will be used and this is fine on some
+  platforms.
+- tx-fifo-depth: See ethernet.txt file in the same directory
+- rx-fifo-depth: See ethernet.txt file in the same directory
 - snps,pbl             Programmable Burst Length
+- snps,aal             Address-Aligned Beats
 - snps,fixed-burst     Program the DMA to use the fixed burst mode
 - snps,mixed-burst     Program the DMA to use the mixed burst mode
 - snps,force_thresh_dma_mode   Force DMA to use the threshold mode for
@@ -29,27 +47,28 @@ Required properties:
                                supported by this device instance
 - snps,perfect-filter-entries: Number of perfect filter entries supported
                                by this device instance
-
-Optional properties:
-- resets: Should contain a phandle to the STMMAC reset signal, if any
-- reset-names: Should contain the reset signal name "stmmaceth", if a
-       reset phandle is given
-- max-frame-size: See ethernet.txt file in the same directory
-- clocks: If present, the first clock should be the GMAC main clock
-  The optional second clock should be peripheral's register interface clock.
-  The third optional clock should be the ptp reference clock.
-  Further clocks may be specified in derived bindings.
-- clock-names: One name for each entry in the clocks property.
-  The first one should be "stmmaceth".
-  The optional second one should be "pclk".
-  The optional third one should be "clk_ptp_ref".
-- snps,burst_len: The AXI burst lenth value of the AXI BUS MODE register.
-- tx-fifo-depth: See ethernet.txt file in the same directory
-- rx-fifo-depth: See ethernet.txt file in the same directory
+- AXI BUS Mode parameters: below the list of all the parameters to program the
+                          AXI register inside the DMA module:
+       - snps,lpi_en: enable Low Power Interface
+       - snps,xit_frm: unlock on WoL
+       - snps,wr_osr_lmt: max write oustanding req. limit
+       - snps,rd_osr_lmt: max read oustanding req. limit
+       - snps,kbbe: do not cross 1KiB boundary.
+       - snps,axi_all: align address
+       - snps,blen: this is a vector of supported burst length.
+       - snps,fb: fixed-burst
+       - snps,mb: mixed-burst
+       - snps,rb: rebuild INCRx Burst
 - mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
 
 Examples:
 
+       stmmac_axi_setup: stmmac-axi-config {
+               snps,wr_osr_lmt = <0xf>;
+               snps,rd_osr_lmt = <0xf>;
+               snps,blen = <256 128 64 32 0 0 0>;
+       };
+
        gmac0: ethernet@e0800000 {
                compatible = "st,spear600-gmac";
                reg = <0xe0800000 0x8000>;
@@ -65,6 +84,7 @@ Examples:
                tx-fifo-depth = <16384>;
                clocks = <&clock>;
                clock-names = "stmmaceth";
+               snps,axi-config = <&stmmac_axi_setup>;
                mdio0 {
                        #address-cells = <1>;
                        #size-cells = <0>;
index edefc26c62042baad86259cc4737c60c507612fb..96aae6b4f736802df34a6524202a5dd2653e4231 100644 (file)
@@ -1,17 +1,46 @@
 * Qualcomm Atheros ath10k wireless devices
 
-For ath10k devices the calibration data can be provided through Device
-Tree. The node is a child node of the PCI controller.
-
 Required properties:
--compatible : Should be "qcom,ath10k"
+- compatible: Should be one of the following:
+       * "qcom,ath10k"
+       * "qcom,ipq4019-wifi"
+
+PCI based devices uses compatible string "qcom,ath10k" and takes only
+calibration data via "qcom,ath10k-calibration-data". Rest of the properties
+are not applicable for PCI based devices.
+
+AHB based devices (i.e. ipq4019) uses compatible string "qcom,ipq4019-wifi"
+and also uses most of the properties defined in this doc.
 
 Optional properties:
+- reg: Address and length of the register set for the device.
+- resets: Must contain an entry for each entry in reset-names.
+          See ../reset/reseti.txt for details.
+- reset-names: Must include the list of following reset names,
+              "wifi_cpu_init"
+              "wifi_radio_srif"
+              "wifi_radio_warm"
+              "wifi_radio_cold"
+              "wifi_core_warm"
+              "wifi_core_cold"
+- clocks: List of clock specifiers, must contain an entry for each required
+          entry in clock-names.
+- clock-names: Should contain the clock names "wifi_wcss_cmd", "wifi_wcss_ref",
+               "wifi_wcss_rtc".
+- interrupts: List of interrupt lines. Must contain an entry
+             for each entry in the interrupt-names property.
+- interrupt-names: Must include the entries for MSI interrupt
+                  names ("msi0" to "msi15") and legacy interrupt
+                  name ("legacy"),
+- qcom,msi_addr: MSI interrupt address.
+- qcom,msi_base: Base value to add before writing MSI data into
+               MSI address register.
 - qcom,ath10k-calibration-data : calibration data as an array, the
                                 length can vary between hw versions
 
+Example (to supply the calibration data alone):
 
-Example:
+In this example, the node is defined as child node of the PCI controller.
 
 pci {
        pcie@0 {
@@ -28,3 +57,53 @@ pci {
                };
        };
 };
+
+Example (to supply ipq4019 SoC wifi block details):
+
+wifi0: wifi@a000000 {
+       compatible = "qcom,ipq4019-wifi";
+       reg = <0xa000000 0x200000>;
+       resets = <&gcc WIFI0_CPU_INIT_RESET>,
+                <&gcc WIFI0_RADIO_SRIF_RESET>,
+                <&gcc WIFI0_RADIO_WARM_RESET>,
+                <&gcc WIFI0_RADIO_COLD_RESET>,
+                <&gcc WIFI0_CORE_WARM_RESET>,
+                <&gcc WIFI0_CORE_COLD_RESET>;
+       reset-names = "wifi_cpu_init",
+                     "wifi_radio_srif",
+                     "wifi_radio_warm",
+                     "wifi_radio_cold",
+                     "wifi_core_warm",
+                     "wifi_core_cold";
+       clocks = <&gcc GCC_WCSS2G_CLK>,
+                <&gcc GCC_WCSS2G_REF_CLK>,
+                <&gcc GCC_WCSS2G_RTC_CLK>;
+       clock-names = "wifi_wcss_cmd",
+                     "wifi_wcss_ref",
+                     "wifi_wcss_rtc";
+       interrupts = <0 0x20 0x1>,
+                    <0 0x21 0x1>,
+                    <0 0x22 0x1>,
+                    <0 0x23 0x1>,
+                    <0 0x24 0x1>,
+                    <0 0x25 0x1>,
+                    <0 0x26 0x1>,
+                    <0 0x27 0x1>,
+                    <0 0x28 0x1>,
+                    <0 0x29 0x1>,
+                    <0 0x2a 0x1>,
+                    <0 0x2b 0x1>,
+                    <0 0x2c 0x1>,
+                    <0 0x2d 0x1>,
+                    <0 0x2e 0x1>,
+                    <0 0x2f 0x1>,
+                    <0 0xa8 0x0>;
+       interrupt-names = "msi0",  "msi1",  "msi2",  "msi3",
+                         "msi4",  "msi5",  "msi6",  "msi7",
+                         "msi8",  "msi9",  "msi10", "msi11",
+                         "msi12", "msi13", "msi14", "msi15",
+                         "legacy";
+       qcom,msi_addr = <0x0b006040>;
+       qcom,msi_base = <0x40>;
+       qcom,ath10k-calibration-data = [ 01 02 03 ... ];
+};
diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt b/Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt
new file mode 100644 (file)
index 0000000..9180724
--- /dev/null
@@ -0,0 +1,36 @@
+* Texas Instruments wl1271 wireless lan controller
+
+The wl1271 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,wl1271"
+- reg :                 Chip select address of device
+- spi-max-frequency :   Maximum SPI clocking speed of device in Hz
+- ref-clock-frequency : Reference clock frequency
+- interrupt-parent, interrupts :
+                        Should contain parameters for 1 interrupt line.
+                        Interrupt parameters: parent, line number, type.
+- vwlan-supply :        Point the node of the regulator that powers/enable the wl1271 chip
+
+Optional properties:
+- clock-xtal :          boolean, clock is generated from XTAL
+
+- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
+  for optional SPI connection related properties,
+
+Examples:
+
+&spi1 {
+       wl1271@1 {
+               compatible = "ti,wl1271";
+
+               reg = <1>;
+               spi-max-frequency = <48000000>;
+               clock-xtal;
+               ref-clock-frequency = <38400000>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+               vwlan-supply = <&vwlan_fixed>;
+       };
+};
index 4e8b90e43dd83c72d81df6d644317ba60b489559..07a75094c5a8ed07e927c0641584d5e8348e3dc6 100644 (file)
@@ -8,6 +8,7 @@ OHCI and EHCI controllers.
 Required properties:
 - compatible: "renesas,pci-r8a7790" for the R8A7790 SoC;
              "renesas,pci-r8a7791" for the R8A7791 SoC;
+             "renesas,pci-r8a7793" for the R8A7793 SoC;
              "renesas,pci-r8a7794" for the R8A7794 SoC;
              "renesas,pci-rcar-gen2" for a generic R-Car Gen2 compatible device
 
index 558fe528ae1951104b6266a2f5ed4849017c6b35..6cf99690eef94fa4ed033fb91e08c2aa010395bf 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
 compatible: "renesas,pcie-r8a7779" for the R8A7779 SoC;
            "renesas,pcie-r8a7790" for the R8A7790 SoC;
            "renesas,pcie-r8a7791" for the R8A7791 SoC;
+           "renesas,pcie-r8a7793" for the R8A7793 SoC;
            "renesas,pcie-r8a7795" for the R8A7795 SoC;
            "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 compatible device.
 
index d18109657da6c0154d3abebd980178f91b4a9102..4f05d208c95cfeac7ebbc217003d34f08e0f4772 100644 (file)
@@ -26,11 +26,7 @@ Example:
                ti,pmic-shutdown-controller;
 
                regulators {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-
                        dcdc1_reg: dcdc1 {
-                               reg = <0>;
                                regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <1800000>;
                                regulator-boot-on;
@@ -38,7 +34,6 @@ Example:
                        };
 
                        dcdc2_reg: dcdc2 {
-                               reg = <1>;
                                regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
@@ -46,7 +41,6 @@ Example:
                        };
 
                        dcdc3_reg: dcc3 {
-                               reg = <2>;
                                regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-boot-on;
@@ -54,7 +48,6 @@ Example:
                        };
 
                        ldo1_reg: ldo1 {
-                               reg = <3>;
                                regulator-min-microvolt = <1000000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
@@ -62,7 +55,6 @@ Example:
                        };
 
                        ldo2_reg: ldo2 {
-                               reg = <4>;
                                regulator-min-microvolt = <900000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
@@ -70,7 +62,6 @@ Example:
                        };
 
                        ldo3_reg: ldo3 {
-                               reg = <5>;
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
@@ -78,7 +69,6 @@ Example:
                        };
 
                        ldo4_reg: ldo4 {
-                               reg = <6>;
                                regulator-min-microvolt = <1800000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-boot-on;
index ac2fcd6ff4b8cde39bf8446c406571fefa7684a9..1068ffce9f9125559e301f60f9c0ce6ca40d2374 100644 (file)
@@ -14,6 +14,10 @@ Required properties:
   interrupt number is the rtc alarm interrupt and second interrupt number
   is the rtc tick interrupt. The number of cells representing a interrupt
   depends on the parent interrupt controller.
+- clocks: Must contain a list of phandle and clock specifier for the rtc
+          and source clocks.
+- clock-names: Must contain "rtc" and "rtc_src" entries sorted in the
+               same order as the clocks property.
 
 Example:
 
@@ -21,4 +25,6 @@ Example:
                compatible = "samsung,s3c6410-rtc";
                reg = <0x10070000 0x100>;
                interrupts = <44 0 45 0>;
+               clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
+               clock-names = "rtc", "rtc_src";
        };
index 35ae1fb3537f3217a50fe92fd8f4042b52e6e6d0..ed94c217c98d18a655aa4df150de7b62f1e17440 100644 (file)
@@ -9,7 +9,7 @@ Optional properties:
 - fsl,uart-has-rtscts : Indicate the uart has rts and cts
 - fsl,irda-mode : Indicate the uart supports irda mode
 - fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
-                  is DCE mode by default.
+                  in DCE mode by default.
 
 Note: Each uart controller should have an alias correctly numbered
 in "aliases" node.
index ce55c0a6f7578ee192a207a6b247095d605072b8..4da41bf1888e9baaf2471a73db7d8019be9d6d0c 100644 (file)
@@ -30,6 +30,8 @@ The compatible list for this generic sound card currently:
  "fsl,imx-audio-sgtl5000"
  (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt)
 
+ "fsl,imx-audio-wm8960"
+
 Required properties:
 
   - compatible         : Contains one of entries in the compatible list.
index 332e625f6ed01cb4e442c0ea530ab29eb92f2a77..e5ee3f15989337f37b9d5e43036c31a2b4c9ff11 100644 (file)
@@ -1,8 +1,9 @@
 * Renesas R-Car Thermal
 
 Required properties:
-- compatible           : "renesas,thermal-<soctype>", "renesas,rcar-thermal"
-                         as fallback.
+- compatible           : "renesas,thermal-<soctype>",
+                          "renesas,rcar-gen2-thermal" (with thermal-zone) or
+                          "renesas,rcar-thermal" (without thermal-zone) as fallback.
                          Examples with soctypes are:
                            - "renesas,thermal-r8a73a4" (R-Mobile APE6)
                            - "renesas,thermal-r8a7779" (R-Car H1)
@@ -36,3 +37,35 @@ thermal@e61f0000 {
                0xe61f0300 0x38>;
        interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>;
 };
+
+Example (with thermal-zone):
+
+thermal-zones {
+       cpu_thermal: cpu-thermal {
+               polling-delay-passive   = <1000>;
+               polling-delay           = <5000>;
+
+               thermal-sensors = <&thermal>;
+
+               trips {
+                       cpu-crit {
+                               temperature     = <115000>;
+                               hysteresis      = <0>;
+                               type            = "critical";
+                       };
+               };
+               cooling-maps {
+               };
+       };
+};
+
+thermal: thermal@e61f0000 {
+       compatible =    "renesas,thermal-r8a7790",
+                       "renesas,rcar-gen2-thermal",
+                       "renesas,rcar-thermal";
+       reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>;
+       interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&mstp5_clks R8A7790_CLK_THERMAL>;
+       power-domains = <&cpg_clocks>;
+       #thermal-sensor-cells = <0>;
+};
index 72e2c5a2b3278facb20378383cbb63baa6485e0f..c6134dcd2e04431f8e9f13f7b7bc4bf7617598c3 100644 (file)
@@ -111,6 +111,7 @@ hp  Hewlett Packard
 i2se   I2SE GmbH
 ibm    International Business Machines (IBM)
 idt    Integrated Device Technologies, Inc.
+ifi    Ingenieurburo Fur Ic-Technologie (I/F/I)
 iom    Iomega Corporation
 img    Imagination Technologies Ltd.
 ingenic        Ingenic Semiconductor
index c477af086e6569398d85b3f938e9f067b1976f7e..686a64bba775e0af9990cf305ab81f1ac4c8c278 100644 (file)
@@ -14,3 +14,10 @@ filesystem.
 efivarfs is typically mounted like this,
 
        mount -t efivarfs none /sys/firmware/efi/efivars
+
+Due to the presence of numerous firmware bugs where removing non-standard
+UEFI variables causes the system firmware to fail to POST, efivarfs
+files that are not well-known standardized variables are created
+as immutable files.  This doesn't prevent removal - "chattr -i" will work -
+but it does prevent this kind of failure from being accomplished
+accidentally.
index fde9fd06fa988b2eac60f10880973351e783fe37..843b045b4069a62c154bdf6c2723b3061bd81abd 100644 (file)
@@ -240,8 +240,8 @@ Table 1-2: Contents of the status files (as of 4.1)
  RssFile                     size of resident file mappings
  RssShmem                    size of resident shmem memory (includes SysV shm,
                              mapping of tmpfs and shared anonymous mappings)
- VmData                      size of data, stack, and text segments
- VmStk                       size of data, stack, and text segments
+ VmData                      size of private data segments
+ VmStk                       size of stack segments
  VmExe                       size of text segment
  VmLib                       size of shared library code
  VmPTE                       size of page table entries
@@ -356,7 +356,7 @@ address           perms offset  dev   inode      pathname
 a7cb1000-a7cb2000 ---p 00000000 00:00 0
 a7cb2000-a7eb2000 rw-p 00000000 00:00 0
 a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0          [stack:1001]
+a7eb3000-a7ed5000 rw-p 00000000 00:00 0
 a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
 a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
 a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
@@ -388,7 +388,6 @@ is not associated with a file:
 
  [heap]                   = the heap of the program
  [stack]                  = the stack of the main process
- [stack:1001]             = the stack of the thread with tid 1001
  [vdso]                   = the "virtual dynamic shared object",
                             the kernel system call handler
 
@@ -396,10 +395,8 @@ is not associated with a file:
 
 The /proc/PID/task/TID/maps is a view of the virtual memory from the viewpoint
 of the individual tasks of a process. In this file you will see a mapping marked
-as [stack] if that task sees it as a stack. This is a key difference from the
-content of /proc/PID/maps, where you will see all mappings that are being used
-as stack by all of those tasks. Hence, for the example above, the task-level
-map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
+as [stack] if that task sees it as a stack. Hence, for the example above, the
+task-level map, i.e. /proc/PID/task/TID/maps for thread 1001 will look like this:
 
 08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
 08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
index 87d40a72f6a1bec998be718138347a875c00117a..9a53c929f017d16527270bc2244352edf1d34cd8 100644 (file)
@@ -1496,6 +1496,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        could change it dynamically, usually by
                        /sys/module/printk/parameters/ignore_loglevel.
 
+       ignore_rlimit_data
+                       Ignore RLIMIT_DATA setting for data mappings,
+                       print warning at first misuse.  Can be changed via
+                       /sys/module/kernel/parameters/ignore_rlimit_data.
+
        ihash_entries=  [KNL]
                        Set number of hash buckets for inode cache.
 
@@ -4230,6 +4235,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        The default value of this parameter is determined by
                        the config option CONFIG_WQ_POWER_EFFICIENT_DEFAULT.
 
+       workqueue.debug_force_rr_cpu
+                       Workqueue used to implicitly guarantee that work
+                       items queued without explicit CPU specified are put
+                       on the local CPU.  This guarantee is no longer true
+                       and while local CPU is still preferred work items
+                       may be put on foreign CPUs.  This debug option
+                       forces round-robin CPU selection to flush out
+                       usages which depend on the now broken guarantee.
+                       When enabled, memory and cache locality will be
+                       impacted.
+
        x2apic_phys     [X86-64,APIC] Use x2apic physical mode instead of
                        default x2apic cluster mode on platforms
                        supporting x2apic.
index aa9c1f9313cda7edf9f6a73dcf0e17cd44eb0574..974e9c387d1e92edc01d51b4ed655a0882dc9ce6 100644 (file)
@@ -524,17 +524,14 @@ Bridge layer
 - port_join_bridge: bridge layer function invoked when a given switch port is
   added to a bridge, this function should be doing the necessary at the switch
   level to permit the joining port from being added to the relevant logical
-  domain for it to ingress/egress traffic with other members of the bridge. DSA
-  does nothing but calculate a bitmask of switch ports currently members of the
-  specified bridge being requested the join
+  domain for it to ingress/egress traffic with other members of the bridge.
 
 - port_leave_bridge: bridge layer function invoked when a given switch port is
   removed from a bridge, this function should be doing the necessary at the
   switch level to deny the leaving port from ingress/egress traffic from the
   remaining bridge members. When the port leaves the bridge, it should be aged
   out at the switch hardware for the switch to (re) learn MAC addresses behind
-  this port. DSA calculates the bitmask of ports still members of the bridge
-  being left
+  this port.
 
 - port_stp_update: bridge layer function invoked when a given switch port STP
   state is computed by the bridge layer and should be propagated to switch
@@ -545,20 +542,15 @@ Bridge layer
 Bridge VLAN filtering
 ---------------------
 
-- port_pvid_get: bridge layer function invoked when a Port-based VLAN ID is
-  queried for the given switch port
-
-- port_pvid_set: bridge layer function invoked when a Port-based VLAN ID needs
-  to be configured on the given switch port
-
 - port_vlan_add: bridge layer function invoked when a VLAN is configured
   (tagged or untagged) for the given switch port
 
 - port_vlan_del: bridge layer function invoked when a VLAN is removed from the
   given switch port
 
-- vlan_getnext: bridge layer function invoked to query the next configured VLAN
-  in the switch, i.e. returns the bitmaps of members and untagged ports
+- port_vlan_dump: bridge layer function invoked with a switchdev callback
+  function that the driver has to call for each VLAN the given port is a member
+  of. A switchdev object is used to carry the VID and bridge flags.
 
 - port_fdb_add: bridge layer function invoked when the bridge wants to install a
   Forwarding Database entry, the switch hardware should be programmed with the
index 24ce97f42d3552cc8ddd9a1de0855a1acb9bdf06..d5df40c75aa4e855c1c9aef5874bd428a001ca06 100644 (file)
@@ -1563,6 +1563,15 @@ temp_prefered_lft - INTEGER
        Preferred lifetime (in seconds) for temporary addresses.
        Default: 86400 (1 day)
 
+keep_addr_on_down - INTEGER
+       Keep all IPv6 addresses on an interface down event. If set static
+       global addresses with no expiration time are not flushed.
+         >0 : enabled
+          0 : system default
+         <0 : disabled
+
+       Default: 0 (addresses are removed)
+
 max_desync_factor - INTEGER
        Maximum value for DESYNC_FACTOR, which is a random value
        that ensures that clients don't synchronize with each
diff --git a/Documentation/networking/kcm.txt b/Documentation/networking/kcm.txt
new file mode 100644 (file)
index 0000000..3476ede
--- /dev/null
@@ -0,0 +1,285 @@
+Kernel Connection Mulitplexor
+-----------------------------
+
+Kernel Connection Multiplexor (KCM) is a mechanism that provides a message based
+interface over TCP for generic application protocols. With KCM an application
+can efficiently send and receive application protocol messages over TCP using
+datagram sockets.
+
+KCM implements an NxM multiplexor in the kernel as diagrammed below:
+
++------------+   +------------+   +------------+   +------------+
+| KCM socket |   | KCM socket |   | KCM socket |   | KCM socket |
++------------+   +------------+   +------------+   +------------+
+      |                 |               |                |
+      +-----------+     |               |     +----------+
+                  |     |               |     |
+               +----------------------------------+
+               |           Multiplexor            |
+               +----------------------------------+
+                 |   |           |           |  |
+       +---------+   |           |           |  ------------+
+       |             |           |           |              |
++----------+  +----------+  +----------+  +----------+ +----------+
+|  Psock   |  |  Psock   |  |  Psock   |  |  Psock   | |  Psock   |
++----------+  +----------+  +----------+  +----------+ +----------+
+      |              |           |            |             |
++----------+  +----------+  +----------+  +----------+ +----------+
+| TCP sock |  | TCP sock |  | TCP sock |  | TCP sock | | TCP sock |
++----------+  +----------+  +----------+  +----------+ +----------+
+
+KCM sockets
+-----------
+
+The KCM sockets provide the user interface to the muliplexor. All the KCM sockets
+bound to a multiplexor are considered to have equivalent function, and I/O
+operations in different sockets may be done in parallel without the need for
+synchronization between threads in userspace.
+
+Multiplexor
+-----------
+
+The multiplexor provides the message steering. In the transmit path, messages
+written on a KCM socket are sent atomically on an appropriate TCP socket.
+Similarly, in the receive path, messages are constructed on each TCP socket
+(Psock) and complete messages are steered to a KCM socket.
+
+TCP sockets & Psocks
+--------------------
+
+TCP sockets may be bound to a KCM multiplexor. A Psock structure is allocated
+for each bound TCP socket, this structure holds the state for constructing
+messages on receive as well as other connection specific information for KCM.
+
+Connected mode semantics
+------------------------
+
+Each multiplexor assumes that all attached TCP connections are to the same
+destination and can use the different connections for load balancing when
+transmitting. The normal send and recv calls (include sendmmsg and recvmmsg)
+can be used to send and receive messages from the KCM socket.
+
+Socket types
+------------
+
+KCM supports SOCK_DGRAM and SOCK_SEQPACKET socket types.
+
+Message delineation
+-------------------
+
+Messages are sent over a TCP stream with some application protocol message
+format that typically includes a header which frames the messages. The length
+of a received message can be deduced from the application protocol header
+(often just a simple length field).
+
+A TCP stream must be parsed to determine message boundaries. Berkeley Packet
+Filter (BPF) is used for this. When attaching a TCP socket to a multiplexor a
+BPF program must be specified. The program is called at the start of receiving
+a new message and is given an skbuff that contains the bytes received so far.
+It parses the message header and returns the length of the message. Given this
+information, KCM will construct the message of the stated length and deliver it
+to a KCM socket.
+
+TCP socket management
+---------------------
+
+When a TCP socket is attached to a KCM multiplexor data ready (POLLIN) and
+write space available (POLLOUT) events are handled by the multiplexor. If there
+is a state change (disconnection) or other error on a TCP socket, an error is
+posted on the TCP socket so that a POLLERR event happens and KCM discontinues
+using the socket. When the application gets the error notification for a
+TCP socket, it should unattach the socket from KCM and then handle the error
+condition (the typical response is to close the socket and create a new
+connection if necessary).
+
+KCM limits the maximum receive message size to be the size of the receive
+socket buffer on the attached TCP socket (the socket buffer size can be set by
+SO_RCVBUF). If the length of a new message reported by the BPF program is
+greater than this limit a corresponding error (EMSGSIZE) is posted on the TCP
+socket. The BPF program may also enforce a maximum messages size and report an
+error when it is exceeded.
+
+A timeout may be set for assembling messages on a receive socket. The timeout
+value is taken from the receive timeout of the attached TCP socket (this is set
+by SO_RCVTIMEO). If the timer expires before assembly is complete an error
+(ETIMEDOUT) is posted on the socket.
+
+User interface
+==============
+
+Creating a multiplexor
+----------------------
+
+A new multiplexor and initial KCM socket is created by a socket call:
+
+  socket(AF_KCM, type, protocol)
+
+  - type is either SOCK_DGRAM or SOCK_SEQPACKET
+  - protocol is KCMPROTO_CONNECTED
+
+Cloning KCM sockets
+-------------------
+
+After the first KCM socket is created using the socket call as described
+above, additional sockets for the multiplexor can be created by cloning
+a KCM socket. This is accomplished by an ioctl on a KCM socket:
+
+  /* From linux/kcm.h */
+  struct kcm_clone {
+        int fd;
+  };
+
+  struct kcm_clone info;
+
+  memset(&info, 0, sizeof(info));
+
+  err = ioctl(kcmfd, SIOCKCMCLONE, &info);
+
+  if (!err)
+    newkcmfd = info.fd;
+
+Attach transport sockets
+------------------------
+
+Attaching of transport sockets to a multiplexor is performed by calling an
+ioctl on a KCM socket for the multiplexor. e.g.:
+
+  /* From linux/kcm.h */
+  struct kcm_attach {
+        int fd;
+       int bpf_fd;
+  };
+
+  struct kcm_attach info;
+
+  memset(&info, 0, sizeof(info));
+
+  info.fd = tcpfd;
+  info.bpf_fd = bpf_prog_fd;
+
+  ioctl(kcmfd, SIOCKCMATTACH, &info);
+
+The kcm_attach structure contains:
+  fd: file descriptor for TCP socket being attached
+  bpf_prog_fd: file descriptor for compiled BPF program downloaded
+
+Unattach transport sockets
+--------------------------
+
+Unattaching a transport socket from a multiplexor is straightforward. An
+"unattach" ioctl is done with the kcm_unattach structure as the argument:
+
+  /* From linux/kcm.h */
+  struct kcm_unattach {
+        int fd;
+  };
+
+  struct kcm_unattach info;
+
+  memset(&info, 0, sizeof(info));
+
+  info.fd = cfd;
+
+  ioctl(fd, SIOCKCMUNATTACH, &info);
+
+Disabling receive on KCM socket
+-------------------------------
+
+A setsockopt is used to disable or enable receiving on a KCM socket.
+When receive is disabled, any pending messages in the socket's
+receive buffer are moved to other sockets. This feature is useful
+if an application thread knows that it will be doing a lot of
+work on a request and won't be able to service new messages for a
+while. Example use:
+
+  int val = 1;
+
+  setsockopt(kcmfd, SOL_KCM, KCM_RECV_DISABLE, &val, sizeof(val))
+
+BFP programs for message delineation
+------------------------------------
+
+BPF programs can be compiled using the BPF LLVM backend. For exmple,
+the BPF program for parsing Thrift is:
+
+  #include "bpf.h" /* for __sk_buff */
+  #include "bpf_helpers.h" /* for load_word intrinsic */
+
+  SEC("socket_kcm")
+  int bpf_prog1(struct __sk_buff *skb)
+  {
+       return load_word(skb, 0) + 4;
+  }
+
+  char _license[] SEC("license") = "GPL";
+
+Use in applications
+===================
+
+KCM accelerates application layer protocols. Specifically, it allows
+applications to use a message based interface for sending and receiving
+messages. The kernel provides necessary assurances that messages are sent
+and received atomically. This relieves much of the burden applications have
+in mapping a message based protocol onto the TCP stream. KCM also make
+application layer messages a unit of work in the kernel for the purposes of
+steerng and scheduling, which in turn allows a simpler networking model in
+multithreaded applications.
+
+Configurations
+--------------
+
+In an Nx1 configuration, KCM logically provides multiple socket handles
+to the same TCP connection. This allows parallelism between in I/O
+operations on the TCP socket (for instance copyin and copyout of data is
+parallelized). In an application, a KCM socket can be opened for each
+processing thread and inserted into the epoll (similar to how SO_REUSEPORT
+is used to allow multiple listener sockets on the same port).
+
+In a MxN configuration, multiple connections are established to the
+same destination. These are used for simple load balancing.
+
+Message batching
+----------------
+
+The primary purpose of KCM is load balancing between KCM sockets and hence
+threads in a nominal use case. Perfect load balancing, that is steering
+each received message to a different KCM socket or steering each sent
+message to a different TCP socket, can negatively impact performance
+since this doesn't allow for affinities to be established. Balancing
+based on groups, or batches of messages, can be beneficial for performance.
+
+On transmit, there are three ways an application can batch (pipeline)
+messages on a KCM socket.
+  1) Send multiple messages in a single sendmmsg.
+  2) Send a group of messages each with a sendmsg call, where all messages
+     except the last have MSG_BATCH in the flags of sendmsg call.
+  3) Create "super message" composed of multiple messages and send this
+     with a single sendmsg.
+
+On receive, the KCM module attempts to queue messages received on the
+same KCM socket during each TCP ready callback. The targeted KCM socket
+changes at each receive ready callback on the KCM socket. The application
+does not need to configure this.
+
+Error handling
+--------------
+
+An application should include a thread to monitor errors raised on
+the TCP connection. Normally, this will be done by placing each
+TCP socket attached to a KCM multiplexor in epoll set for POLLERR
+event. If an error occurs on an attached TCP socket, KCM sets an EPIPE
+on the socket thus waking up the application thread. When the application
+sees the error (which may just be a disconnect) it should unattach the
+socket from KCM and then close it. It is assumed that once an error is
+posted on the TCP socket the data stream is unrecoverable (i.e. an error
+may have occurred in in the middle of receiving a messssge).
+
+TCP connection monitoring
+-------------------------
+
+In KCM there is no means to correlate a message to the TCP socket that
+was used to send or receive the message (except in the case there is
+only one attached TCP socket). However, the application does retain
+an open file descriptor to the socket so it will be able to get statistics
+from the socket which can be used in detecting issues (such as high
+retransmissions on the socket).
index 3a930072b161fd51b3b1d007daac673526609dc2..ec8f934c2eb240f93a54b0044faadd913e7855f8 100644 (file)
@@ -28,6 +28,23 @@ radiotap headers and used to control injection:
    IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
                                  an ACK even if it is a unicast frame
 
+ * IEEE80211_RADIOTAP_RATE
+
+   legacy rate for the transmission (only for devices without own rate control)
+
+ * IEEE80211_RADIOTAP_MCS
+
+   HT rate for the transmission (only for devices without own rate control).
+   Also some flags are parsed
+
+   IEEE80211_TX_RC_SHORT_GI: use short guard interval
+   IEEE80211_TX_RC_40_MHZ_WIDTH: send in HT40 mode
+
+ * IEEE80211_RADIOTAP_DATA_RETRIES
+
+   number of retries when either IEEE80211_RADIOTAP_RATE or
+   IEEE80211_RADIOTAP_MCS was used
+
 The injection code can also skip all other currently defined radiotap fields
 facilitating replay of captured radiotap headers directly.
 
diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
deleted file mode 100644 (file)
index 54f1047..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-This file documents how to use memory mapped I/O with netlink.
-
-Author: Patrick McHardy <kaber@trash.net>
-
-Overview
---------
-
-Memory mapped netlink I/O can be used to increase throughput and decrease
-overhead of unicast receive and transmit operations. Some netlink subsystems
-require high throughput, these are mainly the netfilter subsystems
-nfnetlink_queue and nfnetlink_log, but it can also help speed up large
-dump operations of f.i. the routing database.
-
-Memory mapped netlink I/O used two circular ring buffers for RX and TX which
-are mapped into the processes address space.
-
-The RX ring is used by the kernel to directly construct netlink messages into
-user-space memory without copying them as done with regular socket I/O,
-additionally as long as the ring contains messages no recvmsg() or poll()
-syscalls have to be issued by user-space to get more message.
-
-The TX ring is used to process messages directly from user-space memory, the
-kernel processes all messages contained in the ring using a single sendmsg()
-call.
-
-Usage overview
---------------
-
-In order to use memory mapped netlink I/O, user-space needs three main changes:
-
-- ring setup
-- conversion of the RX path to get messages from the ring instead of recvmsg()
-- conversion of the TX path to construct messages into the ring
-
-Ring setup is done using setsockopt() to provide the ring parameters to the
-kernel, then a call to mmap() to map the ring into the processes address space:
-
-- setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &params, sizeof(params));
-- setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &params, sizeof(params));
-- ring = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
-
-Usage of either ring is optional, but even if only the RX ring is used the
-mapping still needs to be writable in order to update the frame status after
-processing.
-
-Conversion of the reception path involves calling poll() on the file
-descriptor, once the socket is readable the frames from the ring are
-processed in order until no more messages are available, as indicated by
-a status word in the frame header.
-
-On kernel side, in order to make use of memory mapped I/O on receive, the
-originating netlink subsystem needs to support memory mapped I/O, otherwise
-it will use an allocated socket buffer as usual and the contents will be
- copied to the ring on transmission, nullifying most of the performance gains.
-Dumps of kernel databases automatically support memory mapped I/O.
-
-Conversion of the transmit path involves changing message construction to
-use memory from the TX ring instead of (usually) a buffer declared on the
-stack and setting up the frame header appropriately. Optionally poll() can
-be used to wait for free frames in the TX ring.
-
-Structured and definitions for using memory mapped I/O are contained in
-<linux/netlink.h>.
-
-RX and TX rings
-----------------
-
-Each ring contains a number of continuous memory blocks, containing frames of
-fixed size dependent on the parameters used for ring setup.
-
-Ring:  [ block 0 ]
-               [ frame 0 ]
-               [ frame 1 ]
-       [ block 1 ]
-               [ frame 2 ]
-               [ frame 3 ]
-       ...
-       [ block n ]
-               [ frame 2 * n ]
-               [ frame 2 * n + 1 ]
-
-The blocks are only visible to the kernel, from the point of view of user-space
-the ring just contains the frames in a continuous memory zone.
-
-The ring parameters used for setting up the ring are defined as follows:
-
-struct nl_mmap_req {
-       unsigned int    nm_block_size;
-       unsigned int    nm_block_nr;
-       unsigned int    nm_frame_size;
-       unsigned int    nm_frame_nr;
-};
-
-Frames are grouped into blocks, where each block is a continuous region of memory
-and holds nm_block_size / nm_frame_size frames. The total number of frames in
-the ring is nm_frame_nr. The following invariants hold:
-
-- frames_per_block = nm_block_size / nm_frame_size
-
-- nm_frame_nr = frames_per_block * nm_block_nr
-
-Some parameters are constrained, specifically:
-
-- nm_block_size must be a multiple of the architectures memory page size.
-  The getpagesize() function can be used to get the page size.
-
-- nm_frame_size must be equal or larger to NL_MMAP_HDRLEN, IOW a frame must be
-  able to hold at least the frame header
-
-- nm_frame_size must be smaller or equal to nm_block_size
-
-- nm_frame_size must be a multiple of NL_MMAP_MSG_ALIGNMENT
-
-- nm_frame_nr must equal the actual number of frames as specified above.
-
-When the kernel can't allocate physically continuous memory for a ring block,
-it will fall back to use physically discontinuous memory. This might affect
-performance negatively, in order to avoid this the nm_frame_size parameter
-should be chosen to be as small as possible for the required frame size and
-the number of blocks should be increased instead.
-
-Ring frames
-------------
-
-Each frames contain a frame header, consisting of a synchronization word and some
-meta-data, and the message itself.
-
-Frame: [ header message ]
-
-The frame header is defined as follows:
-
-struct nl_mmap_hdr {
-       unsigned int    nm_status;
-       unsigned int    nm_len;
-       __u32           nm_group;
-       /* credentials */
-       __u32           nm_pid;
-       __u32           nm_uid;
-       __u32           nm_gid;
-};
-
-- nm_status is used for synchronizing processing between the kernel and user-
-  space and specifies ownership of the frame as well as the operation to perform
-
-- nm_len contains the length of the message contained in the data area
-
-- nm_group specified the destination multicast group of message
-
-- nm_pid, nm_uid and nm_gid contain the netlink pid, UID and GID of the sending
-  process. These values correspond to the data available using SOCK_PASSCRED in
-  the SCM_CREDENTIALS cmsg.
-
-The possible values in the status word are:
-
-- NL_MMAP_STATUS_UNUSED:
-       RX ring:        frame belongs to the kernel and contains no message
-                       for user-space. Approriate action is to invoke poll()
-                       to wait for new messages.
-
-       TX ring:        frame belongs to user-space and can be used for
-                       message construction.
-
-- NL_MMAP_STATUS_RESERVED:
-       RX ring only:   frame is currently used by the kernel for message
-                       construction and contains no valid message yet.
-                       Appropriate action is to invoke poll() to wait for
-                       new messages.
-
-- NL_MMAP_STATUS_VALID:
-       RX ring:        frame contains a valid message. Approriate action is
-                       to process the message and release the frame back to
-                       the kernel by setting the status to
-                       NL_MMAP_STATUS_UNUSED or queue the frame by setting the
-                       status to NL_MMAP_STATUS_SKIP.
-
-       TX ring:        the frame contains a valid message from user-space to
-                       be processed by the kernel. After completing processing
-                       the kernel will release the frame back to user-space by
-                       setting the status to NL_MMAP_STATUS_UNUSED.
-
-- NL_MMAP_STATUS_COPY:
-       RX ring only:   a message is ready to be processed but could not be
-                       stored in the ring, either because it exceeded the
-                       frame size or because the originating subsystem does
-                       not support memory mapped I/O. Appropriate action is
-                       to invoke recvmsg() to receive the message and release
-                       the frame back to the kernel by setting the status to
-                       NL_MMAP_STATUS_UNUSED.
-
-- NL_MMAP_STATUS_SKIP:
-       RX ring only:   user-space queued the message for later processing, but
-                       processed some messages following it in the ring. The
-                       kernel should skip this frame when looking for unused
-                       frames.
-
-The data area of a frame begins at a offset of NL_MMAP_HDRLEN relative to the
-frame header.
-
-TX limitations
---------------
-
-As of Jan 2015 the message is always copied from the ring frame to an
-allocated buffer due to unresolved security concerns.
-See commit 4682a0358639b29cf ("netlink: Always copy on mmap TX.").
-
-Example
--------
-
-Ring setup:
-
-       unsigned int block_size = 16 * getpagesize();
-       struct nl_mmap_req req = {
-               .nm_block_size          = block_size,
-               .nm_block_nr            = 64,
-               .nm_frame_size          = 16384,
-               .nm_frame_nr            = 64 * block_size / 16384,
-       };
-       unsigned int ring_size;
-       void *rx_ring, *tx_ring;
-
-       /* Configure ring parameters */
-       if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0)
-               exit(1);
-       if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0)
-               exit(1)
-
-       /* Calculate size of each individual ring */
-       ring_size = req.nm_block_nr * req.nm_block_size;
-
-       /* Map RX/TX rings. The TX ring is located after the RX ring */
-       rx_ring = mmap(NULL, 2 * ring_size, PROT_READ | PROT_WRITE,
-                      MAP_SHARED, fd, 0);
-       if ((long)rx_ring == -1L)
-               exit(1);
-       tx_ring = rx_ring + ring_size:
-
-Message reception:
-
-This example assumes some ring parameters of the ring setup are available.
-
-       unsigned int frame_offset = 0;
-       struct nl_mmap_hdr *hdr;
-       struct nlmsghdr *nlh;
-       unsigned char buf[16384];
-       ssize_t len;
-
-       while (1) {
-               struct pollfd pfds[1];
-
-               pfds[0].fd      = fd;
-               pfds[0].events  = POLLIN | POLLERR;
-               pfds[0].revents = 0;
-
-               if (poll(pfds, 1, -1) < 0 && errno != -EINTR)
-                       exit(1);
-
-               /* Check for errors. Error handling omitted */
-               if (pfds[0].revents & POLLERR)
-                       <handle error>
-
-               /* If no new messages, poll again */
-               if (!(pfds[0].revents & POLLIN))
-                       continue;
-
-               /* Process all frames */
-               while (1) {
-                       /* Get next frame header */
-                       hdr = rx_ring + frame_offset;
-
-                       if (hdr->nm_status == NL_MMAP_STATUS_VALID) {
-                               /* Regular memory mapped frame */
-                               nlh = (void *)hdr + NL_MMAP_HDRLEN;
-                               len = hdr->nm_len;
-
-                               /* Release empty message immediately. May happen
-                                * on error during message construction.
-                                */
-                               if (len == 0)
-                                       goto release;
-                       } else if (hdr->nm_status == NL_MMAP_STATUS_COPY) {
-                               /* Frame queued to socket receive queue */
-                               len = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
-                               if (len <= 0)
-                                       break;
-                               nlh = buf;
-                       } else
-                               /* No more messages to process, continue polling */
-                               break;
-
-                       process_msg(nlh);
-release:
-                       /* Release frame back to the kernel */
-                       hdr->nm_status = NL_MMAP_STATUS_UNUSED;
-
-                       /* Advance frame offset to next frame */
-                       frame_offset = (frame_offset + frame_size) % ring_size;
-               }
-       }
-
-Message transmission:
-
-This example assumes some ring parameters of the ring setup are available.
-A single message is constructed and transmitted, to send multiple messages
-at once they would be constructed in consecutive frames before a final call
-to sendto().
-
-       unsigned int frame_offset = 0;
-       struct nl_mmap_hdr *hdr;
-       struct nlmsghdr *nlh;
-       struct sockaddr_nl addr = {
-               .nl_family      = AF_NETLINK,
-       };
-
-       hdr = tx_ring + frame_offset;
-       if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
-               /* No frame available. Use poll() to avoid. */
-               exit(1);
-
-       nlh = (void *)hdr + NL_MMAP_HDRLEN;
-
-       /* Build message */
-       build_message(nlh);
-
-       /* Fill frame header: length and status need to be set */
-       hdr->nm_len     = nlh->nlmsg_len;
-       hdr->nm_status  = NL_MMAP_STATUS_VALID;
-
-       if (sendto(fd, NULL, 0, 0, &addr, sizeof(addr)) < 0)
-               exit(1);
-
-       /* Advance frame offset to next frame */
-       frame_offset = (frame_offset + frame_size) % ring_size;
index e1a3d59bbe0f5f7e75889776dfb0979a7ef20cff..9d219d856d46bf3235ce99c40e3a26454c51adfc 100644 (file)
@@ -19,9 +19,7 @@ to N*N if you use a connection-oriented socket transport like TCP.
 
 RDS is not Infiniband-specific; it was designed to support different
 transports.  The current implementation used to support RDS over TCP as well
-as IB. Work is in progress to support RDS over iWARP, and using DCE to
-guarantee no dropped packets on Ethernet, it may be possible to use RDS over
-UDP in the future.
+as IB.
 
 The high-level semantics of RDS from the application's point of view are
 
index 2ee6ef9a6554d600088ae572b3256ffe44e51d08..1f0c27049340d9603ec90fa1694d4e0e14dbb5c7 100644 (file)
@@ -83,6 +83,8 @@ rfkill drivers that control devices that can be hard-blocked unless they also
 assign the poll_hw_block() callback (then the rfkill core will poll the
 device). Don't do this unless you cannot get the event in any other way.
 
+RFKill provides per-switch LED triggers, which can be used to drive LEDs
+according to the switch state (LED_FULL when blocked, LED_OFF otherwise).
 
 
 5. Userspace support
index 767392ffd31e1451aa14da7453fc581264b4491c..a484d2c109d7ff0689d8997c04ce477ca6e79d1c 100644 (file)
@@ -1,9 +1,7 @@
                High Precision Event Timer Driver for Linux
 
 The High Precision Event Timer (HPET) hardware follows a specification
-by Intel and Microsoft which can be found at
-
-       http://www.intel.com/hardwaredesign/hpetspec_1.pdf
+by Intel and Microsoft, revision 1.
 
 Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
 and up to 32 comparators.  Normally three or more comparators are provided,
index 9f9ec9f76039404a15114c97fe67535fe41fa88c..4e4b6f10d8410f84d8ea64ac51c68a6932bf2158 100644 (file)
@@ -400,3 +400,7 @@ wm8350_wdt:
 nowayout: Watchdog cannot be stopped once started
        (default=kernel config parameter)
 -------------------------------------------------
+sun4v_wdt:
+timeout_ms: Watchdog timeout in milliseconds 1..180000, default=60000)
+nowayout: Watchdog cannot be stopped once started
+-------------------------------------------------
index 4dd2d37e0f71fdd88cbe8062c49eb8550fb0f033..b70294ea7d634a0bf37ce5dcb52a00ea14cb87f6 100644 (file)
@@ -151,7 +151,7 @@ S:  Maintained
 F:     drivers/scsi/53c700*
 
 6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
-M:     Alexander Aring <alex.aring@gmail.com>
+M:     Alexander Aring <aar@pengutronix.de>
 M:     Jukka Rissanen <jukka.rissanen@linux.intel.com>
 L:     linux-bluetooth@vger.kernel.org
 L:     linux-wpan@vger.kernel.org
@@ -223,9 +223,7 @@ F:  drivers/scsi/aacraid/
 
 ABI/API
 L:     linux-api@vger.kernel.org
-F:     Documentation/ABI/
 F:     include/linux/syscalls.h
-F:     include/uapi/
 F:     kernel/sys_ni.c
 
 ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
@@ -686,13 +684,6 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch>
 S:     Supported
 F:     drivers/macintosh/ams/
 
-AMSO1100 RNIC DRIVER
-M:     Tom Tucker <tom@opengridcomputing.com>
-M:     Steve Wise <swise@opengridcomputing.com>
-L:     linux-rdma@vger.kernel.org
-S:     Maintained
-F:     drivers/infiniband/hw/amso1100/
-
 ANALOG DEVICES INC AD9389B DRIVER
 M:     Hans Verkuil <hans.verkuil@cisco.com>
 L:     linux-media@vger.kernel.org
@@ -929,17 +920,24 @@ M:        Emilio López <emilio@elopez.com.ar>
 S:     Maintained
 F:     drivers/clk/sunxi/
 
-ARM/Amlogic MesonX SoC support
+ARM/Amlogic Meson SoC support
 M:     Carlo Caione <carlo@caione.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-meson@googlegroups.com
+W:     http://linux-meson.com/
 S:     Maintained
-F:     drivers/media/rc/meson-ir.c
-N:     meson[x68]
+F:     arch/arm/mach-meson/
+F:     arch/arm/boot/dts/meson*
+N:     meson
 
 ARM/Annapurna Labs ALPINE ARCHITECTURE
 M:     Tsahee Zidenberg <tsahee@annapurnalabs.com>
+M:     Antoine Tenart <antoine.tenart@free-electrons.com>
 S:     Maintained
 F:     arch/arm/mach-alpine/
+F:     arch/arm/boot/dts/alpine*
+F:     arch/arm64/boot/dts/al/
+F:     drivers/*/*alpine*
 
 ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
 M:     Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -967,6 +965,8 @@ M:  Rob Herring <robh@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-highbank/
+F:     arch/arm/boot/dts/highbank.dts
+F:     arch/arm/boot/dts/ecx-*.dts*
 
 ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
 M:     Krzysztof Halasa <khalasa@piap.pl>
@@ -1042,6 +1042,7 @@ M:        Barry Song <baohua@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/baohua/linux.git
 S:     Maintained
+F:     arch/arm/boot/dts/prima2*
 F:     arch/arm/mach-prima2/
 F:     drivers/clk/sirf/
 F:     drivers/clocksource/timer-prima2.c
@@ -1143,6 +1144,10 @@ W:       http://www.hisilicon.com
 S:     Supported
 T:     git git://github.com/hisilicon/linux-hisi.git
 F:     arch/arm/mach-hisi/
+F:     arch/arm/boot/dts/hi3*
+F:     arch/arm/boot/dts/hip*
+F:     arch/arm/boot/dts/hisi*
+F:     arch/arm64/boot/dts/hisilicon/
 
 ARM/HP JORNADA 7XX MACHINE SUPPORT
 M:     Kristoffer Ericson <kristoffer.ericson@gmail.com>
@@ -1219,6 +1224,7 @@ M:        Santosh Shilimkar <ssantosh@kernel.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-keystone/
+F:     arch/arm/boot/dts/k2*
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
 
 ARM/TEXAS INSTRUMENT KEYSTONE CLOCK FRAMEWORK
@@ -1287,6 +1293,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-berlin/
 F:     arch/arm/boot/dts/berlin*
+F:     arch/arm64/boot/dts/marvell/berlin*
 
 
 ARM/Marvell Dove/MV78xx0/Orion SOC support
@@ -1425,6 +1432,7 @@ S:        Maintained
 F:     arch/arm/boot/dts/qcom-*.dts
 F:     arch/arm/boot/dts/qcom-*.dtsi
 F:     arch/arm/mach-qcom/
+F:     arch/arm64/boot/dts/qcom/*
 F:     drivers/soc/qcom/
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
@@ -1441,8 +1449,8 @@ S:        Maintained
 ARM/RENESAS ARM64 ARCHITECTURE
 M:     Simon Horman <horms@verge.net.au>
 M:     Magnus Damm <magnus.damm@gmail.com>
-L:     linux-sh@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-sh/list/
+L:     linux-renesas-soc@vger.kernel.org
+Q:     http://patchwork.kernel.org/project/linux-renesas-soc/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas.git next
 S:     Supported
 F:     arch/arm64/boot/dts/renesas/
@@ -1484,6 +1492,8 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/boot/dts/s3c*
+F:     arch/arm/boot/dts/s5p*
+F:     arch/arm/boot/dts/samsung*
 F:     arch/arm/boot/dts/exynos*
 F:     arch/arm64/boot/dts/exynos/
 F:     arch/arm/plat-samsung/
@@ -1563,6 +1573,7 @@ S:        Maintained
 F:     arch/arm/mach-socfpga/
 F:     arch/arm/boot/dts/socfpga*
 F:     arch/arm/configs/socfpga_defconfig
+F:     arch/arm64/boot/dts/altera/
 W:     http://www.rocketboards.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dinguyen/linux.git
 
@@ -1716,7 +1727,7 @@ M:        Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/boot/dts/vexpress*
-F:     arch/arm64/boot/dts/arm/vexpress*
+F:     arch/arm64/boot/dts/arm/
 F:     arch/arm/mach-vexpress/
 F:     */*/vexpress*
 F:     */*/*/vexpress*
@@ -2148,6 +2159,7 @@ M:        Simon Wunderlich <sw@simonwunderlich.de>
 M:     Antonio Quartulli <a@unstable.cc>
 L:     b.a.t.m.a.n@lists.open-mesh.org
 W:     https://www.open-mesh.org/
+Q:     https://patchwork.open-mesh.org/project/batman/list/
 S:     Maintained
 F:     net/batman-adv/
 
@@ -2343,6 +2355,7 @@ F:        arch/arm/mach-bcm/
 F:     arch/arm/boot/dts/bcm113*
 F:     arch/arm/boot/dts/bcm216*
 F:     arch/arm/boot/dts/bcm281*
+F:     arch/arm64/boot/dts/broadcom/
 F:     arch/arm/configs/bcm_defconfig
 F:     drivers/mmc/host/sdhci-bcm-kona.c
 F:     drivers/clocksource/bcm_kona_timer.c
@@ -2357,14 +2370,6 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git
 S:     Maintained
 N:     bcm2835
 
-BROADCOM BCM33XX MIPS ARCHITECTURE
-M:     Kevin Cernekee <cernekee@gmail.com>
-L:     linux-mips@linux-mips.org
-S:     Maintained
-F:     arch/mips/bcm3384/*
-F:     arch/mips/include/asm/mach-bcm3384/*
-F:     arch/mips/kernel/*bmips*
-
 BROADCOM BCM47XX MIPS ARCHITECTURE
 M:     Hauke Mehrtens <hauke@hauke-m.de>
 M:     RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
@@ -3446,9 +3451,8 @@ S:        Maintained
 F:     drivers/usb/dwc2/
 
 DESIGNWARE USB3 DRD IP DRIVER
-M:     Felipe Balbi <balbi@ti.com>
+M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
-L:     linux-omap@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
 F:     drivers/usb/dwc3/
@@ -3502,6 +3506,14 @@ F:       include/linux/device-mapper.h
 F:     include/linux/dm-*.h
 F:     include/uapi/linux/dm-*.h
 
+DEVLINK
+M:     Jiri Pirko <jiri@mellanox.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     net/core/devlink.c
+F:     include/net/devlink.h
+F:     include/uapi/linux/devlink.h
+
 DIALOG SEMICONDUCTOR DRIVERS
 M:     Support Opensource <support.opensource@diasemi.com>
 W:     http://www.dialog-semiconductor.com/products
@@ -4185,13 +4197,6 @@ W:       http://aeschi.ch.eu.org/efs/
 S:     Orphan
 F:     fs/efs/
 
-EHCA (IBM GX bus InfiniBand adapter) DRIVER
-M:     Hoang-Nam Nguyen <hnguyen@de.ibm.com>
-M:     Christoph Raisch <raisch@de.ibm.com>
-L:     linux-rdma@vger.kernel.org
-S:     Supported
-F:     drivers/infiniband/hw/ehca/
-
 EHEA (IBM pSeries eHEA 10Gb ethernet adapter) DRIVER
 M:     Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
 L:     netdev@vger.kernel.org
@@ -4523,6 +4528,12 @@ L:       linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/dma/fsldma.*
 
+FREESCALE GPMI NAND DRIVER
+M:     Han Xu <han.xu@nxp.com>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/nand/gpmi-nand/*
+
 FREESCALE I2C CPM DRIVER
 M:     Jochen Friedrich <jochen@scram.de>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -4539,7 +4550,7 @@ F:        include/linux/platform_data/video-imxfb.h
 F:     drivers/video/fbdev/imxfb.c
 
 FREESCALE QUAD SPI DRIVER
-M:     Han Xu <han.xu@freescale.com>
+M:     Han Xu <han.xu@nxp.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 F:     drivers/mtd/spi-nor/fsl-quadspi.c
@@ -4553,6 +4564,15 @@ S:       Maintained
 F:     drivers/net/ethernet/freescale/fs_enet/
 F:     include/linux/fs_enet_pd.h
 
+FREESCALE IMX / MXC FEC DRIVER
+M:     Fugang Duan <fugang.duan@nxp.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/freescale/fec_main.c
+F:     drivers/net/ethernet/freescale/fec_ptp.c
+F:     drivers/net/ethernet/freescale/fec.h
+F:     Documentation/devicetree/bindings/net/fsl-fec.txt
+
 FREESCALE QUICC ENGINE LIBRARY
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Orphan
@@ -5425,10 +5445,11 @@ S:      Supported
 F:     drivers/idle/i7300_idle.c
 
 IEEE 802.15.4 SUBSYSTEM
-M:     Alexander Aring <alex.aring@gmail.com>
+M:     Alexander Aring <aar@pengutronix.de>
 L:     linux-wpan@vger.kernel.org
-W:     https://github.com/linux-wpan
-T:     git git://github.com/linux-wpan/linux-wpan-next.git
+W:     http://wpan.cakelab.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
 S:     Maintained
 F:     net/ieee802154/
 F:     net/mac802154/
@@ -5810,12 +5831,6 @@ M:       Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
 S:     Maintained
 F:     net/ipv4/netfilter/ipt_MASQUERADE.c
 
-IPATH DRIVER
-M:     Mike Marciniszyn <infinipath@intel.com>
-L:     linux-rdma@vger.kernel.org
-S:     Maintained
-F:     drivers/staging/rdma/ipath/
-
 IPMI SUBSYSTEM
 M:     Corey Minyard <minyard@acm.org>
 L:     openipmi-developer@lists.sourceforge.net (moderated for non-subscribers)
@@ -6145,7 +6160,7 @@ F:        include/uapi/linux/sunrpc/
 
 KERNEL SELFTEST FRAMEWORK
 M:     Shuah Khan <shuahkh@osg.samsung.com>
-L:     linux-api@vger.kernel.org
+L:     linux-kselftest@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/shuah/linux-kselftest
 S:     Maintained
 F:     tools/testing/selftests
@@ -6775,6 +6790,7 @@ S:        Maintained
 F:     Documentation/networking/mac80211-injection.txt
 F:     include/net/mac80211.h
 F:     net/mac80211/
+F:     drivers/net/wireless/mac80211_hwsim.[ch]
 
 MACVLAN DRIVER
 M:     Patrick McHardy <kaber@trash.net>
@@ -7019,6 +7035,13 @@ F:       include/uapi/linux/meye.h
 F:     include/uapi/linux/ivtv*
 F:     include/uapi/linux/uvcvideo.h
 
+MEDIATEK ETHERNET DRIVER
+M:     Felix Fietkau <nbd@openwrt.org>
+M:     John Crispin <blogic@openwrt.org>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ethernet/mediatek/
+
 MEDIATEK MT7601U WIRELESS LAN DRIVER
 M:     Jakub Kicinski <kubakici@wp.pl>
 L:     linux-wireless@vger.kernel.org
@@ -7371,7 +7394,7 @@ F:        drivers/tty/isicom.c
 F:     include/linux/isicom.h
 
 MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
-M:     Felipe Balbi <balbi@ti.com>
+M:     Bin Liu <b-liu@ti.com>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
@@ -7507,7 +7530,6 @@ F:        net/netrom/
 
 NETRONOME ETHERNET DRIVERS
 M:     Jakub Kicinski <jakub.kicinski@netronome.com>
-M:     Rolf Neugebauer <rolf.neugebauer@netronome.com>
 L:     oss-drivers@netronome.com
 S:     Maintained
 F:     drivers/net/ethernet/netronome/
@@ -7702,13 +7724,13 @@ S:      Maintained
 F:     arch/nios2/
 
 NOKIA N900 POWER SUPPLY DRIVERS
-M:     Pali Rohár <pali.rohar@gmail.com>
-S:     Maintained
+R:     Pali Rohár <pali.rohar@gmail.com>
 F:     include/linux/power/bq2415x_charger.h
 F:     include/linux/power/bq27xxx_battery.h
 F:     include/linux/power/isp1704_charger.h
 F:     drivers/power/bq2415x_charger.c
 F:     drivers/power/bq27xxx_battery.c
+F:     drivers/power/bq27xxx_battery_i2c.c
 F:     drivers/power/isp1704_charger.c
 F:     drivers/power/rx51_battery.c
 
@@ -7939,11 +7961,9 @@ F:       drivers/media/platform/omap3isp/
 F:     drivers/staging/media/omap4iss/
 
 OMAP USB SUPPORT
-M:     Felipe Balbi <balbi@ti.com>
 L:     linux-usb@vger.kernel.org
 L:     linux-omap@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
-S:     Maintained
+S:     Orphan
 F:     drivers/usb/*/*omap*
 F:     arch/arm/*omap*/usb*
 
@@ -8818,6 +8838,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/hzhuang1/linux.git
 T:     git git://github.com/rjarzmik/linux.git
 S:     Maintained
+F:     arch/arm/boot/dts/pxa*
 F:     arch/arm/mach-pxa/
 F:     drivers/dma/pxa*
 F:     drivers/pcmcia/pxa2xx*
@@ -8847,6 +8868,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/hzhuang1/linux.git
 T:     git git://git.linaro.org/people/ycmiao/pxa-linux.git
 S:     Maintained
+F:     arch/arm/boot/dts/mmp*
 F:     arch/arm/mach-mmp/
 
 PXA MMCI DRIVER
@@ -9080,10 +9102,14 @@ S:      Maintained
 F:     drivers/net/ethernet/rdc/r6040.c
 
 RDS - RELIABLE DATAGRAM SOCKETS
-M:     Chien Yen <chien.yen@oracle.com>
+M:     Santosh Shilimkar <santosh.shilimkar@oracle.com>
+L:     netdev@vger.kernel.org
+L:     linux-rdma@vger.kernel.org
 L:     rds-devel@oss.oracle.com (moderated for non-subscribers)
+W:     https://oss.oracle.com/projects/rds/
 S:     Supported
 F:     net/rds/
+F:     Documentation/networking/rds.txt
 
 READ-COPY UPDATE (RCU)
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
@@ -9573,6 +9599,12 @@ M:       Andreas Noever <andreas.noever@gmail.com>
 S:     Maintained
 F:     drivers/thunderbolt/
 
+TI BQ27XXX POWER SUPPLY DRIVER
+R:     Andrew F. Davis <afd@ti.com>
+F:     include/linux/power/bq27xxx_battery.h
+F:     drivers/power/bq27xxx_battery.c
+F:     drivers/power/bq27xxx_battery_i2c.c
+
 TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
 M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
@@ -9794,10 +9826,11 @@ S:      Supported
 F:     drivers/scsi/be2iscsi/
 
 Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER
-M:     Sathya Perla <sathya.perla@avagotech.com>
-M:     Ajit Khaparde <ajit.khaparde@avagotech.com>
-M:     Padmanabh Ratnakar <padmanabh.ratnakar@avagotech.com>
-M:     Sriharsha Basavapatna <sriharsha.basavapatna@avagotech.com>
+M:     Sathya Perla <sathya.perla@broadcom.com>
+M:     Ajit Khaparde <ajit.khaparde@broadcom.com>
+M:     Padmanabh Ratnakar <padmanabh.ratnakar@broadcom.com>
+M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
+M:     Somnath Kotur <somnath.kotur@broadcom.com>
 L:     netdev@vger.kernel.org
 W:     http://www.emulex.com
 S:     Supported
@@ -10159,6 +10192,7 @@ S:      Supported
 F:     drivers/media/pci/solo6x10/
 
 SOFTWARE RAID (Multiple Disks) SUPPORT
+M:     Shaohua Li <shli@kernel.org>
 L:     linux-raid@vger.kernel.org
 T:     git git://neil.brown.name/md
 S:     Supported
@@ -10292,6 +10326,7 @@ L:      spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
+F:     arch/arm/boot/dts/spear*
 F:     arch/arm/mach-spear/
 
 SPEAR CLOCK FRAMEWORK SUPPORT
@@ -11319,7 +11354,7 @@ F:      Documentation/usb/ehci.txt
 F:     drivers/usb/host/ehci*
 
 USB GADGET/PERIPHERAL SUBSYSTEM
-M:     Felipe Balbi <balbi@ti.com>
+M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
 W:     http://www.linux-usb.org/gadget
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
@@ -11343,6 +11378,13 @@ S:     Maintained
 F:     drivers/usb/host/isp116x*
 F:     include/linux/usb/isp116x.h
 
+USB LAN78XX ETHERNET DRIVER
+M:     Woojung Huh <woojung.huh@microchip.com>
+M:     Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     drivers/net/usb/lan78xx.*
+
 USB MASS STORAGE DRIVER
 M:     Matthew Dharm <mdharm-usb@one-eyed-alien.net>
 L:     linux-usb@vger.kernel.org
@@ -11395,7 +11437,7 @@ S:      Maintained
 F:     drivers/net/usb/pegasus.*
 
 USB PHY LAYER
-M:     Felipe Balbi <balbi@ti.com>
+M:     Felipe Balbi <balbi@kernel.org>
 L:     linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
@@ -12025,7 +12067,6 @@ F:      arch/arm64/xen/
 F:     arch/arm64/include/asm/xen/
 
 XEN NETWORK BACKEND DRIVER
-M:     Ian Campbell <ian.campbell@citrix.com>
 M:     Wei Liu <wei.liu2@citrix.com>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
 L:     netdev@vger.kernel.org
@@ -12134,7 +12175,7 @@ F:      drivers/net/hamradio/*scc.c
 F:     drivers/net/hamradio/z8530.h
 
 ZBUD COMPRESSED PAGE ALLOCATOR
-M:     Seth Jennings <sjennings@variantweb.net>
+M:     Seth Jennings <sjenning@redhat.com>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     mm/zbud.c
@@ -12189,7 +12230,7 @@ F:      include/linux/zsmalloc.h
 F:     Documentation/vm/zsmalloc.txt
 
 ZSWAP COMPRESSED SWAP CACHING
-M:     Seth Jennings <sjennings@variantweb.net>
+M:     Seth Jennings <sjenning@redhat.com>
 L:     linux-mm@kvack.org
 S:     Maintained
 F:     mm/zswap.c
index 6c1a3c2479889f807414956d05b3bf5db3908c2b..2d519d2fb3a9be1a64100c85141b824a37924602 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 5
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc7
 NAME = Blurry Fish Butt
 
 # *DOCUMENTATION*
index c5fb9e6bc3a51df64245d31987373aa37930888c..9e46d6e656d978cd203abe4202f8b1ee353bea90 100644 (file)
@@ -95,4 +95,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 76dde9db79349d0977687623307c934de91e314a..8a188bc1786a2c5cb181f21e10e5ba254b368199 100644 (file)
@@ -12,8 +12,6 @@ config ARC
        select BUILDTIME_EXTABLE_SORT
        select COMMON_CLK
        select CLONE_BACKWARDS
-       # ARC Busybox based initramfs absolutely relies on DEVTMPFS for /dev
-       select DEVTMPFS if !INITRAMFS_SOURCE=""
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
        select GENERIC_FIND_FIRST_BIT
@@ -275,14 +273,6 @@ config ARC_DCCM_BASE
        default "0xA0000000"
        depends on ARC_HAS_DCCM
 
-config ARC_HAS_HW_MPY
-       bool "Use Hardware Multiplier (Normal or Faster XMAC)"
-       default y
-       help
-         Influences how gcc generates code for MPY operations.
-         If enabled, MPYxx insns are generated, provided by Standard/XMAC
-         Multipler. Otherwise software multipy lib is used
-
 choice
        prompt "MMU Version"
        default ARC_MMU_V3 if ARC_CPU_770
@@ -338,6 +328,19 @@ config ARC_PAGE_SIZE_4K
 
 endchoice
 
+choice
+       prompt "MMU Super Page Size"
+       depends on ISA_ARCV2 && TRANSPARENT_HUGEPAGE
+       default ARC_HUGEPAGE_2M
+
+config ARC_HUGEPAGE_2M
+       bool "2MB"
+
+config ARC_HUGEPAGE_16M
+       bool "16MB"
+
+endchoice
+
 if ISA_ARCOMPACT
 
 config ARC_COMPACT_IRQ_LEVELS
@@ -410,7 +413,7 @@ config ARC_HAS_RTC
        default n
        depends on !SMP
 
-config ARC_HAS_GRTC
+config ARC_HAS_GFRC
        bool "SMP synchronized 64-bit cycle counter"
        default y
        depends on SMP
@@ -529,14 +532,6 @@ config ARC_DBG_TLB_MISS_COUNT
          Counts number of I and D TLB Misses and exports them via Debugfs
          The counters can be cleared via Debugfs as well
 
-if SMP
-
-config ARC_IPI_DBG
-       bool "Debug Inter Core interrupts"
-       default n
-
-endif
-
 endif
 
 config ARC_UBOOT_SUPPORT
@@ -566,6 +561,12 @@ endmenu
 endmenu         # "ARC Architecture Configuration"
 
 source "mm/Kconfig"
+
+config FORCE_MAX_ZONEORDER
+       int "Maximum zone order"
+       default "12" if ARC_HUGEPAGE_16M
+       default "11"
+
 source "net/Kconfig"
 source "drivers/Kconfig"
 source "fs/Kconfig"
index aeb19021099e315967ba95524e9528c48da0d159..c8230f3395f281f9c11ee6de130137d84e1bb543 100644 (file)
@@ -74,10 +74,6 @@ ldflags-$(CONFIG_CPU_BIG_ENDIAN)     += -EB
 # --build-id w/o "-marclinux". Default arc-elf32-ld is OK
 ldflags-$(upto_gcc44)                  += -marclinux
 
-ifndef CONFIG_ARC_HAS_HW_MPY
-       cflags-y        += -mno-mpy
-endif
-
 LIBGCC := $(shell $(CC) $(cflags-y) --print-libgcc-file-name)
 
 # Modules with short calls might break for calls into builtin-kernel
index f1ac9818b751e1fab854f2c1a4440b9ca8af3e85..5d4e2a07ad3eb8d11c605f385b881769d44b16ae 100644 (file)
@@ -39,6 +39,7 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -73,7 +74,6 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_LOGO=y
@@ -91,12 +91,10 @@ CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_DW=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
 CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
index 323486d6ee83419a9e50d5c53fa042f53e08ebed..87ee46b237ef7baa6dc5008f968e5c914d03aee4 100644 (file)
@@ -39,14 +39,10 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_AXS=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
@@ -78,14 +74,12 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
-CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
@@ -97,12 +91,10 @@ CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_DW=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
 CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
index 66191cd0447eaabc524a36ec497e7047043dc9a4..d80daf4f7e735aa3787df6f75957c2b9a273b361 100644 (file)
@@ -40,14 +40,10 @@ CONFIG_IP_PNP_RARP=y
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_AXS=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_NETDEVICES=y
@@ -79,14 +75,12 @@ CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_DESIGNWARE_PLATFORM=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
-CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
 CONFIG_USB_OHCI_HCD=y
@@ -98,12 +92,10 @@ CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_DW=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT3_FS=y
-CONFIG_EXT4_FS=y
 CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_NTFS_FS=y
 CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
 CONFIG_NFS_FS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
index 138f9d8879570a8b329415d9238c710fa6e5b032..f41095340b6a7a8662fc4e51e16e39524f359ae7 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -26,7 +27,6 @@ CONFIG_ARC_PLAT_SIM=y
 CONFIG_ARC_BUILTIN_DTB_NAME="nsim_700"
 CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -34,6 +34,7 @@ CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -51,7 +52,6 @@ CONFIG_SERIAL_ARC=y
 CONFIG_SERIAL_ARC_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_IOMMU_SUPPORT is not set
@@ -63,4 +63,3 @@ CONFIG_NFS_FS=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_XZ_DEC=y
index f68838e8068af53eb2ebb29c83d88cb10dc0bfac..cfaa33cb59217c6261667ec4d51b2762fea985ab 100644 (file)
@@ -35,6 +35,7 @@ CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -49,7 +50,6 @@ CONFIG_SERIAL_ARC=y
 CONFIG_SERIAL_ARC_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_IOMMU_SUPPORT is not set
@@ -61,4 +61,3 @@ CONFIG_NFS_FS=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
 # CONFIG_DEBUG_PREEMPT is not set
-CONFIG_XZ_DEC=y
index 96bd1c20fb0badeb5d3ebf41f2671f6558939c22..bb2a8dc778b5be48943f25f4415abbe73c476969 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_CROSS_COMPILE="arc-linux-"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -21,13 +22,11 @@ CONFIG_MODULES=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARC_PLAT_SIM=y
-CONFIG_ARC_BOARD_ML509=y
 CONFIG_ISA_ARCV2=y
 CONFIG_SMP=y
 CONFIG_ARC_BUILTIN_DTB_NAME="nsim_hs_idu"
 CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -35,6 +34,7 @@ CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -49,7 +49,6 @@ CONFIG_SERIAL_ARC=y
 CONFIG_SERIAL_ARC_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
 # CONFIG_IOMMU_SUPPORT is not set
@@ -60,4 +59,3 @@ CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
 # CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_XZ_DEC=y
index 31e1d95764ff91dc10fe80d936a5613e6f713cc4..646182e93753af74110471f7739fab2454246b1b 100644 (file)
@@ -33,6 +33,7 @@ CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -58,7 +59,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_HID is not set
index fcae66683ca0bd5865924a88816a388e763604cd..ceca2541950d1bbe7f950bad17ab2c598c79c65a 100644 (file)
@@ -34,12 +34,12 @@ CONFIG_UNIX_DIAG=y
 CONFIG_NET_KEY=y
 CONFIG_INET=y
 # CONFIG_IPV6 is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 # CONFIG_BLK_DEV is not set
 CONFIG_NETDEVICES=y
-CONFIG_NET_OSCI_LAN=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_MOUSE_PS2_ALPS is not set
 # CONFIG_MOUSE_PS2_LOGIPS2PP is not set
@@ -58,7 +58,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_HID is not set
index b01b659168ea4a1c36ac85e0ee41c545aa697ec8..4b6da90f6f261e3d9783719a5bbc2060bf2e8408 100644 (file)
@@ -2,6 +2,7 @@ CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="ARCLinux"
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_IKCONFIG=y
@@ -18,15 +19,11 @@ CONFIG_MODULES=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARC_PLAT_SIM=y
-CONFIG_ARC_BOARD_ML509=y
 CONFIG_ISA_ARCV2=y
 CONFIG_SMP=y
-CONFIG_ARC_HAS_LL64=y
-# CONFIG_ARC_HAS_RTSC is not set
 CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs_idu"
 CONFIG_PREEMPT=y
 # CONFIG_COMPACTION is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=y
@@ -40,6 +37,7 @@ CONFIG_INET=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 # CONFIG_FIRMWARE_IN_KERNEL is not set
@@ -56,14 +54,11 @@ CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_STMICRO is not set
 # CONFIG_NET_VENDOR_VIA is not set
 # CONFIG_NET_VENDOR_WIZNET is not set
-CONFIG_NET_OSCI_LAN=y
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 CONFIG_MOUSE_PS2_TOUCHKIT=y
 # CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIO_LIBPS2=y
 CONFIG_SERIO_ARC_PS2=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_DEVKMEM is not set
 CONFIG_SERIAL_8250=y
@@ -75,9 +70,6 @@ CONFIG_SERIAL_OF_PLATFORM=y
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 CONFIG_FB=y
-CONFIG_ARCPGU_RGB888=y
-CONFIG_ARCPGU_DISPTYPE=0
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_HID is not set
index 3b4dc9cebcf15234f3d42a4efd2e40b9c5bd4150..9b342eaf95aec97830e155a00250d3d419e6d24d 100644 (file)
@@ -3,6 +3,7 @@ CONFIG_CROSS_COMPILE="arc-linux-"
 CONFIG_DEFAULT_HOSTNAME="tb10x"
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
@@ -26,12 +27,10 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLOCK is not set
 CONFIG_ARC_PLAT_TB10X=y
 CONFIG_ARC_CACHE_LINE_SHIFT=5
-CONFIG_ARC_STACK_NONEXEC=y
 CONFIG_HZ=250
 CONFIG_ARC_BUILTIN_DTB_NAME="abilis_tb100_dvk"
 CONFIG_PREEMPT_VOLUNTARY=y
 # CONFIG_COMPACTION is not set
-# CONFIG_CROSS_MEMORY_ATTACH is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
@@ -44,8 +43,8 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
 # CONFIG_FIRMWARE_IN_KERNEL is not set
-CONFIG_PROC_DEVICETREE=y
 CONFIG_NETDEVICES=y
 # CONFIG_NET_CADENCE is not set
 # CONFIG_NET_VENDOR_BROADCOM is not set
@@ -55,9 +54,6 @@ CONFIG_NETDEVICES=y
 # CONFIG_NET_VENDOR_NATSEMI is not set
 # CONFIG_NET_VENDOR_SEEQ is not set
 CONFIG_STMMAC_ETH=y
-CONFIG_STMMAC_DEBUG_FS=y
-CONFIG_STMMAC_DA=y
-CONFIG_STMMAC_CHAINED=y
 # CONFIG_NET_VENDOR_WIZNET is not set
 # CONFIG_WLAN is not set
 # CONFIG_INPUT is not set
@@ -91,7 +87,6 @@ CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
 CONFIG_LEDS_TRIGGER_TRANSIENT=y
 CONFIG_DMADEVICES=y
 CONFIG_DW_DMAC=y
-CONFIG_NET_DMA=y
 CONFIG_ASYNC_TX_DMA=y
 # CONFIG_IOMMU_SUPPORT is not set
 # CONFIG_DNOTIFY is not set
@@ -100,17 +95,16 @@ CONFIG_TMPFS=y
 CONFIG_CONFIGFS_FS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 # CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_DEBUG_INFO=y
 # CONFIG_ENABLE_WARN_DEPRECATED is not set
-CONFIG_MAGIC_SYSRQ=y
 CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
 CONFIG_HEADERS_CHECK=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
index f36c047b33cad0c469bd2368bb3e5fa4260535e5..735985974a3136d2a1b1d6184ff754efd0a02743 100644 (file)
@@ -16,7 +16,7 @@ CONFIG_ARC_PLAT_AXS10X=y
 CONFIG_AXS103=y
 CONFIG_ISA_ARCV2=y
 CONFIG_SMP=y
-# CONFIG_ARC_HAS_GRTC is not set
+# CONFIG_ARC_HAS_GFRC is not set
 CONFIG_ARC_UBOOT_SUPPORT=y
 CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38_smp"
 CONFIG_PREEMPT=y
index 7fac7d85ed6a32bb1abaa4f8e36c5d243cec06c0..f9f4c6f59fdbb3f450ec13420e94f2ee1cb4428c 100644 (file)
@@ -10,7 +10,8 @@
 #define _ASM_ARC_ARCREGS_H
 
 /* Build Configuration Registers */
-#define ARC_REG_DCCMBASE_BCR   0x61    /* DCCM Base Addr */
+#define ARC_REG_AUX_DCCM       0x18    /* DCCM Base Addr ARCv2 */
+#define ARC_REG_DCCM_BASE_BUILD        0x61    /* DCCM Base Addr ARCompact */
 #define ARC_REG_CRC_BCR                0x62
 #define ARC_REG_VECBASE_BCR    0x68
 #define ARC_REG_PERIBASE_BCR   0x69
 #define ARC_REG_DPFP_BCR       0x6C    /* ARCompact: Dbl Precision FPU */
 #define ARC_REG_FP_V2_BCR      0xc8    /* ARCv2 FPU */
 #define ARC_REG_SLC_BCR                0xce
-#define ARC_REG_DCCM_BCR       0x74    /* DCCM Present + SZ */
+#define ARC_REG_DCCM_BUILD     0x74    /* DCCM size (common) */
 #define ARC_REG_TIMERS_BCR     0x75
 #define ARC_REG_AP_BCR         0x76
-#define ARC_REG_ICCM_BCR       0x78
+#define ARC_REG_ICCM_BUILD     0x78    /* ICCM size (common) */
 #define ARC_REG_XY_MEM_BCR     0x79
 #define ARC_REG_MAC_BCR                0x7a
 #define ARC_REG_MUL_BCR                0x7b
@@ -36,6 +37,7 @@
 #define ARC_REG_IRQ_BCR                0xF3
 #define ARC_REG_SMART_BCR      0xFF
 #define ARC_REG_CLUSTER_BCR    0xcf
+#define ARC_REG_AUX_ICCM       0x208   /* ICCM Base Addr (ARCv2) */
 
 /* status32 Bits Positions */
 #define STATUS_AE_BIT          5       /* Exception active */
@@ -246,7 +248,7 @@ struct bcr_perip {
 #endif
 };
 
-struct bcr_iccm {
+struct bcr_iccm_arcompact {
 #ifdef CONFIG_CPU_BIG_ENDIAN
        unsigned int base:16, pad:5, sz:3, ver:8;
 #else
@@ -254,17 +256,15 @@ struct bcr_iccm {
 #endif
 };
 
-/* DCCM Base Address Register: ARC_REG_DCCMBASE_BCR */
-struct bcr_dccm_base {
+struct bcr_iccm_arcv2 {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int addr:24, ver:8;
+       unsigned int pad:8, sz11:4, sz01:4, sz10:4, sz00:4, ver:8;
 #else
-       unsigned int ver:8, addr:24;
+       unsigned int ver:8, sz00:4, sz10:4, sz01:4, sz11:4, pad:8;
 #endif
 };
 
-/* DCCM RAM Configuration Register: ARC_REG_DCCM_BCR */
-struct bcr_dccm {
+struct bcr_dccm_arcompact {
 #ifdef CONFIG_CPU_BIG_ENDIAN
        unsigned int res:21, sz:3, ver:8;
 #else
@@ -272,6 +272,14 @@ struct bcr_dccm {
 #endif
 };
 
+struct bcr_dccm_arcv2 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+       unsigned int pad2:12, cyc:3, pad1:1, sz1:4, sz0:4, ver:8;
+#else
+       unsigned int ver:8, sz0:4, sz1:4, pad1:1, cyc:3, pad2:12;
+#endif
+};
+
 /* ARCompact: Both SP and DP FPU BCRs have same format */
 struct bcr_fp_arcompact {
 #ifdef CONFIG_CPU_BIG_ENDIAN
@@ -315,9 +323,9 @@ struct bcr_bpu_arcv2 {
 
 struct bcr_generic {
 #ifdef CONFIG_CPU_BIG_ENDIAN
-       unsigned int pad:24, ver:8;
+       unsigned int info:24, ver:8;
 #else
-       unsigned int ver:8, pad:24;
+       unsigned int ver:8, info:24;
 #endif
 };
 
@@ -349,14 +357,13 @@ struct cpuinfo_arc {
        struct cpuinfo_arc_bpu bpu;
        struct bcr_identity core;
        struct bcr_isa isa;
-       struct bcr_timer timers;
        unsigned int vec_base;
        struct cpuinfo_arc_ccm iccm, dccm;
        struct {
                unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, pad1:3,
                             fpu_sp:1, fpu_dp:1, pad2:6,
                             debug:1, ap:1, smart:1, rtt:1, pad3:4,
-                            pad4:8;
+                            timer0:1, timer1:1, rtc:1, gfrc:1, pad4:4;
        } extn;
        struct bcr_mpy extn_mpy;
        struct bcr_extn_xymem extn_xymem;
index 4fd7d62a6e30aa513b9e04f6ee881c219b96da96..49014f0ef36d19458203b904f41513f776aeedff 100644 (file)
 #ifdef CONFIG_ISA_ARCOMPACT
 #define TIMER0_IRQ      3
 #define TIMER1_IRQ      4
-#define IPI_IRQ                (NR_CPU_IRQS-1) /* dummy to enable SMP build for up hardware */
 #else
 #define TIMER0_IRQ      16
 #define TIMER1_IRQ      17
-#define IPI_IRQ         19
 #endif
 
 #include <linux/interrupt.h>
index 258b0e5ad3329a614e59204df55d91873e969623..37c2f751eebf03d8f9f16d997bacdcb5b8f6323f 100644 (file)
@@ -22,6 +22,7 @@
 #define AUX_IRQ_CTRL           0x00E
 #define AUX_IRQ_ACT            0x043   /* Active Intr across all levels */
 #define AUX_IRQ_LVL_PEND       0x200   /* Pending Intr across all levels */
+#define AUX_IRQ_HINT           0x201   /* For generating Soft Interrupts */
 #define AUX_IRQ_PRIORITY       0x206
 #define ICAUSE                 0x40a
 #define AUX_IRQ_SELECT         0x40b
 /* Was Intr taken in User Mode */
 #define AUX_IRQ_ACT_BIT_U      31
 
-/* 0 is highest level, but taken by FIRQs, if present in design */
-#define ARCV2_IRQ_DEF_PRIO             0
+/*
+ * User space should be interruptable even by lowest prio interrupt
+ * Safe even if actual interrupt priorities is fewer or even one
+ */
+#define ARCV2_IRQ_DEF_PRIO     15
 
 /* seed value for status register */
 #define ISA_INIT_STATUS_BITS   (STATUS_IE_MASK | STATUS_AD_MASK | \
@@ -112,6 +116,16 @@ static inline int arch_irqs_disabled(void)
        return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
+static inline void arc_softirq_trigger(int irq)
+{
+       write_aux_reg(AUX_IRQ_HINT, irq);
+}
+
+static inline void arc_softirq_clear(int irq)
+{
+       write_aux_reg(AUX_IRQ_HINT, 0);
+}
+
 #else
 
 .macro IRQ_DISABLE  scratch
index 46f4e5351b2a56e96d440a27201fc612d2e9c195..847e3bbe387fc92f9b4433bf7e08fc0b11e3ec70 100644 (file)
@@ -39,8 +39,8 @@ struct mcip_cmd {
 #define CMD_DEBUG_SET_MASK             0x34
 #define CMD_DEBUG_SET_SELECT           0x36
 
-#define CMD_GRTC_READ_LO               0x42
-#define CMD_GRTC_READ_HI               0x43
+#define CMD_GFRC_READ_LO               0x42
+#define CMD_GFRC_READ_HI               0x43
 
 #define CMD_IDU_ENABLE                 0x71
 #define CMD_IDU_DISABLE                        0x72
index 57af2f05ae8459e2ee2427d231370269894ba95f..d426d4215513333289ac85bebea412015e7562d2 100644 (file)
 #define __S111  PAGE_U_X_W_R
 
 /****************************************************************
- * Page Table Lookup split
+ * 2 tier (PGD:PTE) software page walker
  *
- * We implement 2 tier paging and since this is all software, we are free
- * to customize the span of a PGD / PTE entry to suit us
- *
- *                     32 bit virtual address
+ * [31]                    32 bit virtual address              [0]
  * -------------------------------------------------------
- * | BITS_FOR_PGD    |  BITS_FOR_PTE    |  BITS_IN_PAGE  |
+ * |               | <------------ PGDIR_SHIFT ----------> |
+ * |              |                                     |
+ * | BITS_FOR_PGD  |  BITS_FOR_PTE  | <-- PAGE_SHIFT --> |
  * -------------------------------------------------------
  *       |                  |                |
  *       |                  |                --> off in page frame
- *       |                 |
  *       |                  ---> index into Page Table
- *       |
  *       ----> index into Page Directory
+ *
+ * In a single page size configuration, only PAGE_SHIFT is fixed
+ * So both PGD and PTE sizing can be tweaked
+ *  e.g. 8K page (PAGE_SHIFT 13) can have
+ *  - PGDIR_SHIFT 21  -> 11:8:13 address split
+ *  - PGDIR_SHIFT 24  -> 8:11:13 address split
+ *
+ * If Super Page is configured, PGDIR_SHIFT becomes fixed too,
+ * so the sizing flexibility is gone.
  */
 
-#define BITS_IN_PAGE   PAGE_SHIFT
-
-/* Optimal Sizing of Pg Tbl - based on MMU page size */
-#if defined(CONFIG_ARC_PAGE_SIZE_8K)
-#define BITS_FOR_PTE   8               /* 11:8:13 */
-#elif defined(CONFIG_ARC_PAGE_SIZE_16K)
-#define BITS_FOR_PTE   8               /* 10:8:14 */
-#elif defined(CONFIG_ARC_PAGE_SIZE_4K)
-#define BITS_FOR_PTE   9               /* 11:9:12 */
+#if defined(CONFIG_ARC_HUGEPAGE_16M)
+#define PGDIR_SHIFT    24
+#elif defined(CONFIG_ARC_HUGEPAGE_2M)
+#define PGDIR_SHIFT    21
+#else
+/*
+ * Only Normal page support so "hackable" (see comment above)
+ * Default value provides 11:8:13 (8K), 11:9:12 (4K)
+ */
+#define PGDIR_SHIFT    21
 #endif
 
-#define BITS_FOR_PGD   (32 - BITS_FOR_PTE - BITS_IN_PAGE)
+#define BITS_FOR_PTE   (PGDIR_SHIFT - PAGE_SHIFT)
+#define BITS_FOR_PGD   (32 - PGDIR_SHIFT)
 
-#define PGDIR_SHIFT    (32 - BITS_FOR_PGD)
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)    /* vaddr span, not PDG sz */
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
index cbfec79137bf77735fa675d0eb2be57da217ba63..c1264607bbff3dca457fd47b8f078b62993b7af7 100644 (file)
@@ -45,11 +45,12 @@ VECTOR      reserved                ; Reserved slots
 VECTOR handle_interrupt        ; (16) Timer0
 VECTOR handle_interrupt        ; unused (Timer1)
 VECTOR handle_interrupt        ; unused (WDT)
-VECTOR handle_interrupt        ; (19) ICI (inter core interrupt)
-VECTOR handle_interrupt
-VECTOR handle_interrupt
-VECTOR handle_interrupt
-VECTOR handle_interrupt        ; (23) End of fixed IRQs
+VECTOR handle_interrupt        ; (19) Inter core Interrupt (IPI)
+VECTOR handle_interrupt        ; (20) perf Interrupt
+VECTOR handle_interrupt        ; (21) Software Triggered Intr (Self IPI)
+VECTOR handle_interrupt        ; unused
+VECTOR handle_interrupt        ; (23) unused
+# End of fixed IRQs
 
 .rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8
        VECTOR  handle_interrupt
@@ -211,7 +212,11 @@ debug_marker_syscall:
 ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig
 ; entry was via Exception in DS which got preempted in kernel).
 ;
-; IRQ RTIE won't reliably restore DE bit and/or BTA, needs handling
+; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround
+;
+; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline
+; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly
+
 .Lintr_ret_to_delay_slot:
 debug_marker_ds:
 
@@ -222,18 +227,23 @@ debug_marker_ds:
        ld      r2, [sp, PT_ret]
        ld      r3, [sp, PT_status32]
 
+       ; STAT32 for Int return created from scratch
+       ; (No delay dlot, disable Further intr in trampoline)
+
        bic     r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK
        st      r0, [sp, PT_status32]
 
        mov     r1, .Lintr_ret_to_delay_slot_2
        st      r1, [sp, PT_ret]
 
+       ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots
        st      r2, [sp, 0]
        st      r3, [sp, 4]
 
        b       .Lisr_ret_fast_path
 
 .Lintr_ret_to_delay_slot_2:
+       ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP
        sub     sp, sp, SZ_PT_REGS
        st      r9, [sp, -4]
 
@@ -243,11 +253,19 @@ debug_marker_ds:
        ld      r9, [sp, 4]
        sr      r9, [erstatus]
 
+       ; restore AUX_USER_SP if returning to U mode
+       bbit0   r9, STATUS_U_BIT, 1f
+       ld      r9, [sp, PT_sp]
+       sr      r9, [AUX_USER_SP]
+
+1:
        ld      r9, [sp, 8]
        sr      r9, [erbta]
 
        ld      r9, [sp, -4]
        add     sp, sp, SZ_PT_REGS
+
+       ; return from pure kernel mode to delay slot
        rtie
 
 END(ret_from_exception)
index 0394f9f61b466dea018af3ec371c65a8dbc17acb..942526322ae7125cb1e7910adb0523ed16ae7435 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/irqchip.h>
 #include <asm/irq.h>
 
+static int irq_prio;
+
 /*
  * Early Hardware specific Interrupt setup
  * -Called very early (start_kernel -> setup_arch -> setup_processor)
@@ -24,6 +26,14 @@ void arc_init_IRQ(void)
 {
        unsigned int tmp;
 
+       struct irq_build {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+               unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8;
+#else
+               unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3;
+#endif
+       } irq_bcr;
+
        struct aux_irq_ctrl {
 #ifdef CONFIG_CPU_BIG_ENDIAN
                unsigned int res3:18, save_idx_regs:1, res2:1,
@@ -46,28 +56,25 @@ void arc_init_IRQ(void)
 
        WRITE_AUX(AUX_IRQ_CTRL, ictrl);
 
-       /* setup status32, don't enable intr yet as kernel doesn't want */
-       tmp = read_aux_reg(0xa);
-       tmp |= ISA_INIT_STATUS_BITS;
-       tmp &= ~STATUS_IE_MASK;
-       asm volatile("flag %0   \n"::"r"(tmp));
-
        /*
         * ARCv2 core intc provides multiple interrupt priorities (upto 16).
         * Typical builds though have only two levels (0-high, 1-low)
         * Linux by default uses lower prio 1 for most irqs, reserving 0 for
         * NMI style interrupts in future (say perf)
-        *
-        * Read the intc BCR to confirm that Linux default priority is avail
-        * in h/w
-        *
-        * Note:
-        *  IRQ_BCR[27..24] contains N-1 (for N priority levels) and prio level
-        *  is 0 based.
         */
-       tmp = (read_aux_reg(ARC_REG_IRQ_BCR) >> 24 ) & 0xF;
-       if (ARCV2_IRQ_DEF_PRIO > tmp)
-               panic("Linux default irq prio incorrect\n");
+
+       READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
+
+       irq_prio = irq_bcr.prio;        /* Encoded as N-1 for N levels */
+       pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
+               irq_prio + 1, irq_prio,
+               irq_bcr.firq ? " FIRQ (not used)":"");
+
+       /* setup status32, don't enable intr yet as kernel doesn't want */
+       tmp = read_aux_reg(0xa);
+       tmp |= STATUS_AD_MASK | (irq_prio << 1);
+       tmp &= ~STATUS_IE_MASK;
+       asm volatile("flag %0   \n"::"r"(tmp));
 }
 
 static void arcv2_irq_mask(struct irq_data *data)
@@ -86,7 +93,7 @@ void arcv2_irq_enable(struct irq_data *data)
 {
        /* set default priority */
        write_aux_reg(AUX_IRQ_SELECT, data->irq);
-       write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
+       write_aux_reg(AUX_IRQ_PRIORITY, irq_prio);
 
        /*
         * hw auto enables (linux unmask) all by default
index 06bcedf19b622b4ef26503660349bc07a8a52d2e..224d1c3aa9c41dafdf52554450c2fa3b32ac8689 100644 (file)
@@ -81,9 +81,6 @@ static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq,
 {
        switch (irq) {
        case TIMER0_IRQ:
-#ifdef CONFIG_SMP
-       case IPI_IRQ:
-#endif
                irq_set_chip_and_handler(irq, &onchip_intc, handle_percpu_irq);
                break;
        default:
index bd237acdf4f2f9601efbf4c25c45067ddd2b69d9..c41c364b926cab9f50b6550e501f3ea1a8300017 100644 (file)
 #include <linux/smp.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
+#include <asm/irqflags-arcv2.h>
 #include <asm/mcip.h>
 #include <asm/setup.h>
 
+#define IPI_IRQ                19
+#define SOFTIRQ_IRQ    21
+
 static char smp_cpuinfo_buf[128];
 static int idu_detected;
 
@@ -22,6 +26,7 @@ static DEFINE_RAW_SPINLOCK(mcip_lock);
 static void mcip_setup_per_cpu(int cpu)
 {
        smp_ipi_irq_setup(cpu, IPI_IRQ);
+       smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ);
 }
 
 static void mcip_ipi_send(int cpu)
@@ -29,46 +34,44 @@ static void mcip_ipi_send(int cpu)
        unsigned long flags;
        int ipi_was_pending;
 
+       /* ARConnect can only send IPI to others */
+       if (unlikely(cpu == raw_smp_processor_id())) {
+               arc_softirq_trigger(SOFTIRQ_IRQ);
+               return;
+       }
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+
        /*
-        * NOTE: We must spin here if the other cpu hasn't yet
-        * serviced a previous message. This can burn lots
-        * of time, but we MUST follows this protocol or
-        * ipi messages can be lost!!!
-        * Also, we must release the lock in this loop because
-        * the other side may get to this same loop and not
-        * be able to ack -- thus causing deadlock.
+        * If receiver already has a pending interrupt, elide sending this one.
+        * Linux cross core calling works well with concurrent IPIs
+        * coalesced into one
+        * see arch/arc/kernel/smp.c: ipi_send_msg_one()
         */
+       __mcip_cmd(CMD_INTRPT_READ_STATUS, cpu);
+       ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK);
+       if (!ipi_was_pending)
+               __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
 
-       do {
-               raw_spin_lock_irqsave(&mcip_lock, flags);
-               __mcip_cmd(CMD_INTRPT_READ_STATUS, cpu);
-               ipi_was_pending = read_aux_reg(ARC_REG_MCIP_READBACK);
-               if (ipi_was_pending == 0)
-                       break; /* break out but keep lock */
-               raw_spin_unlock_irqrestore(&mcip_lock, flags);
-       } while (1);
-
-       __mcip_cmd(CMD_INTRPT_GENERATE_IRQ, cpu);
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
-
-#ifdef CONFIG_ARC_IPI_DBG
-       if (ipi_was_pending)
-               pr_info("IPI ACK delayed from cpu %d\n", cpu);
-#endif
 }
 
 static void mcip_ipi_clear(int irq)
 {
        unsigned int cpu, c;
        unsigned long flags;
-       unsigned int __maybe_unused copy;
+
+       if (unlikely(irq == SOFTIRQ_IRQ)) {
+               arc_softirq_clear(irq);
+               return;
+       }
 
        raw_spin_lock_irqsave(&mcip_lock, flags);
 
        /* Who sent the IPI */
        __mcip_cmd(CMD_INTRPT_CHECK_SOURCE, 0);
 
-       copy = cpu = read_aux_reg(ARC_REG_MCIP_READBACK);       /* 1,2,4,8... */
+       cpu = read_aux_reg(ARC_REG_MCIP_READBACK);      /* 1,2,4,8... */
 
        /*
         * In rare case, multiple concurrent IPIs sent to same target can
@@ -82,12 +85,6 @@ static void mcip_ipi_clear(int irq)
        } while (cpu);
 
        raw_spin_unlock_irqrestore(&mcip_lock, flags);
-
-#ifdef CONFIG_ARC_IPI_DBG
-       if (c != __ffs(copy))
-               pr_info("IPIs from %x coalesced to %x\n",
-                       copy, raw_smp_processor_id());
-#endif
 }
 
 static void mcip_probe_n_setup(void)
@@ -96,13 +93,13 @@ static void mcip_probe_n_setup(void)
 #ifdef CONFIG_CPU_BIG_ENDIAN
                unsigned int pad3:8,
                             idu:1, llm:1, num_cores:6,
-                            iocoh:1,  grtc:1, dbg:1, pad2:1,
+                            iocoh:1,  gfrc:1, dbg:1, pad2:1,
                             msg:1, sem:1, ipi:1, pad:1,
                             ver:8;
 #else
                unsigned int ver:8,
                             pad:1, ipi:1, sem:1, msg:1,
-                            pad2:1, dbg:1, grtc:1, iocoh:1,
+                            pad2:1, dbg:1, gfrc:1, iocoh:1,
                             num_cores:6, llm:1, idu:1,
                             pad3:8;
 #endif
@@ -111,12 +108,13 @@ static void mcip_probe_n_setup(void)
        READ_BCR(ARC_REG_MCIP_BCR, mp);
 
        sprintf(smp_cpuinfo_buf,
-               "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
+               "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s%s\n",
                mp.ver, mp.num_cores,
                IS_AVAIL1(mp.ipi, "IPI "),
                IS_AVAIL1(mp.idu, "IDU "),
+               IS_AVAIL1(mp.llm, "LLM "),
                IS_AVAIL1(mp.dbg, "DEBUG "),
-               IS_AVAIL1(mp.grtc, "GRTC"));
+               IS_AVAIL1(mp.gfrc, "GFRC"));
 
        idu_detected = mp.idu;
 
@@ -125,8 +123,8 @@ static void mcip_probe_n_setup(void)
                __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
        }
 
-       if (IS_ENABLED(CONFIG_ARC_HAS_GRTC) && !mp.grtc)
-               panic("kernel trying to use non-existent GRTC\n");
+       if (IS_ENABLED(CONFIG_ARC_HAS_GFRC) && !mp.gfrc)
+               panic("kernel trying to use non-existent GFRC\n");
 }
 
 struct plat_smp_ops plat_smp_ops = {
index e1b87444ea9a0740b9651ad6b68fd39f701121a0..cdc821df1809209df9792bcf9ecada0bc991753f 100644 (file)
@@ -42,9 +42,57 @@ struct task_struct *_current_task[NR_CPUS];  /* For stack switching */
 
 struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
 
+static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
+{
+       if (is_isa_arcompact()) {
+               struct bcr_iccm_arcompact iccm;
+               struct bcr_dccm_arcompact dccm;
+
+               READ_BCR(ARC_REG_ICCM_BUILD, iccm);
+               if (iccm.ver) {
+                       cpu->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
+                       cpu->iccm.base_addr = iccm.base << 16;
+               }
+
+               READ_BCR(ARC_REG_DCCM_BUILD, dccm);
+               if (dccm.ver) {
+                       unsigned long base;
+                       cpu->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
+
+                       base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
+                       cpu->dccm.base_addr = base & ~0xF;
+               }
+       } else {
+               struct bcr_iccm_arcv2 iccm;
+               struct bcr_dccm_arcv2 dccm;
+               unsigned long region;
+
+               READ_BCR(ARC_REG_ICCM_BUILD, iccm);
+               if (iccm.ver) {
+                       cpu->iccm.sz = 256 << iccm.sz00;        /* 512B to 16M */
+                       if (iccm.sz00 == 0xF && iccm.sz01 > 0)
+                               cpu->iccm.sz <<= iccm.sz01;
+
+                       region = read_aux_reg(ARC_REG_AUX_ICCM);
+                       cpu->iccm.base_addr = region & 0xF0000000;
+               }
+
+               READ_BCR(ARC_REG_DCCM_BUILD, dccm);
+               if (dccm.ver) {
+                       cpu->dccm.sz = 256 << dccm.sz0;
+                       if (dccm.sz0 == 0xF && dccm.sz1 > 0)
+                               cpu->dccm.sz <<= dccm.sz1;
+
+                       region = read_aux_reg(ARC_REG_AUX_DCCM);
+                       cpu->dccm.base_addr = region & 0xF0000000;
+               }
+       }
+}
+
 static void read_arc_build_cfg_regs(void)
 {
        struct bcr_perip uncached_space;
+       struct bcr_timer timer;
        struct bcr_generic bcr;
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
        unsigned long perip_space;
@@ -53,7 +101,11 @@ static void read_arc_build_cfg_regs(void)
        READ_BCR(AUX_IDENTITY, cpu->core);
        READ_BCR(ARC_REG_ISA_CFG_BCR, cpu->isa);
 
-       READ_BCR(ARC_REG_TIMERS_BCR, cpu->timers);
+       READ_BCR(ARC_REG_TIMERS_BCR, timer);
+       cpu->extn.timer0 = timer.t0;
+       cpu->extn.timer1 = timer.t1;
+       cpu->extn.rtc = timer.rtc;
+
        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
 
        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
@@ -71,36 +123,11 @@ static void read_arc_build_cfg_regs(void)
        cpu->extn.swap = read_aux_reg(ARC_REG_SWAP_BCR) ? 1 : 0;        /* 1,3 */
        cpu->extn.crc = read_aux_reg(ARC_REG_CRC_BCR) ? 1 : 0;
        cpu->extn.minmax = read_aux_reg(ARC_REG_MIXMAX_BCR) > 1 ? 1 : 0; /* 2 */
-
-       /* Note that we read the CCM BCRs independent of kernel config
-        * This is to catch the cases where user doesn't know that
-        * CCMs are present in hardware build
-        */
-       {
-               struct bcr_iccm iccm;
-               struct bcr_dccm dccm;
-               struct bcr_dccm_base dccm_base;
-               unsigned int bcr_32bit_val;
-
-               bcr_32bit_val = read_aux_reg(ARC_REG_ICCM_BCR);
-               if (bcr_32bit_val) {
-                       iccm = *((struct bcr_iccm *)&bcr_32bit_val);
-                       cpu->iccm.base_addr = iccm.base << 16;
-                       cpu->iccm.sz = 0x2000 << (iccm.sz - 1);
-               }
-
-               bcr_32bit_val = read_aux_reg(ARC_REG_DCCM_BCR);
-               if (bcr_32bit_val) {
-                       dccm = *((struct bcr_dccm *)&bcr_32bit_val);
-                       cpu->dccm.sz = 0x800 << (dccm.sz);
-
-                       READ_BCR(ARC_REG_DCCMBASE_BCR, dccm_base);
-                       cpu->dccm.base_addr = dccm_base.addr << 8;
-               }
-       }
-
        READ_BCR(ARC_REG_XY_MEM_BCR, cpu->extn_xymem);
 
+       /* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
+       read_decode_ccm_bcr(cpu);
+
        read_decode_mmu_bcr();
        read_decode_cache_bcr();
 
@@ -208,9 +235,9 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
                       (unsigned int)(arc_get_core_freq() / 10000) % 100);
 
        n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
-                      IS_AVAIL1(cpu->timers.t0, "Timer0 "),
-                      IS_AVAIL1(cpu->timers.t1, "Timer1 "),
-                      IS_AVAIL2(cpu->timers.rtc, "64-bit RTC ",
+                      IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
+                      IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
+                      IS_AVAIL2(cpu->extn.rtc, "Local-64-bit-Ctr ",
                                 CONFIG_ARC_HAS_RTC));
 
        n += i = scnprintf(buf + n, len - n, "%s%s%s%s%s",
@@ -232,8 +259,6 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
 
                        n += scnprintf(buf + n, len - n, "mpy[opt %d] ", opt);
                }
-               n += scnprintf(buf + n, len - n, "%s",
-                              IS_USED_CFG(CONFIG_ARC_HAS_HW_MPY));
        }
 
        n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
@@ -293,13 +318,13 @@ static void arc_chk_core_config(void)
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
        int fpu_enabled;
 
-       if (!cpu->timers.t0)
+       if (!cpu->extn.timer0)
                panic("Timer0 is not present!\n");
 
-       if (!cpu->timers.t1)
+       if (!cpu->extn.timer1)
                panic("Timer1 is not present!\n");
 
-       if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->timers.rtc)
+       if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->extn.rtc)
                panic("RTC is not present\n");
 
 #ifdef CONFIG_ARC_HAS_DCCM
@@ -334,6 +359,7 @@ static void arc_chk_core_config(void)
                panic("FPU non-existent, disable CONFIG_ARC_FPU_SAVE_RESTORE\n");
 
        if (is_isa_arcv2() && IS_ENABLED(CONFIG_SMP) && cpu->isa.atomic &&
+           IS_ENABLED(CONFIG_ARC_HAS_LLSC) &&
            !IS_ENABLED(CONFIG_ARC_STAR_9000923308))
                panic("llock/scond livelock workaround missing\n");
 }
index ef6e9e15b82abf72d946ab45c3e20096854605c5..424e937da5c897d02cca7b1bd5781614f8d5d045 100644 (file)
@@ -336,11 +336,8 @@ irqreturn_t do_IPI(int irq, void *dev_id)
                int rc;
 
                rc = __do_IPI(msg);
-#ifdef CONFIG_ARC_IPI_DBG
-               /* IPI received but no valid @msg */
                if (rc)
                        pr_info("IPI with bogus msg %ld in %ld\n", msg, copy);
-#endif
                pending &= ~(1U << msg);
        } while (pending);
 
index dfad287f1db1c6b55b86faacc0b40d2472636795..156d9833ff84b5c77b7a7bd95d2be15c81d7cbf9 100644 (file)
@@ -62,7 +62,7 @@
 
 /********** Clock Source Device *********/
 
-#ifdef CONFIG_ARC_HAS_GRTC
+#ifdef CONFIG_ARC_HAS_GFRC
 
 static int arc_counter_setup(void)
 {
@@ -83,10 +83,10 @@ static cycle_t arc_counter_read(struct clocksource *cs)
 
        local_irq_save(flags);
 
-       __mcip_cmd(CMD_GRTC_READ_LO, 0);
+       __mcip_cmd(CMD_GFRC_READ_LO, 0);
        stamp.l = read_aux_reg(ARC_REG_MCIP_READBACK);
 
-       __mcip_cmd(CMD_GRTC_READ_HI, 0);
+       __mcip_cmd(CMD_GFRC_READ_HI, 0);
        stamp.h = read_aux_reg(ARC_REG_MCIP_READBACK);
 
        local_irq_restore(flags);
@@ -95,7 +95,7 @@ static cycle_t arc_counter_read(struct clocksource *cs)
 }
 
 static struct clocksource arc_counter = {
-       .name   = "ARConnect GRTC",
+       .name   = "ARConnect GFRC",
        .rating = 400,
        .read   = arc_counter_read,
        .mask   = CLOCKSOURCE_MASK(64),
index 7a6a58ef8aaf815728fd59b0ca7af752495595b0..43788b1a1ac5e64372e1f3d3b012ba97a2e2d6ea 100644 (file)
@@ -195,5 +195,7 @@ CFLAGS_font.o := -Dstatic=
 $(obj)/font.c: $(FONTC)
        $(call cmd,shipped)
 
+AFLAGS_hyp-stub.o := -Wa,-march=armv7-a
+
 $(obj)/hyp-stub.S: $(srctree)/arch/$(SRCARCH)/kernel/hyp-stub.S
        $(call cmd,shipped)
index f3db13d2d90e7d457954c2cd93f3b9df45cb57d2..0cc150b87b86271a7b177afbbc5da952f70aa636 100644 (file)
        };
 };
 
+
+/include/ "tps65217.dtsi"
+
 &tps {
-       compatible = "ti,tps65217";
        /*
         * Configure pmic to enter OFF-state instead of SLEEP-state ("RTC-only
         * mode") at poweroff.  Most BeagleBone versions do not support RTC-only
        ti,pmic-shutdown-controller;
 
        regulators {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                dcdc1_reg: regulator@0 {
-                       reg = <0>;
                        regulator-name = "vdds_dpr";
                        regulator-always-on;
                };
 
                dcdc2_reg: regulator@1 {
-                       reg = <1>;
                        /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <925000>;
                };
 
                dcdc3_reg: regulator@2 {
-                       reg = <2>;
                        /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <925000>;
                };
 
                ldo1_reg: regulator@3 {
-                       reg = <3>;
                        regulator-name = "vio,vrtc,vdds";
                        regulator-always-on;
                };
 
                ldo2_reg: regulator@4 {
-                       reg = <4>;
                        regulator-name = "vdd_3v3aux";
                        regulator-always-on;
                };
 
                ldo3_reg: regulator@5 {
-                       reg = <5>;
                        regulator-name = "vdd_1v8";
                        regulator-always-on;
                };
 
                ldo4_reg: regulator@6 {
-                       reg = <6>;
                        regulator-name = "vdd_3v3a";
                        regulator-always-on;
                };
index fda457b07e15c282887ede12eee576d56c6f3855..857d9894103a9edf6a7754585b5dddd6276d74e6 100644 (file)
 
 };
 
-&tps {
-       compatible = "ti,tps65217";
+/include/ "tps65217.dtsi"
 
+&tps {
        regulators {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                dcdc1_reg: regulator@0 {
-                       reg = <0>;
                        regulator-name = "vdds_dpr";
                        regulator-always-on;
                };
 
                dcdc2_reg: regulator@1 {
-                       reg = <1>;
                        /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <925000>;
                };
 
                dcdc3_reg: regulator@2 {
-                       reg = <2>;
                        /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <925000>;
                };
 
                ldo1_reg: regulator@3 {
-                       reg = <3>;
                        regulator-name = "vio,vrtc,vdds";
                        regulator-boot-on;
                        regulator-always-on;
                };
 
                ldo2_reg: regulator@4 {
-                       reg = <4>;
                        regulator-name = "vdd_3v3aux";
                        regulator-boot-on;
                        regulator-always-on;
                };
 
                ldo3_reg: regulator@5 {
-                       reg = <5>;
                        regulator-name = "vdd_1v8";
                        regulator-boot-on;
                        regulator-always-on;
                };
 
                ldo4_reg: regulator@6 {
-                       reg = <6>;
                        regulator-name = "vdd_3v3d";
                        regulator-boot-on;
                        regulator-always-on;
index 77559a1ded60fb4530d90aef42323ca187ed6ac9..f313999c503e1df2add311257af95594d51e464e 100644 (file)
        wp-gpios = <&gpio3 18 0>;
 };
 
-&tps {
-       compatible = "ti,tps65217";
+#include "tps65217.dtsi"
 
+&tps {
        regulators {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                dcdc1_reg: regulator@0 {
-                       reg = <0>;
                        /* +1.5V voltage with Â±4% tolerance */
                        regulator-min-microvolt = <1450000>;
                        regulator-max-microvolt = <1550000>;
                };
 
                dcdc2_reg: regulator@1 {
-                       reg = <1>;
                        /* VDD_MPU voltage limits 0.95V - 1.1V with Â±4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <915000>;
                };
 
                dcdc3_reg: regulator@2 {
-                       reg = <2>;
                        /* VDD_CORE voltage limits 0.95V - 1.1V with Â±4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <915000>;
                };
 
                ldo1_reg: regulator@3 {
-                       reg = <3>;
                        /* +1.8V voltage with Â±4% tolerance */
                        regulator-min-microvolt = <1750000>;
                        regulator-max-microvolt = <1870000>;
                };
 
                ldo2_reg: regulator@4 {
-                       reg = <4>;
                        /* +3.3V voltage with Â±4% tolerance */
                        regulator-min-microvolt = <3175000>;
                        regulator-max-microvolt = <3430000>;
                };
 
                ldo3_reg: regulator@5 {
-                       reg = <5>;
                        /* +1.8V voltage with Â±4% tolerance */
                        regulator-min-microvolt = <1750000>;
                        regulator-max-microvolt = <1870000>;
                };
 
                ldo4_reg: regulator@6 {
-                       reg = <6>;
                        /* +3.3V voltage with Â±4% tolerance */
                        regulator-min-microvolt = <3175000>;
                        regulator-max-microvolt = <3430000>;
index 471a3a70ea1f173ce15190f77443e6860e15c328..8867aaaec54d565de7f147af80e2e1cb6c4b2967 100644 (file)
        vin-supply = <&vbat>;
 };
 
-&tps {
-       compatible = "ti,tps65217";
+/include/ "tps65217.dtsi"
 
+&tps {
        backlight {
                isel = <1>; /* ISET1 */
                fdim = <200>; /* TPS65217_BL_FDIM_200HZ */
        };
 
        regulators {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                dcdc1_reg: regulator@0 {
-                       reg = <0>;
                        /* VDD_1V8 system supply */
                        regulator-always-on;
                };
 
                dcdc2_reg: regulator@1 {
-                       reg = <1>;
                        /* VDD_CORE voltage limits 0.95V - 1.26V with +/-4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <925000>;
                };
 
                dcdc3_reg: regulator@2 {
-                       reg = <2>;
                        /* VDD_MPU voltage limits 0.95V - 1.1V with +/-4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <925000>;
                };
 
                ldo1_reg: regulator@3 {
-                       reg = <3>;
                        /* VRTC 1.8V always-on supply */
                        regulator-name = "vrtc,vdds";
                        regulator-always-on;
                };
 
                ldo2_reg: regulator@4 {
-                       reg = <4>;
                        /* 3.3V rail */
                        regulator-name = "vdd_3v3aux";
                        regulator-always-on;
                };
 
                ldo3_reg: regulator@5 {
-                       reg = <5>;
                        /* VDD_3V3A 3.3V rail */
                        regulator-name = "vdd_3v3a";
                        regulator-min-microvolt = <3300000>;
                };
 
                ldo4_reg: regulator@6 {
-                       reg = <6>;
                        /* VDD_3V3B 3.3V rail */
                        regulator-name = "vdd_3v3b";
                        regulator-always-on;
index 1b5b044fcd910bc316863370ba4cfe6cab976530..865de8500f1c85cb8505dcf5d35c07c4a660aed9 100644 (file)
@@ -46,7 +46,7 @@
                        gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_BACK>;
                        debounce-interval = <1000>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
 
                front_button {
@@ -54,7 +54,7 @@
                        gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>;
                        linux,code = <KEY_FRONT>;
                        debounce-interval = <1000>;
-                       gpio-key,wakeup;
+                       wakeup-source;
                };
        };
 
index d38edfa53bb9a95df14936af36dc600c55e8e2bc..3303c281697b017901f103aa96fee5af0a25ef8a 100644 (file)
        pinctrl-0 = <&uart4_pins>;
 };
 
+#include "tps65217.dtsi"
+
 &tps {
-       compatible = "ti,tps65217";
        ti,pmic-shutdown-controller;
 
        interrupt-parent = <&intc>;
        interrupts = <7>;       /* NNMI */
 
        regulators {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
                dcdc1_reg: regulator@0 {
-                       reg = <0>;
                        /* VDDS_DDR */
                        regulator-min-microvolt = <1500000>;
                        regulator-max-microvolt = <1500000>;
                };
 
                dcdc2_reg: regulator@1 {
-                       reg = <1>;
                        /* VDD_MPU voltage limits 0.95V - 1.26V with +/-4% tolerance */
                        regulator-name = "vdd_mpu";
                        regulator-min-microvolt = <925000>;
                };
 
                dcdc3_reg: regulator@2 {
-                       reg = <2>;
                        /* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
                        regulator-name = "vdd_core";
                        regulator-min-microvolt = <925000>;
                };
 
                ldo1_reg: regulator@3 {
-                       reg = <3>;
                        /* VRTC / VIO / VDDS*/
                        regulator-always-on;
                        regulator-min-microvolt = <1800000>;
                };
 
                ldo2_reg: regulator@4 {
-                       reg = <4>;
                        /* VDD_3V3AUX */
                        regulator-always-on;
                        regulator-min-microvolt = <3300000>;
                };
 
                ldo3_reg: regulator@5 {
-                       reg = <5>;
                        /* VDD_1V8 */
                        regulator-min-microvolt = <1800000>;
                        regulator-max-microvolt = <1800000>;
                };
 
                ldo4_reg: regulator@6 {
-                       reg = <6>;
                        /* VDD_3V3A */
                        regulator-min-microvolt = <3300000>;
                        regulator-max-microvolt = <3300000>;
index 04885f9f959e21fcffb388940d64be0b6eb32869..1fafaad516ba0481de34cc12320fb9e51c2884ce 100644 (file)
                        ti,mbox-num-users = <4>;
                        ti,mbox-num-fifos = <8>;
                        mbox_wkupm3: wkup_m3 {
+                               ti,mbox-send-noirq;
                                ti,mbox-tx = <0 0 0>;
                                ti,mbox-rx = <0 0 3>;
                        };
index df955ba4dc6203273ff795cc1492e698764eda0d..92068fbf8b577440409c8e029d7cfba28da43cf8 100644 (file)
@@ -73,7 +73,7 @@
        global_timer: timer@48240200 {
                compatible = "arm,cortex-a9-global-timer";
                reg = <0x48240200 0x100>;
-               interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <GIC_PPI 11 IRQ_TYPE_EDGE_RISING>;
                interrupt-parent = <&gic>;
                clocks = <&mpu_periphclk>;
        };
@@ -81,7 +81,7 @@
        local_timer: timer@48240600 {
                compatible = "arm,cortex-a9-twd-timer";
                reg = <0x48240600 0x100>;
-               interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+               interrupts = <GIC_PPI 13 IRQ_TYPE_EDGE_RISING>;
                interrupt-parent = <&gic>;
                clocks = <&mpu_periphclk>;
        };
                        ti,mbox-num-users = <4>;
                        ti,mbox-num-fifos = <8>;
                        mbox_wkupm3: wkup_m3 {
+                               ti,mbox-send-noirq;
                                ti,mbox-tx = <0 0 0>;
                                ti,mbox-rx = <0 0 3>;
                        };
index 64d43325bcbc73aa08bf1da025c255883737f233..ecd09ab6d581bf95aa0b8bee8d596c3da8b9ee22 100644 (file)
                pinctrl-names = "default";
                pinctrl-0 = <&pixcir_ts_pins>;
                reg = <0x5c>;
-               interrupt-parent = <&gpio3>;
-               interrupts = <22 0>;
 
                attb-gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
 
                 * 0x264 represents the offset of padconf register of
                 * gpio3_22 from am43xx_pinmux base.
                 */
-               interrupts-extended = <&gpio3 22 IRQ_TYPE_NONE>,
+               interrupts-extended = <&gpio3 22 IRQ_TYPE_EDGE_FALLING>,
                                      <&am43xx_pinmux 0x264>;
                interrupt-names = "tsc", "wakeup";
 
index 746fd2b179587fe4522724f5b42b16202e97edef..d580e2b70f9a65f7dc078799add6d56628ae0169 100644 (file)
                pinctrl-0 = <&pixcir_ts_pins>;
                reg = <0x5c>;
                interrupt-parent = <&gpio1>;
-               interrupts = <17 0>;
+               interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
 
                attb-gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
 
index 36c0fa6c362ae32000701ffec7e81df73f2a187a..a0986c65be0cfa71856947c58f57abe8df61c7fd 100644 (file)
 
                sound0_master: simple-audio-card,codec {
                        sound-dai = <&tlv320aic3104>;
+                       assigned-clocks = <&clkoutmux2_clk_mux>;
+                       assigned-clock-parents = <&sys_clk2_dclk_div>;
                        clocks = <&clkout2_clk>;
                };
        };
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&mcasp3_pins_default>;
        pinctrl-1 = <&mcasp3_pins_sleep>;
+       assigned-clocks = <&mcasp3_ahclkx_mux>;
+       assigned-clock-parents = <&sys_clkin2>;
        status = "okay";
 
        op-mode = <0>;  /* MCASP_IIS_MODE */
index c53882643ae96b6da8b15c6a26e5fd93ba3300cb..1c06cb76da07c14132e60cd29f5406dab9e9db66 100644 (file)
                        DRA7XX_CORE_IOPAD(0x35b8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
                        DRA7XX_CORE_IOPAD(0x35bc, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
                        DRA7XX_CORE_IOPAD(0x35c0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
-                       DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT_PULLUP | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+                       DRA7XX_CORE_IOPAD(0x35c4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
                >;
        };
 
        pinctrl-names = "default";
        pinctrl-0 = <&qspi1_pins>;
 
-       spi-max-frequency = <20000000>;
+       spi-max-frequency = <48000000>;
 
        spi_flash: spi_flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "spansion,m25p80", "jedec,spi-nor";
                reg = <0>;                              /* CS0 */
-               spi-max-frequency = <20000000>;
+               spi-max-frequency = <48000000>;
 
                partition@0 {
                        label = "uboot";
                ti,debounce-tol = /bits/ 16 <10>;
                ti,debounce-rep = /bits/ 16 <1>;
 
-               linux,wakeup;
+               wakeup-source;
        };
 };
 
 
 &cpsw_emac0 {
        phy_id = <&davinci_mdio>, <0>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-txid";
        dual_emac_res_vlan = <0>;
 };
 
 &cpsw_emac1 {
        phy_id = <&davinci_mdio>, <1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-txid";
        dual_emac_res_vlan = <1>;
 };
 
 };
 
 &usb2 {
-       dr_mode = "peripheral";
+       dr_mode = "host";
 };
 
 &mcasp3 {
index 77bb8e17401a26cad24dcfd2ab5a7c9ddbd4d312..988e99632d49953d012b72e674f8fa040883a1c4 100644 (file)
@@ -25,8 +25,8 @@
 &dra7_pmx_core {
        uart3_pins_default: uart3_pins_default {
                pinctrl-single,pins = <
-                       DRA7XX_CORE_IOPAD(0x37f8, PIN_INPUT_SLEW | MUX_MODE2)   /* uart2_ctsn.uart3_rxd */
-                       DRA7XX_CORE_IOPAD(0x37fc, PIN_INPUT_SLEW | MUX_MODE1)   /* uart2_rtsn.uart3_txd */
+                       DRA7XX_CORE_IOPAD(0x3648, PIN_INPUT_SLEW | MUX_MODE0)   /* uart3_rxd */
+                       DRA7XX_CORE_IOPAD(0x364c, PIN_INPUT_SLEW | MUX_MODE0)   /* uart3_txd */
                >;
        };
 
        pinctrl-0 = <&i2c5_pins_default>;
        clock-frequency = <400000>;
 
-       eeprom_base: atmel@50 {
+       eeprom_base: atmel@54 {
                compatible = "atmel,24c08";
-               reg = <0x50>;
+               reg = <0x54>;
                pagesize = <16>;
        };
 
index 13cf69a8d0fb392b264910f014cf7ff8434f9e2b..fb9e1bbf23385b85b0b82ddb153b922b2d2e0178 100644 (file)
                                nand-on-flash-bbt;
 
                                partitions {
+                                       compatible = "fixed-partitions";
                                        #address-cells = <1>;
                                        #size-cells = <1>;
 
index 77ddff036409f7cb84d28342f8b973ce9792d09e..e683856c507c8bedacb5f8746a43cf9e4aef2207 100644 (file)
 
                        macb0: ethernet@f8008000 {
                                pinctrl-names = "default";
-                               pinctrl-0 = <&pinctrl_macb0_default>;
+                               pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
                                phy-mode = "rmii";
                                status = "okay";
+
+                               ethernet-phy@1 {
+                                       reg = <0x1>;
+                                       interrupt-parent = <&pioA>;
+                                       interrupts = <73 IRQ_TYPE_LEVEL_LOW>;
+                               };
                        };
 
                        pdmic@f8018000 {
                                        bias-disable;
                                };
 
+                               pinctrl_macb0_phy_irq: macb0_phy_irq {
+                                       pinmux = <PIN_PC9__GPIO>;
+                               };
+
                                pinctrl_pdmic_default: pdmic_default {
                                        pinmux = <PIN_PB26__PDMIC_DAT>,
                                                <PIN_PB27__PDMIC_CLK>;
index 131614f28e758653e34cc2b993bb6a5a28f20bbb..569026e8f96cadaf25eeb10ca207c02c7f175121 100644 (file)
                        macb0: ethernet@f8020000 {
                                phy-mode = "rmii";
                                status = "okay";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_macb0_rmii &pinctrl_macb0_phy_irq>;
 
                                phy0: ethernet-phy@1 {
                                        interrupt-parent = <&pioE>;
-                                       interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+                                       interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
                                        reg = <1>;
                                };
                        };
                                                atmel,pins =
                                                        <AT91_PIOE 8 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
                                        };
+                                       pinctrl_macb0_phy_irq: macb0_phy_irq_0 {
+                                               atmel,pins =
+                                                       <AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+                                       };
                                };
                        };
                };
index 2d4a33100af6bdc4fcd4a3500467456673f54325..4e98cda974032221dbf5a0917de97807653cf943 100644 (file)
                        };
 
                        macb0: ethernet@f8020000 {
+                               pinctrl-0 = <&pinctrl_macb0_rmii &pinctrl_macb0_phy_irq>;
                                phy-mode = "rmii";
                                status = "okay";
+
+                               ethernet-phy@1 {
+                                       reg = <0x1>;
+                                       interrupt-parent = <&pioE>;
+                                       interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+                               };
                        };
 
                        mmc1: mmc@fc000000 {
 
                        pinctrl@fc06a000 {
                                board {
+                                       pinctrl_macb0_phy_irq: macb0_phy_irq {
+                                               atmel,pins =
+                                                       <AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+                                       };
                                        pinctrl_mmc0_cd: mmc0_cd {
                                                atmel,pins =
                                                        <AT91_PIOE 5 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
index ca4ddf86817ab64dc6a8a31193191460bfaf8d4b..626c67d666269d5e878c650b76e8babc424bd48a 100644 (file)
        };
 
        panel: panel {
-               compatible = "qd,qd43003c0-40", "simple-panel";
+               compatible = "qiaodian,qd43003c0-40", "simple-panel";
                backlight = <&backlight>;
                power-supply = <&panel_reg>;
                #address-cells = <1>;
index 4f6ae921656f16dfd3814d7a70972be798e0fce9..f74d3db4846dacacd54b37e9cb1d35d707689368 100644 (file)
                                #size-cells = <1>;
                                reg = <0x2100000 0x10000>;
                                ranges = <0 0x2100000 0x10000>;
-                               interrupt-parent = <&intc>;
                                clocks = <&clks IMX6QDL_CLK_CAAM_MEM>,
                                         <&clks IMX6QDL_CLK_CAAM_ACLK>,
                                         <&clks IMX6QDL_CLK_CAAM_IPG>,
index bf4143c6cb8f10991d4abbaae126966f9f9c753c..b84af3da8c84d596b2b950489541c4efd9216783 100644 (file)
@@ -14,7 +14,7 @@
 #include "kirkwood-synology.dtsi"
 
 / {
-       model = "Synology DS111";
+       model = "Synology DS112";
        compatible = "synology,ds111", "marvell,kirkwood";
 
        memory {
index 09eed3cea0afcd0ab74df3a13de8525714f388cc..36eec7392ab491c839f86ca3299cc716af21e356 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WVL/VL
  *
- * Copyright (C) 2015, rogershimizu@gmail.com
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
                button@1 {
                        label = "Function Button";
                        linux,code = <KEY_OPTION>;
-                       gpios = <&gpio0 45 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
                };
 
                button@2 {
                        label = "Power-on Switch";
                        linux,code = <KEY_RESERVED>;
                        linux,input-type = <5>;
-                       gpios = <&gpio0 46 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
                };
 
                button@3 {
                        label = "Power-auto Switch";
                        linux,code = <KEY_ESC>;
                        linux,input-type = <5>;
-                       gpios = <&gpio0 47 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
                };
        };
 
 
                led@1 {
                        label = "lswvl:red:alarm";
-                       gpios = <&gpio0 36 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
                };
 
                led@2 {
                        label = "lswvl:red:func";
-                       gpios = <&gpio0 37 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
                };
 
                led@3 {
                        label = "lswvl:amber:info";
-                       gpios = <&gpio0 38 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
                };
 
                led@4 {
                        label = "lswvl:blue:func";
-                       gpios = <&gpio0 39 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
                };
 
                led@5 {
                        label = "lswvl:blue:power";
-                       gpios = <&gpio0 40 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
                        default-state = "keep";
                };
 
                led@6 {
                        label = "lswvl:red:hdderr0";
-                       gpios = <&gpio0 34 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
                };
 
                led@7 {
                        label = "lswvl:red:hdderr1";
-                       gpios = <&gpio0 35 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
                };
        };
 
                                3250 1
                                5000 0>;
 
-               alarm-gpios = <&gpio0 43 GPIO_ACTIVE_HIGH>;
+               alarm-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
        };
 
        restart_poweroff {
index f5db16a08597e9a732f575c13b00415ce8e40920..b13ec20a708873bb65619ccd203c3552b04bc246 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WXL/WSXL
  *
- * Copyright (C) 2015, rogershimizu@gmail.com
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
                button@1 {
                        label = "Function Button";
                        linux,code = <KEY_OPTION>;
-                       gpios = <&gpio1 41 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
                };
 
                button@2 {
                        label = "Power-on Switch";
                        linux,code = <KEY_RESERVED>;
                        linux,input-type = <5>;
-                       gpios = <&gpio1 42 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
                };
 
                button@3 {
                        label = "Power-auto Switch";
                        linux,code = <KEY_ESC>;
                        linux,input-type = <5>;
-                       gpios = <&gpio1 43 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 11 GPIO_ACTIVE_LOW>;
                };
        };
 
 
                led@1 {
                        label = "lswxl:blue:func";
-                       gpios = <&gpio1 36 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 4 GPIO_ACTIVE_LOW>;
                };
 
                led@2 {
                        label = "lswxl:red:alarm";
-                       gpios = <&gpio1 49 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
                };
 
                led@3 {
 
                led@4 {
                        label = "lswxl:blue:power";
-                       gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
+                       default-state = "keep";
                };
 
                led@5 {
                        label = "lswxl:red:func";
-                       gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
-                       default-state = "keep";
+                       gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
                };
 
                led@6 {
                        label = "lswxl:red:hdderr0";
-                       gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
                };
 
                led@7 {
                        label = "lswxl:red:hdderr1";
-                       gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>;
                };
        };
 
                pinctrl-0 = <&pmx_fan_low &pmx_fan_high &pmx_fan_lock>;
                pinctrl-names = "default";
 
-               gpios = <&gpio0 47 GPIO_ACTIVE_LOW
-                        &gpio0 48 GPIO_ACTIVE_LOW>;
+               gpios = <&gpio1 16 GPIO_ACTIVE_LOW
+                        &gpio1 15 GPIO_ACTIVE_LOW>;
 
                gpio-fan,speed-map = <0 3
                                1500 2
                                3250 1
                                5000 0>;
 
-               alarm-gpios = <&gpio1 49 GPIO_ACTIVE_HIGH>;
+               alarm-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>;
        };
 
        restart_poweroff {
                        enable-active-high;
                        regulator-always-on;
                        regulator-boot-on;
-                       gpio = <&gpio0 37 GPIO_ACTIVE_HIGH>;
+                       gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
                };
                hdd_power0: regulator@2 {
                        compatible = "regulator-fixed";
index 1db6f2c506cce3209e64418493039046c79fd0ec..8082d64266a37c33c8fa2e7e722d3683519c3d0a 100644 (file)
        chip-delay = <40>;
        status = "okay";
        partitions {
+               compatible = "fixed-partitions";
                #address-cells = <1>;
                #size-cells = <1>;
 
index 7fed0bd4f3deea46281881ead81b2ebd29c5fa4b..00805322367e7eb73bcc4ba5bda124eee5372467 100644 (file)
        clock-frequency = <400000>;
 };
 
-&i2c2 {
-       clock-frequency = <400000>;
-};
-
-&i2c3 {
-       clock-frequency = <400000>;
-};
-
 /*
  * Only found on the wireless SOM. For the SOM without wireless, the pins for
  * MMC3 can be routed with jumpers to the second MMC slot on the devkit and
                interrupt-parent = <&gpio5>;
                interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; /* gpio 152 */
                ref-clock-frequency = <26000000>;
+               tcxo-clock-frequency = <26000000>;
        };
 };
 
index 2c84ca236473a10d8381666ef921a29a3ab395e0..ecf12dc225953d08c0b9e68ec3fe3f1ac50f1c67 100644 (file)
                        reg = <0x0 0x2d24000 0x0 0x4000>;
                };
 
+               ptp_clock@2d10e00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x0 0x2d10e00 0x0 0xb0>;
+                       interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc    = <2>;
+                       fsl,tmr-add     = <0xaaaaaaab>;
+                       fsl,tmr-fiper1  = <999999990>;
+                       fsl,tmr-fiper2  = <99990>;
+                       fsl,max-adj     = <499999999>;
+               };
+
                enet0: ethernet@2d10000 {
                        compatible = "fsl,etsec2";
                        device_type = "network";
index 888412c63f97492ef445368c3208434d748912f2..902657d6713b073df82d33158d3d1cd0fac5ef16 100644 (file)
        };
 };
 
+&gpio8 {
+       /* TI trees use GPIO instead of msecure, see also muxing */
+       p234 {
+               gpio-hog;
+               gpios = <10 GPIO_ACTIVE_HIGH>;
+               output-high;
+               line-name = "gpio8_234/msecure";
+       };
+};
+
 &omap5_pmx_core {
        pinctrl-names = "default";
        pinctrl-0 = <
                >;
        };
 
+       /* TI trees use GPIO mode; msecure mode does not work reliably? */
+       palmas_msecure_pins: palmas_msecure_pins {
+               pinctrl-single,pins = <
+                       OMAP5_IOPAD(0x180, PIN_OUTPUT | MUX_MODE6) /* gpio8_234 */
+               >;
+       };
+
        usbhost_pins: pinmux_usbhost_pins {
                pinctrl-single,pins = <
                        OMAP5_IOPAD(0x0c4, PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
                        &usbhost_wkup_pins
        >;
 
+       palmas_sys_nirq_pins: pinmux_palmas_sys_nirq_pins {
+               pinctrl-single,pins = <
+                       OMAP5_IOPAD(0x068, PIN_INPUT_PULLUP | MUX_MODE0) /* sys_nirq1 */
+               >;
+       };
+
        usbhost_wkup_pins: pinmux_usbhost_wkup_pins {
                pinctrl-single,pins = <
                        OMAP5_IOPAD(0x05a, PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
                interrupt-controller;
                #interrupt-cells = <2>;
                ti,system-power-controller;
+               pinctrl-names = "default";
+               pinctrl-0 = <&palmas_sys_nirq_pins &palmas_msecure_pins>;
 
                extcon_usb3: palmas_usb {
                        compatible = "ti,palmas-usb-vid";
                        #clock-cells = <0>;
                };
 
+               rtc {
+                       compatible = "ti,palmas-rtc";
+                       interrupt-parent = <&palmas>;
+                       interrupts = <8 IRQ_TYPE_NONE>;
+                       ti,backup-battery-chargeable;
+                       ti,backup-battery-charge-high-current;
+               };
+
                palmas_pmic {
                        compatible = "ti,palmas-pmic";
                        interrupt-parent = <&palmas>;
index 3daec912b4bf118edba55ef54fdf633413e696e5..aae8a7aceab75d53f84a2eb94fc0d6e020e773a9 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Device Tree file for Buffalo Linkstation LS-WTGL
  *
- * Copyright (C) 2015, Roger Shimizu <rogershimizu@gmail.com>
+ * Copyright (C) 2015, 2016
+ * Roger Shimizu <rogershimizu@gmail.com>
  *
  * This file is dual-licensed: you can use it either under the terms
  * of the GPL or the X11 license, at your option. Note that this dual
@@ -69,8 +70,6 @@
 
                internal-regs {
                        pinctrl: pinctrl@10000 {
-                               pinctrl-0 = <&pmx_usb_power &pmx_power_hdd
-                                       &pmx_fan_low &pmx_fan_high &pmx_fan_lock>;
                                pinctrl-names = "default";
 
                                pmx_led_power: pmx-leds {
                led@1 {
                        label = "lswtgl:blue:power";
                        gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+                       default-state = "keep";
                };
 
                led@2 {
                                3250 1
                                5000 0>;
 
-               alarm-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+               alarm-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
        };
 
        restart_poweroff {
        };
 };
 
+&devbus_bootcs {
+       status = "okay";
+       devbus,keep-config;
+
+       flash@0 {
+               compatible = "jedec-flash";
+               reg = <0 0x40000>;
+               bank-width = <1>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       header@0 {
+                               reg = <0 0x30000>;
+                               read-only;
+                       };
+
+                       uboot@30000 {
+                               reg = <0x30000 0xF000>;
+                               read-only;
+                       };
+
+                       uboot_env@3F000 {
+                               reg = <0x3F000 0x1000>;
+                       };
+               };
+       };
+};
+
 &mdio {
        status = "okay";
 
index 6713b1ea732b0b1d2282368ce5b50e42a9ae6043..01d239c3eaaaa3fe4ca8ab7854fbca9faa3e23e4 100644 (file)
        pinctrl-names = "default";
 
        status = "okay";
-       renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>;
 };
 
 &usbphy {
index 1afe24629d1f85de2a9ec3f8ef62c6372d014abd..b0c912feaa2f0e016b65ff27e272b82c2b0795ed 100644 (file)
@@ -90,7 +90,7 @@
 #define PIN_PA14__I2SC1_MCK            PINMUX_PIN(PIN_PA14, 4, 2)
 #define PIN_PA14__FLEXCOM3_IO2         PINMUX_PIN(PIN_PA14, 5, 1)
 #define PIN_PA14__D9                   PINMUX_PIN(PIN_PA14, 6, 2)
-#define PIN_PA15                       14
+#define PIN_PA15                       15
 #define PIN_PA15__GPIO                 PINMUX_PIN(PIN_PA15, 0, 0)
 #define PIN_PA15__SPI0_MOSI            PINMUX_PIN(PIN_PA15, 1, 1)
 #define PIN_PA15__TF1                  PINMUX_PIN(PIN_PA15, 2, 1)
index b8032bca462152e6904d299f84514c483dde0165..db1151c18466c3ac530be0ba39ba2f00be3a06bc 100644 (file)
                        dbgu: serial@fc069000 {
                                compatible = "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart";
                                reg = <0xfc069000 0x200>;
-                               interrupts = <2 IRQ_TYPE_LEVEL_HIGH 7>;
+                               interrupts = <45 IRQ_TYPE_LEVEL_HIGH 7>;
                                pinctrl-names = "default";
                                pinctrl-0 = <&pinctrl_dbgu>;
                                clocks = <&dbgu_clk>;
index d0c74385331803383d5296d7157516aa63c63758..27a333eb89870167b82a170d3553bd5078fafdfb 100644 (file)
                        };
                        mmcsd_default_mode: mmcsd_default {
                                mmcsd_default_cfg1 {
-                                       /* MCCLK */
-                                       pins = "GPIO8_B10";
-                                       ste,output = <0>;
-                               };
-                               mmcsd_default_cfg2 {
-                                       /* MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2 */
-                                       pins = "GPIO10_C11", "GPIO15_A12",
-                                       "GPIO16_C13", "GPIO23_D15";
-                                       ste,output = <1>;
-                               };
-                               mmcsd_default_cfg3 {
-                                       /* MCCMD, MCDAT3-0, MCMSFBCLK */
-                                       pins = "GPIO9_A10", "GPIO11_B11",
-                                       "GPIO12_A11", "GPIO13_C12",
-                                       "GPIO14_B12", "GPIO24_C15";
-                                       ste,input = <1>;
+                                       /*
+                                        * MCCLK, MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2
+                                        * MCCMD, MCDAT3-0, MCMSFBCLK
+                                        */
+                                       pins = "GPIO8_B10", "GPIO9_A10", "GPIO10_C11", "GPIO11_B11",
+                                              "GPIO12_A11", "GPIO13_C12", "GPIO14_B12", "GPIO15_A12",
+                                              "GPIO16_C13", "GPIO23_D15", "GPIO24_C15";
+                                       ste,output = <2>;
                                };
                        };
                };
                        clock-names = "mclk", "apb_pclk";
                        interrupt-parent = <&vica>;
                        interrupts = <22>;
-                       max-frequency = <48000000>;
+                       max-frequency = <400000>;
                        bus-width = <4>;
                        cap-mmc-highspeed;
                        cap-sd-highspeed;
+                       full-pwr-cycle;
+                       /*
+                        * The STw4811 circuit used with the Nomadik strictly
+                        * requires that all of these signal direction pins be
+                        * routed and used for its 4-bit levelshifter.
+                        */
+                       st,sig-dir-dat0;
+                       st,sig-dir-dat2;
+                       st,sig-dir-dat31;
+                       st,sig-dir-cmd;
+                       st,sig-pin-fbclk;
                        pinctrl-names = "default";
                        pinctrl-0 = <&mmcsd_default_mux>, <&mmcsd_default_mode>;
                        vmmc-supply = <&vmmc_regulator>;
diff --git a/arch/arm/boot/dts/tps65217.dtsi b/arch/arm/boot/dts/tps65217.dtsi
new file mode 100644 (file)
index 0000000..a632724
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.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.
+ */
+
+/*
+ * Integrated Power Management Chip
+ * http://www.ti.com/lit/ds/symlink/tps65217.pdf
+ */
+
+&tps {
+       compatible = "ti,tps65217";
+
+       regulators {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               dcdc1_reg: regulator@0 {
+                       reg = <0>;
+                       regulator-compatible = "dcdc1";
+               };
+
+               dcdc2_reg: regulator@1 {
+                       reg = <1>;
+                       regulator-compatible = "dcdc2";
+               };
+
+               dcdc3_reg: regulator@2 {
+                       reg = <2>;
+                       regulator-compatible = "dcdc3";
+               };
+
+               ldo1_reg: regulator@3 {
+                       reg = <3>;
+                       regulator-compatible = "ldo1";
+               };
+
+               ldo2_reg: regulator@4 {
+                       reg = <4>;
+                       regulator-compatible = "ldo2";
+               };
+
+               ldo3_reg: regulator@5 {
+                       reg = <5>;
+                       regulator-compatible = "ldo3";
+               };
+
+               ldo4_reg: regulator@6 {
+                       reg = <6>;
+                       regulator-compatible = "ldo4";
+               };
+       };
+};
index 2dc6da70ae598af4a43f3b8a9bde05d26d386c77..d7ed252708c57fa86cff5d51887bd756b53b48e7 100644 (file)
@@ -16,7 +16,7 @@
  */
 #include <linux/module.h>
 #include <linux/kernel.h>
-
+#include <asm/div64.h>
 #include <asm/hardware/icst.h>
 
 /*
@@ -29,7 +29,11 @@ EXPORT_SYMBOL(icst525_s2div);
 
 unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco)
 {
-       return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]);
+       u64 dividend = p->ref * 2 * (u64)(vco.v + 8);
+       u32 divisor = (vco.r + 2) * p->s2div[vco.s];
+
+       do_div(dividend, divisor);
+       return (unsigned long)dividend;
 }
 
 EXPORT_SYMBOL(icst_hz);
@@ -58,6 +62,7 @@ icst_hz_to_vco(const struct icst_params *p, unsigned long freq)
 
                if (f > p->vco_min && f <= p->vco_max)
                        break;
+               i++;
        } while (i < 8);
 
        if (i >= 8)
index 314f6be2dca2b4aec6aaa82cc8cfb2ba06c2bb29..8e8b2ace9b7c5fb624f4e24122cf269538195f3d 100644 (file)
@@ -426,6 +426,7 @@ CONFIG_SUNXI_WATCHDOG=y
 CONFIG_IMX2_WDT=y
 CONFIG_TEGRA_WATCHDOG=m
 CONFIG_MESON_WATCHDOG=y
+CONFIG_DW_WATCHDOG=y
 CONFIG_DIGICOLOR_WATCHDOG=y
 CONFIG_MFD_AS3711=y
 CONFIG_MFD_AS3722=y
index c5e1943e5427db037b98ce779566aeab1b1c9310..d18d6b42fcf52f9db076af65a0f6aad022a1173c 100644 (file)
@@ -50,6 +50,7 @@ CONFIG_SOC_AM33XX=y
 CONFIG_SOC_AM43XX=y
 CONFIG_SOC_DRA7XX=y
 CONFIG_ARM_THUMBEE=y
+CONFIG_ARM_KERNMEM_PERMS=y
 CONFIG_ARM_ERRATA_411920=y
 CONFIG_ARM_ERRATA_430973=y
 CONFIG_SMP=y
@@ -177,6 +178,7 @@ CONFIG_TI_CPTS=y
 CONFIG_AT803X_PHY=y
 CONFIG_SMSC_PHY=y
 CONFIG_USB_USBNET=m
+CONFIG_USB_NET_SMSC75XX=m
 CONFIG_USB_NET_SMSC95XX=m
 CONFIG_USB_ALI_M5632=y
 CONFIG_USB_AN2720=y
@@ -290,24 +292,23 @@ CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_TILEBLITTING=y
-CONFIG_OMAP2_DSS=m
-CONFIG_OMAP5_DSS_HDMI=y
-CONFIG_OMAP2_DSS_SDI=y
-CONFIG_OMAP2_DSS_DSI=y
+CONFIG_FB_OMAP5_DSS_HDMI=y
+CONFIG_FB_OMAP2_DSS_SDI=y
+CONFIG_FB_OMAP2_DSS_DSI=y
 CONFIG_FB_OMAP2=m
-CONFIG_DISPLAY_ENCODER_TFP410=m
-CONFIG_DISPLAY_ENCODER_TPD12S015=m
-CONFIG_DISPLAY_CONNECTOR_DVI=m
-CONFIG_DISPLAY_CONNECTOR_HDMI=m
-CONFIG_DISPLAY_CONNECTOR_ANALOG_TV=m
-CONFIG_DISPLAY_PANEL_DPI=m
-CONFIG_DISPLAY_PANEL_DSI_CM=m
-CONFIG_DISPLAY_PANEL_SONY_ACX565AKM=m
-CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02=m
-CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01=m
-CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1=m
-CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1=m
-CONFIG_DISPLAY_PANEL_NEC_NL8048HL11=m
+CONFIG_FB_OMAP2_ENCODER_TFP410=m
+CONFIG_FB_OMAP2_ENCODER_TPD12S015=m
+CONFIG_FB_OMAP2_CONNECTOR_DVI=m
+CONFIG_FB_OMAP2_CONNECTOR_HDMI=m
+CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV=m
+CONFIG_FB_OMAP2_PANEL_DPI=m
+CONFIG_FB_OMAP2_PANEL_DSI_CM=m
+CONFIG_FB_OMAP2_PANEL_SONY_ACX565AKM=m
+CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02=m
+CONFIG_FB_OMAP2_PANEL_SHARP_LS037V7DW01=m
+CONFIG_FB_OMAP2_PANEL_TPO_TD028TTEC1=m
+CONFIG_FB_OMAP2_PANEL_TPO_TD043MTEA1=m
+CONFIG_FB_OMAP2_PANEL_NEC_NL8048HL11=m
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_LCD_PLATFORM=y
@@ -354,6 +355,11 @@ CONFIG_USB_MUSB_DSPS=m
 CONFIG_USB_INVENTRA_DMA=y
 CONFIG_USB_TI_CPPI41_DMA=y
 CONFIG_USB_DWC3=m
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_PL2303=m
 CONFIG_USB_TEST=m
 CONFIG_AM335X_PHY_USB=y
 CONFIG_USB_GADGET=m
@@ -387,6 +393,7 @@ CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=m
 CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_PWM=m
+CONFIG_LEDS_PCA963X=m
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 CONFIG_LEDS_TRIGGER_ONESHOT=m
@@ -449,6 +456,8 @@ CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_SPLIT=y
+CONFIG_DEBUG_INFO_DWARF4=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
index b445a5d56f4342b71540e40c1ce298e0ad786688..89a3a3e592d6646783b9b08533a9704d929da70b 100644 (file)
@@ -364,7 +364,7 @@ static struct crypto_alg aes_algs[] = { {
        .cra_blkcipher = {
                .min_keysize    = AES_MIN_KEY_SIZE,
                .max_keysize    = AES_MAX_KEY_SIZE,
-               .ivsize         = AES_BLOCK_SIZE,
+               .ivsize         = 0,
                .setkey         = ce_aes_setkey,
                .encrypt        = ecb_encrypt,
                .decrypt        = ecb_decrypt,
@@ -441,7 +441,7 @@ static struct crypto_alg aes_algs[] = { {
        .cra_ablkcipher = {
                .min_keysize    = AES_MIN_KEY_SIZE,
                .max_keysize    = AES_MAX_KEY_SIZE,
-               .ivsize         = AES_BLOCK_SIZE,
+               .ivsize         = 0,
                .setkey         = ablk_set_key,
                .encrypt        = ablk_encrypt,
                .decrypt        = ablk_decrypt,
index 7da5503c0591411f43df6bc767fb8c4eef314789..e08d151840567dcb6085271200601666836b0771 100644 (file)
@@ -117,6 +117,7 @@ static inline u32 gic_read_iar(void)
        u32 irqstat;
 
        asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat));
+       dsb(sy);
        return irqstat;
 }
 
index 0375c8caa06194591e065f94bbb3d57a0565c847..9408a994cc91792bcf89a57d67982e21c677d9d7 100644 (file)
@@ -35,14 +35,21 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page,
             dma_addr_t dev_addr, unsigned long offset, size_t size,
             enum dma_data_direction dir, struct dma_attrs *attrs)
 {
-       bool local = XEN_PFN_DOWN(dev_addr) == page_to_xen_pfn(page);
+       unsigned long page_pfn = page_to_xen_pfn(page);
+       unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr);
+       unsigned long compound_pages =
+               (1<<compound_order(page)) * XEN_PFN_PER_PAGE;
+       bool local = (page_pfn <= dev_pfn) &&
+               (dev_pfn - page_pfn < compound_pages);
+
        /*
-        * Dom0 is mapped 1:1, while the Linux page can be spanned accross
-        * multiple Xen page, it's not possible to have a mix of local and
-        * foreign Xen page. So if the first xen_pfn == mfn the page is local
-        * otherwise it's a foreign page grant-mapped in dom0. If the page is
-        * local we can safely call the native dma_ops function, otherwise we
-        * call the xen specific function.
+        * Dom0 is mapped 1:1, while the Linux page can span across
+        * multiple Xen pages, it's not possible for it to contain a
+        * mix of local and foreign Xen pages. So if the first xen_pfn
+        * == mfn the page is local otherwise it's a foreign page
+        * grant-mapped in dom0. If the page is local we can safely
+        * call the native dma_ops function, otherwise we call the xen
+        * specific function.
         */
        if (local)
                __generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs);
index 2c5f160be65e44cbabc2c5d01b023d56df0a1985..ad325a8c7e1e5d1dfbad11e8846169696d36e6bc 100644 (file)
@@ -88,6 +88,7 @@ obj-$(CONFIG_DEBUG_LL)        += debug.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 
 obj-$(CONFIG_ARM_VIRT_EXT)     += hyp-stub.o
+AFLAGS_hyp-stub.o              :=-Wa,-march=armv7-a
 ifeq ($(CONFIG_ARM_PSCI),y)
 obj-$(CONFIG_SMP)              += psci_smp.o
 endif
index 5fa69d7bae58a06ef19f7ca72fd04cf6603d6963..99361f11354a0d8928c9aaead7fdf5e09436b3ac 100644 (file)
@@ -161,7 +161,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        u64 val;
 
        val = kvm_arm_timer_get_reg(vcpu, reg->id);
-       return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
+       return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
 static unsigned long num_core_regs(void)
index 7f33b2056ae6d92f568ad71fbf28cd52044b11fb..0f6600f05137921b61fe5c9a80b87302e7d03234 100644 (file)
@@ -206,7 +206,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
        run->mmio.is_write      = is_write;
        run->mmio.phys_addr     = fault_ipa;
        run->mmio.len           = len;
-       memcpy(run->mmio.data, data_buf, len);
+       if (is_write)
+               memcpy(run->mmio.data, data_buf, len);
 
        if (!ret) {
                /* We handled the access successfully in the kernel. */
index 809827265fb39d1b8a7178481bb91e87951c4a14..bab814d2f37dcc9a18229d5e912422a653307088 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/setup.h>
 #include <asm/mach/arch.h>
+#include <asm/system_info.h>
 
 #include "common.h"
 
@@ -77,12 +78,31 @@ static const char *const n900_boards_compat[] __initconst = {
        NULL,
 };
 
+/* Set system_rev from atags */
+static void __init rx51_set_system_rev(const struct tag *tags)
+{
+       const struct tag *tag;
+
+       if (tags->hdr.tag != ATAG_CORE)
+               return;
+
+       for_each_tag(tag, tags) {
+               if (tag->hdr.tag == ATAG_REVISION) {
+                       system_rev = tag->u.revision.rev;
+                       break;
+               }
+       }
+}
+
 /* Legacy userspace on Nokia N900 needs ATAGS exported in /proc/atags,
  * save them while the data is still not overwritten
  */
 static void __init rx51_reserve(void)
 {
-       save_atags((const struct tag *)(PAGE_OFFSET + 0x100));
+       const struct tag *tags = (const struct tag *)(PAGE_OFFSET + 0x100);
+
+       save_atags(tags);
+       rx51_set_system_rev(tags);
        omap_reserve();
 }
 
index 9cda974a3009f3295e7bd013709f1bf586752282..d7f1d69daf6d4d083005e15d11d556c412aacfbc 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/pinctrl/machine.h>
-#include <linux/platform_data/mailbox-omap.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -66,32 +65,6 @@ static int __init omap3_l3_init(void)
 }
 omap_postcore_initcall(omap3_l3_init);
 
-#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
-static inline void __init omap_init_mbox(void)
-{
-       struct omap_hwmod *oh;
-       struct platform_device *pdev;
-       struct omap_mbox_pdata *pdata;
-
-       oh = omap_hwmod_lookup("mailbox");
-       if (!oh) {
-               pr_err("%s: unable to find hwmod\n", __func__);
-               return;
-       }
-       if (!oh->dev_attr) {
-               pr_err("%s: hwmod doesn't have valid attrs\n", __func__);
-               return;
-       }
-
-       pdata = (struct omap_mbox_pdata *)oh->dev_attr;
-       pdev = omap_device_build("omap-mailbox", -1, oh, pdata, sizeof(*pdata));
-       WARN(IS_ERR(pdev), "%s: could not build device, err %ld\n",
-                                               __func__, PTR_ERR(pdev));
-}
-#else
-static inline void omap_init_mbox(void) { }
-#endif /* CONFIG_OMAP2PLUS_MBOX */
-
 static inline void omap_init_sti(void) {}
 
 #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
@@ -229,7 +202,6 @@ static int __init omap2_init_devices(void)
                 * please keep these calls, and their implementations above,
                 * in alphabetical order so they're easier to sort through.
                 */
-               omap_init_mbox();
                omap_init_mcspi();
                omap_init_sham();
                omap_init_aes();
index 7b76ce01c21dd3aa3b4cad36ce2431f3c8350900..8633c703546a65c2e5b0071ffca0d5a12b664884 100644 (file)
@@ -101,10 +101,8 @@ static void omap2_onenand_set_async_mode(void __iomem *onenand_base)
 
 static void set_onenand_cfg(void __iomem *onenand_base)
 {
-       u32 reg;
+       u32 reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT;
 
-       reg = readw(onenand_base + ONENAND_REG_SYS_CFG1);
-       reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
        reg |=  (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
                ONENAND_SYS_CFG1_BL_16;
        if (onenand_flags & ONENAND_FLAG_SYNCREAD)
@@ -123,6 +121,7 @@ static void set_onenand_cfg(void __iomem *onenand_base)
                reg |= ONENAND_SYS_CFG1_VHF;
        else
                reg &= ~ONENAND_SYS_CFG1_VHF;
+
        writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
 }
 
@@ -289,6 +288,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
                }
        }
 
+       onenand_async.sync_write = true;
        omap2_onenand_calc_async_timings(&t);
 
        ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
index 0437537751bc0c593dbe3554e216727b845f3a78..f7ff3b9dad8784aeab4d3752061514a8498774ae 100644 (file)
@@ -191,12 +191,22 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_device *od;
+       int err;
 
        switch (event) {
        case BUS_NOTIFY_DEL_DEVICE:
                if (pdev->archdata.od)
                        omap_device_delete(pdev->archdata.od);
                break;
+       case BUS_NOTIFY_UNBOUND_DRIVER:
+               od = to_omap_device(pdev);
+               if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
+                       dev_info(dev, "enabled after unload, idling\n");
+                       err = omap_device_idle(pdev);
+                       if (err)
+                               dev_err(dev, "failed to idle\n");
+               }
+               break;
        case BUS_NOTIFY_ADD_DEVICE:
                if (pdev->dev.of_node)
                        omap_device_build_from_dt(pdev);
@@ -602,8 +612,10 @@ static int _od_runtime_resume(struct device *dev)
        int ret;
 
        ret = omap_device_enable(pdev);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "use pm_runtime_put_sync_suspend() in driver?\n");
                return ret;
+       }
 
        return pm_generic_runtime_resume(dev);
 }
index e781e4fae13a92fd68aa04ac891b9731bc8fa60e..a935d28443dab40e1a8005b7144aeb8de436c73c 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/platform_data/pinctrl-single.h>
 #include <linux/platform_data/iommu-omap.h>
 #include <linux/platform_data/wkup_m3.h>
+#include <linux/platform_data/pwm_omap_dmtimer.h>
+#include <plat/dmtimer.h>
 
 #include "common.h"
 #include "common-board-devices.h"
@@ -449,6 +451,24 @@ void omap_auxdata_legacy_init(struct device *dev)
        dev->platform_data = &twl_gpio_auxdata;
 }
 
+/* Dual mode timer PWM callbacks platdata */
+#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
+struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = {
+       .request_by_node = omap_dm_timer_request_by_node,
+       .free = omap_dm_timer_free,
+       .enable = omap_dm_timer_enable,
+       .disable = omap_dm_timer_disable,
+       .get_fclk = omap_dm_timer_get_fclk,
+       .start = omap_dm_timer_start,
+       .stop = omap_dm_timer_stop,
+       .set_load = omap_dm_timer_set_load,
+       .set_match = omap_dm_timer_set_match,
+       .set_pwm = omap_dm_timer_set_pwm,
+       .set_prescaler = omap_dm_timer_set_prescaler,
+       .write_counter = omap_dm_timer_write_counter,
+};
+#endif
+
 /*
  * Few boards still need auxdata populated before we populate
  * the dev entries in of_platform_populate().
@@ -502,6 +522,9 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("ti,am4372-wkup-m3", 0x44d00000, "44d00000.wkup_m3",
                       &wkup_m3_data),
 #endif
+#if IS_ENABLED(CONFIG_OMAP_DM_TIMER)
+       OF_DEV_AUXDATA("ti,omap-dmtimer-pwm", 0, NULL, &pwm_dmtimer_pdata),
+#endif
 #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
        OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu",
                       &omap4_iommu_pdata),
index eafd120b53f1bc15c82f2cc47dc8033e31ca566e..1b9f0520dea9154afa31f9668241e03f211fdc6a 100644 (file)
@@ -86,13 +86,18 @@ ENTRY(enable_omap3630_toggle_l2_on_restore)
        stmfd   sp!, {lr}       @ save registers on stack
        /* Setup so that we will disable and enable l2 */
        mov     r1, #0x1
-       adrl    r2, l2dis_3630  @ may be too distant for plain adr
-       str     r1, [r2]
+       adrl    r3, l2dis_3630_offset   @ may be too distant for plain adr
+       ldr     r2, [r3]                @ value for offset
+       str     r1, [r2, r3]            @ write to l2dis_3630
        ldmfd   sp!, {pc}       @ restore regs and return
 ENDPROC(enable_omap3630_toggle_l2_on_restore)
 
-       .text
-/* Function to call rom code to save secure ram context */
+/*
+ * Function to call rom code to save secure ram context. This gets
+ * relocated to SRAM, so it can be all in .data section. Otherwise
+ * we need to initialize api_params separately.
+ */
+       .data
        .align  3
 ENTRY(save_secure_ram_context)
        stmfd   sp!, {r4 - r11, lr}     @ save registers on stack
@@ -126,6 +131,8 @@ ENDPROC(save_secure_ram_context)
 ENTRY(save_secure_ram_context_sz)
        .word   . - save_secure_ram_context
 
+       .text
+
 /*
  * ======================
  * == Idle entry point ==
@@ -289,12 +296,6 @@ wait_sdrc_ready:
        bic     r5, r5, #0x40
        str     r5, [r4]
 
-/*
- * PC-relative stores lead to undefined behaviour in Thumb-2: use a r7 as a
- * base instead.
- * Be careful not to clobber r7 when maintaing this code.
- */
-
 is_dll_in_lock_mode:
        /* Is dll in lock mode? */
        ldr     r4, sdrc_dlla_ctrl
@@ -302,11 +303,7 @@ is_dll_in_lock_mode:
        tst     r5, #0x4
        bne     exit_nonoff_modes       @ Return if locked
        /* wait till dll locks */
-       adr     r7, kick_counter
 wait_dll_lock_timed:
-       ldr     r4, wait_dll_lock_counter
-       add     r4, r4, #1
-       str     r4, [r7, #wait_dll_lock_counter - kick_counter]
        ldr     r4, sdrc_dlla_status
        /* Wait 20uS for lock */
        mov     r6, #8
@@ -330,9 +327,6 @@ kick_dll:
        orr     r6, r6, #(1<<3)         @ enable dll
        str     r6, [r4]
        dsb
-       ldr     r4, kick_counter
-       add     r4, r4, #1
-       str     r4, [r7]                @ kick_counter
        b       wait_dll_lock_timed
 
 exit_nonoff_modes:
@@ -360,15 +354,6 @@ sdrc_dlla_status:
        .word   SDRC_DLLA_STATUS_V
 sdrc_dlla_ctrl:
        .word   SDRC_DLLA_CTRL_V
-       /*
-        * When exporting to userspace while the counters are in SRAM,
-        * these 2 words need to be at the end to facilitate retrival!
-        */
-kick_counter:
-       .word   0
-wait_dll_lock_counter:
-       .word   0
-
 ENTRY(omap3_do_wfi_sz)
        .word   . - omap3_do_wfi
 
@@ -437,7 +422,9 @@ ENTRY(omap3_restore)
        cmp     r2, #0x0        @ Check if target power state was OFF or RET
        bne     logic_l1_restore
 
-       ldr     r0, l2dis_3630
+       adr     r1, l2dis_3630_offset   @ address for offset
+       ldr     r0, [r1]                @ value for offset
+       ldr     r0, [r1, r0]            @ value at l2dis_3630
        cmp     r0, #0x1        @ should we disable L2 on 3630?
        bne     skipl2dis
        mrc     p15, 0, r0, c1, c0, 1
@@ -449,12 +436,14 @@ skipl2dis:
        and     r1, #0x700
        cmp     r1, #0x300
        beq     l2_inv_gp
+       adr     r0, l2_inv_api_params_offset
+       ldr     r3, [r0]
+       add     r3, r3, r0              @ r3 points to dummy parameters
        mov     r0, #40                 @ set service ID for PPA
        mov     r12, r0                 @ copy secure Service ID in r12
        mov     r1, #0                  @ set task id for ROM code in r1
        mov     r2, #4                  @ set some flags in r2, r6
        mov     r6, #0xff
-       adr     r3, l2_inv_api_params   @ r3 points to dummy parameters
        dsb                             @ data write barrier
        dmb                             @ data memory barrier
        smc     #1                      @ call SMI monitor (smi #1)
@@ -488,8 +477,8 @@ skipl2dis:
        b       logic_l1_restore
 
        .align
-l2_inv_api_params:
-       .word   0x1, 0x00
+l2_inv_api_params_offset:
+       .long   l2_inv_api_params - .
 l2_inv_gp:
        /* Execute smi to invalidate L2 cache */
        mov r12, #0x1                   @ set up to invalidate L2
@@ -506,7 +495,9 @@ l2_inv_gp:
        mov     r12, #0x2
        smc     #0                      @ Call SMI monitor (smieq)
 logic_l1_restore:
-       ldr     r1, l2dis_3630
+       adr     r0, l2dis_3630_offset   @ adress for offset
+       ldr     r1, [r0]                @ value for offset
+       ldr     r1, [r0, r1]            @ value at l2dis_3630
        cmp     r1, #0x1                @ Test if L2 re-enable needed on 3630
        bne     skipl2reen
        mrc     p15, 0, r1, c1, c0, 1
@@ -535,9 +526,17 @@ control_stat:
        .word   CONTROL_STAT
 control_mem_rta:
        .word   CONTROL_MEM_RTA_CTRL
+l2dis_3630_offset:
+       .long   l2dis_3630 - .
+
+       .data
 l2dis_3630:
        .word   0
 
+       .data
+l2_inv_api_params:
+       .word   0x1, 0x00
+
 /*
  * Internal functions
  */
index 9b09d85d811a1c52b0fa735a2e2743e05346843d..c7a3b4aab4b5441249ddd9a7fdc362ef9370d737 100644 (file)
        dsb
 .endm
 
-ppa_zero_params:
-       .word           0x0
-
-ppa_por_params:
-       .word           1, 0
-
 #ifdef CONFIG_ARCH_OMAP4
 
 /*
@@ -266,7 +260,9 @@ ENTRY(omap4_cpu_resume)
        beq     skip_ns_smp_enable
 ppa_actrl_retry:
        mov     r0, #OMAP4_PPA_CPU_ACTRL_SMP_INDEX
-       adr     r3, ppa_zero_params             @ Pointer to parameters
+       adr     r1, ppa_zero_params_offset
+       ldr     r3, [r1]
+       add     r3, r3, r1                      @ Pointer to ppa_zero_params
        mov     r1, #0x0                        @ Process ID
        mov     r2, #0x4                        @ Flag
        mov     r6, #0xff
@@ -303,7 +299,9 @@ skip_ns_smp_enable:
        ldr     r0, =OMAP4_PPA_L2_POR_INDEX
        ldr     r1, =OMAP44XX_SAR_RAM_BASE
        ldr     r4, [r1, #L2X0_PREFETCH_CTRL_OFFSET]
-       adr     r3, ppa_por_params
+       adr     r1, ppa_por_params_offset
+       ldr     r3, [r1]
+       add     r3, r3, r1                      @ Pointer to ppa_por_params
        str     r4, [r3, #0x04]
        mov     r1, #0x0                        @ Process ID
        mov     r2, #0x4                        @ Flag
@@ -328,6 +326,8 @@ skip_l2en:
 #endif
 
        b       cpu_resume                      @ Jump to generic resume
+ppa_por_params_offset:
+       .long   ppa_por_params - .
 ENDPROC(omap4_cpu_resume)
 #endif /* CONFIG_ARCH_OMAP4 */
 
@@ -380,4 +380,13 @@ ENTRY(omap_do_wfi)
        nop
 
        ldmfd   sp!, {pc}
+ppa_zero_params_offset:
+       .long   ppa_zero_params - .
 ENDPROC(omap_do_wfi)
+
+       .data
+ppa_zero_params:
+       .word           0
+
+ppa_por_params:
+       .word           1, 0
index def40a0dd60cd290d91233cc47a1a8bad4ea6aa1..70ab4a25a5f853d4d8dade14490618d2523fcd13 100644 (file)
@@ -1,5 +1,6 @@
 menuconfig ARCH_REALVIEW
-       bool "ARM Ltd. RealView family" if ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7
+       bool "ARM Ltd. RealView family"
+       depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7
        select ARM_AMBA
        select ARM_TIMER_SP804
        select COMMON_CLK_VERSATILE
index 65585392655b3ac499dff837b2f6adfe02d5a708..6964e88760614ba1f8fa60c7f6fd12f3b07dfe20 100644 (file)
@@ -80,7 +80,7 @@ static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
                     virt_to_phys(versatile_secondary_startup));
 }
 
-struct smp_operations realview_dt_smp_ops __initdata = {
+static const struct smp_operations realview_dt_smp_ops __initconst = {
        .smp_prepare_cpus       = realview_smp_prepare_cpus,
        .smp_secondary_init     = versatile_secondary_init,
        .smp_boot_secondary     = versatile_boot_secondary,
index 9cb11215cebaeb2e4e0a8355589ce6d7e5270b78..b3a4ed5289ec7c8c35661a1b6062d4387d13d097 100644 (file)
@@ -4,7 +4,6 @@
 extern void shmobile_init_delay(void);
 extern void shmobile_boot_vector(void);
 extern unsigned long shmobile_boot_fn;
-extern unsigned long shmobile_boot_arg;
 extern unsigned long shmobile_boot_size;
 extern void shmobile_smp_boot(void);
 extern void shmobile_smp_sleep(void);
index fa5248c52399c9b5e78e3c1cd7c167523f306424..5e503d91ad70ddf2b8f375ffaf36a09361c9be8c 100644 (file)
@@ -38,9 +38,3 @@ ENTRY(shmobile_boot_scu)
 
        b       secondary_startup
 ENDPROC(shmobile_boot_scu)
-
-       .text
-       .align  2
-       .globl  shmobile_scu_base
-shmobile_scu_base:
-       .space  4
index 330c1fc63197df89684e03578c1c0693b8e6f24f..32e0bf6e3ccb9bd317c68be65ef7071a0c05eeed 100644 (file)
@@ -24,7 +24,6 @@
        .arm
        .align  12
 ENTRY(shmobile_boot_vector)
-       ldr     r0, 2f
        ldr     r1, 1f
        bx      r1
 
@@ -34,9 +33,6 @@ ENDPROC(shmobile_boot_vector)
        .globl  shmobile_boot_fn
 shmobile_boot_fn:
 1:     .space  4
-       .globl  shmobile_boot_arg
-shmobile_boot_arg:
-2:     .space  4
        .globl  shmobile_boot_size
 shmobile_boot_size:
        .long   . - shmobile_boot_vector
@@ -46,13 +42,15 @@ shmobile_boot_size:
  */
 
 ENTRY(shmobile_smp_boot)
-                                               @ r0 = MPIDR_HWID_BITMASK
        mrc     p15, 0, r1, c0, c0, 5           @ r1 = MPIDR
-       and     r0, r1, r0                      @ r0 = cpu_logical_map() value
+       and     r0, r1, #0xffffff               @ MPIDR_HWID_BITMASK
+                                               @ r0 = cpu_logical_map() value
        mov     r1, #0                          @ r1 = CPU index
-       adr     r5, 1f                          @ array of per-cpu mpidr values
-       adr     r6, 2f                          @ array of per-cpu functions
-       adr     r7, 3f                          @ array of per-cpu arguments
+       adr     r2, 1f
+       ldmia   r2, {r5, r6, r7}
+       add     r5, r5, r2                      @ array of per-cpu mpidr values
+       add     r6, r6, r2                      @ array of per-cpu functions
+       add     r7, r7, r2                      @ array of per-cpu arguments
 
 shmobile_smp_boot_find_mpidr:
        ldr     r8, [r5, r1, lsl #2]
@@ -80,12 +78,18 @@ ENTRY(shmobile_smp_sleep)
        b       shmobile_smp_boot
 ENDPROC(shmobile_smp_sleep)
 
+       .align  2
+1:     .long   shmobile_smp_mpidr - .
+       .long   shmobile_smp_fn - 1b
+       .long   shmobile_smp_arg - 1b
+
+       .bss
        .globl  shmobile_smp_mpidr
 shmobile_smp_mpidr:
-1:     .space  NR_CPUS * 4
+       .space  NR_CPUS * 4
        .globl  shmobile_smp_fn
 shmobile_smp_fn:
-2:     .space  NR_CPUS * 4
+       .space  NR_CPUS * 4
        .globl  shmobile_smp_arg
 shmobile_smp_arg:
-3:     .space  NR_CPUS * 4
+       .space  NR_CPUS * 4
index 911884f7e28b174c271c6724c863520afe859868..aba75c89f9c1c5eb2d7070def50bb8e77118df3c 100644 (file)
@@ -123,7 +123,6 @@ void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
 {
        /* install boot code shared by all CPUs */
        shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
-       shmobile_boot_arg = MPIDR_HWID_BITMASK;
 
        /* perform per-cpu setup */
        apmu_parse_cfg(apmu_init_cpu, apmu_config, num);
index 64663110ab6ca0e1d8f06cc04e69175165e2cace..081a097c9219f41785229c9492b95b250151c1f4 100644 (file)
@@ -17,6 +17,9 @@
 #include <asm/smp_scu.h>
 #include "common.h"
 
+
+void __iomem *shmobile_scu_base;
+
 static int shmobile_smp_scu_notifier_call(struct notifier_block *nfb,
                                          unsigned long action, void *hcpu)
 {
@@ -41,7 +44,6 @@ void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus)
 {
        /* install boot code shared by all CPUs */
        shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
-       shmobile_boot_arg = MPIDR_HWID_BITMASK;
 
        /* enable SCU and cache coherency on booting CPU */
        scu_enable(shmobile_scu_base);
index b854fe2095ad14616b7c4aae209b47f7e4f7ded3..0b024a9dbd4397e7235827dbdaf62d65a5ad3d16 100644 (file)
@@ -92,8 +92,6 @@ static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus)
 {
        /* Map the reset vector (in headsmp-scu.S, headsmp.S) */
        __raw_writel(__pa(shmobile_boot_vector), AVECR);
-       shmobile_boot_fn = virt_to_phys(shmobile_boot_scu);
-       shmobile_boot_arg = (unsigned long)shmobile_scu_base;
 
        /* setup r8a7779 specific SCU bits */
        shmobile_scu_base = IOMEM(R8A7779_SCU_BASE);
index d6a3714b096e69801c381d320a0ccb1be3472585..ebe15b93bbe870804eb17759b05096a8f7298167 100644 (file)
@@ -1,5 +1,6 @@
 config ARCH_TANGO
-       bool "Sigma Designs Tango4 (SMP87xx)" if ARCH_MULTI_V7
+       bool "Sigma Designs Tango4 (SMP87xx)"
+       depends on ARCH_MULTI_V7
        # Cortex-A9 MPCore r3p0, PL310 r3p2
        select ARCH_HAS_HOLES_MEMORYMODEL
        select ARM_ERRATA_754322
index a18d5a34e2f5738e4f62bd24bf8a0b9edff7a3e8..a21f55e000d258c734535cbfc9df57744599887a 100644 (file)
@@ -9,7 +9,7 @@ static int tango_boot_secondary(unsigned int cpu, struct task_struct *idle)
        return 0;
 }
 
-static struct smp_operations tango_smp_ops __initdata = {
+static const struct smp_operations tango_smp_ops __initconst = {
        .smp_boot_secondary     = tango_boot_secondary,
 };
 
index 49d1110cff5341954e3d980d003fda4f516138f0..52db8bf7e153b09b4d7532cae4ddff12213f2921 100644 (file)
  *
  */
 
+#include <linux/property.h>
 #include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
-#include <linux/rfkill-gpio.h>
 
 #include "board.h"
 
-static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
-       .name   = "wifi_rfkill",
-       .type   = RFKILL_TYPE_WLAN,
+static struct property_entry __initdata wifi_rfkill_prop[] = {
+       PROPERTY_ENTRY_STRING("name", "wifi_rfkill"),
+       PROPERTY_ENTRY_STRING("type", "wlan"),
+       { },
+};
+
+static struct property_set __initdata wifi_rfkill_pset = {
+       .properties = wifi_rfkill_prop,
 };
 
 static struct platform_device wifi_rfkill_device = {
        .name   = "rfkill_gpio",
        .id     = -1,
-       .dev    = {
-               .platform_data = &wifi_rfkill_platform_data,
-       },
 };
 
 static struct gpiod_lookup_table wifi_gpio_lookup = {
@@ -47,6 +49,7 @@ static struct gpiod_lookup_table wifi_gpio_lookup = {
 
 void __init tegra_paz00_wifikill_init(void)
 {
+       platform_device_add_properties(&wifi_rfkill_device, &wifi_rfkill_pset);
        gpiod_add_lookup_table(&wifi_gpio_lookup);
        platform_device_register(&wifi_rfkill_device);
 }
index 4b4058db0781f63e307d4f5101a74d5330ddf337..66353caa35b9f78fa2aa4754dea3ce813593303f 100644 (file)
@@ -173,7 +173,7 @@ unsigned long arch_mmap_rnd(void)
 {
        unsigned long rnd;
 
-       rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+       rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 
        return rnd << PAGE_SHIFT;
 }
index cf30daff8932504f95422c2aa3b5882b154713b5..d19b1ad29b075fd8624d34edb0d9c18c9ef11e51 100644 (file)
@@ -49,6 +49,9 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
+       if (!numpages)
+               return 0;
+
        if (start < MODULES_VADDR || start >= MODULES_END)
                return -EINVAL;
 
index 307237cfe728b152e350b5fb4f1c1abc18d6fb4c..b5e3f6d42b88bef5f17d3c21a80f9e97a013b676 100644 (file)
@@ -88,7 +88,7 @@ Image: vmlinux
 Image.%: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
-zinstall install: vmlinux
+zinstall install:
        $(Q)$(MAKE) $(build)=$(boot) $@
 
 %.dtb: scripts
index abcbba2f01baad4c76f0c414372ba4713beafa11..305c552b5ec16ee903c4b6d0a73066a191dd7d31 100644 (file)
@@ -34,10 +34,10 @@ $(obj)/Image.lzma: $(obj)/Image FORCE
 $(obj)/Image.lzo: $(obj)/Image FORCE
        $(call if_changed,lzo)
 
-install: $(obj)/Image
+install:
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
        $(obj)/Image System.map "$(INSTALL_PATH)"
 
-zinstall: $(obj)/Image.gz
+zinstall:
        $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
        $(obj)/Image.gz System.map "$(INSTALL_PATH)"
index 5d87a3dc44b86090bc2b275e0cbe14d75f75aadc..278f106a0054c5f53b66fb8453700ffbd0acee32 100644 (file)
                              <0x0 0x1f600000 0x0 0Xd100>,
                              <0x0 0x20000000 0x0 0X220000>;
                        interrupts = <0 108 4>,
-                                    <0 109 4>;
+                                    <0 109 4>,
+                                    <0 110 4>,
+                                    <0 111 4>,
+                                    <0 112 4>,
+                                    <0 113 4>,
+                                    <0 114 4>,
+                                    <0 115 4>;
                        port-id = <1>;
                        dma-coherent;
                        clocks = <&xge1clk 0>;
index fe30f7671ea3bc2707fb70a312c70e18bb1c2550..cafb2c2715fbae02551ffe32bc2693463d665423 100644 (file)
                              <0x0 0x18000000 0x0 0X200>;
                        reg-names = "enet_csr", "ring_csr", "ring_cmd";
                        interrupts = <0x0 0x60 0x4>,
-                                    <0x0 0x61 0x4>;
+                                    <0x0 0x61 0x4>,
+                                    <0x0 0x62 0x4>,
+                                    <0x0 0x63 0x4>,
+                                    <0x0 0x64 0x4>,
+                                    <0x0 0x65 0x4>,
+                                    <0x0 0x66 0x4>,
+                                    <0x0 0x67 0x4>;
                        dma-coherent;
                        clocks = <&xge0clk 0>;
                        /* mac address will be overwritten by the bootloader */
index dd5158eb5872396693bba678cda765a719e25e97..e5b59ca9debb1916764746bb168d969572e17771 100644 (file)
                             <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+                            <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
index 7dfe1c085966de45b27ee1b10f8073af9c5914dc..62f33fc84e3ea7afd11655069a16a45b7e120b90 100644 (file)
@@ -12,6 +12,8 @@
                rtc1 = "/rtc@0,7000e000";
        };
 
+       chosen { };
+
        memory {
                device_type = "memory";
                reg = <0x0 0x80000000 0x0 0x80000000>;
index 12ed78aa6f0c27d4a76066b8064d8a3654db9ed0..d91e1f0225733750097f4533c7a2a9045c9ab175 100644 (file)
 #   $4 - default install path (blank if root directory)
 #
 
+verify () {
+       if [ ! -f "$1" ]; then
+               echo ""                                                   1>&2
+               echo " *** Missing file: $1"                              1>&2
+               echo ' *** You need to run "make" before "make install".' 1>&2
+               echo ""                                                   1>&2
+               exit 1
+       fi
+}
+
+# Make sure the files actually exist
+verify "$2"
+verify "$3"
+
 # User may have a custom install script
 if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
 if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
index 05d9e16c0dfdd81a8a6ffe141e5c6f5cc96b3e7e..7a3d22a46faf502224fa397c527ab6338bac8933 100644 (file)
@@ -294,7 +294,7 @@ static struct crypto_alg aes_algs[] = { {
        .cra_blkcipher = {
                .min_keysize    = AES_MIN_KEY_SIZE,
                .max_keysize    = AES_MAX_KEY_SIZE,
-               .ivsize         = AES_BLOCK_SIZE,
+               .ivsize         = 0,
                .setkey         = aes_setkey,
                .encrypt        = ecb_encrypt,
                .decrypt        = ecb_decrypt,
@@ -371,7 +371,7 @@ static struct crypto_alg aes_algs[] = { {
        .cra_ablkcipher = {
                .min_keysize    = AES_MIN_KEY_SIZE,
                .max_keysize    = AES_MAX_KEY_SIZE,
-               .ivsize         = AES_BLOCK_SIZE,
+               .ivsize         = 0,
                .setkey         = ablk_set_key,
                .encrypt        = ablk_encrypt,
                .decrypt        = ablk_decrypt,
index 2731d3b25ed2e338e76966b5efd86658b7e22263..8ec88e5b290f9bc12a416841e73ef56414972b59 100644 (file)
@@ -103,6 +103,7 @@ static inline u64 gic_read_iar_common(void)
        u64 irqstat;
 
        asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+       dsb(sy);
        return irqstat;
 }
 
index 007a69fc4f408d5f2f7e58f4070b6cb354a5e022..5f3ab8c1db55cca8dbf4c9e1fc315e90335b6d60 100644 (file)
@@ -121,6 +121,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                return -EFAULT;
 
        asm volatile("// futex_atomic_cmpxchg_inatomic\n"
+ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
 "      prfm    pstl1strm, %2\n"
 "1:    ldxr    %w1, %2\n"
 "      sub     %w3, %w1, %w4\n"
@@ -137,6 +138,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 "      .align  3\n"
 "      .quad   1b, 4b, 2b, 4b\n"
 "      .popsection\n"
+ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
        : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
        : "r" (oldval), "r" (newval), "Ir" (-EFAULT)
        : "memory");
index 738a95f93e493e3002ac8749857f8599c5ae3404..d201d4b396d15fee10129494b6d274bbf77a2320 100644 (file)
 #define TCR_EL2_MASK   (TCR_EL2_TG0 | TCR_EL2_SH0 | \
                         TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
 
-#define TCR_EL2_FLAGS  (TCR_EL2_RES1 | TCR_EL2_PS_40B)
-
 /* VTCR_EL2 Registers bits */
 #define VTCR_EL2_RES1          (1 << 31)
 #define VTCR_EL2_PS_MASK       (7 << 16)
 #define CPTR_EL2_TCPAC (1 << 31)
 #define CPTR_EL2_TTA   (1 << 20)
 #define CPTR_EL2_TFP   (1 << CPTR_EL2_TFP_SHIFT)
+#define CPTR_EL2_DEFAULT       0x000033ff
 
 /* Hyp Debug Configuration Register bits */
 #define MDCR_EL2_TDRA          (1 << 11)
index 3066328cd86b69a91274e0cb841059b428666140..779a5872a2c5fb5f9aa9b49af6f77391aefc2336 100644 (file)
@@ -127,10 +127,14 @@ static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
 {
-       u32 mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
+       u32 mode;
 
-       if (vcpu_mode_is_32bit(vcpu))
+       if (vcpu_mode_is_32bit(vcpu)) {
+               mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
                return mode > COMPAT_PSR_MODE_USR;
+       }
+
+       mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
 
        return mode != PSR_MODE_EL0t;
 }
index 9b2f5a9d019df493fa6021ee3ca6b4779401d8c4..ae615b9d9a551bab47bb4900e867c8d15db02bb1 100644 (file)
@@ -39,6 +39,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/personality.h> /* for READ_IMPLIES_EXEC */
 #include <asm/pgtable-types.h>
 
 extern void __cpu_clear_user_page(void *p, unsigned long user);
index bf464de33f52f77d2520db0a12e53b3749ced6cc..f5060867458024a5a61ccfd4a77330c728e13010 100644 (file)
 /*
  * VMALLOC and SPARSEMEM_VMEMMAP ranges.
  *
- * VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array
+ * VMEMAP_SIZE: allows the whole linear region to be covered by a struct page array
  *     (rounded up to PUD_SIZE).
  * VMALLOC_START: beginning of the kernel VA space
  * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space,
  *     fixed mappings and modules
  */
-#define VMEMMAP_SIZE           ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
+#define VMEMMAP_SIZE           ALIGN((1UL << (VA_BITS - PAGE_SHIFT - 1)) * sizeof(struct page), PUD_SIZE)
 
 #ifndef CONFIG_KASAN
 #define VMALLOC_START          (VA_START)
@@ -51,7 +51,8 @@
 
 #define VMALLOC_END            (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
 
-#define vmemmap                        ((struct page *)(VMALLOC_END + SZ_64K))
+#define VMEMMAP_START          (VMALLOC_END + SZ_64K)
+#define vmemmap                        ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
 
 #define FIRST_USER_ADDRESS     0UL
 
index 8aee3aeec3e687edde6f5be67233299e7a4f7d4f..c536c9e307b9a484dca6d03572f28cbf9f8c0667 100644 (file)
@@ -226,11 +226,28 @@ static int call_step_hook(struct pt_regs *regs, unsigned int esr)
        return retval;
 }
 
+static void send_user_sigtrap(int si_code)
+{
+       struct pt_regs *regs = current_pt_regs();
+       siginfo_t info = {
+               .si_signo       = SIGTRAP,
+               .si_errno       = 0,
+               .si_code        = si_code,
+               .si_addr        = (void __user *)instruction_pointer(regs),
+       };
+
+       if (WARN_ON(!user_mode(regs)))
+               return;
+
+       if (interrupts_enabled(regs))
+               local_irq_enable();
+
+       force_sig_info(SIGTRAP, &info, current);
+}
+
 static int single_step_handler(unsigned long addr, unsigned int esr,
                               struct pt_regs *regs)
 {
-       siginfo_t info;
-
        /*
         * If we are stepping a pending breakpoint, call the hw_breakpoint
         * handler first.
@@ -239,11 +256,7 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
                return 0;
 
        if (user_mode(regs)) {
-               info.si_signo = SIGTRAP;
-               info.si_errno = 0;
-               info.si_code  = TRAP_HWBKPT;
-               info.si_addr  = (void __user *)instruction_pointer(regs);
-               force_sig_info(SIGTRAP, &info, current);
+               send_user_sigtrap(TRAP_HWBKPT);
 
                /*
                 * ptrace will disable single step unless explicitly
@@ -307,17 +320,8 @@ static int call_break_hook(struct pt_regs *regs, unsigned int esr)
 static int brk_handler(unsigned long addr, unsigned int esr,
                       struct pt_regs *regs)
 {
-       siginfo_t info;
-
        if (user_mode(regs)) {
-               info = (siginfo_t) {
-                       .si_signo = SIGTRAP,
-                       .si_errno = 0,
-                       .si_code  = TRAP_BRKPT,
-                       .si_addr  = (void __user *)instruction_pointer(regs),
-               };
-
-               force_sig_info(SIGTRAP, &info, current);
+               send_user_sigtrap(TRAP_BRKPT);
        } else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
                pr_warning("Unexpected kernel BRK exception at EL1\n");
                return -EFAULT;
@@ -328,7 +332,6 @@ static int brk_handler(unsigned long addr, unsigned int esr,
 
 int aarch32_break_handler(struct pt_regs *regs)
 {
-       siginfo_t info;
        u32 arm_instr;
        u16 thumb_instr;
        bool bp = false;
@@ -359,14 +362,7 @@ int aarch32_break_handler(struct pt_regs *regs)
        if (!bp)
                return -EFAULT;
 
-       info = (siginfo_t) {
-               .si_signo = SIGTRAP,
-               .si_errno = 0,
-               .si_code  = TRAP_BRKPT,
-               .si_addr  = pc,
-       };
-
-       force_sig_info(SIGTRAP, &info, current);
+       send_user_sigtrap(TRAP_BRKPT);
        return 0;
 }
 
index 999633bd7294aab399183bd3bcf33c64ce8a6e2c..352f7abd91c998f297b229d00e5cbb2f4882e81c 100644 (file)
@@ -89,6 +89,7 @@ __efistub_memcpy              = KALLSYMS_HIDE(__pi_memcpy);
 __efistub_memmove              = KALLSYMS_HIDE(__pi_memmove);
 __efistub_memset               = KALLSYMS_HIDE(__pi_memset);
 __efistub_strlen               = KALLSYMS_HIDE(__pi_strlen);
+__efistub_strnlen              = KALLSYMS_HIDE(__pi_strnlen);
 __efistub_strcmp               = KALLSYMS_HIDE(__pi_strcmp);
 __efistub_strncmp              = KALLSYMS_HIDE(__pi_strncmp);
 __efistub___flush_dcache_area  = KALLSYMS_HIDE(__pi___flush_dcache_area);
index 4fad9787ab46ed04bf36873e8f7f7eb724beb262..d9751a4769e758b220181d6a400bd5a238c2cedb 100644 (file)
@@ -44,14 +44,13 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
        unsigned long irq_stack_ptr;
 
        /*
-        * Use raw_smp_processor_id() to avoid false-positives from
-        * CONFIG_DEBUG_PREEMPT. get_wchan() calls unwind_frame() on sleeping
-        * task stacks, we can be pre-empted in this case, so
-        * {raw_,}smp_processor_id() may give us the wrong value. Sleeping
-        * tasks can't ever be on an interrupt stack, so regardless of cpu,
-        * the checks will always fail.
+        * Switching between stacks is valid when tracing current and in
+        * non-preemptible context.
         */
-       irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
+       if (tsk == current && !preemptible())
+               irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       else
+               irq_stack_ptr = 0;
 
        low  = frame->sp;
        /* irq stacks are not THREAD_SIZE aligned */
@@ -64,8 +63,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
                return -EINVAL;
 
        frame->sp = fp + 0x10;
-       frame->fp = *(unsigned long *)(fp);
-       frame->pc = *(unsigned long *)(fp + 8);
+       frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
+       frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (tsk && tsk->ret_stack &&
index cbedd724f48efcf487e443fa3fc21516d8d898a6..c5392081b49ba4ac4f48d9a0782442ac888ed222 100644 (file)
@@ -146,9 +146,18 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
 static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
 {
        struct stackframe frame;
-       unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       unsigned long irq_stack_ptr;
        int skip;
 
+       /*
+        * Switching between stacks is valid when tracing current and in
+        * non-preemptible context.
+        */
+       if (tsk == current && !preemptible())
+               irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+       else
+               irq_stack_ptr = 0;
+
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
index fcb778899a3804455f2e9ef5f3fad33456d2d96e..9e54ad7c240ac5d2239ba5140b04c6727b20377e 100644 (file)
@@ -194,7 +194,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        u64 val;
 
        val = kvm_arm_timer_get_reg(vcpu, reg->id);
-       return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id));
+       return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0;
 }
 
 /**
index 3e568dcd907b8c82806ee4c2bf4f355e64cf7d51..d073b5a216f72b1db65fbef79efd942b28df6f6e 100644 (file)
@@ -64,7 +64,7 @@ __do_hyp_init:
        mrs     x4, tcr_el1
        ldr     x5, =TCR_EL2_MASK
        and     x4, x4, x5
-       ldr     x5, =TCR_EL2_FLAGS
+       mov     x5, #TCR_EL2_RES1
        orr     x4, x4, x5
 
 #ifndef CONFIG_ARM64_VA_BITS_48
@@ -85,15 +85,17 @@ __do_hyp_init:
        ldr_l   x5, idmap_t0sz
        bfi     x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
 #endif
-       msr     tcr_el2, x4
-
-       ldr     x4, =VTCR_EL2_FLAGS
        /*
         * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
-        * VTCR_EL2.
+        * TCR_EL2 and VTCR_EL2.
         */
        mrs     x5, ID_AA64MMFR0_EL1
        bfi     x4, x5, #16, #3
+
+       msr     tcr_el2, x4
+
+       ldr     x4, =VTCR_EL2_FLAGS
+       bfi     x4, x5, #16, #3
        /*
         * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS bit in
         * VTCR_EL2.
index ca8f5a5e2f965748fca28ced482c9c195270e5ab..f0e7bdfae134a727ec7c0ac76466020fdb65e0fb 100644 (file)
@@ -36,7 +36,11 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
        write_sysreg(val, hcr_el2);
        /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
        write_sysreg(1 << 15, hstr_el2);
-       write_sysreg(CPTR_EL2_TTA | CPTR_EL2_TFP, cptr_el2);
+
+       val = CPTR_EL2_DEFAULT;
+       val |= CPTR_EL2_TTA | CPTR_EL2_TFP;
+       write_sysreg(val, cptr_el2);
+
        write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
 }
 
@@ -45,7 +49,7 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
        write_sysreg(HCR_RW, hcr_el2);
        write_sysreg(0, hstr_el2);
        write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
-       write_sysreg(0, cptr_el2);
+       write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
 }
 
 static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
index 9142e082f5f3996df9428670f2e107cfc948d2e3..5dd2a26444ec116cd46d51f118c62ddcd78752ae 100644 (file)
@@ -147,16 +147,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
        max_lr_idx = vtr_to_max_lr_idx(val);
        nr_pri_bits = vtr_to_nr_pri_bits(val);
 
-       switch (nr_pri_bits) {
-       case 7:
-                write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
-                write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
-       case 6:
-                write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
-       default:
-                write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
-       }                                          
-                                                  
        switch (nr_pri_bits) {
        case 7:
                 write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
@@ -167,6 +157,16 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
                 write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
        }
 
+       switch (nr_pri_bits) {
+       case 7:
+                write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
+                write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+       case 6:
+                write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+       default:
+                write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+       }
+
        switch (max_lr_idx) {
        case 15:
                write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)], ICH_LR15_EL2);
index 648112e90ed546d2d052ccf7d9f66866d2390d06..4d1ac81870d27e6f272abde088e0f5e8290c80d1 100644 (file)
 
 #define PSTATE_FAULT_BITS_64   (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
                                 PSR_I_BIT | PSR_D_BIT)
-#define EL1_EXCEPT_SYNC_OFFSET 0x200
+
+#define CURRENT_EL_SP_EL0_VECTOR       0x0
+#define CURRENT_EL_SP_ELx_VECTOR       0x200
+#define LOWER_EL_AArch64_VECTOR                0x400
+#define LOWER_EL_AArch32_VECTOR                0x600
 
 static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 {
@@ -97,6 +101,34 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
                *fsr = 0x14;
 }
 
+enum exception_type {
+       except_type_sync        = 0,
+       except_type_irq         = 0x80,
+       except_type_fiq         = 0x100,
+       except_type_serror      = 0x180,
+};
+
+static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
+{
+       u64 exc_offset;
+
+       switch (*vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT)) {
+       case PSR_MODE_EL1t:
+               exc_offset = CURRENT_EL_SP_EL0_VECTOR;
+               break;
+       case PSR_MODE_EL1h:
+               exc_offset = CURRENT_EL_SP_ELx_VECTOR;
+               break;
+       case PSR_MODE_EL0t:
+               exc_offset = LOWER_EL_AArch64_VECTOR;
+               break;
+       default:
+               exc_offset = LOWER_EL_AArch32_VECTOR;
+       }
+
+       return vcpu_sys_reg(vcpu, VBAR_EL1) + exc_offset + type;
+}
+
 static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
 {
        unsigned long cpsr = *vcpu_cpsr(vcpu);
@@ -108,8 +140,8 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
        *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
 
+       *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-       *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
 
        vcpu_sys_reg(vcpu, FAR_EL1) = addr;
 
@@ -143,8 +175,8 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
        *vcpu_spsr(vcpu) = cpsr;
        *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
 
+       *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-       *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
 
        /*
         * Build an unknown exception, depending on the instruction
index eec3598b4184077b83b5a1f24321891cb110f5bb..2e90371cfb378b0e064667506a2b74c9275cacfb 100644 (file)
@@ -1007,10 +1007,9 @@ static int emulate_cp(struct kvm_vcpu *vcpu,
                if (likely(r->access(vcpu, params, r))) {
                        /* Skip instruction, since it was emulated */
                        kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+                       /* Handled */
+                       return 0;
                }
-
-               /* Handled */
-               return 0;
        }
 
        /* Not handled */
@@ -1043,7 +1042,7 @@ static void unhandled_cp_access(struct kvm_vcpu *vcpu,
 }
 
 /**
- * kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP15 access
+ * kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP14/CP15 access
  * @vcpu: The VCPU pointer
  * @run:  The kvm_run struct
  */
@@ -1095,7 +1094,7 @@ out:
 }
 
 /**
- * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
+ * kvm_handle_cp_32 -- handles a mrc/mcr trap on a guest CP14/CP15 access
  * @vcpu: The VCPU pointer
  * @run:  The kvm_run struct
  */
index 2ca665711bf21e590b79f89578dbe4cbba0ca9b3..eae38da6e0bb3911a5cad1fb2f6da46b4bb0090a 100644 (file)
@@ -168,4 +168,4 @@ CPU_LE( lsr tmp2, tmp2, tmp4 )      /* Shift (tmp1 & 63).  */
 .Lhit_limit:
        mov     len, limit
        ret
-ENDPROC(strnlen)
+ENDPIPROC(strnlen)
index 331c4ca6205c4e7211d4bc7bc4832891d26080cc..a6e757cbab7785ed411e919b95c6d13caaf21726 100644 (file)
@@ -933,6 +933,10 @@ static int __init __iommu_dma_init(void)
                ret = register_iommu_dma_ops_notifier(&platform_bus_type);
        if (!ret)
                ret = register_iommu_dma_ops_notifier(&amba_bustype);
+
+       /* handle devices queued before this arch_initcall */
+       if (!ret)
+               __iommu_attach_notifier(NULL, BUS_NOTIFY_ADD_DEVICE, NULL);
        return ret;
 }
 arch_initcall(__iommu_dma_init);
index 92ddac1e8ca2f35b8f24028514bb761aed3591a4..abe2a9542b3a367c778a96051dcf3618881d6fa1 100644 (file)
@@ -371,6 +371,13 @@ static int __kprobes do_translation_fault(unsigned long addr,
        return 0;
 }
 
+static int do_alignment_fault(unsigned long addr, unsigned int esr,
+                             struct pt_regs *regs)
+{
+       do_bad_area(addr, esr, regs);
+       return 0;
+}
+
 /*
  * This abort handler always returns "fault".
  */
@@ -418,7 +425,7 @@ static struct fault_info {
        { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "synchronous parity error (translation table walk)" },
        { do_bad,               SIGBUS,  0,             "unknown 32"                    },
-       { do_bad,               SIGBUS,  BUS_ADRALN,    "alignment fault"               },
+       { do_alignment_fault,   SIGBUS,  BUS_ADRALN,    "alignment fault"               },
        { do_bad,               SIGBUS,  0,             "unknown 34"                    },
        { do_bad,               SIGBUS,  0,             "unknown 35"                    },
        { do_bad,               SIGBUS,  0,             "unknown 36"                    },
index f3b061e67bfe0f4565d5df29322eeaef38a9bcc3..7802f216a67a588ab778b7d2b7649a2979e68b87 100644 (file)
@@ -319,8 +319,8 @@ void __init mem_init(void)
 #endif
                  MLG(VMALLOC_START, VMALLOC_END),
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-                 MLG((unsigned long)vmemmap,
-                     (unsigned long)vmemmap + VMEMMAP_SIZE),
+                 MLG(VMEMMAP_START,
+                     VMEMMAP_START + VMEMMAP_SIZE),
                  MLM((unsigned long)virt_to_page(PAGE_OFFSET),
                      (unsigned long)virt_to_page(high_memory)),
 #endif
index 4c893b5189ddd027537511c5daaca70f158577c4..232f787a088ae8e992c52cba450159a43a900174 100644 (file)
@@ -53,10 +53,10 @@ unsigned long arch_mmap_rnd(void)
 
 #ifdef CONFIG_COMPAT
        if (test_thread_flag(TIF_32BIT))
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
        else
 #endif
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
        return rnd << PAGE_SHIFT;
 }
 
index cf6240741134ecbeece606dade39dc90478a08b6..0795c3a36d8f0d140cf4952bd91b14962e7f81b4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/vmalloc.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -44,6 +45,7 @@ static int change_memory_common(unsigned long addr, int numpages,
        unsigned long end = start + size;
        int ret;
        struct page_change_data data;
+       struct vm_struct *area;
 
        if (!PAGE_ALIGNED(addr)) {
                start &= PAGE_MASK;
@@ -51,10 +53,23 @@ static int change_memory_common(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
-       if (start < MODULES_VADDR || start >= MODULES_END)
-               return -EINVAL;
-
-       if (end < MODULES_VADDR || end >= MODULES_END)
+       /*
+        * Kernel VA mappings are always live, and splitting live section
+        * mappings into page mappings may cause TLB conflicts. This means
+        * we have to ensure that changing the permission bits of the range
+        * we are operating on does not result in such splitting.
+        *
+        * Let's restrict ourselves to mappings created by vmalloc (or vmap).
+        * Those are guaranteed to consist entirely of page mappings, and
+        * splitting is never needed.
+        *
+        * So check whether the [addr, addr + size) interval is entirely
+        * covered by precisely one VM area that has the VM_ALLOC flag set.
+        */
+       area = find_vm_area((void *)addr);
+       if (!area ||
+           end > (unsigned long)area->addr + area->size ||
+           !(area->flags & VM_ALLOC))
                return -EINVAL;
 
        if (!numpages)
index 9de0796240a0015b8a315d847f8f827e389ed4e1..1fd147f09a3805d75f1e8150a825250a6e38121b 100644 (file)
@@ -88,4 +88,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _UAPI__ASM_AVR32_SOCKET_H */
index f02e4849ae838f0163848d7426b70cd3183685eb..afbc98f02d278d097d31add71104f5e4fe4040ea 100644 (file)
@@ -88,5 +88,7 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_SOCKET_H */
 
index bce29166de1bfa28d5ec86b3bcaae941ce62cb21..0018fad9039f4bd9435d2b6a5976093e56d38db7 100644 (file)
@@ -97,4 +97,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_IA64_SOCKET_H */
index 836ac5a963c83140d18dcd762459d19e1fd0c101..2841c0a3fd3bb201a4bed53d823858b32a0a009b 100644 (file)
@@ -276,6 +276,7 @@ source "kernel/Kconfig.preempt"
 
 config SMP
        bool "Symmetric multi-processing support"
+       depends on MMU
        ---help---
          This enables support for systems with more than one CPU. If you have
          a system with only one CPU, say N. If you have a system with more
index 14aa4a6bccf125fc3c553dfb984e6eae3e6fd1e5..5fe42fc7b6c5dd29e15edbcfbb8ea4cb370ea25c 100644 (file)
@@ -88,4 +88,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_M32R_SOCKET_H */
index fc96e814188e57aa9dee8ed516c62200c543ad56..d1fc4796025edb8769ee01195e64b91821f3625a 100644 (file)
@@ -108,6 +108,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -266,6 +268,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -366,6 +374,7 @@ CONFIG_ARIADNE=y
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 CONFIG_HYDRA=y
 CONFIG_APNE=y
 CONFIG_ZORRO8390=y
index 05c904f08d9d496fb7455df0d1506fb8d8c9bc23..9bfe8be3658c18231ca4473d8c075a1fb2ac4d5e 100644 (file)
@@ -106,6 +106,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -264,6 +266,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -344,6 +352,7 @@ CONFIG_VETH=m
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index d572b731c510fdb2dc60616ee1ff0ce7e10516ce..ebdcfae555801cd1c7367d4ca40974b3d39099cb 100644 (file)
@@ -106,6 +106,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -264,6 +266,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -353,6 +361,7 @@ CONFIG_ATARILANCE=y
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 CONFIG_NE2000=y
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
index 11a30c65ad44cb52347929d51f80301c8aca648b..8acc65e54995388614666716febdab1dda706376 100644 (file)
@@ -104,6 +104,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -262,6 +264,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -343,6 +351,7 @@ CONFIG_BVME6000_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index 6630a5154b9d797ebea93cdbe70886bc673f60cd..0c6a3d52b26e2b2559f24963040d3ba65a91ed47 100644 (file)
@@ -106,6 +106,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -264,6 +266,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -345,6 +353,7 @@ CONFIG_HPLANCE=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index 1d90b71d09038da90cfad0cab267d60dae0fd752..12a8a6cb32f4914f06c1f5d4c8e5dd6ba31381ef 100644 (file)
@@ -105,6 +105,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -266,6 +268,12 @@ CONFIG_DEV_APPLETALK=m
 CONFIG_IPDDP=m
 CONFIG_IPDDP_ENCAP=y
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -362,6 +370,7 @@ CONFIG_MAC89x0=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 CONFIG_MACSONIC=y
+# CONFIG_NET_VENDOR_NETRONOME is not set
 CONFIG_MAC8390=y
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
index 1fd21c1ca87fd8da85ace8c64930cfeed4383370..64ff2dcb34c89a3e60e26f9c468d654ed943e97f 100644 (file)
@@ -115,6 +115,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -276,6 +278,12 @@ CONFIG_DEV_APPLETALK=m
 CONFIG_IPDDP=m
 CONFIG_IPDDP_ENCAP=y
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -404,6 +412,7 @@ CONFIG_MVME16x_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 CONFIG_MACSONIC=y
+# CONFIG_NET_VENDOR_NETRONOME is not set
 CONFIG_HYDRA=y
 CONFIG_MAC8390=y
 CONFIG_NE2000=y
index 74e10f79d7b1f9475574d422451314b7bcc1af64..07fc6abcfe0c50e4b656a63a9da36c728b13cec4 100644 (file)
@@ -103,6 +103,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -261,6 +263,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -343,6 +351,7 @@ CONFIG_MVME147_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index 7034e716f166be8f869f872b12f9cbf960054029..69903ded88f71d1d51ad4b430acbd2f745fdf867 100644 (file)
@@ -104,6 +104,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -262,6 +264,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -343,6 +351,7 @@ CONFIG_MVME16x_NET=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index f7deb5f702a6484dda646577f48ade90b902bf18..bd8401686ddef143bf036159cb3f4ea650772f32 100644 (file)
@@ -104,6 +104,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -262,6 +264,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -352,6 +360,7 @@ CONFIG_VETH=m
 # CONFIG_NET_VENDOR_INTEL is not set
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 CONFIG_NE2000=y
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
index 0ce79eb0d80503140d928c3c6c77061a2ead34d9..5f9fb3ab9636808d46b75f3696f477ab91e6dd79 100644 (file)
@@ -101,6 +101,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -259,6 +261,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -340,6 +348,7 @@ CONFIG_SUN3_82586=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index 4cb787e4991fcfd02646b1144999419b40454f83..5d1c674530e2ba73ca43ffc4940f139772962152 100644 (file)
@@ -101,6 +101,8 @@ CONFIG_NFT_NAT=m
 CONFIG_NFT_QUEUE=m
 CONFIG_NFT_REJECT=m
 CONFIG_NFT_COMPAT=m
+CONFIG_NFT_DUP_NETDEV=m
+CONFIG_NFT_FWD_NETDEV=m
 CONFIG_NETFILTER_XT_SET=m
 CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
 CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
@@ -259,6 +261,12 @@ CONFIG_L2TP=m
 CONFIG_BRIDGE=m
 CONFIG_ATALK=m
 CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m
+CONFIG_6LOWPAN_GHC_UDP=m
+CONFIG_6LOWPAN_GHC_ICMPV6=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=m
+CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=m
 CONFIG_DNS_RESOLVER=y
 CONFIG_BATMAN_ADV=m
 CONFIG_BATMAN_ADV_DAT=y
@@ -341,6 +349,7 @@ CONFIG_SUN3LANCE=y
 # CONFIG_NET_VENDOR_MARVELL is not set
 # CONFIG_NET_VENDOR_MICREL is not set
 # CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NETRONOME is not set
 # CONFIG_NET_VENDOR_QUALCOMM is not set
 # CONFIG_NET_VENDOR_RENESAS is not set
 # CONFIG_NET_VENDOR_ROCKER is not set
index f9d96bf869109c028e5a9f1f12ad3e9fe8b933ba..bafaff6dcd7bda8a28101f140159f9a7a76638db 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            376
+#define NR_syscalls            377
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 36cf129de663a7ca22f1bf1bba5a6245b7b04c03..0ca729665f29e9d67851aed2c1c52be75bbd078b 100644 (file)
 #define __NR_userfaultfd       373
 #define __NR_membarrier                374
 #define __NR_mlock2            375
+#define __NR_copy_file_range   376
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 282cd903f4c469197738eb9e840eaa75c77ec11a..8bb94261ff97d953fcfbe7c305e6a7ecfce27a97 100644 (file)
@@ -396,3 +396,4 @@ ENTRY(sys_call_table)
        .long sys_userfaultfd
        .long sys_membarrier
        .long sys_mlock2                /* 375 */
+       .long sys_copy_file_range
index 57a945e832f43ff711fe04d1fa8a52fe1970f000..74a3db92da1b52edc15165ac06d3b1558b8b78c0 100644 (file)
@@ -2085,7 +2085,7 @@ config PAGE_SIZE_32KB
 
 config PAGE_SIZE_64KB
        bool "64kB"
-       depends on !CPU_R3000 && !CPU_TX39XX
+       depends on !CPU_R3000 && !CPU_TX39XX && !CPU_R6000
        help
          Using 64kB page size will result in higher performance kernel at
          the price of higher memory consumption.  This option is available on
index 459b9b252c3b73fe2c95362177655b3a6f154a6f..d61b1616b604552be9a30f89eb42539de6838b14 100644 (file)
@@ -74,6 +74,7 @@
                timer: timer@10000040 {
                        compatible = "syscon";
                        reg = <0x10000040 0x2c>;
+                       little-endian;
                };
 
                reboot {
index 4fc7ecee273c105027ff20cea02f2bd5cf86c9fe..1a7efa883c5e3fd2e046b554485270036193b382 100644 (file)
@@ -98,6 +98,7 @@
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x60c>;
+                       little-endian;
                };
 
                reboot {
index a3039bb53477d40a426fec1d1318f3156ede8be3..d4bf52cfcf170ee8ac84daa874495e0a6420e542 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index 4274ff41ec2122ac0bfd52d814aee8432c26553e..8e2501694d03fbd93827aeda79ef22f7cfd5d094 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index 0dcc9163c27bdd0022e5b66f3ffd65da7fd6ce31..7e5f76040fb898b19a4bbc301c8a20f3b9368aa4 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index 2f3f9fc2c478df36ef57c5990dd81f6757240e3a..c739ea77acb0dfe17363ec52cf390cace407e54c 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index bee221b3b56857c8d84dac3e2fa9bfe8b3c54a85..5f55d0a50a28622614ec6142eb0ff19746dfaade 100644 (file)
@@ -99,6 +99,7 @@
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x60c>;
+                       little-endian;
                };
 
                reboot {
index 571f30f52e3ff5780ec4fd72e18e72737e51537d..e24d41ab4e30f9163605180d78605fc02a477db6 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index 614ee211f71a89356dd1eb814a38ec3071885747..8b9432cc062bc7e89898f2f1f2213926193389f8 100644 (file)
                sun_top_ctrl: syscon@404000 {
                        compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
                        reg = <0x404000 0x51c>;
+                       little-endian;
                };
 
                reboot {
index cefb7a5968783094befa3ee5925b02ab1f972fac..e090fc388e02483faf1291e2f4844f823aec5bc2 100644 (file)
@@ -227,7 +227,7 @@ struct mips_elf_abiflags_v0 {
        int __res = 1;                                                  \
        struct elfhdr *__h = (hdr);                                     \
                                                                        \
-       if (__h->e_machine != EM_MIPS)                                  \
+       if (!mips_elf_check_machine(__h))                               \
                __res = 0;                                              \
        if (__h->e_ident[EI_CLASS] != ELFCLASS32)                       \
                __res = 0;                                              \
@@ -258,7 +258,7 @@ struct mips_elf_abiflags_v0 {
        int __res = 1;                                                  \
        struct elfhdr *__h = (hdr);                                     \
                                                                        \
-       if (__h->e_machine != EM_MIPS)                                  \
+       if (!mips_elf_check_machine(__h))                               \
                __res = 0;                                              \
        if (__h->e_ident[EI_CLASS] != ELFCLASS64)                       \
                __res = 0;                                              \
@@ -285,6 +285,11 @@ struct mips_elf_abiflags_v0 {
 
 #endif /* !defined(ELF_ARCH) */
 
+#define mips_elf_check_machine(x) ((x)->e_machine == EM_MIPS)
+
+#define vmcore_elf32_check_arch mips_elf_check_machine
+#define vmcore_elf64_check_arch mips_elf_check_machine
+
 struct mips_abi;
 
 extern struct mips_abi mips_abi;
index 9cbf383b8834c7551820930b0dc98a66895012fa..f06f97bd62df906bf4160594119dec4d52b028eb 100644 (file)
@@ -179,6 +179,10 @@ static inline void lose_fpu_inatomic(int save, struct task_struct *tsk)
                if (save)
                        _save_fp(tsk);
                __disable_fpu();
+       } else {
+               /* FPU should not have been left enabled with no owner */
+               WARN(read_c0_status() & ST0_CU1,
+                    "Orphaned FPU left enabled");
        }
        KSTK_STATUS(tsk) &= ~ST0_CU1;
        clear_tsk_thread_flag(tsk, TIF_USEDFPU);
index 8ebd3f579b848ea5c1a1f6c3cb4d79a2bafbcfac..3ed10a8d78651373a55e4f99c722767cbbc26810 100644 (file)
@@ -128,7 +128,8 @@ static inline int octeon_has_feature(enum octeon_feature feature)
        case OCTEON_FEATURE_PCIE:
                return OCTEON_IS_MODEL(OCTEON_CN56XX)
                        || OCTEON_IS_MODEL(OCTEON_CN52XX)
-                       || OCTEON_IS_MODEL(OCTEON_CN6XXX);
+                       || OCTEON_IS_MODEL(OCTEON_CN6XXX)
+                       || OCTEON_IS_MODEL(OCTEON_CN7XXX);
 
        case OCTEON_FEATURE_SRIO:
                return OCTEON_IS_MODEL(OCTEON_CN63XX)
index 3f832c3dd8f5f1cad76461b47ee00a0b7f85722d..041153f5cf93432ea1140c10cd53c3d48e91ab76 100644 (file)
@@ -45,7 +45,7 @@ extern unsigned int vced_count, vcei_count;
  * User space process size: 2GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  */
-#define TASK_SIZE      0x7fff8000UL
+#define TASK_SIZE      0x80000000UL
 #endif
 
 #define STACK_TOP_MAX  TASK_SIZE
index a71da576883c8f4b1a3d60279ebfaefb95798031..eebf3954960644daf75dd5ae0d6e7eca1c50f34a 100644 (file)
                .set    reorder
                .set    noat
                mfc0    a0, CP0_STATUS
-               li      v1, 0xff00
+               li      v1, ST0_CU1 | ST0_IM
                ori     a0, STATMASK
                xori    a0, STATMASK
                mtc0    a0, CP0_STATUS
                ori     a0, STATMASK
                xori    a0, STATMASK
                mtc0    a0, CP0_STATUS
-               li      v1, 0xff00
+               li      v1, ST0_CU1 | ST0_FR | ST0_IM
                and     a0, v1
                LONG_L  v0, PT_STATUS(sp)
                nor     v1, $0, v1
index 6499d93ae68d7096d63416a349d9afcdcc0cb3ae..47bc45a67e9ba187fb709b97e755900e9bcb4caf 100644 (file)
@@ -101,10 +101,8 @@ static inline void syscall_get_arguments(struct task_struct *task,
        /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */
        if ((config_enabled(CONFIG_32BIT) ||
            test_tsk_thread_flag(task, TIF_32BIT_REGS)) &&
-           (regs->regs[2] == __NR_syscall)) {
+           (regs->regs[2] == __NR_syscall))
                i++;
-               n++;
-       }
 
        while (n--)
                ret |= mips_get_syscall_arg(args++, task, regs, i++);
index 5910fe294e932d66f94cbff106ab1d4ce470c55b..2027240aafbb8432f0cc67148b70ae57f48ed2a6 100644 (file)
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 90f03a7da6654da7000108042dcf00944d322406..3129795de940b0c370c3eb6926ade8b11f878f91 100644 (file)
 #define __NR_userfaultfd               (__NR_Linux + 357)
 #define __NR_membarrier                        (__NR_Linux + 358)
 #define __NR_mlock2                    (__NR_Linux + 359)
+#define __NR_copy_file_range           (__NR_Linux + 360)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            359
+#define __NR_Linux_syscalls            360
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                359
+#define __NR_O32_Linux_syscalls                360
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_userfaultfd               (__NR_Linux + 317)
 #define __NR_membarrier                        (__NR_Linux + 318)
 #define __NR_mlock2                    (__NR_Linux + 319)
+#define __NR_copy_file_range           (__NR_Linux + 320)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            319
+#define __NR_Linux_syscalls            320
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         319
+#define __NR_64_Linux_syscalls         320
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_userfaultfd               (__NR_Linux + 321)
 #define __NR_membarrier                        (__NR_Linux + 322)
 #define __NR_mlock2                    (__NR_Linux + 323)
+#define __NR_copy_file_range           (__NR_Linux + 324)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            323
+#define __NR_Linux_syscalls            324
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                323
+#define __NR_N32_Linux_syscalls                324
 
 #endif /* _UAPI_ASM_UNISTD_H */
index 8c6d76c9b2d69bf6603e32598e3b8d74cba15bf6..d9907e57e9b986f4d296c829c4cf0d5d8c995d38 100644 (file)
@@ -270,7 +270,7 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
 }
 EXPORT_SYMBOL(jz_gpio_port_get_value);
 
-#define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f)
+#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
 
 static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
 {
index 1188e00bb120a2637c53f3916f28b1f990a9515e..1b992c6e3d8e212420673fbb697edeff0b6314e3 100644 (file)
@@ -35,7 +35,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
        int __res = 1;                                                  \
        struct elfhdr *__h = (hdr);                                     \
                                                                        \
-       if (__h->e_machine != EM_MIPS)                                  \
+       if (!mips_elf_check_machine(__h))                               \
                __res = 0;                                              \
        if (__h->e_ident[EI_CLASS] != ELFCLASS32)                       \
                __res = 0;                                              \
index 928767858b867b65cce4aa92f965f96064a1f429..abd3affe5fb3bd71367b908f9439b54ddea7a61c 100644 (file)
@@ -47,7 +47,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
        int __res = 1;                                                  \
        struct elfhdr *__h = (hdr);                                     \
                                                                        \
-       if (__h->e_machine != EM_MIPS)                                  \
+       if (!mips_elf_check_machine(__h))                               \
                __res = 0;                                              \
        if (__h->e_ident[EI_CLASS] != ELFCLASS32)                       \
                __res = 0;                                              \
index f2975d4d1e449cc948d84dacac736451a3144cf9..eddd5fd6fdfa2ee20f50886b8fbbad9045fd496d 100644 (file)
@@ -65,12 +65,10 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
        status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
        status |= KU_USER;
        regs->cp0_status = status;
+       lose_fpu(0);
+       clear_thread_flag(TIF_MSA_CTX_LIVE);
        clear_used_math();
-       clear_fpu_owner();
        init_dsp();
-       clear_thread_flag(TIF_USEDMSA);
-       clear_thread_flag(TIF_MSA_CTX_LIVE);
-       disable_msa();
        regs->cp0_epc = pc;
        regs->regs[29] = sp;
 }
index 5ce3b746cedc0bdea6e305cc72ef2121f0026053..b4ac6374a38f28e182b2558934ff979b88b33bb2 100644 (file)
@@ -125,7 +125,7 @@ LEAF(_restore_fp_context)
        END(_restore_fp_context)
        .set    reorder
 
-       .type   fault@function
+       .type   fault@function
        .ent    fault
 fault: li      v0, -EFAULT
        jr      ra
index f09546ee2cdc907dc02e4c391c103ba381e35a5e..17732f876eff1ad7e7e868f960304420e380db93 100644 (file)
@@ -358,7 +358,7 @@ LEAF(_restore_msa_all_upper)
 
        .set    reorder
 
-       .type   fault@function
+       .type   fault@function
        .ent    fault
 fault: li      v0, -EFAULT                             # failure
        jr      ra
index 2d23c834ba96cd328a87d016e328176fc9a6876e..a56317444bdad94c73325eb1f72d75ff46af1b82 100644 (file)
@@ -595,3 +595,4 @@ EXPORT(sys_call_table)
        PTR     sys_userfaultfd
        PTR     sys_membarrier
        PTR     sys_mlock2
+       PTR     sys_copy_file_range             /* 4360 */
index deac63315d0ed4123d1e0f09b617e9250d68c885..2b2dc14610d02b58dc704ee63de6520d45ee5156 100644 (file)
@@ -433,4 +433,5 @@ EXPORT(sys_call_table)
        PTR     sys_userfaultfd
        PTR     sys_membarrier
        PTR     sys_mlock2
+       PTR     sys_copy_file_range             /* 5320 */
        .size   sys_call_table,.-sys_call_table
index 5a69eb48d0a8cef87c33c3184f4ddc3236f01d2d..2bf5c8593d91daad1a9ee5ffea26eb59318854d9 100644 (file)
@@ -423,4 +423,5 @@ EXPORT(sysn32_call_table)
        PTR     sys_userfaultfd
        PTR     sys_membarrier
        PTR     sys_mlock2
+       PTR     sys_copy_file_range
        .size   sysn32_call_table,.-sysn32_call_table
index e4b6d7c9782263e7c6dfca1b7eb4e6818ca78a6e..c5b759e584c758a9d56acf44d7677ff74dc7ecf8 100644 (file)
@@ -578,4 +578,5 @@ EXPORT(sys32_call_table)
        PTR     sys_userfaultfd
        PTR     sys_membarrier
        PTR     sys_mlock2
+       PTR     sys_copy_file_range             /* 4360 */
        .size   sys32_call_table,.-sys32_call_table
index 569a7d5242ddda902e7ab1a03430ab14c712e5cd..5fdaf8bdcd2ebeed8e31eb7825edd958bfc1c251 100644 (file)
@@ -782,6 +782,7 @@ static inline void prefill_possible_map(void) {}
 void __init setup_arch(char **cmdline_p)
 {
        cpu_probe();
+       mips_cm_probe();
        prom_init();
 
        setup_early_fdc_console();
index bafcb7ad5c854d5109010485dd190f12486c363e..bf14da9f3e33b74473d2a23c3b3b388456c4bdc5 100644 (file)
@@ -663,7 +663,7 @@ static int simulate_rdhwr_normal(struct pt_regs *regs, unsigned int opcode)
        return -1;
 }
 
-static int simulate_rdhwr_mm(struct pt_regs *regs, unsigned short opcode)
+static int simulate_rdhwr_mm(struct pt_regs *regs, unsigned int opcode)
 {
        if ((opcode & MM_POOL32A_FUNC) == MM_RDHWR) {
                int rd = (opcode & MM_RS) >> 16;
@@ -690,15 +690,15 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode)
 asmlinkage void do_ov(struct pt_regs *regs)
 {
        enum ctx_state prev_state;
-       siginfo_t info;
+       siginfo_t info = {
+               .si_signo = SIGFPE,
+               .si_code = FPE_INTOVF,
+               .si_addr = (void __user *)regs->cp0_epc,
+       };
 
        prev_state = exception_enter();
        die_if_kernel("Integer overflow", regs);
 
-       info.si_code = FPE_INTOVF;
-       info.si_signo = SIGFPE;
-       info.si_errno = 0;
-       info.si_addr = (void __user *) regs->cp0_epc;
        force_sig_info(SIGFPE, &info, current);
        exception_exit(prev_state);
 }
@@ -874,7 +874,7 @@ out:
 void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
        const char *str)
 {
-       siginfo_t info;
+       siginfo_t info = { 0 };
        char b[40];
 
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
@@ -903,7 +903,6 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
                else
                        info.si_code = FPE_INTOVF;
                info.si_signo = SIGFPE;
-               info.si_errno = 0;
                info.si_addr = (void __user *) regs->cp0_epc;
                force_sig_info(SIGFPE, &info, current);
                break;
@@ -1119,11 +1118,12 @@ no_r2_instr:
        if (get_isa16_mode(regs->cp0_epc)) {
                unsigned short mmop[2] = { 0 };
 
-               if (unlikely(get_user(mmop[0], epc) < 0))
+               if (unlikely(get_user(mmop[0], (u16 __user *)epc + 0) < 0))
                        status = SIGSEGV;
-               if (unlikely(get_user(mmop[1], epc) < 0))
+               if (unlikely(get_user(mmop[1], (u16 __user *)epc + 1) < 0))
                        status = SIGSEGV;
-               opcode = (mmop[0] << 16) | mmop[1];
+               opcode = mmop[0];
+               opcode = (opcode << 16) | mmop[1];
 
                if (status < 0)
                        status = simulate_rdhwr_mm(regs, opcode);
@@ -1369,26 +1369,12 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                if (unlikely(compute_return_epc(regs) < 0))
                        break;
 
-               if (get_isa16_mode(regs->cp0_epc)) {
-                       unsigned short mmop[2] = { 0 };
-
-                       if (unlikely(get_user(mmop[0], epc) < 0))
-                               status = SIGSEGV;
-                       if (unlikely(get_user(mmop[1], epc) < 0))
-                               status = SIGSEGV;
-                       opcode = (mmop[0] << 16) | mmop[1];
-
-                       if (status < 0)
-                               status = simulate_rdhwr_mm(regs, opcode);
-               } else {
+               if (!get_isa16_mode(regs->cp0_epc)) {
                        if (unlikely(get_user(opcode, epc) < 0))
                                status = SIGSEGV;
 
                        if (!cpu_has_llsc && status < 0)
                                status = simulate_llsc(regs, opcode);
-
-                       if (status < 0)
-                               status = simulate_rdhwr_normal(regs, opcode);
                }
 
                if (status < 0)
index 8bc3977576e6af5f7b5c1a17f306da0f21b26937..3110447ab1e9bffc37fa8572f5ce62d44d4a5fd9 100644 (file)
@@ -702,7 +702,7 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
        } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
                void __user *uaddr = (void __user *)(long)reg->addr;
 
-               return copy_to_user(uaddr, vs, 16);
+               return copy_to_user(uaddr, vs, 16) ? -EFAULT : 0;
        } else {
                return -EINVAL;
        }
@@ -732,7 +732,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
        } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
                void __user *uaddr = (void __user *)(long)reg->addr;
 
-               return copy_from_user(vs, uaddr, 16);
+               return copy_from_user(vs, uaddr, 16) ? -EFAULT : 0;
        } else {
                return -EINVAL;
        }
index 5c81fdd032c3b1269549f27e27348e9606eb5424..353037699512ca5515b11ce8fb2c808eb6386c78 100644 (file)
@@ -146,7 +146,7 @@ unsigned long arch_mmap_rnd(void)
 {
        unsigned long rnd;
 
-       rnd = (unsigned long)get_random_int();
+       rnd = get_random_long();
        rnd <<= PAGE_SHIFT;
        if (TASK_IS_32BIT_ADDR)
                rnd &= 0xfffffful;
@@ -174,7 +174,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 
 static inline unsigned long brk_rnd(void)
 {
-       unsigned long rnd = get_random_int();
+       unsigned long rnd = get_random_long();
 
        rnd = rnd << PAGE_SHIFT;
        /* 8MB for 32bit, 256MB for 64bit */
index 3bd0597d9c3da3a56ea6ba083ca05c67bd71c5e7..91dec32c77b722a838ce9ca352d89ca3939fba2b 100644 (file)
@@ -164,11 +164,13 @@ static int __init mips_sc_probe_cm3(void)
 
        sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK;
        sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF;
-       c->scache.sets = 64 << sets;
+       if (sets)
+               c->scache.sets = 64 << sets;
 
        line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK;
        line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF;
-       c->scache.linesz = 2 << line_sz;
+       if (line_sz)
+               c->scache.linesz = 2 << line_sz;
 
        assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK;
        assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF;
@@ -176,13 +178,12 @@ static int __init mips_sc_probe_cm3(void)
        c->scache.waysize = c->scache.sets * c->scache.linesz;
        c->scache.waybit = __ffs(c->scache.waysize);
 
-       c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+       if (c->scache.linesz) {
+               c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
+               return 1;
+       }
 
-       return 1;
-}
-
-void __weak platform_early_l2_init(void)
-{
+       return 0;
 }
 
 static inline int __init mips_sc_probe(void)
@@ -194,12 +195,6 @@ static inline int __init mips_sc_probe(void)
        /* Mark as not present until probe completed */
        c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
 
-       /*
-        * Do we need some platform specific probing before
-        * we configure L2?
-        */
-       platform_early_l2_init();
-
        if (mips_cm_revision() >= CM_REV_CM3)
                return mips_sc_probe_cm3();
 
index 571148c5fd0baa5ce8656e87574144d90b58e346..dc2c5214809d38703a7048babe7a16f83d77f28a 100644 (file)
@@ -293,7 +293,6 @@ mips_pci_controller:
        console_config();
 #endif
        /* Early detection of CMP support */
-       mips_cm_probe();
        mips_cpc_probe();
 
        if (!register_cps_smp_ops())
@@ -304,10 +303,3 @@ mips_pci_controller:
                return;
        register_up_smp_ops();
 }
-
-void platform_early_l2_init(void)
-{
-       /* L2 configuration lives in the CM3 */
-       if (mips_cm_revision() >= CM_REV_CM3)
-               mips_cm_probe();
-}
index a009ee4589343fab6442f902f2412d1236c6a4d1..1ae932c2d78b364b6c93b142d075c6a42bb1c7b6 100644 (file)
@@ -297,12 +297,12 @@ static int mt7620_pci_probe(struct platform_device *pdev)
                return PTR_ERR(rstpcie0);
 
        bridge_base = devm_ioremap_resource(&pdev->dev, bridge_res);
-       if (!bridge_base)
-               return -ENOMEM;
+       if (IS_ERR(bridge_base))
+               return PTR_ERR(bridge_base);
 
        pcie_base = devm_ioremap_resource(&pdev->dev, pcie_res);
-       if (!pcie_base)
-               return -ENOMEM;
+       if (IS_ERR(pcie_base))
+               return PTR_ERR(pcie_base);
 
        iomem_resource.start = 0;
        iomem_resource.end = ~0;
index e3733cde50d6f5caa82fda165c7971946001a8ed..402ac2ec7e83490358f2a945247630e401acd41b 100644 (file)
@@ -320,11 +320,12 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
 #if IS_ENABLED(CONFIG_TC35815)
 static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
-       struct ethtool_cmd cmd;
-       if (__ethtool_get_settings(dev, &cmd))
+       struct ethtool_link_ksettings cmd;
+
+       if (__ethtool_get_link_ksettings(dev, &cmd))
                return 100;     /* default 100Mbps */
 
-       return ethtool_cmd_speed(&cmd);
+       return cmd.base.speed;
 }
 
 static int tx4939_netdev_event(struct notifier_block *this,
index 58b1aa01ab9f140c7e910215aa727691bf7d5bcd..5129f23a9ee1008fc4b7203d2af689b0bc915a46 100644 (file)
@@ -88,4 +88,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_SOCKET_H */
index f84ff12574b7375f0d08396047aca4f7fc22854f..6d8276cd25cad289b838bf20df02b6bcd8a06bb8 100644 (file)
@@ -33,7 +33,7 @@
  * floppy accesses go through the track buffer.
  */
 #define _CROSS_64KB(a,s,vdma) \
-(!vdma && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
 
 #define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
 
index f9cf1223422ce6db81d1f144d1a2d1c709e912ab..9c935d717df94c998dce3dc66ad8eefd1b71d066 100644 (file)
@@ -87,4 +87,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       0x402C
 #define SO_ATTACH_REUSEPORT_EBPF       0x402D
 
+#define SO_CNX_ADVICE          0x402E
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 35bdccbb203622e116f288741ac4a9bc173034b0..b75039f9211645becb970599deeaafe257b86001 100644 (file)
 #define __NR_membarrier                (__NR_Linux + 343)
 #define __NR_userfaultfd       (__NR_Linux + 344)
 #define __NR_mlock2            (__NR_Linux + 345)
+#define __NR_copy_file_range   (__NR_Linux + 346)
 
-#define __NR_Linux_syscalls    (__NR_mlock2 + 1)
+#define __NR_Linux_syscalls    (__NR_copy_file_range + 1)
 
 
 #define __IGNORE_select                /* newselect */
index 9585c81f755fc667370ed850cba16ee1ff91024c..ce0b2b4075c704f9ee2006c263b1ba1cf3e9afd1 100644 (file)
@@ -269,14 +269,19 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 
 long do_syscall_trace_enter(struct pt_regs *regs)
 {
-       long ret = 0;
-
        /* Do the secure computing check first. */
        secure_computing_strict(regs->gr[20]);
 
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
-           tracehook_report_syscall_entry(regs))
-               ret = -1L;
+           tracehook_report_syscall_entry(regs)) {
+               /*
+                * Tracing decided this syscall should not happen or the
+                * debugger stored an invalid system call number. Skip
+                * the system call and the system call restart handling.
+                */
+               regs->gr[20] = -1UL;
+               goto out;
+       }
 
 #ifdef CONFIG_64BIT
        if (!is_compat_task())
@@ -290,7 +295,8 @@ long do_syscall_trace_enter(struct pt_regs *regs)
                        regs->gr[24] & 0xffffffff,
                        regs->gr[23] & 0xffffffff);
 
-       return ret ? : regs->gr[20];
+out:
+       return regs->gr[20];
 }
 
 void do_syscall_trace_exit(struct pt_regs *regs)
index 3fbd7252a4b27efd106250f5b21e98910f8af8bd..fbafa0d0e2bf865db726d15f9c4beb4817afe86c 100644 (file)
@@ -343,7 +343,7 @@ tracesys_next:
 #endif
 
        comiclr,>>=     __NR_Linux_syscalls, %r20, %r0
-       b,n     .Lsyscall_nosys
+       b,n     .Ltracesys_nosys
 
        LDREGX  %r20(%r19), %r19
 
@@ -359,6 +359,9 @@ tracesys_next:
        be      0(%sr7,%r19)
        ldo     R%tracesys_exit(%r2),%r2
 
+.Ltracesys_nosys:
+       ldo     -ENOSYS(%r0),%r28               /* set errno */
+
        /* Do *not* call this function on the gateway page, because it
        makes a direct call to syscall_trace. */
        
index d4ffcfbc98851e7c3f0707ec9d82470d918bed2e..585d50fc75c0f9776cf2bca74651387790ab6c22 100644 (file)
        ENTRY_SAME(membarrier)
        ENTRY_SAME(userfaultfd)
        ENTRY_SAME(mlock2)              /* 345 */
+       ENTRY_SAME(copy_file_range)
 
 
 .ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
index e4824fd04bb7449d262c1a7697b5f539b03f6bab..9faa18c4f3f702adceb4f555b05b72bc8437cf6c 100644 (file)
@@ -557,7 +557,7 @@ choice
 
 config PPC_4K_PAGES
        bool "4k page size"
-       select HAVE_ARCH_SOFT_DIRTY if CHECKPOINT_RESTORE && PPC_BOOK3S
+       select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64
 
 config PPC_16K_PAGES
        bool "16k page size"
@@ -566,7 +566,7 @@ config PPC_16K_PAGES
 config PPC_64K_PAGES
        bool "64k page size"
        depends on !PPC_FSL_BOOK3E && (44x || PPC_STD_MMU_64 || PPC_BOOK3E_64)
-       select HAVE_ARCH_SOFT_DIRTY if CHECKPOINT_RESTORE && PPC_BOOK3S
+       select HAVE_ARCH_SOFT_DIRTY if PPC_BOOK3S_64
 
 config PPC_256K_PAGES
        bool "256k page size"
index 8d1c41d283184ed56b750f438a8fe201d87dbc4d..ac07a30a7934265ed98706efb9f2c82ac8db85ce 100644 (file)
@@ -281,6 +281,10 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
 extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                            pmd_t *pmdp);
 
+#define __HAVE_ARCH_PMDP_HUGE_SPLIT_PREPARE
+extern void pmdp_huge_split_prepare(struct vm_area_struct *vma,
+                                   unsigned long address, pmd_t *pmdp);
+
 #define pmd_move_must_withdraw pmd_move_must_withdraw
 struct spinlock;
 static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
index c5eb86f3d452fbe66d44ae1cce9bbfff91a8b14d..867c39b45df6ce4c1bd5a342ca314a888bb185bf 100644 (file)
@@ -81,6 +81,7 @@ struct pci_dn;
 #define EEH_PE_KEEP            (1 << 8)        /* Keep PE on hotplug   */
 #define EEH_PE_CFG_RESTRICTED  (1 << 9)        /* Block config on error */
 #define EEH_PE_REMOVED         (1 << 10)       /* Removed permanently  */
+#define EEH_PE_PRI_BUS         (1 << 11)       /* Cached primary bus   */
 
 struct eeh_pe {
        int type;                       /* PE type: PHB/Bus/Device      */
index 8e86b48d03699047dda0f493a3955c8c05e34909..32e36b16773fd876a7b246ddb9e23c28193c3570 100644 (file)
@@ -57,12 +57,14 @@ DEFINE_EVENT(ppc64_interrupt_class, timer_interrupt_exit,
 extern void hcall_tracepoint_regfunc(void);
 extern void hcall_tracepoint_unregfunc(void);
 
-TRACE_EVENT_FN(hcall_entry,
+TRACE_EVENT_FN_COND(hcall_entry,
 
        TP_PROTO(unsigned long opcode, unsigned long *args),
 
        TP_ARGS(opcode, args),
 
+       TP_CONDITION(cpu_online(raw_smp_processor_id())),
+
        TP_STRUCT__entry(
                __field(unsigned long, opcode)
        ),
@@ -76,13 +78,15 @@ TRACE_EVENT_FN(hcall_entry,
        hcall_tracepoint_regfunc, hcall_tracepoint_unregfunc
 );
 
-TRACE_EVENT_FN(hcall_exit,
+TRACE_EVENT_FN_COND(hcall_exit,
 
        TP_PROTO(unsigned long opcode, unsigned long retval,
                unsigned long *retbuf),
 
        TP_ARGS(opcode, retval, retbuf),
 
+       TP_CONDITION(cpu_online(raw_smp_processor_id())),
+
        TP_STRUCT__entry(
                __field(unsigned long, opcode)
                __field(unsigned long, retval)
index dd54f28ecdeca2cf82bdddb2c8e2570862d3b46e..1672e3398270bf50a740895c6ad534689eb84cf5 100644 (file)
@@ -95,4 +95,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index 938742135ee08fc8dd058df690cfba7eacdabc0b..650cfb31ea3d9b3cee0301948bd85e54400cb951 100644 (file)
@@ -418,8 +418,7 @@ static void *eeh_rmv_device(void *data, void *userdata)
                eeh_pcid_put(dev);
                if (driver->err_handler &&
                    driver->err_handler->error_detected &&
-                   driver->err_handler->slot_reset &&
-                   driver->err_handler->resume)
+                   driver->err_handler->slot_reset)
                        return NULL;
        }
 
@@ -564,6 +563,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
         */
        eeh_pe_state_mark(pe, EEH_PE_KEEP);
        if (bus) {
+               eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
                pci_lock_rescan_remove();
                pcibios_remove_pci_devices(bus);
                pci_unlock_rescan_remove();
@@ -803,6 +803,7 @@ perm_error:
         * the their PCI config any more.
         */
        if (frozen_bus) {
+               eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
                eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
 
                pci_lock_rescan_remove();
@@ -886,6 +887,7 @@ static void eeh_handle_special_event(void)
                                        continue;
 
                                /* Notify all devices to be down */
+                               eeh_pe_state_clear(pe, EEH_PE_PRI_BUS);
                                bus = eeh_pe_bus_get(phb_pe);
                                eeh_pe_dev_traverse(pe,
                                        eeh_report_failure, NULL);
index ca9e5371930ea7ca272913b931e0a5c6ffc8b656..98f81800e00c1030b69c80d79eb8d43edbda9728 100644 (file)
@@ -928,7 +928,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
                bus = pe->phb->bus;
        } else if (pe->type & EEH_PE_BUS ||
                   pe->type & EEH_PE_DEVICE) {
-               if (pe->bus) {
+               if (pe->state & EEH_PE_PRI_BUS) {
                        bus = pe->bus;
                        goto out;
                }
index 05e804cdecaa975dc6546ba251bbb61772f72219..aec9a1b1d25bc5a1d998b2a4f099176f9c48934d 100644 (file)
@@ -109,8 +109,9 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp)
         * If the breakpoint is unregistered between a hw_breakpoint_handler()
         * and the single_step_dabr_instruction(), then cleanup the breakpoint
         * restoration variables to prevent dangling pointers.
+        * FIXME, this should not be using bp->ctx at all! Sayeth peterz.
         */
-       if (bp->ctx && bp->ctx->task)
+       if (bp->ctx && bp->ctx->task && bp->ctx->task != ((void *)-1L))
                bp->ctx->task->thread.last_hit_ubp = NULL;
 }
 
index ac64ffdb52c848d170fa34ef9ffe50d8db4d19c0..08b7a40de5f85ab1c6f7e5ed205ca52edd5ab12c 100644 (file)
@@ -340,7 +340,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab)
                        if (name[0] == '.') {
                                if (strcmp(name+1, "TOC.") == 0)
                                        syms[i].st_shndx = SHN_ABS;
-                               memmove(name, name+1, strlen(name));
+                               syms[i].st_name++;
                        }
                }
        }
index dccc87e8fee5e6544de0d8fc732a97aa14f45907..3c5736e52a14b7d42dd0c28425e709b0a7147c3c 100644 (file)
@@ -1768,9 +1768,9 @@ static inline unsigned long brk_rnd(void)
 
        /* 8MB for 32bit, 1GB for 64bit */
        if (is_32bit_task())
-               rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT)));
+               rnd = (get_random_long() % (1UL<<(23-PAGE_SHIFT)));
        else
-               rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT)));
+               rnd = (get_random_long() % (1UL<<(30-PAGE_SHIFT)));
 
        return rnd << PAGE_SHIFT;
 }
index 0762c1e08c88644f35cc8a3df5ba50c52c1801a2..edb09912f0c9b5ca316216bf3d912c7efe8d920a 100644 (file)
@@ -111,7 +111,13 @@ int __hash_page_4K(unsigned long ea, unsigned long access, unsigned long vsid,
         */
        if (!(old_pte & _PAGE_COMBO)) {
                flush_hash_page(vpn, rpte, MMU_PAGE_64K, ssize, flags);
-               old_pte &= ~_PAGE_HASHPTE | _PAGE_F_GIX | _PAGE_F_SECOND;
+               /*
+                * clear the old slot details from the old and new pte.
+                * On hash insert failure we use old pte value and we don't
+                * want slot information there if we have a insert failure.
+                */
+               old_pte &= ~(_PAGE_HASHPTE | _PAGE_F_GIX | _PAGE_F_SECOND);
+               new_pte &= ~(_PAGE_HASHPTE | _PAGE_F_GIX | _PAGE_F_SECOND);
                goto htab_insert_hpte;
        }
        /*
index 49b152b0f926289e1dcaa595988932a036df5325..eb2accdd76fd8bb70a762c4a57df8bc2c425ffad 100644 (file)
@@ -78,9 +78,19 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
                 * base page size. This is because demote_segment won't flush
                 * hash page table entries.
                 */
-               if ((old_pmd & _PAGE_HASHPTE) && !(old_pmd & _PAGE_COMBO))
+               if ((old_pmd & _PAGE_HASHPTE) && !(old_pmd & _PAGE_COMBO)) {
                        flush_hash_hugepage(vsid, ea, pmdp, MMU_PAGE_64K,
                                            ssize, flags);
+                       /*
+                        * With THP, we also clear the slot information with
+                        * respect to all the 64K hash pte mapping the 16MB
+                        * page. They are all invalid now. This make sure we
+                        * don't find the slot valid when we fault with 4k
+                        * base page size.
+                        *
+                        */
+                       memset(hpte_slot_array, 0, PTE_FRAG_SIZE);
+               }
        }
 
        valid = hpte_valid(hpte_slot_array, index);
index 7e6d0880813fe9e363a7e9edd2f5278ef10e4a9e..83a8be791e0646778ddf805d83b5a761bf0d62b1 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
+#include <asm/mmu.h>
+
 #ifdef CONFIG_PPC_FSL_BOOK3E
 #ifdef CONFIG_PPC64
 static inline int tlb1_next(void)
@@ -60,6 +62,14 @@ static inline void book3e_tlb_lock(void)
        unsigned long tmp;
        int token = smp_processor_id() + 1;
 
+       /*
+        * Besides being unnecessary in the absence of SMT, this
+        * check prevents trying to do lbarx/stbcx. on e5500 which
+        * doesn't implement either feature.
+        */
+       if (!cpu_has_feature(CPU_FTR_SMT))
+               return;
+
        asm volatile("1: lbarx %0, 0, %1;"
                     "cmpwi %0, 0;"
                     "bne 2f;"
@@ -80,6 +90,9 @@ static inline void book3e_tlb_unlock(void)
 {
        struct paca_struct *paca = get_paca();
 
+       if (!cpu_has_feature(CPU_FTR_SMT))
+               return;
+
        isync();
        paca->tcd_ptr->lock = 0;
 }
index 0f0502e12f6c4c8accbe7fc28eb4db08158decfb..4087705ba90f34241200e2f30765794ea6b74b55 100644 (file)
@@ -59,9 +59,9 @@ unsigned long arch_mmap_rnd(void)
 
        /* 8MB for 32bit, 1GB for 64bit */
        if (is_32bit_task())
-               rnd = (unsigned long)get_random_int() % (1<<(23-PAGE_SHIFT));
+               rnd = get_random_long() % (1<<(23-PAGE_SHIFT));
        else
-               rnd = (unsigned long)get_random_int() % (1<<(30-PAGE_SHIFT));
+               rnd = get_random_long() % (1UL<<(30-PAGE_SHIFT));
 
        return rnd << PAGE_SHIFT;
 }
index 3124a20d0fab7a66b3a170356037da0d18c9da85..cdf2123d46db4813a4e87f30d29f8da359c313d9 100644 (file)
@@ -646,6 +646,28 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
        return pgtable;
 }
 
+void pmdp_huge_split_prepare(struct vm_area_struct *vma,
+                            unsigned long address, pmd_t *pmdp)
+{
+       VM_BUG_ON(address & ~HPAGE_PMD_MASK);
+       VM_BUG_ON(REGION_ID(address) != USER_REGION_ID);
+
+       /*
+        * We can't mark the pmd none here, because that will cause a race
+        * against exit_mmap. We need to continue mark pmd TRANS HUGE, while
+        * we spilt, but at the same time we wan't rest of the ppc64 code
+        * not to insert hash pte on this, because we will be modifying
+        * the deposited pgtable in the caller of this function. Hence
+        * clear the _PAGE_USER so that we move the fault handling to
+        * higher level function and that will serialize against ptl.
+        * We need to flush existing hash pte entries here even though,
+        * the translation is still valid, because we will withdraw
+        * pgtable_t after this.
+        */
+       pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_USER, 0);
+}
+
+
 /*
  * set a new huge pmd. We should not be called for updating
  * an existing pmd entry. That should go via pmd_hugepage_update.
@@ -663,10 +685,20 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
        return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
 }
 
+/*
+ * We use this to invalidate a pmdp entry before switching from a
+ * hugepte to regular pmd entry.
+ */
 void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                     pmd_t *pmdp)
 {
        pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
+
+       /*
+        * This ensures that generic code that rely on IRQ disabling
+        * to prevent a parallel THP split work as expected.
+        */
+       kick_all_cpus_sync();
 }
 
 /*
index 5f152b95ca0c8493536d787a51d741ae628adb8a..87f47e55aab65ac234df1d67c926ca17b1517f06 100644 (file)
@@ -444,9 +444,12 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
         * PCI devices of the PE are expected to be removed prior
         * to PE reset.
         */
-       if (!edev->pe->bus)
+       if (!(edev->pe->state & EEH_PE_PRI_BUS)) {
                edev->pe->bus = pci_find_bus(hose->global_number,
                                             pdn->busno);
+               if (edev->pe->bus)
+                       edev->pe->state |= EEH_PE_PRI_BUS;
+       }
 
        /*
         * Enable EEH explicitly so that we will do EEH check
index 573ae1994097fb91e15e3f7f6351fe1e73b35c59..f90dc04395bf47bcc0e662a7a1c17526220ccda2 100644 (file)
@@ -3180,6 +3180,7 @@ static void pnv_pci_ioda_shutdown(struct pci_controller *hose)
 
 static const struct pci_controller_ops pnv_pci_ioda_controller_ops = {
        .dma_dev_setup = pnv_pci_dma_dev_setup,
+       .dma_bus_setup = pnv_pci_dma_bus_setup,
 #ifdef CONFIG_PCI_MSI
        .setup_msi_irqs = pnv_setup_msi_irqs,
        .teardown_msi_irqs = pnv_teardown_msi_irqs,
index 2f55c86df703554bfd9541a44f8ba26bec072729..b1ef84a6c9d13cff03c2d4a5234e57265ef5bc75 100644 (file)
@@ -599,6 +599,9 @@ int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
        u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
        long i;
 
+       if (proto_tce & TCE_PCI_WRITE)
+               proto_tce |= TCE_PCI_READ;
+
        for (i = 0; i < npages; i++) {
                unsigned long newtce = proto_tce |
                        ((rpn + i) << tbl->it_page_shift);
@@ -620,6 +623,9 @@ int pnv_tce_xchg(struct iommu_table *tbl, long index,
 
        BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl));
 
+       if (newtce & TCE_PCI_WRITE)
+               newtce |= TCE_PCI_READ;
+
        oldtce = xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce));
        *hpa = be64_to_cpu(oldtce) & ~(TCE_PCI_READ | TCE_PCI_WRITE);
        *direction = iommu_tce_direction(oldtce);
@@ -760,6 +766,26 @@ void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
                phb->dma_dev_setup(phb, pdev);
 }
 
+void pnv_pci_dma_bus_setup(struct pci_bus *bus)
+{
+       struct pci_controller *hose = bus->sysdata;
+       struct pnv_phb *phb = hose->private_data;
+       struct pnv_ioda_pe *pe;
+
+       list_for_each_entry(pe, &phb->ioda.pe_list, list) {
+               if (!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)))
+                       continue;
+
+               if (!pe->pbus)
+                       continue;
+
+               if (bus->number == ((pe->rid >> 8) & 0xFF)) {
+                       pe->pbus = bus;
+                       break;
+               }
+       }
+}
+
 void pnv_pci_shutdown(void)
 {
        struct pci_controller *hose;
index 7f56313e8d7223dfd9f22b927c807b20516cf941..00691a9b99af67b09967c73b39b652b973392f06 100644 (file)
@@ -242,6 +242,7 @@ extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
 extern int pnv_eeh_phb_reset(struct pci_controller *hose, int option);
 
 extern void pnv_pci_dma_dev_setup(struct pci_dev *pdev);
+extern void pnv_pci_dma_bus_setup(struct pci_bus *bus);
 extern int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type);
 extern void pnv_teardown_msi_irqs(struct pci_dev *pdev);
 
index ea91ddfe54ebb901007bb625f833f7457eff0253..629c90865a073174f61fcc47268d3311db4f3a9e 100644 (file)
@@ -40,6 +40,7 @@ static inline void convert_fp_to_vx(__vector128 *vxrs, freg_t *fprs)
 static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
 {
        fpregs->pad = 0;
+       fpregs->fpc = fpu->fpc;
        if (MACHINE_HAS_VX)
                convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs);
        else
@@ -49,6 +50,7 @@ static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu)
 
 static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu)
 {
+       fpu->fpc = fpregs->fpc;
        if (MACHINE_HAS_VX)
                convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs);
        else
index 7aa799134a11754b09ad523a00e54c92a6e1c7a9..a52b6cca873d380adc9bec726cc31816dba5cd6b 100644 (file)
@@ -37,7 +37,7 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
        regs->psw.addr = ip;
 }
 #else
-#error Live patching support is disabled; check CONFIG_LIVEPATCH
+#error Include linux/livepatch.h, not asm/livepatch.h
 #endif
 
 #endif
index d02e89d14fefe45d298e564685a9de377ce7f901..41b51c2f4f1ba98055f7f75ac36915665b62392c 100644 (file)
@@ -94,4 +94,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _ASM_SOCKET_H */
index 66c94417c0ba09a471244a629c78d2457f38b17d..4af60374eba01fba89dc8b170a41428b094160b5 100644 (file)
@@ -271,7 +271,7 @@ static int restore_sigregs_ext32(struct pt_regs *regs,
 
        /* Restore high gprs from signal stack */
        if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high,
-                            sizeof(&sregs_ext->gprs_high)))
+                            sizeof(sregs_ext->gprs_high)))
                return -EFAULT;
        for (i = 0; i < NUM_GPRS; i++)
                *(__u32 *)&regs->gprs[i] = gprs_high[i];
index cfcba2dd9bb51d30b105990e1257543e8b9c39fd..0943b11a2f6e22c088dc13d3b8a0de9b4e6ef92c 100644 (file)
@@ -260,12 +260,13 @@ static unsigned long __store_trace(struct perf_callchain_entry *entry,
 void perf_callchain_kernel(struct perf_callchain_entry *entry,
                           struct pt_regs *regs)
 {
-       unsigned long head;
+       unsigned long head, frame_size;
        struct stack_frame *head_sf;
 
        if (user_mode(regs))
                return;
 
+       frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
        head = regs->gprs[15];
        head_sf = (struct stack_frame *) head;
 
@@ -273,8 +274,9 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
                return;
 
        head = head_sf->back_chain;
-       head = __store_trace(entry, head, S390_lowcore.async_stack - ASYNC_SIZE,
-                            S390_lowcore.async_stack);
+       head = __store_trace(entry, head,
+                            S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
+                            S390_lowcore.async_stack + frame_size);
 
        __store_trace(entry, head, S390_lowcore.thread_info,
                      S390_lowcore.thread_info + THREAD_SIZE);
index 5acba3cb7220ea8c779d9606268a17f9b0a9a928..8f64ebd63767c7a1a3e434b994b65110e890f741 100644 (file)
@@ -59,26 +59,32 @@ static unsigned long save_context_stack(struct stack_trace *trace,
        }
 }
 
-void save_stack_trace(struct stack_trace *trace)
+static void __save_stack_trace(struct stack_trace *trace, unsigned long sp)
 {
-       register unsigned long sp asm ("15");
-       unsigned long orig_sp, new_sp;
+       unsigned long new_sp, frame_size;
 
-       orig_sp = sp;
-       new_sp = save_context_stack(trace, orig_sp,
-                                   S390_lowcore.panic_stack - PAGE_SIZE,
-                                   S390_lowcore.panic_stack, 1);
-       if (new_sp != orig_sp)
-               return;
+       frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
+       new_sp = save_context_stack(trace, sp,
+                       S390_lowcore.panic_stack + frame_size - PAGE_SIZE,
+                       S390_lowcore.panic_stack + frame_size, 1);
        new_sp = save_context_stack(trace, new_sp,
-                                   S390_lowcore.async_stack - ASYNC_SIZE,
-                                   S390_lowcore.async_stack, 1);
-       if (new_sp != orig_sp)
-               return;
+                       S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
+                       S390_lowcore.async_stack + frame_size, 1);
        save_context_stack(trace, new_sp,
                           S390_lowcore.thread_info,
                           S390_lowcore.thread_info + THREAD_SIZE, 1);
 }
+
+void save_stack_trace(struct stack_trace *trace)
+{
+       register unsigned long r15 asm ("15");
+       unsigned long sp;
+
+       sp = r15;
+       __save_stack_trace(trace, sp);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
 EXPORT_SYMBOL_GPL(save_stack_trace);
 
 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
@@ -86,6 +92,10 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
        unsigned long sp, low, high;
 
        sp = tsk->thread.ksp;
+       if (tsk == current) {
+               /* Get current stack pointer. */
+               asm volatile("la %0,0(15)" : "=a" (sp));
+       }
        low = (unsigned long) task_stack_page(tsk);
        high = (unsigned long) task_pt_regs(tsk);
        save_context_stack(trace, sp, low, high, 0);
@@ -93,3 +103,14 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
 EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+
+void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
+{
+       unsigned long sp;
+
+       sp = kernel_stack_pointer(regs);
+       __save_stack_trace(trace, sp);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_regs);
index 21a5df99552bce6e4f84c872acdda43e6c5732c3..dde7654f5c68e5d117d3493d9c0f130f2e24e830 100644 (file)
@@ -18,6 +18,9 @@ void trace_s390_diagnose_norecursion(int diag_nr)
        unsigned long flags;
        unsigned int *depth;
 
+       /* Avoid lockdep recursion. */
+       if (IS_ENABLED(CONFIG_LOCKDEP))
+               return;
        local_irq_save(flags);
        depth = this_cpu_ptr(&diagnose_trace_depth);
        if (*depth == 0) {
index fec59c067d0dddf8ecb4a550124691d0838cda46..792f9c63fbca5b97e03d1251bfff1facc987f9c4 100644 (file)
@@ -93,15 +93,19 @@ static int __memcpy_real(void *dest, void *src, size_t count)
  */
 int memcpy_real(void *dest, void *src, size_t count)
 {
+       int irqs_disabled, rc;
        unsigned long flags;
-       int rc;
 
        if (!count)
                return 0;
-       local_irq_save(flags);
-       __arch_local_irq_stnsm(0xfbUL);
+       flags = __arch_local_irq_stnsm(0xf8UL);
+       irqs_disabled = arch_irqs_disabled_flags(flags);
+       if (!irqs_disabled)
+               trace_hardirqs_off();
        rc = __memcpy_real(dest, src, count);
-       local_irq_restore(flags);
+       if (!irqs_disabled)
+               trace_hardirqs_on();
+       __arch_local_irq_ssm(flags);
        return rc;
 }
 
index fe0bfe370c4534a1ab5ceac19d54372390e19289..1884e17595294bbfafdcaf8e183fd80e40d8ea48 100644 (file)
@@ -54,12 +54,13 @@ __show_trace(unsigned int *depth, unsigned long sp,
 
 void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
 {
-       unsigned long head;
+       unsigned long head, frame_size;
        struct stack_frame* head_sf;
 
        if (user_mode(regs))
                return;
 
+       frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
        head = regs->gprs[15];
        head_sf = (struct stack_frame*)head;
 
@@ -68,8 +69,9 @@ void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
 
        head = head_sf->back_chain;
 
-       head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE,
-                           S390_lowcore.async_stack);
+       head = __show_trace(&depth, head,
+                           S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
+                           S390_lowcore.async_stack + frame_size);
 
        __show_trace(&depth, head, S390_lowcore.thread_info,
                     S390_lowcore.thread_info + THREAD_SIZE);
index eaee14637d93ec5db5f95931b52cc31d5a8c2108..8496a074bd0eb74548ce1e38709b8a8dfe7dfb31 100644 (file)
@@ -24,7 +24,13 @@ LDFLAGS        := -m elf32_sparc
 export BITS    := 32
 UTS_MACHINE    := sparc
 
+# We are adding -Wa,-Av8 to KBUILD_CFLAGS to deal with a specs bug in some
+# versions of gcc.  Some gcc versions won't pass -Av8 to binutils when you
+# give -mcpu=v8.  This silently worked with older bintutils versions but
+# does not any more.
 KBUILD_CFLAGS  += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+KBUILD_CFLAGS  += -Wa,-Av8
+
 KBUILD_AFLAGS  += -m32 -Wa,-Av8
 
 else
index d270ee91968e50ae1e527aea02eecb832e70d2d2..31aede3af088034934c4205f2ab3bf7003956370 100644 (file)
@@ -84,6 +84,8 @@
 #define SO_ATTACH_REUSEPORT_CBPF       0x0035
 #define SO_ATTACH_REUSEPORT_EBPF       0x0036
 
+#define SO_CNX_ADVICE          0x0037
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index 1c26d440d288dfb8d28579fda55e2a76ccf4c139..b6de8b10a55b8b8f09eedb2c90d86906d5445686 100644 (file)
 #define __NR_listen            354
 #define __NR_setsockopt                355
 #define __NR_mlock2            356
+#define __NR_copy_file_range   357
 
-#define NR_syscalls            357
+#define NR_syscalls            358
 
 /* Bitmask values returned from kern_features system call.  */
 #define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
index 33c02b15f47859a8262677d08635fcfdbb8872cb..a83707c83be803b78b3019cac6dde9dba2cfabd6 100644 (file)
@@ -948,7 +948,24 @@ linux_syscall_trace:
        cmp     %o0, 0
        bne     3f
         mov    -ENOSYS, %o0
+
+       /* Syscall tracing can modify the registers.  */
+       ld      [%sp + STACKFRAME_SZ + PT_G1], %g1
+       sethi   %hi(sys_call_table), %l7
+       ld      [%sp + STACKFRAME_SZ + PT_I0], %i0
+       or      %l7, %lo(sys_call_table), %l7
+       ld      [%sp + STACKFRAME_SZ + PT_I1], %i1
+       ld      [%sp + STACKFRAME_SZ + PT_I2], %i2
+       ld      [%sp + STACKFRAME_SZ + PT_I3], %i3
+       ld      [%sp + STACKFRAME_SZ + PT_I4], %i4
+       ld      [%sp + STACKFRAME_SZ + PT_I5], %i5
+       cmp     %g1, NR_syscalls
+       bgeu    3f
+        mov    -ENOSYS, %o0
+
+       sll     %g1, 2, %l4
        mov     %i0, %o0
+       ld      [%l7 + %l4], %l7
        mov     %i1, %o1
        mov     %i2, %o2
        mov     %i3, %o3
index afbaba52d2f16cb30daf092f5cd3986e7ca9c299..d127130bf4246032d39cf923248fce7eebf92867 100644 (file)
@@ -338,8 +338,9 @@ ENTRY(sun4v_mach_set_watchdog)
        mov     %o1, %o4
        mov     HV_FAST_MACH_SET_WATCHDOG, %o5
        ta      HV_FAST_TRAP
+       brnz,a,pn %o4, 0f
        stx     %o1, [%o4]
-       retl
+0:     retl
         nop
 ENDPROC(sun4v_mach_set_watchdog)
 
index d88beff47bab3eb74fece39e282f7c701ab84868..39aaec173f66ebce88fe7953c99b412f5b07cc3d 100644 (file)
@@ -52,7 +52,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        unsigned char fenab;
        int err;
 
-       flush_user_windows();
+       synchronize_user_stack();
        if (get_thread_wsaved()                                 ||
            (((unsigned long)ucp) & (sizeof(unsigned long)-1))  ||
            (!__access_ok(ucp, sizeof(*ucp))))
index a92d5d2c46a3a6553bf13a57f95f65c6d61c334c..9e034f29dcc52208ca98a648e028f955f7c8f882 100644 (file)
@@ -37,6 +37,7 @@ EXPORT_SYMBOL(sun4v_niagara_getperf);
 EXPORT_SYMBOL(sun4v_niagara_setperf);
 EXPORT_SYMBOL(sun4v_niagara2_getperf);
 EXPORT_SYMBOL(sun4v_niagara2_setperf);
+EXPORT_SYMBOL(sun4v_mach_set_watchdog);
 
 /* from hweight.S */
 EXPORT_SYMBOL(__arch_hweight8);
index c690c8e16a96ef2758fca4e9af8080ec7af6c17a..b489e9759518182b6a3884935e5a1c22b1af3524 100644 (file)
@@ -264,7 +264,7 @@ static unsigned long mmap_rnd(void)
        unsigned long rnd = 0UL;
 
        if (current->flags & PF_RANDOMIZE) {
-               unsigned long val = get_random_int();
+               unsigned long val = get_random_long();
                if (test_thread_flag(TIF_32BIT))
                        rnd = (val % (1UL << (23UL-PAGE_SHIFT)));
                else
index bb0008927598b1f7bbeeccdf30c6fa154219a4ce..c4a1b5c40e4efc7ed17bcc0d67d1f058ea4f09f8 100644 (file)
@@ -158,7 +158,25 @@ linux_syscall_trace32:
         add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
+
+       /* Syscall tracing can modify the registers.  */
+       ldx     [%sp + PTREGS_OFF + PT_V9_G1], %g1
+       sethi   %hi(sys_call_table32), %l7
+       ldx     [%sp + PTREGS_OFF + PT_V9_I0], %i0
+       or      %l7, %lo(sys_call_table32), %l7
+       ldx     [%sp + PTREGS_OFF + PT_V9_I1], %i1
+       ldx     [%sp + PTREGS_OFF + PT_V9_I2], %i2
+       ldx     [%sp + PTREGS_OFF + PT_V9_I3], %i3
+       ldx     [%sp + PTREGS_OFF + PT_V9_I4], %i4
+       ldx     [%sp + PTREGS_OFF + PT_V9_I5], %i5
+
+       cmp     %g1, NR_syscalls
+       bgeu,pn %xcc, 3f
+        mov    -ENOSYS, %o0
+
+       sll     %g1, 2, %l4
        srl     %i0, 0, %o0
+       lduw    [%l7 + %l4], %l7
        srl     %i4, 0, %o4
        srl     %i1, 0, %o1
        srl     %i2, 0, %o2
@@ -170,7 +188,25 @@ linux_syscall_trace:
         add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
+
+       /* Syscall tracing can modify the registers.  */
+       ldx     [%sp + PTREGS_OFF + PT_V9_G1], %g1
+       sethi   %hi(sys_call_table64), %l7
+       ldx     [%sp + PTREGS_OFF + PT_V9_I0], %i0
+       or      %l7, %lo(sys_call_table64), %l7
+       ldx     [%sp + PTREGS_OFF + PT_V9_I1], %i1
+       ldx     [%sp + PTREGS_OFF + PT_V9_I2], %i2
+       ldx     [%sp + PTREGS_OFF + PT_V9_I3], %i3
+       ldx     [%sp + PTREGS_OFF + PT_V9_I4], %i4
+       ldx     [%sp + PTREGS_OFF + PT_V9_I5], %i5
+
+       cmp     %g1, NR_syscalls
+       bgeu,pn %xcc, 3f
+        mov    -ENOSYS, %o0
+
+       sll     %g1, 2, %l4
        mov     %i0, %o0
+       lduw    [%l7 + %l4], %l7
        mov     %i1, %o1
        mov     %i2, %o2
        mov     %i3, %o3
index e663b6c78de2e6498a5a458f1129504cae3ab2a8..6c3dd6c52f8bd09135e81f1d56704602d10c4f4e 100644 (file)
@@ -88,4 +88,4 @@ sys_call_table:
 /*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
 /*345*/        .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
 /*350*/        .long sys_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
-/*355*/        .long sys_setsockopt, sys_mlock2
+/*355*/        .long sys_setsockopt, sys_mlock2, sys_copy_file_range
index 1557121f4cdce8a6ae21c31fb33e9aa2d7cbc443..12b524cfcfa0120caabdf7aa5b8606ecc3978c96 100644 (file)
@@ -89,7 +89,7 @@ sys_call_table32:
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
 /*350*/        .word sys32_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
-       .word compat_sys_setsockopt, sys_mlock2
+       .word compat_sys_setsockopt, sys_mlock2, sys_copy_file_range
 
 #endif /* CONFIG_COMPAT */
 
@@ -170,4 +170,4 @@ sys_call_table:
 /*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
        .word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
 /*350*/        .word sys64_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
-       .word sys_setsockopt, sys_mlock2
+       .word sys_setsockopt, sys_mlock2, sys_copy_file_range
index e13d41c392ae4f4940a41e6c8049099c71d28a04..f878bec23576c54c619b633ce0c81508519ddb56 100644 (file)
@@ -34,21 +34,18 @@ struct page;
 
 #if defined(CONFIG_3_LEVEL_PGTABLES) && !defined(CONFIG_64BIT)
 
-typedef struct { unsigned long pte_low, pte_high; } pte_t;
+typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
-#define pte_val(x) ((x).pte_low | ((unsigned long long) (x).pte_high << 32))
-
-#define pte_get_bits(pte, bits) ((pte).pte_low & (bits))
-#define pte_set_bits(pte, bits) ((pte).pte_low |= (bits))
-#define pte_clear_bits(pte, bits) ((pte).pte_low &= ~(bits))
-#define pte_copy(to, from) ({ (to).pte_high = (from).pte_high; \
-                             smp_wmb(); \
-                             (to).pte_low = (from).pte_low; })
-#define pte_is_zero(pte) (!((pte).pte_low & ~_PAGE_NEWPAGE) && !(pte).pte_high)
-#define pte_set_val(pte, phys, prot) \
-       ({ (pte).pte_high = (phys) >> 32; \
-          (pte).pte_low = (phys) | pgprot_val(prot); })
+#define pte_val(p) ((p).pte)
+
+#define pte_get_bits(p, bits) ((p).pte & (bits))
+#define pte_set_bits(p, bits) ((p).pte |= (bits))
+#define pte_clear_bits(p, bits) ((p).pte &= ~(bits))
+#define pte_copy(to, from) ({ (to).pte = (from).pte; })
+#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE))
+#define pte_set_val(p, phys, prot) \
+       ({ (p).pte = (phys) | pgprot_val(prot); })
 
 #define pmd_val(x)     ((x).pmd)
 #define __pmd(x) ((pmd_t) { (x) } )
index 9bdf67a092a53bc9b9f68939abce7cc872e2a8b6..b60a9f8cda7550729a571c1eb6433eb83dcbd858 100644 (file)
@@ -12,6 +12,7 @@
 #include <skas.h>
 
 void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
 
 static void kill_off_processes(void)
 {
index fc8be0e3a4ff879a2cf9fddc8e017dfa974ffc95..57acbd67d85dbd4051cd3c534ceff2a300ce9906 100644 (file)
@@ -69,7 +69,7 @@ void do_signal(struct pt_regs *regs)
        struct ksignal ksig;
        int handled_sig = 0;
 
-       if (get_signal(&ksig)) {
+       while (get_signal(&ksig)) {
                handled_sig = 1;
                /* Whee!  Actually deliver the signal.  */
                handle_signal(&ksig, regs);
index 9af2e63384005002bc99c762f8a61fdd1bbbb3ca..c46662f64c392050d1c45b722e3de7c01f87e250 100644 (file)
@@ -475,6 +475,7 @@ config X86_UV
        depends on X86_64
        depends on X86_EXTENDED_PLATFORM
        depends on NUMA
+       depends on EFI
        depends on X86_X2APIC
        depends on PCI
        ---help---
@@ -777,8 +778,8 @@ config HPET_TIMER
          HPET is the next generation timer replacing legacy 8254s.
          The HPET provides a stable time base on SMP
          systems, unlike the TSC, but it is more expensive to access,
-         as it is off-chip.  You can find the HPET spec at
-         <http://www.intel.com/hardwaredesign/hpetspec_1.pdf>.
+         as it is off-chip.  The interface used is documented
+         in the HPET spec, revision 1.
 
          You can safely choose Y here.  However, HPET will only be
          activated if the platform and the BIOS support this feature.
index 77d8c5112900e0edb73741af9c7cc4a60b0bb8f5..bb3e376d0f33c8dda5a9cf7b4e2b3f2d39f6389a 100644 (file)
@@ -294,6 +294,7 @@ sysenter_past_esp:
        pushl   $__USER_DS              /* pt_regs->ss */
        pushl   %ebp                    /* pt_regs->sp (stashed in bp) */
        pushfl                          /* pt_regs->flags (except IF = 0) */
+       ASM_CLAC                        /* Clear AC after saving FLAGS */
        orl     $X86_EFLAGS_IF, (%esp)  /* Fix IF */
        pushl   $__USER_CS              /* pt_regs->cs */
        pushl   $0                      /* pt_regs->ip = 0 (placeholder) */
index ff1c6d61f332d22e6f95f54a782b150b39bf75dc..3c990eeee40bd6e83b4d830654fdf966250bb0e1 100644 (file)
@@ -261,6 +261,7 @@ ENTRY(entry_INT80_compat)
         * Interrupts are off on entry.
         */
        PARAVIRT_ADJUST_EXCEPTION_FRAME
+       ASM_CLAC                        /* Do this early to minimize exposure */
        SWAPGS
 
        /*
index 19c099afa8613ead6565917f5787deb3df12c9e7..e795f5274217a47cf1713063399675a175d5a4ea 100644 (file)
@@ -41,7 +41,7 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
        regs->ip = ip;
 }
 #else
-#error Live patching support is disabled; check CONFIG_LIVEPATCH
+#error Include linux/livepatch.h, not asm/livepatch.h
 #endif
 
 #endif /* _ASM_X86_LIVEPATCH_H */
index 46873fbd44e1b522b5d40ad5ebf963714df566a1..d08eacd298c2f4b2436b9841203dd5c90f295697 100644 (file)
@@ -93,6 +93,8 @@ extern raw_spinlock_t pci_config_lock;
 extern int (*pcibios_enable_irq)(struct pci_dev *dev);
 extern void (*pcibios_disable_irq)(struct pci_dev *dev);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 struct pci_raw_ops {
        int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val);
index 2d5a50cb61a2d6ad5c68d5563636edcc112ff4f9..20c11d1aa4ccce11b0709c3fe56092a5505151cf 100644 (file)
@@ -766,7 +766,7 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk);
  * Return saved PC of a blocked thread.
  * What is this good for? it will be always the scheduler or ret_from_fork.
  */
-#define thread_saved_pc(t)     (*(unsigned long *)((t)->thread.sp - 8))
+#define thread_saved_pc(t)     READ_ONCE_NOCHECK(*(unsigned long *)((t)->thread.sp - 8))
 
 #define task_pt_regs(tsk)      ((struct pt_regs *)(tsk)->thread.sp0 - 1)
 extern unsigned long KSTK_ESP(struct task_struct *task);
index 70bbe39043a9cda384e9afcd0a2f633cfde20931..7c247e7404be778e06ebff15f020dbd792fb7be0 100644 (file)
@@ -37,7 +37,7 @@ print_context_stack_bp(struct thread_info *tinfo,
 /* Generic stack tracer with callbacks */
 
 struct stacktrace_ops {
-       void (*address)(void *data, unsigned long address, int reliable);
+       int (*address)(void *data, unsigned long address, int reliable);
        /* On negative return stop dumping */
        int (*stack)(void *data, char *name);
        walk_stack_t    walk_stack;
index f5dcb5204dcd5b27e8b8e9a1b87612a28cda10c6..3fe0eac59462b39fc12ce28a6e22d6e347b8719a 100644 (file)
@@ -48,20 +48,28 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __put_user_size(*(u8 *)from, (u8 __user *)to,
                                        1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __put_user_size(*(u16 *)from, (u16 __user *)to,
                                        2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __put_user_size(*(u32 *)from, (u32 __user *)to,
                                        4, ret, 4);
+                       __uaccess_end();
                        return ret;
                case 8:
+                       __uaccess_begin();
                        __put_user_size(*(u64 *)from, (u64 __user *)to,
                                        8, ret, 8);
+                       __uaccess_end();
                        return ret;
                }
        }
@@ -103,13 +111,19 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       __uaccess_end();
                        return ret;
                }
        }
@@ -148,13 +162,19 @@ __copy_from_user(void *to, const void __user *from, unsigned long n)
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       __uaccess_end();
                        return ret;
                }
        }
@@ -170,13 +190,19 @@ static __always_inline unsigned long __copy_from_user_nocache(void *to,
 
                switch (n) {
                case 1:
+                       __uaccess_begin();
                        __get_user_size(*(u8 *)to, from, 1, ret, 1);
+                       __uaccess_end();
                        return ret;
                case 2:
+                       __uaccess_begin();
                        __get_user_size(*(u16 *)to, from, 2, ret, 2);
+                       __uaccess_end();
                        return ret;
                case 4:
+                       __uaccess_begin();
                        __get_user_size(*(u32 *)to, from, 4, ret, 4);
+                       __uaccess_end();
                        return ret;
                }
        }
index 968d57dd54c9d19ed0a93cb3be6633d3328dc4e7..f320ee32d5a139a522c1b26f75e1076c9606f563 100644 (file)
@@ -57,7 +57,7 @@ static inline int xen_pci_frontend_enable_msi(struct pci_dev *dev,
 {
        if (xen_pci_frontend && xen_pci_frontend->enable_msi)
                return xen_pci_frontend->enable_msi(dev, vectors);
-       return -ENODEV;
+       return -ENOSYS;
 }
 static inline void xen_pci_frontend_disable_msi(struct pci_dev *dev)
 {
@@ -69,7 +69,7 @@ static inline int xen_pci_frontend_enable_msix(struct pci_dev *dev,
 {
        if (xen_pci_frontend && xen_pci_frontend->enable_msix)
                return xen_pci_frontend->enable_msix(dev, vectors, nvec);
-       return -ENODEV;
+       return -ENOSYS;
 }
 static inline void xen_pci_frontend_disable_msix(struct pci_dev *dev)
 {
index d1daead5fcddd57ab4cd0675315420bf52608584..adb3eaf8fe2a5e038c2444bd8f75b55716faf607 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/cacheflush.h>
 #include <asm/realmode.h>
 
+#include <linux/ftrace.h>
 #include "../../realmode/rm/wakeup.h"
 #include "sleep.h"
 
@@ -107,7 +108,13 @@ int x86_acpi_suspend_lowlevel(void)
        saved_magic = 0x123456789abcdef0L;
 #endif /* CONFIG_64BIT */
 
+       /*
+        * Pause/unpause graph tracing around do_suspend_lowlevel as it has
+        * inconsistent call/return info after it jumps to the wakeup vector.
+        */
+       pause_graph_tracing();
        do_suspend_lowlevel();
+       unpause_graph_tracing();
        return 0;
 }
 
index 1b443db2db5005d62ed4e08f918fdfcaa071ac37..d276b31ca47366e51605a8cdf2fc846739ad4fe7 100644 (file)
@@ -2180,11 +2180,11 @@ static int backtrace_stack(void *data, char *name)
        return 0;
 }
 
-static void backtrace_address(void *data, unsigned long addr, int reliable)
+static int backtrace_address(void *data, unsigned long addr, int reliable)
 {
        struct perf_callchain_entry *entry = data;
 
-       perf_callchain_store(entry, addr);
+       return perf_callchain_store(entry, addr);
 }
 
 static const struct stacktrace_ops backtrace_ops = {
index 49742746a6c963c4a86c08c773430087225fec53..8836fc9fa84b08de4e35ddd60ac7b0f828fec231 100644 (file)
@@ -323,6 +323,8 @@ static int amd_uncore_cpu_up_prepare(unsigned int cpu)
        return 0;
 
 fail:
+       if (amd_uncore_nb)
+               *per_cpu_ptr(amd_uncore_nb, cpu) = NULL;
        kfree(uncore_nb);
        return -ENOMEM;
 }
index 9c30acfadae24757cca11f00513d089e488da78d..0d1ff4b407d4e1f9c445cf7516495824f85f3cfe 100644 (file)
@@ -135,7 +135,8 @@ print_context_stack_bp(struct thread_info *tinfo,
                if (!__kernel_text_address(addr))
                        break;
 
-               ops->address(data, addr, 1);
+               if (ops->address(data, addr, 1))
+                       break;
                frame = frame->next_frame;
                ret_addr = &frame->return_address;
                print_ftrace_graph_addr(addr, data, ops, tinfo, graph);
@@ -154,10 +155,11 @@ static int print_trace_stack(void *data, char *name)
 /*
  * Print one address/symbol entries per line.
  */
-static void print_trace_address(void *data, unsigned long addr, int reliable)
+static int print_trace_address(void *data, unsigned long addr, int reliable)
 {
        touch_nmi_watchdog();
        printk_stack_address(addr, reliable, data);
+       return 0;
 }
 
 static const struct stacktrace_ops print_trace_ops = {
index fdd0c6430e5abc97c878d192439447298b2fd06c..9ee98eefc44dec04148dada9c3b8000c016fd738 100644 (file)
@@ -14,30 +14,34 @@ static int save_stack_stack(void *data, char *name)
        return 0;
 }
 
-static void
+static int
 __save_stack_address(void *data, unsigned long addr, bool reliable, bool nosched)
 {
        struct stack_trace *trace = data;
 #ifdef CONFIG_FRAME_POINTER
        if (!reliable)
-               return;
+               return 0;
 #endif
        if (nosched && in_sched_functions(addr))
-               return;
+               return 0;
        if (trace->skip > 0) {
                trace->skip--;
-               return;
+               return 0;
        }
-       if (trace->nr_entries < trace->max_entries)
+       if (trace->nr_entries < trace->max_entries) {
                trace->entries[trace->nr_entries++] = addr;
+               return 0;
+       } else {
+               return -1; /* no more room, stop walking the stack */
+       }
 }
 
-static void save_stack_address(void *data, unsigned long addr, int reliable)
+static int save_stack_address(void *data, unsigned long addr, int reliable)
 {
        return __save_stack_address(data, addr, reliable, false);
 }
 
-static void
+static int
 save_stack_address_nosched(void *data, unsigned long addr, int reliable)
 {
        return __save_stack_address(data, addr, reliable, true);
index 1505587d06e97826703b21aba540ea8403bd8f2c..b9b09fec173bf2fedb0b9ee122b3c4668eb6e471 100644 (file)
@@ -650,10 +650,10 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
        u16 sel;
 
        la = seg_base(ctxt, addr.seg) + addr.ea;
-       *linear = la;
        *max_size = 0;
        switch (mode) {
        case X86EMUL_MODE_PROT64:
+               *linear = la;
                if (is_noncanonical_address(la))
                        goto bad;
 
@@ -662,6 +662,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
                        goto bad;
                break;
        default:
+               *linear = la = (u32)la;
                usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
                                                addr.seg);
                if (!usable)
@@ -689,7 +690,6 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
                        if (size > *max_size)
                                goto bad;
                }
-               la &= (u32)-1;
                break;
        }
        if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0))
index 6c9fed957cce1c897f0a490ec74c3f4e4f76d4dc..2ce4f05e81d3804cef4ded542a105a5a917b8bed 100644 (file)
@@ -249,7 +249,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
                        return ret;
 
                kvm_vcpu_mark_page_dirty(vcpu, table_gfn);
-               walker->ptes[level] = pte;
+               walker->ptes[level - 1] = pte;
        }
        return 0;
 }
index e2951b6edbbce4deb5bad4fb38b8858c8093f8d5..0ff453749a909b9f0140b5de5d5d2dbb133e99d9 100644 (file)
@@ -596,6 +596,8 @@ struct vcpu_vmx {
        /* Support for PML */
 #define PML_ENTITY_NUM         512
        struct page *pml_pg;
+
+       u64 current_tsc_ratio;
 };
 
 enum segment_cache_field {
@@ -2127,14 +2129,16 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
                vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
 
-               /* Setup TSC multiplier */
-               if (cpu_has_vmx_tsc_scaling())
-                       vmcs_write64(TSC_MULTIPLIER,
-                                    vcpu->arch.tsc_scaling_ratio);
-
                vmx->loaded_vmcs->cpu = cpu;
        }
 
+       /* Setup TSC multiplier */
+       if (kvm_has_tsc_control &&
+           vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio) {
+               vmx->current_tsc_ratio = vcpu->arch.tsc_scaling_ratio;
+               vmcs_write64(TSC_MULTIPLIER, vmx->current_tsc_ratio);
+       }
+
        vmx_vcpu_pi_load(vcpu, cpu);
 }
 
index 4244c2baf57da55aa5dd266b63781642dcc8af12..eaf6ee8c28b8f1619e7404bfd7efbf78beecc574 100644 (file)
@@ -6618,12 +6618,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
         * KVM_DEBUGREG_WONT_EXIT again.
         */
        if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) {
-               int i;
-
                WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP);
                kvm_x86_ops->sync_dirty_debug_regs(vcpu);
-               for (i = 0; i < KVM_NR_DB_REGS; i++)
-                       vcpu->arch.eff_db[i] = vcpu->arch.db[i];
+               kvm_update_dr0123(vcpu);
+               kvm_update_dr6(vcpu);
+               kvm_update_dr7(vcpu);
+               vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
        }
 
        /*
index 982ce34f4a9bf66011fc2652b45466d9c2b276f9..27f89c79a44b7da6fc6aef54e3961426e542e7ed 100644 (file)
@@ -232,17 +232,31 @@ ENDPROC(copy_user_enhanced_fast_string)
 
 /*
  * copy_user_nocache - Uncached memory copy with exception handling
- * This will force destination/source out of cache for more performance.
+ * This will force destination out of cache for more performance.
+ *
+ * Note: Cached memory copy is used when destination or size is not
+ * naturally aligned. That is:
+ *  - Require 8-byte alignment when size is 8 bytes or larger.
+ *  - Require 4-byte alignment when size is 4 bytes.
  */
 ENTRY(__copy_user_nocache)
        ASM_STAC
+
+       /* If size is less than 8 bytes, go to 4-byte copy */
        cmpl $8,%edx
-       jb 20f          /* less then 8 bytes, go to byte copy loop */
+       jb .L_4b_nocache_copy_entry
+
+       /* If destination is not 8-byte aligned, "cache" copy to align it */
        ALIGN_DESTINATION
+
+       /* Set 4x8-byte copy count and remainder */
        movl %edx,%ecx
        andl $63,%edx
        shrl $6,%ecx
-       jz 17f
+       jz .L_8b_nocache_copy_entry     /* jump if count is 0 */
+
+       /* Perform 4x8-byte nocache loop-copy */
+.L_4x8b_nocache_copy_loop:
 1:     movq (%rsi),%r8
 2:     movq 1*8(%rsi),%r9
 3:     movq 2*8(%rsi),%r10
@@ -262,60 +276,106 @@ ENTRY(__copy_user_nocache)
        leaq 64(%rsi),%rsi
        leaq 64(%rdi),%rdi
        decl %ecx
-       jnz 1b
-17:    movl %edx,%ecx
+       jnz .L_4x8b_nocache_copy_loop
+
+       /* Set 8-byte copy count and remainder */
+.L_8b_nocache_copy_entry:
+       movl %edx,%ecx
        andl $7,%edx
        shrl $3,%ecx
-       jz 20f
-18:    movq (%rsi),%r8
-19:    movnti %r8,(%rdi)
+       jz .L_4b_nocache_copy_entry     /* jump if count is 0 */
+
+       /* Perform 8-byte nocache loop-copy */
+.L_8b_nocache_copy_loop:
+20:    movq (%rsi),%r8
+21:    movnti %r8,(%rdi)
        leaq 8(%rsi),%rsi
        leaq 8(%rdi),%rdi
        decl %ecx
-       jnz 18b
-20:    andl %edx,%edx
-       jz 23f
+       jnz .L_8b_nocache_copy_loop
+
+       /* If no byte left, we're done */
+.L_4b_nocache_copy_entry:
+       andl %edx,%edx
+       jz .L_finish_copy
+
+       /* If destination is not 4-byte aligned, go to byte copy: */
+       movl %edi,%ecx
+       andl $3,%ecx
+       jnz .L_1b_cache_copy_entry
+
+       /* Set 4-byte copy count (1 or 0) and remainder */
        movl %edx,%ecx
-21:    movb (%rsi),%al
-22:    movb %al,(%rdi)
+       andl $3,%edx
+       shrl $2,%ecx
+       jz .L_1b_cache_copy_entry       /* jump if count is 0 */
+
+       /* Perform 4-byte nocache copy: */
+30:    movl (%rsi),%r8d
+31:    movnti %r8d,(%rdi)
+       leaq 4(%rsi),%rsi
+       leaq 4(%rdi),%rdi
+
+       /* If no bytes left, we're done: */
+       andl %edx,%edx
+       jz .L_finish_copy
+
+       /* Perform byte "cache" loop-copy for the remainder */
+.L_1b_cache_copy_entry:
+       movl %edx,%ecx
+.L_1b_cache_copy_loop:
+40:    movb (%rsi),%al
+41:    movb %al,(%rdi)
        incq %rsi
        incq %rdi
        decl %ecx
-       jnz 21b
-23:    xorl %eax,%eax
+       jnz .L_1b_cache_copy_loop
+
+       /* Finished copying; fence the prior stores */
+.L_finish_copy:
+       xorl %eax,%eax
        ASM_CLAC
        sfence
        ret
 
        .section .fixup,"ax"
-30:    shll $6,%ecx
+.L_fixup_4x8b_copy:
+       shll $6,%ecx
        addl %ecx,%edx
-       jmp 60f
-40:    lea (%rdx,%rcx,8),%rdx
-       jmp 60f
-50:    movl %ecx,%edx
-60:    sfence
+       jmp .L_fixup_handle_tail
+.L_fixup_8b_copy:
+       lea (%rdx,%rcx,8),%rdx
+       jmp .L_fixup_handle_tail
+.L_fixup_4b_copy:
+       lea (%rdx,%rcx,4),%rdx
+       jmp .L_fixup_handle_tail
+.L_fixup_1b_copy:
+       movl %ecx,%edx
+.L_fixup_handle_tail:
+       sfence
        jmp copy_user_handle_tail
        .previous
 
-       _ASM_EXTABLE(1b,30b)
-       _ASM_EXTABLE(2b,30b)
-       _ASM_EXTABLE(3b,30b)
-       _ASM_EXTABLE(4b,30b)
-       _ASM_EXTABLE(5b,30b)
-       _ASM_EXTABLE(6b,30b)
-       _ASM_EXTABLE(7b,30b)
-       _ASM_EXTABLE(8b,30b)
-       _ASM_EXTABLE(9b,30b)
-       _ASM_EXTABLE(10b,30b)
-       _ASM_EXTABLE(11b,30b)
-       _ASM_EXTABLE(12b,30b)
-       _ASM_EXTABLE(13b,30b)
-       _ASM_EXTABLE(14b,30b)
-       _ASM_EXTABLE(15b,30b)
-       _ASM_EXTABLE(16b,30b)
-       _ASM_EXTABLE(18b,40b)
-       _ASM_EXTABLE(19b,40b)
-       _ASM_EXTABLE(21b,50b)
-       _ASM_EXTABLE(22b,50b)
+       _ASM_EXTABLE(1b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(2b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(3b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(4b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(5b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(6b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(7b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(8b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(9b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(10b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(11b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(12b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(13b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(14b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(15b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(16b,.L_fixup_4x8b_copy)
+       _ASM_EXTABLE(20b,.L_fixup_8b_copy)
+       _ASM_EXTABLE(21b,.L_fixup_8b_copy)
+       _ASM_EXTABLE(30b,.L_fixup_4b_copy)
+       _ASM_EXTABLE(31b,.L_fixup_4b_copy)
+       _ASM_EXTABLE(40b,.L_fixup_1b_copy)
+       _ASM_EXTABLE(41b,.L_fixup_1b_copy)
 ENDPROC(__copy_user_nocache)
index eef44d9a3f77e2acc88baa424683388f67985e24..e830c71a13232f4305adf9ef1eb8ce6ffe201d5b 100644 (file)
@@ -287,6 +287,9 @@ static noinline int vmalloc_fault(unsigned long address)
        if (!pmd_k)
                return -1;
 
+       if (pmd_huge(*pmd_k))
+               return 0;
+
        pte_k = pte_offset_kernel(pmd_k, address);
        if (!pte_present(*pte_k))
                return -1;
@@ -360,8 +363,6 @@ void vmalloc_sync_all(void)
  * 64-bit:
  *
  *   Handle a fault on the vmalloc area
- *
- * This assumes no large pages in there.
  */
 static noinline int vmalloc_fault(unsigned long address)
 {
@@ -403,17 +404,23 @@ static noinline int vmalloc_fault(unsigned long address)
        if (pud_none(*pud_ref))
                return -1;
 
-       if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref))
+       if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
                BUG();
 
+       if (pud_huge(*pud))
+               return 0;
+
        pmd = pmd_offset(pud, address);
        pmd_ref = pmd_offset(pud_ref, address);
        if (pmd_none(*pmd_ref))
                return -1;
 
-       if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref))
+       if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
                BUG();
 
+       if (pmd_huge(*pmd))
+               return 0;
+
        pte_ref = pte_offset_kernel(pmd_ref, address);
        if (!pte_present(*pte_ref))
                return -1;
index 6d5eb59003721b79213a7661994be1a339bc5590..d8a798d8bf50ac037fa2ac4854085bd78759c249 100644 (file)
@@ -102,7 +102,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
                        return 0;
                }
 
-               page = pte_page(pte);
                if (pte_devmap(pte)) {
                        pgmap = get_dev_pagemap(pte_pfn(pte), pgmap);
                        if (unlikely(!pgmap)) {
@@ -115,6 +114,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
                        return 0;
                }
                VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+               page = pte_page(pte);
                get_page(page);
                put_dev_pagemap(pgmap);
                SetPageReferenced(page);
index 42982b26e32be693713d90e8fa4e18b8f771eb4a..740d7ac03a552bc4937edfc8ff7e8b9d044a61b6 100644 (file)
@@ -173,10 +173,10 @@ static __init int setup_hugepagesz(char *opt)
 }
 __setup("hugepagesz=", setup_hugepagesz);
 
-#ifdef CONFIG_CMA
+#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
 static __init int gigantic_pages_init(void)
 {
-       /* With CMA we can allocate gigantic pages at runtime */
+       /* With compaction or CMA we can allocate gigantic pages at runtime */
        if (cpu_has_gbpages && !size_to_hstate(1UL << PUD_SHIFT))
                hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
        return 0;
index 96bd1e2bffafb3b8ffbc28906a2998ad992d50e8..72bb52f93c3d619d0dc6c0355b7ab293a24c3199 100644 (file)
@@ -71,12 +71,12 @@ unsigned long arch_mmap_rnd(void)
 
        if (mmap_is_ia32())
 #ifdef CONFIG_COMPAT
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
 #else
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 #endif
        else
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 
        return rnd << PAGE_SHIFT;
 }
index b2fd67da1701433d9168ebf1d0a908330544bd7d..ef05755a190063cdf79210f7ac164aef1a0f4ec5 100644 (file)
@@ -123,7 +123,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
                break;
        }
 
-       if (regno > nr_registers) {
+       if (regno >= nr_registers) {
                WARN_ONCE(1, "decoded an instruction with an invalid register");
                return -EINVAL;
        }
index c3b3f653ed0c6c9112297164c5cf535494f19461..d04f8094bc2323bbaa76095ab09efa2e8357cc7e 100644 (file)
@@ -469,7 +469,7 @@ static void __init numa_clear_kernel_node_hotplug(void)
 {
        int i, nid;
        nodemask_t numa_kernel_nodes = NODE_MASK_NONE;
-       unsigned long start, end;
+       phys_addr_t start, end;
        struct memblock_region *r;
 
        /*
index 2440814b00699e33809ce061d6f86a48437f7a10..9cf96d82147a8da38ce4f57413d75075003cb244 100644 (file)
@@ -419,24 +419,30 @@ pmd_t *lookup_pmd_address(unsigned long address)
 phys_addr_t slow_virt_to_phys(void *__virt_addr)
 {
        unsigned long virt_addr = (unsigned long)__virt_addr;
-       unsigned long phys_addr, offset;
+       phys_addr_t phys_addr;
+       unsigned long offset;
        enum pg_level level;
        pte_t *pte;
 
        pte = lookup_address(virt_addr, &level);
        BUG_ON(!pte);
 
+       /*
+        * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t
+        * before being left-shifted PAGE_SHIFT bits -- this trick is to
+        * make 32-PAE kernel work correctly.
+        */
        switch (level) {
        case PG_LEVEL_1G:
-               phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
+               phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT;
                offset = virt_addr & ~PUD_PAGE_MASK;
                break;
        case PG_LEVEL_2M:
-               phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
+               phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT;
                offset = virt_addr & ~PMD_PAGE_MASK;
                break;
        default:
-               phys_addr = pte_pfn(*pte) << PAGE_SHIFT;
+               phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT;
                offset = virt_addr & ~PAGE_MASK;
        }
 
index 4e664bdb535ad89d09633fd73ea6eca5a46d4097..cb31a4440e588552f5fd046ae787c107aa09ec94 100644 (file)
@@ -23,12 +23,13 @@ static int backtrace_stack(void *data, char *name)
        return 0;
 }
 
-static void backtrace_address(void *data, unsigned long addr, int reliable)
+static int backtrace_address(void *data, unsigned long addr, int reliable)
 {
        unsigned int *depth = data;
 
        if ((*depth)--)
                oprofile_add_trace(addr);
+       return 0;
 }
 
 static struct stacktrace_ops backtrace_ops = {
index 2879efc73a967bca70606547014decd3703c84bf..d34b5118b4e8e7a30c55d722733d03b00bade013 100644 (file)
@@ -711,28 +711,22 @@ int pcibios_add_device(struct pci_dev *dev)
        return 0;
 }
 
-int pcibios_alloc_irq(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
-       /*
-        * If the PCI device was already claimed by core code and has
-        * MSI enabled, probing of the pcibios IRQ will overwrite
-        * dev->irq.  So bail out if MSI is already enabled.
-        */
-       if (pci_dev_msi_enabled(dev))
-               return -EBUSY;
+       int err;
 
-       return pcibios_enable_irq(dev);
-}
+       if ((err = pci_enable_resources(dev, mask)) < 0)
+               return err;
 
-void pcibios_free_irq(struct pci_dev *dev)
-{
-       if (pcibios_disable_irq)
-               pcibios_disable_irq(dev);
+       if (!pci_dev_msi_enabled(dev))
+               return pcibios_enable_irq(dev);
+       return 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev, int mask)
+void pcibios_disable_device (struct pci_dev *dev)
 {
-       return pci_enable_resources(dev, mask);
+       if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq)
+               pcibios_disable_irq(dev);
 }
 
 int pci_ext_cfg_avail(void)
index 0d24e7c101454057f432dd976ea7e3d537e0a38c..8b93e634af84c4698e6f7c6ab718a018e2cdc9db 100644 (file)
@@ -215,7 +215,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
        int polarity;
        int ret;
 
-       if (pci_has_managed_irq(dev))
+       if (dev->irq_managed && dev->irq > 0)
                return 0;
 
        switch (intel_mid_identify_cpu()) {
@@ -256,13 +256,10 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (pci_has_managed_irq(dev)) {
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed &&
+           dev->irq > 0) {
                mp_unmap_irq(dev->irq);
                dev->irq_managed = 0;
-               /*
-                * Don't reset dev->irq here, otherwise
-                * intel_mid_pci_irq_enable() will fail on next call.
-                */
        }
 }
 
index 32e70343e6fdd0e58ab80644284dd01000dccd82..9bd115484745703791c6515b289938546d2478ab 100644 (file)
@@ -1202,7 +1202,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
                        struct pci_dev *temp_dev;
                        int irq;
 
-                       if (pci_has_managed_irq(dev))
+                       if (dev->irq_managed && dev->irq > 0)
                                return 0;
 
                        irq = IO_APIC_get_PCI_irq_vector(dev->bus->number,
@@ -1230,7 +1230,8 @@ static int pirq_enable_irq(struct pci_dev *dev)
                        }
                        dev = temp_dev;
                        if (irq >= 0) {
-                               pci_set_managed_irq(dev, irq);
+                               dev->irq_managed = 1;
+                               dev->irq = irq;
                                dev_info(&dev->dev, "PCI->APIC IRQ transform: "
                                         "INT %c -> IRQ %d\n", 'A' + pin - 1, irq);
                                return 0;
@@ -1256,10 +1257,24 @@ static int pirq_enable_irq(struct pci_dev *dev)
        return 0;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && pci_has_managed_irq(dev)) {
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
+           dev->irq_managed && dev->irq) {
                mp_unmap_irq(dev->irq);
-               pci_reset_managed_irq(dev);
+               dev->irq = 0;
+               dev->irq_managed = 0;
        }
 }
index ff31ab464213fc49f21d0dde5bdcb14cc0763020..beac4dfdade6c05c02591e924fd913d5db53abcd 100644 (file)
@@ -196,7 +196,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        return 0;
 
 error:
-       dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
+       if (ret == -ENOSYS)
+               dev_err(&dev->dev, "Xen PCI frontend has not registered MSI/MSI-X support!\n");
+       else if (ret)
+               dev_err(&dev->dev, "Xen PCI frontend error: %d!\n", ret);
 free:
        kfree(v);
        return ret;
index c61b6c332e971929fd4d639b9754e8707f513930..bfadcd0f4944276e39999cd00b86d6c786d1a085 100644 (file)
@@ -592,14 +592,14 @@ static void __init imr_fixup_memmap(struct imr_device *idev)
        end = (unsigned long)__end_rodata - 1;
 
        /*
-        * Setup a locked IMR around the physical extent of the kernel
+        * Setup an unlocked IMR around the physical extent of the kernel
         * from the beginning of the .text secton to the end of the
         * .rodata section as one physically contiguous block.
         *
         * We don't round up @size since it is already PAGE_SIZE aligned.
         * See vmlinux.lds.S for details.
         */
-       ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, true);
+       ret = imr_add_range(base, size, IMR_CPU, IMR_CPU, false);
        if (ret < 0) {
                pr_err("unable to setup IMR for kernel: %zu KiB (%lx - %lx)\n",
                        size / 1024, start, end);
index 8502ad30e61bcfc49a9e28c975d356b4b628a62c..5adb6a2fd117df01c232156e2091bfc3d190eac7 100644 (file)
@@ -109,7 +109,7 @@ unsigned long os_get_top_address(void)
                exit(1);
        }
 
-       printf("0x%x\n", bottom << UM_KERN_PAGE_SHIFT);
+       printf("0x%lx\n", bottom << UM_KERN_PAGE_SHIFT);
        printf("Locating the top of the address space ... ");
        fflush(stdout);
 
@@ -134,7 +134,7 @@ out:
                exit(1);
        }
        top <<= UM_KERN_PAGE_SHIFT;
-       printf("0x%x\n", top);
+       printf("0x%lx\n", top);
 
        return top;
 }
index fd3b96d1153fdf04e8813f1612a4ad7903fae574..81435d995e1183d07ed0aac8903503e174a5c21e 100644 (file)
@@ -99,4 +99,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* _XTENSA_SOCKET_H */
index 161491d0a879ed11ce2276a1923a60bc1d92479e..0363cd731320d8d9d93cdcd8e3fb5351682e6464 100644 (file)
@@ -88,6 +88,19 @@ config BLK_DEV_INTEGRITY
        T10/SCSI Data Integrity Field or the T13/ATA External Path
        Protection.  If in doubt, say N.
 
+config BLK_DEV_DAX
+       bool "Block device DAX support"
+       depends on FS_DAX
+       depends on BROKEN
+       help
+         When DAX support is available (CONFIG_FS_DAX) raw block
+         devices can also support direct userspace access to the
+         storage capacity via MMAP(2) similar to a file on a
+         DAX-enabled filesystem.  However, the DAX I/O-path disables
+         some standard I/O-statistics, and the MMAP(2) path has some
+         operational differences due to bypassing the page
+         cache.  If in doubt, say N.
+
 config BLK_DEV_THROTTLING
        bool "Block layer bio throttling support"
        depends on BLK_CGROUP=y
index dbabd48b1934739bba125827e2019414cf34adee..cf7591551b1716b74fa3765cb1c271a554e8ef56 100644 (file)
@@ -874,7 +874,7 @@ int submit_bio_wait(int rw, struct bio *bio)
        bio->bi_private = &ret;
        bio->bi_end_io = submit_bio_wait_endio;
        submit_bio(rw, bio);
-       wait_for_completion(&ret.event);
+       wait_for_completion_io(&ret.event);
 
        return ret.error;
 }
@@ -1090,9 +1090,12 @@ int bio_uncopy_user(struct bio *bio)
        if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
                /*
                 * if we're in a workqueue, the request is orphaned, so
-                * don't copy into a random user address space, just free.
+                * don't copy into a random user address space, just free
+                * and return -EINTR so user space doesn't expect any data.
                 */
-               if (current->mm && bio_data_dir(bio) == READ)
+               if (!current->mm)
+                       ret = -EINTR;
+               else if (bio_data_dir(bio) == READ)
                        ret = bio_copy_to_iter(bio, bmd->iter);
                if (bmd->is_our_pages)
                        bio_free_pages(bio);
index 5a37188b559fba8feb1da48b00d5290c3a6a09b6..66e6f1aae02eeb14de30ada1e6696622082729c1 100644 (file)
@@ -788,6 +788,7 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
 {
        struct gendisk *disk;
        struct blkcg_gq *blkg;
+       struct module *owner;
        unsigned int major, minor;
        int key_len, part, ret;
        char *body;
@@ -804,7 +805,9 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
        if (!disk)
                return -ENODEV;
        if (part) {
+               owner = disk->fops->owner;
                put_disk(disk);
+               module_put(owner);
                return -ENODEV;
        }
 
@@ -820,7 +823,9 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
                ret = PTR_ERR(blkg);
                rcu_read_unlock();
                spin_unlock_irq(disk->queue->queue_lock);
+               owner = disk->fops->owner;
                put_disk(disk);
+               module_put(owner);
                /*
                 * If queue was bypassing, we should retry.  Do so after a
                 * short msleep().  It isn't strictly necessary but queue
@@ -851,9 +856,13 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep);
 void blkg_conf_finish(struct blkg_conf_ctx *ctx)
        __releases(ctx->disk->queue->queue_lock) __releases(rcu)
 {
+       struct module *owner;
+
        spin_unlock_irq(ctx->disk->queue->queue_lock);
        rcu_read_unlock();
+       owner = ctx->disk->fops->owner;
        put_disk(ctx->disk);
+       module_put(owner);
 }
 EXPORT_SYMBOL_GPL(blkg_conf_finish);
 
index ab51685988c253616f751615ba06206732149de4..b83d29755b5a04509edd3ebfe70f89f354a09932 100644 (file)
@@ -2455,14 +2455,16 @@ struct request *blk_peek_request(struct request_queue *q)
 
                        rq = NULL;
                        break;
-               } else if (ret == BLKPREP_KILL) {
+               } else if (ret == BLKPREP_KILL || ret == BLKPREP_INVALID) {
+                       int err = (ret == BLKPREP_INVALID) ? -EREMOTEIO : -EIO;
+
                        rq->cmd_flags |= REQ_QUIET;
                        /*
                         * Mark this request as started so we don't trigger
                         * any debug logic in the end I/O path.
                         */
                        blk_start_request(rq);
-                       __blk_end_request_all(rq, -EIO);
+                       __blk_end_request_all(rq, err);
                } else {
                        printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
                        break;
index f565e11f465aa145120973bce58ef7ecc192f349..a54f0543b956e5ccf5f20206e7983fe66ce2698d 100644 (file)
@@ -57,6 +57,49 @@ static int __blk_rq_unmap_user(struct bio *bio)
        return ret;
 }
 
+static int __blk_rq_map_user_iov(struct request *rq,
+               struct rq_map_data *map_data, struct iov_iter *iter,
+               gfp_t gfp_mask, bool copy)
+{
+       struct request_queue *q = rq->q;
+       struct bio *bio, *orig_bio;
+       int ret;
+
+       if (copy)
+               bio = bio_copy_user_iov(q, map_data, iter, gfp_mask);
+       else
+               bio = bio_map_user_iov(q, iter, gfp_mask);
+
+       if (IS_ERR(bio))
+               return PTR_ERR(bio);
+
+       if (map_data && map_data->null_mapped)
+               bio_set_flag(bio, BIO_NULL_MAPPED);
+
+       iov_iter_advance(iter, bio->bi_iter.bi_size);
+       if (map_data)
+               map_data->offset += bio->bi_iter.bi_size;
+
+       orig_bio = bio;
+       blk_queue_bounce(q, &bio);
+
+       /*
+        * We link the bounce buffer in and could have to traverse it
+        * later so we have to get a ref to prevent it from being freed
+        */
+       bio_get(bio);
+
+       ret = blk_rq_append_bio(q, rq, bio);
+       if (ret) {
+               bio_endio(bio);
+               __blk_rq_unmap_user(orig_bio);
+               bio_put(bio);
+               return ret;
+       }
+
+       return 0;
+}
+
 /**
  * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage
  * @q:         request queue where request should be inserted
@@ -82,10 +125,11 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                        struct rq_map_data *map_data,
                        const struct iov_iter *iter, gfp_t gfp_mask)
 {
-       struct bio *bio;
-       int unaligned = 0;
-       struct iov_iter i;
        struct iovec iov, prv = {.iov_base = NULL, .iov_len = 0};
+       bool copy = (q->dma_pad_mask & iter->count) || map_data;
+       struct bio *bio = NULL;
+       struct iov_iter i;
+       int ret;
 
        if (!iter || !iter->count)
                return -EINVAL;
@@ -101,42 +145,29 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                 */
                if ((uaddr & queue_dma_alignment(q)) ||
                    iovec_gap_to_prv(q, &prv, &iov))
-                       unaligned = 1;
+                       copy = true;
 
                prv.iov_base = iov.iov_base;
                prv.iov_len = iov.iov_len;
        }
 
-       if (unaligned || (q->dma_pad_mask & iter->count) || map_data)
-               bio = bio_copy_user_iov(q, map_data, iter, gfp_mask);
-       else
-               bio = bio_map_user_iov(q, iter, gfp_mask);
-
-       if (IS_ERR(bio))
-               return PTR_ERR(bio);
-
-       if (map_data && map_data->null_mapped)
-               bio_set_flag(bio, BIO_NULL_MAPPED);
-
-       if (bio->bi_iter.bi_size != iter->count) {
-               /*
-                * Grab an extra reference to this bio, as bio_unmap_user()
-                * expects to be able to drop it twice as it happens on the
-                * normal IO completion path
-                */
-               bio_get(bio);
-               bio_endio(bio);
-               __blk_rq_unmap_user(bio);
-               return -EINVAL;
-       }
+       i = *iter;
+       do {
+               ret =__blk_rq_map_user_iov(rq, map_data, &i, gfp_mask, copy);
+               if (ret)
+                       goto unmap_rq;
+               if (!bio)
+                       bio = rq->bio;
+       } while (iov_iter_count(&i));
 
        if (!bio_flagged(bio, BIO_USER_MAPPED))
                rq->cmd_flags |= REQ_COPY_USER;
-
-       blk_queue_bounce(q, &bio);
-       bio_get(bio);
-       blk_rq_bio_prep(q, rq, bio);
        return 0;
+
+unmap_rq:
+       __blk_rq_unmap_user(bio);
+       rq->bio = NULL;
+       return -EINVAL;
 }
 EXPORT_SYMBOL(blk_rq_map_user_iov);
 
index 888a7fec81f715199c3050576516e55b692f2b9b..261353166dcf33a042ea4466ecae044388dddc98 100644 (file)
@@ -304,7 +304,6 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
                                   struct bio *nxt)
 {
        struct bio_vec end_bv = { NULL }, nxt_bv;
-       struct bvec_iter iter;
 
        if (!blk_queue_cluster(q))
                return 0;
@@ -316,11 +315,8 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
        if (!bio_has_data(bio))
                return 1;
 
-       bio_for_each_segment(end_bv, bio, iter)
-               if (end_bv.bv_len == iter.bi_size)
-                       break;
-
-       nxt_bv = bio_iovec(nxt);
+       bio_get_last_bvec(bio, &end_bv);
+       bio_get_first_bvec(nxt, &nxt_bv);
 
        if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv))
                return 0;
index 4c0622fae41383d0f5577ea9b8b127d93df33bb6..56c0a726b619374ec9f8cf4b60649a14919f0625 100644 (file)
@@ -599,8 +599,10 @@ static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx,
                 * If a request wasn't started before the queue was
                 * marked dying, kill it here or it'll go unnoticed.
                 */
-               if (unlikely(blk_queue_dying(rq->q)))
-                       blk_mq_complete_request(rq, -EIO);
+               if (unlikely(blk_queue_dying(rq->q))) {
+                       rq->errors = -EIO;
+                       blk_mq_end_request(rq, rq->errors);
+               }
                return;
        }
 
index dd49735839789167d427dc8b64da71c6b21f08f5..c7bb666aafd100a329c67b97e616c9f9037c508e 100644 (file)
@@ -91,8 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
        lim->virt_boundary_mask = 0;
        lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
-       lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors =
-               BLK_SAFE_MAX_SECTORS;
+       lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+       lim->max_dev_sectors = 0;
        lim->chunk_sectors = 0;
        lim->max_write_same_sectors = 0;
        lim->max_discard_sectors = 0;
index e140cc487ce11349ff1917e4e866eccf0a18106c..dd93763057ce0187dcc1b81602b75a43310d451d 100644 (file)
@@ -147,10 +147,9 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
 
 static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page)
 {
-       unsigned long long val;
 
-       val = q->limits.max_hw_discard_sectors << 9;
-       return sprintf(page, "%llu\n", val);
+       return sprintf(page, "%llu\n",
+               (unsigned long long)q->limits.max_hw_discard_sectors << 9);
 }
 
 static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
index a753df2b3fc29324a850442966b15199bc932508..d0dd7882d8c7fa7ffe80ea2e9a6ad3c0f5e97a68 100644 (file)
@@ -39,7 +39,6 @@ struct deadline_data {
         */
        struct request *next_rq[2];
        unsigned int batching;          /* number of sequential requests made */
-       sector_t last_sector;           /* head position */
        unsigned int starved;           /* times reads have starved writes */
 
        /*
@@ -210,8 +209,6 @@ deadline_move_request(struct deadline_data *dd, struct request *rq)
        dd->next_rq[WRITE] = NULL;
        dd->next_rq[data_dir] = deadline_latter_request(rq);
 
-       dd->last_sector = rq_end_sector(rq);
-
        /*
         * take it off the sort and fifo list, move
         * to dispatch queue
index 38c1aa89d3a0a7c4448bcd094ca1f268b9156a2d..28556fce42671e2f182d5239d3dc6468e5b1d970 100644 (file)
@@ -65,18 +65,10 @@ struct skcipher_async_req {
        struct skcipher_async_rsgl first_sgl;
        struct list_head list;
        struct scatterlist *tsg;
-       char iv[];
+       atomic_t *inflight;
+       struct skcipher_request req;
 };
 
-#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \
-       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)))
-
-#define GET_REQ_SIZE(ctx) \
-       crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))
-
-#define GET_IV_SIZE(ctx) \
-       crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req))
-
 #define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \
                      sizeof(struct scatterlist) - 1)
 
@@ -102,15 +94,12 @@ static void skcipher_free_async_sgls(struct skcipher_async_req *sreq)
 
 static void skcipher_async_cb(struct crypto_async_request *req, int err)
 {
-       struct sock *sk = req->data;
-       struct alg_sock *ask = alg_sk(sk);
-       struct skcipher_ctx *ctx = ask->private;
-       struct skcipher_async_req *sreq = GET_SREQ(req, ctx);
+       struct skcipher_async_req *sreq = req->data;
        struct kiocb *iocb = sreq->iocb;
 
-       atomic_dec(&ctx->inflight);
+       atomic_dec(sreq->inflight);
        skcipher_free_async_sgls(sreq);
-       kfree(req);
+       kzfree(sreq);
        iocb->ki_complete(iocb, err, err);
 }
 
@@ -306,8 +295,11 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
+       struct sock *psk = ask->parent;
+       struct alg_sock *pask = alg_sk(psk);
        struct skcipher_ctx *ctx = ask->private;
-       struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
+       struct skcipher_tfm *skc = pask->private;
+       struct crypto_skcipher *tfm = skc->skcipher;
        unsigned ivsize = crypto_skcipher_ivsize(tfm);
        struct skcipher_sg_list *sgl;
        struct af_alg_control con = {};
@@ -509,37 +501,43 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
+       struct sock *psk = ask->parent;
+       struct alg_sock *pask = alg_sk(psk);
        struct skcipher_ctx *ctx = ask->private;
+       struct skcipher_tfm *skc = pask->private;
+       struct crypto_skcipher *tfm = skc->skcipher;
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
        struct skcipher_async_req *sreq;
        struct skcipher_request *req;
        struct skcipher_async_rsgl *last_rsgl = NULL;
-       unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx);
-       unsigned int reqlen = sizeof(struct skcipher_async_req) +
-                               GET_REQ_SIZE(ctx) + GET_IV_SIZE(ctx);
+       unsigned int txbufs = 0, len = 0, tx_nents;
+       unsigned int reqsize = crypto_skcipher_reqsize(tfm);
+       unsigned int ivsize = crypto_skcipher_ivsize(tfm);
        int err = -ENOMEM;
        bool mark = false;
+       char *iv;
 
-       lock_sock(sk);
-       req = kmalloc(reqlen, GFP_KERNEL);
-       if (unlikely(!req))
-               goto unlock;
+       sreq = kzalloc(sizeof(*sreq) + reqsize + ivsize, GFP_KERNEL);
+       if (unlikely(!sreq))
+               goto out;
 
-       sreq = GET_SREQ(req, ctx);
+       req = &sreq->req;
+       iv = (char *)(req + 1) + reqsize;
        sreq->iocb = msg->msg_iocb;
-       memset(&sreq->first_sgl, '\0', sizeof(struct skcipher_async_rsgl));
        INIT_LIST_HEAD(&sreq->list);
+       sreq->inflight = &ctx->inflight;
+
+       lock_sock(sk);
+       tx_nents = skcipher_all_sg_nents(ctx);
        sreq->tsg = kcalloc(tx_nents, sizeof(*sg), GFP_KERNEL);
-       if (unlikely(!sreq->tsg)) {
-               kfree(req);
+       if (unlikely(!sreq->tsg))
                goto unlock;
-       }
        sg_init_table(sreq->tsg, tx_nents);
-       memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx));
-       skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req));
-       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-                                     skcipher_async_cb, sk);
+       memcpy(iv, ctx->iv, ivsize);
+       skcipher_request_set_tfm(req, tfm);
+       skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
+                                     skcipher_async_cb, sreq);
 
        while (iov_iter_count(&msg->msg_iter)) {
                struct skcipher_async_rsgl *rsgl;
@@ -615,20 +613,22 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
                sg_mark_end(sreq->tsg + txbufs - 1);
 
        skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
-                                  len, sreq->iv);
+                                  len, iv);
        err = ctx->enc ? crypto_skcipher_encrypt(req) :
                         crypto_skcipher_decrypt(req);
        if (err == -EINPROGRESS) {
                atomic_inc(&ctx->inflight);
                err = -EIOCBQUEUED;
+               sreq = NULL;
                goto unlock;
        }
 free:
        skcipher_free_async_sgls(sreq);
-       kfree(req);
 unlock:
        skcipher_wmem_wakeup(sk);
        release_sock(sk);
+       kzfree(sreq);
+out:
        return err;
 }
 
@@ -637,9 +637,12 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
        struct alg_sock *ask = alg_sk(sk);
+       struct sock *psk = ask->parent;
+       struct alg_sock *pask = alg_sk(psk);
        struct skcipher_ctx *ctx = ask->private;
-       unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm(
-               &ctx->req));
+       struct skcipher_tfm *skc = pask->private;
+       struct crypto_skcipher *tfm = skc->skcipher;
+       unsigned bs = crypto_skcipher_blocksize(tfm);
        struct skcipher_sg_list *sgl;
        struct scatterlist *sg;
        int err = -EAGAIN;
@@ -947,7 +950,8 @@ static int skcipher_accept_parent_nokey(void *private, struct sock *sk)
        ask->private = ctx;
 
        skcipher_request_set_tfm(&ctx->req, skcipher);
-       skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+       skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_SLEEP |
+                                                CRYPTO_TFM_REQ_MAY_BACKLOG,
                                      af_alg_complete, &ctx->completion);
 
        sk->sk_destruct = skcipher_sock_destruct;
index 237f3795cfaaa1f988fadf5b07eefe3c44609091..43fe85f20d577b4f3d1bbd6576b6d752bc578531 100644 (file)
@@ -499,6 +499,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (link->dump == NULL)
                        return -EINVAL;
 
+               down_read(&crypto_alg_sem);
                list_for_each_entry(alg, &crypto_alg_list, cra_list)
                        dump_alloc += CRYPTO_REPORT_MAXSIZE;
 
@@ -508,8 +509,11 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                .done = link->done,
                                .min_dump_alloc = dump_alloc,
                        };
-                       return netlink_dump_start(crypto_nlsk, skb, nlh, &c);
+                       err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
                }
+               up_read(&crypto_alg_sem);
+
+               return err;
        }
 
        err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
index c570b1d9f09480ecec5513d3cfe61d33c26c81b5..0872d5fecb82f2dee893c7feb0ac6a408f903384 100644 (file)
@@ -880,7 +880,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
                break;
        case BUS_NOTIFY_DRIVER_NOT_BOUND:
        case BUS_NOTIFY_UNBOUND_DRIVER:
-               pdev->dev.pm_domain = NULL;
+               dev_pm_domain_set(&pdev->dev, NULL);
                break;
        case BUS_NOTIFY_ADD_DEVICE:
                dev_pm_domain_set(&pdev->dev, &acpi_lpss_pm_domain);
index ad6d8c6b777e7c83885cc3f854396808153653f3..35947ac8764459ab0cea484d66bb3f7e7589dc82 100644 (file)
@@ -469,37 +469,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc,
        nfit_mem->bdw = NULL;
 }
 
-static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
+static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc,
                struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa)
 {
        u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
        struct nfit_memdev *nfit_memdev;
        struct nfit_flush *nfit_flush;
-       struct nfit_dcr *nfit_dcr;
        struct nfit_bdw *nfit_bdw;
        struct nfit_idt *nfit_idt;
        u16 idt_idx, range_index;
 
-       list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
-               if (nfit_dcr->dcr->region_index != dcr)
-                       continue;
-               nfit_mem->dcr = nfit_dcr->dcr;
-               break;
-       }
-
-       if (!nfit_mem->dcr) {
-               dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n",
-                               spa->range_index, __to_nfit_memdev(nfit_mem)
-                               ? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR");
-               return -ENODEV;
-       }
-
-       /*
-        * We've found enough to create an nvdimm, optionally
-        * find an associated BDW
-        */
-       list_add(&nfit_mem->list, &acpi_desc->dimms);
-
        list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) {
                if (nfit_bdw->bdw->region_index != dcr)
                        continue;
@@ -508,12 +487,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
        }
 
        if (!nfit_mem->bdw)
-               return 0;
+               return;
 
        nfit_mem_find_spa_bdw(acpi_desc, nfit_mem);
 
        if (!nfit_mem->spa_bdw)
-               return 0;
+               return;
 
        range_index = nfit_mem->spa_bdw->range_index;
        list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
@@ -538,8 +517,6 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
                }
                break;
        }
-
-       return 0;
 }
 
 static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
@@ -548,7 +525,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
        struct nfit_mem *nfit_mem, *found;
        struct nfit_memdev *nfit_memdev;
        int type = nfit_spa_type(spa);
-       u16 dcr;
 
        switch (type) {
        case NFIT_SPA_DCR:
@@ -559,14 +535,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
        }
 
        list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
-               int rc;
+               struct nfit_dcr *nfit_dcr;
+               u32 device_handle;
+               u16 dcr;
 
                if (nfit_memdev->memdev->range_index != spa->range_index)
                        continue;
                found = NULL;
                dcr = nfit_memdev->memdev->region_index;
+               device_handle = nfit_memdev->memdev->device_handle;
                list_for_each_entry(nfit_mem, &acpi_desc->dimms, list)
-                       if (__to_nfit_memdev(nfit_mem)->region_index == dcr) {
+                       if (__to_nfit_memdev(nfit_mem)->device_handle
+                                       == device_handle) {
                                found = nfit_mem;
                                break;
                        }
@@ -579,6 +559,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
                        if (!nfit_mem)
                                return -ENOMEM;
                        INIT_LIST_HEAD(&nfit_mem->list);
+                       list_add(&nfit_mem->list, &acpi_desc->dimms);
+               }
+
+               list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) {
+                       if (nfit_dcr->dcr->region_index != dcr)
+                               continue;
+                       /*
+                        * Record the control region for the dimm.  For
+                        * the ACPI 6.1 case, where there are separate
+                        * control regions for the pmem vs blk
+                        * interfaces, be sure to record the extended
+                        * blk details.
+                        */
+                       if (!nfit_mem->dcr)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       else if (nfit_mem->dcr->windows == 0
+                                       && nfit_dcr->dcr->windows)
+                               nfit_mem->dcr = nfit_dcr->dcr;
+                       break;
+               }
+
+               if (dcr && !nfit_mem->dcr) {
+                       dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n",
+                                       spa->range_index, dcr);
+                       return -ENODEV;
                }
 
                if (type == NFIT_SPA_DCR) {
@@ -595,6 +600,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
                                nfit_mem->idt_dcr = nfit_idt->idt;
                                break;
                        }
+                       nfit_mem_init_bdw(acpi_desc, nfit_mem, spa);
                } else {
                        /*
                         * A single dimm may belong to multiple SPA-PM
@@ -603,13 +609,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc,
                         */
                        nfit_mem->memdev_pmem = nfit_memdev->memdev;
                }
-
-               if (found)
-                       continue;
-
-               rc = nfit_mem_add(acpi_desc, nfit_mem, spa);
-               if (rc)
-                       return rc;
        }
 
        return 0;
@@ -1504,9 +1503,7 @@ static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
                case 1:
                        /* ARS unsupported, but we should never get here */
                        return 0;
-               case 2:
-                       return -EINVAL;
-               case 3:
+               case 6:
                        /* ARS is in progress */
                        msleep(1000);
                        break;
@@ -1517,13 +1514,13 @@ static int ars_do_start(struct nvdimm_bus_descriptor *nd_desc,
 }
 
 static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
-               struct nd_cmd_ars_status *cmd)
+               struct nd_cmd_ars_status *cmd, u32 size)
 {
        int rc;
 
        while (1) {
                rc = nd_desc->ndctl(nd_desc, NULL, ND_CMD_ARS_STATUS, cmd,
-                       sizeof(*cmd));
+                       size);
                if (rc || cmd->status & 0xffff)
                        return -ENXIO;
 
@@ -1538,6 +1535,8 @@ static int ars_get_status(struct nvdimm_bus_descriptor *nd_desc,
                case 2:
                        /* No ARS performed for the current boot */
                        return 0;
+               case 3:
+                       /* TODO: error list overflow support */
                default:
                        return -ENXIO;
                }
@@ -1581,6 +1580,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
        struct nd_cmd_ars_start *ars_start = NULL;
        struct nd_cmd_ars_cap *ars_cap = NULL;
        u64 start, len, cur, remaining;
+       u32 ars_status_size;
        int rc;
 
        ars_cap = kzalloc(sizeof(*ars_cap), GFP_KERNEL);
@@ -1590,14 +1590,21 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
        start = ndr_desc->res->start;
        len = ndr_desc->res->end - ndr_desc->res->start + 1;
 
+       /*
+        * If ARS is unimplemented, unsupported, or if the 'Persistent Memory
+        * Scrub' flag in extended status is not set, skip this but continue
+        * initialization
+        */
        rc = ars_get_cap(nd_desc, ars_cap, start, len);
+       if (rc == -ENOTTY) {
+               dev_dbg(acpi_desc->dev,
+                       "Address Range Scrub is not implemented, won't create an error list\n");
+               rc = 0;
+               goto out;
+       }
        if (rc)
                goto out;
 
-       /*
-        * If ARS is unsupported, or if the 'Persistent Memory Scrub' flag in
-        * extended status is not set, skip this but continue initialization
-        */
        if ((ars_cap->status & 0xffff) ||
                !(ars_cap->status >> 16 & ND_ARS_PERSISTENT)) {
                dev_warn(acpi_desc->dev,
@@ -1610,14 +1617,14 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
         * Check if a full-range ARS has been run. If so, use those results
         * without having to start a new ARS.
         */
-       ars_status = kzalloc(ars_cap->max_ars_out + sizeof(*ars_status),
-                       GFP_KERNEL);
+       ars_status_size = ars_cap->max_ars_out;
+       ars_status = kzalloc(ars_status_size, GFP_KERNEL);
        if (!ars_status) {
                rc = -ENOMEM;
                goto out;
        }
 
-       rc = ars_get_status(nd_desc, ars_status);
+       rc = ars_get_status(nd_desc, ars_status, ars_status_size);
        if (rc)
                goto out;
 
@@ -1647,7 +1654,7 @@ static int acpi_nfit_find_poison(struct acpi_nfit_desc *acpi_desc,
                if (rc)
                        goto out;
 
-               rc = ars_get_status(nd_desc, ars_status);
+               rc = ars_get_status(nd_desc, ars_status, ars_status_size);
                if (rc)
                        goto out;
 
index d30184c7f3bcb851c62fe410906160b6e802a631..c8e169e46673ae253882872cda7a94249540c3a5 100644 (file)
@@ -406,7 +406,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                return 0;
        }
 
-       if (pci_has_managed_irq(dev))
+       if (dev->irq_managed && dev->irq > 0)
                return 0;
 
        entry = acpi_pci_irq_lookup(dev, pin);
@@ -451,7 +451,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                kfree(entry);
                return rc;
        }
-       pci_set_managed_irq(dev, rc);
+       dev->irq = rc;
+       dev->irq_managed = 1;
 
        if (link)
                snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link);
@@ -474,9 +475,17 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        u8 pin;
 
        pin = dev->pin;
-       if (!pin || !pci_has_managed_irq(dev))
+       if (!pin || !dev->irq_managed || dev->irq <= 0)
                return;
 
+       /* Keep IOAPIC pin configuration when suspending */
+       if (dev->dev.power.is_prepared)
+               return;
+#ifdef CONFIG_PM
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
                return;
@@ -496,6 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
-               pci_reset_managed_irq(dev);
+               dev->irq_managed = 0;
        }
 }
index fa2863567eed3c944c884245118c0d55d5ec5fdd..ededa909df2fc02eb2b77fb495e43f8e850c5469 100644 (file)
@@ -4,7 +4,6 @@
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
  *  Copyright (C) 2002       Dominik Brodowski <devel@brodo.de>
- *  Copyright (c) 2015, The Linux Foundation. All rights reserved.
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -438,6 +437,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
  * enabled system.
  */
 
+#define ACPI_MAX_IRQS          256
 #define ACPI_MAX_ISA_IRQ       16
 
 #define PIRQ_PENALTY_PCI_AVAILABLE     (0)
@@ -447,7 +447,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
 #define PIRQ_PENALTY_ISA_USED          (16*16*16*16*16)
 #define PIRQ_PENALTY_ISA_ALWAYS                (16*16*16*16*16*16)
 
-static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = {
+static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ0 timer */
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ1 keyboard */
        PIRQ_PENALTY_ISA_ALWAYS,        /* IRQ2 cascade */
@@ -464,68 +464,9 @@ static int acpi_irq_isa_penalty[ACPI_MAX_ISA_IRQ] = {
        PIRQ_PENALTY_ISA_USED,          /* IRQ13 fpe, sometimes */
        PIRQ_PENALTY_ISA_USED,          /* IRQ14 ide0 */
        PIRQ_PENALTY_ISA_USED,          /* IRQ15 ide1 */
+       /* >IRQ15 */
 };
 
-struct irq_penalty_info {
-       int irq;
-       int penalty;
-       struct list_head node;
-};
-
-static LIST_HEAD(acpi_irq_penalty_list);
-
-static int acpi_irq_get_penalty(int irq)
-{
-       struct irq_penalty_info *irq_info;
-
-       if (irq < ACPI_MAX_ISA_IRQ)
-               return acpi_irq_isa_penalty[irq];
-
-       list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
-               if (irq_info->irq == irq)
-                       return irq_info->penalty;
-       }
-
-       return 0;
-}
-
-static int acpi_irq_set_penalty(int irq, int new_penalty)
-{
-       struct irq_penalty_info *irq_info;
-
-       /* see if this is a ISA IRQ */
-       if (irq < ACPI_MAX_ISA_IRQ) {
-               acpi_irq_isa_penalty[irq] = new_penalty;
-               return 0;
-       }
-
-       /* next, try to locate from the dynamic list */
-       list_for_each_entry(irq_info, &acpi_irq_penalty_list, node) {
-               if (irq_info->irq == irq) {
-                       irq_info->penalty  = new_penalty;
-                       return 0;
-               }
-       }
-
-       /* nope, let's allocate a slot for this IRQ */
-       irq_info = kzalloc(sizeof(*irq_info), GFP_KERNEL);
-       if (!irq_info)
-               return -ENOMEM;
-
-       irq_info->irq = irq;
-       irq_info->penalty = new_penalty;
-       list_add_tail(&irq_info->node, &acpi_irq_penalty_list);
-
-       return 0;
-}
-
-static void acpi_irq_add_penalty(int irq, int penalty)
-{
-       int curpen = acpi_irq_get_penalty(irq);
-
-       acpi_irq_set_penalty(irq, curpen + penalty);
-}
-
 int __init acpi_irq_penalty_init(void)
 {
        struct acpi_pci_link *link;
@@ -546,16 +487,15 @@ int __init acpi_irq_penalty_init(void)
                            link->irq.possible_count;
 
                        for (i = 0; i < link->irq.possible_count; i++) {
-                               if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) {
-                                       int irqpos = link->irq.possible[i];
-
-                                       acpi_irq_add_penalty(irqpos, penalty);
-                               }
+                               if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
+                                       acpi_irq_penalty[link->irq.
+                                                        possible[i]] +=
+                                           penalty;
                        }
 
                } else if (link->irq.active) {
-                       acpi_irq_add_penalty(link->irq.active,
-                                            PIRQ_PENALTY_PCI_POSSIBLE);
+                       acpi_irq_penalty[link->irq.active] +=
+                           PIRQ_PENALTY_PCI_POSSIBLE;
                }
        }
 
@@ -607,12 +547,12 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
                 * the use of IRQs 9, 10, 11, and >15.
                 */
                for (i = (link->irq.possible_count - 1); i >= 0; i--) {
-                       if (acpi_irq_get_penalty(irq) >
-                           acpi_irq_get_penalty(link->irq.possible[i]))
+                       if (acpi_irq_penalty[irq] >
+                           acpi_irq_penalty[link->irq.possible[i]])
                                irq = link->irq.possible[i];
                }
        }
-       if (acpi_irq_get_penalty(irq) >= PIRQ_PENALTY_ISA_ALWAYS) {
+       if (acpi_irq_penalty[irq] >= PIRQ_PENALTY_ISA_ALWAYS) {
                printk(KERN_ERR PREFIX "No IRQ available for %s [%s]. "
                            "Try pci=noacpi or acpi=off\n",
                            acpi_device_name(link->device),
@@ -628,8 +568,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
                            acpi_device_bid(link->device));
                return -ENODEV;
        } else {
-               acpi_irq_add_penalty(link->irq.active, PIRQ_PENALTY_PCI_USING);
-
+               acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
                printk(KERN_WARNING PREFIX "%s [%s] enabled at IRQ %d\n",
                       acpi_device_name(link->device),
                       acpi_device_bid(link->device), link->irq.active);
@@ -839,7 +778,7 @@ static void acpi_pci_link_remove(struct acpi_device *device)
 }
 
 /*
- * modify penalty from cmdline
+ * modify acpi_irq_penalty[] from cmdline
  */
 static int __init acpi_irq_penalty_update(char *str, int used)
 {
@@ -857,10 +796,13 @@ static int __init acpi_irq_penalty_update(char *str, int used)
                if (irq < 0)
                        continue;
 
+               if (irq >= ARRAY_SIZE(acpi_irq_penalty))
+                       continue;
+
                if (used)
-                       acpi_irq_add_penalty(irq, PIRQ_PENALTY_ISA_USED);
+                       acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
                else
-                       acpi_irq_set_penalty(irq, PIRQ_PENALTY_PCI_AVAILABLE);
+                       acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
 
                if (retval != 2)        /* no next number */
                        break;
@@ -877,15 +819,18 @@ static int __init acpi_irq_penalty_update(char *str, int used)
  */
 void acpi_penalize_isa_irq(int irq, int active)
 {
-       if (irq >= 0)
-               acpi_irq_add_penalty(irq, active ?
-                       PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING);
+       if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
+               if (active)
+                       acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
+               else
+                       acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+       }
 }
 
 bool acpi_isa_irq_available(int irq)
 {
-       return irq >= 0 &&
-               (acpi_irq_get_penalty(irq) < PIRQ_PENALTY_ISA_ALWAYS);
+       return irq >= 0 && (irq >= ARRAY_SIZE(acpi_irq_penalty) ||
+                           acpi_irq_penalty[irq] < PIRQ_PENALTY_ISA_ALWAYS);
 }
 
 /*
@@ -895,18 +840,13 @@ bool acpi_isa_irq_available(int irq)
  */
 void acpi_penalize_sci_irq(int irq, int trigger, int polarity)
 {
-       int penalty;
-
-       if (irq < 0)
-               return;
-
-       if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
-           polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
-               penalty = PIRQ_PENALTY_ISA_ALWAYS;
-       else
-               penalty = PIRQ_PENALTY_PCI_USING;
-
-       acpi_irq_add_penalty(irq, penalty);
+       if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) {
+               if (trigger != ACPI_MADT_TRIGGER_LEVEL ||
+                   polarity != ACPI_MADT_POLARITY_ACTIVE_LOW)
+                       acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS;
+               else
+                       acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+       }
 }
 
 /*
index a39e85f9efa98854768f39b01502274401673957..7d00b7a015ead0182feaace6231a8d7fad719b64 100644 (file)
@@ -2074,7 +2074,7 @@ static int binder_thread_write(struct binder_proc *proc,
                        if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                                return -EFAULT;
 
-                       ptr += sizeof(void *);
+                       ptr += sizeof(cookie);
                        list_for_each_entry(w, &proc->delivered_death, entry) {
                                struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
 
index 594fcabd22cd16bfcc09626338a3da33481497cc..146dc0b8ec61752c03278cf5121061aaaf4c27ce 100644 (file)
@@ -264,6 +264,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
        { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
+       { PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
        { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
        { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
        { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
@@ -347,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/
        { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
        { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
        { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
+       { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1305,6 +1331,44 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
 {}
 #endif
 
+#ifdef CONFIG_ARM64
+/*
+ * Due to ERRATA#22536, ThunderX needs to handle HOST_IRQ_STAT differently.
+ * Workaround is to make sure all pending IRQs are served before leaving
+ * handler.
+ */
+static irqreturn_t ahci_thunderx_irq_handler(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       struct ahci_host_priv *hpriv;
+       unsigned int rc = 0;
+       void __iomem *mmio;
+       u32 irq_stat, irq_masked;
+       unsigned int handled = 1;
+
+       VPRINTK("ENTER\n");
+       hpriv = host->private_data;
+       mmio = hpriv->mmio;
+       irq_stat = readl(mmio + HOST_IRQ_STAT);
+       if (!irq_stat)
+               return IRQ_NONE;
+
+       do {
+               irq_masked = irq_stat & hpriv->port_map;
+               spin_lock(&host->lock);
+               rc = ahci_handle_port_intr(host, irq_masked);
+               if (!rc)
+                       handled = 0;
+               writel(irq_stat, mmio + HOST_IRQ_STAT);
+               irq_stat = readl(mmio + HOST_IRQ_STAT);
+               spin_unlock(&host->lock);
+       } while (irq_stat);
+       VPRINTK("EXIT\n");
+
+       return IRQ_RETVAL(handled);
+}
+#endif
+
 /*
  * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
  * to single msi.
@@ -1540,6 +1604,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ahci_broken_devslp(pdev))
                hpriv->flags |= AHCI_HFLAG_NO_DEVSLP;
 
+#ifdef CONFIG_ARM64
+       if (pdev->vendor == 0x177d && pdev->device == 0xa01c)
+               hpriv->irq_handler = ahci_thunderx_irq_handler;
+#endif
+
        /* save initial config */
        ahci_pci_save_initial_config(pdev, hpriv);
 
index a4faa438889c075070084fb1f1cd943d61082a88..167ba7e3b92e8fcec115ddcbd1988326e7c67ba5 100644 (file)
@@ -240,8 +240,7 @@ enum {
                                                        error-handling stage) */
        AHCI_HFLAG_NO_DEVSLP            = (1 << 17), /* no device sleep */
        AHCI_HFLAG_NO_FBS               = (1 << 18), /* no FBS */
-       AHCI_HFLAG_EDGE_IRQ             = (1 << 19), /* HOST_IRQ_STAT behaves as
-                                                       Edge Triggered */
+
 #ifdef CONFIG_PCI_MSI
        AHCI_HFLAG_MULTI_MSI            = (1 << 20), /* multiple PCI MSIs */
        AHCI_HFLAG_MULTI_MSIX           = (1 << 21), /* per-port MSI-X */
@@ -250,6 +249,7 @@ enum {
        AHCI_HFLAG_MULTI_MSI            = 0,
        AHCI_HFLAG_MULTI_MSIX           = 0,
 #endif
+       AHCI_HFLAG_WAKE_BEFORE_STOP     = (1 << 22), /* wake before DMA stop */
 
        /* ap->flags bits */
 
@@ -360,6 +360,7 @@ struct ahci_host_priv {
         * be overridden anytime before the host is activated.
         */
        void                    (*start_engine)(struct ata_port *ap);
+       irqreturn_t             (*irq_handler)(int irq, void *dev_instance);
 };
 
 #ifdef CONFIG_PCI_MSI
@@ -423,6 +424,7 @@ int ahci_reset_em(struct ata_host *host);
 void ahci_print_info(struct ata_host *host, const char *scc_s);
 int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht);
 void ahci_error_handler(struct ata_port *ap);
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked);
 
 static inline void __iomem *__ahci_port_base(struct ata_host *host,
                                             unsigned int port_no)
index b36cae2fd04b2b2969cfefcfe54f63beadef48e2..e87bcec0fd7c31d9623e54cf84fa6c62b41f2f39 100644 (file)
@@ -317,6 +317,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
        if (IS_ERR(hpriv))
                return PTR_ERR(hpriv);
        hpriv->plat_data = priv;
+       hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
 
        brcm_sata_alpm_init(hpriv);
 
index e2c6d9e0c5ac5ce5ce389b0ae1b0597ae979ee8b..8e3f7faf00d383f8eea284fe122e90a44ee7ce40 100644 (file)
@@ -548,6 +548,88 @@ softreset_retry:
        return rc;
 }
 
+/**
+ * xgene_ahci_handle_broken_edge_irq - Handle the broken irq.
+ * @ata_host: Host that recieved the irq
+ * @irq_masked: HOST_IRQ_STAT value
+ *
+ * For hardware with broken edge trigger latch
+ * the HOST_IRQ_STAT register misses the edge interrupt
+ * when clearing of HOST_IRQ_STAT register and hardware
+ * reporting the PORT_IRQ_STAT register at the
+ * same clock cycle.
+ * As such, the algorithm below outlines the workaround.
+ *
+ * 1. Read HOST_IRQ_STAT register and save the state.
+ * 2. Clear the HOST_IRQ_STAT register.
+ * 3. Read back the HOST_IRQ_STAT register.
+ * 4. If HOST_IRQ_STAT register equals to zero, then
+ *    traverse the rest of port's PORT_IRQ_STAT register
+ *    to check if an interrupt is triggered at that point else
+ *    go to step 6.
+ * 5. If PORT_IRQ_STAT register of rest ports is not equal to zero
+ *    then update the state of HOST_IRQ_STAT saved in step 1.
+ * 6. Handle port interrupts.
+ * 7. Exit
+ */
+static int xgene_ahci_handle_broken_edge_irq(struct ata_host *host,
+                                            u32 irq_masked)
+{
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *port_mmio;
+       int i;
+
+       if (!readl(hpriv->mmio + HOST_IRQ_STAT)) {
+               for (i = 0; i < host->n_ports; i++) {
+                       if (irq_masked & (1 << i))
+                               continue;
+
+                       port_mmio = ahci_port_base(host->ports[i]);
+                       if (readl(port_mmio + PORT_IRQ_STAT))
+                               irq_masked |= (1 << i);
+               }
+       }
+
+       return ahci_handle_port_intr(host, irq_masked);
+}
+
+static irqreturn_t xgene_ahci_irq_intr(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       struct ahci_host_priv *hpriv;
+       unsigned int rc = 0;
+       void __iomem *mmio;
+       u32 irq_stat, irq_masked;
+
+       VPRINTK("ENTER\n");
+
+       hpriv = host->private_data;
+       mmio = hpriv->mmio;
+
+       /* sigh.  0xffffffff is a valid return from h/w */
+       irq_stat = readl(mmio + HOST_IRQ_STAT);
+       if (!irq_stat)
+               return IRQ_NONE;
+
+       irq_masked = irq_stat & hpriv->port_map;
+
+       spin_lock(&host->lock);
+
+       /*
+        * HOST_IRQ_STAT behaves as edge triggered latch meaning that
+        * it should be cleared before all the port events are cleared.
+        */
+       writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+       rc = xgene_ahci_handle_broken_edge_irq(host, irq_masked);
+
+       spin_unlock(&host->lock);
+
+       VPRINTK("EXIT\n");
+
+       return IRQ_RETVAL(rc);
+}
+
 static struct ata_port_operations xgene_ahci_v1_ops = {
        .inherits = &ahci_ops,
        .host_stop = xgene_ahci_host_stop,
@@ -779,7 +861,8 @@ skip_clk_phy:
                hpriv->flags = AHCI_HFLAG_NO_NCQ;
                break;
        case XGENE_AHCI_V2:
-               hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
+               hpriv->flags |= AHCI_HFLAG_YES_FBS;
+               hpriv->irq_handler = xgene_ahci_irq_intr;
                break;
        default:
                break;
index d61740e78d6dc93a1b17d9e3c9d9425067190a21..85ea5142a09518acc9e5c781fffbbf737f262f31 100644 (file)
@@ -113,6 +113,7 @@ static ssize_t ahci_store_em_buffer(struct device *dev,
                                    const char *buf, size_t size);
 static ssize_t ahci_show_em_supported(struct device *dev,
                                      struct device_attribute *attr, char *buf);
+static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance);
 
 static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
 static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
@@ -496,8 +497,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
                }
        }
 
-       /* fabricate port_map from cap.nr_ports */
-       if (!port_map) {
+       /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
+       if (!port_map && vers < 0x10300) {
                port_map = (1 << ahci_nr_ports(cap)) - 1;
                dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
 
@@ -512,6 +513,9 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
 
        if (!hpriv->start_engine)
                hpriv->start_engine = ahci_start_engine;
+
+       if (!hpriv->irq_handler)
+               hpriv->irq_handler = ahci_single_level_irq_intr;
 }
 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
 
@@ -593,8 +597,22 @@ EXPORT_SYMBOL_GPL(ahci_start_engine);
 int ahci_stop_engine(struct ata_port *ap)
 {
        void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_host_priv *hpriv = ap->host->private_data;
        u32 tmp;
 
+       /*
+        * On some controllers, stopping a port's DMA engine while the port
+        * is in ALPM state (partial or slumber) results in failures on
+        * subsequent DMA engine starts.  For those controllers, put the
+        * port back in active state before stopping its DMA engine.
+        */
+       if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
+           (ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
+           ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
+               dev_err(ap->host->dev, "Failed to wake up port before engine stop\n");
+               return -EIO;
+       }
+
        tmp = readl(port_mmio + PORT_CMD);
 
        /* check if the HBA is idle */
@@ -689,6 +707,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
        void __iomem *port_mmio = ahci_port_base(ap);
 
        if (policy != ATA_LPM_MAX_POWER) {
+               /* wakeup flag only applies to the max power policy */
+               hints &= ~ATA_LPM_WAKE_ONLY;
+
                /*
                 * Disable interrupts on Phy Ready. This keeps us from
                 * getting woken up due to spurious phy ready
@@ -704,7 +725,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
                u32 cmd = readl(port_mmio + PORT_CMD);
 
                if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
-                       cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
+                       if (!(hints & ATA_LPM_WAKE_ONLY))
+                               cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
                        cmd |= PORT_CMD_ICC_ACTIVE;
 
                        writel(cmd, port_mmio + PORT_CMD);
@@ -712,6 +734,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
 
                        /* wait 10ms to be sure we've come out of LPM state */
                        ata_msleep(ap, 10);
+
+                       if (hints & ATA_LPM_WAKE_ONLY)
+                               return 0;
                } else {
                        cmd |= PORT_CMD_ALPE;
                        if (policy == ATA_LPM_MIN_POWER)
@@ -1143,8 +1168,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap,
 
        /* mark esata ports */
        tmp = readl(port_mmio + PORT_CMD);
-       if ((tmp & PORT_CMD_HPCP) ||
-           ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)))
+       if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))
                ap->pflags |= ATA_PFLAG_EXTERNAL;
 }
 
@@ -1825,7 +1849,7 @@ static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
        return IRQ_HANDLED;
 }
 
-static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
+u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
 {
        unsigned int i, handled = 0;
 
@@ -1851,43 +1875,7 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
 
        return handled;
 }
-
-static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
-{
-       struct ata_host *host = dev_instance;
-       struct ahci_host_priv *hpriv;
-       unsigned int rc = 0;
-       void __iomem *mmio;
-       u32 irq_stat, irq_masked;
-
-       VPRINTK("ENTER\n");
-
-       hpriv = host->private_data;
-       mmio = hpriv->mmio;
-
-       /* sigh.  0xffffffff is a valid return from h/w */
-       irq_stat = readl(mmio + HOST_IRQ_STAT);
-       if (!irq_stat)
-               return IRQ_NONE;
-
-       irq_masked = irq_stat & hpriv->port_map;
-
-       spin_lock(&host->lock);
-
-       /*
-        * HOST_IRQ_STAT behaves as edge triggered latch meaning that
-        * it should be cleared before all the port events are cleared.
-        */
-       writel(irq_stat, mmio + HOST_IRQ_STAT);
-
-       rc = ahci_handle_port_intr(host, irq_masked);
-
-       spin_unlock(&host->lock);
-
-       VPRINTK("EXIT\n");
-
-       return IRQ_RETVAL(rc);
-}
+EXPORT_SYMBOL_GPL(ahci_handle_port_intr);
 
 static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
 {
@@ -2514,14 +2502,18 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
        int irq = hpriv->irq;
        int rc;
 
-       if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX))
+       if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX)) {
+               if (hpriv->irq_handler)
+                       dev_warn(host->dev, "both AHCI_HFLAG_MULTI_MSI flag set \
+                                and custom irq handler implemented\n");
+
                rc = ahci_host_activate_multi_irqs(host, sht);
-       else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
-               rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
-                                      IRQF_SHARED, sht);
-       else
-               rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
+       } else {
+               rc = ata_host_activate(host, irq, hpriv->irq_handler,
                                       IRQF_SHARED, sht);
+       }
+
+
        return rc;
 }
 EXPORT_SYMBOL_GPL(ahci_host_activate);
index cbb74719d2c1b80d61590ddf3fb2f9c71a31ce06..55e257c268ddde37677cf4ff85472f65e9a63c97 100644 (file)
@@ -4125,6 +4125,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "SAMSUNG CD-ROM SN-124", "N001",      ATA_HORKAGE_NODMA },
        { "Seagate STT20000A", NULL,            ATA_HORKAGE_NODMA },
        { " 2GB ATA Flash Disk", "ADMA428M",    ATA_HORKAGE_NODMA },
+       { "VRFDFC22048UCHC-TE*", NULL,          ATA_HORKAGE_NODMA },
        /* Odd clown on sil3726/4726 PMPs */
        { "Config  Disk",       NULL,           ATA_HORKAGE_DISABLE },
 
index 7e959f90c0203f9b94124ab73867e4a72bd11188..e417e1a1d02c568595fa465682ade483a9d0645a 100644 (file)
@@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap)
 int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
                     int cmd, void __user *arg)
 {
-       int val = -EINVAL, rc = -EINVAL;
+       unsigned long val;
+       int rc = -EINVAL;
        unsigned long flags;
 
        switch (cmd) {
-       case ATA_IOC_GET_IO32:
+       case HDIO_GET_32BIT:
                spin_lock_irqsave(ap->lock, flags);
                val = ata_ioc32(ap);
                spin_unlock_irqrestore(ap->lock, flags);
-               if (copy_to_user(arg, &val, 1))
-                       return -EFAULT;
-               return 0;
+               return put_user(val, (unsigned long __user *)arg);
 
-       case ATA_IOC_SET_IO32:
+       case HDIO_SET_32BIT:
                val = (unsigned long) arg;
                rc = 0;
                spin_lock_irqsave(ap->lock, flags);
index cdf6215a9a22beb93ede75a702797e12c5ad4870..051b6158d1b7f45b7116b9debc98376a9d4d240f 100644 (file)
@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
 static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
 {
        struct ata_port *ap = qc->ap;
-       unsigned long flags;
 
        if (ap->ops->error_handler) {
                if (in_wq) {
-                       spin_lock_irqsave(ap->lock, flags);
-
                        /* EH might have kicked in while host lock is
                         * released.
                         */
@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
                                } else
                                        ata_port_freeze(ap);
                        }
-
-                       spin_unlock_irqrestore(ap->lock, flags);
                } else {
                        if (likely(!(qc->err_mask & AC_ERR_HSM)))
                                ata_qc_complete(qc);
@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
                }
        } else {
                if (in_wq) {
-                       spin_lock_irqsave(ap->lock, flags);
                        ata_sff_irq_on(ap);
                        ata_qc_complete(qc);
-                       spin_unlock_irqrestore(ap->lock, flags);
                } else
                        ata_qc_complete(qc);
        }
@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
 {
        struct ata_link *link = qc->dev->link;
        struct ata_eh_info *ehi = &link->eh_info;
-       unsigned long flags = 0;
        int poll_next;
 
+       lockdep_assert_held(ap->lock);
+
        WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
 
        /* Make sure ata_sff_qc_issue() does not throw things
@@ -1112,14 +1106,6 @@ fsm_start:
                        }
                }
 
-               /* Send the CDB (atapi) or the first data block (ata pio out).
-                * During the state transition, interrupt handler shouldn't
-                * be invoked before the data transfer is complete and
-                * hsm_task_state is changed. Hence, the following locking.
-                */
-               if (in_wq)
-                       spin_lock_irqsave(ap->lock, flags);
-
                if (qc->tf.protocol == ATA_PROT_PIO) {
                        /* PIO data out protocol.
                         * send first data block.
@@ -1135,9 +1121,6 @@ fsm_start:
                        /* send CDB */
                        atapi_send_cdb(ap, qc);
 
-               if (in_wq)
-                       spin_unlock_irqrestore(ap->lock, flags);
-
                /* if polling, ata_sff_pio_task() handles the rest.
                 * otherwise, interrupt handler takes over from here.
                 */
@@ -1296,7 +1279,8 @@ fsm_start:
                break;
        default:
                poll_next = 0;
-               BUG();
+               WARN(true, "ata%d: SFF host state machine in invalid state %d",
+                    ap->print_id, ap->hsm_task_state);
        }
 
        return poll_next;
@@ -1361,12 +1345,14 @@ static void ata_sff_pio_task(struct work_struct *work)
        u8 status;
        int poll_next;
 
+       spin_lock_irq(ap->lock);
+
        BUG_ON(ap->sff_pio_task_link == NULL);
        /* qc can be NULL if timeout occurred */
        qc = ata_qc_from_tag(ap, link->active_tag);
        if (!qc) {
                ap->sff_pio_task_link = NULL;
-               return;
+               goto out_unlock;
        }
 
 fsm_start:
@@ -1381,11 +1367,14 @@ fsm_start:
         */
        status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
        if (status & ATA_BUSY) {
+               spin_unlock_irq(ap->lock);
                ata_msleep(ap, 2);
+               spin_lock_irq(ap->lock);
+
                status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
                if (status & ATA_BUSY) {
                        ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
-                       return;
+                       goto out_unlock;
                }
        }
 
@@ -1402,6 +1391,8 @@ fsm_start:
         */
        if (poll_next)
                goto fsm_start;
+out_unlock:
+       spin_unlock_irq(ap->lock);
 }
 
 /**
index 12fe0f3bb7e9b0bf8120af19badf4ddf72903565..c8b6a780a29050775f66ec60bc89773d71677683 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/libata.h>
 #include <scsi/scsi_host.h>
 
+#include <asm/mach-rc32434/rb.h>
+
 #define DRV_NAME       "pata-rb532-cf"
 #define DRV_VERSION    "0.1.0"
 #define DRV_DESC       "PATA driver for RouterBOARD 532 Compact Flash"
@@ -107,6 +109,7 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
        int gpio;
        struct resource *res;
        struct ata_host *ah;
+       struct cf_device *pdata;
        struct rb532_cf_info *info;
        int ret;
 
@@ -122,7 +125,13 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
                return -ENOENT;
        }
 
-       gpio = irq_to_gpio(irq);
+       pdata = dev_get_platdata(&pdev->dev);
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data specified\n");
+               return -EINVAL;
+       }
+
+       gpio = pdata->gpio_pin;
        if (gpio < 0) {
                dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq);
                return -ENOENT;
index 89f5cf68d80a143198c2c253d6d21c0d9fb38388..04a1582e80bb83d00fa80c3fb95d325bb165b261 100644 (file)
@@ -206,6 +206,8 @@ static void component_match_release(struct device *master,
                if (mc->release)
                        mc->release(master, mc->data);
        }
+
+       kfree(match->compare);
 }
 
 static void devm_component_match_release(struct device *dev, void *res)
@@ -221,14 +223,14 @@ static int component_match_realloc(struct device *dev,
        if (match->alloc == num)
                return 0;
 
-       new = devm_kmalloc_array(dev, num, sizeof(*new), GFP_KERNEL);
+       new = kmalloc_array(num, sizeof(*new), GFP_KERNEL);
        if (!new)
                return -ENOMEM;
 
        if (match->compare) {
                memcpy(new, match->compare, sizeof(*new) *
                                            min(match->num, num));
-               devm_kfree(dev, match->compare);
+               kfree(match->compare);
        }
        match->compare = new;
        match->alloc = num;
@@ -283,6 +285,24 @@ void component_match_add_release(struct device *master,
 }
 EXPORT_SYMBOL(component_match_add_release);
 
+static void free_master(struct master *master)
+{
+       struct component_match *match = master->match;
+       int i;
+
+       list_del(&master->node);
+
+       if (match) {
+               for (i = 0; i < match->num; i++) {
+                       struct component *c = match->compare[i].component;
+                       if (c)
+                               c->master = NULL;
+               }
+       }
+
+       kfree(master);
+}
+
 int component_master_add_with_match(struct device *dev,
        const struct component_master_ops *ops,
        struct component_match *match)
@@ -309,11 +329,9 @@ int component_master_add_with_match(struct device *dev,
 
        ret = try_to_bring_up_master(master, NULL);
 
-       if (ret < 0) {
-               /* Delete off the list if we weren't successful */
-               list_del(&master->node);
-               kfree(master);
-       }
+       if (ret < 0)
+               free_master(master);
+
        mutex_unlock(&component_mutex);
 
        return ret < 0 ? ret : 0;
@@ -324,25 +342,12 @@ void component_master_del(struct device *dev,
        const struct component_master_ops *ops)
 {
        struct master *master;
-       int i;
 
        mutex_lock(&component_mutex);
        master = __master_find(dev, ops);
        if (master) {
-               struct component_match *match = master->match;
-
                take_down_master(master);
-
-               list_del(&master->node);
-
-               if (match) {
-                       for (i = 0; i < match->num; i++) {
-                               struct component *c = match->compare[i].component;
-                               if (c)
-                                       c->master = NULL;
-                       }
-               }
-               kfree(master);
+               free_master(master);
        }
        mutex_unlock(&component_mutex);
 }
@@ -486,6 +491,8 @@ int component_add(struct device *dev, const struct component_ops *ops)
 
        ret = try_to_bring_up_masters(component);
        if (ret < 0) {
+               if (component->master)
+                       remove_component(component->master, component);
                list_del(&component->node);
 
                kfree(component);
index 93ed14cc22524ccdd04301dbe460e0958bb69acf..f6a9ad52cbbff0663e58540f33bb29e08abf0e96 100644 (file)
@@ -146,7 +146,7 @@ void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd)
        if (dev->pm_domain == pd)
                return;
 
-       WARN(device_is_bound(dev),
+       WARN(pd && device_is_bound(dev),
             "PM domains can only be changed for unbound devices\n");
        dev->pm_domain = pd;
        device_pm_check_callbacks(dev);
index 784dbe897a5e1878057f9663a7a39d1b9db4a21c..301b785f9f56f5d00b7f83798b6f7cce53bf0e03 100644 (file)
@@ -173,14 +173,14 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 }
 
 /**
- * __genpd_poweron - Restore power to a given PM domain and its masters.
+ * genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  * @depth: nesting count for lockdep.
  *
  * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
-static int __genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
+static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
 {
        struct gpd_link *link;
        int ret = 0;
@@ -200,7 +200,7 @@ static int __genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
                genpd_sd_counter_inc(master);
 
                mutex_lock_nested(&master->lock, depth + 1);
-               ret = __genpd_poweron(master, depth + 1);
+               ret = genpd_poweron(master, depth + 1);
                mutex_unlock(&master->lock);
 
                if (ret) {
@@ -227,21 +227,6 @@ static int __genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth)
        return ret;
 }
 
-/**
- * genpd_poweron - Restore power to a given PM domain and its masters.
- * @genpd: PM domain to power up.
- */
-static int genpd_poweron(struct generic_pm_domain *genpd)
-{
-       int ret;
-
-       mutex_lock(&genpd->lock);
-       ret = __genpd_poweron(genpd, 0);
-       mutex_unlock(&genpd->lock);
-       return ret;
-}
-
-
 static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
 {
        return GENPD_DEV_CALLBACK(genpd, int, save_state, dev);
@@ -489,7 +474,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
        }
 
        mutex_lock(&genpd->lock);
-       ret = __genpd_poweron(genpd, 0);
+       ret = genpd_poweron(genpd, 0);
        mutex_unlock(&genpd->lock);
 
        if (ret)
@@ -1821,8 +1806,10 @@ int genpd_dev_pm_attach(struct device *dev)
 
        dev->pm_domain->detach = genpd_dev_pm_detach;
        dev->pm_domain->sync = genpd_dev_pm_sync;
-       ret = genpd_poweron(pd);
 
+       mutex_lock(&pd->lock);
+       ret = genpd_poweron(pd, 0);
+       mutex_unlock(&pd->lock);
 out:
        return ret ? -EPROBE_DEFER : 0;
 }
index 8812bfb9e3b89256f4a5d1468cf45484b18e4cd1..eea51569f0eb9c9e36f5a4bca90de61c8f833444 100644 (file)
@@ -133,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
        while (val_size) {
                switch (ctx->val_bytes) {
                case 1:
-                       __raw_writeb(*(u8 *)val, ctx->regs + offset);
+                       writeb(*(u8 *)val, ctx->regs + offset);
                        break;
                case 2:
-                       __raw_writew(*(u16 *)val, ctx->regs + offset);
+                       writew(*(u16 *)val, ctx->regs + offset);
                        break;
                case 4:
-                       __raw_writel(*(u32 *)val, ctx->regs + offset);
+                       writel(*(u32 *)val, ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       __raw_writeq(*(u64 *)val, ctx->regs + offset);
+                       writeq(*(u64 *)val, ctx->regs + offset);
                        break;
 #endif
                default:
@@ -193,17 +193,17 @@ static int regmap_mmio_read(void *context,
        while (val_size) {
                switch (ctx->val_bytes) {
                case 1:
-                       *(u8 *)val = __raw_readb(ctx->regs + offset);
+                       *(u8 *)val = readb(ctx->regs + offset);
                        break;
                case 2:
-                       *(u16 *)val = __raw_readw(ctx->regs + offset);
+                       *(u16 *)val = readw(ctx->regs + offset);
                        break;
                case 4:
-                       *(u32 *)val = __raw_readl(ctx->regs + offset);
+                       *(u32 *)val = readl(ctx->regs + offset);
                        break;
 #ifdef CONFIG_64BIT
                case 8:
-                       *(u64 *)val = __raw_readq(ctx->regs + offset);
+                       *(u64 *)val = readq(ctx->regs + offset);
                        break;
 #endif
                default:
index 023d448ed3fa6047549d635fade7fb26205a8633..efdc2ae8441af08dd7b55bf2249148ddcb1d66f3 100644 (file)
@@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
 
          If unsure, say N
 
+config BCMA_PFLASH
+       bool
+       depends on BCMA_DRIVER_MIPS
+       default y
+
 config BCMA_SFLASH
        bool
        depends on BCMA_DRIVER_MIPS
index f32af9b76bcd2aaa7e0da61e26b2e33174803f7f..087948a1d20d96d9aa83540897b827cc34936e8f 100644 (file)
@@ -1,6 +1,7 @@
 bcma-y                                 += main.o scan.o core.o sprom.o
 bcma-y                                 += driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y                                 += driver_chipcommon_b.o
+bcma-$(CONFIG_BCMA_PFLASH)             += driver_chipcommon_pflash.o
 bcma-$(CONFIG_BCMA_SFLASH)             += driver_chipcommon_sflash.o
 bcma-$(CONFIG_BCMA_NFLASH)             += driver_chipcommon_nflash.o
 bcma-$(CONFIG_BCMA_DRIVER_PCI)         += driver_pci.o
index 38f156745d533a666deae90f167dd6d51d718d54..eda09090cb523f5ddc2a6c174502110ae8999a57 100644 (file)
@@ -47,10 +47,6 @@ int bcma_sprom_get(struct bcma_bus *bus);
 void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
 void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
 void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
-#ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
-extern struct platform_device bcma_pflash_dev;
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
 
 /* driver_chipcommon_b.c */
 int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
@@ -62,6 +58,21 @@ void bcma_pmu_init(struct bcma_drv_cc *cc);
 u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
 u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
 
+/**************************************************
+ * driver_chipcommon_sflash.c
+ **************************************************/
+
+#ifdef CONFIG_BCMA_PFLASH
+extern struct platform_device bcma_pflash_dev;
+int bcma_pflash_init(struct bcma_drv_cc *cc);
+#else
+static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
+{
+       bcma_err(cc->core->bus, "Parallel flash not supported\n");
+       return 0;
+}
+#endif /* CONFIG_BCMA_PFLASH */
+
 #ifdef CONFIG_BCMA_SFLASH
 /* driver_chipcommon_sflash.c */
 int bcma_sflash_init(struct bcma_drv_cc *cc);
index b7c8a8d4e6d1a232d44a28412a8b9ceba94e1ce9..921ce1834673231e597d2b85e48bb5e4307bf3b1 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+
 static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
                                         u32 mask, u32 value)
 {
@@ -113,8 +115,37 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
        return 0;
 }
 
+static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
+{
+       struct bcma_bus *bus = cc->core->bus;
+
+       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
+       case BCMA_CC_FLASHT_STSER:
+       case BCMA_CC_FLASHT_ATSER:
+               bcma_debug(bus, "Found serial flash\n");
+               bcma_sflash_init(cc);
+               break;
+       case BCMA_CC_FLASHT_PARA:
+               bcma_debug(bus, "Found parallel flash\n");
+               bcma_pflash_init(cc);
+               break;
+       default:
+               bcma_err(bus, "Flash type not supported\n");
+       }
+
+       if (cc->core->id.rev == 38 ||
+           bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+               if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
+                       bcma_debug(bus, "Found NAND flash\n");
+                       bcma_nflash_init(cc);
+               }
+       }
+}
+
 void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
 {
+       struct bcma_bus *bus = cc->core->bus;
+
        if (cc->early_setup_done)
                return;
 
@@ -129,6 +160,12 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
        if (cc->capabilities & BCMA_CC_CAP_PMU)
                bcma_pmu_early_init(cc);
 
+       if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
+               bcma_chipco_serial_init(cc);
+
+       if (bus->hosttype == BCMA_HOSTTYPE_SOC)
+               bcma_core_chipcommon_flash_detect(cc);
+
        cc->early_setup_done = true;
 }
 
@@ -185,11 +222,12 @@ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
                        ticks = 2;
                else if (ticks > maxt)
                        ticks = maxt;
-               bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
        } else {
                struct bcma_bus *bus = cc->core->bus;
 
                if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+                   bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
                    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
                        bcma_core_set_clockmode(cc->core,
                                                ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
@@ -314,9 +352,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
        return res;
 }
 
-#ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 {
+#if IS_BUILTIN(CONFIG_BCM47XX)
        unsigned int irq;
        u32 baud_base;
        u32 i;
@@ -358,5 +396,5 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
                ports[i].baud_base = baud_base;
                ports[i].reg_shift = 0;
        }
+#endif /* CONFIG_BCM47XX */
 }
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
diff --git a/drivers/bcma/driver_chipcommon_pflash.c b/drivers/bcma/driver_chipcommon_pflash.c
new file mode 100644 (file)
index 0000000..3b497c9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon parallel flash
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+
+static const char * const part_probes[] = { "bcm47xxpart", NULL };
+
+static struct physmap_flash_data bcma_pflash_data = {
+       .part_probe_types       = part_probes,
+};
+
+static struct resource bcma_pflash_resource = {
+       .name   = "bcma_pflash",
+       .flags  = IORESOURCE_MEM,
+};
+
+struct platform_device bcma_pflash_dev = {
+       .name           = "physmap-flash",
+       .dev            = {
+               .platform_data  = &bcma_pflash_data,
+       },
+       .resource       = &bcma_pflash_resource,
+       .num_resources  = 1,
+};
+
+int bcma_pflash_init(struct bcma_drv_cc *cc)
+{
+       struct bcma_pflash *pflash = &cc->pflash;
+
+       pflash->present = true;
+
+       if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
+               bcma_pflash_data.width = 1;
+       else
+               bcma_pflash_data.width = 2;
+
+       bcma_pflash_resource.start = BCMA_SOC_FLASH2;
+       bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
+
+       return 0;
+}
index fe0d48cb17788a9f3614fd8a36add7bac5f58848..f1eb4d3e1d575b2806c3d43155efb85f7640228d 100644 (file)
 
 u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
 
 void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
 
 void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
                             u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
 
 void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
                                 u32 offset, u32 mask, u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
 
 void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
                                u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 
@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc)
 {
        u32 ilp_ctl, alp_hz;
 
-       if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
+       if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
              BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
                return 0;
 
-       bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
-                       BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+       bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+                        BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
        usleep_range(1000, 2000);
 
-       ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+       ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
        ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
 
-       bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
 
        alp_hz = ilp_ctl * 32768 / 4;
        return (alp_hz + 50000) / 100000 * 100;
@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
                mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
                              BCMA_RES_4314_MACPHY_CLK_AVAIL);
 
-               bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
-               bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+               bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+               bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
                bcma_wait_value(cc->core, BCMA_CLKCTLST,
                                BCMA_CLKCTLST_HAVEHT, 0, 20000);
                break;
@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
 
        /* Flush */
        if (cc->pmu.rev >= 2)
-               bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+               bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
 
        /* TODO: Do we need to update OTP? */
 }
@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
 
        /* Set the resource masks. */
        if (min_msk)
-               bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
        if (max_msk)
-               bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
 
        /*
         * Add some delay; allow resources to come up and settle.
@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 
 void bcma_pmu_early_init(struct bcma_drv_cc *cc)
 {
+       struct bcma_bus *bus = cc->core->bus;
        u32 pmucap;
 
-       pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
+       if (cc->core->id.rev >= 35 &&
+           cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
+               cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
+               if (!cc->pmu.core)
+                       bcma_warn(bus, "Couldn't find expected PMU core");
+       }
+       if (!cc->pmu.core)
+               cc->pmu.core = cc->core;
+
+       pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
        cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
 
-       bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
-                  cc->pmu.rev, pmucap);
+       bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
+                  pmucap);
 }
 
 void bcma_pmu_init(struct bcma_drv_cc *cc)
 {
        if (cc->pmu.rev == 1)
-               bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
-                             ~BCMA_CC_PMU_CTL_NOILPONW);
+               bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
+                               ~BCMA_CC_PMU_CTL_NOILPONW);
        else
-               bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
-                            BCMA_CC_PMU_CTL_NOILPONW);
+               bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
+                              BCMA_CC_PMU_CTL_NOILPONW);
 
        bcma_pmu_pll_init(cc);
        bcma_pmu_resources_init(cc);
@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
 static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                         u32 value)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
 }
 
 void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
                       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
 
                /* RMW only the P1 divider */
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
                                BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
-               tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+               tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
                tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
                tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
 
                /* RMW only the int feedback divider */
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
                                BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
-               tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+               tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
                tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
 
                tmp = BCMA_CC_PMU_CTL_PLL_UPD;
                break;
@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
                break;
        }
 
-       tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
-       bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
+       tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
 }
 EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
index 7e11ef4cb7dbed69bd52685cf03a177fe6a8a01a..04d706ca5f439be4576c8f78afb4b10a66b5dd3e 100644 (file)
@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
+       { "MX25L25635F", 0x18, 0x10000, 512, },
        { NULL },
 };
 
index 98067f757fb0d9348fc8fb8f6fd25eb81e32bbf2..771a2a253440f736711bd996044d78b6ce3b723a 100644 (file)
@@ -192,6 +192,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
        case BCMA_CHIP_ID_BCM4707:
        case BCMA_CHIP_ID_BCM5357:
        case BCMA_CHIP_ID_BCM53572:
+       case BCMA_CHIP_ID_BCM47094:
                chip->ngpio     = 32;
                break;
        default:
index 24424f3fef96d5784be6d5af59dbf40b3abc94e2..96f17132820080843e9216523bc1328b2f8f7939 100644 (file)
@@ -14,8 +14,6 @@
 
 #include <linux/bcma/bcma.h>
 
-#include <linux/mtd/physmap.h>
-#include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
@@ -32,26 +30,6 @@ enum bcma_boot_dev {
        BCMA_BOOT_DEV_NAND,
 };
 
-static const char * const part_probes[] = { "bcm47xxpart", NULL };
-
-static struct physmap_flash_data bcma_pflash_data = {
-       .part_probe_types       = part_probes,
-};
-
-static struct resource bcma_pflash_resource = {
-       .name   = "bcma_pflash",
-       .flags  = IORESOURCE_MEM,
-};
-
-struct platform_device bcma_pflash_dev = {
-       .name           = "physmap-flash",
-       .dev            = {
-               .platform_data  = &bcma_pflash_data,
-       },
-       .resource       = &bcma_pflash_resource,
-       .num_resources  = 1,
-};
-
 /* The 47162a0 hangs when reading MIPS DMP registers registers */
 static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
 {
@@ -272,48 +250,11 @@ static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
        return BCMA_BOOT_DEV_SERIAL;
 }
 
-static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
+static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
 {
        struct bcma_bus *bus = mcore->core->bus;
-       struct bcma_drv_cc *cc = &bus->drv_cc;
-       struct bcma_pflash *pflash = &cc->pflash;
        enum bcma_boot_dev boot_dev;
 
-       switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
-       case BCMA_CC_FLASHT_STSER:
-       case BCMA_CC_FLASHT_ATSER:
-               bcma_debug(bus, "Found serial flash\n");
-               bcma_sflash_init(cc);
-               break;
-       case BCMA_CC_FLASHT_PARA:
-               bcma_debug(bus, "Found parallel flash\n");
-               pflash->present = true;
-               pflash->window = BCMA_SOC_FLASH2;
-               pflash->window_size = BCMA_SOC_FLASH2_SZ;
-
-               if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
-                    BCMA_CC_FLASH_CFG_DS) == 0)
-                       pflash->buswidth = 1;
-               else
-                       pflash->buswidth = 2;
-
-               bcma_pflash_data.width = pflash->buswidth;
-               bcma_pflash_resource.start = pflash->window;
-               bcma_pflash_resource.end = pflash->window + pflash->window_size;
-
-               break;
-       default:
-               bcma_err(bus, "Flash type not supported\n");
-       }
-
-       if (cc->core->id.rev == 38 ||
-           bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
-               if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
-                       bcma_debug(bus, "Found NAND flash\n");
-                       bcma_nflash_init(cc);
-               }
-       }
-
        /* Determine flash type this SoC boots from */
        boot_dev = bcma_boot_dev(bus);
        switch (boot_dev) {
@@ -337,13 +278,10 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 
 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 {
-       struct bcma_bus *bus = mcore->core->bus;
-
        if (mcore->early_setup_done)
                return;
 
-       bcma_chipco_serial_init(&bus->drv_cc);
-       bcma_core_mips_flash_detect(mcore);
+       bcma_core_mips_nvram_init(mcore);
 
        mcore->early_setup_done = true;
 }
index 0856189c065fd57826df7edab2dba3217d5e283c..cae5385cf4996c28353e55f0676f8aa9ba8ec1ac 100644 (file)
@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
index c466f752b067d2bbbcbbd2cdcaf50bb82942d80f..786be8fed39e980add0b9e1cddc9e0682171dc9a 100644 (file)
@@ -350,7 +350,7 @@ static int bcma_register_devices(struct bcma_bus *bus)
                bcma_register_core(bus, core);
        }
 
-#ifdef CONFIG_BCMA_DRIVER_MIPS
+#ifdef CONFIG_BCMA_PFLASH
        if (bus->drv_cc.pflash.present) {
                err = platform_device_register(&bcma_pflash_dev);
                if (err)
index df806b9c549084fab8e61569718b2441485f17e4..4a2d1b235fb5af3e51ac8b044e6a18aed5753cec 100644 (file)
@@ -98,6 +98,9 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
        { BCMA_CORE_SHIM, "SHIM" },
        { BCMA_CORE_PCIE2, "PCIe Gen2" },
        { BCMA_CORE_ARM_CR4, "ARM CR4" },
+       { BCMA_CORE_GCI, "GCI" },
+       { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
+       { BCMA_CORE_ARM_CA7, "ARM CA7" },
        { BCMA_CORE_DEFAULT, "Default" },
 };
 
@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                switch (core->id.id) {
                case BCMA_CORE_4706_MAC_GBIT_COMMON:
                case BCMA_CORE_NS_CHIPCOMMON_B:
+               case BCMA_CORE_PMU:
+               case BCMA_CORE_GCI:
                /* Not used yet: case BCMA_CORE_OOB_ROUTER: */
                        break;
                default:
index 9e251201dd48ef2a850b8069edf7ffc05be98a4e..84708a5f8c520cb86db4ad62a4b845a5ec83b88f 100644 (file)
@@ -866,7 +866,7 @@ static void set_fdc(int drive)
 }
 
 /* locks the driver */
-static int lock_fdc(int drive, bool interruptible)
+static int lock_fdc(int drive)
 {
        if (WARN(atomic_read(&usage_count) == 0,
                 "Trying to lock fdc while usage count=0\n"))
@@ -2173,7 +2173,7 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
 {
        int ret;
 
-       if (lock_fdc(drive, true))
+       if (lock_fdc(drive))
                return -EINTR;
 
        set_floppy(drive);
@@ -2960,7 +2960,7 @@ static int user_reset_fdc(int drive, int arg, bool interruptible)
 {
        int ret;
 
-       if (lock_fdc(drive, interruptible))
+       if (lock_fdc(drive))
                return -EINTR;
 
        if (arg == FD_RESET_ALWAYS)
@@ -3243,7 +3243,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
                mutex_lock(&open_lock);
-               if (lock_fdc(drive, true)) {
+               if (lock_fdc(drive)) {
                        mutex_unlock(&open_lock);
                        return -EINTR;
                }
@@ -3263,7 +3263,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
        } else {
                int oldStretch;
 
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                if (cmd != FDDEFPRM) {
                        /* notice a disk change immediately, else
@@ -3349,7 +3349,7 @@ static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
        if (type)
                *g = &floppy_type[type];
        else {
-               if (lock_fdc(drive, false))
+               if (lock_fdc(drive))
                        return -EINTR;
                if (poll_drive(false, 0) == -EINTR)
                        return -EINTR;
@@ -3433,7 +3433,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                if (UDRS->fd_ref != 1)
                        /* somebody else has this drive open */
                        return -EBUSY;
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
 
                /* do the actual eject. Fails on
@@ -3445,7 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                process_fd_request();
                return ret;
        case FDCLRPRM:
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                current_type[drive] = NULL;
                floppy_sizes[drive] = MAX_DISK_SIZE << 1;
@@ -3467,7 +3467,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                UDP->flags &= ~FTD_MSG;
                return 0;
        case FDFMTBEG:
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
                        return -EINTR;
@@ -3484,7 +3484,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                return do_format(drive, &inparam.f);
        case FDFMTEND:
        case FDFLUSH:
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                return invalidate_drive(bdev);
        case FDSETEMSGTRESH:
@@ -3507,7 +3507,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                outparam = UDP;
                break;
        case FDPOLLDRVSTAT:
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
                        return -EINTR;
@@ -3530,7 +3530,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
        case FDRAWCMD:
                if (type)
                        return -EINVAL;
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                set_floppy(drive);
                i = raw_cmd_ioctl(cmd, (void __user *)param);
@@ -3539,7 +3539,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                process_fd_request();
                return i;
        case FDTWADDLE:
-               if (lock_fdc(drive, true))
+               if (lock_fdc(drive))
                        return -EINTR;
                twaddle();
                process_fd_request();
@@ -3663,6 +3663,11 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
 
        opened_bdev[drive] = bdev;
 
+       if (!(mode & (FMODE_READ|FMODE_WRITE))) {
+               res = -EINVAL;
+               goto out;
+       }
+
        res = -ENXIO;
 
        if (!floppy_track_buffer) {
@@ -3706,21 +3711,20 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        if (UFDCS->rawcmd == 1)
                UFDCS->rawcmd = 2;
 
-       if (!(mode & FMODE_NDELAY)) {
-               if (mode & (FMODE_READ|FMODE_WRITE)) {
-                       UDRS->last_checked = 0;
-                       clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
-                       check_disk_change(bdev);
-                       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
-                               goto out;
-                       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
-                               goto out;
-               }
-               res = -EROFS;
-               if ((mode & FMODE_WRITE) &&
-                   !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
-                       goto out;
-       }
+       UDRS->last_checked = 0;
+       clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+       check_disk_change(bdev);
+       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+               goto out;
+       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+               goto out;
+
+       res = -EROFS;
+
+       if ((mode & FMODE_WRITE) &&
+                       !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
+               goto out;
+
        mutex_unlock(&open_lock);
        mutex_unlock(&floppy_mutex);
        return 0;
@@ -3748,7 +3752,8 @@ static unsigned int floppy_check_events(struct gendisk *disk,
                return DISK_EVENT_MEDIA_CHANGE;
 
        if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
-               lock_fdc(drive, false);
+               if (lock_fdc(drive))
+                       return -EINTR;
                poll_drive(false, 0);
                process_fd_request();
        }
@@ -3847,7 +3852,9 @@ static int floppy_revalidate(struct gendisk *disk)
                         "VFS: revalidate called on non-open device.\n"))
                        return -EFAULT;
 
-               lock_fdc(drive, false);
+               res = lock_fdc(drive);
+               if (res)
+                       return res;
                cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
                      test_bit(FD_VERIFY_BIT, &UDRS->flags));
                if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
index 8ba1e97d573c3b804c2ee7d14946f94b4c32fc93..64a7b5971b57046eafd210d726fa039b05bc705d 100644 (file)
@@ -478,7 +478,7 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
        id->ver_id = 0x1;
        id->vmnt = 0;
        id->cgrps = 1;
-       id->cap = 0x3;
+       id->cap = 0x2;
        id->dom = 0x1;
 
        id->ppaf.blk_offset = 0;
@@ -707,9 +707,7 @@ static int null_add_dev(void)
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q);
        queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q);
 
-
        mutex_lock(&lock);
-       list_add_tail(&nullb->list, &nullb_list);
        nullb->index = nullb_indexes++;
        mutex_unlock(&lock);
 
@@ -743,6 +741,10 @@ static int null_add_dev(void)
        strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
 
        add_disk(disk);
+
+       mutex_lock(&lock);
+       list_add_tail(&nullb->list, &nullb_list);
+       mutex_unlock(&lock);
 done:
        return 0;
 
index 8a8dc91c39f7292be4fc0b1c172e12e97f5fed5c..83eb9e6bf8b06673640ff5d5ef05db1555e4912f 100644 (file)
@@ -1873,6 +1873,43 @@ again:
        return err;
 }
 
+static int negotiate_mq(struct blkfront_info *info)
+{
+       unsigned int backend_max_queues = 0;
+       int err;
+       unsigned int i;
+
+       BUG_ON(info->nr_rings);
+
+       /* Check if backend supports multiple queues. */
+       err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+                          "multi-queue-max-queues", "%u", &backend_max_queues);
+       if (err < 0)
+               backend_max_queues = 1;
+
+       info->nr_rings = min(backend_max_queues, xen_blkif_max_queues);
+       /* We need at least one ring. */
+       if (!info->nr_rings)
+               info->nr_rings = 1;
+
+       info->rinfo = kzalloc(sizeof(struct blkfront_ring_info) * info->nr_rings, GFP_KERNEL);
+       if (!info->rinfo) {
+               xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < info->nr_rings; i++) {
+               struct blkfront_ring_info *rinfo;
+
+               rinfo = &info->rinfo[i];
+               INIT_LIST_HEAD(&rinfo->indirect_pages);
+               INIT_LIST_HEAD(&rinfo->grants);
+               rinfo->dev_info = info;
+               INIT_WORK(&rinfo->work, blkif_restart_queue);
+               spin_lock_init(&rinfo->ring_lock);
+       }
+       return 0;
+}
 /**
  * Entry point to this code when a new device is created.  Allocate the basic
  * structures and the ring buffer for communication with the backend, and
@@ -1883,9 +1920,7 @@ static int blkfront_probe(struct xenbus_device *dev,
                          const struct xenbus_device_id *id)
 {
        int err, vdevice;
-       unsigned int r_index;
        struct blkfront_info *info;
-       unsigned int backend_max_queues = 0;
 
        /* FIXME: Use dynamic device id if this is not set. */
        err = xenbus_scanf(XBT_NIL, dev->nodename,
@@ -1936,33 +1971,10 @@ static int blkfront_probe(struct xenbus_device *dev,
        }
 
        info->xbdev = dev;
-       /* Check if backend supports multiple queues. */
-       err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-                          "multi-queue-max-queues", "%u", &backend_max_queues);
-       if (err < 0)
-               backend_max_queues = 1;
-
-       info->nr_rings = min(backend_max_queues, xen_blkif_max_queues);
-       /* We need at least one ring. */
-       if (!info->nr_rings)
-               info->nr_rings = 1;
-
-       info->rinfo = kzalloc(sizeof(struct blkfront_ring_info) * info->nr_rings, GFP_KERNEL);
-       if (!info->rinfo) {
-               xenbus_dev_fatal(dev, -ENOMEM, "allocating ring_info structure");
+       err = negotiate_mq(info);
+       if (err) {
                kfree(info);
-               return -ENOMEM;
-       }
-
-       for (r_index = 0; r_index < info->nr_rings; r_index++) {
-               struct blkfront_ring_info *rinfo;
-
-               rinfo = &info->rinfo[r_index];
-               INIT_LIST_HEAD(&rinfo->indirect_pages);
-               INIT_LIST_HEAD(&rinfo->grants);
-               rinfo->dev_info = info;
-               INIT_WORK(&rinfo->work, blkif_restart_queue);
-               spin_lock_init(&rinfo->ring_lock);
+               return err;
        }
 
        mutex_init(&info->mutex);
@@ -2123,12 +2135,16 @@ static int blkif_recover(struct blkfront_info *info)
 static int blkfront_resume(struct xenbus_device *dev)
 {
        struct blkfront_info *info = dev_get_drvdata(&dev->dev);
-       int err;
+       int err = 0;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
 
        blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
 
+       err = negotiate_mq(info);
+       if (err)
+               return err;
+
        err = talk_to_blkback(dev, info);
 
        /*
index ec6af15950622ef2448cfda759fd73bb141286f0..cf50fd2e96df8d886580e9f26885b6f5b4b18c2c 100644 (file)
@@ -169,6 +169,17 @@ config BT_HCIUART_QCA
 
          Say Y here to compile support for QCA protocol.
 
+config BT_HCIUART_AG6XX
+       bool "Intel AG6XX protocol support"
+       depends on BT_HCIUART
+       select BT_HCIUART_H4
+       select BT_INTEL
+       help
+         The Intel/AG6XX protocol support enables Bluetooth HCI over serial
+         port interface for Intel ibt 2.1 Bluetooth controllers.
+
+         Say Y here to compile support for Intel AG6XX protocol.
+
 config BT_HCIBCM203X
        tristate "HCI BCM203x USB driver"
        depends on USB
index 07c9cf381e5aeb2585a18beb0f9aa98a75862e9e..9c18939fc5c98fe02d0bfa039331c62f30d2632b 100644 (file)
@@ -36,6 +36,7 @@ hci_uart-$(CONFIG_BT_HCIUART_3WIRE)   += hci_h5.o
 hci_uart-$(CONFIG_BT_HCIUART_INTEL)    += hci_intel.o
 hci_uart-$(CONFIG_BT_HCIUART_BCM)      += hci_bcm.o
 hci_uart-$(CONFIG_BT_HCIUART_QCA)      += hci_qca.o
+hci_uart-$(CONFIG_BT_HCIUART_AG6XX)    += hci_ag6xx.o
 hci_uart-objs                          := $(hci_uart-y)
 
 ccflags-y += -D__CHECK_ENDIAN__
index fa893c3ec4087f39382f3dc83b968c9859f41cca..93747389dd289d99961bd88d3126a4a2c5d3764a 100644 (file)
@@ -82,6 +82,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe05f) },
        { USB_DEVICE(0x0489, 0xe076) },
        { USB_DEVICE(0x0489, 0xe078) },
+       { USB_DEVICE(0x0489, 0xe095) },
        { USB_DEVICE(0x04c5, 0x1330) },
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
@@ -92,6 +93,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x300d) },
        { USB_DEVICE(0x04CA, 0x300f) },
        { USB_DEVICE(0x04CA, 0x3010) },
+       { USB_DEVICE(0x04CA, 0x3014) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0930, 0x021c) },
        { USB_DEVICE(0x0930, 0x0220) },
@@ -113,6 +115,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x13d3, 0x3375) },
        { USB_DEVICE(0x13d3, 0x3393) },
+       { USB_DEVICE(0x13d3, 0x3395) },
        { USB_DEVICE(0x13d3, 0x3402) },
        { USB_DEVICE(0x13d3, 0x3408) },
        { USB_DEVICE(0x13d3, 0x3423) },
@@ -144,6 +147,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe095), .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 },
@@ -154,6 +158,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -175,6 +180,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { 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, 0x3395), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
@@ -497,6 +503,7 @@ static int ath3k_probe(struct usb_interface *intf,
        /* match device ID in ath3k blacklist table */
        if (!id->driver_info) {
                const struct usb_device_id *match;
+
                match = usb_match_id(intf, ath3k_blist_tbl);
                if (match)
                        id = match;
index 0b697946e9bc7d91abf76b0dbfa7384fec4ce9b8..fdb44829ab6ff7009597a1b0080b741bcd09b9b9 100644 (file)
@@ -467,7 +467,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
        err = request_firmware(&fw, fw_name, &hdev->dev);
        if (err < 0) {
                BT_INFO("%s: BCM: Patch %s not found", hdev->name, fw_name);
-               return 0;
+               goto done;
        }
 
        btbcm_patchram(hdev, fw);
@@ -501,6 +501,7 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
        BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
        kfree_skb(skb);
 
+done:
        btbcm_check_bdaddr(hdev);
 
        set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
index a191e318fab88a92fa52641b3d27d1ea94ced0ce..97f3bba93a8e2c5c010fa234321caaeca3737cf4 100644 (file)
@@ -196,6 +196,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe095), .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 },
@@ -206,6 +207,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
@@ -227,6 +229,7 @@ static const struct usb_device_id blacklist_table[] = {
        { 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, 0x3395), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/hci_ag6xx.c b/drivers/bluetooth/hci_ag6xx.c
new file mode 100644 (file)
index 0000000..6923d17
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ *
+ *  Bluetooth HCI UART driver for Intel/AG6xx devices
+ *
+ *  Copyright (C) 2016  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+#include "btintel.h"
+
+struct ag6xx_data {
+       struct sk_buff *rx_skb;
+       struct sk_buff_head txq;
+};
+
+struct pbn_entry {
+       __le32 addr;
+       __le32 plen;
+       __u8 data[0];
+} __packed;
+
+static int ag6xx_open(struct hci_uart *hu)
+{
+       struct ag6xx_data *ag6xx;
+
+       BT_DBG("hu %p", hu);
+
+       ag6xx = kzalloc(sizeof(*ag6xx), GFP_KERNEL);
+       if (!ag6xx)
+               return -ENOMEM;
+
+       skb_queue_head_init(&ag6xx->txq);
+
+       hu->priv = ag6xx;
+       return 0;
+}
+
+static int ag6xx_close(struct hci_uart *hu)
+{
+       struct ag6xx_data *ag6xx = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ag6xx->txq);
+       kfree_skb(ag6xx->rx_skb);
+       kfree(ag6xx);
+
+       hu->priv = NULL;
+       return 0;
+}
+
+static int ag6xx_flush(struct hci_uart *hu)
+{
+       struct ag6xx_data *ag6xx = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ag6xx->txq);
+       return 0;
+}
+
+static struct sk_buff *ag6xx_dequeue(struct hci_uart *hu)
+{
+       struct ag6xx_data *ag6xx = hu->priv;
+       struct sk_buff *skb;
+
+       skb = skb_dequeue(&ag6xx->txq);
+       if (!skb)
+               return skb;
+
+       /* Prepend skb with frame type */
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+       return skb;
+}
+
+static int ag6xx_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+       struct ag6xx_data *ag6xx = hu->priv;
+
+       skb_queue_tail(&ag6xx->txq, skb);
+       return 0;
+}
+
+static const struct h4_recv_pkt ag6xx_recv_pkts[] = {
+       { H4_RECV_ACL,    .recv = hci_recv_frame   },
+       { H4_RECV_SCO,    .recv = hci_recv_frame   },
+       { H4_RECV_EVENT,  .recv = hci_recv_frame   },
+};
+
+static int ag6xx_recv(struct hci_uart *hu, const void *data, int count)
+{
+       struct ag6xx_data *ag6xx = hu->priv;
+
+       if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+               return -EUNATCH;
+
+       ag6xx->rx_skb = h4_recv_buf(hu->hdev, ag6xx->rx_skb, data, count,
+                                   ag6xx_recv_pkts,
+                                   ARRAY_SIZE(ag6xx_recv_pkts));
+       if (IS_ERR(ag6xx->rx_skb)) {
+               int err = PTR_ERR(ag6xx->rx_skb);
+               bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
+               ag6xx->rx_skb = NULL;
+               return err;
+       }
+
+       return count;
+}
+
+static int intel_mem_write(struct hci_dev *hdev, u32 addr, u32 plen,
+                          const void *data)
+{
+       /* Can write a maximum of 247 bytes per HCI command.
+        * HCI cmd Header (3), Intel mem write header (6), data (247).
+        */
+       while (plen > 0) {
+               struct sk_buff *skb;
+               u8 cmd_param[253], fragment_len = (plen > 247) ? 247 : plen;
+               __le32 leaddr = cpu_to_le32(addr);
+
+               memcpy(cmd_param, &leaddr, 4);
+               cmd_param[4] = 0;
+               cmd_param[5] = fragment_len;
+               memcpy(cmd_param + 6, data, fragment_len);
+
+               skb = __hci_cmd_sync(hdev, 0xfc8e, fragment_len + 6, cmd_param,
+                                    HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb))
+                       return PTR_ERR(skb);
+               kfree_skb(skb);
+
+               plen -= fragment_len;
+               data += fragment_len;
+               addr += fragment_len;
+       }
+
+       return 0;
+}
+
+static int ag6xx_setup(struct hci_uart *hu)
+{
+       struct hci_dev *hdev = hu->hdev;
+       struct sk_buff *skb;
+       struct intel_version ver;
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       char fwname[64];
+       bool patched = false;
+       int err;
+
+       hu->hdev->set_diag = btintel_set_diag;
+       hu->hdev->set_bdaddr = btintel_set_bdaddr;
+
+       err = btintel_enter_mfg(hdev);
+       if (err)
+               return err;
+
+       err = btintel_read_version(hdev, &ver);
+       if (err)
+               return err;
+
+       btintel_version_info(hdev, &ver);
+
+       /* The hardware platform number has a fixed value of 0x37 and
+        * for now only accept this single value.
+        */
+       if (ver.hw_platform != 0x37) {
+               bt_dev_err(hdev, "Unsupported Intel hardware platform: 0x%X",
+                          ver.hw_platform);
+               return -EINVAL;
+       }
+
+       /* Only the hardware variant iBT 2.1 (AG6XX) is supported by this
+        * firmware setup method.
+        */
+       if (ver.hw_variant != 0x0a) {
+               bt_dev_err(hdev, "Unsupported Intel hardware variant: 0x%x",
+                          ver.hw_variant);
+               return -EINVAL;
+       }
+
+       snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bddata",
+                ver.hw_platform, ver.hw_variant);
+
+       err = request_firmware(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to open Intel bddata file: %s (%d)",
+                          fwname, err);
+               goto patch;
+       }
+       fw_ptr = fw->data;
+
+       bt_dev_info(hdev, "Applying bddata (%s)", fwname);
+
+       skb = __hci_cmd_sync_ev(hdev, 0xfc2f, fw->size, fw->data,
+                               HCI_EV_CMD_STATUS, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Applying bddata failed (%ld)", PTR_ERR(skb));
+               release_firmware(fw);
+               return PTR_ERR(skb);
+       }
+       kfree_skb(skb);
+
+       release_firmware(fw);
+
+patch:
+       /* If there is no applied patch, fw_patch_num is always 0x00. In other
+        * cases, current firmware is already patched. No need to patch it.
+        */
+       if (ver.fw_patch_num) {
+               bt_dev_info(hdev, "Device is already patched. patch num: %02x",
+                           ver.fw_patch_num);
+               patched = true;
+               goto complete;
+       }
+
+       snprintf(fwname, sizeof(fwname),
+                "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.pbn",
+                ver.hw_platform, ver.hw_variant, ver.hw_revision,
+                ver.fw_variant,  ver.fw_revision, ver.fw_build_num,
+                ver.fw_build_ww, ver.fw_build_yy);
+
+       err = request_firmware(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               bt_dev_err(hdev, "Failed to open Intel patch file: %s(%d)",
+                          fwname, err);
+               goto complete;
+       }
+       fw_ptr = fw->data;
+
+       bt_dev_info(hdev, "Patching firmware file (%s)", fwname);
+
+       /* PBN patch file contains a list of binary patches to be applied on top
+        * of the embedded firmware. Each patch entry header contains the target
+        * address and patch size.
+        *
+        * Patch entry:
+        * | addr(le) | patch_len(le) | patch_data |
+        * | 4 Bytes  |    4 Bytes    |   n Bytes  |
+        *
+        * PBN file is terminated by a patch entry whose address is 0xffffffff.
+        */
+       while (fw->size > fw_ptr - fw->data) {
+               struct pbn_entry *pbn = (void *)fw_ptr;
+               u32 addr, plen;
+
+               if (pbn->addr == 0xffffffff) {
+                       bt_dev_info(hdev, "Patching complete");
+                       patched = true;
+                       break;
+               }
+
+               addr = le32_to_cpu(pbn->addr);
+               plen = le32_to_cpu(pbn->plen);
+
+               if (fw->data + fw->size <= pbn->data + plen) {
+                       bt_dev_info(hdev, "Invalid patch len (%d)", plen);
+                       break;
+               }
+
+               bt_dev_info(hdev, "Patching %td/%zu", (fw_ptr - fw->data),
+                           fw->size);
+
+               err = intel_mem_write(hdev, addr, plen, pbn->data);
+               if (err) {
+                       bt_dev_err(hdev, "Patching failed");
+                       break;
+               }
+
+               fw_ptr = pbn->data + plen;
+       }
+
+       release_firmware(fw);
+
+complete:
+       /* Exit manufacturing mode and reset */
+       err = btintel_exit_mfg(hdev, true, patched);
+       if (err)
+               return err;
+
+       /* Set the event mask for Intel specific vendor events. This enables
+        * a few extra events that are useful during general operation.
+        */
+       btintel_set_event_mask_mfg(hdev, false);
+
+       btintel_check_bdaddr(hdev);
+       return 0;
+}
+
+static const struct hci_uart_proto ag6xx_proto = {
+       .id             = HCI_UART_AG6XX,
+       .name           = "AG6XX",
+       .manufacturer   = 2,
+       .open           = ag6xx_open,
+       .close          = ag6xx_close,
+       .flush          = ag6xx_flush,
+       .setup          = ag6xx_setup,
+       .recv           = ag6xx_recv,
+       .enqueue        = ag6xx_enqueue,
+       .dequeue        = ag6xx_dequeue,
+};
+
+int __init ag6xx_init(void)
+{
+       return hci_uart_register_proto(&ag6xx_proto);
+}
+
+int __exit ag6xx_deinit(void)
+{
+       return hci_uart_unregister_proto(&ag6xx_proto);
+}
index 5f3de181e7443632746ef77d6ee73ec9a26494fa..bb4c5a00aea076059d4114ddb7f23466ba70c8c2 100644 (file)
@@ -820,10 +820,12 @@ static const struct acpi_device_id bcm_acpi_match[] = {
        { "BCM2E3D", 0 },
        { "BCM2E3F", 0 },
        { "BCM2E40", 0 },
+       { "BCM2E54", 0 },
        { "BCM2E64", 0 },
        { "BCM2E65", 0 },
        { "BCM2E67", 0 },
        { "BCM2E7B", 0 },
+       { "BCM2E7C", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
index 3d63ea37bd4ca683b37c7ea7661be70163b6590c..91d605147b10e45a721941582ac366185afb0da3 100644 (file)
@@ -488,7 +488,7 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed)
        clear_bit(STATE_BOOTING, &intel->flags);
 
        /* In case of timeout, try to continue anyway */
-       if (err && err != ETIMEDOUT)
+       if (err && err != -ETIMEDOUT)
                return err;
 
        bt_dev_info(hdev, "Change controller speed to %d", speed);
@@ -581,7 +581,7 @@ static int intel_setup(struct hci_uart *hu)
        clear_bit(STATE_BOOTING, &intel->flags);
 
        /* In case of timeout, try to continue anyway */
-       if (err && err != ETIMEDOUT)
+       if (err && err != -ETIMEDOUT)
                return err;
 
        set_bit(STATE_BOOTLOADER, &intel->flags);
index 73202624133b4e180a45c75f12ae329cc934bac0..c00168a5bb800f3e74f6924f197e668020f02eb9 100644 (file)
@@ -804,6 +804,9 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_QCA
        qca_init();
 #endif
+#ifdef CONFIG_BT_HCIUART_AG6XX
+       ag6xx_init();
+#endif
 
        return 0;
 }
@@ -836,6 +839,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_QCA
        qca_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_AG6XX
+       ag6xx_deinit();
+#endif
 
        /* Release tty registration of line discipline */
        err = tty_unregister_ldisc(N_HCI);
index 82c92f1b65b4af7c317c8a0af91723a481ac3874..4814ff08f4270156c70aaced894ec0cb2a5d5f63 100644 (file)
@@ -35,7 +35,7 @@
 #define HCIUARTGETFLAGS                _IOR('U', 204, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO     9
+#define HCI_UART_MAX_PROTO     10
 
 #define HCI_UART_H4    0
 #define HCI_UART_BCSP  1
@@ -46,6 +46,7 @@
 #define HCI_UART_INTEL 6
 #define HCI_UART_BCM   7
 #define HCI_UART_QCA   8
+#define HCI_UART_AG6XX 9
 
 #define HCI_UART_RAW_DEVICE    0
 #define HCI_UART_RESET_ON_INIT 1
@@ -182,3 +183,8 @@ int bcm_deinit(void);
 int qca_init(void);
 int qca_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_AG6XX
+int ag6xx_init(void);
+int ag6xx_deinit(void);
+#endif
index 129d47bcc5fc8d1b9d0ef0e087bbf36cee1336be..9a92c072a485def0b2730340503d1984d5a6dc1d 100644 (file)
@@ -132,7 +132,7 @@ config SUNXI_RSB
          and AC100/AC200 ICs.
 
 config UNIPHIER_SYSTEM_BUS
-       bool "UniPhier System Bus driver"
+       tristate "UniPhier System Bus driver"
        depends on ARCH_UNIPHIER && OF
        default y
        help
index 6575c0fe6a4ea3a1e3bc1bae99010eefd9d7ff94..c3cb76b363c63c54d67343dacf4c9ec20032a95f 100644 (file)
@@ -192,8 +192,10 @@ static int __init vexpress_config_init(void)
        /* Need the config devices early, before the "normal" devices... */
        for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
                err = vexpress_config_populate(node);
-               if (err)
+               if (err) {
+                       of_node_put(node);
                        break;
+               }
        }
 
        return err;
index 240b6cf1d97c66fc828f97df90726cb64d500fba..be54e5331a4517899e0e4ace0c48418cbb082a0e 100644 (file)
@@ -42,7 +42,7 @@
 /*
  * The High Precision Event Timer driver.
  * This driver is closely modelled after the rtc.c driver.
- * http://www.intel.com/hardwaredesign/hpetspec_1.pdf
+ * See HPET spec revision 1.
  */
 #define        HPET_USER_FREQ  (64)
 #define        HPET_DRIFT      (500)
index 9fda22e3387e59030b4a16f4ab1712bb1555b0ce..7fddd8696211f0320011c964a88a37a16133c4ba 100644 (file)
@@ -68,6 +68,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/acpi.h>
 
 #ifdef CONFIG_PARISC
 #include <asm/hardware.h>      /* for register_parisc_driver() stuff */
@@ -2054,8 +2055,6 @@ static int hardcode_find_bmc(void)
 
 #ifdef CONFIG_ACPI
 
-#include <linux/acpi.h>
-
 /*
  * Once we get an ACPI failure, we don't try any more, because we go
  * through the tables sequentially.  Once we don't find a table, there
index d0da5d852d41e5588bb9bd192431a403a9696848..b583e53366306db870a0d61918156f41985f075e 100644 (file)
@@ -1818,6 +1818,28 @@ unsigned int get_random_int(void)
 }
 EXPORT_SYMBOL(get_random_int);
 
+/*
+ * Same as get_random_int(), but returns unsigned long.
+ */
+unsigned long get_random_long(void)
+{
+       __u32 *hash;
+       unsigned long ret;
+
+       if (arch_get_random_long(&ret))
+               return ret;
+
+       hash = get_cpu_var(get_random_int_hash);
+
+       hash[0] += current->pid + jiffies + random_get_entropy();
+       md5_transform(hash, random_int_secret);
+       ret = *(unsigned long *)hash;
+       put_cpu_var(get_random_int_hash);
+
+       return ret;
+}
+EXPORT_SYMBOL(get_random_long);
+
 /*
  * randomize_range() returns a start address such that
  *
index b038e36660587aaf97d4c3b41de17d1175635694..bae4be6501dfb06a51dc0aaa3befb91b47156ca0 100644 (file)
@@ -43,7 +43,7 @@ obj-$(CONFIG_COMMON_CLK_SI514)                += clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI570)         += clk-si570.o
 obj-$(CONFIG_COMMON_CLK_CDCE925)       += clk-cdce925.o
 obj-$(CONFIG_ARCH_STM32)               += clk-stm32f4.o
-obj-$(CONFIG_ARCH_TANGOX)              += clk-tango4.o
+obj-$(CONFIG_ARCH_TANGO              += clk-tango4.o
 obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)                        += clk-u300.o
 obj-$(CONFIG_ARCH_VT8500)              += clk-vt8500.o
index 19fed65587e8206c20f6ee13a1b736276e8922ae..7b09a265d79fc8595a31332ecd40480beaed7bc5 100644 (file)
@@ -289,7 +289,7 @@ static void __init of_gpio_clk_setup(struct device_node *node,
 
        num_parents = of_clk_get_parent_count(node);
        if (num_parents < 0)
-               return;
+               num_parents = 0;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
index cd0f2726f5e0dd0da33b06e4518f02fc231cf1f7..89e9ca78bb947ec2ff8242d5d826ccf8449d6259 100644 (file)
@@ -299,7 +299,7 @@ static int scpi_clocks_probe(struct platform_device *pdev)
        /* Add the virtual cpufreq device */
        cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
                                                      -1, NULL, 0);
-       if (!cpufreq_dev)
+       if (IS_ERR(cpufreq_dev))
                pr_warn("unable to register cpufreq device");
 
        return 0;
index d5c5bfa35a5aef734a47e6d199c410eebe237d75..3e0b52daa35f8814a413ccfe7599ac80a3f59e8f 100644 (file)
@@ -247,7 +247,7 @@ static struct clk_onecell_data dove_divider_data = {
 
 void __init dove_divider_clk_init(struct device_node *np)
 {
-       void *base;
+       void __iomem *base;
 
        base = of_iomap(np, 0);
        if (WARN_ON(!base))
index cf73e539e9f63aee727a5f3bab2e2e28fae4e1d9..070037a29ea5842ba6cd332563570fc1ffd8689c 100644 (file)
@@ -3587,7 +3587,6 @@ static const struct regmap_config gcc_apq8084_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x1fc0,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_apq8084_desc = {
index b692ae881d6a978a8d1e665dd09fa52820f96a90..dd5402bac62029824fd059a353d0c00d4e8576fc 100644 (file)
@@ -3005,7 +3005,6 @@ static const struct regmap_config gcc_ipq806x_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x3e40,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_ipq806x_desc = {
index f6a2b14dfec4ecd026282d01167278df0f2c6c3b..ad413036f7c783ee0ba8576bf512dfe3dea08dda 100644 (file)
@@ -2702,7 +2702,6 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x363c,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8660_desc = {
index e3bf09d7d0ef07f5672f9933dca6dd6896daff4c..8cc9b2868b41a83c1621d0b27bc18598888a6939 100644 (file)
@@ -3336,7 +3336,6 @@ static const struct regmap_config gcc_msm8916_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x80000,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8916_desc = {
index f31111e32d44314f7c808aa56c3b6f78f906bbbb..983dd7dc89a7970e3c1c8d35a427a56b48959929 100644 (file)
@@ -3468,7 +3468,6 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x3660,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct regmap_config gcc_apq8064_regmap_config = {
@@ -3477,7 +3476,6 @@ static const struct regmap_config gcc_apq8064_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x3880,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8960_desc = {
index df164d618e34682ba4f99f9e517c7b1bdd8500fd..335952db309bd3260c4c86cd048417fb43ac9cbd 100644 (file)
@@ -2680,7 +2680,6 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x1fc0,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc gcc_msm8974_desc = {
index 62e79fadd5f7aee5772bef7760f9c7e20e721501..db3998e5e2d83d77a5b07f8d1e29490b2e532f6d 100644 (file)
@@ -419,7 +419,6 @@ static const struct regmap_config lcc_ipq806x_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0xfc,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc lcc_ipq806x_desc = {
index bf95bb0ea1b8c536a5e058de40e33edffa412021..4fcf9d1d233c0a0c64c2455efcdd11015da89b18 100644 (file)
@@ -524,7 +524,6 @@ static const struct regmap_config lcc_msm8960_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0xfc,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc lcc_msm8960_desc = {
index 1e703fda8a0f8ee4f18a0434a7ed073c1762ed6a..30777f9f1a439eef1ad5e8d4446017d7f3999392 100644 (file)
@@ -3368,7 +3368,6 @@ static const struct regmap_config mmcc_apq8084_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x5104,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_apq8084_desc = {
index d73a048d3b9dc59c62fc3b413a59121d3b47fa06..00e36192a1defe9131f1f1505f89b88b574f4284 100644 (file)
@@ -3029,7 +3029,6 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x334,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct regmap_config mmcc_apq8064_regmap_config = {
@@ -3038,7 +3037,6 @@ static const struct regmap_config mmcc_apq8064_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x350,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_msm8960_desc = {
index bbe28ed936692da75079aace6aa1cbc1e2ce23e4..9d790bcadf25a75a360f8d5aebfdf4ab50237c61 100644 (file)
@@ -2594,7 +2594,6 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
        .val_bits       = 32,
        .max_register   = 0x5104,
        .fast_io        = true,
-       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static const struct qcom_cc_desc mmcc_msm8974_desc = {
index ebce98033fbb76ea687d439b5842e707f62eeb80..bc7fbac83ab74dfca9e534401bc430f629d01357 100644 (file)
@@ -133,7 +133,7 @@ PNAME(mux_spdif_p)  = { "spdif_src", "spdif_frac", "xin12m" };
 PNAME(mux_uart0_p)     = { "uart0_src", "uart0_frac", "xin24m" };
 PNAME(mux_uart1_p)     = { "uart1_src", "uart1_frac", "xin24m" };
 PNAME(mux_uart2_p)     = { "uart2_src", "uart2_frac", "xin24m" };
-PNAME(mux_mac_p)       = { "mac_pll_src", "ext_gmac" };
+PNAME(mux_mac_p)       = { "mac_pll_src", "rmii_clkin" };
 PNAME(mux_dclk_p)      = { "dclk_lcdc", "dclk_cru" };
 
 static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
@@ -224,16 +224,16 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(2), 2, GFLAGS),
 
        COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
-                       RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
+                       RK2928_CLKSEL_CON(2), 4, 1, MFLAGS,
                        RK2928_CLKGATE_CON(1), 0, GFLAGS),
        COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
-                       RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
+                       RK2928_CLKSEL_CON(2), 5, 1, MFLAGS,
                        RK2928_CLKGATE_CON(1), 1, GFLAGS),
        COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
-                       RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
+                       RK2928_CLKSEL_CON(2), 6, 1, MFLAGS,
                        RK2928_CLKGATE_CON(2), 4, GFLAGS),
        COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
-                       RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
+                       RK2928_CLKSEL_CON(2), 7, 1, MFLAGS,
                        RK2928_CLKGATE_CON(2), 5, GFLAGS),
 
        MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
@@ -242,11 +242,11 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
                        RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
                        RK2928_CLKGATE_CON(1), 8, GFLAGS),
        COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
-                       RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
-                       RK2928_CLKGATE_CON(1), 8, GFLAGS),
+                       RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
+                       RK2928_CLKGATE_CON(1), 10, GFLAGS),
        COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
-                       RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
-                       RK2928_CLKGATE_CON(1), 8, GFLAGS),
+                       RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
+                       RK2928_CLKGATE_CON(1), 12, GFLAGS),
        COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(17), 0,
                        RK2928_CLKGATE_CON(1), 9, GFLAGS,
@@ -279,13 +279,13 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(3), 2, GFLAGS),
 
        COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
-                       RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
+                       RK2928_CLKSEL_CON(12), 8, 2, MFLAGS,
                        RK2928_CLKGATE_CON(2), 11, GFLAGS),
        DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
                        RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
 
        COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
-                       RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
+                       RK2928_CLKSEL_CON(12), 10, 2, MFLAGS,
                        RK2928_CLKGATE_CON(2), 13, GFLAGS),
        DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
                        RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
@@ -344,12 +344,12 @@ static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
                        RK2928_CLKGATE_CON(10), 5, GFLAGS),
 
        COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
-                       RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
+                       RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 9, 5, DFLAGS),
        MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
                        RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
 
        COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
-                       RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
+                       RK2928_CLKSEL_CON(21), 4, 5, DFLAGS,
                        RK2928_CLKGATE_CON(2), 6, GFLAGS),
 
        MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
index be0ede52226994a0ae7248c8098285e0ebfd4a86..21f3ea909fabdb7c4f753cd4ed817035c15a31e0 100644 (file)
@@ -780,13 +780,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
        GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS),
 
        /* pclk_pd_alive gates */
-       GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS),
-       GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS),
-       GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS),
-       GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS),
-       GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS),
-       GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS),
-       GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS),
+       GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 13, GFLAGS),
+       GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 12, GFLAGS),
+       GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 9, GFLAGS),
+       GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(22), 8, GFLAGS),
+       GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 3, GFLAGS),
+       GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 2, GFLAGS),
+       GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(22), 1, GFLAGS),
 
        /*
         * pclk_vio gates
@@ -796,12 +796,12 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
        GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS),
 
        /* pclk_pd_pmu gates */
-       GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS),
-       GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS),
-       GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS),
-       GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
-       GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS),
-       GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS),
+       GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 5, GFLAGS),
+       GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(23), 4, GFLAGS),
+       GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 3, GFLAGS),
+       GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 2, GFLAGS),
+       GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 1, GFLAGS),
+       GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(23), 0, GFLAGS),
 
        /* timer gates */
        GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS),
index e1fe8f35d45c47c553997845657e09d3b71ca9a1..74e7544f861ba083f63f1d5aa886a7a90b0f295f 100644 (file)
@@ -450,8 +450,10 @@ static int load_timings_from_dt(struct tegra_clk_emc *tegra,
                struct emc_timing *timing = tegra->timings + (i++);
 
                err = load_one_timing_from_dt(tegra, timing, child);
-               if (err)
+               if (err) {
+                       of_node_put(child);
                        return err;
+               }
 
                timing->ram_code = ram_code;
        }
@@ -499,9 +501,9 @@ struct clk *tegra_clk_register_emc(void __iomem *base, struct device_node *np,
                 * fuses until the apbmisc driver is loaded.
                 */
                err = load_timings_from_dt(tegra, node, node_ram_code);
+               of_node_put(node);
                if (err)
                        return ERR_PTR(err);
-               of_node_put(node);
                break;
        }
 
index 19ce0738ee764bb13e9dfde5ca542fd2cf472e9a..62ea38187b715814ac5d7b5265cbd4cd934a22c3 100644 (file)
@@ -11,6 +11,7 @@ enum clk_id {
        tegra_clk_afi,
        tegra_clk_amx,
        tegra_clk_amx1,
+       tegra_clk_apb2ape,
        tegra_clk_apbdma,
        tegra_clk_apbif,
        tegra_clk_ape,
index a534bfab30b39ee53c81a89c3a5c5b1d2979144e..6ac3f843e7caa3a8abb6513a0eb9fc2c829d3a39 100644 (file)
 #define PLLE_SS_DISABLE (PLLE_SS_CNTL_BYPASS_SS | PLLE_SS_CNTL_INTERP_RESET |\
                                PLLE_SS_CNTL_SSC_BYP)
 #define PLLE_SS_MAX_MASK 0x1ff
-#define PLLE_SS_MAX_VAL 0x25
+#define PLLE_SS_MAX_VAL_TEGRA114 0x25
+#define PLLE_SS_MAX_VAL_TEGRA210 0x21
 #define PLLE_SS_INC_MASK (0xff << 16)
 #define PLLE_SS_INC_VAL (0x1 << 16)
 #define PLLE_SS_INCINTRV_MASK (0x3f << 24)
-#define PLLE_SS_INCINTRV_VAL (0x20 << 24)
+#define PLLE_SS_INCINTRV_VAL_TEGRA114 (0x20 << 24)
+#define PLLE_SS_INCINTRV_VAL_TEGRA210 (0x23 << 24)
 #define PLLE_SS_COEFFICIENTS_MASK \
        (PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK)
-#define PLLE_SS_COEFFICIENTS_VAL \
-       (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
+#define PLLE_SS_COEFFICIENTS_VAL_TEGRA114 \
+       (PLLE_SS_MAX_VAL_TEGRA114 | PLLE_SS_INC_VAL |\
+        PLLE_SS_INCINTRV_VAL_TEGRA114)
+#define PLLE_SS_COEFFICIENTS_VAL_TEGRA210 \
+       (PLLE_SS_MAX_VAL_TEGRA210 | PLLE_SS_INC_VAL |\
+        PLLE_SS_INCINTRV_VAL_TEGRA210)
 
 #define PLLE_AUX_PLLP_SEL      BIT(2)
 #define PLLE_AUX_USE_LOCKDET   BIT(3)
@@ -880,7 +886,7 @@ static int clk_plle_training(struct tegra_clk_pll *pll)
 static int clk_plle_enable(struct clk_hw *hw)
 {
        struct tegra_clk_pll *pll = to_clk_pll(hw);
-       unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+       unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
        struct tegra_clk_pll_freq_table sel;
        u32 val;
        int err;
@@ -1378,7 +1384,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        u32 val;
        int ret;
        unsigned long flags = 0;
-       unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+       unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
 
        if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
                return -EINVAL;
@@ -1401,7 +1407,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        val |= PLLE_MISC_IDDQ_SW_CTRL;
        val &= ~PLLE_MISC_IDDQ_SW_VALUE;
        val |= PLLE_MISC_PLLE_PTS;
-       val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+       val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK);
        pll_writel_misc(val, pll);
        udelay(5);
 
@@ -1428,7 +1434,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
        val = pll_readl(PLLE_SS_CTRL, pll);
        val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
        val &= ~PLLE_SS_COEFFICIENTS_MASK;
-       val |= PLLE_SS_COEFFICIENTS_VAL;
+       val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA114;
        pll_writel(val, PLLE_SS_CTRL, pll);
        val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
        pll_writel(val, PLLE_SS_CTRL, pll);
@@ -2012,9 +2018,9 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
        struct tegra_clk_pll *pll = to_clk_pll(hw);
        struct tegra_clk_pll_freq_table sel;
        u32 val;
-       int ret;
+       int ret = 0;
        unsigned long flags = 0;
-       unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
+       unsigned long input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
 
        if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate))
                return -EINVAL;
@@ -2022,22 +2028,20 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
        if (pll->lock)
                spin_lock_irqsave(pll->lock, flags);
 
+       val = pll_readl(pll->params->aux_reg, pll);
+       if (val & PLLE_AUX_SEQ_ENABLE)
+               goto out;
+
        val = pll_readl_base(pll);
        val &= ~BIT(30); /* Disable lock override */
        pll_writel_base(val, pll);
 
-       val = pll_readl(pll->params->aux_reg, pll);
-       val |= PLLE_AUX_ENABLE_SWCTL;
-       val &= ~PLLE_AUX_SEQ_ENABLE;
-       pll_writel(val, pll->params->aux_reg, pll);
-       udelay(1);
-
        val = pll_readl_misc(pll);
        val |= PLLE_MISC_LOCK_ENABLE;
        val |= PLLE_MISC_IDDQ_SW_CTRL;
        val &= ~PLLE_MISC_IDDQ_SW_VALUE;
        val |= PLLE_MISC_PLLE_PTS;
-       val |= PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK;
+       val &= ~(PLLE_MISC_VREG_BG_CTRL_MASK | PLLE_MISC_VREG_CTRL_MASK);
        pll_writel_misc(val, pll);
        udelay(5);
 
@@ -2067,7 +2071,7 @@ static int clk_plle_tegra210_enable(struct clk_hw *hw)
        val = pll_readl(PLLE_SS_CTRL, pll);
        val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT);
        val &= ~PLLE_SS_COEFFICIENTS_MASK;
-       val |= PLLE_SS_COEFFICIENTS_VAL;
+       val |= PLLE_SS_COEFFICIENTS_VAL_TEGRA210;
        pll_writel(val, PLLE_SS_CTRL, pll);
        val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS);
        pll_writel(val, PLLE_SS_CTRL, pll);
@@ -2104,15 +2108,25 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
        if (pll->lock)
                spin_lock_irqsave(pll->lock, flags);
 
+       /* If PLLE HW sequencer is enabled, SW should not disable PLLE */
+       val = pll_readl(pll->params->aux_reg, pll);
+       if (val & PLLE_AUX_SEQ_ENABLE)
+               goto out;
+
        val = pll_readl_base(pll);
        val &= ~PLLE_BASE_ENABLE;
        pll_writel_base(val, pll);
 
+       val = pll_readl(pll->params->aux_reg, pll);
+       val |= PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL;
+       pll_writel(val, pll->params->aux_reg, pll);
+
        val = pll_readl_misc(pll);
        val |= PLLE_MISC_IDDQ_SW_CTRL | PLLE_MISC_IDDQ_SW_VALUE;
        pll_writel_misc(val, pll);
        udelay(1);
 
+out:
        if (pll->lock)
                spin_unlock_irqrestore(pll->lock, flags);
 }
index 6ad381a888a6176801494c60bcc4f057f23ebe82..ea2b9cbf9e70b0c10204d5d34dc96ab929d36427 100644 (file)
@@ -773,7 +773,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
        XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
        MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
-       MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
+       MUX8("nvenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
        MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
        MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
        MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
@@ -782,7 +782,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
        MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
        MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
-       MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
+       I2C("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, tegra_clk_vi_i2c),
        MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
        MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
        MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
@@ -829,6 +829,7 @@ static struct tegra_periph_init_data gate_clks[] = {
        GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0),
        GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0),
        GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0),
+       GATE("apb2ape", "clk_m", 107, 0, tegra_clk_apb2ape, 0),
 };
 
 static struct tegra_periph_init_data div_clks[] = {
index 4559a20e3af6e424e52c7b08930cd7664965fea2..474de0f0c26d80b0f9b20ff845575ce049165038 100644 (file)
@@ -67,7 +67,7 @@ static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
                                         "pll_p", "pll_p_out4", "unused",
                                         "unused", "pll_x", "pll_x_out0" };
 
-const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
+static const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
        .gen = gen4,
        .sclk_parents = sclk_parents,
        .cclk_g_parents = cclk_g_parents,
@@ -93,7 +93,7 @@ static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unu
                                        "unused", "unused", "unused", "unused",
                                        "dfllCPU_out" };
 
-const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
+static const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
        .gen = gen5,
        .sclk_parents = sclk_parents_gen5,
        .cclk_g_parents = cclk_g_parents_gen5,
@@ -171,7 +171,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base,
        *dt_clk = clk;
 }
 
-void __init tegra_super_clk_init(void __iomem *clk_base,
+static void __init tegra_super_clk_init(void __iomem *clk_base,
                                void __iomem *pmc_base,
                                struct tegra_clk *tegra_clks,
                                struct tegra_clk_pll_params *params,
index 58514c44ea830c476b8b23606e962ecf8ef8ef7a..637041fd53ad11b95cd305952cb0a80eaf0d3b61 100644 (file)
@@ -59,8 +59,8 @@
 #define PLLC3_MISC3 0x50c
 
 #define PLLM_BASE 0x90
-#define PLLM_MISC0 0x9c
 #define PLLM_MISC1 0x98
+#define PLLM_MISC2 0x9c
 #define PLLP_BASE 0xa0
 #define PLLP_MISC0 0xac
 #define PLLP_MISC1 0x680
@@ -99,7 +99,7 @@
 #define PLLC4_MISC0 0x5a8
 #define PLLC4_OUT 0x5e4
 #define PLLMB_BASE 0x5e8
-#define PLLMB_MISC0 0x5ec
+#define PLLMB_MISC1 0x5ec
 #define PLLA1_BASE 0x6a4
 #define PLLA1_MISC0 0x6a8
 #define PLLA1_MISC1 0x6ac
@@ -243,7 +243,8 @@ static unsigned long tegra210_input_freq[] = {
 };
 
 static const char *mux_pllmcp_clkm[] = {
-       "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
+       "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_mb", "pll_mb",
+       "pll_p",
 };
 #define mux_pllmcp_clkm_idx NULL
 
@@ -367,12 +368,12 @@ static const char *mux_pllmcp_clkm[] = {
 /* PLLMB */
 #define PLLMB_BASE_LOCK                        (1 << 27)
 
-#define PLLMB_MISC0_LOCK_OVERRIDE      (1 << 18)
-#define PLLMB_MISC0_IDDQ               (1 << 17)
-#define PLLMB_MISC0_LOCK_ENABLE                (1 << 16)
+#define PLLMB_MISC1_LOCK_OVERRIDE      (1 << 18)
+#define PLLMB_MISC1_IDDQ               (1 << 17)
+#define PLLMB_MISC1_LOCK_ENABLE                (1 << 16)
 
-#define PLLMB_MISC0_DEFAULT_VALUE      0x00030000
-#define PLLMB_MISC0_WRITE_MASK         0x0007ffff
+#define PLLMB_MISC1_DEFAULT_VALUE      0x00030000
+#define PLLMB_MISC1_WRITE_MASK         0x0007ffff
 
 /* PLLP */
 #define PLLP_BASE_OVERRIDE             (1 << 28)
@@ -457,7 +458,8 @@ static void pllcx_check_defaults(struct tegra_clk_pll_params *params)
                        PLLCX_MISC3_WRITE_MASK);
 }
 
-void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
+static void tegra210_pllcx_set_defaults(const char *name,
+                                       struct tegra_clk_pll *pllcx)
 {
        pllcx->params->defaults_set = true;
 
@@ -482,22 +484,22 @@ void tegra210_pllcx_set_defaults(const char *name, struct tegra_clk_pll *pllcx)
        udelay(1);
 }
 
-void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc_set_defaults(struct tegra_clk_pll *pllcx)
 {
        tegra210_pllcx_set_defaults("PLL_C", pllcx);
 }
 
-void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc2_set_defaults(struct tegra_clk_pll *pllcx)
 {
        tegra210_pllcx_set_defaults("PLL_C2", pllcx);
 }
 
-void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
+static void _pllc3_set_defaults(struct tegra_clk_pll *pllcx)
 {
        tegra210_pllcx_set_defaults("PLL_C3", pllcx);
 }
 
-void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
+static void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
 {
        tegra210_pllcx_set_defaults("PLL_A1", pllcx);
 }
@@ -507,7 +509,7 @@ void _plla1_set_defaults(struct tegra_clk_pll *pllcx)
  * PLL with dynamic ramp and fractional SDM. Dynamic ramp is not used.
  * Fractional SDM is allowed to provide exact audio rates.
  */
-void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
+static void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
 {
        u32 mask;
        u32 val = readl_relaxed(clk_base + plla->params->base_reg);
@@ -559,7 +561,7 @@ void tegra210_plla_set_defaults(struct tegra_clk_pll *plla)
  * PLLD
  * PLL with fractional SDM.
  */
-void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
+static void tegra210_plld_set_defaults(struct tegra_clk_pll *plld)
 {
        u32 val;
        u32 mask = 0xffff;
@@ -698,7 +700,7 @@ static void plldss_defaults(const char *pll_name, struct tegra_clk_pll *plldss,
        udelay(1);
 }
 
-void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
+static void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
 {
        plldss_defaults("PLL_D2", plld2, PLLD2_MISC0_DEFAULT_VALUE,
                        PLLD2_MISC1_CFG_DEFAULT_VALUE,
@@ -706,7 +708,7 @@ void tegra210_plld2_set_defaults(struct tegra_clk_pll *plld2)
                        PLLD2_MISC3_CTRL2_DEFAULT_VALUE);
 }
 
-void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
+static void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
 {
        plldss_defaults("PLL_DP", plldp, PLLDP_MISC0_DEFAULT_VALUE,
                        PLLDP_MISC1_CFG_DEFAULT_VALUE,
@@ -719,7 +721,7 @@ void tegra210_plldp_set_defaults(struct tegra_clk_pll *plldp)
  * Base and misc0 layout is the same as PLLD2/PLLDP, but no SDM/SSC support.
  * VCO is exposed to the clock tree via fixed 1/3 and 1/5 dividers.
  */
-void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
+static void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
 {
        plldss_defaults("PLL_C4", pllc4, PLLC4_MISC0_DEFAULT_VALUE, 0, 0, 0);
 }
@@ -728,7 +730,7 @@ void tegra210_pllc4_set_defaults(struct tegra_clk_pll *pllc4)
  * PLLRE
  * VCO is exposed to the clock tree directly along with post-divider output
  */
-void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
+static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre)
 {
        u32 mask;
        u32 val = readl_relaxed(clk_base + pllre->params->base_reg);
@@ -780,13 +782,13 @@ static void pllx_get_dyn_steps(struct clk_hw *hw, u32 *step_a, u32 *step_b)
 {
        unsigned long input_rate;
 
-       if (!IS_ERR_OR_NULL(hw->clk)) {
+       /* cf rate */
+       if (!IS_ERR_OR_NULL(hw->clk))
                input_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
-               /* cf rate */
-               input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
-       } else {
+       else
                input_rate = 38400000;
-       }
+
+       input_rate /= tegra_pll_get_fixed_mdiv(hw, input_rate);
 
        switch (input_rate) {
        case 12000000:
@@ -841,7 +843,7 @@ static void pllx_check_defaults(struct tegra_clk_pll *pll)
                        PLLX_MISC5_WRITE_MASK);
 }
 
-void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
+static void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
 {
        u32 val;
        u32 step_a, step_b;
@@ -901,7 +903,7 @@ void tegra210_pllx_set_defaults(struct tegra_clk_pll *pllx)
 }
 
 /* PLLMB */
-void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
+static void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
 {
        u32 mask, val = readl_relaxed(clk_base + pllmb->params->base_reg);
 
@@ -914,15 +916,15 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
                 * PLL is ON: check if defaults already set, then set those
                 * that can be updated in flight.
                 */
-               val = PLLMB_MISC0_DEFAULT_VALUE & (~PLLMB_MISC0_IDDQ);
-               mask = PLLMB_MISC0_LOCK_ENABLE | PLLMB_MISC0_LOCK_OVERRIDE;
+               val = PLLMB_MISC1_DEFAULT_VALUE & (~PLLMB_MISC1_IDDQ);
+               mask = PLLMB_MISC1_LOCK_ENABLE | PLLMB_MISC1_LOCK_OVERRIDE;
                _pll_misc_chk_default(clk_base, pllmb->params, 0, val,
-                               ~mask & PLLMB_MISC0_WRITE_MASK);
+                               ~mask & PLLMB_MISC1_WRITE_MASK);
 
                /* Enable lock detect */
                val = readl_relaxed(clk_base + pllmb->params->ext_misc_reg[0]);
                val &= ~mask;
-               val |= PLLMB_MISC0_DEFAULT_VALUE & mask;
+               val |= PLLMB_MISC1_DEFAULT_VALUE & mask;
                writel_relaxed(val, clk_base + pllmb->params->ext_misc_reg[0]);
                udelay(1);
 
@@ -930,7 +932,7 @@ void tegra210_pllmb_set_defaults(struct tegra_clk_pll *pllmb)
        }
 
        /* set IDDQ, enable lock detect */
-       writel_relaxed(PLLMB_MISC0_DEFAULT_VALUE,
+       writel_relaxed(PLLMB_MISC1_DEFAULT_VALUE,
                        clk_base + pllmb->params->ext_misc_reg[0]);
        udelay(1);
 }
@@ -960,7 +962,7 @@ static void pllp_check_defaults(struct tegra_clk_pll *pll, bool enabled)
                        ~mask & PLLP_MISC1_WRITE_MASK);
 }
 
-void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
+static void tegra210_pllp_set_defaults(struct tegra_clk_pll *pllp)
 {
        u32 mask;
        u32 val = readl_relaxed(clk_base + pllp->params->base_reg);
@@ -1022,7 +1024,7 @@ static void pllu_check_defaults(struct tegra_clk_pll *pll, bool hw_control)
                        ~mask & PLLU_MISC1_WRITE_MASK);
 }
 
-void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
+static void tegra210_pllu_set_defaults(struct tegra_clk_pll *pllu)
 {
        u32 val = readl_relaxed(clk_base + pllu->params->base_reg);
 
@@ -1212,8 +1214,9 @@ static void tegra210_clk_pll_set_gain(struct tegra_clk_pll_freq_table *cfg)
        cfg->m *= PLL_SDM_COEFF;
 }
 
-unsigned long tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
-                                         unsigned long parent_rate)
+static unsigned long
+tegra210_clk_adjust_vco_min(struct tegra_clk_pll_params *params,
+                           unsigned long parent_rate)
 {
        unsigned long vco_min = params->vco_min;
 
@@ -1386,7 +1389,7 @@ static struct tegra_clk_pll_params pll_c_params = {
        .mdiv_default = 3,
        .div_nmp = &pllc_nmp,
        .freq_table = pll_cx_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .set_defaults = _pllc_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1425,7 +1428,7 @@ static struct tegra_clk_pll_params pll_c2_params = {
        .ext_misc_reg[2] = PLLC2_MISC2,
        .ext_misc_reg[3] = PLLC2_MISC3,
        .freq_table = pll_cx_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .set_defaults = _pllc2_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1455,7 +1458,7 @@ static struct tegra_clk_pll_params pll_c3_params = {
        .ext_misc_reg[2] = PLLC3_MISC2,
        .ext_misc_reg[3] = PLLC3_MISC3,
        .freq_table = pll_cx_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .set_defaults = _pllc3_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1505,7 +1508,6 @@ static struct tegra_clk_pll_params pll_c4_vco_params = {
        .base_reg = PLLC4_BASE,
        .misc_reg = PLLC4_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .max_p = PLL_QLIN_PDIV_MAX,
        .ext_misc_reg[0] = PLLC4_MISC0,
@@ -1517,8 +1519,7 @@ static struct tegra_clk_pll_params pll_c4_vco_params = {
        .div_nmp = &pllss_nmp,
        .freq_table = pll_c4_vco_freq_table,
        .set_defaults = tegra210_pllc4_set_defaults,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
-                TEGRA_PLL_VCO_OUT,
+       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
 
@@ -1559,15 +1560,15 @@ static struct tegra_clk_pll_params pll_m_params = {
        .vco_min = 800000000,
        .vco_max = 1866000000,
        .base_reg = PLLM_BASE,
-       .misc_reg = PLLM_MISC1,
+       .misc_reg = PLLM_MISC2,
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLLM_MISC_LOCK_ENABLE,
        .lock_delay = 300,
-       .iddq_reg = PLLM_MISC0,
+       .iddq_reg = PLLM_MISC2,
        .iddq_bit_idx = PLLM_IDDQ_BIT,
        .max_p = PLL_QLIN_PDIV_MAX,
-       .ext_misc_reg[0] = PLLM_MISC0,
-       .ext_misc_reg[0] = PLLM_MISC1,
+       .ext_misc_reg[0] = PLLM_MISC2,
+       .ext_misc_reg[1] = PLLM_MISC1,
        .round_p_to_pdiv = pll_qlin_p_to_pdiv,
        .pdiv_tohw = pll_qlin_pdiv_to_hw,
        .div_nmp = &pllm_nmp,
@@ -1586,19 +1587,18 @@ static struct tegra_clk_pll_params pll_mb_params = {
        .vco_min = 800000000,
        .vco_max = 1866000000,
        .base_reg = PLLMB_BASE,
-       .misc_reg = PLLMB_MISC0,
+       .misc_reg = PLLMB_MISC1,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLMB_MISC_LOCK_ENABLE,
        .lock_delay = 300,
-       .iddq_reg = PLLMB_MISC0,
+       .iddq_reg = PLLMB_MISC1,
        .iddq_bit_idx = PLLMB_IDDQ_BIT,
        .max_p = PLL_QLIN_PDIV_MAX,
-       .ext_misc_reg[0] = PLLMB_MISC0,
+       .ext_misc_reg[0] = PLLMB_MISC1,
        .round_p_to_pdiv = pll_qlin_p_to_pdiv,
        .pdiv_tohw = pll_qlin_pdiv_to_hw,
        .div_nmp = &pllm_nmp,
        .freq_table = pll_m_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .set_defaults = tegra210_pllmb_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1671,7 +1671,6 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
        .base_reg = PLLRE_BASE,
        .misc_reg = PLLRE_MISC0,
        .lock_mask = PLLRE_MISC_LOCK,
-       .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .max_p = PLL_QLIN_PDIV_MAX,
        .ext_misc_reg[0] = PLLRE_MISC0,
@@ -1681,8 +1680,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
        .pdiv_tohw = pll_qlin_pdiv_to_hw,
        .div_nmp = &pllre_nmp,
        .freq_table = pll_re_vco_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC |
-                TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_LOCK_MISC | TEGRA_PLL_VCO_OUT,
        .set_defaults = tegra210_pllre_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1712,7 +1710,6 @@ static struct tegra_clk_pll_params pll_p_params = {
        .base_reg = PLLP_BASE,
        .misc_reg = PLLP_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLP_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .iddq_reg = PLLP_MISC0,
        .iddq_bit_idx = PLLXP_IDDQ_BIT,
@@ -1721,8 +1718,7 @@ static struct tegra_clk_pll_params pll_p_params = {
        .div_nmp = &pllp_nmp,
        .freq_table = pll_p_freq_table,
        .fixed_rate = 408000000,
-       .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
-                TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_VCO_OUT,
+       .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
        .set_defaults = tegra210_pllp_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1750,7 +1746,7 @@ static struct tegra_clk_pll_params pll_a1_params = {
        .ext_misc_reg[2] = PLLA1_MISC2,
        .ext_misc_reg[3] = PLLA1_MISC3,
        .freq_table = pll_cx_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .set_defaults = _plla1_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -1787,7 +1783,6 @@ static struct tegra_clk_pll_params pll_a_params = {
        .base_reg = PLLA_BASE,
        .misc_reg = PLLA_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLA_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .round_p_to_pdiv = pll_qlin_p_to_pdiv,
        .pdiv_tohw = pll_qlin_pdiv_to_hw,
@@ -1802,8 +1797,7 @@ static struct tegra_clk_pll_params pll_a_params = {
        .ext_misc_reg[1] = PLLA_MISC1,
        .ext_misc_reg[2] = PLLA_MISC2,
        .freq_table = pll_a_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW |
-                TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK | TEGRA_MDIV_NEW,
        .set_defaults = tegra210_plla_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
        .set_gain = tegra210_clk_pll_set_gain,
@@ -1836,7 +1830,6 @@ static struct tegra_clk_pll_params pll_d_params = {
        .base_reg = PLLD_BASE,
        .misc_reg = PLLD_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLD_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
        .iddq_reg = PLLD_MISC0,
        .iddq_bit_idx = PLLD_IDDQ_BIT,
@@ -1850,7 +1843,7 @@ static struct tegra_clk_pll_params pll_d_params = {
        .ext_misc_reg[0] = PLLD_MISC0,
        .ext_misc_reg[1] = PLLD_MISC1,
        .freq_table = pll_d_freq_table,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .mdiv_default = 1,
        .set_defaults = tegra210_plld_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
@@ -1876,7 +1869,6 @@ static struct tegra_clk_pll_params pll_d2_params = {
        .base_reg = PLLD2_BASE,
        .misc_reg = PLLD2_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .iddq_reg = PLLD2_BASE,
        .iddq_bit_idx = PLLSS_IDDQ_BIT,
@@ -1897,7 +1889,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
        .mdiv_default = 1,
        .freq_table = tegra210_pll_d2_freq_table,
        .set_defaults = tegra210_plld2_set_defaults,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
        .set_gain = tegra210_clk_pll_set_gain,
        .adjust_vco = tegra210_clk_adjust_vco_min,
@@ -1920,7 +1912,6 @@ static struct tegra_clk_pll_params pll_dp_params = {
        .base_reg = PLLDP_BASE,
        .misc_reg = PLLDP_MISC,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE,
        .lock_delay = 300,
        .iddq_reg = PLLDP_BASE,
        .iddq_bit_idx = PLLSS_IDDQ_BIT,
@@ -1941,7 +1932,7 @@ static struct tegra_clk_pll_params pll_dp_params = {
        .mdiv_default = 1,
        .freq_table = pll_dp_freq_table,
        .set_defaults = tegra210_plldp_set_defaults,
-       .flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
+       .flags = TEGRA_PLL_USE_LOCK,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
        .set_gain = tegra210_clk_pll_set_gain,
        .adjust_vco = tegra210_clk_adjust_vco_min,
@@ -1973,7 +1964,6 @@ static struct tegra_clk_pll_params pll_u_vco_params = {
        .base_reg = PLLU_BASE,
        .misc_reg = PLLU_MISC0,
        .lock_mask = PLL_BASE_LOCK,
-       .lock_enable_bit_idx = PLLU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
        .iddq_reg = PLLU_MISC0,
        .iddq_bit_idx = PLLU_IDDQ_BIT,
@@ -1983,8 +1973,7 @@ static struct tegra_clk_pll_params pll_u_vco_params = {
        .pdiv_tohw = pll_qlin_pdiv_to_hw,
        .div_nmp = &pllu_nmp,
        .freq_table = pll_u_freq_table,
-       .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
-                TEGRA_PLL_VCO_OUT,
+       .flags = TEGRA_PLLU | TEGRA_PLL_USE_LOCK | TEGRA_PLL_VCO_OUT,
        .set_defaults = tegra210_pllu_set_defaults,
        .calc_rate = tegra210_pll_fixed_mdiv_cfg,
 };
@@ -2218,6 +2207,7 @@ static struct tegra_clk tegra210_clks[tegra_clk_max] __initdata = {
        [tegra_clk_pll_c4_out1] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT1, .present = true },
        [tegra_clk_pll_c4_out2] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT2, .present = true },
        [tegra_clk_pll_c4_out3] = { .dt_id = TEGRA210_CLK_PLL_C4_OUT3, .present = true },
+       [tegra_clk_apb2ape] = { .dt_id = TEGRA210_CLK_APB2APE, .present = true },
 };
 
 static struct tegra_devclk devclks[] __initdata = {
@@ -2519,7 +2509,7 @@ static void __init tegra210_pll_init(void __iomem *clk_base,
 
        /* PLLU_VCO */
        val = readl(clk_base + pll_u_vco_params.base_reg);
-       val &= ~BIT(24); /* disable PLLU_OVERRIDE */
+       val &= ~PLLU_BASE_OVERRIDE; /* disable PLLU_OVERRIDE */
        writel(val, clk_base + pll_u_vco_params.base_reg);
 
        clk = tegra_clk_register_pllre("pll_u_vco", "pll_ref", clk_base, pmc,
@@ -2738,8 +2728,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
        { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
        { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
        { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
-       { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
-       { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
        { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
        { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
        { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
index 1c300388782ba19d1377bdbbbf9ab05a8939791d..cc739291a3ce47466e87023c2bdfd56951e7bf2f 100644 (file)
@@ -460,7 +460,8 @@ int omap3_noncore_dpll_enable(struct clk_hw *hw)
 
        parent = clk_hw_get_parent(hw);
 
-       if (clk_hw_get_rate(hw) == clk_get_rate(dd->clk_bypass)) {
+       if (clk_hw_get_rate(hw) ==
+           clk_hw_get_rate(__clk_get_hw(dd->clk_bypass))) {
                WARN_ON(parent != __clk_get_hw(dd->clk_bypass));
                r = _omap3_noncore_dpll_bypass(clk);
        } else {
index e62f8cb2c9b53ec4f22811549878ad844e24b612..3bca438ecd19dabbc3df761dedb81c96a463b449 100644 (file)
@@ -78,6 +78,9 @@ static int vco_set(struct clk_icst *icst, struct icst_vco vco)
        ret = regmap_read(icst->map, icst->vcoreg_off, &val);
        if (ret)
                return ret;
+
+       /* Mask the 18 bits used by the VCO */
+       val &= ~0x7ffff;
        val |= vco.v | (vco.r << 9) | (vco.s << 16);
 
        /* This magic unlocks the VCO so it can be controlled */
index 659879a56dbac59c7f18e0d2f51393bf9a3e645f..f93511031177f7801bf4e6bc5c29a0da22b47f5c 100644 (file)
@@ -296,6 +296,7 @@ endif
 config QORIQ_CPUFREQ
        tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
        depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
+       depends on !CPU_THERMAL || THERMAL
        select CLK_QORIQ
        help
          This adds the CPUFreq driver support for Freescale QorIQ SoCs
index 0031069b64c95aa93f2d1d0696ee8a9c63cc59ef..14b1f9393b057e106d7b068883ce486ea70239ec 100644 (file)
@@ -84,10 +84,10 @@ config ARM_KIRKWOOD_CPUFREQ
          SoCs.
 
 config ARM_MT8173_CPUFREQ
-       bool "Mediatek MT8173 CPUFreq support"
+       tristate "Mediatek MT8173 CPUFreq support"
        depends on ARCH_MEDIATEK && REGULATOR
        depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
-       depends on !CPU_THERMAL || THERMAL=y
+       depends on !CPU_THERMAL || THERMAL
        select PM_OPP
        help
          This adds the CPUFreq driver support for Mediatek MT8173 SoC.
index 1efba340456dfc5df4b2005517fe0c1b048e198a..2058e6d292ce95fbcd6fb3099b08adf36f857cd1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/cpu_cooling.h>
 #include <linux/cpufreq.h>
 #include <linux/cpumask.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
index 20de861aa0ea6c275edb746e14fcb372344fcd48..8bf9914d4d150b439e087688b51c884fdd1d022c 100644 (file)
@@ -782,7 +782,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err)
        dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
                        SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
 
-       clk_disable_unprepare(dd->iclk);
+       clk_disable(dd->iclk);
 
        if (req->base.complete)
                req->base.complete(&req->base, err);
@@ -795,7 +795,7 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
 {
        int err;
 
-       err = clk_prepare_enable(dd->iclk);
+       err = clk_enable(dd->iclk);
        if (err)
                return err;
 
@@ -822,7 +822,7 @@ static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd)
        dev_info(dd->dev,
                        "version: 0x%x\n", dd->hw_version);
 
-       clk_disable_unprepare(dd->iclk);
+       clk_disable(dd->iclk);
 }
 
 static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
@@ -1410,6 +1410,10 @@ static int atmel_sha_probe(struct platform_device *pdev)
                goto res_err;
        }
 
+       err = clk_prepare(sha_dd->iclk);
+       if (err)
+               goto res_err;
+
        atmel_sha_hw_version_init(sha_dd);
 
        atmel_sha_get_cap(sha_dd);
@@ -1421,12 +1425,12 @@ static int atmel_sha_probe(struct platform_device *pdev)
                        if (IS_ERR(pdata)) {
                                dev_err(&pdev->dev, "platform data not available\n");
                                err = PTR_ERR(pdata);
-                               goto res_err;
+                               goto iclk_unprepare;
                        }
                }
                if (!pdata->dma_slave) {
                        err = -ENXIO;
-                       goto res_err;
+                       goto iclk_unprepare;
                }
                err = atmel_sha_dma_init(sha_dd, pdata);
                if (err)
@@ -1457,6 +1461,8 @@ err_algs:
        if (sha_dd->caps.has_dma)
                atmel_sha_dma_cleanup(sha_dd);
 err_sha_dma:
+iclk_unprepare:
+       clk_unprepare(sha_dd->iclk);
 res_err:
        tasklet_kill(&sha_dd->done_task);
 sha_dd_err:
@@ -1483,12 +1489,7 @@ static int atmel_sha_remove(struct platform_device *pdev)
        if (sha_dd->caps.has_dma)
                atmel_sha_dma_cleanup(sha_dd);
 
-       iounmap(sha_dd->io_base);
-
-       clk_put(sha_dd->iclk);
-
-       if (sha_dd->irq >= 0)
-               free_irq(sha_dd->irq, sha_dd);
+       clk_unprepare(sha_dd->iclk);
 
        return 0;
 }
index 0643e3366e3309de88a03e687a2d5353f5715a22..c0656e7f37b5993672002a8a192dc1c9dcf0c4bd 100644 (file)
@@ -306,7 +306,7 @@ static int mv_cesa_dev_dma_init(struct mv_cesa_dev *cesa)
                return -ENOMEM;
 
        dma->padding_pool = dmam_pool_create("cesa_padding", dev, 72, 1, 0);
-       if (!dma->cache_pool)
+       if (!dma->padding_pool)
                return -ENOMEM;
 
        cesa->dma = dma;
index 848b93ee930fd8ec204a332755c57b18457bfede..fe9dce0245bf0c7d32b2c8eb3590e7f73651ae6d 100644 (file)
@@ -500,6 +500,8 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
        clk_set_min_rate(tegra->emc_clock, rate);
        clk_set_rate(tegra->emc_clock, 0);
 
+       *freq = rate;
+
        return 0;
 }
 
index e893318560db9f79300579ff01e73b07b5baae38..5ad0ec1f0e29f750eee5c70889df5427d7413556 100644 (file)
@@ -156,7 +156,6 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
 
        /* Enable interrupts */
        channel_set_bit(dw, MASK.XFER, dwc->mask);
-       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
        channel_set_bit(dw, MASK.ERROR, dwc->mask);
 
        dwc->initialized = true;
@@ -588,6 +587,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
 
                spin_unlock_irqrestore(&dwc->lock, flags);
        }
+
+       /* Re-enable interrupts */
+       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -618,11 +620,8 @@ static void dw_dma_tasklet(unsigned long data)
                        dwc_scan_descriptors(dw, dwc);
        }
 
-       /*
-        * Re-enable interrupts.
-        */
+       /* Re-enable interrupts */
        channel_set_bit(dw, MASK.XFER, dw->all_chan_mask);
-       channel_set_bit(dw, MASK.BLOCK, dw->all_chan_mask);
        channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask);
 }
 
@@ -1261,6 +1260,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 int dw_dma_cyclic_start(struct dma_chan *chan)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
+       struct dw_dma           *dw = to_dw_dma(chan->device);
        unsigned long           flags;
 
        if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
@@ -1269,7 +1269,12 @@ int dw_dma_cyclic_start(struct dma_chan *chan)
        }
 
        spin_lock_irqsave(&dwc->lock, flags);
+
+       /* Enable interrupts to perform cyclic transfer */
+       channel_set_bit(dw, MASK.BLOCK, dwc->mask);
+
        dwc_dostart(dwc, dwc->cdesc->desc[0]);
+
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return 0;
index 4c30fdd092b3b1e5b7e6050b7e7d1afee6c11e57..358f9689a3f5ace77d3dfd601f1873b880704060 100644 (file)
@@ -108,6 +108,10 @@ static const struct pci_device_id dw_pci_id_table[] = {
 
        /* Haswell */
        { PCI_VDEVICE(INTEL, 0x9c60) },
+
+       /* Broadwell */
+       { PCI_VDEVICE(INTEL, 0x9ce0) },
+
        { }
 };
 MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
index d92d655494068992f5a689ff83604158115bee4d..e3d7fcb69b4c2e4ffc4221c8ea8ec4e360648fd7 100644 (file)
 #define GET_NUM_REGN(x)                ((x & 0x300000) >> 20) /* bits 20-21 */
 #define CHMAP_EXIST            BIT(24)
 
+/* CCSTAT register */
+#define EDMA_CCSTAT_ACTV       BIT(4)
+
 /*
  * Max of 20 segments per channel to conserve PaRAM slots
  * Also note that MAX_NR_SG should be atleast the no.of periods
@@ -1680,9 +1683,20 @@ static void edma_issue_pending(struct dma_chan *chan)
        spin_unlock_irqrestore(&echan->vchan.lock, flags);
 }
 
+/*
+ * This limit exists to avoid a possible infinite loop when waiting for proof
+ * that a particular transfer is completed. This limit can be hit if there
+ * are large bursts to/from slow devices or the CPU is never able to catch
+ * the DMA hardware idle. On an AM335x transfering 48 bytes from the UART
+ * RX-FIFO, as many as 55 loops have been seen.
+ */
+#define EDMA_MAX_TR_WAIT_LOOPS 1000
+
 static u32 edma_residue(struct edma_desc *edesc)
 {
        bool dst = edesc->direction == DMA_DEV_TO_MEM;
+       int loop_count = EDMA_MAX_TR_WAIT_LOOPS;
+       struct edma_chan *echan = edesc->echan;
        struct edma_pset *pset = edesc->pset;
        dma_addr_t done, pos;
        int i;
@@ -1691,7 +1705,32 @@ static u32 edma_residue(struct edma_desc *edesc)
         * We always read the dst/src position from the first RamPar
         * pset. That's the one which is active now.
         */
-       pos = edma_get_position(edesc->echan->ecc, edesc->echan->slot[0], dst);
+       pos = edma_get_position(echan->ecc, echan->slot[0], dst);
+
+       /*
+        * "pos" may represent a transfer request that is still being
+        * processed by the EDMACC or EDMATC. We will busy wait until
+        * any one of the situations occurs:
+        *   1. the DMA hardware is idle
+        *   2. a new transfer request is setup
+        *   3. we hit the loop limit
+        */
+       while (edma_read(echan->ecc, EDMA_CCSTAT) & EDMA_CCSTAT_ACTV) {
+               /* check if a new transfer request is setup */
+               if (edma_get_position(echan->ecc,
+                                     echan->slot[0], dst) != pos) {
+                       break;
+               }
+
+               if (!--loop_count) {
+                       dev_dbg_ratelimited(echan->vchan.chan.device->dev,
+                               "%s: timeout waiting for PaRAM update\n",
+                               __func__);
+                       break;
+               }
+
+               cpu_relax();
+       }
 
        /*
         * Cyclic is simple. Just subtract pset[0].addr from pos.
index 1d5df2ef148b16d3c379a11e14a7da5283f9d5b8..21539d5c54c3d5c2d2dc3244650691bf414cf879 100644 (file)
@@ -861,32 +861,42 @@ void ioat_timer_event(unsigned long data)
                        return;
        }
 
+       spin_lock_bh(&ioat_chan->cleanup_lock);
+
+       /* handle the no-actives case */
+       if (!ioat_ring_active(ioat_chan)) {
+               spin_lock_bh(&ioat_chan->prep_lock);
+               check_active(ioat_chan);
+               spin_unlock_bh(&ioat_chan->prep_lock);
+               spin_unlock_bh(&ioat_chan->cleanup_lock);
+               return;
+       }
+
        /* if we haven't made progress and we have already
         * acknowledged a pending completion once, then be more
         * forceful with a restart
         */
-       spin_lock_bh(&ioat_chan->cleanup_lock);
        if (ioat_cleanup_preamble(ioat_chan, &phys_complete))
                __cleanup(ioat_chan, phys_complete);
        else if (test_bit(IOAT_COMPLETION_ACK, &ioat_chan->state)) {
+               u32 chanerr;
+
+               chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
+               dev_warn(to_dev(ioat_chan), "Restarting channel...\n");
+               dev_warn(to_dev(ioat_chan), "CHANSTS: %#Lx CHANERR: %#x\n",
+                        status, chanerr);
+               dev_warn(to_dev(ioat_chan), "Active descriptors: %d\n",
+                        ioat_ring_active(ioat_chan));
+
                spin_lock_bh(&ioat_chan->prep_lock);
                ioat_restart_channel(ioat_chan);
                spin_unlock_bh(&ioat_chan->prep_lock);
                spin_unlock_bh(&ioat_chan->cleanup_lock);
                return;
-       } else {
+       } else
                set_bit(IOAT_COMPLETION_ACK, &ioat_chan->state);
-               mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
-       }
-
 
-       if (ioat_ring_active(ioat_chan))
-               mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
-       else {
-               spin_lock_bh(&ioat_chan->prep_lock);
-               check_active(ioat_chan);
-               spin_unlock_bh(&ioat_chan->prep_lock);
-       }
+       mod_timer(&ioat_chan->timer, jiffies + COMPLETION_TIMEOUT);
        spin_unlock_bh(&ioat_chan->cleanup_lock);
 }
 
index f2a0310ae7718c3c49a6ef5a516a50851e1b0359..debca824bed676f0ecacc9e71476ecc33a477298 100644 (file)
@@ -583,6 +583,8 @@ static void set_updater_desc(struct pxad_desc_sw *sw_desc,
                (PXA_DCMD_LENGTH & sizeof(u32));
        if (flags & DMA_PREP_INTERRUPT)
                updater->dcmd |= PXA_DCMD_ENDIRQEN;
+       if (sw_desc->cyclic)
+               sw_desc->hw_desc[sw_desc->nb_desc - 2]->ddadr = sw_desc->first;
 }
 
 static bool is_desc_completed(struct virt_dma_desc *vd)
@@ -673,6 +675,10 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id)
                dev_dbg(&chan->vc.chan.dev->device,
                        "%s(): checking txd %p[%x]: completed=%d\n",
                        __func__, vd, vd->tx.cookie, is_desc_completed(vd));
+               if (to_pxad_sw_desc(vd)->cyclic) {
+                       vchan_cyclic_callback(vd);
+                       break;
+               }
                if (is_desc_completed(vd)) {
                        list_del(&vd->node);
                        vchan_cookie_complete(vd);
@@ -1080,7 +1086,7 @@ pxad_prep_dma_cyclic(struct dma_chan *dchan,
                return NULL;
 
        pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr);
-       dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH | period_len);
+       dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH & period_len);
        dev_dbg(&chan->vc.chan.dev->device,
                "%s(): buf_addr=0x%lx len=%zu period=%zu dir=%d flags=%lx\n",
                __func__, (unsigned long)buf_addr, len, period_len, dir, flags);
index 756eca8c4cf8f291025a3ad44f7cbb9981aeb5fd..10e6774ab2a2248d0a04d935b773c15a38519f46 100644 (file)
@@ -221,7 +221,7 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
        }
 
        if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
-           efivar_validate(name, data, size) == false) {
+           efivar_validate(vendor, name, data, size) == false) {
                printk(KERN_ERR "efivars: Malformed variable content\n");
                return -EINVAL;
        }
@@ -447,7 +447,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
        }
 
        if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
-           efivar_validate(name, data, size) == false) {
+           efivar_validate(new_var->VendorGuid, name, data,
+                           size) == false) {
                printk(KERN_ERR "efivars: Malformed variable content\n");
                return -EINVAL;
        }
@@ -540,38 +541,30 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
 static int
 efivar_create_sysfs_entry(struct efivar_entry *new_var)
 {
-       int i, short_name_size;
+       int short_name_size;
        char *short_name;
-       unsigned long variable_name_size;
-       efi_char16_t *variable_name;
+       unsigned long utf8_name_size;
+       efi_char16_t *variable_name = new_var->var.VariableName;
        int ret;
 
-       variable_name = new_var->var.VariableName;
-       variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
-
        /*
-        * Length of the variable bytes in ASCII, plus the '-' separator,
+        * Length of the variable bytes in UTF8, plus the '-' separator,
         * plus the GUID, plus trailing NUL
         */
-       short_name_size = variable_name_size / sizeof(efi_char16_t)
-                               + 1 + EFI_VARIABLE_GUID_LEN + 1;
-
-       short_name = kzalloc(short_name_size, GFP_KERNEL);
+       utf8_name_size = ucs2_utf8size(variable_name);
+       short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
 
+       short_name = kmalloc(short_name_size, GFP_KERNEL);
        if (!short_name)
                return -ENOMEM;
 
-       /* Convert Unicode to normal chars (assume top bits are 0),
-          ala UTF-8 */
-       for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
-               short_name[i] = variable_name[i] & 0xFF;
-       }
+       ucs2_as_utf8(short_name, variable_name, short_name_size);
+
        /* This is ugly, but necessary to separate one vendor's
           private variables from another's.         */
-
-       *(short_name + strlen(short_name)) = '-';
+       short_name[utf8_name_size] = '-';
        efi_guid_to_str(&new_var->var.VendorGuid,
-                        short_name + strlen(short_name));
+                        short_name + utf8_name_size + 1);
 
        new_var->kobj.kset = efivars_kset;
 
index 70a0fb10517f94ea5b28bada280d9935f0693cc7..7f2ea21c730dd76a86f3ab5a1e253878878960a7 100644 (file)
@@ -165,67 +165,133 @@ validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
 }
 
 struct variable_validate {
+       efi_guid_t vendor;
        char *name;
        bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
                         unsigned long len);
 };
 
+/*
+ * This is the list of variables we need to validate, as well as the
+ * whitelist for what we think is safe not to default to immutable.
+ *
+ * If it has a validate() method that's not NULL, it'll go into the
+ * validation routine.  If not, it is assumed valid, but still used for
+ * whitelisting.
+ *
+ * Note that it's sorted by {vendor,name}, but globbed names must come after
+ * any other name with the same prefix.
+ */
 static const struct variable_validate variable_validate[] = {
-       { "BootNext", validate_uint16 },
-       { "BootOrder", validate_boot_order },
-       { "DriverOrder", validate_boot_order },
-       { "Boot*", validate_load_option },
-       { "Driver*", validate_load_option },
-       { "ConIn", validate_device_path },
-       { "ConInDev", validate_device_path },
-       { "ConOut", validate_device_path },
-       { "ConOutDev", validate_device_path },
-       { "ErrOut", validate_device_path },
-       { "ErrOutDev", validate_device_path },
-       { "Timeout", validate_uint16 },
-       { "Lang", validate_ascii_string },
-       { "PlatformLang", validate_ascii_string },
-       { "", NULL },
+       { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 },
+       { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order },
+       { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option },
+       { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order },
+       { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option },
+       { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
+       { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
+       { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
+       { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
+       { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
+       { LINUX_EFI_CRASH_GUID, "*", NULL },
+       { NULL_GUID, "", NULL },
 };
 
+static bool
+variable_matches(const char *var_name, size_t len, const char *match_name,
+                int *match)
+{
+       for (*match = 0; ; (*match)++) {
+               char c = match_name[*match];
+               char u = var_name[*match];
+
+               /* Wildcard in the matching name means we've matched */
+               if (c == '*')
+                       return true;
+
+               /* Case sensitive match */
+               if (!c && *match == len)
+                       return true;
+
+               if (c != u)
+                       return false;
+
+               if (!c)
+                       return true;
+       }
+       return true;
+}
+
 bool
-efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len)
+efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
+               unsigned long data_size)
 {
        int i;
-       u16 *unicode_name = var_name;
+       unsigned long utf8_size;
+       u8 *utf8_name;
 
-       for (i = 0; variable_validate[i].validate != NULL; i++) {
-               const char *name = variable_validate[i].name;
-               int match;
+       utf8_size = ucs2_utf8size(var_name);
+       utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL);
+       if (!utf8_name)
+               return false;
 
-               for (match = 0; ; match++) {
-                       char c = name[match];
-                       u16 u = unicode_name[match];
+       ucs2_as_utf8(utf8_name, var_name, utf8_size);
+       utf8_name[utf8_size] = '\0';
 
-                       /* All special variables are plain ascii */
-                       if (u > 127)
-                               return true;
+       for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
+               const char *name = variable_validate[i].name;
+               int match = 0;
 
-                       /* Wildcard in the matching name means we've matched */
-                       if (c == '*')
-                               return variable_validate[i].validate(var_name,
-                                                            match, data, len);
+               if (efi_guidcmp(vendor, variable_validate[i].vendor))
+                       continue;
 
-                       /* Case sensitive match */
-                       if (c != u)
+               if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
+                       if (variable_validate[i].validate == NULL)
                                break;
-
-                       /* Reached the end of the string while matching */
-                       if (!c)
-                               return variable_validate[i].validate(var_name,
-                                                            match, data, len);
+                       kfree(utf8_name);
+                       return variable_validate[i].validate(var_name, match,
+                                                            data, data_size);
                }
        }
-
+       kfree(utf8_name);
        return true;
 }
 EXPORT_SYMBOL_GPL(efivar_validate);
 
+bool
+efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
+                            size_t len)
+{
+       int i;
+       bool found = false;
+       int match = 0;
+
+       /*
+        * Check if our variable is in the validated variables list
+        */
+       for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
+               if (efi_guidcmp(variable_validate[i].vendor, vendor))
+                       continue;
+
+               if (variable_matches(var_name, len,
+                                    variable_validate[i].name, &match)) {
+                       found = true;
+                       break;
+               }
+       }
+
+       /*
+        * If it's in our list, it is removable.
+        */
+       return found;
+}
+EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
+
 static efi_status_t
 check_var_size(u32 attributes, unsigned long size)
 {
@@ -852,7 +918,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
 
        *set = false;
 
-       if (efivar_validate(name, data, *size) == false)
+       if (efivar_validate(*vendor, name, data, *size) == false)
                return -EINVAL;
 
        /*
index 2aeaebd1c6e7af574fca9058cd0cf758e635943b..3f87a03abc222bc31cbc68eef98993c9e3303ad4 100644 (file)
@@ -312,8 +312,8 @@ static int altera_gpio_probe(struct platform_device *pdev)
                handle_simple_irq, IRQ_TYPE_NONE);
 
        if (ret) {
-               dev_info(&pdev->dev, "could not add irqchip\n");
-               return ret;
+               dev_err(&pdev->dev, "could not add irqchip\n");
+               goto teardown;
        }
 
        gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc,
@@ -326,6 +326,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
 skip_irq:
        return 0;
 teardown:
+       of_mm_gpiochip_remove(&altera_gc->mmchip);
        pr_err("%s: registration failed with status %d\n",
                node->full_name, ret);
 
index ec58f4288649b4ee1f0c98f7761439a525ac093e..cd007a67b3021e6e384889bf06ff7c9b292a7906 100644 (file)
@@ -195,7 +195,7 @@ static int davinci_gpio_of_xlate(struct gpio_chip *gc,
 static int davinci_gpio_probe(struct platform_device *pdev)
 {
        int i, base;
-       unsigned ngpio;
+       unsigned ngpio, nbank;
        struct davinci_gpio_controller *chips;
        struct davinci_gpio_platform_data *pdata;
        struct davinci_gpio_regs __iomem *regs;
@@ -224,8 +224,9 @@ static int davinci_gpio_probe(struct platform_device *pdev)
        if (WARN_ON(ARCH_NR_GPIOS < ngpio))
                ngpio = ARCH_NR_GPIOS;
 
+       nbank = DIV_ROUND_UP(ngpio, 32);
        chips = devm_kzalloc(dev,
-                            ngpio * sizeof(struct davinci_gpio_controller),
+                            nbank * sizeof(struct davinci_gpio_controller),
                             GFP_KERNEL);
        if (!chips)
                return -ENOMEM;
@@ -511,7 +512,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
                        return irq;
                }
 
-               irq_domain = irq_domain_add_legacy(NULL, ngpio, irq, 0,
+               irq_domain = irq_domain_add_legacy(dev->of_node, ngpio, irq, 0,
                                                        &davinci_gpio_irq_ops,
                                                        chips);
                if (!irq_domain) {
index cf41440aff91971e89090138e7912a3713427623..d9ab0cd1d205963528d7022d66213c26bf8304e5 100644 (file)
@@ -196,6 +196,44 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
        return 0;
 }
 
+static void gpio_rcar_irq_bus_lock(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+       pm_runtime_get_sync(&p->pdev->dev);
+}
+
+static void gpio_rcar_irq_bus_sync_unlock(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+       pm_runtime_put(&p->pdev->dev);
+}
+
+
+static int gpio_rcar_irq_request_resources(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+       int error;
+
+       error = pm_runtime_get_sync(&p->pdev->dev);
+       if (error < 0)
+               return error;
+
+       return 0;
+}
+
+static void gpio_rcar_irq_release_resources(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct gpio_rcar_priv *p = gpiochip_get_data(gc);
+
+       pm_runtime_put(&p->pdev->dev);
+}
+
 static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
 {
        struct gpio_rcar_priv *p = dev_id;
@@ -450,6 +488,10 @@ static int gpio_rcar_probe(struct platform_device *pdev)
        irq_chip->irq_unmask = gpio_rcar_irq_enable;
        irq_chip->irq_set_type = gpio_rcar_irq_set_type;
        irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
+       irq_chip->irq_bus_lock = gpio_rcar_irq_bus_lock;
+       irq_chip->irq_bus_sync_unlock = gpio_rcar_irq_bus_sync_unlock;
+       irq_chip->irq_request_resources = gpio_rcar_irq_request_resources;
+       irq_chip->irq_release_resources = gpio_rcar_irq_release_resources;
        irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
 
        ret = gpiochip_add_data(gpio_chip, p);
index 66f729eaf00bb99f09ef5960daf8c7630ceccb96..20c9539abc36e887dea47d00982e308be412d93e 100644 (file)
@@ -25,7 +25,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \
        amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o
 
 # add asic specific block
-amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o gmc_v7_0.o cik_ih.o kv_smc.o kv_dpm.o \
+amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
        ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o \
        amdgpu_amdkfd_gfx_v7.o
 
@@ -34,6 +34,7 @@ amdgpu-y += \
 
 # add GMC block
 amdgpu-y += \
+       gmc_v7_0.o \
        gmc_v8_0.o
 
 # add IH block
index 82edf95b7740d7fe9070cba62009374c08c34562..5e7770f9a415be24140df77708e9d9d39dee7faa 100644 (file)
@@ -87,6 +87,8 @@ extern int amdgpu_sched_jobs;
 extern int amdgpu_sched_hw_submission;
 extern int amdgpu_enable_semaphores;
 extern int amdgpu_powerplay;
+extern unsigned amdgpu_pcie_gen_cap;
+extern unsigned amdgpu_pcie_lane_cap;
 
 #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS         3000
 #define AMDGPU_MAX_USEC_TIMEOUT                        100000  /* 100 ms */
@@ -132,47 +134,6 @@ extern int amdgpu_powerplay;
 #define AMDGPU_RESET_VCE                       (1 << 13)
 #define AMDGPU_RESET_VCE1                      (1 << 14)
 
-/* CG block flags */
-#define AMDGPU_CG_BLOCK_GFX                    (1 << 0)
-#define AMDGPU_CG_BLOCK_MC                     (1 << 1)
-#define AMDGPU_CG_BLOCK_SDMA                   (1 << 2)
-#define AMDGPU_CG_BLOCK_UVD                    (1 << 3)
-#define AMDGPU_CG_BLOCK_VCE                    (1 << 4)
-#define AMDGPU_CG_BLOCK_HDP                    (1 << 5)
-#define AMDGPU_CG_BLOCK_BIF                    (1 << 6)
-
-/* CG flags */
-#define AMDGPU_CG_SUPPORT_GFX_MGCG             (1 << 0)
-#define AMDGPU_CG_SUPPORT_GFX_MGLS             (1 << 1)
-#define AMDGPU_CG_SUPPORT_GFX_CGCG             (1 << 2)
-#define AMDGPU_CG_SUPPORT_GFX_CGLS             (1 << 3)
-#define AMDGPU_CG_SUPPORT_GFX_CGTS             (1 << 4)
-#define AMDGPU_CG_SUPPORT_GFX_CGTS_LS          (1 << 5)
-#define AMDGPU_CG_SUPPORT_GFX_CP_LS            (1 << 6)
-#define AMDGPU_CG_SUPPORT_GFX_RLC_LS           (1 << 7)
-#define AMDGPU_CG_SUPPORT_MC_LS                        (1 << 8)
-#define AMDGPU_CG_SUPPORT_MC_MGCG              (1 << 9)
-#define AMDGPU_CG_SUPPORT_SDMA_LS              (1 << 10)
-#define AMDGPU_CG_SUPPORT_SDMA_MGCG            (1 << 11)
-#define AMDGPU_CG_SUPPORT_BIF_LS               (1 << 12)
-#define AMDGPU_CG_SUPPORT_UVD_MGCG             (1 << 13)
-#define AMDGPU_CG_SUPPORT_VCE_MGCG             (1 << 14)
-#define AMDGPU_CG_SUPPORT_HDP_LS               (1 << 15)
-#define AMDGPU_CG_SUPPORT_HDP_MGCG             (1 << 16)
-
-/* PG flags */
-#define AMDGPU_PG_SUPPORT_GFX_PG               (1 << 0)
-#define AMDGPU_PG_SUPPORT_GFX_SMG              (1 << 1)
-#define AMDGPU_PG_SUPPORT_GFX_DMG              (1 << 2)
-#define AMDGPU_PG_SUPPORT_UVD                  (1 << 3)
-#define AMDGPU_PG_SUPPORT_VCE                  (1 << 4)
-#define AMDGPU_PG_SUPPORT_CP                   (1 << 5)
-#define AMDGPU_PG_SUPPORT_GDS                  (1 << 6)
-#define AMDGPU_PG_SUPPORT_RLC_SMU_HS           (1 << 7)
-#define AMDGPU_PG_SUPPORT_SDMA                 (1 << 8)
-#define AMDGPU_PG_SUPPORT_ACP                  (1 << 9)
-#define AMDGPU_PG_SUPPORT_SAMU                 (1 << 10)
-
 /* GFX current status */
 #define AMDGPU_GFX_NORMAL_MODE                 0x00000000L
 #define AMDGPU_GFX_SAFE_MODE                   0x00000001L
@@ -606,8 +567,6 @@ struct amdgpu_sa_manager {
        uint32_t                align;
 };
 
-struct amdgpu_sa_bo;
-
 /* sub-allocation buffer */
 struct amdgpu_sa_bo {
        struct list_head                olist;
@@ -2360,6 +2319,8 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo);
 int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr,
                                     uint32_t flags);
 bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm);
+bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
+                                 unsigned long end);
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm);
 uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
                                 struct ttm_mem_reg *mem);
index 0e1376317683e4de30803a987450dba3e01b9621..362bedc9e50791ee6a9b1e60f4885a87ba158677 100644 (file)
@@ -154,7 +154,7 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .get_fw_version = get_fw_version
 };
 
-struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions()
+struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void)
 {
        return (struct kfd2kgd_calls *)&kfd2kgd;
 }
index 79fa5c7de856eab635ea9010ab0b8bfc446c37c2..04b744d64b57a6355f38ff071f48836148880257 100644 (file)
@@ -115,7 +115,7 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .get_fw_version = get_fw_version
 };
 
-struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions()
+struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void)
 {
        return (struct kfd2kgd_calls *)&kfd2kgd;
 }
index a081dda9fa2f6e66e82ee135fcdcd8446bd1674a..7a4b101e10c63564aa3b0b8fffc638c171c1d199 100644 (file)
@@ -795,6 +795,12 @@ static int amdgpu_cgs_query_system_info(void *cgs_device,
        case CGS_SYSTEM_INFO_PCIE_MLW:
                sys_info->value = adev->pm.pcie_mlw_mask;
                break;
+       case CGS_SYSTEM_INFO_CG_FLAGS:
+               sys_info->value = adev->cg_flags;
+               break;
+       case CGS_SYSTEM_INFO_PG_FLAGS:
+               sys_info->value = adev->pg_flags;
+               break;
        default:
                return -ENODEV;
        }
index 89c3dd62ba21ecd116b8490ed105573cecd86a82..119cdc2c43e7cef7fadf72736100cfcef1e200cd 100644 (file)
@@ -77,7 +77,7 @@ void amdgpu_connector_hotplug(struct drm_connector *connector)
                        } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
                                /* Don't try to start link training before we
                                 * have the dpcd */
-                               if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+                               if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
                                        return;
 
                                /* set it to OFF so that drm_helper_connector_dpms()
index 65531463f88e5b9eb736fdd5e9df357f2f191680..51bfc114584ed5e2fcd086efed40b57f344d2c4f 100644 (file)
@@ -1795,15 +1795,20 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        }
 
        /* post card */
-       amdgpu_atom_asic_init(adev->mode_info.atom_context);
+       if (!amdgpu_card_posted(adev))
+               amdgpu_atom_asic_init(adev->mode_info.atom_context);
 
        r = amdgpu_resume(adev);
+       if (r)
+               DRM_ERROR("amdgpu_resume failed (%d).\n", r);
 
        amdgpu_fence_driver_resume(adev);
 
-       r = amdgpu_ib_ring_tests(adev);
-       if (r)
-               DRM_ERROR("ib ring test failed (%d).\n", r);
+       if (resume) {
+               r = amdgpu_ib_ring_tests(adev);
+               if (r)
+                       DRM_ERROR("ib ring test failed (%d).\n", r);
+       }
 
        r = amdgpu_late_init(adev);
        if (r)
@@ -1933,80 +1938,97 @@ retry:
        return r;
 }
 
+#define AMDGPU_DEFAULT_PCIE_GEN_MASK 0x30007  /* gen: chipset 1/2, asic 1/2/3 */
+#define AMDGPU_DEFAULT_PCIE_MLW_MASK 0x2f0000 /* 1/2/4/8/16 lanes */
+
 void amdgpu_get_pcie_info(struct amdgpu_device *adev)
 {
        u32 mask;
        int ret;
 
-       if (pci_is_root_bus(adev->pdev->bus))
-               return;
+       if (amdgpu_pcie_gen_cap)
+               adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap;
 
-       if (amdgpu_pcie_gen2 == 0)
-               return;
+       if (amdgpu_pcie_lane_cap)
+               adev->pm.pcie_mlw_mask = amdgpu_pcie_lane_cap;
 
-       if (adev->flags & AMD_IS_APU)
+       /* covers APUs as well */
+       if (pci_is_root_bus(adev->pdev->bus)) {
+               if (adev->pm.pcie_gen_mask == 0)
+                       adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK;
+               if (adev->pm.pcie_mlw_mask == 0)
+                       adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK;
                return;
+       }
 
-       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-       if (!ret) {
-               adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
-                                         CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
-                                         CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
-
-               if (mask & DRM_PCIE_SPEED_25)
-                       adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
-               if (mask & DRM_PCIE_SPEED_50)
-                       adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2;
-               if (mask & DRM_PCIE_SPEED_80)
-                       adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3;
-       }
-       ret = drm_pcie_get_max_link_width(adev->ddev, &mask);
-       if (!ret) {
-               switch (mask) {
-               case 32:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 16:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 12:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 8:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 4:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 2:
-                       adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
-                                                 CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
-                       break;
-               case 1:
-                       adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
-                       break;
-               default:
-                       break;
+       if (adev->pm.pcie_gen_mask == 0) {
+               ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
+               if (!ret) {
+                       adev->pm.pcie_gen_mask = (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
+                                                 CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+                                                 CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
+
+                       if (mask & DRM_PCIE_SPEED_25)
+                               adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
+                       if (mask & DRM_PCIE_SPEED_50)
+                               adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2;
+                       if (mask & DRM_PCIE_SPEED_80)
+                               adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3;
+               } else {
+                       adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK;
+               }
+       }
+       if (adev->pm.pcie_mlw_mask == 0) {
+               ret = drm_pcie_get_max_link_width(adev->ddev, &mask);
+               if (!ret) {
+                       switch (mask) {
+                       case 32:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 16:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 12:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 8:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 4:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 2:
+                               adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
+                                                         CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
+                               break;
+                       case 1:
+                               adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK;
                }
        }
 }
index acd066d0a8051d0ad17f7311d8db1acd37348060..8297bc319369d6e4e4dd1579195ca1b6161a57d1 100644 (file)
@@ -72,8 +72,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
 
        struct drm_crtc *crtc = &amdgpuCrtc->base;
        unsigned long flags;
-       unsigned i;
-       int vpos, hpos, stat, min_udelay;
+       unsigned i, repcnt = 4;
+       int vpos, hpos, stat, min_udelay = 0;
        struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
        amdgpu_flip_wait_fence(adev, &work->excl);
@@ -96,7 +96,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
         * In practice this won't execute very often unless on very fast
         * machines because the time window for this to happen is very small.
         */
-       for (;;) {
+       while (amdgpuCrtc->enabled && repcnt--) {
                /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
                 * start in hpos, and to the "fudged earlier" vblank start in
                 * vpos.
@@ -114,10 +114,22 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
                /* Sleep at least until estimated real start of hw vblank */
                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+               if (min_udelay > vblank->framedur_ns / 2000) {
+                       /* Don't wait ridiculously long - something is wrong */
+                       repcnt = 0;
+                       break;
+               }
                usleep_range(min_udelay, 2 * min_udelay);
                spin_lock_irqsave(&crtc->dev->event_lock, flags);
        };
 
+       if (!repcnt)
+               DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+                                "framedur %d, linedur %d, stat %d, vpos %d, "
+                                "hpos %d\n", work->crtc_id, min_udelay,
+                                vblank->framedur_ns / 1000,
+                                vblank->linedur_ns / 1000, stat, vpos, hpos);
+
        /* do the flip (mmio) */
        adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
        /* set the flip status */
index b5dbbb57349190ce4b28409547781c515283994f..9ef1db87cf260c2a6a8abd423dde4be313f355ae 100644 (file)
@@ -83,6 +83,8 @@ int amdgpu_sched_jobs = 32;
 int amdgpu_sched_hw_submission = 2;
 int amdgpu_enable_semaphores = 0;
 int amdgpu_powerplay = -1;
+unsigned amdgpu_pcie_gen_cap = 0;
+unsigned amdgpu_pcie_lane_cap = 0;
 
 MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes");
 module_param_named(vramlimit, amdgpu_vram_limit, int, 0600);
@@ -170,6 +172,12 @@ MODULE_PARM_DESC(powerplay, "Powerplay component (1 = enable, 0 = disable, -1 =
 module_param_named(powerplay, amdgpu_powerplay, int, 0444);
 #endif
 
+MODULE_PARM_DESC(pcie_gen_cap, "PCIE Gen Caps (0: autodetect (default))");
+module_param_named(pcie_gen_cap, amdgpu_pcie_gen_cap, uint, 0444);
+
+MODULE_PARM_DESC(pcie_lane_cap, "PCIE Lane Caps (0: autodetect (default))");
+module_param_named(pcie_lane_cap, amdgpu_pcie_lane_cap, uint, 0444);
+
 static struct pci_device_id pciidlist[] = {
 #ifdef CONFIG_DRM_AMDGPU_CIK
        /* Kaveri */
@@ -256,11 +264,11 @@ static struct pci_device_id pciidlist[] = {
        {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU},
 #endif
        /* topaz */
-       {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT},
+       {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+       {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+       {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+       {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
+       {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ},
        /* tonga */
        {0x1002, 0x6920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
        {0x1002, 0x6921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA},
index 7380f782cd14a2ba1b3bb182832971368545e404..d20c2a8929cbdaf39164e6c709df67d36b352f35 100644 (file)
@@ -596,7 +596,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
                break;
        }
        ttm_eu_backoff_reservation(&ticket, &list);
-       if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
+       if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) &&
+           !amdgpu_vm_debug)
                amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
 
        drm_gem_object_unreference_unlocked(gobj);
index b1969f2b2038db79af8447fc9826ba8257207cf4..d4e2780c079663a643bddeaa7e2da5e15a2ff47d 100644 (file)
@@ -142,7 +142,8 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn,
 
                list_for_each_entry(bo, &node->bos, mn_list) {
 
-                       if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound)
+                       if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start,
+                                                         end))
                                continue;
 
                        r = amdgpu_bo_reserve(bo, true);
index a2a16acee34d3b4658f5317da10a43ea551f899c..b8fbbd7699e4586e13e57905b0cef818f6e43e6b 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/amdgpu_drm.h>
+#include <drm/drm_cache.h>
 #include "amdgpu.h"
 #include "amdgpu_trace.h"
 
@@ -261,6 +262,13 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev,
                                       AMDGPU_GEM_DOMAIN_OA);
 
        bo->flags = flags;
+
+       /* For architectures that don't support WC memory,
+        * mask out the WC flag from the BO
+        */
+       if (!drm_arch_can_wc_memory())
+               bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
+
        amdgpu_fill_placement_to_bo(bo, placement);
        /* Kernel allocation are uninterruptible */
        r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type,
index 7d8d84eaea4a5ab258eb5dac4a383f6aff81850d..95a4a25d8df9e8d37e1ec06d2d566e337353f222 100644 (file)
@@ -113,6 +113,10 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev,
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = ddev->dev_private;
 
+       if  ((adev->flags & AMD_IS_PX) &&
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+               return snprintf(buf, PAGE_SIZE, "off\n");
+
        if (adev->pp_enabled) {
                enum amd_dpm_forced_level level;
 
@@ -140,6 +144,11 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
        enum amdgpu_dpm_forced_level level;
        int ret = 0;
 
+       /* Can't force performance level when the card is off */
+       if  ((adev->flags & AMD_IS_PX) &&
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+               return -EINVAL;
+
        if (strncmp("low", buf, strlen("low")) == 0) {
                level = AMDGPU_DPM_FORCED_LEVEL_LOW;
        } else if (strncmp("high", buf, strlen("high")) == 0) {
@@ -157,6 +166,7 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
                mutex_lock(&adev->pm.mutex);
                if (adev->pm.dpm.thermal_active) {
                        count = -EINVAL;
+                       mutex_unlock(&adev->pm.mutex);
                        goto fail;
                }
                ret = amdgpu_dpm_force_performance_level(adev, level);
@@ -167,8 +177,6 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,
                mutex_unlock(&adev->pm.mutex);
        }
 fail:
-       mutex_unlock(&adev->pm.mutex);
-
        return count;
 }
 
@@ -182,8 +190,14 @@ static ssize_t amdgpu_hwmon_show_temp(struct device *dev,
                                      char *buf)
 {
        struct amdgpu_device *adev = dev_get_drvdata(dev);
+       struct drm_device *ddev = adev->ddev;
        int temp;
 
+       /* Can't get temperature when the card is off */
+       if  ((adev->flags & AMD_IS_PX) &&
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
+               return -EINVAL;
+
        if (!adev->pp_enabled && !adev->pm.funcs->get_temperature)
                temp = 0;
        else
@@ -634,11 +648,6 @@ force:
 
        /* update display watermarks based on new power state */
        amdgpu_display_bandwidth_update(adev);
-       /* update displays */
-       amdgpu_dpm_display_configuration_changed(adev);
-
-       adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
-       adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
 
        /* wait for the rings to drain */
        for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
@@ -655,6 +664,12 @@ force:
 
        amdgpu_dpm_post_set_power_state(adev);
 
+       /* update displays */
+       amdgpu_dpm_display_configuration_changed(adev);
+
+       adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
+       adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
+
        if (adev->pm.funcs->force_performance_level) {
                if (adev->pm.dpm.thermal_active) {
                        enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level;
@@ -847,12 +862,16 @@ static int amdgpu_debugfs_pm_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        struct amdgpu_device *adev = dev->dev_private;
+       struct drm_device *ddev = adev->ddev;
 
        if (!adev->pm.dpm_enabled) {
                seq_printf(m, "dpm not enabled\n");
                return 0;
        }
-       if (adev->pp_enabled) {
+       if  ((adev->flags & AMD_IS_PX) &&
+            (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) {
+               seq_printf(m, "PX asic powered off\n");
+       } else if (adev->pp_enabled) {
                amdgpu_dpm_debugfs_print_current_performance_level(adev, m);
        } else {
                mutex_lock(&adev->pm.mutex);
index b9d0d55f6b47df33ab7ebf7024fe7ca6e821892a..3cb6d6c413c71b0207fe1766d26ca190a083e880 100644 (file)
@@ -143,8 +143,10 @@ static int amdgpu_pp_late_init(void *handle)
                                        adev->powerplay.pp_handle);
 
 #ifdef CONFIG_DRM_AMD_POWERPLAY
-       if (adev->pp_enabled)
+       if (adev->pp_enabled) {
                amdgpu_pm_sysfs_init(adev);
+               amdgpu_dpm_dispatch_task(adev, AMD_PP_EVENT_COMPLETE_INIT, NULL, NULL);
+       }
 #endif
        return ret;
 }
index 8b88edb0434bfb43ed4b7aae7e6f3e7dc63d0893..ca72a2e487b9b9d846b65479e9b865dd1ef71281 100644 (file)
@@ -354,12 +354,15 @@ int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
 
                for (i = 0, count = 0; i < AMDGPU_MAX_RINGS; ++i)
                        if (fences[i])
-                               fences[count++] = fences[i];
+                               fences[count++] = fence_get(fences[i]);
 
                if (count) {
                        spin_unlock(&sa_manager->wq.lock);
                        t = fence_wait_any_timeout(fences, count, false,
                                                   MAX_SCHEDULE_TIMEOUT);
+                       for (i = 0; i < count; ++i)
+                               fence_put(fences[i]);
+
                        r = (t > 0) ? 0 : t;
                        spin_lock(&sa_manager->wq.lock);
                } else {
index 8a1752ff3d8e55a1d8b8ab3061f5c9c425058d0f..1cbb16e153079e7463a0ac070d1a19461deb588e 100644 (file)
@@ -712,7 +712,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm)
                                                       0, PAGE_SIZE,
                                                       PCI_DMA_BIDIRECTIONAL);
                if (pci_dma_mapping_error(adev->pdev, gtt->ttm.dma_address[i])) {
-                       while (--i) {
+                       while (i--) {
                                pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i],
                                               PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
                                gtt->ttm.dma_address[i] = 0;
@@ -783,6 +783,25 @@ bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm)
        return !!gtt->userptr;
 }
 
+bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
+                                 unsigned long end)
+{
+       struct amdgpu_ttm_tt *gtt = (void *)ttm;
+       unsigned long size;
+
+       if (gtt == NULL)
+               return false;
+
+       if (gtt->ttm.ttm.state != tt_bound || !gtt->userptr)
+               return false;
+
+       size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE;
+       if (gtt->userptr > end || gtt->userptr + size <= start)
+               return false;
+
+       return true;
+}
+
 bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
 {
        struct amdgpu_ttm_tt *gtt = (void *)ttm;
@@ -808,7 +827,7 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
                        flags |= AMDGPU_PTE_SNOOPED;
        }
 
-       if (adev->asic_type >= CHIP_TOPAZ)
+       if (adev->asic_type >= CHIP_TONGA)
                flags |= AMDGPU_PTE_EXECUTABLE;
 
        flags |= AMDGPU_PTE_READABLE;
index 8b4731d4e10eabbd78f17f799c5fcd1156ba9862..474ca02b094935283c3548534a2502cd01412665 100644 (file)
@@ -31,6 +31,7 @@
 #include "ci_dpm.h"
 #include "gfx_v7_0.h"
 #include "atom.h"
+#include "amd_pcie.h"
 #include <linux/seq_file.h>
 
 #include "smu/smu_7_0_1_d.h"
@@ -5835,18 +5836,16 @@ static int ci_dpm_init(struct amdgpu_device *adev)
        u8 frev, crev;
        struct ci_power_info *pi;
        int ret;
-       u32 mask;
 
        pi = kzalloc(sizeof(struct ci_power_info), GFP_KERNEL);
        if (pi == NULL)
                return -ENOMEM;
        adev->pm.dpm.priv = pi;
 
-       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-       if (ret)
-               pi->sys_pcie_mask = 0;
-       else
-               pi->sys_pcie_mask = mask;
+       pi->sys_pcie_mask =
+               (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >>
+               CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT;
+
        pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
 
        pi->pcie_gen_performance.max = AMDGPU_PCIE_GEN1;
index fd9c9588ef46335d7a154e664bce8275d62f3ae9..155965ed14a3bee05d745b5e25fccf03546dc4ae 100644 (file)
@@ -1762,6 +1762,9 @@ static void cik_program_aspm(struct amdgpu_device *adev)
        if (amdgpu_aspm == 0)
                return;
 
+       if (pci_is_root_bus(adev->pdev->bus))
+               return;
+
        /* XXX double check APUs */
        if (adev->flags & AMD_IS_APU)
                return;
@@ -2332,72 +2335,72 @@ static int cik_common_early_init(void *handle)
        switch (adev->asic_type) {
        case CHIP_BONAIRE:
                adev->cg_flags =
-                       AMDGPU_CG_SUPPORT_GFX_MGCG |
-                       AMDGPU_CG_SUPPORT_GFX_MGLS |
-                       /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-                       AMDGPU_CG_SUPPORT_GFX_CGLS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-                       AMDGPU_CG_SUPPORT_GFX_CP_LS |
-                       AMDGPU_CG_SUPPORT_MC_LS |
-                       AMDGPU_CG_SUPPORT_MC_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_LS |
-                       AMDGPU_CG_SUPPORT_BIF_LS |
-                       AMDGPU_CG_SUPPORT_VCE_MGCG |
-                       AMDGPU_CG_SUPPORT_UVD_MGCG |
-                       AMDGPU_CG_SUPPORT_HDP_LS |
-                       AMDGPU_CG_SUPPORT_HDP_MGCG;
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CGTS_LS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
                adev->pg_flags = 0;
                adev->external_rev_id = adev->rev_id + 0x14;
                break;
        case CHIP_HAWAII:
                adev->cg_flags =
-                       AMDGPU_CG_SUPPORT_GFX_MGCG |
-                       AMDGPU_CG_SUPPORT_GFX_MGLS |
-                       /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-                       AMDGPU_CG_SUPPORT_GFX_CGLS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS |
-                       AMDGPU_CG_SUPPORT_GFX_CP_LS |
-                       AMDGPU_CG_SUPPORT_MC_LS |
-                       AMDGPU_CG_SUPPORT_MC_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_LS |
-                       AMDGPU_CG_SUPPORT_BIF_LS |
-                       AMDGPU_CG_SUPPORT_VCE_MGCG |
-                       AMDGPU_CG_SUPPORT_UVD_MGCG |
-                       AMDGPU_CG_SUPPORT_HDP_LS |
-                       AMDGPU_CG_SUPPORT_HDP_MGCG;
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_MC_LS |
+                       AMD_CG_SUPPORT_MC_MGCG |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
                adev->pg_flags = 0;
                adev->external_rev_id = 0x28;
                break;
        case CHIP_KAVERI:
                adev->cg_flags =
-                       AMDGPU_CG_SUPPORT_GFX_MGCG |
-                       AMDGPU_CG_SUPPORT_GFX_MGLS |
-                       /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-                       AMDGPU_CG_SUPPORT_GFX_CGLS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-                       AMDGPU_CG_SUPPORT_GFX_CP_LS |
-                       AMDGPU_CG_SUPPORT_SDMA_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_LS |
-                       AMDGPU_CG_SUPPORT_BIF_LS |
-                       AMDGPU_CG_SUPPORT_VCE_MGCG |
-                       AMDGPU_CG_SUPPORT_UVD_MGCG |
-                       AMDGPU_CG_SUPPORT_HDP_LS |
-                       AMDGPU_CG_SUPPORT_HDP_MGCG;
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CGTS_LS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
                adev->pg_flags =
-                       /*AMDGPU_PG_SUPPORT_GFX_PG |
-                         AMDGPU_PG_SUPPORT_GFX_SMG |
-                         AMDGPU_PG_SUPPORT_GFX_DMG |*/
-                       AMDGPU_PG_SUPPORT_UVD |
-                       /*AMDGPU_PG_SUPPORT_VCE |
-                         AMDGPU_PG_SUPPORT_CP |
-                         AMDGPU_PG_SUPPORT_GDS |
-                         AMDGPU_PG_SUPPORT_RLC_SMU_HS |
-                         AMDGPU_PG_SUPPORT_ACP |
-                         AMDGPU_PG_SUPPORT_SAMU |*/
+                       /*AMD_PG_SUPPORT_GFX_PG |
+                         AMD_PG_SUPPORT_GFX_SMG |
+                         AMD_PG_SUPPORT_GFX_DMG |*/
+                       AMD_PG_SUPPORT_UVD |
+                       /*AMD_PG_SUPPORT_VCE |
+                         AMD_PG_SUPPORT_CP |
+                         AMD_PG_SUPPORT_GDS |
+                         AMD_PG_SUPPORT_RLC_SMU_HS |
+                         AMD_PG_SUPPORT_ACP |
+                         AMD_PG_SUPPORT_SAMU |*/
                        0;
                if (adev->pdev->device == 0x1312 ||
                        adev->pdev->device == 0x1316 ||
@@ -2409,29 +2412,29 @@ static int cik_common_early_init(void *handle)
        case CHIP_KABINI:
        case CHIP_MULLINS:
                adev->cg_flags =
-                       AMDGPU_CG_SUPPORT_GFX_MGCG |
-                       AMDGPU_CG_SUPPORT_GFX_MGLS |
-                       /*AMDGPU_CG_SUPPORT_GFX_CGCG |*/
-                       AMDGPU_CG_SUPPORT_GFX_CGLS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS |
-                       AMDGPU_CG_SUPPORT_GFX_CGTS_LS |
-                       AMDGPU_CG_SUPPORT_GFX_CP_LS |
-                       AMDGPU_CG_SUPPORT_SDMA_MGCG |
-                       AMDGPU_CG_SUPPORT_SDMA_LS |
-                       AMDGPU_CG_SUPPORT_BIF_LS |
-                       AMDGPU_CG_SUPPORT_VCE_MGCG |
-                       AMDGPU_CG_SUPPORT_UVD_MGCG |
-                       AMDGPU_CG_SUPPORT_HDP_LS |
-                       AMDGPU_CG_SUPPORT_HDP_MGCG;
+                       AMD_CG_SUPPORT_GFX_MGCG |
+                       AMD_CG_SUPPORT_GFX_MGLS |
+                       /*AMD_CG_SUPPORT_GFX_CGCG |*/
+                       AMD_CG_SUPPORT_GFX_CGLS |
+                       AMD_CG_SUPPORT_GFX_CGTS |
+                       AMD_CG_SUPPORT_GFX_CGTS_LS |
+                       AMD_CG_SUPPORT_GFX_CP_LS |
+                       AMD_CG_SUPPORT_SDMA_MGCG |
+                       AMD_CG_SUPPORT_SDMA_LS |
+                       AMD_CG_SUPPORT_BIF_LS |
+                       AMD_CG_SUPPORT_VCE_MGCG |
+                       AMD_CG_SUPPORT_UVD_MGCG |
+                       AMD_CG_SUPPORT_HDP_LS |
+                       AMD_CG_SUPPORT_HDP_MGCG;
                adev->pg_flags =
-                       /*AMDGPU_PG_SUPPORT_GFX_PG |
-                         AMDGPU_PG_SUPPORT_GFX_SMG | */
-                       AMDGPU_PG_SUPPORT_UVD |
-                       /*AMDGPU_PG_SUPPORT_VCE |
-                         AMDGPU_PG_SUPPORT_CP |
-                         AMDGPU_PG_SUPPORT_GDS |
-                         AMDGPU_PG_SUPPORT_RLC_SMU_HS |
-                         AMDGPU_PG_SUPPORT_SAMU |*/
+                       /*AMD_PG_SUPPORT_GFX_PG |
+                         AMD_PG_SUPPORT_GFX_SMG | */
+                       AMD_PG_SUPPORT_UVD |
+                       /*AMD_PG_SUPPORT_VCE |
+                         AMD_PG_SUPPORT_CP |
+                         AMD_PG_SUPPORT_GDS |
+                         AMD_PG_SUPPORT_RLC_SMU_HS |
+                         AMD_PG_SUPPORT_SAMU |*/
                        0;
                if (adev->asic_type == CHIP_KABINI) {
                        if (adev->rev_id == 0)
index 5f712ceddf08e4765fb544aff0cad26e6bbcd890..c55ecf0ea8454822a07711c3b85479a9e51e214d 100644 (file)
@@ -885,7 +885,7 @@ static void cik_enable_sdma_mgcg(struct amdgpu_device *adev,
 {
        u32 orig, data;
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_MGCG)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG)) {
                WREG32(mmSDMA0_CLK_CTRL + SDMA0_REGISTER_OFFSET, 0x00000100);
                WREG32(mmSDMA0_CLK_CTRL + SDMA1_REGISTER_OFFSET, 0x00000100);
        } else {
@@ -906,7 +906,7 @@ static void cik_enable_sdma_mgls(struct amdgpu_device *adev,
 {
        u32 orig, data;
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_SDMA_LS)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_SDMA_LS)) {
                orig = data = RREG32(mmSDMA0_POWER_CNTL + SDMA0_REGISTER_OFFSET);
                data |= 0x100;
                if (orig != data)
index 4dd17f2dd9059125eace5ffd5fc2a8cf2eb46802..e7ef2261ff4a70821a318e0377a33f7383607314 100644 (file)
@@ -445,13 +445,13 @@ static int cz_dpm_init(struct amdgpu_device *adev)
        pi->gfx_pg_threshold = 500;
        pi->caps_fps = true;
        /* uvd */
-       pi->caps_uvd_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_UVD) ? true : false;
+       pi->caps_uvd_pg = (adev->pg_flags & AMD_PG_SUPPORT_UVD) ? true : false;
        pi->caps_uvd_dpm = true;
        /* vce */
-       pi->caps_vce_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_VCE) ? true : false;
+       pi->caps_vce_pg = (adev->pg_flags & AMD_PG_SUPPORT_VCE) ? true : false;
        pi->caps_vce_dpm = true;
        /* acp */
-       pi->caps_acp_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_ACP) ? true : false;
+       pi->caps_acp_pg = (adev->pg_flags & AMD_PG_SUPPORT_ACP) ? true : false;
        pi->caps_acp_dpm = true;
 
        pi->caps_stable_power_state = false;
@@ -2202,8 +2202,7 @@ static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
                                                            AMD_PG_STATE_GATE);
 
                                cz_enable_vce_dpm(adev, false);
-                               /* TODO: to figure out why vce can't be poweroff. */
-                               /* cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF); */
+                               cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerOFF);
                                pi->vce_power_gated = true;
                        } else {
                                cz_send_msg_to_smc(adev, PPSMC_MSG_VCEPowerON);
@@ -2226,10 +2225,8 @@ static void cz_dpm_powergate_vce(struct amdgpu_device *adev, bool gate)
                }
        } else { /*pi->caps_vce_pg*/
                cz_update_vce_dpm(adev);
-               cz_enable_vce_dpm(adev, true);
+               cz_enable_vce_dpm(adev, !gate);
        }
-
-       return;
 }
 
 const struct amd_ip_funcs cz_dpm_ip_funcs = {
index 72793f93e2fcc9989e5f936ec1d43ba0593ac69e..06602df707f86375d8db781db550d6db160e06e0 100644 (file)
@@ -3628,6 +3628,19 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
                                        unsigned vm_id, uint64_t pd_addr)
 {
        int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX);
+       uint32_t seq = ring->fence_drv.sync_seq;
+       uint64_t addr = ring->fence_drv.gpu_addr;
+
+       amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
+                                WAIT_REG_MEM_FUNCTION(3) | /* equal */
+                                WAIT_REG_MEM_ENGINE(usepfp)));   /* pfp or me */
+       amdgpu_ring_write(ring, addr & 0xfffffffc);
+       amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+       amdgpu_ring_write(ring, seq);
+       amdgpu_ring_write(ring, 0xffffffff);
+       amdgpu_ring_write(ring, 4); /* poll interval */
+
        if (usepfp) {
                /* synce CE with ME to prevent CE fetch CEIB before context switch done */
                amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
@@ -4109,7 +4122,7 @@ static void gfx_v7_0_enable_cgcg(struct amdgpu_device *adev, bool enable)
 
        orig = data = RREG32(mmRLC_CGCG_CGLS_CTRL);
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGCG)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG)) {
                gfx_v7_0_enable_gui_idle_interrupt(adev, true);
 
                tmp = gfx_v7_0_halt_rlc(adev);
@@ -4147,9 +4160,9 @@ static void gfx_v7_0_enable_mgcg(struct amdgpu_device *adev, bool enable)
 {
        u32 data, orig, tmp = 0;
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGCG)) {
-               if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGLS) {
-                       if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CP_LS) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG)) {
+               if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) {
+                       if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) {
                                orig = data = RREG32(mmCP_MEM_SLP_CNTL);
                                data |= CP_MEM_SLP_CNTL__CP_MEM_LS_EN_MASK;
                                if (orig != data)
@@ -4176,14 +4189,14 @@ static void gfx_v7_0_enable_mgcg(struct amdgpu_device *adev, bool enable)
 
                gfx_v7_0_update_rlc(adev, tmp);
 
-               if (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGTS) {
+               if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGTS) {
                        orig = data = RREG32(mmCGTS_SM_CTRL_REG);
                        data &= ~CGTS_SM_CTRL_REG__SM_MODE_MASK;
                        data |= (0x2 << CGTS_SM_CTRL_REG__SM_MODE__SHIFT);
                        data |= CGTS_SM_CTRL_REG__SM_MODE_ENABLE_MASK;
                        data &= ~CGTS_SM_CTRL_REG__OVERRIDE_MASK;
-                       if ((adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_MGLS) &&
-                           (adev->cg_flags & AMDGPU_CG_SUPPORT_GFX_CGTS_LS))
+                       if ((adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) &&
+                           (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGTS_LS))
                                data &= ~CGTS_SM_CTRL_REG__LS_OVERRIDE_MASK;
                        data &= ~CGTS_SM_CTRL_REG__ON_MONITOR_ADD_MASK;
                        data |= CGTS_SM_CTRL_REG__ON_MONITOR_ADD_EN_MASK;
@@ -4249,7 +4262,7 @@ static void gfx_v7_0_enable_sclk_slowdown_on_pu(struct amdgpu_device *adev,
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_RLC_SMU_HS))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS))
                data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
        else
                data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PU_ENABLE_MASK;
@@ -4263,7 +4276,7 @@ static void gfx_v7_0_enable_sclk_slowdown_on_pd(struct amdgpu_device *adev,
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_RLC_SMU_HS))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS))
                data |= RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
        else
                data &= ~RLC_PG_CNTL__SMU_CLK_SLOWDOWN_ON_PD_ENABLE_MASK;
@@ -4276,7 +4289,7 @@ static void gfx_v7_0_enable_cp_pg(struct amdgpu_device *adev, bool enable)
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_CP))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_CP))
                data &= ~0x8000;
        else
                data |= 0x8000;
@@ -4289,7 +4302,7 @@ static void gfx_v7_0_enable_gds_pg(struct amdgpu_device *adev, bool enable)
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GDS))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GDS))
                data &= ~0x2000;
        else
                data |= 0x2000;
@@ -4370,7 +4383,7 @@ static void gfx_v7_0_enable_gfx_cgpg(struct amdgpu_device *adev,
 {
        u32 data, orig;
 
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG)) {
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) {
                orig = data = RREG32(mmRLC_PG_CNTL);
                data |= RLC_PG_CNTL__GFX_POWER_GATING_ENABLE_MASK;
                if (orig != data)
@@ -4442,7 +4455,7 @@ static void gfx_v7_0_enable_gfx_static_mgpg(struct amdgpu_device *adev,
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_SMG))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG))
                data |= RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
        else
                data &= ~RLC_PG_CNTL__STATIC_PER_CU_PG_ENABLE_MASK;
@@ -4456,7 +4469,7 @@ static void gfx_v7_0_enable_gfx_dynamic_mgpg(struct amdgpu_device *adev,
        u32 data, orig;
 
        orig = data = RREG32(mmRLC_PG_CNTL);
-       if (enable && (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_DMG))
+       if (enable && (adev->pg_flags & AMD_PG_SUPPORT_GFX_DMG))
                data |= RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
        else
                data &= ~RLC_PG_CNTL__DYN_PER_CU_PG_ENABLE_MASK;
@@ -4623,15 +4636,15 @@ static void gfx_v7_0_get_csb_buffer(struct amdgpu_device *adev,
 
 static void gfx_v7_0_init_pg(struct amdgpu_device *adev)
 {
-       if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-                             AMDGPU_PG_SUPPORT_GFX_SMG |
-                             AMDGPU_PG_SUPPORT_GFX_DMG |
-                             AMDGPU_PG_SUPPORT_CP |
-                             AMDGPU_PG_SUPPORT_GDS |
-                             AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
                gfx_v7_0_enable_sclk_slowdown_on_pu(adev, true);
                gfx_v7_0_enable_sclk_slowdown_on_pd(adev, true);
-               if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
                        gfx_v7_0_init_gfx_cgpg(adev);
                        gfx_v7_0_enable_cp_pg(adev, true);
                        gfx_v7_0_enable_gds_pg(adev, true);
@@ -4643,14 +4656,14 @@ static void gfx_v7_0_init_pg(struct amdgpu_device *adev)
 
 static void gfx_v7_0_fini_pg(struct amdgpu_device *adev)
 {
-       if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-                             AMDGPU_PG_SUPPORT_GFX_SMG |
-                             AMDGPU_PG_SUPPORT_GFX_DMG |
-                             AMDGPU_PG_SUPPORT_CP |
-                             AMDGPU_PG_SUPPORT_GDS |
-                             AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
                gfx_v7_0_update_gfx_pg(adev, false);
-               if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
                        gfx_v7_0_enable_cp_pg(adev, false);
                        gfx_v7_0_enable_gds_pg(adev, false);
                }
@@ -4738,6 +4751,22 @@ static int gfx_v7_0_early_init(void *handle)
        return 0;
 }
 
+static int gfx_v7_0_late_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       int r;
+
+       r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
+       if (r)
+               return r;
+
+       r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
+       if (r)
+               return r;
+
+       return 0;
+}
+
 static int gfx_v7_0_sw_init(void *handle)
 {
        struct amdgpu_ring *ring;
@@ -4890,6 +4919,8 @@ static int gfx_v7_0_hw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
+       amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
        gfx_v7_0_cp_enable(adev, false);
        gfx_v7_0_rlc_stop(adev);
        gfx_v7_0_fini_pg(adev);
@@ -5509,14 +5540,14 @@ static int gfx_v7_0_set_powergating_state(void *handle,
        if (state == AMD_PG_STATE_GATE)
                gate = true;
 
-       if (adev->pg_flags & (AMDGPU_PG_SUPPORT_GFX_PG |
-                             AMDGPU_PG_SUPPORT_GFX_SMG |
-                             AMDGPU_PG_SUPPORT_GFX_DMG |
-                             AMDGPU_PG_SUPPORT_CP |
-                             AMDGPU_PG_SUPPORT_GDS |
-                             AMDGPU_PG_SUPPORT_RLC_SMU_HS)) {
+       if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG |
+                             AMD_PG_SUPPORT_GFX_SMG |
+                             AMD_PG_SUPPORT_GFX_DMG |
+                             AMD_PG_SUPPORT_CP |
+                             AMD_PG_SUPPORT_GDS |
+                             AMD_PG_SUPPORT_RLC_SMU_HS)) {
                gfx_v7_0_update_gfx_pg(adev, gate);
-               if (adev->pg_flags & AMDGPU_PG_SUPPORT_GFX_PG) {
+               if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) {
                        gfx_v7_0_enable_cp_pg(adev, gate);
                        gfx_v7_0_enable_gds_pg(adev, gate);
                }
@@ -5527,7 +5558,7 @@ static int gfx_v7_0_set_powergating_state(void *handle,
 
 const struct amd_ip_funcs gfx_v7_0_ip_funcs = {
        .early_init = gfx_v7_0_early_init,
-       .late_init = NULL,
+       .late_init = gfx_v7_0_late_init,
        .sw_init = gfx_v7_0_sw_init,
        .sw_fini = gfx_v7_0_sw_fini,
        .hw_init = gfx_v7_0_hw_init,
index 95c0cdfbd1b3e6383803cb2256efcda9b4f6df7d..7086ac17abee11aa68e6a863099c73b273db1717 100644 (file)
@@ -111,7 +111,6 @@ MODULE_FIRMWARE("amdgpu/topaz_ce.bin");
 MODULE_FIRMWARE("amdgpu/topaz_pfp.bin");
 MODULE_FIRMWARE("amdgpu/topaz_me.bin");
 MODULE_FIRMWARE("amdgpu/topaz_mec.bin");
-MODULE_FIRMWARE("amdgpu/topaz_mec2.bin");
 MODULE_FIRMWARE("amdgpu/topaz_rlc.bin");
 
 MODULE_FIRMWARE("amdgpu/fiji_ce.bin");
@@ -828,7 +827,8 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev)
        adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version);
        adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version);
 
-       if (adev->asic_type != CHIP_STONEY) {
+       if ((adev->asic_type != CHIP_STONEY) &&
+           (adev->asic_type != CHIP_TOPAZ)) {
                snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name);
                err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev);
                if (!err) {
@@ -3851,10 +3851,16 @@ static int gfx_v8_0_cp_resume(struct amdgpu_device *adev)
                        if (r)
                                return -EINVAL;
 
-                       r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
-                                                       AMDGPU_UCODE_ID_CP_MEC1);
-                       if (r)
-                               return -EINVAL;
+                       if (adev->asic_type == CHIP_TOPAZ) {
+                               r = gfx_v8_0_cp_compute_load_microcode(adev);
+                               if (r)
+                                       return r;
+                       } else {
+                               r = adev->smu.smumgr_funcs->check_fw_load_finish(adev,
+                                                                                AMDGPU_UCODE_ID_CP_MEC1);
+                               if (r)
+                                       return -EINVAL;
+                       }
                }
        }
 
@@ -3901,6 +3907,8 @@ static int gfx_v8_0_hw_fini(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0);
+       amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0);
        gfx_v8_0_cp_enable(adev, false);
        gfx_v8_0_rlc_stop(adev);
        gfx_v8_0_cp_compute_fini(adev);
@@ -4329,6 +4337,14 @@ static int gfx_v8_0_late_init(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int r;
 
+       r = amdgpu_irq_get(adev, &adev->gfx.priv_reg_irq, 0);
+       if (r)
+               return r;
+
+       r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0);
+       if (r)
+               return r;
+
        /* requires IBs so do in late init after IB pool is initialized */
        r = gfx_v8_0_do_edc_gpr_workarounds(adev);
        if (r)
@@ -4793,7 +4809,8 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring,
 
        amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
        amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */
-                WAIT_REG_MEM_FUNCTION(3))); /* equal */
+                                WAIT_REG_MEM_FUNCTION(3) | /* equal */
+                                WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */
        amdgpu_ring_write(ring, addr & 0xfffffffc);
        amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
        amdgpu_ring_write(ring, seq);
@@ -4979,7 +4996,7 @@ static int gfx_v8_0_set_priv_reg_fault_state(struct amdgpu_device *adev,
        case AMDGPU_IRQ_STATE_ENABLE:
                cp_int_cntl = RREG32(mmCP_INT_CNTL_RING0);
                cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CP_INT_CNTL_RING0,
-                                           PRIV_REG_INT_ENABLE, 0);
+                                           PRIV_REG_INT_ENABLE, 1);
                WREG32(mmCP_INT_CNTL_RING0, cp_int_cntl);
                break;
        default:
index 3f956065d069125df0200f78527437134bf7f6d1..b8060795b27b96409a37ce213a3f6076127c7d71 100644 (file)
@@ -42,9 +42,39 @@ static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev);
 
 MODULE_FIRMWARE("radeon/bonaire_mc.bin");
 MODULE_FIRMWARE("radeon/hawaii_mc.bin");
+MODULE_FIRMWARE("amdgpu/topaz_mc.bin");
+
+static const u32 golden_settings_iceland_a11[] =
+{
+       mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+       mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+       mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
+       mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff
+};
+
+static const u32 iceland_mgcg_cgcg_init[] =
+{
+       mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
+};
+
+static void gmc_v7_0_init_golden_registers(struct amdgpu_device *adev)
+{
+       switch (adev->asic_type) {
+       case CHIP_TOPAZ:
+               amdgpu_program_register_sequence(adev,
+                                                iceland_mgcg_cgcg_init,
+                                                (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init));
+               amdgpu_program_register_sequence(adev,
+                                                golden_settings_iceland_a11,
+                                                (const u32)ARRAY_SIZE(golden_settings_iceland_a11));
+               break;
+       default:
+               break;
+       }
+}
 
 /**
- * gmc8_mc_wait_for_idle - wait for MC idle callback.
+ * gmc7_mc_wait_for_idle - wait for MC idle callback.
  *
  * @adev: amdgpu_device pointer
  *
@@ -132,13 +162,20 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev)
        case CHIP_HAWAII:
                chip_name = "hawaii";
                break;
+       case CHIP_TOPAZ:
+               chip_name = "topaz";
+               break;
        case CHIP_KAVERI:
        case CHIP_KABINI:
                return 0;
        default: BUG();
        }
 
-       snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+       if (adev->asic_type == CHIP_TOPAZ)
+               snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name);
+       else
+               snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+
        err = request_firmware(&adev->mc.fw, fw_name, adev->dev);
        if (err)
                goto out;
@@ -755,7 +792,7 @@ static void gmc_v7_0_enable_mc_ls(struct amdgpu_device *adev,
 
        for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
                orig = data = RREG32(mc_cg_registers[i]);
-               if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_LS))
+               if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_LS))
                        data |= mc_cg_ls_en[i];
                else
                        data &= ~mc_cg_ls_en[i];
@@ -772,7 +809,7 @@ static void gmc_v7_0_enable_mc_mgcg(struct amdgpu_device *adev,
 
        for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
                orig = data = RREG32(mc_cg_registers[i]);
-               if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_MC_MGCG))
+               if (enable && (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG))
                        data |= mc_cg_en[i];
                else
                        data &= ~mc_cg_en[i];
@@ -788,7 +825,7 @@ static void gmc_v7_0_enable_bif_mgls(struct amdgpu_device *adev,
 
        orig = data = RREG32_PCIE(ixPCIE_CNTL2);
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_BIF_LS)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_BIF_LS)) {
                data = REG_SET_FIELD(data, PCIE_CNTL2, SLV_MEM_LS_EN, 1);
                data = REG_SET_FIELD(data, PCIE_CNTL2, MST_MEM_LS_EN, 1);
                data = REG_SET_FIELD(data, PCIE_CNTL2, REPLAY_MEM_LS_EN, 1);
@@ -811,7 +848,7 @@ static void gmc_v7_0_enable_hdp_mgcg(struct amdgpu_device *adev,
 
        orig = data = RREG32(mmHDP_HOST_PATH_CNTL);
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_MGCG))
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG))
                data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 0);
        else
                data = REG_SET_FIELD(data, HDP_HOST_PATH_CNTL, CLOCK_GATING_DIS, 1);
@@ -827,7 +864,7 @@ static void gmc_v7_0_enable_hdp_ls(struct amdgpu_device *adev,
 
        orig = data = RREG32(mmHDP_MEM_POWER_LS);
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_HDP_LS))
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS))
                data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 1);
        else
                data = REG_SET_FIELD(data, HDP_MEM_POWER_LS, LS_ENABLE, 0);
@@ -984,6 +1021,8 @@ static int gmc_v7_0_hw_init(void *handle)
        int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       gmc_v7_0_init_golden_registers(adev);
+
        gmc_v7_0_mc_program(adev);
 
        if (!(adev->flags & AMD_IS_APU)) {
index c0c9a0101eb453c3139b9796ac8449350f0fb4bd..3efd45546241afc65e5d7db1fbc541fda946857b 100644 (file)
@@ -42,9 +42,7 @@
 static void gmc_v8_0_set_gart_funcs(struct amdgpu_device *adev);
 static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev);
 
-MODULE_FIRMWARE("amdgpu/topaz_mc.bin");
 MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
-MODULE_FIRMWARE("amdgpu/fiji_mc.bin");
 
 static const u32 golden_settings_tonga_a11[] =
 {
@@ -75,19 +73,6 @@ static const u32 fiji_mgcg_cgcg_init[] =
        mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
 };
 
-static const u32 golden_settings_iceland_a11[] =
-{
-       mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-       mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-       mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff,
-       mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff
-};
-
-static const u32 iceland_mgcg_cgcg_init[] =
-{
-       mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
-};
-
 static const u32 cz_mgcg_cgcg_init[] =
 {
        mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104
@@ -102,14 +87,6 @@ static const u32 stoney_mgcg_cgcg_init[] =
 static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev)
 {
        switch (adev->asic_type) {
-       case CHIP_TOPAZ:
-               amdgpu_program_register_sequence(adev,
-                                                iceland_mgcg_cgcg_init,
-                                                (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init));
-               amdgpu_program_register_sequence(adev,
-                                                golden_settings_iceland_a11,
-                                                (const u32)ARRAY_SIZE(golden_settings_iceland_a11));
-               break;
        case CHIP_FIJI:
                amdgpu_program_register_sequence(adev,
                                                 fiji_mgcg_cgcg_init,
@@ -229,15 +206,10 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev)
        DRM_DEBUG("\n");
 
        switch (adev->asic_type) {
-       case CHIP_TOPAZ:
-               chip_name = "topaz";
-               break;
        case CHIP_TONGA:
                chip_name = "tonga";
                break;
        case CHIP_FIJI:
-               chip_name = "fiji";
-               break;
        case CHIP_CARRIZO:
        case CHIP_STONEY:
                return 0;
@@ -1007,7 +979,7 @@ static int gmc_v8_0_hw_init(void *handle)
 
        gmc_v8_0_mc_program(adev);
 
-       if (!(adev->flags & AMD_IS_APU)) {
+       if (adev->asic_type == CHIP_TONGA) {
                r = gmc_v8_0_mc_load_microcode(adev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
index 966d4b2ed9dad0527a2d0246b23731f1d802d9e2..090486c182497ba8de2aaa7840242be9cf4750aa 100644 (file)
@@ -432,7 +432,7 @@ static uint32_t iceland_smu_get_mask_for_fw_type(uint32_t fw_type)
                case AMDGPU_UCODE_ID_CP_ME:
                        return UCODE_ID_CP_ME_MASK;
                case AMDGPU_UCODE_ID_CP_MEC1:
-                       return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK | UCODE_ID_CP_MEC_JT2_MASK;
+                       return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK;
                case AMDGPU_UCODE_ID_CP_MEC2:
                        return UCODE_ID_CP_MEC_MASK;
                case AMDGPU_UCODE_ID_RLC_G:
@@ -522,12 +522,6 @@ static int iceland_smu_request_load_fw(struct amdgpu_device *adev)
                return -EINVAL;
        }
 
-       if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2,
-                       &toc->entry[toc->num_entries++])) {
-               DRM_ERROR("Failed to get firmware entry for MEC_JT2\n");
-               return -EINVAL;
-       }
-
        if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0,
                        &toc->entry[toc->num_entries++])) {
                DRM_ERROR("Failed to get firmware entry for SDMA0\n");
@@ -550,8 +544,8 @@ static int iceland_smu_request_load_fw(struct amdgpu_device *adev)
                        UCODE_ID_CP_ME_MASK |
                        UCODE_ID_CP_PFP_MASK |
                        UCODE_ID_CP_MEC_MASK |
-                       UCODE_ID_CP_MEC_JT1_MASK |
-                       UCODE_ID_CP_MEC_JT2_MASK;
+                       UCODE_ID_CP_MEC_JT1_MASK;
+
 
        if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) {
                DRM_ERROR("Fail to request SMU load ucode\n");
index 7e9154c7f1dbbb7f9d3eee6791c0e4fcc835ea8d..654d76723bc39d8004b461c7c51d401384d2ee20 100644 (file)
@@ -2859,11 +2859,11 @@ static int kv_dpm_init(struct amdgpu_device *adev)
        pi->voltage_drop_t = 0;
        pi->caps_sclk_throttle_low_notification = false;
        pi->caps_fps = false; /* true? */
-       pi->caps_uvd_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_UVD) ? true : false;
+       pi->caps_uvd_pg = (adev->pg_flags & AMD_PG_SUPPORT_UVD) ? true : false;
        pi->caps_uvd_dpm = true;
-       pi->caps_vce_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_VCE) ? true : false;
-       pi->caps_samu_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_SAMU) ? true : false;
-       pi->caps_acp_pg = (adev->pg_flags & AMDGPU_PG_SUPPORT_ACP) ? true : false;
+       pi->caps_vce_pg = (adev->pg_flags & AMD_PG_SUPPORT_VCE) ? true : false;
+       pi->caps_samu_pg = (adev->pg_flags & AMD_PG_SUPPORT_SAMU) ? true : false;
+       pi->caps_acp_pg = (adev->pg_flags & AMD_PG_SUPPORT_ACP) ? true : false;
        pi->caps_stable_p_state = false;
 
        ret = kv_parse_sys_info_table(adev);
index 5e9f73af83a8431b25d6d153132df3a22ce31e31..fbd3767671bb9266d68ac6229a41194aa5a184ac 100644 (file)
@@ -611,7 +611,7 @@ static void uvd_v4_2_enable_mgcg(struct amdgpu_device *adev,
 {
        u32 orig, data;
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) {
                data = RREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL);
                data = 0xfff;
                WREG32_UVD_CTX(ixUVD_CGC_MEM_CTRL, data);
@@ -830,6 +830,9 @@ static int uvd_v4_2_set_clockgating_state(void *handle,
        bool gate = false;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
+               return 0;
+
        if (state == AMD_CG_STATE_GATE)
                gate = true;
 
@@ -848,7 +851,10 @@ static int uvd_v4_2_set_powergating_state(void *handle,
         * revisit this when there is a cleaner line between
         * the smc and the hw blocks
         */
-        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+               return 0;
 
        if (state == AMD_PG_STATE_GATE) {
                uvd_v4_2_stop(adev);
index 38864f5629814c7782682b4b8436b67e30aede3a..57f1c5bf3bf19a107c2c35d1b9fb653e2d37ac8d 100644 (file)
@@ -774,6 +774,11 @@ static int uvd_v5_0_process_interrupt(struct amdgpu_device *adev,
 static int uvd_v5_0_set_clockgating_state(void *handle,
                                          enum amd_clockgating_state state)
 {
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
+               return 0;
+
        return 0;
 }
 
@@ -789,6 +794,9 @@ static int uvd_v5_0_set_powergating_state(void *handle,
         */
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+               return 0;
+
        if (state == AMD_PG_STATE_GATE) {
                uvd_v5_0_stop(adev);
                return 0;
index 3d5913926436b6b759169575b9e235bc38f0d0df..0b365b7651ffbac65324701a13da702306e27467 100644 (file)
@@ -532,7 +532,7 @@ static int uvd_v6_0_start(struct amdgpu_device *adev)
        uvd_v6_0_mc_resume(adev);
 
        /* Set dynamic clock gating in S/W control mode */
-       if (adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG) {
+       if (adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG) {
                if (adev->flags & AMD_IS_APU)
                        cz_set_uvd_clock_gating_branches(adev, false);
                else
@@ -1000,7 +1000,7 @@ static int uvd_v6_0_set_clockgating_state(void *handle,
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
 
-       if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_UVD_MGCG))
+       if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
                return 0;
 
        if (enable) {
@@ -1030,6 +1030,9 @@ static int uvd_v6_0_set_powergating_state(void *handle,
         */
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
+               return 0;
+
        if (state == AMD_PG_STATE_GATE) {
                uvd_v6_0_stop(adev);
                return 0;
index 52ac7a8f1e58b91f3ad0c441b6a175062bddad29..a822edacfa95c979a60cb49eb6e4bb51239e05f0 100644 (file)
@@ -373,7 +373,7 @@ static void vce_v2_0_enable_mgcg(struct amdgpu_device *adev, bool enable)
 {
        bool sw_cg = false;
 
-       if (enable && (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)) {
+       if (enable && (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)) {
                if (sw_cg)
                        vce_v2_0_set_sw_cg(adev, true);
                else
@@ -608,6 +608,9 @@ static int vce_v2_0_set_powergating_state(void *handle,
         */
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
+               return 0;
+
        if (state == AMD_PG_STATE_GATE)
                /* XXX do we need a vce_v2_0_stop()? */
                return 0;
index e99af81e4aec3543278c681418138b12feae4c94..d662fa9f9091a33c51eefa8b0ae5d753229e195b 100644 (file)
@@ -277,7 +277,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
                WREG32_P(mmVCE_STATUS, 0, ~1);
 
                /* Set Clock-Gating off */
-               if (adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG)
+               if (adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG)
                        vce_v3_0_set_vce_sw_clock_gating(adev, false);
 
                if (r) {
@@ -676,7 +676,7 @@ static int vce_v3_0_set_clockgating_state(void *handle,
        bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
        int i;
 
-       if (!(adev->cg_flags & AMDGPU_CG_SUPPORT_VCE_MGCG))
+       if (!(adev->cg_flags & AMD_CG_SUPPORT_VCE_MGCG))
                return 0;
 
        mutex_lock(&adev->grbm_idx_mutex);
@@ -728,6 +728,9 @@ static int vce_v3_0_set_powergating_state(void *handle,
         */
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       if (!(adev->pg_flags & AMD_PG_SUPPORT_VCE))
+               return 0;
+
        if (state == AMD_PG_STATE_GATE)
                /* XXX do we need a vce_v3_0_stop()? */
                return 0;
index 652e76644c31cab37fee1964797d890749fbf0a7..0d14d108a6c4adf7a152edcff56cafa4b219cf1a 100644 (file)
@@ -61,6 +61,7 @@
 #include "vi.h"
 #include "vi_dpm.h"
 #include "gmc_v8_0.h"
+#include "gmc_v7_0.h"
 #include "gfx_v8_0.h"
 #include "sdma_v2_4.h"
 #include "sdma_v3_0.h"
@@ -1109,10 +1110,10 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] =
        },
        {
                .type = AMD_IP_BLOCK_TYPE_GMC,
-               .major = 8,
-               .minor = 0,
+               .major = 7,
+               .minor = 4,
                .rev = 0,
-               .funcs = &gmc_v8_0_ip_funcs,
+               .funcs = &gmc_v7_0_ip_funcs,
        },
        {
                .type = AMD_IP_BLOCK_TYPE_IH,
@@ -1442,8 +1443,7 @@ static int vi_common_early_init(void *handle)
                break;
        case CHIP_FIJI:
                adev->has_uvd = true;
-               adev->cg_flags = AMDGPU_CG_SUPPORT_UVD_MGCG |
-                               AMDGPU_CG_SUPPORT_VCE_MGCG;
+               adev->cg_flags = 0;
                adev->pg_flags = 0;
                adev->external_rev_id = adev->rev_id + 0x3c;
                break;
@@ -1457,8 +1457,7 @@ static int vi_common_early_init(void *handle)
        case CHIP_STONEY:
                adev->has_uvd = true;
                adev->cg_flags = 0;
-               /* Disable UVD pg */
-               adev->pg_flags = /* AMDGPU_PG_SUPPORT_UVD | */AMDGPU_PG_SUPPORT_VCE;
+               adev->pg_flags = 0;
                adev->external_rev_id = adev->rev_id + 0x1;
                break;
        default:
index 9be007081b72a8b5c75b4baf1fe01e92bfe792bc..a902ae037398389cf6e19c1ab7379ca64e6a46ed 100644 (file)
@@ -194,7 +194,7 @@ static void kfd_process_wq_release(struct work_struct *work)
 
        kfree(p);
 
-       kfree((void *)work);
+       kfree(work);
 }
 
 static void kfd_process_destroy_delayed(struct rcu_head *rcu)
index 1195d06f55bc491930f434684324a6618f22d087..dbf7e6413cab4207940659b81ceb02095b4ae515 100644 (file)
@@ -85,6 +85,38 @@ enum amd_powergating_state {
        AMD_PG_STATE_UNGATE,
 };
 
+/* CG flags */
+#define AMD_CG_SUPPORT_GFX_MGCG                        (1 << 0)
+#define AMD_CG_SUPPORT_GFX_MGLS                        (1 << 1)
+#define AMD_CG_SUPPORT_GFX_CGCG                        (1 << 2)
+#define AMD_CG_SUPPORT_GFX_CGLS                        (1 << 3)
+#define AMD_CG_SUPPORT_GFX_CGTS                        (1 << 4)
+#define AMD_CG_SUPPORT_GFX_CGTS_LS             (1 << 5)
+#define AMD_CG_SUPPORT_GFX_CP_LS               (1 << 6)
+#define AMD_CG_SUPPORT_GFX_RLC_LS              (1 << 7)
+#define AMD_CG_SUPPORT_MC_LS                   (1 << 8)
+#define AMD_CG_SUPPORT_MC_MGCG                 (1 << 9)
+#define AMD_CG_SUPPORT_SDMA_LS                 (1 << 10)
+#define AMD_CG_SUPPORT_SDMA_MGCG               (1 << 11)
+#define AMD_CG_SUPPORT_BIF_LS                  (1 << 12)
+#define AMD_CG_SUPPORT_UVD_MGCG                        (1 << 13)
+#define AMD_CG_SUPPORT_VCE_MGCG                        (1 << 14)
+#define AMD_CG_SUPPORT_HDP_LS                  (1 << 15)
+#define AMD_CG_SUPPORT_HDP_MGCG                        (1 << 16)
+
+/* PG flags */
+#define AMD_PG_SUPPORT_GFX_PG                  (1 << 0)
+#define AMD_PG_SUPPORT_GFX_SMG                 (1 << 1)
+#define AMD_PG_SUPPORT_GFX_DMG                 (1 << 2)
+#define AMD_PG_SUPPORT_UVD                     (1 << 3)
+#define AMD_PG_SUPPORT_VCE                     (1 << 4)
+#define AMD_PG_SUPPORT_CP                      (1 << 5)
+#define AMD_PG_SUPPORT_GDS                     (1 << 6)
+#define AMD_PG_SUPPORT_RLC_SMU_HS              (1 << 7)
+#define AMD_PG_SUPPORT_SDMA                    (1 << 8)
+#define AMD_PG_SUPPORT_ACP                     (1 << 9)
+#define AMD_PG_SUPPORT_SAMU                    (1 << 10)
+
 enum amd_pm_state_type {
        /* not used for dpm */
        POWER_STATE_TYPE_DEFAULT,
index 713aec95469271e7a678b73ab917f9a49258455e..aec38fc3834f9d867b4477c2f1d1d1166285f1fe 100644 (file)
@@ -109,6 +109,8 @@ enum cgs_system_info_id {
        CGS_SYSTEM_INFO_ADAPTER_BDF_ID = 1,
        CGS_SYSTEM_INFO_PCIE_GEN_INFO,
        CGS_SYSTEM_INFO_PCIE_MLW,
+       CGS_SYSTEM_INFO_CG_FLAGS,
+       CGS_SYSTEM_INFO_PG_FLAGS,
        CGS_SYSTEM_INFO_ID_MAXIMUM,
 };
 
index aa67244a77ae38cf69761bc964c5f1d4400874c5..589599f66fcce851e9ce5b94b2c5617544165022 100644 (file)
@@ -402,8 +402,11 @@ int pp_dpm_dispatch_tasks(void *handle, enum amd_pp_event event_id, void *input,
 
                data.requested_ui_label = power_state_convert(ps);
                ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+               break;
        }
-       break;
+       case AMD_PP_EVENT_COMPLETE_INIT:
+               ret = pem_handle_event(pp_handle->eventmgr, event_id, &data);
+               break;
        default:
                break;
        }
index 83be3cf210e01439c224e78a5681606472d40bfa..6b52c78cb404870ae019b3cd262f7d9711b590b3 100644 (file)
@@ -165,6 +165,7 @@ const struct action_chain resume_action_chain = {
 };
 
 static const pem_event_action *complete_init_event[] = {
+       unblock_adjust_power_state_tasks,
        adjust_power_state_tasks,
        enable_gfx_clock_gating_tasks,
        enable_gfx_voltage_island_power_gating_tasks,
index 52a3efc97f05651bfb0daeaf475d5a4bfadbd43f..46410e3c73493acce741f955f60790fc9745256e 100644 (file)
@@ -31,7 +31,7 @@
 static int pem_init(struct pp_eventmgr *eventmgr)
 {
        int result = 0;
-       struct pem_event_data event_data;
+       struct pem_event_data event_data = { {0} };
 
        /* Initialize PowerPlay feature info */
        pem_init_feature_info(eventmgr);
@@ -52,7 +52,7 @@ static int pem_init(struct pp_eventmgr *eventmgr)
 
 static void pem_fini(struct pp_eventmgr *eventmgr)
 {
-       struct pem_event_data event_data;
+       struct pem_event_data event_data = { {0} };
 
        pem_uninit_featureInfo(eventmgr);
        pem_unregister_interrupts(eventmgr);
index ad7700822a1cb2ee26235bf6bbba9541480ff88e..ff08ce41bde92f82596894ee178a545916d288df 100644 (file)
@@ -226,7 +226,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
                }
        } else {
                cz_dpm_update_vce_dpm(hwmgr);
-               cz_enable_disable_vce_dpm(hwmgr, true);
+               cz_enable_disable_vce_dpm(hwmgr, !bgate);
                return 0;
        }
 
index 0874ab42ee95e7e83d4a027639b97a1a45a35890..cf01177ca3b5e36eb845fe187f13b7135cde03b6 100644 (file)
@@ -174,6 +174,8 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
 {
        struct cz_hwmgr *cz_hwmgr = (struct cz_hwmgr *)(hwmgr->backend);
        uint32_t i;
+       struct cgs_system_info sys_info = {0};
+       int result;
 
        cz_hwmgr->gfx_ramp_step = 256*25/100;
 
@@ -247,6 +249,22 @@ static int cz_initialize_dpm_defaults(struct pp_hwmgr *hwmgr)
        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
                                   PHM_PlatformCaps_DisableVoltageIsland);
 
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_UVDPowerGating);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_VCEPowerGating);
+       sys_info.size = sizeof(struct cgs_system_info);
+       sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
+       result = cgs_query_system_info(hwmgr->device, &sys_info);
+       if (!result) {
+               if (sys_info.value & AMD_PG_SUPPORT_UVD)
+                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                     PHM_PlatformCaps_UVDPowerGating);
+               if (sys_info.value & AMD_PG_SUPPORT_VCE)
+                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                     PHM_PlatformCaps_VCEPowerGating);
+       }
+
        return 0;
 }
 
index 44a925006479176617c54a5fa3c33a1eb6b92bad..980d3bf8ea768e161ffbba4cde1b960ea46e7819 100644 (file)
@@ -4451,6 +4451,7 @@ int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
        pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
        struct phm_ppt_v1_information *pptable_info = (struct phm_ppt_v1_information *)(hwmgr->pptable);
        phw_tonga_ulv_parm *ulv;
+       struct cgs_system_info sys_info = {0};
 
        PP_ASSERT_WITH_CODE((NULL != hwmgr),
                "Invalid Parameter!", return -1;);
@@ -4615,9 +4616,23 @@ int tonga_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
 
        data->vddc_phase_shed_control = 0;
 
-       if (0 == result) {
-               struct cgs_system_info sys_info = {0};
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_UVDPowerGating);
+       phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                     PHM_PlatformCaps_VCEPowerGating);
+       sys_info.size = sizeof(struct cgs_system_info);
+       sys_info.info_id = CGS_SYSTEM_INFO_PG_FLAGS;
+       result = cgs_query_system_info(hwmgr->device, &sys_info);
+       if (!result) {
+               if (sys_info.value & AMD_PG_SUPPORT_UVD)
+                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                     PHM_PlatformCaps_UVDPowerGating);
+               if (sys_info.value & AMD_PG_SUPPORT_VCE)
+                       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                                     PHM_PlatformCaps_VCEPowerGating);
+       }
 
+       if (0 == result) {
                data->is_tlu_enabled = 0;
                hwmgr->platform_descriptor.hardwareActivityPerformanceLevels =
                        TONGA_MAX_HARDWARE_POWERLEVELS;
index 9759009d1da367cd8b3f264671ea7942aa3ab79a..b1480acbb3c3587c720570031eae9c41498d1d93 100644 (file)
@@ -227,7 +227,7 @@ static int ast_get_dram_info(struct drm_device *dev)
        } while (ast_read32(ast, 0x10000) != 0x01);
        data = ast_read32(ast, 0x10004);
 
-       if (data & 0x400)
+       if (data & 0x40)
                ast->dram_bus_width = 16;
        else
                ast->dram_bus_width = 32;
index 3f74193885f1ff1df95db09fa76e01174f6353b4..9a7b44616b552920b6ef8f62553bd791d36af935 100644 (file)
@@ -65,8 +65,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
         */
        state->allow_modeset = true;
 
-       state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
-
        state->crtcs = kcalloc(dev->mode_config.num_crtc,
                               sizeof(*state->crtcs), GFP_KERNEL);
        if (!state->crtcs)
@@ -83,16 +81,6 @@ drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
                                      sizeof(*state->plane_states), GFP_KERNEL);
        if (!state->plane_states)
                goto fail;
-       state->connectors = kcalloc(state->num_connector,
-                                   sizeof(*state->connectors),
-                                   GFP_KERNEL);
-       if (!state->connectors)
-               goto fail;
-       state->connector_states = kcalloc(state->num_connector,
-                                         sizeof(*state->connector_states),
-                                         GFP_KERNEL);
-       if (!state->connector_states)
-               goto fail;
 
        state->dev = dev;
 
@@ -823,19 +811,27 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
 
        index = drm_connector_index(connector);
 
-       /*
-        * Construction of atomic state updates can race with a connector
-        * hot-add which might overflow. In this case flip the table and just
-        * restart the entire ioctl - no one is fast enough to livelock a cpu
-        * with physical hotplug events anyway.
-        *
-        * Note that we only grab the indexes once we have the right lock to
-        * prevent hotplug/unplugging of connectors. So removal is no problem,
-        * at most the array is a bit too large.
-        */
        if (index >= state->num_connector) {
-               DRM_DEBUG_ATOMIC("Hot-added connector would overflow state array, restarting\n");
-               return ERR_PTR(-EAGAIN);
+               struct drm_connector **c;
+               struct drm_connector_state **cs;
+               int alloc = max(index + 1, config->num_connector);
+
+               c = krealloc(state->connectors, alloc * sizeof(*state->connectors), GFP_KERNEL);
+               if (!c)
+                       return ERR_PTR(-ENOMEM);
+
+               state->connectors = c;
+               memset(&state->connectors[state->num_connector], 0,
+                      sizeof(*state->connectors) * (alloc - state->num_connector));
+
+               cs = krealloc(state->connector_states, alloc * sizeof(*state->connector_states), GFP_KERNEL);
+               if (!cs)
+                       return ERR_PTR(-ENOMEM);
+
+               state->connector_states = cs;
+               memset(&state->connector_states[state->num_connector], 0,
+                      sizeof(*state->connector_states) * (alloc - state->num_connector));
+               state->num_connector = alloc;
        }
 
        if (state->connector_states[index])
index 7c523060a076f715746829004657b227a9308640..4f2d3e161593057bfff2b046c1b1f30a3cc90d41 100644 (file)
@@ -1493,7 +1493,7 @@ void drm_atomic_helper_swap_state(struct drm_device *dev,
 {
        int i;
 
-       for (i = 0; i < dev->mode_config.num_connector; i++) {
+       for (i = 0; i < state->num_connector; i++) {
                struct drm_connector *connector = state->connectors[i];
 
                if (!connector)
index d40bab29747edb0ea989afd81b0e5b5102dfb555..f6191215b2cbc97c11fbfda5eeadb9f61b2387e8 100644 (file)
@@ -918,12 +918,19 @@ int drm_connector_init(struct drm_device *dev,
        connector->base.properties = &connector->properties;
        connector->dev = dev;
        connector->funcs = funcs;
+
+       connector->connector_id = ida_simple_get(&config->connector_ida, 0, 0, GFP_KERNEL);
+       if (connector->connector_id < 0) {
+               ret = connector->connector_id;
+               goto out_put;
+       }
+
        connector->connector_type = connector_type;
        connector->connector_type_id =
                ida_simple_get(connector_ida, 1, 0, GFP_KERNEL);
        if (connector->connector_type_id < 0) {
                ret = connector->connector_type_id;
-               goto out_put;
+               goto out_put_id;
        }
        connector->name =
                kasprintf(GFP_KERNEL, "%s-%d",
@@ -931,7 +938,7 @@ int drm_connector_init(struct drm_device *dev,
                          connector->connector_type_id);
        if (!connector->name) {
                ret = -ENOMEM;
-               goto out_put;
+               goto out_put_type_id;
        }
 
        INIT_LIST_HEAD(&connector->probed_modes);
@@ -959,7 +966,12 @@ int drm_connector_init(struct drm_device *dev,
        }
 
        connector->debugfs_entry = NULL;
-
+out_put_type_id:
+       if (ret)
+               ida_remove(connector_ida, connector->connector_type_id);
+out_put_id:
+       if (ret)
+               ida_remove(&config->connector_ida, connector->connector_id);
 out_put:
        if (ret)
                drm_mode_object_put(dev, &connector->base);
@@ -996,6 +1008,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
        ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
                   connector->connector_type_id);
 
+       ida_remove(&dev->mode_config.connector_ida,
+                  connector->connector_id);
+
        kfree(connector->display_info.bus_formats);
        drm_mode_object_put(dev, &connector->base);
        kfree(connector->name);
@@ -1012,32 +1027,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
-/**
- * drm_connector_index - find the index of a registered connector
- * @connector: connector to find index for
- *
- * Given a registered connector, return the index of that connector within a DRM
- * device's list of connectors.
- */
-unsigned int drm_connector_index(struct drm_connector *connector)
-{
-       unsigned int index = 0;
-       struct drm_connector *tmp;
-       struct drm_mode_config *config = &connector->dev->mode_config;
-
-       WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
-
-       drm_for_each_connector(tmp, connector->dev) {
-               if (tmp == connector)
-                       return index;
-
-               index++;
-       }
-
-       BUG();
-}
-EXPORT_SYMBOL(drm_connector_index);
-
 /**
  * drm_connector_register - register a connector
  * @connector: the connector to register
@@ -5789,6 +5778,7 @@ void drm_mode_config_init(struct drm_device *dev)
        INIT_LIST_HEAD(&dev->mode_config.plane_list);
        idr_init(&dev->mode_config.crtc_idr);
        idr_init(&dev->mode_config.tile_idr);
+       ida_init(&dev->mode_config.connector_ida);
 
        drm_modeset_lock_all(dev);
        drm_mode_create_standard_properties(dev);
@@ -5869,6 +5859,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
                crtc->funcs->destroy(crtc);
        }
 
+       ida_destroy(&dev->mode_config.connector_ida);
        idr_destroy(&dev->mode_config.tile_idr);
        idr_destroy(&dev->mode_config.crtc_idr);
        drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
index 6ed90a2437e50438c713fc028f28705e7954b806..27fbd79d0daf0003be2014cee00c9dcdb49fdb43 100644 (file)
@@ -803,12 +803,33 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad)
        return mstb;
 }
 
+static void drm_dp_free_mst_port(struct kref *kref);
+
+static void drm_dp_free_mst_branch_device(struct kref *kref)
+{
+       struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
+       if (mstb->port_parent) {
+               if (list_empty(&mstb->port_parent->next))
+                       kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port);
+       }
+       kfree(mstb);
+}
+
 static void drm_dp_destroy_mst_branch_device(struct kref *kref)
 {
        struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
        struct drm_dp_mst_port *port, *tmp;
        bool wake_tx = false;
 
+       /*
+        * init kref again to be used by ports to remove mst branch when it is
+        * not needed anymore
+        */
+       kref_init(kref);
+
+       if (mstb->port_parent && list_empty(&mstb->port_parent->next))
+               kref_get(&mstb->port_parent->kref);
+
        /*
         * destroy all ports - don't need lock
         * as there are no more references to the mst branch
@@ -835,7 +856,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
 
        if (wake_tx)
                wake_up(&mstb->mgr->tx_waitq);
-       kfree(mstb);
+
+       kref_put(kref, drm_dp_free_mst_branch_device);
 }
 
 static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
@@ -883,6 +905,7 @@ static void drm_dp_destroy_port(struct kref *kref)
                         * from an EDID retrieval */
 
                        mutex_lock(&mgr->destroy_connector_lock);
+                       kref_get(&port->parent->kref);
                        list_add(&port->next, &mgr->destroy_connector_list);
                        mutex_unlock(&mgr->destroy_connector_lock);
                        schedule_work(&mgr->destroy_connector_work);
@@ -1018,18 +1041,27 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port)
        return send_link;
 }
 
-static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
-                                  struct drm_dp_mst_port *port)
+static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
 {
        int ret;
-       if (port->dpcd_rev >= 0x12) {
-               port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid);
-               if (!port->guid_valid) {
-                       ret = drm_dp_send_dpcd_write(mstb->mgr,
-                                                    port,
-                                                    DP_GUID,
-                                                    16, port->guid);
-                       port->guid_valid = true;
+
+       memcpy(mstb->guid, guid, 16);
+
+       if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
+               if (mstb->port_parent) {
+                       ret = drm_dp_send_dpcd_write(
+                                       mstb->mgr,
+                                       mstb->port_parent,
+                                       DP_GUID,
+                                       16,
+                                       mstb->guid);
+               } else {
+
+                       ret = drm_dp_dpcd_write(
+                                       mstb->mgr->aux,
+                                       DP_GUID,
+                                       mstb->guid,
+                                       16);
                }
        }
 }
@@ -1086,7 +1118,6 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
        port->dpcd_rev = port_msg->dpcd_revision;
        port->num_sdp_streams = port_msg->num_sdp_streams;
        port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks;
-       memcpy(port->guid, port_msg->peer_guid, 16);
 
        /* manage mstb port lists with mgr lock - take a reference
           for this list */
@@ -1099,11 +1130,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
 
        if (old_ddps != port->ddps) {
                if (port->ddps) {
-                       drm_dp_check_port_guid(mstb, port);
                        if (!port->input)
                                drm_dp_send_enum_path_resources(mstb->mgr, mstb, port);
                } else {
-                       port->guid_valid = false;
                        port->available_pbn = 0;
                        }
        }
@@ -1162,10 +1191,8 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb,
 
        if (old_ddps != port->ddps) {
                if (port->ddps) {
-                       drm_dp_check_port_guid(mstb, port);
                        dowork = true;
                } else {
-                       port->guid_valid = false;
                        port->available_pbn = 0;
                }
        }
@@ -1222,13 +1249,14 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
        struct drm_dp_mst_branch *found_mstb;
        struct drm_dp_mst_port *port;
 
+       if (memcmp(mstb->guid, guid, 16) == 0)
+               return mstb;
+
+
        list_for_each_entry(port, &mstb->ports, next) {
                if (!port->mstb)
                        continue;
 
-               if (port->guid_valid && memcmp(port->guid, guid, 16) == 0)
-                       return port->mstb;
-
                found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
 
                if (found_mstb)
@@ -1247,10 +1275,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid(
        /* find the port by iterating down */
        mutex_lock(&mgr->lock);
 
-       if (mgr->guid_valid && memcmp(mgr->guid, guid, 16) == 0)
-               mstb = mgr->mst_primary;
-       else
-               mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
+       mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid);
 
        if (mstb)
                kref_get(&mstb->kref);
@@ -1555,6 +1580,9 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
                                       txmsg->reply.u.link_addr.ports[i].num_sdp_streams,
                                       txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks);
                        }
+
+                       drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid);
+
                        for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) {
                                drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]);
                        }
@@ -1602,6 +1630,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
        return 0;
 }
 
+static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
+{
+       if (!mstb->port_parent)
+               return NULL;
+
+       if (mstb->port_parent->mstb != mstb)
+               return mstb->port_parent;
+
+       return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent);
+}
+
+static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr,
+                                                                        struct drm_dp_mst_branch *mstb,
+                                                                        int *port_num)
+{
+       struct drm_dp_mst_branch *rmstb = NULL;
+       struct drm_dp_mst_port *found_port;
+       mutex_lock(&mgr->lock);
+       if (mgr->mst_primary) {
+               found_port = drm_dp_get_last_connected_port_to_mstb(mstb);
+
+               if (found_port) {
+                       rmstb = found_port->parent;
+                       kref_get(&rmstb->kref);
+                       *port_num = found_port->port_num;
+               }
+       }
+       mutex_unlock(&mgr->lock);
+       return rmstb;
+}
+
 static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
                                   struct drm_dp_mst_port *port,
                                   int id,
@@ -1609,13 +1668,18 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
 {
        struct drm_dp_sideband_msg_tx *txmsg;
        struct drm_dp_mst_branch *mstb;
-       int len, ret;
+       int len, ret, port_num;
        u8 sinks[DRM_DP_MAX_SDP_STREAMS];
        int i;
 
+       port_num = port->port_num;
        mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
-       if (!mstb)
-               return -EINVAL;
+       if (!mstb) {
+               mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
+
+               if (!mstb)
+                       return -EINVAL;
+       }
 
        txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
        if (!txmsg) {
@@ -1627,7 +1691,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
                sinks[i] = i;
 
        txmsg->dst = mstb;
-       len = build_allocate_payload(txmsg, port->port_num,
+       len = build_allocate_payload(txmsg, port_num,
                                     id,
                                     pbn, port->num_sdp_streams, sinks);
 
@@ -1983,31 +2047,17 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
                mgr->mst_primary = mstb;
                kref_get(&mgr->mst_primary->kref);
 
-               {
-                       struct drm_dp_payload reset_pay;
-                       reset_pay.start_slot = 0;
-                       reset_pay.num_slots = 0x3f;
-                       drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
-               }
-
                ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
-                                        DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
+                                                        DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC);
                if (ret < 0) {
                        goto out_unlock;
                }
 
-
-               /* sort out guid */
-               ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16);
-               if (ret != 16) {
-                       DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret);
-                       goto out_unlock;
-               }
-
-               mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid);
-               if (!mgr->guid_valid) {
-                       ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16);
-                       mgr->guid_valid = true;
+               {
+                       struct drm_dp_payload reset_pay;
+                       reset_pay.start_slot = 0;
+                       reset_pay.num_slots = 0x3f;
+                       drm_dp_dpcd_write_payload(mgr, 0, &reset_pay);
                }
 
                queue_work(system_long_wq, &mgr->work);
@@ -2231,6 +2281,7 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr)
                        }
 
                        drm_dp_update_port(mstb, &msg.u.conn_stat);
+
                        DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type);
                        (*mgr->cbs->hotplug)(mgr);
 
@@ -2446,6 +2497,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp
                DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn);
                if (pbn == port->vcpi.pbn) {
                        *slots = port->vcpi.num_slots;
+                       drm_dp_put_port(port);
                        return true;
                }
        }
@@ -2605,32 +2657,31 @@ EXPORT_SYMBOL(drm_dp_check_act_status);
  */
 int drm_dp_calc_pbn_mode(int clock, int bpp)
 {
-       fixed20_12 pix_bw;
-       fixed20_12 fbpp;
-       fixed20_12 result;
-       fixed20_12 margin, tmp;
-       u32 res;
-
-       pix_bw.full = dfixed_const(clock);
-       fbpp.full = dfixed_const(bpp);
-       tmp.full = dfixed_const(8);
-       fbpp.full = dfixed_div(fbpp, tmp);
-
-       result.full = dfixed_mul(pix_bw, fbpp);
-       margin.full = dfixed_const(54);
-       tmp.full = dfixed_const(64);
-       margin.full = dfixed_div(margin, tmp);
-       result.full = dfixed_div(result, margin);
-
-       margin.full = dfixed_const(1006);
-       tmp.full = dfixed_const(1000);
-       margin.full = dfixed_div(margin, tmp);
-       result.full = dfixed_mul(result, margin);
-
-       result.full = dfixed_div(result, tmp);
-       result.full = dfixed_ceil(result);
-       res = dfixed_trunc(result);
-       return res;
+       u64 kbps;
+       s64 peak_kbps;
+       u32 numerator;
+       u32 denominator;
+
+       kbps = clock * bpp;
+
+       /*
+        * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006
+        * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on
+        * common multiplier to render an integer PBN for all link rate/lane
+        * counts combinations
+        * calculate
+        * peak_kbps *= (1006/1000)
+        * peak_kbps *= (64/54)
+        * peak_kbps *= 8    convert to bytes
+        */
+
+       numerator = 64 * 1006;
+       denominator = 54 * 8 * 1000 * 1000;
+
+       kbps *= numerator;
+       peak_kbps = drm_fixp_from_fraction(kbps, denominator);
+
+       return drm_fixp2int_ceil(peak_kbps);
 }
 EXPORT_SYMBOL(drm_dp_calc_pbn_mode);
 
@@ -2638,11 +2689,23 @@ static int test_calc_pbn_mode(void)
 {
        int ret;
        ret = drm_dp_calc_pbn_mode(154000, 30);
-       if (ret != 689)
+       if (ret != 689) {
+               DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+                               154000, 30, 689, ret);
                return -EINVAL;
+       }
        ret = drm_dp_calc_pbn_mode(234000, 30);
-       if (ret != 1047)
+       if (ret != 1047) {
+               DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+                               234000, 30, 1047, ret);
+               return -EINVAL;
+       }
+       ret = drm_dp_calc_pbn_mode(297000, 24);
+       if (ret != 1063) {
+               DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n",
+                               297000, 24, 1063, ret);
                return -EINVAL;
+       }
        return 0;
 }
 
@@ -2783,6 +2846,13 @@ static void drm_dp_tx_work(struct work_struct *work)
        mutex_unlock(&mgr->qlock);
 }
 
+static void drm_dp_free_mst_port(struct kref *kref)
+{
+       struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
+       kref_put(&port->parent->kref, drm_dp_free_mst_branch_device);
+       kfree(port);
+}
+
 static void drm_dp_destroy_connector_work(struct work_struct *work)
 {
        struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
@@ -2803,13 +2873,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
                list_del(&port->next);
                mutex_unlock(&mgr->destroy_connector_lock);
 
+               kref_init(&port->kref);
+               INIT_LIST_HEAD(&port->next);
+
                mgr->cbs->destroy_connector(mgr, port->connector);
 
                drm_dp_port_teardown_pdt(port, port->pdt);
 
-               if (!port->input && port->vcpi.vcpi > 0)
-                       drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
-               kfree(port);
+               if (!port->input && port->vcpi.vcpi > 0) {
+                       if (mgr->mst_state) {
+                               drm_dp_mst_reset_vcpi_slots(mgr, port);
+                               drm_dp_update_payload_part1(mgr);
+                               drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
+                       }
+               }
+
+               kref_put(&port->kref, drm_dp_free_mst_port);
                send_hotplug = true;
        }
        if (send_hotplug)
@@ -2847,6 +2926,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
        mgr->max_dpcd_transaction_bytes = max_dpcd_transaction_bytes;
        mgr->max_payloads = max_payloads;
        mgr->conn_base_id = conn_base_id;
+       if (max_payloads + 1 > sizeof(mgr->payload_mask) * 8 ||
+           max_payloads + 1 > sizeof(mgr->vcpi_mask) * 8)
+               return -EINVAL;
        mgr->payloads = kcalloc(max_payloads, sizeof(struct drm_dp_payload), GFP_KERNEL);
        if (!mgr->payloads)
                return -ENOMEM;
@@ -2854,7 +2936,9 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
        if (!mgr->proposed_vcpis)
                return -ENOMEM;
        set_bit(0, &mgr->payload_mask);
-       test_calc_pbn_mode();
+       if (test_calc_pbn_mode() < 0)
+               DRM_ERROR("MST PBN self-test failed\n");
+
        return 0;
 }
 EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
index d12a4efa651b015179f776e1fc056da96dc1faf0..1fe14579e8c941b002c5362f7c69936c85cf855b 100644 (file)
@@ -224,6 +224,64 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
                diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
        }
 
+       /*
+        * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
+        * interval? If so then vblank irqs keep running and it will likely
+        * happen that the hardware vblank counter is not trustworthy as it
+        * might reset at some point in that interval and vblank timestamps
+        * are not trustworthy either in that interval. Iow. this can result
+        * in a bogus diff >> 1 which must be avoided as it would cause
+        * random large forward jumps of the software vblank counter.
+        */
+       if (diff > 1 && (vblank->inmodeset & 0x2)) {
+               DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
+                             " due to pre-modeset.\n", pipe, diff);
+               diff = 1;
+       }
+
+       /*
+        * FIMXE: Need to replace this hack with proper seqlocks.
+        *
+        * Restrict the bump of the software vblank counter to a safe maximum
+        * value of +1 whenever there is the possibility that concurrent readers
+        * of vblank timestamps could be active at the moment, as the current
+        * implementation of the timestamp caching and updating is not safe
+        * against concurrent readers for calls to store_vblank() with a bump
+        * of anything but +1. A bump != 1 would very likely return corrupted
+        * timestamps to userspace, because the same slot in the cache could
+        * be concurrently written by store_vblank() and read by one of those
+        * readers without the read-retry logic detecting the collision.
+        *
+        * Concurrent readers can exist when we are called from the
+        * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
+        * irq callers. However, all those calls to us are happening with the
+        * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
+        * can't increase while we are executing. Therefore a zero refcount at
+        * this point is safe for arbitrary counter bumps if we are called
+        * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
+        * we must also accept a refcount of 1, as whenever we are called from
+        * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
+        * we must let that one pass through in order to not lose vblank counts
+        * during vblank irq off - which would completely defeat the whole
+        * point of this routine.
+        *
+        * Whenever we are called from vblank irq, we have to assume concurrent
+        * readers exist or can show up any time during our execution, even if
+        * the refcount is currently zero, as vblank irqs are usually only
+        * enabled due to the presence of readers, and because when we are called
+        * from vblank irq we can't hold the vbl_lock to protect us from sudden
+        * bumps in vblank refcount. Therefore also restrict bumps to +1 when
+        * called from vblank irq.
+        */
+       if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
+           (flags & DRM_CALLED_FROM_VBLIRQ))) {
+               DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
+                             "refcount %u, vblirq %u\n", pipe, diff,
+                             atomic_read(&vblank->refcount),
+                             (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
+               diff = 1;
+       }
+
        DRM_DEBUG_VBL("updating vblank count on crtc %u:"
                      " current=%u, diff=%u, hw=%u hw_last=%u\n",
                      pipe, vblank->count, diff, cur_vblank, vblank->last);
@@ -1316,7 +1374,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
        spin_lock_irqsave(&dev->event_lock, irqflags);
 
        spin_lock(&dev->vbl_lock);
-       vblank_disable_and_save(dev, pipe);
+       DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+                     pipe, vblank->enabled, vblank->inmodeset);
+
+       /* Avoid redundant vblank disables without previous drm_vblank_on(). */
+       if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
+               vblank_disable_and_save(dev, pipe);
+
        wake_up(&vblank->queue);
 
        /*
@@ -1418,6 +1482,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
                return;
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
+                     pipe, vblank->enabled, vblank->inmodeset);
+
        /* Drop our private "prevent drm_vblank_get" refcount */
        if (vblank->inmodeset) {
                atomic_dec(&vblank->refcount);
@@ -1430,8 +1497,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
         * re-enable interrupts if there are users left, or the
         * user wishes vblank interrupts to be enabled all the time.
         */
-       if (atomic_read(&vblank->refcount) != 0 ||
-           (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
+       if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
                WARN_ON(drm_vblank_enable(dev, pipe));
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
@@ -1526,6 +1592,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
        if (vblank->inmodeset) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                dev->vblank_disable_allowed = true;
+               drm_reset_vblank_timestamp(dev, pipe);
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 
                if (vblank->inmodeset & 0x2)
index 83efca941388a73874a8da10412c77d9bc3801e4..f17d3927959604301e9e53c7614fcb1e4982e80c 100644 (file)
@@ -1,6 +1,6 @@
 config DRM_EXYNOS
        tristate "DRM Support for Samsung SoC EXYNOS Series"
-       depends on OF && DRM && (PLAT_SAMSUNG || ARCH_MULTIPLATFORM)
+       depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM)
        select DRM_KMS_HELPER
        select DRM_KMS_FB_HELPER
        select FB_CFB_FILLRECT
index 1bf6a21130c7cbde6088dbb70e2a2b650f244b06..162ab93e99cb519e20963066c2285d50b6f08b88 100644 (file)
@@ -93,7 +93,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
        if (test_bit(BIT_SUSPENDED, &ctx->flags))
                return -EPERM;
 
-       if (test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
+       if (!test_and_set_bit(BIT_IRQS_ENABLED, &ctx->flags)) {
                val = VIDINTCON0_INTEN;
                if (ctx->out_type == IFTYPE_I80)
                        val |= VIDINTCON0_FRAMEDONE;
@@ -402,8 +402,6 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
                decon_enable_vblank(ctx->crtc);
 
        decon_commit(ctx->crtc);
-
-       set_bit(BIT_SUSPENDED, &ctx->flags);
 }
 
 static void decon_disable(struct exynos_drm_crtc *crtc)
@@ -582,9 +580,9 @@ out:
 static int exynos5433_decon_suspend(struct device *dev)
 {
        struct decon_context *ctx = dev_get_drvdata(dev);
-       int i;
+       int i = ARRAY_SIZE(decon_clks_name);
 
-       for (i = 0; i < ARRAY_SIZE(decon_clks_name); i++)
+       while (--i >= 0)
                clk_disable_unprepare(ctx->clks[i]);
 
        return 0;
index b79c316c2ad2ce7b7eb48e152a49c41ab6e93431..673164b331c8806e14aaa10d82e2f787c10bfb09 100644 (file)
@@ -1392,7 +1392,7 @@ static const struct component_ops exynos_dp_ops = {
 static int exynos_dp_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *panel_node = NULL, *bridge_node, *endpoint = NULL;
+       struct device_node *np = NULL, *endpoint = NULL;
        struct exynos_dp_device *dp;
        int ret;
 
@@ -1404,41 +1404,36 @@ static int exynos_dp_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, dp);
 
        /* This is for the backward compatibility. */
-       panel_node = of_parse_phandle(dev->of_node, "panel", 0);
-       if (panel_node) {
-               dp->panel = of_drm_find_panel(panel_node);
-               of_node_put(panel_node);
+       np = of_parse_phandle(dev->of_node, "panel", 0);
+       if (np) {
+               dp->panel = of_drm_find_panel(np);
+               of_node_put(np);
                if (!dp->panel)
                        return -EPROBE_DEFER;
-       } else {
-               endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
-               if (endpoint) {
-                       panel_node = of_graph_get_remote_port_parent(endpoint);
-                       if (panel_node) {
-                               dp->panel = of_drm_find_panel(panel_node);
-                               of_node_put(panel_node);
-                               if (!dp->panel)
-                                       return -EPROBE_DEFER;
-                       } else {
-                               DRM_ERROR("no port node for panel device.\n");
-                               return -EINVAL;
-                       }
-               }
-       }
-
-       if (endpoint)
                goto out;
+       }
 
        endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
        if (endpoint) {
-               bridge_node = of_graph_get_remote_port_parent(endpoint);
-               if (bridge_node) {
-                       dp->ptn_bridge = of_drm_find_bridge(bridge_node);
-                       of_node_put(bridge_node);
-                       if (!dp->ptn_bridge)
-                               return -EPROBE_DEFER;
-               } else
-                       return -EPROBE_DEFER;
+               np = of_graph_get_remote_port_parent(endpoint);
+               if (np) {
+                       /* The remote port can be either a panel or a bridge */
+                       dp->panel = of_drm_find_panel(np);
+                       if (!dp->panel) {
+                               dp->ptn_bridge = of_drm_find_bridge(np);
+                               if (!dp->ptn_bridge) {
+                                       of_node_put(np);
+                                       return -EPROBE_DEFER;
+                               }
+                       }
+                       of_node_put(np);
+               } else {
+                       DRM_ERROR("no remote endpoint device node found.\n");
+                       return -EINVAL;
+               }
+       } else {
+               DRM_ERROR("no port endpoint subnode found.\n");
+               return -EINVAL;
        }
 
 out:
index d84a498ef099712c56f319c8333c8c8564ef457a..26e81d191f56eaa8b63f9755f9542dac034c9096 100644 (file)
@@ -1782,6 +1782,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
 
        bridge = of_drm_find_bridge(dsi->bridge_node);
        if (bridge) {
+               encoder->bridge = bridge;
                drm_bridge_attach(drm_dev, bridge);
        }
 
@@ -1906,8 +1907,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int exynos_dsi_suspend(struct device *dev)
+static int __maybe_unused exynos_dsi_suspend(struct device *dev)
 {
        struct drm_encoder *encoder = dev_get_drvdata(dev);
        struct exynos_dsi *dsi = encoder_to_dsi(encoder);
@@ -1938,7 +1938,7 @@ static int exynos_dsi_suspend(struct device *dev)
        return 0;
 }
 
-static int exynos_dsi_resume(struct device *dev)
+static int __maybe_unused exynos_dsi_resume(struct device *dev)
 {
        struct drm_encoder *encoder = dev_get_drvdata(dev);
        struct exynos_dsi *dsi = encoder_to_dsi(encoder);
@@ -1972,7 +1972,6 @@ err_clk:
 
        return ret;
 }
-#endif
 
 static const struct dev_pm_ops exynos_dsi_pm_ops = {
        SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
index f6118baa8e3efad8732f8297ab6f6529d763171e..8baabd813ff55a1d713b0bdbf11386c135878d9a 100644 (file)
@@ -50,7 +50,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
        if (vm_size > exynos_gem->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->pages,
+       ret = dma_mmap_attrs(helper->dev->dev, vma, exynos_gem->cookie,
                             exynos_gem->dma_addr, exynos_gem->size,
                             &exynos_gem->dma_attrs);
        if (ret < 0) {
index c747824f3c98551bf2883a7659249a840359de62..8a4f4a0211d0dd57001f2605a4815dae06686b9f 100644 (file)
@@ -1723,7 +1723,7 @@ static int fimc_probe(struct platform_device *pdev)
                goto err_put_clk;
        }
 
-       DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
+       DRM_DEBUG_KMS("id[%d]ippdrv[%p]\n", ctx->id, ippdrv);
 
        spin_lock_init(&ctx->lock);
        platform_set_drvdata(pdev, ctx);
index c17efdb238a6e24f6fcecac58c395b8964b12703..8dfe6e113a883b315419755b75c5b01159c60373 100644 (file)
@@ -1166,7 +1166,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
                goto err_free_event;
        }
 
-       cmd = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd;
+       cmd = (struct drm_exynos_g2d_cmd *)(unsigned long)req->cmd;
 
        if (copy_from_user(cmdlist->data + cmdlist->last,
                                (void __user *)cmd,
@@ -1184,7 +1184,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
        if (req->cmd_buf_nr) {
                struct drm_exynos_g2d_cmd *cmd_buf;
 
-               cmd_buf = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd_buf;
+               cmd_buf = (struct drm_exynos_g2d_cmd *)
+                               (unsigned long)req->cmd_buf;
 
                if (copy_from_user(cmdlist->data + cmdlist->last,
                                        (void __user *)cmd_buf,
index 32358c5e3db4be25e7127225fa86e343b97757c7..26b5e4bd55b6afd8f1cb042da863e90a5ee6ef8c 100644 (file)
@@ -218,7 +218,7 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
                return ERR_PTR(ret);
        }
 
-       DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
+       DRM_DEBUG_KMS("created file object = %p\n", obj->filp);
 
        return exynos_gem;
 }
@@ -335,7 +335,7 @@ static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
        if (vm_size > exynos_gem->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->pages,
+       ret = dma_mmap_attrs(drm_dev->dev, vma, exynos_gem->cookie,
                             exynos_gem->dma_addr, exynos_gem->size,
                             &exynos_gem->dma_attrs);
        if (ret < 0) {
index 7aecd23cfa11a6638d783366b890fd33a9c0ea2e..5d20da8f957e2eac724331bb866f7c1b96244087 100644 (file)
@@ -1723,7 +1723,7 @@ static int gsc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
+       DRM_DEBUG_KMS("id[%d]ippdrv[%p]\n", ctx->id, ippdrv);
 
        mutex_init(&ctx->lock);
        platform_set_drvdata(pdev, ctx);
index 67d24236e745c4dd1cc014ba0c5386784d3441f8..95eeb9116f102a931313eaea212e1e0aa4f89a18 100644 (file)
@@ -208,7 +208,7 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
         * e.g PAUSE state, queue buf, command control.
         */
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
-               DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
+               DRM_DEBUG_KMS("count[%d]ippdrv[%p]\n", count++, ippdrv);
 
                mutex_lock(&ippdrv->cmd_lock);
                list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
@@ -388,8 +388,8 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
        }
        property->prop_id = ret;
 
-       DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
-               property->prop_id, property->cmd, (int)ippdrv);
+       DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%p]\n",
+               property->prop_id, property->cmd, ippdrv);
 
        /* stored property information and ippdrv in private data */
        c_node->property = *property;
@@ -518,7 +518,7 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
 {
        int i;
 
-       DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+       DRM_DEBUG_KMS("node[%p]\n", m_node);
 
        if (!m_node) {
                DRM_ERROR("invalid dequeue node.\n");
@@ -562,7 +562,7 @@ static struct drm_exynos_ipp_mem_node
        m_node->buf_id = qbuf->buf_id;
        INIT_LIST_HEAD(&m_node->list);
 
-       DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]\n", (int)m_node, qbuf->ops_id);
+       DRM_DEBUG_KMS("m_node[%p]ops_id[%d]\n", m_node, qbuf->ops_id);
        DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
 
        for_each_ipp_planar(i) {
@@ -582,8 +582,8 @@ static struct drm_exynos_ipp_mem_node
 
                        buf_info->handles[i] = qbuf->handle[i];
                        buf_info->base[i] = *addr;
-                       DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%lx]\n", i,
-                                     buf_info->base[i], buf_info->handles[i]);
+                       DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i,
+                                     &buf_info->base[i], buf_info->handles[i]);
                }
        }
 
@@ -664,7 +664,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
 
        mutex_lock(&c_node->event_lock);
        list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
-               DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
+               DRM_DEBUG_KMS("count[%d]e[%p]\n", count++, e);
 
                /*
                 * qbuf == NULL condition means all event deletion.
@@ -755,7 +755,7 @@ static struct drm_exynos_ipp_mem_node
 
        /* find memory node from memory list */
        list_for_each_entry(m_node, head, list) {
-               DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
+               DRM_DEBUG_KMS("count[%d]m_node[%p]\n", count++, m_node);
 
                /* compare buffer id */
                if (m_node->buf_id == qbuf->buf_id)
@@ -772,7 +772,7 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
        struct exynos_drm_ipp_ops *ops = NULL;
        int ret = 0;
 
-       DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
+       DRM_DEBUG_KMS("node[%p]\n", m_node);
 
        if (!m_node) {
                DRM_ERROR("invalid queue node.\n");
@@ -1237,7 +1237,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                        m_node = list_first_entry(head,
                                struct drm_exynos_ipp_mem_node, list);
 
-                       DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node);
+                       DRM_DEBUG_KMS("m_node[%p]\n", m_node);
 
                        ret = ipp_set_mem_node(ippdrv, c_node, m_node);
                        if (ret) {
@@ -1610,8 +1610,8 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
                }
                ippdrv->prop_list.ipp_id = ret;
 
-               DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n",
-                       count++, (int)ippdrv, ret);
+               DRM_DEBUG_KMS("count[%d]ippdrv[%p]ipp_id[%d]\n",
+                       count++, ippdrv, ret);
 
                /* store parent device for node */
                ippdrv->parent_dev = dev;
@@ -1668,7 +1668,7 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
 
        file_priv->ipp_dev = dev;
 
-       DRM_DEBUG_KMS("done priv[0x%x]\n", (int)dev);
+       DRM_DEBUG_KMS("done priv[%p]\n", dev);
 
        return 0;
 }
@@ -1685,8 +1685,8 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
                mutex_lock(&ippdrv->cmd_lock);
                list_for_each_entry_safe(c_node, tc_node,
                        &ippdrv->cmd_list, list) {
-                       DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
-                               count++, (int)ippdrv);
+                       DRM_DEBUG_KMS("count[%d]ippdrv[%p]\n",
+                               count++, ippdrv);
 
                        if (c_node->filp == file) {
                                /*
index 4eaef36aec5a42d9d1ccd70ff4f15f39d707648c..9869d70e9e54af32abb775dc0e17f0c1da83999b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_graph.h>
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <drm/drmP.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
@@ -306,9 +307,9 @@ exit:
        return ret;
 }
 
-void mic_disable(struct drm_bridge *bridge) { }
+static void mic_disable(struct drm_bridge *bridge) { }
 
-void mic_post_disable(struct drm_bridge *bridge)
+static void mic_post_disable(struct drm_bridge *bridge)
 {
        struct exynos_mic *mic = bridge->driver_private;
        int i;
@@ -328,7 +329,7 @@ already_disabled:
        mutex_unlock(&mic_mutex);
 }
 
-void mic_pre_enable(struct drm_bridge *bridge)
+static void mic_pre_enable(struct drm_bridge *bridge)
 {
        struct exynos_mic *mic = bridge->driver_private;
        int ret, i;
@@ -371,11 +372,35 @@ already_enabled:
        mutex_unlock(&mic_mutex);
 }
 
-void mic_enable(struct drm_bridge *bridge) { }
+static void mic_enable(struct drm_bridge *bridge) { }
 
-void mic_destroy(struct drm_bridge *bridge)
+static const struct drm_bridge_funcs mic_bridge_funcs = {
+       .disable = mic_disable,
+       .post_disable = mic_post_disable,
+       .pre_enable = mic_pre_enable,
+       .enable = mic_enable,
+};
+
+static int exynos_mic_bind(struct device *dev, struct device *master,
+                          void *data)
 {
-       struct exynos_mic *mic = bridge->driver_private;
+       struct exynos_mic *mic = dev_get_drvdata(dev);
+       int ret;
+
+       mic->bridge.funcs = &mic_bridge_funcs;
+       mic->bridge.of_node = dev->of_node;
+       mic->bridge.driver_private = mic;
+       ret = drm_bridge_add(&mic->bridge);
+       if (ret)
+               DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
+
+       return ret;
+}
+
+static void exynos_mic_unbind(struct device *dev, struct device *master,
+                             void *data)
+{
+       struct exynos_mic *mic = dev_get_drvdata(dev);
        int i;
 
        mutex_lock(&mic_mutex);
@@ -387,16 +412,16 @@ void mic_destroy(struct drm_bridge *bridge)
 
 already_disabled:
        mutex_unlock(&mic_mutex);
+
+       drm_bridge_remove(&mic->bridge);
 }
 
-static const struct drm_bridge_funcs mic_bridge_funcs = {
-       .disable = mic_disable,
-       .post_disable = mic_post_disable,
-       .pre_enable = mic_pre_enable,
-       .enable = mic_enable,
+static const struct component_ops exynos_mic_component_ops = {
+       .bind   = exynos_mic_bind,
+       .unbind = exynos_mic_unbind,
 };
 
-int exynos_mic_probe(struct platform_device *pdev)
+static int exynos_mic_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos_mic *mic;
@@ -435,17 +460,8 @@ int exynos_mic_probe(struct platform_device *pdev)
                goto err;
        }
 
-       mic->bridge.funcs = &mic_bridge_funcs;
-       mic->bridge.of_node = dev->of_node;
-       mic->bridge.driver_private = mic;
-       ret = drm_bridge_add(&mic->bridge);
-       if (ret) {
-               DRM_ERROR("mic: Failed to add MIC to the global bridge list\n");
-               goto err;
-       }
-
        for (i = 0; i < NUM_CLKS; i++) {
-               mic->clks[i] = of_clk_get_by_name(dev->of_node, clk_names[i]);
+               mic->clks[i] = devm_clk_get(dev, clk_names[i]);
                if (IS_ERR(mic->clks[i])) {
                        DRM_ERROR("mic: Failed to get clock (%s)\n",
                                                                clk_names[i]);
@@ -454,7 +470,10 @@ int exynos_mic_probe(struct platform_device *pdev)
                }
        }
 
+       platform_set_drvdata(pdev, mic);
+
        DRM_DEBUG_KMS("MIC has been probed\n");
+       return component_add(dev, &exynos_mic_component_ops);
 
 err:
        return ret;
@@ -462,14 +481,7 @@ err:
 
 static int exynos_mic_remove(struct platform_device *pdev)
 {
-       struct exynos_mic *mic = platform_get_drvdata(pdev);
-       int i;
-
-       drm_bridge_remove(&mic->bridge);
-
-       for (i = NUM_CLKS - 1; i > -1; i--)
-               clk_put(mic->clks[i]);
-
+       component_del(&pdev->dev, &exynos_mic_component_ops);
        return 0;
 }
 
index bea0f7826d30a168022c79598c9cea6f4641afcd..ce59f4443394f5394c85956e2e261dc62eaedf43 100644 (file)
@@ -754,7 +754,7 @@ static int rotator_probe(struct platform_device *pdev)
                goto err_ippdrv_register;
        }
 
-       DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
+       DRM_DEBUG_KMS("ippdrv[%p]\n", ippdrv);
 
        platform_set_drvdata(pdev, rot);
 
index 62ac4e5fa51dbb00cda1f02d50f630b48b6d44bc..b605bd7395eccf2e3a6fb8264c37bd31774b1634 100644 (file)
@@ -223,7 +223,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
        }
 }
 
-static int vidi_show_connection(struct device *dev,
+static ssize_t vidi_show_connection(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        struct vidi_context *ctx = dev_get_drvdata(dev);
@@ -238,7 +238,7 @@ static int vidi_show_connection(struct device *dev,
        return rc;
 }
 
-static int vidi_store_connection(struct device *dev,
+static ssize_t vidi_store_connection(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t len)
 {
@@ -294,7 +294,9 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        }
 
        if (vidi->connection) {
-               struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
+               struct edid *raw_edid;
+
+               raw_edid = (struct edid *)(unsigned long)vidi->edid;
                if (!drm_edid_is_valid(raw_edid)) {
                        DRM_DEBUG_KMS("edid data is invalid.\n");
                        return -EINVAL;
index b5fbc1cbf02454d0e8c76de88f91f2c63e343e2c..0a5a60005f7e5711e14147dfa21990be1b88a2b8 100644 (file)
@@ -1289,8 +1289,7 @@ static int mixer_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int exynos_mixer_suspend(struct device *dev)
+static int __maybe_unused exynos_mixer_suspend(struct device *dev)
 {
        struct mixer_context *ctx = dev_get_drvdata(dev);
        struct mixer_resources *res = &ctx->mixer_res;
@@ -1306,7 +1305,7 @@ static int exynos_mixer_suspend(struct device *dev)
        return 0;
 }
 
-static int exynos_mixer_resume(struct device *dev)
+static int __maybe_unused exynos_mixer_resume(struct device *dev)
 {
        struct mixer_context *ctx = dev_get_drvdata(dev);
        struct mixer_resources *res = &ctx->mixer_res;
@@ -1342,7 +1341,6 @@ static int exynos_mixer_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static const struct dev_pm_ops exynos_mixer_pm_ops = {
        SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
index 533d1e3d4a999f971b2479f471c965e3708a73f2..a02112ba1c3df692b3a089a3ab24a8f30d35b7ec 100644 (file)
@@ -136,6 +136,7 @@ static bool adv7511_register_volatile(struct device *dev, unsigned int reg)
        case ADV7511_REG_BKSV(3):
        case ADV7511_REG_BKSV(4):
        case ADV7511_REG_DDC_STATUS:
+       case ADV7511_REG_EDID_READ_CTRL:
        case ADV7511_REG_BSTATUS(0):
        case ADV7511_REG_BSTATUS(1):
        case ADV7511_REG_CHIP_ID_HIGH:
@@ -362,24 +363,31 @@ static void adv7511_power_on(struct adv7511 *adv7511)
 {
        adv7511->current_edid_segment = -1;
 
-       regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                    ADV7511_INT0_EDID_READY);
-       regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
-                    ADV7511_INT1_DDC_ERROR);
        regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                           ADV7511_POWER_POWER_DOWN, 0);
+       if (adv7511->i2c_main->irq) {
+               /*
+                * Documentation says the INT_ENABLE registers are reset in
+                * POWER_DOWN mode. My 7511w preserved the bits, however.
+                * Still, let's be safe and stick to the documentation.
+                */
+               regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+                            ADV7511_INT0_EDID_READY);
+               regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+                            ADV7511_INT1_DDC_ERROR);
+       }
 
        /*
-        * Per spec it is allowed to pulse the HDP signal to indicate that the
+        * Per spec it is allowed to pulse the HPD signal to indicate that the
         * EDID information has changed. Some monitors do this when they wakeup
-        * from standby or are enabled. When the HDP goes low the adv7511 is
+        * from standby or are enabled. When the HPD goes low the adv7511 is
         * reset and the outputs are disabled which might cause the monitor to
-        * go to standby again. To avoid this we ignore the HDP pin for the
+        * go to standby again. To avoid this we ignore the HPD pin for the
         * first few seconds after enabling the output.
         */
        regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-                          ADV7511_REG_POWER2_HDP_SRC_MASK,
-                          ADV7511_REG_POWER2_HDP_SRC_NONE);
+                          ADV7511_REG_POWER2_HPD_SRC_MASK,
+                          ADV7511_REG_POWER2_HPD_SRC_NONE);
 
        /*
         * Most of the registers are reset during power down or when HPD is low.
@@ -413,9 +421,9 @@ static bool adv7511_hpd(struct adv7511 *adv7511)
        if (ret < 0)
                return false;
 
-       if (irq0 & ADV7511_INT0_HDP) {
+       if (irq0 & ADV7511_INT0_HPD) {
                regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_HDP);
+                            ADV7511_INT0_HPD);
                return true;
        }
 
@@ -438,7 +446,7 @@ static int adv7511_irq_process(struct adv7511 *adv7511)
        regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
        regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
 
-       if (irq0 & ADV7511_INT0_HDP && adv7511->encoder)
+       if (irq0 & ADV7511_INT0_HPD && adv7511->encoder)
                drm_helper_hpd_irq_event(adv7511->encoder->dev);
 
        if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
@@ -567,12 +575,14 @@ static int adv7511_get_modes(struct drm_encoder *encoder,
 
        /* Reading the EDID only works if the device is powered */
        if (!adv7511->powered) {
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(0),
-                            ADV7511_INT0_EDID_READY);
-               regmap_write(adv7511->regmap, ADV7511_REG_INT(1),
-                            ADV7511_INT1_DDC_ERROR);
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER,
                                   ADV7511_POWER_POWER_DOWN, 0);
+               if (adv7511->i2c_main->irq) {
+                       regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(0),
+                                    ADV7511_INT0_EDID_READY);
+                       regmap_write(adv7511->regmap, ADV7511_REG_INT_ENABLE(1),
+                                    ADV7511_INT1_DDC_ERROR);
+               }
                adv7511->current_edid_segment = -1;
        }
 
@@ -638,10 +648,10 @@ adv7511_encoder_detect(struct drm_encoder *encoder,
                if (adv7511->status == connector_status_connected)
                        status = connector_status_disconnected;
        } else {
-               /* Renable HDP sensing */
+               /* Renable HPD sensing */
                regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2,
-                                  ADV7511_REG_POWER2_HDP_SRC_MASK,
-                                  ADV7511_REG_POWER2_HDP_SRC_BOTH);
+                                  ADV7511_REG_POWER2_HPD_SRC_MASK,
+                                  ADV7511_REG_POWER2_HPD_SRC_BOTH);
        }
 
        adv7511->status = status;
index 6599ed538426d60f41a9dbebe3e9bcd8e8b11acc..38515b30cedfc84812a556638fe7333ff6ebeb8b 100644 (file)
@@ -90,7 +90,7 @@
 #define ADV7511_CSC_ENABLE                     BIT(7)
 #define ADV7511_CSC_UPDATE_MODE                        BIT(5)
 
-#define ADV7511_INT0_HDP                       BIT(7)
+#define ADV7511_INT0_HPD                       BIT(7)
 #define ADV7511_INT0_VSYNC                     BIT(5)
 #define ADV7511_INT0_AUDIO_FIFO_FULL           BIT(4)
 #define ADV7511_INT0_EDID_READY                        BIT(2)
 #define ADV7511_PACKET_ENABLE_SPARE2           BIT(1)
 #define ADV7511_PACKET_ENABLE_SPARE1           BIT(0)
 
-#define ADV7511_REG_POWER2_HDP_SRC_MASK                0xc0
-#define ADV7511_REG_POWER2_HDP_SRC_BOTH                0x00
-#define ADV7511_REG_POWER2_HDP_SRC_HDP         0x40
-#define ADV7511_REG_POWER2_HDP_SRC_CEC         0x80
-#define ADV7511_REG_POWER2_HDP_SRC_NONE                0xc0
+#define ADV7511_REG_POWER2_HPD_SRC_MASK                0xc0
+#define ADV7511_REG_POWER2_HPD_SRC_BOTH                0x00
+#define ADV7511_REG_POWER2_HPD_SRC_HPD         0x40
+#define ADV7511_REG_POWER2_HPD_SRC_CEC         0x80
+#define ADV7511_REG_POWER2_HPD_SRC_NONE                0xc0
 #define ADV7511_REG_POWER2_TDMS_ENABLE         BIT(4)
 #define ADV7511_REG_POWER2_GATE_INPUT_CLK      BIT(0)
 
index fcd77b27514dfdb738334024c2b1201732af6dc3..051eab33e4c7b13260994ebb884cc44a5394c4bc 100644 (file)
@@ -10,7 +10,6 @@ config DRM_I915
        # the shmem_readpage() which depends upon tmpfs
        select SHMEM
        select TMPFS
-       select STOP_MACHINE
        select DRM_KMS_HELPER
        select DRM_PANEL
        select DRM_MIPI_DSI
index 0fc38bb7276c26920b372ca52c053eba504aa722..cf39ed3133d63aaa434120dc085bd6ea0811b2ee 100644 (file)
@@ -825,8 +825,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                }
 
                for_each_pipe(dev_priv, pipe) {
-                       if (!intel_display_power_is_enabled(dev_priv,
-                                               POWER_DOMAIN_PIPE(pipe))) {
+                       enum intel_display_power_domain power_domain;
+
+                       power_domain = POWER_DOMAIN_PIPE(pipe);
+                       if (!intel_display_power_get_if_enabled(dev_priv,
+                                                               power_domain)) {
                                seq_printf(m, "Pipe %c power disabled\n",
                                           pipe_name(pipe));
                                continue;
@@ -840,6 +843,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                        seq_printf(m, "Pipe %c IER:\t%08x\n",
                                   pipe_name(pipe),
                                   I915_READ(GEN8_DE_PIPE_IER(pipe)));
+
+                       intel_display_power_put(dev_priv, power_domain);
                }
 
                seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -3985,6 +3990,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
        struct intel_crtc *crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev,
                                                                        pipe));
+       enum intel_display_power_domain power_domain;
        u32 val = 0; /* shut up gcc */
        int ret;
 
@@ -3995,7 +4001,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
        if (pipe_crc->source && source)
                return -EINVAL;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe))) {
+       power_domain = POWER_DOMAIN_PIPE(pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
                DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
                return -EIO;
        }
@@ -4012,7 +4019,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                ret = ivb_pipe_crc_ctl_reg(dev, pipe, &source, &val);
 
        if (ret != 0)
-               return ret;
+               goto out;
 
        /* none -> real source transition */
        if (source) {
@@ -4024,8 +4031,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
                                  sizeof(pipe_crc->entries[0]),
                                  GFP_KERNEL);
-               if (!entries)
-                       return -ENOMEM;
+               if (!entries) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
 
                /*
                 * When IPS gets enabled, the pipe CRC changes. Since IPS gets
@@ -4081,7 +4090,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
                hsw_enable_ips(crtc);
        }
 
-       return 0;
+       ret = 0;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 /*
index 3ac616d7363bafcc4197aa126c509932d15fb299..f357058c74d938a41f922c4b40e3da1d67aa029a 100644 (file)
@@ -501,7 +501,9 @@ void intel_detect_pch(struct drm_device *dev)
                                WARN_ON(!IS_SKYLAKE(dev) &&
                                        !IS_KABYLAKE(dev));
                        } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) ||
-                                  (id == INTEL_PCH_QEMU_DEVICE_ID_TYPE)) {
+                                  ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) &&
+                                   pch->subsystem_vendor == 0x1af4 &&
+                                   pch->subsystem_device == 0x1100)) {
                                dev_priv->pch_type = intel_virt_detect_pch(dev);
                        } else
                                continue;
index f0f75d7c0d94263f86ccfdd7d8b84af831462be0..b0847b9155452366569a4676c9da62bc6c2bc94d 100644 (file)
@@ -751,6 +751,7 @@ struct intel_csr {
        uint32_t mmio_count;
        i915_reg_t mmioaddr[8];
        uint32_t mmiodata[8];
+       uint32_t dc_state;
 };
 
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -1988,6 +1989,9 @@ enum hdmi_force_audio {
 #define I915_GTT_OFFSET_NONE ((u32)-1)
 
 struct drm_i915_gem_object_ops {
+       unsigned int flags;
+#define I915_GEM_OBJECT_HAS_STRUCT_PAGE 0x1
+
        /* Interface between the GEM object and its backing storage.
         * get_pages() is called once prior to the use of the associated set
         * of pages before to binding them into the GTT, and put_pages() is
@@ -2003,6 +2007,7 @@ struct drm_i915_gem_object_ops {
         */
        int (*get_pages)(struct drm_i915_gem_object *);
        void (*put_pages)(struct drm_i915_gem_object *);
+
        int (*dmabuf_export)(struct drm_i915_gem_object *);
        void (*release)(struct drm_i915_gem_object *);
 };
index ddc21d4b388d2419a63fbd4f4a5745deea80957b..bb44bad15403556fb443998852864d8e0fb83472 100644 (file)
@@ -4425,6 +4425,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 }
 
 static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
+       .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE,
        .get_pages = i915_gem_object_get_pages_gtt,
        .put_pages = i915_gem_object_put_pages_gtt,
 };
@@ -5261,7 +5262,7 @@ i915_gem_object_get_dirty_page(struct drm_i915_gem_object *obj, int n)
        struct page *page;
 
        /* Only default objects have per-page dirty tracking */
-       if (WARN_ON(obj->ops != &i915_gem_object_ops))
+       if (WARN_ON((obj->ops->flags & I915_GEM_OBJECT_HAS_STRUCT_PAGE) == 0))
                return NULL;
 
        page = i915_gem_object_get_page(obj, n);
index 19fb0bddc1cddfce0804e459319dc11ba96c5ab7..59e45b3a69379a0e892fbd85d7a17ba3f85913eb 100644 (file)
@@ -789,9 +789,10 @@ i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj)
 }
 
 static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
-       .dmabuf_export = i915_gem_userptr_dmabuf_export,
+       .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE,
        .get_pages = i915_gem_userptr_get_pages,
        .put_pages = i915_gem_userptr_put_pages,
+       .dmabuf_export = i915_gem_userptr_dmabuf_export,
        .release = i915_gem_userptr_release,
 };
 
index 007ae83a4086d65ff7e4d3862f2ad2a035c74540..4897728713f698d1b3fdbbd31cbf473524c4ecd1 100644 (file)
@@ -3287,19 +3287,20 @@ enum skl_disp_power_wells {
 
 #define PORT_HOTPLUG_STAT      _MMIO(dev_priv->info.display_mmio_offset + 0x61114)
 /*
- * HDMI/DP bits are gen4+
+ * HDMI/DP bits are g4x+
  *
  * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
  * Please check the detailed lore in the commit message for for experimental
  * evidence.
  */
-#define   PORTD_HOTPLUG_LIVE_STATUS_G4X                (1 << 29)
+/* Bspec says GM45 should match G4X/VLV/CHV, but reality disagrees */
+#define   PORTD_HOTPLUG_LIVE_STATUS_GM45       (1 << 29)
+#define   PORTC_HOTPLUG_LIVE_STATUS_GM45       (1 << 28)
+#define   PORTB_HOTPLUG_LIVE_STATUS_GM45       (1 << 27)
+/* G4X/VLV/CHV DP/HDMI bits again match Bspec */
+#define   PORTD_HOTPLUG_LIVE_STATUS_G4X                (1 << 27)
 #define   PORTC_HOTPLUG_LIVE_STATUS_G4X                (1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_G4X                (1 << 27)
-/* VLV DP/HDMI bits again match Bspec */
-#define   PORTD_HOTPLUG_LIVE_STATUS_VLV                (1 << 27)
-#define   PORTC_HOTPLUG_LIVE_STATUS_VLV                (1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS_VLV                (1 << 29)
+#define   PORTB_HOTPLUG_LIVE_STATUS_G4X                (1 << 29)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTD_HOTPLUG_INT_LONG_PULSE         (2 << 21)
 #define   PORTD_HOTPLUG_INT_SHORT_PULSE                (1 << 21)
@@ -7514,7 +7515,7 @@ enum skl_disp_power_wells {
 #define  DPLL_CFGCR2_PDIV_7 (4<<2)
 #define  DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
 
-#define DPLL_CFGCR1(id)        _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2)
+#define DPLL_CFGCR1(id)        _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR1)
 #define DPLL_CFGCR2(id)        _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2)
 
 /* BXT display engine PLL */
index a2aa09ce3202f3ca72e64f550244e2a2c8e8a29f..a8af594fbd0097ba066071710a4832c3b731474e 100644 (file)
@@ -49,7 +49,7 @@ static void i915_save_display(struct drm_device *dev)
                dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS);
                dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS);
                dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR);
-       } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
+       } else if (INTEL_INFO(dev)->gen <= 4) {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
                dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS);
                dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
@@ -84,7 +84,7 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
                I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
                I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
-       } else if (!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
+       } else if (INTEL_INFO(dev)->gen <= 4) {
                I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
                I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
                I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
index 9c89df1af036de613d71a5e8fccc83050722a088..a7b4a524faddc8a80c6693c89eee98efa3fc4450 100644 (file)
@@ -71,22 +71,29 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
        struct intel_crt *crt = intel_encoder_to_crt(encoder);
        enum intel_display_power_domain power_domain;
        u32 tmp;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        tmp = I915_READ(crt->adpa_reg);
 
        if (!(tmp & ADPA_DAC_ENABLE))
-               return false;
+               goto out;
 
        if (HAS_PCH_CPT(dev))
                *pipe = PORT_TO_PIPE_CPT(tmp);
        else
                *pipe = PORT_TO_PIPE(tmp);
 
-       return true;
+       ret = true;
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
index 9bb63a85997a4ffbf31da0e8dbd211786f2e626c..647d85e77c2f4700e84bc275efb711f9b2dc2363 100644 (file)
@@ -240,6 +240,8 @@ void intel_csr_load_program(struct drm_i915_private *dev_priv)
                I915_WRITE(dev_priv->csr.mmioaddr[i],
                           dev_priv->csr.mmiodata[i]);
        }
+
+       dev_priv->csr.dc_state = 0;
 }
 
 static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
index e6408e5583d7a88af4511c6ec2334db2b7922555..0f3df2c39f7cdd3a69d8f0044cbd725e3b9bac6d 100644 (file)
@@ -1589,7 +1589,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
                         DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
                         DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
                         wrpll_params.central_freq;
-       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+       } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+                  intel_encoder->type == INTEL_OUTPUT_DP_MST) {
                switch (crtc_state->port_clock / 2) {
                case 81000:
                        ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
@@ -1968,13 +1969,16 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
        enum transcoder cpu_transcoder;
        enum intel_display_power_domain power_domain;
        uint32_t tmp;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(intel_encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
-       if (!intel_encoder->get_hw_state(intel_encoder, &pipe))
-               return false;
+       if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) {
+               ret = false;
+               goto out;
+       }
 
        if (port == PORT_A)
                cpu_transcoder = TRANSCODER_EDP;
@@ -1986,23 +1990,33 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
        switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
        case TRANS_DDI_MODE_SELECT_HDMI:
        case TRANS_DDI_MODE_SELECT_DVI:
-               return (type == DRM_MODE_CONNECTOR_HDMIA);
+               ret = type == DRM_MODE_CONNECTOR_HDMIA;
+               break;
 
        case TRANS_DDI_MODE_SELECT_DP_SST:
-               if (type == DRM_MODE_CONNECTOR_eDP)
-                       return true;
-               return (type == DRM_MODE_CONNECTOR_DisplayPort);
+               ret = type == DRM_MODE_CONNECTOR_eDP ||
+                     type == DRM_MODE_CONNECTOR_DisplayPort;
+               break;
+
        case TRANS_DDI_MODE_SELECT_DP_MST:
                /* if the transcoder is in MST state then
                 * connector isn't connected */
-               return false;
+               ret = false;
+               break;
 
        case TRANS_DDI_MODE_SELECT_FDI:
-               return (type == DRM_MODE_CONNECTOR_VGA);
+               ret = type == DRM_MODE_CONNECTOR_VGA;
+               break;
 
        default:
-               return false;
+               ret = false;
+               break;
        }
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
@@ -2014,15 +2028,18 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
        enum intel_display_power_domain power_domain;
        u32 tmp;
        int i;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        tmp = I915_READ(DDI_BUF_CTL(port));
 
        if (!(tmp & DDI_BUF_CTL_ENABLE))
-               return false;
+               goto out;
 
        if (port == PORT_A) {
                tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
@@ -2040,25 +2057,32 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
                        break;
                }
 
-               return true;
-       } else {
-               for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
-                       tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
+               ret = true;
 
-                       if ((tmp & TRANS_DDI_PORT_MASK)
-                           == TRANS_DDI_SELECT_PORT(port)) {
-                               if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
-                                       return false;
+               goto out;
+       }
 
-                               *pipe = i;
-                               return true;
-                       }
+       for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
+               tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
+
+               if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
+                       if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
+                           TRANS_DDI_MODE_SELECT_DP_MST)
+                               goto out;
+
+                       *pipe = i;
+                       ret = true;
+
+                       goto out;
                }
        }
 
        DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
 
-       return false;
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
@@ -2507,12 +2531,14 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
 {
        uint32_t val;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
        val = I915_READ(WRPLL_CTL(pll->id));
        hw_state->wrpll = val;
 
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
        return val & WRPLL_PLL_ENABLE;
 }
 
@@ -2522,12 +2548,14 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
 {
        uint32_t val;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
        val = I915_READ(SPLL_CTL);
        hw_state->spll = val;
 
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
        return val & SPLL_PLL_ENABLE;
 }
 
@@ -2644,16 +2672,19 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
        uint32_t val;
        unsigned int dpll;
        const struct skl_dpll_regs *regs = skl_dpll_regs;
+       bool ret;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
+       ret = false;
+
        /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
        dpll = pll->id + 1;
 
        val = I915_READ(regs[pll->id].ctl);
        if (!(val & LCPLL_PLL_ENABLE))
-               return false;
+               goto out;
 
        val = I915_READ(DPLL_CTRL1);
        hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
@@ -2663,8 +2694,12 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
                hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
                hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
        }
+       ret = true;
 
-       return true;
+out:
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+       return ret;
 }
 
 static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -2931,13 +2966,16 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
 {
        enum port port = (enum port)pll->id;    /* 1:1 port->PLL mapping */
        uint32_t val;
+       bool ret;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
+       ret = false;
+
        val = I915_READ(BXT_PORT_PLL_ENABLE(port));
        if (!(val & PORT_PLL_ENABLE))
-               return false;
+               goto out;
 
        hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
        hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
@@ -2984,7 +3022,12 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
                                 I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
        hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+       return ret;
 }
 
 static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -3119,11 +3162,15 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
 {
        u32 temp;
 
-       if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
+       if (intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
                temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+
+               intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+
                if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
                        return true;
        }
+
        return false;
 }
 
index 2f00828ccc6e923a65447424c716d9cc5ee0e99b..46947fffd5998074555c95ce8d373343aac20bd6 100644 (file)
@@ -1351,18 +1351,21 @@ void assert_pipe(struct drm_i915_private *dev_priv,
        bool cur_state;
        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
                                                                      pipe);
+       enum intel_display_power_domain power_domain;
 
        /* if we need the pipe quirk it must be always on */
        if ((pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) ||
            (pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
                state = true;
 
-       if (!intel_display_power_is_enabled(dev_priv,
-                               POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
-               cur_state = false;
-       } else {
+       power_domain = POWER_DOMAIN_TRANSCODER(cpu_transcoder);
+       if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
                u32 val = I915_READ(PIPECONF(cpu_transcoder));
                cur_state = !!(val & PIPECONF_ENABLE);
+
+               intel_display_power_put(dev_priv, power_domain);
+       } else {
+               cur_state = false;
        }
 
        I915_STATE_WARN(cur_state != state,
@@ -2946,7 +2949,7 @@ u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
        struct i915_vma *vma;
        u64 offset;
 
-       intel_fill_fb_ggtt_view(&view, intel_plane->base.fb,
+       intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
                                intel_plane->base.state);
 
        vma = i915_gem_obj_to_ggtt_view(obj, &view);
@@ -8171,18 +8174,22 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        uint32_t tmp;
+       bool ret;
 
-       if (!intel_display_power_is_enabled(dev_priv,
-                                           POWER_DOMAIN_PIPE(crtc->pipe)))
+       power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
+       ret = false;
+
        tmp = I915_READ(PIPECONF(crtc->pipe));
        if (!(tmp & PIPECONF_ENABLE))
-               return false;
+               goto out;
 
        if (IS_G4X(dev) || IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                switch (tmp & PIPECONF_BPC_MASK) {
@@ -8262,7 +8269,12 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        pipe_config->base.adjusted_mode.crtc_clock =
                pipe_config->port_clock / pipe_config->pixel_multiplier;
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void ironlake_init_pch_refclk(struct drm_device *dev)
@@ -9366,18 +9378,21 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        uint32_t tmp;
+       bool ret;
 
-       if (!intel_display_power_is_enabled(dev_priv,
-                                           POWER_DOMAIN_PIPE(crtc->pipe)))
+       power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
+       ret = false;
        tmp = I915_READ(PIPECONF(crtc->pipe));
        if (!(tmp & PIPECONF_ENABLE))
-               return false;
+               goto out;
 
        switch (tmp & PIPECONF_BPC_MASK) {
        case PIPECONF_6BPC:
@@ -9440,7 +9455,12 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
 
        ironlake_get_pfit_config(crtc, pipe_config);
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
@@ -9950,12 +9970,17 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum intel_display_power_domain pfit_domain;
+       enum intel_display_power_domain power_domain;
+       unsigned long power_domain_mask;
        uint32_t tmp;
+       bool ret;
 
-       if (!intel_display_power_is_enabled(dev_priv,
-                                        POWER_DOMAIN_PIPE(crtc->pipe)))
+       power_domain = POWER_DOMAIN_PIPE(crtc->pipe);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
+       power_domain_mask = BIT(power_domain);
+
+       ret = false;
 
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
@@ -9982,13 +10007,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                        pipe_config->cpu_transcoder = TRANSCODER_EDP;
        }
 
-       if (!intel_display_power_is_enabled(dev_priv,
-                       POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
-               return false;
+       power_domain = POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder);
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
+               goto out;
+       power_domain_mask |= BIT(power_domain);
 
        tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
        if (!(tmp & PIPECONF_ENABLE))
-               return false;
+               goto out;
 
        haswell_get_ddi_port_state(crtc, pipe_config);
 
@@ -9998,14 +10024,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                skl_init_scalers(dev, crtc, pipe_config);
        }
 
-       pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
-
        if (INTEL_INFO(dev)->gen >= 9) {
                pipe_config->scaler_state.scaler_id = -1;
                pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
        }
 
-       if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
+       power_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
+       if (intel_display_power_get_if_enabled(dev_priv, power_domain)) {
+               power_domain_mask |= BIT(power_domain);
                if (INTEL_INFO(dev)->gen >= 9)
                        skylake_get_pfit_config(crtc, pipe_config);
                else
@@ -10023,7 +10049,13 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                pipe_config->pixel_multiplier = 1;
        }
 
-       return true;
+       ret = true;
+
+out:
+       for_each_power_domain(power_domain, power_domain_mask)
+               intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
@@ -12075,11 +12107,21 @@ connected_sink_compute_bpp(struct intel_connector *connector,
                pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
        }
 
-       /* Clamp bpp to 8 on screens without EDID 1.4 */
-       if (connector->base.display_info.bpc == 0 && bpp > 24) {
-               DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
-                             bpp);
-               pipe_config->pipe_bpp = 24;
+       /* Clamp bpp to default limit on screens without EDID 1.4 */
+       if (connector->base.display_info.bpc == 0) {
+               int type = connector->base.connector_type;
+               int clamp_bpp = 24;
+
+               /* Fall back to 18 bpp when DP sink capability is unknown. */
+               if (type == DRM_MODE_CONNECTOR_DisplayPort ||
+                   type == DRM_MODE_CONNECTOR_eDP)
+                       clamp_bpp = 18;
+
+               if (bpp > clamp_bpp) {
+                       DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of %d\n",
+                                     bpp, clamp_bpp);
+                       pipe_config->pipe_bpp = clamp_bpp;
+               }
        }
 }
 
@@ -13620,7 +13662,7 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
 {
        uint32_t val;
 
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
                return false;
 
        val = I915_READ(PCH_DPLL(pll->id));
@@ -13628,6 +13670,8 @@ static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
        hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
        hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
 
+       intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
        return val & DPLL_VCO_ENABLE;
 }
 
@@ -13883,11 +13927,12 @@ intel_check_primary_plane(struct drm_plane *plane,
        int max_scale = DRM_PLANE_HELPER_NO_SCALING;
        bool can_position = false;
 
-       /* use scaler when colorkey is not required */
-       if (INTEL_INFO(plane->dev)->gen >= 9 &&
-           state->ckey.flags == I915_SET_COLORKEY_NONE) {
-               min_scale = 1;
-               max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
+       if (INTEL_INFO(plane->dev)->gen >= 9) {
+               /* use scaler when colorkey is not required */
+               if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
+                       min_scale = 1;
+                       max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state);
+               }
                can_position = true;
        }
 
@@ -15557,10 +15602,12 @@ void i915_redisable_vga(struct drm_device *dev)
         * level, just check if the power well is enabled instead of trying to
         * follow the "don't touch the power well if we don't need it" policy
         * the rest of the driver uses. */
-       if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_VGA))
+       if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_VGA))
                return;
 
        i915_redisable_vga_power_on(dev);
+
+       intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
 }
 
 static bool primary_get_hw_state(struct intel_plane *plane)
index 796e3d313cb975efc3797a39b15beb8e55ab7f92..1d8de43bed56839fd1fee3a75b6d61b6221c7c0a 100644 (file)
@@ -2362,15 +2362,18 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum intel_display_power_domain power_domain;
        u32 tmp;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        tmp = I915_READ(intel_dp->output_reg);
 
        if (!(tmp & DP_PORT_EN))
-               return false;
+               goto out;
 
        if (IS_GEN7(dev) && port == PORT_A) {
                *pipe = PORT_TO_PIPE_CPT(tmp);
@@ -2381,7 +2384,9 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
                        u32 trans_dp = I915_READ(TRANS_DP_CTL(p));
                        if (TRANS_DP_PIPE_TO_PORT(trans_dp) == port) {
                                *pipe = p;
-                               return true;
+                               ret = true;
+
+                               goto out;
                        }
                }
 
@@ -2393,7 +2398,12 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
                *pipe = PORT_TO_PIPE(tmp);
        }
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void intel_dp_get_config(struct intel_encoder *encoder,
@@ -4493,20 +4503,20 @@ static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
        return I915_READ(PORT_HOTPLUG_STAT) & bit;
 }
 
-static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
-                                      struct intel_digital_port *port)
+static bool gm45_digital_port_connected(struct drm_i915_private *dev_priv,
+                                       struct intel_digital_port *port)
 {
        u32 bit;
 
        switch (port->port) {
        case PORT_B:
-               bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTB_HOTPLUG_LIVE_STATUS_GM45;
                break;
        case PORT_C:
-               bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTC_HOTPLUG_LIVE_STATUS_GM45;
                break;
        case PORT_D:
-               bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+               bit = PORTD_HOTPLUG_LIVE_STATUS_GM45;
                break;
        default:
                MISSING_CASE(port->port);
@@ -4558,8 +4568,8 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
                return cpt_digital_port_connected(dev_priv, port);
        else if (IS_BROXTON(dev_priv))
                return bxt_digital_port_connected(dev_priv, port);
-       else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               return vlv_digital_port_connected(dev_priv, port);
+       else if (IS_GM45(dev_priv))
+               return gm45_digital_port_connected(dev_priv, port);
        else
                return g4x_digital_port_connected(dev_priv, port);
 }
index 88887938e0bfd3e0cf3e7bdebd66a145f7e036a7..0b8eefc2acc5d93088b960e4714bce55944df82e 100644 (file)
@@ -215,27 +215,46 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
        }
 }
 
-static void
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+/*
+ * Pick training pattern for channel equalization. Training Pattern 3 for HBR2
+ * or 1.2 devices that support it, Training Pattern 2 otherwise.
+ */
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 {
-       bool channel_eq = false;
-       int tries, cr_tries;
-       uint32_t training_pattern = DP_TRAINING_PATTERN_2;
+       u32 training_pattern = DP_TRAINING_PATTERN_2;
+       bool source_tps3, sink_tps3;
 
        /*
-        * Training Pattern 3 for HBR2 or 1.2 devices that support it.
-        *
         * Intel platforms that support HBR2 also support TPS3. TPS3 support is
-        * also mandatory for downstream devices that support HBR2.
+        * also mandatory for downstream devices that support HBR2. However, not
+        * all sinks follow the spec.
         *
         * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
-        * supported but still not enabled.
+        * supported in source but still not enabled.
         */
-       if (intel_dp_source_supports_hbr2(intel_dp) &&
-           drm_dp_tps3_supported(intel_dp->dpcd))
+       source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
+       sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+
+       if (source_tps3 && sink_tps3) {
                training_pattern = DP_TRAINING_PATTERN_3;
-       else if (intel_dp->link_rate == 540000)
-               DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
+       } else if (intel_dp->link_rate == 540000) {
+               if (!source_tps3)
+                       DRM_DEBUG_KMS("5.4 Gbps link rate without source HBR2/TPS3 support\n");
+               if (!sink_tps3)
+                       DRM_DEBUG_KMS("5.4 Gbps link rate without sink TPS3 support\n");
+       }
+
+       return training_pattern;
+}
+
+static void
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+{
+       bool channel_eq = false;
+       int tries, cr_tries;
+       u32 training_pattern;
+
+       training_pattern = intel_dp_training_pattern(intel_dp);
 
        /* channel equalization */
        if (!intel_dp_set_link_train(intel_dp,
index ea5415851c6e2cc36d4c6790db473fab637fd46d..df7f3cb66056e754c3c8f596583cae343fc2d5a9 100644 (file)
@@ -1428,6 +1428,8 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
                                      enum intel_display_power_domain domain);
 void intel_display_power_get(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
+bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+                                       enum intel_display_power_domain domain);
 void intel_display_power_put(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
 
@@ -1514,6 +1516,7 @@ enable_rpm_wakeref_asserts(struct drm_i915_private *dev_priv)
        enable_rpm_wakeref_asserts(dev_priv)
 
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
+bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
 
index 44742fa2f616dd22fc25847b0f4ddb5730e550de..0193c62a53ef34f8e2027fb39e3172d44703bfba 100644 (file)
@@ -664,13 +664,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        enum intel_display_power_domain power_domain;
        enum port port;
+       bool ret;
 
        DRM_DEBUG_KMS("\n");
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        /* XXX: this only works for one DSI output */
        for_each_dsi_port(port, intel_dsi->ports) {
                i915_reg_t ctrl_reg = IS_BROXTON(dev) ?
@@ -691,12 +694,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
                if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) {
                        if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) {
                                *pipe = port == PORT_A ? PIPE_A : PIPE_B;
-                               return true;
+                               ret = true;
+
+                               goto out;
                        }
                }
        }
+out:
+       intel_display_power_put(dev_priv, power_domain);
 
-       return false;
+       return ret;
 }
 
 static void intel_dsi_get_config(struct intel_encoder *encoder,
index a5e99ac305daab3ef69471d37b0ec9a97a27425c..e8113ad6547782ff5836839f1354a860aea5e464 100644 (file)
@@ -204,10 +204,28 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
        struct drm_device *dev = intel_dsi->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (dev_priv->vbt.dsi.seq_version >= 3)
+               data++;
+
        gpio = *data++;
 
        /* pull up/down */
-       action = *data++;
+       action = *data++ & 1;
+
+       if (gpio >= ARRAY_SIZE(gtable)) {
+               DRM_DEBUG_KMS("unknown gpio %u\n", gpio);
+               goto out;
+       }
+
+       if (!IS_VALLEYVIEW(dev_priv)) {
+               DRM_DEBUG_KMS("GPIO element not supported on this platform\n");
+               goto out;
+       }
+
+       if (dev_priv->vbt.dsi.seq_version >= 3) {
+               DRM_DEBUG_KMS("GPIO element v3 not supported\n");
+               goto out;
+       }
 
        function = gtable[gpio].function_reg;
        pad = gtable[gpio].pad_reg;
@@ -226,6 +244,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
        vlv_gpio_nc_write(dev_priv, pad, val);
        mutex_unlock(&dev_priv->sb_lock);
 
+out:
        return data;
 }
 
index 4a77639a489dfcd67ff0937e6e3fa4da61fed461..cb5d1b15755c3b19a496105c7a8df99982e83cb9 100644 (file)
@@ -880,15 +880,18 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        enum intel_display_power_domain power_domain;
        u32 tmp;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        tmp = I915_READ(intel_hdmi->hdmi_reg);
 
        if (!(tmp & SDVO_ENABLE))
-               return false;
+               goto out;
 
        if (HAS_PCH_CPT(dev))
                *pipe = PORT_TO_PIPE_CPT(tmp);
@@ -897,7 +900,12 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
        else
                *pipe = PORT_TO_PIPE(tmp);
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void intel_hdmi_get_config(struct intel_encoder *encoder,
index 25254b5c1ac5c95173d0d5b4fa101f35a1131cb7..deb8282c26d83f952473ae145c4fef0b3112b9f1 100644 (file)
@@ -683,7 +683,7 @@ int intel_setup_gmbus(struct drm_device *dev)
        return 0;
 
 err:
-       while (--pin) {
+       while (pin--) {
                if (!intel_gmbus_is_valid_pin(dev_priv, pin))
                        continue;
 
index 3aa614731d7e4b7160a85336d96df41469587991..f1fa756c5d5d59bf8877daded5c23329f63ed331 100644 (file)
@@ -1707,6 +1707,7 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request,
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
 
index 0da0240caf815089447d4614b200ac818fd85250..bc04d8d29acb0bcc8112b39741f7614db6615625 100644 (file)
@@ -75,22 +75,30 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
        struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
        enum intel_display_power_domain power_domain;
        u32 tmp;
+       bool ret;
 
        power_domain = intel_display_port_power_domain(encoder);
-       if (!intel_display_power_is_enabled(dev_priv, power_domain))
+       if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                return false;
 
+       ret = false;
+
        tmp = I915_READ(lvds_encoder->reg);
 
        if (!(tmp & LVDS_PORT_EN))
-               return false;
+               goto out;
 
        if (HAS_PCH_CPT(dev))
                *pipe = PORT_TO_PIPE_CPT(tmp);
        else
                *pipe = PORT_TO_PIPE(tmp);
 
-       return true;
+       ret = true;
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static void intel_lvds_get_config(struct intel_encoder *encoder,
index eb5fa05cf476e465ab2c0df6ee52f6870ec568f8..b28c29f20e754ec740e5aacd101bbe07867f65a6 100644 (file)
@@ -1783,16 +1783,20 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
                                   const struct intel_plane_state *pstate,
                                   uint32_t mem_value)
 {
-       int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+       /*
+        * We treat the cursor plane as always-on for the purposes of watermark
+        * calculation.  Until we have two-stage watermark programming merged,
+        * this is necessary to avoid flickering.
+        */
+       int cpp = 4;
+       int width = pstate->visible ? pstate->base.crtc_w : 64;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active)
                return 0;
 
        return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                              cstate->base.adjusted_mode.crtc_htotal,
-                             drm_rect_width(&pstate->dst),
-                             bpp,
-                             mem_value);
+                             width, cpp, mem_value);
 }
 
 /* Only for WM_LP. */
@@ -2825,7 +2829,10 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
        memset(ddb, 0, sizeof(*ddb));
 
        for_each_pipe(dev_priv, pipe) {
-               if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe)))
+               enum intel_display_power_domain power_domain;
+
+               power_domain = POWER_DOMAIN_PIPE(pipe);
+               if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
                        continue;
 
                for_each_plane(dev_priv, pipe, plane) {
@@ -2837,6 +2844,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
                val = I915_READ(CUR_BUF_CFG(pipe));
                skl_ddb_entry_init_from_hw(&ddb->plane[pipe][PLANE_CURSOR],
                                           val);
+
+               intel_display_power_put(dev_priv, power_domain);
        }
 }
 
index 339701d7a9a5069ccce00f2f171f923073d2c3b5..40c6aff57256140a3dccd780356cfcd859f377ba 100644 (file)
@@ -331,6 +331,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req,
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
        if (invalidate_domains) {
@@ -403,6 +404,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req,
        if (flush_domains) {
                flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
                flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
                flags |= PIPE_CONTROL_FLUSH_ENABLE;
        }
        if (invalidate_domains) {
index ddbdbffe829a684eff8c2ef42a3cf29ccbf112d8..4f43d9b32e6639a9f12db67ba0da213ae440f982 100644 (file)
@@ -470,6 +470,43 @@ static void gen9_set_dc_state_debugmask_memory_up(
        }
 }
 
+static void gen9_write_dc_state(struct drm_i915_private *dev_priv,
+                               u32 state)
+{
+       int rewrites = 0;
+       int rereads = 0;
+       u32 v;
+
+       I915_WRITE(DC_STATE_EN, state);
+
+       /* It has been observed that disabling the dc6 state sometimes
+        * doesn't stick and dmc keeps returning old value. Make sure
+        * the write really sticks enough times and also force rewrite until
+        * we are confident that state is exactly what we want.
+        */
+       do  {
+               v = I915_READ(DC_STATE_EN);
+
+               if (v != state) {
+                       I915_WRITE(DC_STATE_EN, state);
+                       rewrites++;
+                       rereads = 0;
+               } else if (rereads++ > 5) {
+                       break;
+               }
+
+       } while (rewrites < 100);
+
+       if (v != state)
+               DRM_ERROR("Writing dc state to 0x%x failed, now 0x%x\n",
+                         state, v);
+
+       /* Most of the times we need one retry, avoid spam */
+       if (rewrites > 1)
+               DRM_DEBUG_KMS("Rewrote dc state to 0x%x %d times\n",
+                             state, rewrites);
+}
+
 static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
 {
        uint32_t val;
@@ -494,10 +531,18 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
        val = I915_READ(DC_STATE_EN);
        DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
                      val & mask, state);
+
+       /* Check if DMC is ignoring our DC state requests */
+       if ((val & mask) != dev_priv->csr.dc_state)
+               DRM_ERROR("DC state mismatch (0x%x -> 0x%x)\n",
+                         dev_priv->csr.dc_state, val & mask);
+
        val &= ~mask;
        val |= state;
-       I915_WRITE(DC_STATE_EN, val);
-       POSTING_READ(DC_STATE_EN);
+
+       gen9_write_dc_state(dev_priv, val);
+
+       dev_priv->csr.dc_state = val & mask;
 }
 
 void bxt_enable_dc9(struct drm_i915_private *dev_priv)
@@ -1442,6 +1487,22 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
        chv_set_pipe_power_well(dev_priv, power_well, false);
 }
 
+static void
+__intel_display_power_get_domain(struct drm_i915_private *dev_priv,
+                                enum intel_display_power_domain domain)
+{
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       struct i915_power_well *power_well;
+       int i;
+
+       for_each_power_well(i, power_well, BIT(domain), power_domains) {
+               if (!power_well->count++)
+                       intel_power_well_enable(dev_priv, power_well);
+       }
+
+       power_domains->domain_use_count[domain]++;
+}
+
 /**
  * intel_display_power_get - grab a power domain reference
  * @dev_priv: i915 device instance
@@ -1457,24 +1518,53 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
 void intel_display_power_get(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain)
 {
-       struct i915_power_domains *power_domains;
-       struct i915_power_well *power_well;
-       int i;
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
 
        intel_runtime_pm_get(dev_priv);
 
-       power_domains = &dev_priv->power_domains;
+       mutex_lock(&power_domains->lock);
+
+       __intel_display_power_get_domain(dev_priv, domain);
+
+       mutex_unlock(&power_domains->lock);
+}
+
+/**
+ * intel_display_power_get_if_enabled - grab a reference for an enabled display power domain
+ * @dev_priv: i915 device instance
+ * @domain: power domain to reference
+ *
+ * This function grabs a power domain reference for @domain and ensures that the
+ * power domain and all its parents are powered up. Therefore users should only
+ * grab a reference to the innermost power domain they need.
+ *
+ * Any power domain reference obtained by this function must have a symmetric
+ * call to intel_display_power_put() to release the reference again.
+ */
+bool intel_display_power_get_if_enabled(struct drm_i915_private *dev_priv,
+                                       enum intel_display_power_domain domain)
+{
+       struct i915_power_domains *power_domains = &dev_priv->power_domains;
+       bool is_enabled;
+
+       if (!intel_runtime_pm_get_if_in_use(dev_priv))
+               return false;
 
        mutex_lock(&power_domains->lock);
 
-       for_each_power_well(i, power_well, BIT(domain), power_domains) {
-               if (!power_well->count++)
-                       intel_power_well_enable(dev_priv, power_well);
+       if (__intel_display_power_is_enabled(dev_priv, domain)) {
+               __intel_display_power_get_domain(dev_priv, domain);
+               is_enabled = true;
+       } else {
+               is_enabled = false;
        }
 
-       power_domains->domain_use_count[domain]++;
-
        mutex_unlock(&power_domains->lock);
+
+       if (!is_enabled)
+               intel_runtime_pm_put(dev_priv);
+
+       return is_enabled;
 }
 
 /**
@@ -2213,15 +2303,15 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume)
  */
 void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
 {
-       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
-               skl_display_core_uninit(dev_priv);
-
        /*
         * Even if power well support was disabled we still want to disable
         * power wells while we are system suspended.
         */
        if (!i915.disable_power_well)
                intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+               skl_display_core_uninit(dev_priv);
 }
 
 /**
@@ -2245,6 +2335,41 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
        assert_rpm_wakelock_held(dev_priv);
 }
 
+/**
+ * intel_runtime_pm_get_if_in_use - grab a runtime pm reference if device in use
+ * @dev_priv: i915 device instance
+ *
+ * This function grabs a device-level runtime pm reference if the device is
+ * already in use and ensures that it is powered up.
+ *
+ * Any runtime pm reference obtained by this function must have a symmetric
+ * call to intel_runtime_pm_put() to release the reference again.
+ */
+bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       if (IS_ENABLED(CONFIG_PM)) {
+               int ret = pm_runtime_get_if_in_use(device);
+
+               /*
+                * In cases runtime PM is disabled by the RPM core and we get
+                * an -EINVAL return value we are not supposed to call this
+                * function, since the power state is undefined. This applies
+                * atm to the late/early system suspend/resume handlers.
+                */
+               WARN_ON_ONCE(ret < 0);
+               if (ret <= 0)
+                       return false;
+       }
+
+       atomic_inc(&dev_priv->pm.wakeref_count);
+       assert_rpm_wakelock_held(dev_priv);
+
+       return true;
+}
+
 /**
  * intel_runtime_pm_get_noresume - grab a runtime pm reference
  * @dev_priv: i915 device instance
index 78f520d05de92ea627980c5e8f2bb8388715e6fe..e3acc35e3805e58b09fa47fe8dc70223aff175dc 100644 (file)
@@ -1520,7 +1520,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
                                    DMA_BIDIRECTIONAL);
 
                if (dma_mapping_error(pdev, addr)) {
-                       while (--i) {
+                       while (i--) {
                                dma_unmap_page(pdev, ttm_dma->dma_address[i],
                                               PAGE_SIZE, DMA_BIDIRECTIONAL);
                                ttm_dma->dma_address[i] = 0;
index 24be27d3cd18cfb35821b00fe9531c5d0337c284..20935eb2a09e9600e68d37edec8dcb3404a0db60 100644 (file)
@@ -635,10 +635,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
                nv_crtc->lut.depth = 0;
        }
 
-       /* Make sure that drm and hw vblank irqs get resumed if needed. */
-       for (head = 0; head < dev->mode_config.num_crtc; head++)
-               drm_vblank_on(dev, head);
-
        /* This should ensure we don't hit a locking problem when someone
         * wakes us up via a connector.  We should never go into suspend
         * while the display is on anyways.
@@ -648,6 +644,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
 
        drm_helper_resume_force_mode(dev);
 
+       /* Make sure that drm and hw vblank irqs get resumed if needed. */
+       for (head = 0; head < dev->mode_config.num_crtc; head++)
+               drm_vblank_on(dev, head);
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
index 8a70cec59bcd3f58b43d2d8119afa14c44190bce..2dfe58af12e4ee05103d14946dc4a0d001f7f9c6 100644 (file)
@@ -24,7 +24,7 @@
 static int nouveau_platform_probe(struct platform_device *pdev)
 {
        const struct nvkm_device_tegra_func *func;
-       struct nvkm_device *device;
+       struct nvkm_device *device = NULL;
        struct drm_device *drm;
        int ret;
 
index 7f8a42721eb20ccafe19fcaefe3d972f432a6c7f..e7e581d6a8ff24d256b6526d2b93c41b7a00daa3 100644 (file)
@@ -252,32 +252,40 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
 
        if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL)))
                return -ENOMEM;
-       *pdevice = &tdev->device;
+
        tdev->func = func;
        tdev->pdev = pdev;
        tdev->irq = -1;
 
        tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");
-       if (IS_ERR(tdev->vdd))
-               return PTR_ERR(tdev->vdd);
+       if (IS_ERR(tdev->vdd)) {
+               ret = PTR_ERR(tdev->vdd);
+               goto free;
+       }
 
        tdev->rst = devm_reset_control_get(&pdev->dev, "gpu");
-       if (IS_ERR(tdev->rst))
-               return PTR_ERR(tdev->rst);
+       if (IS_ERR(tdev->rst)) {
+               ret = PTR_ERR(tdev->rst);
+               goto free;
+       }
 
        tdev->clk = devm_clk_get(&pdev->dev, "gpu");
-       if (IS_ERR(tdev->clk))
-               return PTR_ERR(tdev->clk);
+       if (IS_ERR(tdev->clk)) {
+               ret = PTR_ERR(tdev->clk);
+               goto free;
+       }
 
        tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr");
-       if (IS_ERR(tdev->clk_pwr))
-               return PTR_ERR(tdev->clk_pwr);
+       if (IS_ERR(tdev->clk_pwr)) {
+               ret = PTR_ERR(tdev->clk_pwr);
+               goto free;
+       }
 
        nvkm_device_tegra_probe_iommu(tdev);
 
        ret = nvkm_device_tegra_power_up(tdev);
        if (ret)
-               return ret;
+               goto remove;
 
        tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value;
        ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,
@@ -285,9 +293,19 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
                               cfg, dbg, detect, mmio, subdev_mask,
                               &tdev->device);
        if (ret)
-               return ret;
+               goto powerdown;
+
+       *pdevice = &tdev->device;
 
        return 0;
+
+powerdown:
+       nvkm_device_tegra_power_down(tdev);
+remove:
+       nvkm_device_tegra_remove_iommu(tdev);
+free:
+       kfree(tdev);
+       return ret;
 }
 #else
 int
index 74e2f7c6c07e4a583d9e3f6d62016b92c5694d28..9688970eca47dbe4ccea5b2e700b0cfdb40b02e0 100644 (file)
@@ -328,6 +328,7 @@ nvkm_dp_train(struct work_struct *w)
                .outp = outp,
        }, *dp = &_dp;
        u32 datarate = 0;
+       u8  pwr;
        int ret;
 
        if (!outp->base.info.location && disp->func->sor.magic)
@@ -355,6 +356,15 @@ nvkm_dp_train(struct work_struct *w)
        /* disable link interrupt handling during link training */
        nvkm_notify_put(&outp->irq);
 
+       /* ensure sink is not in a low-power state */
+       if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) {
+               if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
+                       pwr &= ~DPCD_SC00_SET_POWER;
+                       pwr |=  DPCD_SC00_SET_POWER_D0;
+                       nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1);
+               }
+       }
+
        /* enable down-spreading and execute pre-train script from vbios */
        dp_link_train_init(dp, outp->dpcd[3] & 0x01);
 
index 9596290329c70e0cbe34259fbf5db39e12a9cbcb..6e10c5e0ef1162232253b29a248ad2c15e801f21 100644 (file)
 #define DPCD_LS0C_LANE1_POST_CURSOR2                                       0x0c
 #define DPCD_LS0C_LANE0_POST_CURSOR2                                       0x03
 
+/* DPCD Sink Control */
+#define DPCD_SC00                                                       0x00600
+#define DPCD_SC00_SET_POWER                                                0x03
+#define DPCD_SC00_SET_POWER_D0                                             0x01
+#define DPCD_SC00_SET_POWER_D3                                             0x03
+
 void nvkm_dp_train(struct work_struct *);
 #endif
index 2ae8577497ca6e1c9cc87b265ff7ca92ee5375ec..7c2e78201ead9d475c3ba97d083c523026c21a47 100644 (file)
@@ -168,7 +168,8 @@ static int qxl_process_single_command(struct qxl_device *qdev,
                       cmd->command_size))
                return -EFAULT;
 
-       reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL);
+       reloc_info = kmalloc_array(cmd->relocs_num,
+                                  sizeof(struct qxl_reloc_info), GFP_KERNEL);
        if (!reloc_info)
                return -ENOMEM;
 
index 3d031b50a8fd13dd8203f4de284ecedbb95ecbcc..9f029dda1f071431a9d90894096ab4a3f89bbe0a 100644 (file)
@@ -68,5 +68,5 @@ int qxl_gem_prime_mmap(struct drm_gem_object *obj,
                       struct vm_area_struct *area)
 {
        WARN_ONCE(1, "not implemented");
-       return ENOSYS;
+       return -ENOSYS;
 }
index 902b59cebac584b075639a2b7d34f031907cc3d1..4197ca1bb1e4d3f5d1455cc7c282787778660e9c 100644 (file)
@@ -1744,7 +1744,6 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        }
 
        drm_kms_helper_poll_enable(dev);
-       drm_helper_hpd_irq_event(dev);
 
        /* set the power state here in case we are a PX system or headless */
        if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
index 298ea1c453c3638fecdf6cef5afce1a48fdefa82..2b9ba03a7c1a84bc00564fe0f6391771977c2e7b 100644 (file)
@@ -403,7 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
        struct drm_crtc *crtc = &radeon_crtc->base;
        unsigned long flags;
        int r;
-       int vpos, hpos, stat, min_udelay;
+       int vpos, hpos, stat, min_udelay = 0;
+       unsigned repcnt = 4;
        struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
 
         down_read(&rdev->exclusive_lock);
@@ -454,7 +455,7 @@ static void radeon_flip_work_func(struct work_struct *__work)
         * In practice this won't execute very often unless on very fast
         * machines because the time window for this to happen is very small.
         */
-       for (;;) {
+       while (radeon_crtc->enabled && repcnt--) {
                /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
                 * start in hpos, and to the "fudged earlier" vblank start in
                 * vpos.
@@ -472,10 +473,22 @@ static void radeon_flip_work_func(struct work_struct *__work)
                /* Sleep at least until estimated real start of hw vblank */
                spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+               if (min_udelay > vblank->framedur_ns / 2000) {
+                       /* Don't wait ridiculously long - something is wrong */
+                       repcnt = 0;
+                       break;
+               }
                usleep_range(min_udelay, 2 * min_udelay);
                spin_lock_irqsave(&crtc->dev->event_lock, flags);
        };
 
+       if (!repcnt)
+               DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
+                                "framedur %d, linedur %d, stat %d, vpos %d, "
+                                "hpos %d\n", work->crtc_id, min_udelay,
+                                vblank->framedur_ns / 1000,
+                                vblank->linedur_ns / 1000, stat, vpos, hpos);
+
        /* do the flip (mmio) */
        radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
 
index 84d45633d28c9b1c58f58dc6ec6383eba2207230..fb6ad143873f5b40d2c027a20dd25914dbd5e29e 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
+#include <drm/drm_cache.h>
 #include "radeon.h"
 #include "radeon_trace.h"
 
@@ -245,6 +246,12 @@ int radeon_bo_create(struct radeon_device *rdev,
                DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
                              "better performance thanks to write-combining\n");
        bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+#else
+       /* For architectures that don't support WC memory,
+        * mask out the WC flag from the BO
+        */
+       if (!drm_arch_can_wc_memory())
+               bo->flags &= ~RADEON_GEM_GTT_WC;
 #endif
 
        radeon_ttm_placement_from_domain(bo, domain);
index 460c8f2989daca1ba9af3b7ba59d724c27182c1c..0f14d897baf9b32974a97eaa59153363e3d8c97b 100644 (file)
@@ -276,8 +276,12 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
        if (rdev->irq.installed) {
                for (i = 0; i < rdev->num_crtc; i++) {
                        if (rdev->pm.active_crtcs & (1 << i)) {
-                               rdev->pm.req_vblank |= (1 << i);
-                               drm_vblank_get(rdev->ddev, i);
+                               /* This can fail if a modeset is in progress */
+                               if (drm_vblank_get(rdev->ddev, i) == 0)
+                                       rdev->pm.req_vblank |= (1 << i);
+                               else
+                                       DRM_DEBUG_DRIVER("crtc %d no vblank, can glitch\n",
+                                                        i);
                        }
                }
        }
@@ -1075,12 +1079,6 @@ force:
 
        /* update display watermarks based on new power state */
        radeon_bandwidth_update(rdev);
-       /* update displays */
-       radeon_dpm_display_configuration_changed(rdev);
-
-       rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
-       rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
-       rdev->pm.dpm.single_display = single_display;
 
        /* wait for the rings to drain */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
@@ -1097,6 +1095,13 @@ force:
 
        radeon_dpm_post_set_power_state(rdev);
 
+       /* update displays */
+       radeon_dpm_display_configuration_changed(rdev);
+
+       rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+       rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+       rdev->pm.dpm.single_display = single_display;
+
        if (rdev->asic->dpm.force_performance_level) {
                if (rdev->pm.dpm.thermal_active) {
                        enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
index c507896aca45a43a3fe271b79b84e7db61bfb85a..197b157b73d09b96f7ced03c6703b6696c210793 100644 (file)
@@ -349,8 +349,13 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
                        /* see if we can skip over some allocations */
                } while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
 
+               for (i = 0; i < RADEON_NUM_RINGS; ++i)
+                       radeon_fence_ref(fences[i]);
+
                spin_unlock(&sa_manager->wq.lock);
                r = radeon_fence_wait_any(rdev, fences, false);
+               for (i = 0; i < RADEON_NUM_RINGS; ++i)
+                       radeon_fence_unref(&fences[i]);
                spin_lock(&sa_manager->wq.lock);
                /* if we have nothing to wait for block */
                if (r == -ENOENT) {
index e34307459e501f60895ca4a0abe156995706f921..e06ac546a90ff185a31f64b4ce6e9fd76d071adc 100644 (file)
@@ -758,7 +758,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
                                                       0, PAGE_SIZE,
                                                       PCI_DMA_BIDIRECTIONAL);
                if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) {
-                       while (--i) {
+                       while (i--) {
                                pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i],
                                               PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
                                gtt->ttm.dma_address[i] = 0;
index 18dfe3ec9a6274a57e8b311d5c62c82cb50c124f..22278bcfc60eac4ed40fac0e31dda840aa4b703e 100644 (file)
@@ -215,7 +215,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
        struct drm_gem_cma_object *cma_obj;
 
        if (size == 0)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        /* First, try to get a vc4_bo from the kernel BO cache. */
        if (from_cache) {
@@ -237,7 +237,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size,
                if (IS_ERR(cma_obj)) {
                        DRM_ERROR("Failed to allocate from CMA:\n");
                        vc4_bo_stats_dump(vc4);
-                       return NULL;
+                       return ERR_PTR(-ENOMEM);
                }
        }
 
@@ -259,8 +259,8 @@ int vc4_dumb_create(struct drm_file *file_priv,
                args->size = args->pitch * args->height;
 
        bo = vc4_bo_create(dev, args->size, false);
-       if (!bo)
-               return -ENOMEM;
+       if (IS_ERR(bo))
+               return PTR_ERR(bo);
 
        ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
        drm_gem_object_unreference_unlocked(&bo->base.base);
@@ -443,8 +443,8 @@ int vc4_create_bo_ioctl(struct drm_device *dev, void *data,
         * get zeroed, and that might leak data between users.
         */
        bo = vc4_bo_create(dev, args->size, false);
-       if (!bo)
-               return -ENOMEM;
+       if (IS_ERR(bo))
+               return PTR_ERR(bo);
 
        ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
        drm_gem_object_unreference_unlocked(&bo->base.base);
@@ -496,8 +496,8 @@ vc4_create_shader_bo_ioctl(struct drm_device *dev, void *data,
        }
 
        bo = vc4_bo_create(dev, args->size, true);
-       if (!bo)
-               return -ENOMEM;
+       if (IS_ERR(bo))
+               return PTR_ERR(bo);
 
        ret = copy_from_user(bo->base.vaddr,
                             (void __user *)(uintptr_t)args->data,
index 080865ec2bae67c7ff7b04a97fdb5956096cc156..51a63330d4f8bd3bef1946224aafba621eaa26a5 100644 (file)
@@ -91,8 +91,12 @@ struct vc4_dev {
        struct vc4_bo *overflow_mem;
        struct work_struct overflow_mem_work;
 
+       int power_refcount;
+
+       /* Mutex controlling the power refcount. */
+       struct mutex power_lock;
+
        struct {
-               uint32_t last_ct0ca, last_ct1ca;
                struct timer_list timer;
                struct work_struct reset_work;
        } hangcheck;
@@ -142,6 +146,7 @@ struct vc4_seqno_cb {
 };
 
 struct vc4_v3d {
+       struct vc4_dev *vc4;
        struct platform_device *pdev;
        void __iomem *regs;
 };
@@ -192,6 +197,11 @@ struct vc4_exec_info {
        /* Sequence number for this bin/render job. */
        uint64_t seqno;
 
+       /* Last current addresses the hardware was processing when the
+        * hangcheck timer checked on us.
+        */
+       uint32_t last_ct0ca, last_ct1ca;
+
        /* Kernel-space copy of the ioctl arguments */
        struct drm_vc4_submit_cl *args;
 
@@ -434,7 +444,6 @@ void vc4_plane_async_set_fb(struct drm_plane *plane,
 extern struct platform_driver vc4_v3d_driver;
 int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused);
 int vc4_v3d_debugfs_regs(struct seq_file *m, void *unused);
-int vc4_v3d_set_power(struct vc4_dev *vc4, bool on);
 
 /* vc4_validate.c */
 int
index 48ce30a6f4b5cebb21348c1148d85a8c2450e45f..202aa1544acc7df6b669781764f387daa99dd871 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/device.h>
 #include <linux/io.h>
 
@@ -228,8 +229,16 @@ vc4_reset(struct drm_device *dev)
        struct vc4_dev *vc4 = to_vc4_dev(dev);
 
        DRM_INFO("Resetting GPU.\n");
-       vc4_v3d_set_power(vc4, false);
-       vc4_v3d_set_power(vc4, true);
+
+       mutex_lock(&vc4->power_lock);
+       if (vc4->power_refcount) {
+               /* Power the device off and back on the by dropping the
+                * reference on runtime PM.
+                */
+               pm_runtime_put_sync_suspend(&vc4->v3d->pdev->dev);
+               pm_runtime_get_sync(&vc4->v3d->pdev->dev);
+       }
+       mutex_unlock(&vc4->power_lock);
 
        vc4_irq_reset(dev);
 
@@ -257,10 +266,17 @@ vc4_hangcheck_elapsed(unsigned long data)
        struct drm_device *dev = (struct drm_device *)data;
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        uint32_t ct0ca, ct1ca;
+       unsigned long irqflags;
+       struct vc4_exec_info *exec;
+
+       spin_lock_irqsave(&vc4->job_lock, irqflags);
+       exec = vc4_first_job(vc4);
 
        /* If idle, we can stop watching for hangs. */
-       if (list_empty(&vc4->job_list))
+       if (!exec) {
+               spin_unlock_irqrestore(&vc4->job_lock, irqflags);
                return;
+       }
 
        ct0ca = V3D_READ(V3D_CTNCA(0));
        ct1ca = V3D_READ(V3D_CTNCA(1));
@@ -268,14 +284,16 @@ vc4_hangcheck_elapsed(unsigned long data)
        /* If we've made any progress in execution, rearm the timer
         * and wait.
         */
-       if (ct0ca != vc4->hangcheck.last_ct0ca ||
-           ct1ca != vc4->hangcheck.last_ct1ca) {
-               vc4->hangcheck.last_ct0ca = ct0ca;
-               vc4->hangcheck.last_ct1ca = ct1ca;
+       if (ct0ca != exec->last_ct0ca || ct1ca != exec->last_ct1ca) {
+               exec->last_ct0ca = ct0ca;
+               exec->last_ct1ca = ct1ca;
+               spin_unlock_irqrestore(&vc4->job_lock, irqflags);
                vc4_queue_hangcheck(dev);
                return;
        }
 
+       spin_unlock_irqrestore(&vc4->job_lock, irqflags);
+
        /* We've gone too long with no progress, reset.  This has to
         * be done from a work struct, since resetting can sleep and
         * this timer hook isn't allowed to.
@@ -340,12 +358,7 @@ vc4_wait_for_seqno(struct drm_device *dev, uint64_t seqno, uint64_t timeout_ns,
        finish_wait(&vc4->job_wait_queue, &wait);
        trace_vc4_wait_for_seqno_end(dev, seqno);
 
-       if (ret && ret != -ERESTARTSYS) {
-               DRM_ERROR("timeout waiting for render thread idle\n");
-               return ret;
-       }
-
-       return 0;
+       return ret;
 }
 
 static void
@@ -578,9 +591,9 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
        }
 
        bo = vc4_bo_create(dev, exec_size, true);
-       if (!bo) {
+       if (IS_ERR(bo)) {
                DRM_ERROR("Couldn't allocate BO for binning\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(bo);
                goto fail;
        }
        exec->exec_bo = &bo->base;
@@ -617,6 +630,7 @@ fail:
 static void
 vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
 {
+       struct vc4_dev *vc4 = to_vc4_dev(dev);
        unsigned i;
 
        /* Need the struct lock for drm_gem_object_unreference(). */
@@ -635,6 +649,11 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
        }
        mutex_unlock(&dev->struct_mutex);
 
+       mutex_lock(&vc4->power_lock);
+       if (--vc4->power_refcount == 0)
+               pm_runtime_put(&vc4->v3d->pdev->dev);
+       mutex_unlock(&vc4->power_lock);
+
        kfree(exec);
 }
 
@@ -746,6 +765,9 @@ vc4_wait_bo_ioctl(struct drm_device *dev, void *data,
        struct drm_gem_object *gem_obj;
        struct vc4_bo *bo;
 
+       if (args->pad != 0)
+               return -EINVAL;
+
        gem_obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (!gem_obj) {
                DRM_ERROR("Failed to look up GEM BO %d\n", args->handle);
@@ -772,7 +794,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
        struct vc4_dev *vc4 = to_vc4_dev(dev);
        struct drm_vc4_submit_cl *args = data;
        struct vc4_exec_info *exec;
-       int ret;
+       int ret = 0;
 
        if ((args->flags & ~VC4_SUBMIT_CL_USE_CLEAR_COLOR) != 0) {
                DRM_ERROR("Unknown flags: 0x%02x\n", args->flags);
@@ -785,6 +807,15 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
                return -ENOMEM;
        }
 
+       mutex_lock(&vc4->power_lock);
+       if (vc4->power_refcount++ == 0)
+               ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
+       mutex_unlock(&vc4->power_lock);
+       if (ret < 0) {
+               kfree(exec);
+               return ret;
+       }
+
        exec->args = args;
        INIT_LIST_HEAD(&exec->unref_list);
 
@@ -839,6 +870,8 @@ vc4_gem_init(struct drm_device *dev)
                    (unsigned long)dev);
 
        INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
+
+       mutex_init(&vc4->power_lock);
 }
 
 void
index b68060e758dbd26e1dccd17beeba4c09bbb1441e..78a21357fb2de9fe88d50a26f20f0634d97dbd88 100644 (file)
@@ -57,7 +57,7 @@ vc4_overflow_mem_work(struct work_struct *work)
        struct vc4_bo *bo;
 
        bo = vc4_bo_create(dev, 256 * 1024, true);
-       if (!bo) {
+       if (IS_ERR(bo)) {
                DRM_ERROR("Couldn't allocate binner overflow mem\n");
                return;
        }
index 8a2a312e2c1bb618ea414ed3f0dd87e82ed7e09a..0f12418725e552f7378dada1d5af1244f52599ad 100644 (file)
@@ -316,20 +316,11 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
        size += xtiles * ytiles * loop_body_size;
 
        setup->rcl = &vc4_bo_create(dev, size, true)->base;
-       if (!setup->rcl)
-               return -ENOMEM;
+       if (IS_ERR(setup->rcl))
+               return PTR_ERR(setup->rcl);
        list_add_tail(&to_vc4_bo(&setup->rcl->base)->unref_head,
                      &exec->unref_list);
 
-       rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
-       rcl_u32(setup,
-               (setup->color_write ? (setup->color_write->paddr +
-                                      args->color_write.offset) :
-                0));
-       rcl_u16(setup, args->width);
-       rcl_u16(setup, args->height);
-       rcl_u16(setup, args->color_write.bits);
-
        /* The tile buffer gets cleared when the previous tile is stored.  If
         * the clear values changed between frames, then the tile buffer has
         * stale clear values in it, so we have to do a store in None mode (no
@@ -349,6 +340,15 @@ static int vc4_create_rcl_bo(struct drm_device *dev, struct vc4_exec_info *exec,
                rcl_u32(setup, 0); /* no address, since we're in None mode */
        }
 
+       rcl_u8(setup, VC4_PACKET_TILE_RENDERING_MODE_CONFIG);
+       rcl_u32(setup,
+               (setup->color_write ? (setup->color_write->paddr +
+                                      args->color_write.offset) :
+                0));
+       rcl_u16(setup, args->width);
+       rcl_u16(setup, args->height);
+       rcl_u16(setup, args->color_write.bits);
+
        for (y = min_y_tile; y <= max_y_tile; y++) {
                for (x = min_x_tile; x <= max_x_tile; x++) {
                        bool first = (x == min_x_tile && y == min_y_tile);
index 314ff71db978dedfd8272ea0afe0087f1903ca4a..31de5d17bc856a0c152f9d9b4ebaae4c48880ce9 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include "linux/component.h"
+#include "linux/pm_runtime.h"
 #include "vc4_drv.h"
 #include "vc4_regs.h"
 
@@ -144,18 +145,6 @@ int vc4_v3d_debugfs_ident(struct seq_file *m, void *unused)
 }
 #endif /* CONFIG_DEBUG_FS */
 
-int
-vc4_v3d_set_power(struct vc4_dev *vc4, bool on)
-{
-       /* XXX: This interface is needed for GPU reset, and the way to
-        * do it is to turn our power domain off and back on.  We
-        * can't just reset from within the driver, because the reset
-        * bits are in the power domain's register area, and get set
-        * during the poweron process.
-        */
-       return 0;
-}
-
 static void vc4_v3d_init_hw(struct drm_device *dev)
 {
        struct vc4_dev *vc4 = to_vc4_dev(dev);
@@ -167,6 +156,29 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
        V3D_WRITE(V3D_VPMBASE, 0);
 }
 
+#ifdef CONFIG_PM
+static int vc4_v3d_runtime_suspend(struct device *dev)
+{
+       struct vc4_v3d *v3d = dev_get_drvdata(dev);
+       struct vc4_dev *vc4 = v3d->vc4;
+
+       vc4_irq_uninstall(vc4->dev);
+
+       return 0;
+}
+
+static int vc4_v3d_runtime_resume(struct device *dev)
+{
+       struct vc4_v3d *v3d = dev_get_drvdata(dev);
+       struct vc4_dev *vc4 = v3d->vc4;
+
+       vc4_v3d_init_hw(vc4->dev);
+       vc4_irq_postinstall(vc4->dev);
+
+       return 0;
+}
+#endif
+
 static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -179,6 +191,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
        if (!v3d)
                return -ENOMEM;
 
+       dev_set_drvdata(dev, v3d);
+
        v3d->pdev = pdev;
 
        v3d->regs = vc4_ioremap_regs(pdev, 0);
@@ -186,6 +200,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
                return PTR_ERR(v3d->regs);
 
        vc4->v3d = v3d;
+       v3d->vc4 = vc4;
 
        if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
                DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
@@ -207,6 +222,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
+       pm_runtime_enable(dev);
+
        return 0;
 }
 
@@ -216,6 +233,8 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dev *vc4 = to_vc4_dev(drm);
 
+       pm_runtime_disable(dev);
+
        drm_irq_uninstall(drm);
 
        /* Disable the binner's overflow memory address, so the next
@@ -228,6 +247,10 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
        vc4->v3d = NULL;
 }
 
+static const struct dev_pm_ops vc4_v3d_pm_ops = {
+       SET_RUNTIME_PM_OPS(vc4_v3d_runtime_suspend, vc4_v3d_runtime_resume, NULL)
+};
+
 static const struct component_ops vc4_v3d_ops = {
        .bind   = vc4_v3d_bind,
        .unbind = vc4_v3d_unbind,
@@ -255,5 +278,6 @@ struct platform_driver vc4_v3d_driver = {
        .driver = {
                .name = "vc4_v3d",
                .of_match_table = vc4_v3d_dt_match,
+               .pm = &vc4_v3d_pm_ops,
        },
 };
index e26d9f6face3c498a4ddb5278e7d9f043cd2de2c..24c2c746e8f397aafd0285323508bd2ee351d3a2 100644 (file)
@@ -401,8 +401,8 @@ validate_tile_binning_config(VALIDATE_ARGS)
        tile_bo = vc4_bo_create(dev, exec->tile_alloc_offset + tile_alloc_size,
                                true);
        exec->tile_bo = &tile_bo->base;
-       if (!exec->tile_bo)
-               return -ENOMEM;
+       if (IS_ERR(exec->tile_bo))
+               return PTR_ERR(exec->tile_bo);
        list_add_tail(&tile_bo->unref_head, &exec->unref_list);
 
        /* tile alloc address. */
index 58704f0a46077f138236dd1ba6f51047c45ad6ec..531d22025fecf05a4264ece921d9a8c2031542c1 100644 (file)
@@ -25,6 +25,8 @@
  *
  **************************************************************************/
 
+#include <linux/kernel.h>
+
 #ifdef __KERNEL__
 
 #include <drm/vmwgfx_drm.h>
@@ -36,7 +38,6 @@
 #define ARRAY_SIZE(_A) (sizeof(_A) / sizeof((_A)[0]))
 #endif /* ARRAY_SIZE */
 
-#define DIV_ROUND_UP(x, y)  (((x) + (y) - 1) / (y))
 #define max_t(type, x, y)  ((x) > (y) ? (x) : (y))
 #define surf_size_struct SVGA3dSize
 #define u32 uint32
@@ -987,12 +988,12 @@ svga3dsurface_get_size_in_blocks(const struct svga3d_surface_desc *desc,
                                 const surf_size_struct *pixel_size,
                                 surf_size_struct *block_size)
 {
-       block_size->width = DIV_ROUND_UP(pixel_size->width,
-                                        desc->block_size.width);
-       block_size->height = DIV_ROUND_UP(pixel_size->height,
-                                         desc->block_size.height);
-       block_size->depth = DIV_ROUND_UP(pixel_size->depth,
-                                        desc->block_size.depth);
+       block_size->width = __KERNEL_DIV_ROUND_UP(pixel_size->width,
+                                                 desc->block_size.width);
+       block_size->height = __KERNEL_DIV_ROUND_UP(pixel_size->height,
+                                                  desc->block_size.height);
+       block_size->depth = __KERNEL_DIV_ROUND_UP(pixel_size->depth,
+                                                 desc->block_size.depth);
 }
 
 static inline bool
@@ -1100,8 +1101,9 @@ svga3dsurface_get_pixel_offset(SVGA3dSurfaceFormat format,
        const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
        const u32 bw = desc->block_size.width, bh = desc->block_size.height;
        const u32 bd = desc->block_size.depth;
-       const u32 rowstride = DIV_ROUND_UP(width, bw) * desc->bytes_per_block;
-       const u32 imgstride = DIV_ROUND_UP(height, bh) * rowstride;
+       const u32 rowstride = __KERNEL_DIV_ROUND_UP(width, bw) *
+                             desc->bytes_per_block;
+       const u32 imgstride = __KERNEL_DIV_ROUND_UP(height, bh) * rowstride;
        const u32 offset = (z / bd * imgstride +
                            y / bh * rowstride +
                            x / bw * desc->bytes_per_block);
index da462afcb225ea6958918b3d8ff52a0ee928cca3..dd2dbb9746cebc337b17733eb41c4cf4536d75c6 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/host1x.h>
 #include <linux/of.h>
 #include <linux/slab.h>
+#include <linux/of_device.h>
 
 #include "bus.h"
 #include "dev.h"
@@ -394,6 +395,7 @@ static int host1x_device_add(struct host1x *host1x,
        device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
        device->dev.dma_mask = &device->dev.coherent_dma_mask;
        dev_set_name(&device->dev, "%s", driver->driver.name);
+       of_dma_configure(&device->dev, host1x->dev->of_node);
        device->dev.release = host1x_device_release;
        device->dev.bus = &host1x_bus_type;
        device->dev.parent = host1x->dev;
index 314bf3718cc799b01462dd2cee678dcec604632e..ff348690df94a0eebcddaadedfbf440cb05cac4a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/host1x.h>
@@ -68,6 +69,7 @@ static const struct host1x_info host1x01_info = {
        .nb_bases       = 8,
        .init           = host1x01_init,
        .sync_offset    = 0x3000,
+       .dma_mask       = DMA_BIT_MASK(32),
 };
 
 static const struct host1x_info host1x02_info = {
@@ -77,6 +79,7 @@ static const struct host1x_info host1x02_info = {
        .nb_bases = 12,
        .init = host1x02_init,
        .sync_offset = 0x3000,
+       .dma_mask = DMA_BIT_MASK(32),
 };
 
 static const struct host1x_info host1x04_info = {
@@ -86,6 +89,7 @@ static const struct host1x_info host1x04_info = {
        .nb_bases = 64,
        .init = host1x04_init,
        .sync_offset = 0x2100,
+       .dma_mask = DMA_BIT_MASK(34),
 };
 
 static const struct host1x_info host1x05_info = {
@@ -95,6 +99,7 @@ static const struct host1x_info host1x05_info = {
        .nb_bases = 64,
        .init = host1x05_init,
        .sync_offset = 0x2100,
+       .dma_mask = DMA_BIT_MASK(34),
 };
 
 static struct of_device_id host1x_of_match[] = {
@@ -148,6 +153,8 @@ static int host1x_probe(struct platform_device *pdev)
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
 
+       dma_set_mask_and_coherent(host->dev, host->info->dma_mask);
+
        if (host->info->init) {
                err = host->info->init(host);
                if (err)
index 0b6e8e9629c5330fbc7fadba1a1ae318ae07da12..dace124994bb2683cc0c66218dcd5cdd15902d2b 100644 (file)
@@ -96,6 +96,7 @@ struct host1x_info {
        int     nb_mlocks;              /* host1x: number of mlocks */
        int     (*init)(struct host1x *); /* initialize per SoC ops */
        int     sync_offset;
+       u64     dma_mask;               /* mask of addressable memory */
 };
 
 struct host1x {
index f155b83804819ff97455ba5312f62de7f14991e2..2b3105c8aed399f8ce9cd3df03d6a265378131fc 100644 (file)
@@ -126,7 +126,7 @@ static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
        struct ads1015_data *data = i2c_get_clientdata(client);
        unsigned int pga = data->channel_data[channel].pga;
        int fullscale = fullscale_table[pga];
-       const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
+       const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
 
        return DIV_ROUND_CLOSEST(reg * fullscale, mask);
 }
index 82de3deeb18a7ddf5e041e695b35cc8b1500abea..685568b1236d4a26db2d685ce36dcb9729e9f3ab 100644 (file)
@@ -406,16 +406,11 @@ static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev,
                                  unsigned long *state)
 {
        struct gpio_fan_data *fan_data = cdev->devdata;
-       int r;
 
        if (!fan_data)
                return -EINVAL;
 
-       r = get_fan_speed_index(fan_data);
-       if (r < 0)
-               return r;
-
-       *state = r;
+       *state = fan_data->speed_index;
        return 0;
 }
 
index 52f708bcf77f397952ea0f278ce5b161780e076a..d50c701b19d678e9998319be36a492bb3a8eba6d 100644 (file)
@@ -313,6 +313,10 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
                hwlock = radix_tree_deref_slot(slot);
                if (unlikely(!hwlock))
                        continue;
+               if (radix_tree_is_indirect_ptr(hwlock)) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
 
                if (hwlock->bank->dev->of_node == args.np) {
                        ret = 0;
index 3711df1d452622edd57fb805f2ffcbbab236d9b4..4a45408dd82060fc56b9e8e10c2e8534e8ebba5d 100644 (file)
@@ -586,8 +586,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
 
-       dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(struct bsc_regs *),
-                                      GFP_KERNEL);
+       dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL);
        if (!dev->bsc_regmap)
                return -ENOMEM;
 
index f62d69799a9c55b0f79e2de5e29ec9a09b257c98..27fa0cb09538cebfd0f9388112cfe30abb773edd 100644 (file)
@@ -1271,6 +1271,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
        switch (dev->device) {
        case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
        case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+       case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS:
+       case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS:
        case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
                priv->features |= FEATURE_I2C_BLOCK_READ;
                priv->features |= FEATURE_IRQ;
index 08d26ba61ed3326a8905c99cdb6ee8caaef45727..13c45296ce5bfc5390a1bbffcca9960b3b1b90b6 100644 (file)
@@ -1450,7 +1450,8 @@ omap_i2c_probe(struct platform_device *pdev)
 
 err_unuse_clocks:
        omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
-       pm_runtime_put(omap->dev);
+       pm_runtime_dont_use_autosuspend(omap->dev);
+       pm_runtime_put_sync(omap->dev);
        pm_runtime_disable(&pdev->dev);
 err_free_mem:
 
@@ -1468,6 +1469,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
                return ret;
 
        omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0);
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return 0;
index f3e5ff8522f0af6ef77af252f3269114fe4b803e..213ba55e17c3a35bfe9faacc9155a3f8072b2899 100644 (file)
@@ -467,7 +467,7 @@ static int uniphier_fi2c_clk_init(struct device *dev,
                bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
 
        if (!bus_speed) {
-               dev_err(dev, "clock-freqyency should not be zero\n");
+               dev_err(dev, "clock-frequency should not be zero\n");
                return -EINVAL;
        }
 
index 1f4f3f53819c7a88516dad5eab11d773fceb89f9..89eaa8a7e1e01578a4ee27f322a8cbfe75abf5e8 100644 (file)
@@ -328,7 +328,7 @@ static int uniphier_i2c_clk_init(struct device *dev,
                bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
 
        if (!bus_speed) {
-               dev_err(dev, "clock-freqyency should not be zero\n");
+               dev_err(dev, "clock-frequency should not be zero\n");
                return -EINVAL;
        }
 
index edc29b173f6c9012635771116a6cca23193a096e..833ea9dd4464b664e9d11103c8543961a65f5f01 100644 (file)
@@ -213,6 +213,7 @@ config STK8312
 config STK8BA50
        tristate "Sensortek STK8BA50 3-Axis Accelerometer Driver"
        depends on I2C
+       depends on IIO_TRIGGER
        help
          Say yes here to get support for the Sensortek STK8BA50 3-axis
          accelerometer.
index 605ff42c46310201e7aba3fd2f7ab42a0a873e04..283ded7747a9379be4c105ef49964d5c5d674b0f 100644 (file)
@@ -175,6 +175,7 @@ config DA9150_GPADC
 config EXYNOS_ADC
        tristate "Exynos ADC driver support"
        depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
+       depends on HAS_IOMEM
        help
          Core support for the ADC block found in the Samsung EXYNOS series
          of SoCs for drivers such as the touchscreen and hwmon to use to share
@@ -207,6 +208,7 @@ config INA2XX_ADC
 config IMX7D_ADC
        tristate "IMX7D ADC driver"
        depends on ARCH_MXC || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Say yes here to build support for IMX7D ADC.
 
@@ -409,6 +411,7 @@ config TWL6030_GPADC
 config VF610_ADC
        tristate "Freescale vf610 ADC driver"
        depends on OF
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index 942320e32753c3838e967e9e0a96d4db2d691fce..c1e05532d437f263a9aa3d7f7c96147b13bfe682 100644 (file)
@@ -289,7 +289,7 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
                goto error_kfifo_free;
 
        indio_dev->setup_ops = setup_ops;
-       indio_dev->modes |= INDIO_BUFFER_HARDWARE;
+       indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
 
        return 0;
 
index 43d14588448d65f507ab02ce22c0e01d7a9008ad..b4dde8315210c6519c7e2a7db4bd8bf3b6607988 100644 (file)
@@ -300,6 +300,7 @@ static int mcp4725_probe(struct i2c_client *client,
        data->client = client;
 
        indio_dev->dev.parent = &client->dev;
+       indio_dev->name = id->name;
        indio_dev->info = &mcp4725_info;
        indio_dev->channels = &mcp4725_channel;
        indio_dev->num_channels = 1;
index 1165b1c4f9d67bd93db24f784da5b13010d9fd99..cfc5a051ab9f3946bfdfd4aaf5aaac01f7245f36 100644 (file)
@@ -117,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
        if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
                return -EIO;
 
-       dht11->timestamp = ktime_get_real_ns();
+       dht11->timestamp = ktime_get_boot_ns();
        if (hum_int < 20) {  /* DHT22 */
                dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
                                        ((temp_int & 0x80) ? -100 : 100);
@@ -145,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
 
        /* TODO: Consider making the handler safe for IRQ sharing */
        if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
-               dht11->edges[dht11->num_edges].ts = ktime_get_real_ns();
+               dht11->edges[dht11->num_edges].ts = ktime_get_boot_ns();
                dht11->edges[dht11->num_edges++].value =
                                                gpio_get_value(dht11->gpio);
 
@@ -164,7 +164,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
        int ret, timeres;
 
        mutex_lock(&dht11->lock);
-       if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {
+       if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) {
                timeres = ktime_get_resolution_ns();
                if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
                        dev_err(dht11->dev, "timeresolution %dns too low\n",
@@ -279,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1;
+       dht11->timestamp = ktime_get_boot_ns() - DHT11_DATA_VALID_TIME - 1;
        dht11->num_edges = -1;
 
        platform_set_drvdata(pdev, iio);
index 48fbc0bc7e2a1d499015001bace2c46db2c8b440..8f8d1370ed8b9b3359d3a4f1135767a622df2c21 100644 (file)
@@ -5,9 +5,9 @@
 config INV_MPU6050_IIO
        tristate "Invensense MPU6050 devices"
        depends on I2C && SYSFS
+       depends on I2C_MUX
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
-       select I2C_MUX
        help
          This driver supports the Invensense MPU6050 devices.
          This driver can also support MPU6500 in MPU6050 compatibility mode
index 80fbbfd76faf9e1859eefb1b5dc55b2129f9858b..734a0042de0cb4265ee3145ee48f22a19b8b50af 100644 (file)
@@ -349,6 +349,8 @@ EXPORT_SYMBOL_GPL(iio_channel_get);
 
 void iio_channel_release(struct iio_channel *channel)
 {
+       if (!channel)
+               return;
        iio_device_put(channel->indio_dev);
        kfree(channel);
 }
index 60537ec0c923b98c45160d011f4a17ac932e4609..53201d99a16c8d760f4ec909c8c5fb1cba6bc8be 100644 (file)
@@ -54,7 +54,9 @@ static const struct iio_chan_spec acpi_als_channels[] = {
                        .realbits       = 32,
                        .storagebits    = 32,
                },
-               .info_mask_separate     = BIT(IIO_CHAN_INFO_RAW),
+               /* _RAW is here for backward ABI compatibility */
+               .info_mask_separate     = BIT(IIO_CHAN_INFO_RAW) |
+                                         BIT(IIO_CHAN_INFO_PROCESSED),
        },
 };
 
@@ -152,7 +154,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev,
        s32 temp_val;
        int ret;
 
-       if (mask != IIO_CHAN_INFO_RAW)
+       if ((mask != IIO_CHAN_INFO_PROCESSED) && (mask != IIO_CHAN_INFO_RAW))
                return -EINVAL;
 
        /* we support only illumination (_ALI) so far. */
index 809a961b9a7f6d0d0077114e12767e4e267c7606..6bf89d8f374191cee48f258d1c25810b0e5dc410 100644 (file)
@@ -180,7 +180,7 @@ static const struct ltr501_samp_table ltr501_ps_samp_table[] = {
                        {500000, 2000000}
 };
 
-static unsigned int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
+static int ltr501_match_samp_freq(const struct ltr501_samp_table *tab,
                                           int len, int val, int val2)
 {
        int i, freq;
index f5ecd6e19f5de725e715e547a5527f5875050561..a0d7deeac62f78dfc416bf597e0b894436c75a8c 100644 (file)
@@ -117,7 +117,7 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
                *val = ret >> 6;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_OFFSET:
-               *val = 605;
+               *val = -605;
                *val2 = 750000;
                return IIO_VAL_INT_PLUS_MICRO;
        case IIO_CHAN_INFO_SCALE:
index 93e29fb67fa00f94e9ca0a614addfc5cde7ebb76..db35e04a063767a9b2b6011cf3d0345c9d0929bd 100644 (file)
@@ -87,7 +87,7 @@ static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
 
        ret = i2c_transfer(client->adapter, msg, 2);
 
-       return (ret == 2) ? 0 : ret;
+       return (ret == 2) ? 0 : -EIO;
 }
 
 static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
index 00da80e02154205c428ca00702f4b7c10fa5a829..94b80a51ab68e7e15c327778122f54351254b9a6 100644 (file)
@@ -358,6 +358,7 @@ int ib_register_device(struct ib_device *device,
        ret = device->query_device(device, &device->attrs, &uhw);
        if (ret) {
                printk(KERN_WARNING "Couldn't query the device attributes\n");
+               ib_cache_cleanup_one(device);
                goto out;
        }
 
index f334090bb6129bf7f3cfe788e5cff7bc762752c3..1e37f3515d98a7fba49a7cbd57975ba2b8492bd5 100644 (file)
@@ -1071,7 +1071,7 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
                }
        }
 
-       if (rec->hop_limit > 1 || use_roce) {
+       if (rec->hop_limit > 0 || use_roce) {
                ah_attr->ah_flags = IB_AH_GRH;
                ah_attr->grh.dgid = rec->dgid;
 
index 3de93517efe43b097d7f58e37cfbe36bd8ab0f65..14606afbfaa8d6c865d28a545c292146ffc1b4bc 100644 (file)
@@ -336,7 +336,6 @@ static ssize_t _show_port_gid_attr(struct ib_port *p,
        union ib_gid gid;
        struct ib_gid_attr gid_attr = {};
        ssize_t ret;
-       va_list args;
 
        ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid,
                           &gid_attr);
@@ -348,7 +347,6 @@ static ssize_t _show_port_gid_attr(struct ib_port *p,
 err:
        if (gid_attr.ndev)
                dev_put(gid_attr.ndev);
-       va_end(args);
        return ret;
 }
 
@@ -722,12 +720,11 @@ static struct attribute_group *get_counter_table(struct ib_device *dev,
 
        if (get_perf_mad(dev, port_num, IB_PMA_CLASS_PORT_INFO,
                                &cpi, 40, sizeof(cpi)) >= 0) {
-
-               if (cpi.capability_mask && IB_PMA_CLASS_CAP_EXT_WIDTH)
+               if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH)
                        /* We have extended counters */
                        return &pma_group_ext;
 
-               if (cpi.capability_mask && IB_PMA_CLASS_CAP_EXT_WIDTH_NOIETF)
+               if (cpi.capability_mask & IB_PMA_CLASS_CAP_EXT_WIDTH_NOIETF)
                        /* But not the IETF ones */
                        return &pma_group_noietf;
        }
index 19837d2702789e63f1d948c1abaf4bae9a28d7f6..2116132568e70e61c8465ffc9d922d732aca28ed 100644 (file)
@@ -322,6 +322,8 @@ int ib_ud_header_init(int     payload_bytes,
                      int    immediate_present,
                      struct ib_ud_header *header)
 {
+       size_t udp_bytes = udp_present ? IB_UDP_BYTES : 0;
+
        grh_present = grh_present && !ip_version;
        memset(header, 0, sizeof *header);
 
@@ -353,7 +355,8 @@ int ib_ud_header_init(int     payload_bytes,
        if (ip_version == 6 || grh_present) {
                header->grh.ip_version      = 6;
                header->grh.payload_length  =
-                       cpu_to_be16((IB_BTH_BYTES     +
+                       cpu_to_be16((udp_bytes        +
+                                    IB_BTH_BYTES     +
                                     IB_DETH_BYTES    +
                                     payload_bytes    +
                                     4                + /* ICRC     */
@@ -362,8 +365,6 @@ int ib_ud_header_init(int     payload_bytes,
        }
 
        if (ip_version == 4) {
-               int udp_bytes = udp_present ? IB_UDP_BYTES : 0;
-
                header->ip4.ver = 4; /* version 4 */
                header->ip4.hdr_len = 5; /* 5 words */
                header->ip4.tot_len =
index 6ffc9c4e93afb4efa27fe6f3c17fc3cdf41d8c21..6c6fbff19752ecbcf2d4822965ff6bb09d7ee656 100644 (file)
@@ -1970,7 +1970,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
                   resp_size);
        INIT_UDATA(&uhw, buf + sizeof(cmd),
                   (unsigned long)cmd.response + resp_size,
-                  in_len - sizeof(cmd), out_len - resp_size);
+                  in_len - sizeof(cmd) - sizeof(struct ib_uverbs_cmd_hdr),
+                  out_len - resp_size);
 
        memset(&cmd_ex, 0, sizeof(cmd_ex));
        cmd_ex.user_handle = cmd.user_handle;
@@ -3413,7 +3414,8 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
 
        INIT_UDATA(&udata, buf + sizeof cmd,
                   (unsigned long) cmd.response + sizeof resp,
-                  in_len - sizeof cmd, out_len - sizeof resp);
+                  in_len - sizeof cmd - sizeof(struct ib_uverbs_cmd_hdr),
+                  out_len - sizeof resp);
 
        ret = __uverbs_create_xsrq(file, ib_dev, &xcmd, &udata);
        if (ret)
@@ -3439,7 +3441,8 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file,
 
        INIT_UDATA(&udata, buf + sizeof cmd,
                   (unsigned long) cmd.response + sizeof resp,
-                  in_len - sizeof cmd, out_len - sizeof resp);
+                  in_len - sizeof cmd - sizeof(struct ib_uverbs_cmd_hdr),
+                  out_len - sizeof resp);
 
        ret = __uverbs_create_xsrq(file, ib_dev, &cmd, &udata);
        if (ret)
index fc01deac1d3c77497189fc5580ed6a61e9d5ced9..db4aa13ebae0c693138bdb51832961e2a1d492ba 100644 (file)
@@ -1,6 +1,7 @@
 config MLX4_INFINIBAND
        tristate "Mellanox ConnectX HCA support"
        depends on NETDEVICES && ETHERNET && PCI && INET
+       depends on MAY_USE_DEVLINK
        select NET_VENDOR_MELLANOX
        select MLX4_CORE
        ---help---
index 26833bfa639bb61fb9658187bfa5cd45497340ed..d68f506c1922e8d18af269a4fcde33fd0e3ae5d5 100644 (file)
@@ -817,17 +817,48 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
 }
 
-static void edit_counter(struct mlx4_counter *cnt,
-                                       struct ib_pma_portcounters *pma_cnt)
+static void edit_counter(struct mlx4_counter *cnt, void *counters,
+                        __be16 attr_id)
 {
-       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
-                            (be64_to_cpu(cnt->tx_bytes) >> 2));
-       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
-                            (be64_to_cpu(cnt->rx_bytes) >> 2));
-       ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
-                            be64_to_cpu(cnt->tx_frames));
-       ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
-                            be64_to_cpu(cnt->rx_frames));
+       switch (attr_id) {
+       case IB_PMA_PORT_COUNTERS:
+       {
+               struct ib_pma_portcounters *pma_cnt =
+                       (struct ib_pma_portcounters *)counters;
+
+               ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data,
+                                    (be64_to_cpu(cnt->tx_bytes) >> 2));
+               ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data,
+                                    (be64_to_cpu(cnt->rx_bytes) >> 2));
+               ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets,
+                                    be64_to_cpu(cnt->tx_frames));
+               ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets,
+                                    be64_to_cpu(cnt->rx_frames));
+               break;
+       }
+       case IB_PMA_PORT_COUNTERS_EXT:
+       {
+               struct ib_pma_portcounters_ext *pma_cnt_ext =
+                       (struct ib_pma_portcounters_ext *)counters;
+
+               pma_cnt_ext->port_xmit_data =
+                       cpu_to_be64(be64_to_cpu(cnt->tx_bytes) >> 2);
+               pma_cnt_ext->port_rcv_data =
+                       cpu_to_be64(be64_to_cpu(cnt->rx_bytes) >> 2);
+               pma_cnt_ext->port_xmit_packets = cnt->tx_frames;
+               pma_cnt_ext->port_rcv_packets = cnt->rx_frames;
+               break;
+       }
+       }
+}
+
+static int iboe_process_mad_port_info(void *out_mad)
+{
+       struct ib_class_port_info cpi = {};
+
+       cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH;
+       memcpy(out_mad, &cpi, sizeof(cpi));
+       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
 }
 
 static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
@@ -842,6 +873,9 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
        if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
                return -EINVAL;
 
+       if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO)
+               return iboe_process_mad_port_info((void *)(out_mad->data + 40));
+
        memset(&counter_stats, 0, sizeof(counter_stats));
        mutex_lock(&dev->counters_table[port_num - 1].mutex);
        list_for_each_entry(tmp_counter,
@@ -863,7 +897,8 @@ static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
                switch (counter_stats.counter_mode & 0xf) {
                case 0:
                        edit_counter(&counter_stats,
-                                    (void *)(out_mad->data + 40));
+                                    (void *)(out_mad->data + 40),
+                                    in_mad->mad_hdr.attr_id);
                        err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
                        break;
                default:
@@ -894,8 +929,10 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
         */
        if (link == IB_LINK_LAYER_INFINIBAND) {
                if (mlx4_is_slave(dev->dev) &&
-                   in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
-                   in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS)
+                   (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
+                    (in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS ||
+                     in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT ||
+                     in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO)))
                        return iboe_process_mad(ibdev, mad_flags, port_num, in_wc,
                                                in_grh, in_mad, out_mad);
 
index 1c7ab6cabbb86989fba8952b8f5e6be645e313dc..a15a7b37d3862358eab3a5744c94d194224b7d71 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/if_vlan.h>
 #include <net/ipv6.h>
 #include <net/addrconf.h>
+#include <net/devlink.h>
 
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
@@ -2519,6 +2520,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        }
 
        ibdev->ib_active = true;
+       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+               devlink_port_type_ib_set(mlx4_get_devlink_port(dev, i),
+                                        &ibdev->ib_dev);
 
        if (mlx4_is_mfunc(ibdev->dev))
                init_pkeys(ibdev);
@@ -2643,7 +2647,10 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr)
 {
        struct mlx4_ib_dev *ibdev = ibdev_ptr;
        int p;
+       int i;
 
+       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+               devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
        ibdev->ib_active = false;
        flush_workqueue(wq);
 
index bc5536f00b6cd4cc148f65b2c6131d7e627544eb..fd97534762b8dc7f83651a52e9398a3aa6e4944e 100644 (file)
@@ -1681,9 +1681,12 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (qp->ibqp.uobject)
-               context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index);
+               context->usr_page = cpu_to_be32(
+                       mlx4_to_hw_uar_index(dev->dev,
+                                            to_mucontext(ibqp->uobject->context)->uar.index));
        else
-               context->usr_page = cpu_to_be32(dev->priv_uar.index);
+               context->usr_page = cpu_to_be32(
+                       mlx4_to_hw_uar_index(dev->dev, dev->priv_uar.index));
 
        if (attr_mask & IB_QP_DEST_QPN)
                context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
index ec737e2287fe150ff8d5d83e6ca7042a2cca8b62..e1cea4415704d5249d4c53e25416323b9d30d9b4 100644 (file)
@@ -42,6 +42,7 @@
 #include <rdma/ib_user_verbs.h>
 #include <rdma/ib_addr.h>
 #include <rdma/ib_cache.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/vport.h>
 #include <rdma/ib_smi.h>
 #include <rdma/ib_umem.h>
@@ -844,6 +845,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        int err;
        int i;
        size_t reqlen;
+       size_t min_req_v2 = offsetof(struct mlx5_ib_alloc_ucontext_req_v2,
+                                    max_cqe_version);
 
        if (!dev->ib_active)
                return ERR_PTR(-EAGAIN);
@@ -854,7 +857,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        reqlen = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr);
        if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req))
                ver = 0;
-       else if (reqlen >= sizeof(struct mlx5_ib_alloc_ucontext_req_v2))
+       else if (reqlen >= min_req_v2)
                ver = 2;
        else
                return ERR_PTR(-EINVAL);
@@ -2214,7 +2217,9 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev)
                (1ull << IB_USER_VERBS_CMD_CREATE_XSRQ)         |
                (1ull << IB_USER_VERBS_CMD_OPEN_QP);
        dev->ib_dev.uverbs_ex_cmd_mask =
-               (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE);
+               (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE)     |
+               (1ull << IB_USER_VERBS_EX_CMD_CREATE_CQ)        |
+               (1ull << IB_USER_VERBS_EX_CMD_CREATE_QP);
 
        dev->ib_dev.query_device        = mlx5_ib_query_device;
        dev->ib_dev.query_port          = mlx5_ib_query_port;
index 8fb9c27485e19959a09edf3b3bdf3f7c56557732..34cb8e87c7b8b673493285f807206c437ac42a84 100644 (file)
@@ -270,8 +270,10 @@ static int sq_overhead(enum ib_qp_type qp_type)
                /* fall through */
        case IB_QPT_RC:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
-                       sizeof(struct mlx5_wqe_atomic_seg) +
-                       sizeof(struct mlx5_wqe_raddr_seg);
+                       max(sizeof(struct mlx5_wqe_atomic_seg) +
+                           sizeof(struct mlx5_wqe_raddr_seg),
+                           sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+                           sizeof(struct mlx5_mkey_seg));
                break;
 
        case IB_QPT_XRC_TGT:
@@ -279,9 +281,9 @@ static int sq_overhead(enum ib_qp_type qp_type)
 
        case IB_QPT_UC:
                size += sizeof(struct mlx5_wqe_ctrl_seg) +
-                       sizeof(struct mlx5_wqe_raddr_seg) +
-                       sizeof(struct mlx5_wqe_umr_ctrl_seg) +
-                       sizeof(struct mlx5_mkey_seg);
+                       max(sizeof(struct mlx5_wqe_raddr_seg),
+                           sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+                           sizeof(struct mlx5_mkey_seg));
                break;
 
        case IB_QPT_UD:
@@ -1036,7 +1038,7 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
        wq = MLX5_ADDR_OF(rqc, rqc, wq);
        MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
        MLX5_SET(wq, wq, end_padding_mode,
-                MLX5_GET64(qpc, qpc, end_padding_mode));
+                MLX5_GET(qpc, qpc, end_padding_mode));
        MLX5_SET(wq, wq, page_offset, MLX5_GET(qpc, qpc, page_offset));
        MLX5_SET(wq, wq, pd, MLX5_GET(qpc, qpc, pd));
        MLX5_SET64(wq, wq, dbr_addr, MLX5_GET64(qpc, qpc, dbr_addr));
@@ -1615,15 +1617,6 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
 
        if (pd) {
                dev = to_mdev(pd->device);
-       } else {
-               /* being cautious here */
-               if (init_attr->qp_type != IB_QPT_XRC_TGT &&
-                   init_attr->qp_type != MLX5_IB_QPT_REG_UMR) {
-                       pr_warn("%s: no PD for transport %s\n", __func__,
-                               ib_qp_type_str(init_attr->qp_type));
-                       return ERR_PTR(-EINVAL);
-               }
-               dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
 
                if (init_attr->qp_type == IB_QPT_RAW_PACKET) {
                        if (!pd->uobject) {
@@ -1634,6 +1627,15 @@ struct ib_qp *mlx5_ib_create_qp(struct ib_pd *pd,
                                return ERR_PTR(-EINVAL);
                        }
                }
+       } else {
+               /* being cautious here */
+               if (init_attr->qp_type != IB_QPT_XRC_TGT &&
+                   init_attr->qp_type != MLX5_IB_QPT_REG_UMR) {
+                       pr_warn("%s: no PD for transport %s\n", __func__,
+                               ib_qp_type_str(init_attr->qp_type));
+                       return ERR_PTR(-EINVAL);
+               }
+               dev = to_mdev(to_mxrcd(init_attr->xrcd)->ibxrcd.device);
        }
 
        switch (init_attr->qp_type) {
index 4659256cd95e698c3a9dad3c69407276e2117f29..3b2ddd64a371689e1533cb08c23007a4d6016b03 100644 (file)
@@ -75,7 +75,8 @@ static void mlx5_ib_srq_event(struct mlx5_core_srq *srq, enum mlx5_event type)
 
 static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
                           struct mlx5_create_srq_mbox_in **in,
-                          struct ib_udata *udata, int buf_size, int *inlen)
+                          struct ib_udata *udata, int buf_size, int *inlen,
+                          int is_xrc)
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
        struct mlx5_ib_create_srq ucmd = {};
@@ -87,13 +88,8 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
        int ncont;
        u32 offset;
        u32 uidx = MLX5_IB_DEFAULT_UIDX;
-       int drv_data = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr);
 
-       if (drv_data < 0)
-               return -EINVAL;
-
-       ucmdlen = (drv_data < sizeof(ucmd)) ?
-                 drv_data : sizeof(ucmd);
+       ucmdlen = min(udata->inlen, sizeof(ucmd));
 
        if (ib_copy_from_udata(&ucmd, udata, ucmdlen)) {
                mlx5_ib_dbg(dev, "failed copy udata\n");
@@ -103,15 +99,17 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
        if (ucmd.reserved0 || ucmd.reserved1)
                return -EINVAL;
 
-       if (drv_data > sizeof(ucmd) &&
+       if (udata->inlen > sizeof(ucmd) &&
            !ib_is_udata_cleared(udata, sizeof(ucmd),
-                                drv_data - sizeof(ucmd)))
+                                udata->inlen - sizeof(ucmd)))
                return -EINVAL;
 
-       err = get_srq_user_index(to_mucontext(pd->uobject->context),
-                                &ucmd, udata->inlen, &uidx);
-       if (err)
-               return err;
+       if (is_xrc) {
+               err = get_srq_user_index(to_mucontext(pd->uobject->context),
+                                        &ucmd, udata->inlen, &uidx);
+               if (err)
+                       return err;
+       }
 
        srq->wq_sig = !!(ucmd.flags & MLX5_SRQ_FLAG_SIGNATURE);
 
@@ -151,7 +149,8 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq,
        (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
        (*in)->ctx.pgoff_cqn = cpu_to_be32(offset << 26);
 
-       if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) {
+       if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
+            is_xrc){
                xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
                                     xrc_srq_context_entry);
                MLX5_SET(xrc_srqc, xsrqc, user_index, uidx);
@@ -170,7 +169,7 @@ err_umem:
 
 static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
                             struct mlx5_create_srq_mbox_in **in, int buf_size,
-                            int *inlen)
+                            int *inlen, int is_xrc)
 {
        int err;
        int i;
@@ -224,7 +223,8 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq,
 
        (*in)->ctx.log_pg_sz = page_shift - MLX5_ADAPTER_PAGE_SHIFT;
 
-       if (MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) {
+       if ((MLX5_CAP_GEN(dev->mdev, cqe_version) == MLX5_CQE_VERSION_V1) &&
+            is_xrc){
                xsrqc = MLX5_ADDR_OF(create_xrc_srq_in, *in,
                                     xrc_srq_context_entry);
                /* 0xffffff means we ask to work with cqe version 0 */
@@ -302,10 +302,14 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
                    desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
                    srq->msrq.max_avail_gather);
 
+       is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
+
        if (pd->uobject)
-               err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen);
+               err = create_srq_user(pd, srq, &in, udata, buf_size, &inlen,
+                                     is_xrc);
        else
-               err = create_srq_kernel(dev, srq, &in, buf_size, &inlen);
+               err = create_srq_kernel(dev, srq, &in, buf_size, &inlen,
+                                       is_xrc);
 
        if (err) {
                mlx5_ib_warn(dev, "create srq %s failed, err %d\n",
@@ -313,7 +317,6 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
                goto err_srq;
        }
 
-       is_xrc = (init_attr->srq_type == IB_SRQT_XRC);
        in->ctx.state_log_sz = ilog2(srq->msrq.max);
        flgs = ((srq->msrq.wqe_shift - 4) | (is_xrc << 5) | (srq->wq_sig << 7)) << 24;
        xrcdn = 0;
index 846dc97cf260658c5edb3edd95b9ccfd0b089edb..7964eba8e7ede7b8746027ab60595bf6f86e7279 100644 (file)
@@ -2,7 +2,6 @@ config INFINIBAND_NES
        tristate "NetEffect RNIC Driver"
        depends on PCI && INET && INFINIBAND
        select LIBCRC32C
-       select INET_LRO
        ---help---
          This is the RDMA Network Interface Card (RNIC) driver for
          NetEffect Ethernet Cluster Server Adapters.
index 4713dd7ed76432b6d11b042e6dfd24c268f82325..a1c6481d8038b5611736da10ee8ee0e30e05928f 100644 (file)
 #include <linux/moduleparam.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
 #include <linux/if_vlan.h>
-#include <linux/inet_lro.h>
 #include <linux/slab.h>
 
 #include "nes.h"
 
-static unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR;
-module_param(nes_lro_max_aggr, uint, 0444);
-MODULE_PARM_DESC(nes_lro_max_aggr, "NIC LRO max packet aggregation");
-
 static int wide_ppm_offset;
 module_param(wide_ppm_offset, int, 0644);
 MODULE_PARM_DESC(wide_ppm_offset, "Increase CX4 interface clock ppm offset, 0=100ppm (default), 1=300ppm");
@@ -1642,25 +1635,6 @@ static void nes_rq_wqes_timeout(unsigned long parm)
 }
 
 
-static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr,
-                              void **tcph, u64 *hdr_flags, void *priv)
-{
-       unsigned int ip_len;
-       struct iphdr *iph;
-       skb_reset_network_header(skb);
-       iph = ip_hdr(skb);
-       if (iph->protocol != IPPROTO_TCP)
-               return -1;
-       ip_len = ip_hdrlen(skb);
-       skb_set_transport_header(skb, ip_len);
-       *tcph = tcp_hdr(skb);
-
-       *hdr_flags = LRO_IPV4 | LRO_TCP;
-       *iphdr = iph;
-       return 0;
-}
-
-
 /**
  * nes_init_nic_qp
  */
@@ -1895,14 +1869,6 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
                return -ENOMEM;
        }
 
-       nesvnic->lro_mgr.max_aggr       = nes_lro_max_aggr;
-       nesvnic->lro_mgr.max_desc       = NES_MAX_LRO_DESCRIPTORS;
-       nesvnic->lro_mgr.lro_arr        = nesvnic->lro_desc;
-       nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr;
-       nesvnic->lro_mgr.features       = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
-       nesvnic->lro_mgr.dev            = netdev;
-       nesvnic->lro_mgr.ip_summed      = CHECKSUM_UNNECESSARY;
-       nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
        return 0;
 }
 
@@ -2809,13 +2775,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
        u16 pkt_type;
        u16 rqes_processed = 0;
        u8 sq_cqes = 0;
-       u8 nes_use_lro = 0;
 
        head = cq->cq_head;
        cq_size = cq->cq_size;
        cq->cqes_pending = 1;
-       if (nesvnic->netdev->features & NETIF_F_LRO)
-               nes_use_lro = 1;
        do {
                if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
                                NES_NIC_CQE_VALID) {
@@ -2950,10 +2913,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
 
                                        __vlan_hwaccel_put_tag(rx_skb, htons(ETH_P_8021Q), vlan_tag);
                                }
-                               if (nes_use_lro)
-                                       lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
-                               else
-                                       netif_receive_skb(rx_skb);
+                               napi_gro_receive(&nesvnic->napi, rx_skb);
 
 skip_rx_indicate0:
                                ;
@@ -2984,8 +2944,6 @@ skip_rx_indicate0:
 
        } while (1);
 
-       if (nes_use_lro)
-               lro_flush_all(&nesvnic->lro_mgr);
        if (sq_cqes) {
                barrier();
                /* restart the queue if it had been stopped */
index c9080208aad2ec4b022f915407d61479de40c41f..1b66ef1e9937133d98a0e41710790885e2160b08 100644 (file)
@@ -33,8 +33,6 @@
 #ifndef __NES_HW_H
 #define __NES_HW_H
 
-#include <linux/inet_lro.h>
-
 #define NES_PHY_TYPE_CX4       1
 #define NES_PHY_TYPE_1G        2
 #define NES_PHY_TYPE_ARGUS     4
@@ -1049,8 +1047,6 @@ struct nes_hw_tune_timer {
 #define NES_TIMER_ENABLE_LIMIT      4
 #define NES_MAX_LINK_INTERRUPTS     128
 #define NES_MAX_LINK_CHECK          200
-#define NES_MAX_LRO_DESCRIPTORS     32
-#define NES_LRO_MAX_AGGR            64
 
 struct nes_adapter {
        u64              fw_ver;
@@ -1263,9 +1259,6 @@ struct nes_vnic {
        u8  next_qp_nic_index;
        u8  of_device_registered;
        u8  rdma_enabled;
-       u32 lro_max_aggr;
-       struct net_lro_mgr lro_mgr;
-       struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
        struct timer_list event_timer;
        enum ib_event_type delayed_event;
        enum ib_event_type last_dispatched_event;
index 6a0bdfa0ce2e76f4741454a740426e0b891015bc..3ea9e055fdd37f27be5f8accad68aca74caa3780 100644 (file)
@@ -1085,9 +1085,6 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
        "Free 4Kpbls",
        "Free 256pbls",
        "Timer Inits",
-       "LRO aggregated",
-       "LRO flushed",
-       "LRO no_desc",
        "PAU CreateQPs",
        "PAU DestroyQPs",
 };
@@ -1302,9 +1299,6 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
        target_stat_values[++index] = nesadapter->free_4kpbl;
        target_stat_values[++index] = nesadapter->free_256pbl;
        target_stat_values[++index] = int_mod_timer_init;
-       target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated;
-       target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed;
-       target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc;
        target_stat_values[++index] = atomic_read(&pau_qps_created);
        target_stat_values[++index] = atomic_read(&pau_qps_destroyed);
 }
@@ -1709,7 +1703,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
                netdev->hw_features |= NETIF_F_TSO;
 
        netdev->features = netdev->hw_features | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX;
-       netdev->hw_features |= NETIF_F_LRO;
 
        nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
                        " nic_index = %d, logical_port = %d, mac_index = %d.\n",
index 040bb8b5cb15a65c34b15ab67c3c5fe14e27524c..12503f15fbd6b29830dee04d81f8fd4082319be2 100644 (file)
@@ -323,9 +323,6 @@ struct ocrdma_cq {
                         */
        u32 max_hw_cqe;
        bool phase_change;
-       bool deferred_arm, deferred_sol;
-       bool first_arm;
-
        spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization
                                                   * to cq polling
                                                   */
index 573849354cb94f4ef6f46397266518f9aaf7ef7b..f38743018cb454bca0e42440ebd27071e16a1ffe 100644 (file)
@@ -228,6 +228,11 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
 
        ocrdma_alloc_pd_pool(dev);
 
+       if (!ocrdma_alloc_stats_resources(dev)) {
+               pr_err("%s: stats resource allocation failed\n", __func__);
+               goto alloc_err;
+       }
+
        spin_lock_init(&dev->av_tbl.lock);
        spin_lock_init(&dev->flush_q_lock);
        return 0;
@@ -238,6 +243,7 @@ alloc_err:
 
 static void ocrdma_free_resources(struct ocrdma_dev *dev)
 {
+       ocrdma_release_stats_resources(dev);
        kfree(dev->stag_arr);
        kfree(dev->qp_tbl);
        kfree(dev->cq_tbl);
index 86c303a620c1660625ebb94f1b54e578856b26ff..255f774080a4aae08952df0374cdcb5a4063c8d1 100644 (file)
@@ -64,10 +64,11 @@ static int ocrdma_add_stat(char *start, char *pcur,
        return cpy_len;
 }
 
-static bool ocrdma_alloc_stats_mem(struct ocrdma_dev *dev)
+bool ocrdma_alloc_stats_resources(struct ocrdma_dev *dev)
 {
        struct stats_mem *mem = &dev->stats_mem;
 
+       mutex_init(&dev->stats_lock);
        /* Alloc mbox command mem*/
        mem->size = max_t(u32, sizeof(struct ocrdma_rdma_stats_req),
                        sizeof(struct ocrdma_rdma_stats_resp));
@@ -91,13 +92,14 @@ static bool ocrdma_alloc_stats_mem(struct ocrdma_dev *dev)
        return true;
 }
 
-static void ocrdma_release_stats_mem(struct ocrdma_dev *dev)
+void ocrdma_release_stats_resources(struct ocrdma_dev *dev)
 {
        struct stats_mem *mem = &dev->stats_mem;
 
        if (mem->va)
                dma_free_coherent(&dev->nic_info.pdev->dev, mem->size,
                                  mem->va, mem->pa);
+       mem->va = NULL;
        kfree(mem->debugfs_mem);
 }
 
@@ -838,15 +840,9 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
                                &dev->reset_stats, &ocrdma_dbg_ops))
                goto err;
 
-       /* Now create dma_mem for stats mbx command */
-       if (!ocrdma_alloc_stats_mem(dev))
-               goto err;
-
-       mutex_init(&dev->stats_lock);
 
        return;
 err:
-       ocrdma_release_stats_mem(dev);
        debugfs_remove_recursive(dev->dir);
        dev->dir = NULL;
 }
@@ -855,9 +851,7 @@ void ocrdma_rem_port_stats(struct ocrdma_dev *dev)
 {
        if (!dev->dir)
                return;
-       debugfs_remove(dev->dir);
-       mutex_destroy(&dev->stats_lock);
-       ocrdma_release_stats_mem(dev);
+       debugfs_remove_recursive(dev->dir);
 }
 
 void ocrdma_init_debugfs(void)
index c9e58d04c7b8d15c15c5d8ae4205c87cc3be521c..bba1fec4f11f265bd88f376dde4c9474634063e6 100644 (file)
@@ -65,6 +65,8 @@ enum OCRDMA_STATS_TYPE {
 
 void ocrdma_rem_debugfs(void);
 void ocrdma_init_debugfs(void);
+bool ocrdma_alloc_stats_resources(struct ocrdma_dev *dev);
+void ocrdma_release_stats_resources(struct ocrdma_dev *dev);
 void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
 void ocrdma_add_port_stats(struct ocrdma_dev *dev);
 int ocrdma_pma_counters(struct ocrdma_dev *dev,
index d4c687b548d8696e66752da16a28f03d2481cd60..12420e4ecf3da09d552ac117adcd85049ccd891b 100644 (file)
@@ -125,8 +125,8 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr,
                                        IB_DEVICE_SYS_IMAGE_GUID |
                                        IB_DEVICE_LOCAL_DMA_LKEY |
                                        IB_DEVICE_MEM_MGT_EXTENSIONS;
-       attr->max_sge = min(dev->attr.max_send_sge, dev->attr.max_srq_sge);
-       attr->max_sge_rd = 0;
+       attr->max_sge = dev->attr.max_send_sge;
+       attr->max_sge_rd = attr->max_sge;
        attr->max_cq = dev->attr.max_cq;
        attr->max_cqe = dev->attr.max_cqe;
        attr->max_mr = dev->attr.max_mr;
@@ -1094,7 +1094,6 @@ struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev,
        spin_lock_init(&cq->comp_handler_lock);
        INIT_LIST_HEAD(&cq->sq_head);
        INIT_LIST_HEAD(&cq->rq_head);
-       cq->first_arm = true;
 
        if (ib_ctx) {
                uctx = get_ocrdma_ucontext(ib_ctx);
@@ -2726,8 +2725,7 @@ static int ocrdma_update_ud_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe)
                OCRDMA_CQE_UD_STATUS_MASK) >> OCRDMA_CQE_UD_STATUS_SHIFT;
        ibwc->src_qp = le32_to_cpu(cqe->flags_status_srcqpn) &
                                                OCRDMA_CQE_SRCQP_MASK;
-       ibwc->pkey_index = le32_to_cpu(cqe->ud.rxlen_pkey) &
-                                               OCRDMA_CQE_PKEY_MASK;
+       ibwc->pkey_index = 0;
        ibwc->wc_flags = IB_WC_GRH;
        ibwc->byte_len = (le32_to_cpu(cqe->ud.rxlen_pkey) >>
                                        OCRDMA_CQE_UD_XFER_LEN_SHIFT);
@@ -2911,12 +2909,9 @@ expand_cqe:
        }
 stop_cqe:
        cq->getp = cur_getp;
-       if (cq->deferred_arm || polled_hw_cqes) {
-               ocrdma_ring_cq_db(dev, cq->id, cq->deferred_arm,
-                                 cq->deferred_sol, polled_hw_cqes);
-               cq->deferred_arm = false;
-               cq->deferred_sol = false;
-       }
+
+       if (polled_hw_cqes)
+               ocrdma_ring_cq_db(dev, cq->id, false, false, polled_hw_cqes);
 
        return i;
 }
@@ -3000,13 +2995,7 @@ int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)
        if (cq_flags & IB_CQ_SOLICITED)
                sol_needed = true;
 
-       if (cq->first_arm) {
-               ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
-               cq->first_arm = false;
-       }
-
-       cq->deferred_arm = true;
-       cq->deferred_sol = sol_needed;
+       ocrdma_ring_cq_db(dev, cq_id, arm_needed, sol_needed, 0);
        spin_unlock_irqrestore(&cq->cq_lock, flags);
 
        return 0;
index 6cdb4d23f78f99c0282be7d202083f5aa63091e7..a5bfbba6bbac0e9d918462ebb37d041608b9d321 100644 (file)
@@ -269,7 +269,6 @@ int usnic_ib_query_device(struct ib_device *ibdev,
        struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
        union ib_gid gid;
        struct ethtool_drvinfo info;
-       struct ethtool_cmd cmd;
        int qp_per_vf;
 
        usnic_dbg("\n");
@@ -278,7 +277,6 @@ int usnic_ib_query_device(struct ib_device *ibdev,
 
        mutex_lock(&us_ibdev->usdev_lock);
        us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
-       us_ibdev->netdev->ethtool_ops->get_settings(us_ibdev->netdev, &cmd);
        memset(props, 0, sizeof(*props));
        usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
                        &gid.raw[0]);
@@ -326,12 +324,12 @@ int usnic_ib_query_port(struct ib_device *ibdev, u8 port,
                                struct ib_port_attr *props)
 {
        struct usnic_ib_dev *us_ibdev = to_usdev(ibdev);
-       struct ethtool_cmd cmd;
+       struct ethtool_link_ksettings cmd;
 
        usnic_dbg("\n");
 
        mutex_lock(&us_ibdev->usdev_lock);
-       us_ibdev->netdev->ethtool_ops->get_settings(us_ibdev->netdev, &cmd);
+       __ethtool_get_link_ksettings(us_ibdev->netdev, &cmd);
        memset(props, 0, sizeof(*props));
 
        props->lid = 0;
@@ -355,8 +353,8 @@ int usnic_ib_query_port(struct ib_device *ibdev, u8 port,
        props->pkey_tbl_len = 1;
        props->bad_pkey_cntr = 0;
        props->qkey_viol_cntr = 0;
-       eth_speed_to_ib_speed(cmd.speed, &props->active_speed,
-                               &props->active_width);
+       eth_speed_to_ib_speed(cmd.base.speed, &props->active_speed,
+                             &props->active_width);
        props->max_mtu = IB_MTU_4096;
        props->active_mtu = iboe_get_mtu(us_ibdev->ufdev->mtu);
        /* Userspace will adjust for hdrs */
index 5ea0c14070d1f2d8af36a05c15206c63f406b97d..fa9c42ff1fb00963a47a71868ff96abb6e15189b 100644 (file)
@@ -245,8 +245,6 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
        skb_reset_mac_header(skb);
        skb_pull(skb, IPOIB_ENCAP_LEN);
 
-       skb->truesize = SKB_TRUESIZE(skb->len);
-
        ++dev->stats.rx_packets;
        dev->stats.rx_bytes += skb->len;
 
index 050dfa175d169dd3f77ee83767f1988062989891..25889311b1e9c8db412f784a77de5aa8ef0a29cb 100644 (file)
@@ -456,7 +456,10 @@ out_locked:
        return status;
 }
 
-static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
+/*
+ * Caller must hold 'priv->lock'
+ */
+static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ib_sa_multicast *multicast;
@@ -466,6 +469,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
        ib_sa_comp_mask comp_mask;
        int ret = 0;
 
+       if (!priv->broadcast ||
+           !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags))
+               return -EINVAL;
+
        ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw);
 
        rec.mgid     = mcast->mcmember.mgid;
@@ -525,20 +532,23 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
                        rec.join_state = 4;
 #endif
        }
+       spin_unlock_irq(&priv->lock);
 
        multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
                                         &rec, comp_mask, GFP_KERNEL,
                                         ipoib_mcast_join_complete, mcast);
+       spin_lock_irq(&priv->lock);
        if (IS_ERR(multicast)) {
                ret = PTR_ERR(multicast);
                ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
-               spin_lock_irq(&priv->lock);
                /* Requeue this join task with a backoff delay */
                __ipoib_mcast_schedule_join_thread(priv, mcast, 1);
                clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
                spin_unlock_irq(&priv->lock);
                complete(&mcast->done);
+               spin_lock_irq(&priv->lock);
        }
+       return 0;
 }
 
 void ipoib_mcast_join_task(struct work_struct *work)
@@ -620,9 +630,10 @@ void ipoib_mcast_join_task(struct work_struct *work)
                                /* Found the next unjoined group */
                                init_completion(&mcast->done);
                                set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
-                               spin_unlock_irq(&priv->lock);
-                               ipoib_mcast_join(dev, mcast);
-                               spin_lock_irq(&priv->lock);
+                               if (ipoib_mcast_join(dev, mcast)) {
+                                       spin_unlock_irq(&priv->lock);
+                                       return;
+                               }
                        } else if (!delay_until ||
                                 time_before(mcast->delay_until, delay_until))
                                delay_until = mcast->delay_until;
@@ -641,10 +652,9 @@ out:
        if (mcast) {
                init_completion(&mcast->done);
                set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+               ipoib_mcast_join(dev, mcast);
        }
        spin_unlock_irq(&priv->lock);
-       if (mcast)
-               ipoib_mcast_join(dev, mcast);
 }
 
 int ipoib_mcast_start_thread(struct net_device *dev)
index 6727954ab74be9338e9c3d46e12a55fa3db7a6e7..e8a84d12b7fffe812cd329a88da26f6922c219af 100644 (file)
@@ -1207,7 +1207,6 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
 #else
 static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
 static void xpad_led_disconnect(struct usb_xpad *xpad) { }
-static void xpad_identify_controller(struct usb_xpad *xpad) { }
 #endif
 
 static int xpad_start_input(struct usb_xpad *xpad)
index 4d446d5085aad9b110ca7ecb05a3167f859ef12c..c01a1d648f9f087df57aafedf7eb3e56b4df2b8e 100644 (file)
@@ -235,7 +235,7 @@ struct adp5589_kpad {
        unsigned short gpimapsize;
        unsigned extend_cfg;
        bool is_adp5585;
-       bool adp5585_support_row5;
+       bool support_row5;
 #ifdef CONFIG_GPIOLIB
        unsigned char gpiomap[ADP5589_MAXGPIO];
        bool export_gpio;
@@ -485,7 +485,7 @@ static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,
        if (kpad->extend_cfg & C4_EXTEND_CFG)
                pin_used[kpad->var->c4_extend_cfg] = true;
 
-       if (!kpad->adp5585_support_row5)
+       if (!kpad->support_row5)
                pin_used[5] = true;
 
        for (i = 0; i < kpad->var->maxgpio; i++)
@@ -884,12 +884,13 @@ static int adp5589_probe(struct i2c_client *client,
 
        switch (id->driver_data) {
        case ADP5585_02:
-               kpad->adp5585_support_row5 = true;
+               kpad->support_row5 = true;
        case ADP5585_01:
                kpad->is_adp5585 = true;
                kpad->var = &const_adp5585;
                break;
        case ADP5589:
+               kpad->support_row5 = true;
                kpad->var = &const_adp5589;
                break;
        }
index 378db10001df5067adcf4fe5bfc2b38e42098574..4401be225d64b28b8ffa798ba71cce07c8a81282 100644 (file)
@@ -304,8 +304,10 @@ static int cap11xx_init_leds(struct device *dev,
                led->cdev.brightness = LED_OFF;
 
                error = of_property_read_u32(child, "reg", &reg);
-               if (error != 0 || reg >= num_leds)
+               if (error != 0 || reg >= num_leds) {
+                       of_node_put(child);
                        return -EINVAL;
+               }
 
                led->reg = reg;
                led->priv = priv;
@@ -313,8 +315,10 @@ static int cap11xx_init_leds(struct device *dev,
                INIT_WORK(&led->work, cap11xx_led_work);
 
                error = devm_led_classdev_register(dev, &led->cdev);
-               if (error)
+               if (error) {
+                       of_node_put(child);
                        return error;
+               }
 
                priv->num_leds++;
                led++;
index d6d16fa782815481e04609771b09b32e862ce679..1f2337abcf2f333de7b10cc449aaad56aadd5369 100644 (file)
@@ -733,7 +733,7 @@ config INPUT_XEN_KBDDEV_FRONTEND
          module will be called xen-kbdfront.
 
 config INPUT_SIRFSOC_ONKEY
-       bool "CSR SiRFSoC power on/off/suspend key support"
+       tristate "CSR SiRFSoC power on/off/suspend key support"
        depends on ARCH_SIRF && OF
        default y
        help
index 9d5b89befe6fb059e593c6fe1e6265f0b3819199..ed7237f1953966c378c3822faa9a40f7c6a044dd 100644 (file)
@@ -101,7 +101,7 @@ static void sirfsoc_pwrc_close(struct input_dev *input)
 static const struct of_device_id sirfsoc_pwrc_of_match[] = {
        { .compatible = "sirf,prima2-pwrc" },
        {},
-}
+};
 MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
 
 static int sirfsoc_pwrc_probe(struct platform_device *pdev)
index e272f06258cefb3c2119058298ad10f2cb77b7ce..a3f0f5a47490e936e31b45594861d692503429b1 100644 (file)
@@ -458,8 +458,6 @@ int vmmouse_init(struct psmouse *psmouse)
        priv->abs_dev = abs_dev;
        psmouse->private = priv;
 
-       input_set_capability(rel_dev, EV_REL, REL_WHEEL);
-
        /* Set up and register absolute device */
        snprintf(priv->phys, sizeof(priv->phys), "%s/input1",
                 psmouse->ps2dev.serio->phys);
@@ -475,10 +473,6 @@ int vmmouse_init(struct psmouse *psmouse)
        abs_dev->id.version = psmouse->model;
        abs_dev->dev.parent = &psmouse->ps2dev.serio->dev;
 
-       error = input_register_device(priv->abs_dev);
-       if (error)
-               goto init_fail;
-
        /* Set absolute device capabilities */
        input_set_capability(abs_dev, EV_KEY, BTN_LEFT);
        input_set_capability(abs_dev, EV_KEY, BTN_RIGHT);
@@ -488,6 +482,13 @@ int vmmouse_init(struct psmouse *psmouse)
        input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0);
        input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0);
 
+       error = input_register_device(priv->abs_dev);
+       if (error)
+               goto init_fail;
+
+       /* Add wheel capability to the relative device */
+       input_set_capability(rel_dev, EV_REL, REL_WHEEL);
+
        psmouse->protocol_handler = vmmouse_process_byte;
        psmouse->disconnect = vmmouse_disconnect;
        psmouse->reconnect = vmmouse_reconnect;
index 8f828975ab10b03746e700dd26dce1cb03d2c17e..1ca7f551e2dabe73896f780ec53e4c6735d13019 100644 (file)
@@ -134,7 +134,7 @@ static void serio_find_driver(struct serio *serio)
        int error;
 
        error = device_attach(&serio->dev);
-       if (error < 0)
+       if (error < 0 && error != -EPROBE_DEFER)
                dev_warn(&serio->dev,
                         "device_attach() failed for %s (%s), error: %d\n",
                         serio->phys, serio->name, error);
index 5d4903a402cc6a5f183010ded6e7af17c1136a49..69828d015d45ffa4747368e79f6fa5f47108c0c9 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 0b0f8c17f3f7e0f4df1e69144d693b46741f4025..23fbe382da8b420791a1fec28962454132d4e7ef 100644 (file)
@@ -822,16 +822,22 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
        int error;
 
        error = device_property_read_u32(dev, "threshold", &val);
-       if (!error)
-               reg_addr->reg_threshold = val;
+       if (!error) {
+               edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val);
+               tsdata->threshold = val;
+       }
 
        error = device_property_read_u32(dev, "gain", &val);
-       if (!error)
-               reg_addr->reg_gain = val;
+       if (!error) {
+               edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val);
+               tsdata->gain = val;
+       }
 
        error = device_property_read_u32(dev, "offset", &val);
-       if (!error)
-               reg_addr->reg_offset = val;
+       if (!error) {
+               edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
+               tsdata->offset = val;
+       }
 }
 
 static void
index e5e223938eecc9f013e33977b1de50bbb3cfae3d..374c129219ef0c48c8ff3004662c413d78ad2b4c 100644 (file)
@@ -114,6 +114,7 @@ struct kmem_cache *amd_iommu_irq_cache;
 
 static void update_domain(struct protection_domain *domain);
 static int protection_domain_init(struct protection_domain *domain);
+static void detach_device(struct device *dev);
 
 /*
  * For dynamic growth the aperture size is split into ranges of 128MB of
@@ -384,6 +385,9 @@ static void iommu_uninit_device(struct device *dev)
        if (!dev_data)
                return;
 
+       if (dev_data->domain)
+               detach_device(dev);
+
        iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev,
                            dev);
 
index 013bdfff2d4d023c30a57baf4c833788bfd7dbee..bf4959f4225bd35c356c49172e0f978e0c81166f 100644 (file)
@@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void);
 static int __init iommu_go_to_state(enum iommu_init_state state);
 static void init_device_table_dma(void);
 
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+                                   u8 bank, u8 cntr, u8 fxn,
+                                   u64 *value, bool is_write);
+
 static inline void update_last_devid(u16 devid)
 {
        if (devid > amd_iommu_last_bdf)
@@ -1015,6 +1019,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
        pci_write_config_dword(iommu->dev, 0xf0, 0x90);
 }
 
+/*
+ * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission)
+ * Workaround:
+ *     BIOS should enable ATS write permission check by setting
+ *     L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b
+ */
+static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu)
+{
+       u32 value;
+
+       if ((boot_cpu_data.x86 != 0x15) ||
+           (boot_cpu_data.x86_model < 0x30) ||
+           (boot_cpu_data.x86_model > 0x3f))
+               return;
+
+       /* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */
+       value = iommu_read_l2(iommu, 0x47);
+
+       if (value & BIT(0))
+               return;
+
+       /* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */
+       iommu_write_l2(iommu, 0x47, value | BIT(0));
+
+       pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n",
+               dev_name(&iommu->dev->dev));
+}
+
 /*
  * This function clues the initialization function for one IOMMU
  * together and also allocates the command buffer and programs the
@@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu)
        amd_iommu_pc_present = true;
 
        /* Check if the performance counters can be written to */
-       if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) ||
-           (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) ||
+       if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) ||
+           (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) ||
            (val != val2)) {
                pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n");
                amd_iommu_pc_present = false;
@@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
        }
 
        amd_iommu_erratum_746_workaround(iommu);
+       amd_iommu_ats_write_check_workaround(iommu);
 
        iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu,
                                               amd_iommu_groups, "ivhd%d",
@@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid)
 }
 EXPORT_SYMBOL(amd_iommu_pc_get_max_counters);
 
-int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu,
+                                   u8 bank, u8 cntr, u8 fxn,
                                    u64 *value, bool is_write)
 {
-       struct amd_iommu *iommu;
        u32 offset;
        u32 max_offset_lim;
 
-       /* Make sure the IOMMU PC resource is available */
-       if (!amd_iommu_pc_present)
-               return -ENODEV;
-
-       /* Locate the iommu associated with the device ID */
-       iommu = amd_iommu_rlookup_table[devid];
-
        /* Check for valid iommu and pc register indexing */
-       if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7)))
+       if (WARN_ON((fxn > 0x28) || (fxn & 7)))
                return -ENODEV;
 
        offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn);
@@ -2322,3 +2348,16 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
        return 0;
 }
 EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val);
+
+int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
+                                   u64 *value, bool is_write)
+{
+       struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
+
+       /* Make sure the IOMMU PC resource is available */
+       if (!amd_iommu_pc_present || iommu == NULL)
+               return -ENODEV;
+
+       return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn,
+                                       value, is_write);
+}
index 62a400c5ba0614fde00d18ad2207b430d99433ee..8ffd7568fc919e32b97354b2777db21be263d37f 100644 (file)
@@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
        /* Only care about add/remove events for physical functions */
        if (pdev->is_virtfn)
                return NOTIFY_DONE;
-       if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
+       if (action != BUS_NOTIFY_ADD_DEVICE &&
+           action != BUS_NOTIFY_REMOVED_DEVICE)
                return NOTIFY_DONE;
 
        info = dmar_alloc_pci_notify_info(pdev, action);
@@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
        down_write(&dmar_global_lock);
        if (action == BUS_NOTIFY_ADD_DEVICE)
                dmar_pci_bus_add_dev(info);
-       else if (action == BUS_NOTIFY_DEL_DEVICE)
+       else if (action == BUS_NOTIFY_REMOVED_DEVICE)
                dmar_pci_bus_del_dev(info);
        up_write(&dmar_global_lock);
 
@@ -1353,7 +1354,7 @@ void dmar_disable_qi(struct intel_iommu *iommu)
 
        raw_spin_lock_irqsave(&iommu->register_lock, flags);
 
-       sts =  dmar_readq(iommu->reg + DMAR_GSTS_REG);
+       sts =  readl(iommu->reg + DMAR_GSTS_REG);
        if (!(sts & DMA_GSTS_QIES))
                goto end;
 
index 986a53e3eb96b4bb56faedfdb36b4bd658aacb99..a2e1b7f14df29cc78b625ec88455438d0fa1fe07 100644 (file)
@@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
                                rmrru->devices_cnt);
                        if(ret < 0)
                                return ret;
-               } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+               } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
                        dmar_remove_dev_scope(info, rmrr->segment,
                                rmrru->devices, rmrru->devices_cnt);
                }
@@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
                                break;
                        else if(ret < 0)
                                return ret;
-               } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+               } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
                        if (dmar_remove_dev_scope(info, atsr->segment,
                                        atsru->devices, atsru->devices_cnt))
                                break;
index 50464833d0b84732a4d397cee8b73ed43a721712..d9939fa9b58887567d1fe8a7a94c7e5f1452cdf0 100644 (file)
@@ -249,12 +249,30 @@ static void intel_flush_pasid_dev(struct intel_svm *svm, struct intel_svm_dev *s
 static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
 {
        struct intel_svm *svm = container_of(mn, struct intel_svm, notifier);
+       struct intel_svm_dev *sdev;
 
+       /* This might end up being called from exit_mmap(), *before* the page
+        * tables are cleared. And __mmu_notifier_release() will delete us from
+        * the list of notifiers so that our invalidate_range() callback doesn't
+        * get called when the page tables are cleared. So we need to protect
+        * against hardware accessing those page tables.
+        *
+        * We do it by clearing the entry in the PASID table and then flushing
+        * the IOTLB and the PASID table caches. This might upset hardware;
+        * perhaps we'll want to point the PASID to a dummy PGD (like the zero
+        * page) so that we end up taking a fault that the hardware really
+        * *has* to handle gracefully without affecting other processes.
+        */
        svm->iommu->pasid_table[svm->pasid].val = 0;
+       wmb();
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdev, &svm->devs, list) {
+               intel_flush_pasid_dev(svm, sdev, svm->pasid);
+               intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm);
+       }
+       rcu_read_unlock();
 
-       /* There's no need to do any flush because we can't get here if there
-        * are any devices left anyway. */
-       WARN_ON(!list_empty(&svm->devs));
 }
 
 static const struct mmu_notifier_ops intel_mmuops = {
@@ -379,7 +397,6 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_
                                goto out;
                        }
                        iommu->pasid_table[svm->pasid].val = (u64)__pa(mm->pgd) | 1;
-                       mm = NULL;
                } else
                        iommu->pasid_table[svm->pasid].val = (u64)__pa(init_mm.pgd) | 1 | (1ULL << 11);
                wmb();
@@ -442,11 +459,11 @@ int intel_svm_unbind_mm(struct device *dev, int pasid)
                                kfree_rcu(sdev, rcu);
 
                                if (list_empty(&svm->devs)) {
-                                       mmu_notifier_unregister(&svm->notifier, svm->mm);
 
                                        idr_remove(&svm->iommu->pasid_idr, svm->pasid);
                                        if (svm->mm)
-                                               mmput(svm->mm);
+                                               mmu_notifier_unregister(&svm->notifier, svm->mm);
+
                                        /* We mandate that no page faults may be outstanding
                                         * for the PASID when intel_svm_unbind_mm() is called.
                                         * If that is not obeyed, subtle errors will happen.
@@ -507,6 +524,10 @@ static irqreturn_t prq_event_thread(int irq, void *d)
        struct intel_svm *svm = NULL;
        int head, tail, handled = 0;
 
+       /* Clear PPR bit before reading head/tail registers, to
+        * ensure that we get a new interrupt if needed. */
+       writel(DMA_PRS_PPR, iommu->reg + DMAR_PRS_REG);
+
        tail = dmar_readq(iommu->reg + DMAR_PQT_REG) & PRQ_RING_MASK;
        head = dmar_readq(iommu->reg + DMAR_PQH_REG) & PRQ_RING_MASK;
        while (head != tail) {
@@ -551,6 +572,9 @@ static irqreturn_t prq_event_thread(int irq, void *d)
                 * any faults on kernel addresses. */
                if (!svm->mm)
                        goto bad_req;
+               /* If the mm is already defunct, don't handle faults. */
+               if (!atomic_inc_not_zero(&svm->mm->mm_users))
+                       goto bad_req;
                down_read(&svm->mm->mmap_sem);
                vma = find_extend_vma(svm->mm, address);
                if (!vma || address < vma->vm_start)
@@ -567,6 +591,7 @@ static irqreturn_t prq_event_thread(int irq, void *d)
                result = QI_RESP_SUCCESS;
        invalid:
                up_read(&svm->mm->mmap_sem);
+               mmput(svm->mm);
        bad_req:
                /* Accounting for major/minor faults? */
                rcu_read_lock();
index c12ba4516df25b7201731b44ef4a175c78f2d0e0..ac596928f6b40af32e9c44ecf388ebf7ed4b10ed 100644 (file)
@@ -629,7 +629,7 @@ static void iommu_disable_irq_remapping(struct intel_iommu *iommu)
 
        raw_spin_lock_irqsave(&iommu->register_lock, flags);
 
-       sts = dmar_readq(iommu->reg + DMAR_GSTS_REG);
+       sts = readl(iommu->reg + DMAR_GSTS_REG);
        if (!(sts & DMA_GSTS_IRES))
                goto end;
 
index 3447549fcc9306a37e7695d27e06589d45d3d0e4..43dfd15c1dd22e4e18b1dbb37e1b3da811b0ceaf 100644 (file)
@@ -66,7 +66,10 @@ struct its_node {
        unsigned long           phys_base;
        struct its_cmd_block    *cmd_base;
        struct its_cmd_block    *cmd_write;
-       void                    *tables[GITS_BASER_NR_REGS];
+       struct {
+               void            *base;
+               u32             order;
+       } tables[GITS_BASER_NR_REGS];
        struct its_collection   *collections;
        struct list_head        its_device_list;
        u64                     flags;
@@ -75,6 +78,9 @@ struct its_node {
 
 #define ITS_ITT_ALIGN          SZ_256
 
+/* Convert page order to size in bytes */
+#define PAGE_ORDER_TO_SIZE(o)  (PAGE_SIZE << (o))
+
 struct event_lpi_map {
        unsigned long           *lpi_map;
        u16                     *col_map;
@@ -597,11 +603,6 @@ static void its_unmask_irq(struct irq_data *d)
        lpi_set_config(d, true);
 }
 
-static void its_eoi_irq(struct irq_data *d)
-{
-       gic_write_eoir(d->hwirq);
-}
-
 static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
 {
@@ -638,7 +639,7 @@ static struct irq_chip its_irq_chip = {
        .name                   = "ITS",
        .irq_mask               = its_mask_irq,
        .irq_unmask             = its_unmask_irq,
-       .irq_eoi                = its_eoi_irq,
+       .irq_eoi                = irq_chip_eoi_parent,
        .irq_set_affinity       = its_set_affinity,
        .irq_compose_msi_msg    = its_irq_compose_msi_msg,
 };
@@ -807,9 +808,10 @@ static void its_free_tables(struct its_node *its)
        int i;
 
        for (i = 0; i < GITS_BASER_NR_REGS; i++) {
-               if (its->tables[i]) {
-                       free_page((unsigned long)its->tables[i]);
-                       its->tables[i] = NULL;
+               if (its->tables[i].base) {
+                       free_pages((unsigned long)its->tables[i].base,
+                                  its->tables[i].order);
+                       its->tables[i].base = NULL;
                }
        }
 }
@@ -842,7 +844,6 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
                u64 type = GITS_BASER_TYPE(val);
                u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
                int order = get_order(psz);
-               int alloc_size;
                int alloc_pages;
                u64 tmp;
                void *base;
@@ -874,9 +875,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
                        }
                }
 
-               alloc_size = (1 << order) * PAGE_SIZE;
 retry_alloc_baser:
-               alloc_pages = (alloc_size / psz);
+               alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz);
                if (alloc_pages > GITS_BASER_PAGES_MAX) {
                        alloc_pages = GITS_BASER_PAGES_MAX;
                        order = get_order(GITS_BASER_PAGES_MAX * psz);
@@ -890,7 +890,8 @@ retry_alloc_baser:
                        goto out_free;
                }
 
-               its->tables[i] = base;
+               its->tables[i].base = base;
+               its->tables[i].order = order;
 
 retry_baser:
                val = (virt_to_phys(base)                                |
@@ -928,7 +929,7 @@ retry_baser:
                        shr = tmp & GITS_BASER_SHAREABILITY_MASK;
                        if (!shr) {
                                cache = GITS_BASER_nC;
-                               __flush_dcache_area(base, alloc_size);
+                               __flush_dcache_area(base, PAGE_ORDER_TO_SIZE(order));
                        }
                        goto retry_baser;
                }
@@ -940,7 +941,7 @@ retry_baser:
                         * something is horribly wrong...
                         */
                        free_pages((unsigned long)base, order);
-                       its->tables[i] = NULL;
+                       its->tables[i].base = NULL;
 
                        switch (psz) {
                        case SZ_16K:
@@ -961,7 +962,7 @@ retry_baser:
                }
 
                pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
-                       (int)(alloc_size / entry_size),
+                       (int)(PAGE_ORDER_TO_SIZE(order) / entry_size),
                        its_base_type_string[type],
                        (unsigned long)virt_to_phys(base),
                        psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
index 911758c056c14152d5a248110c14f35bd48e9b78..8f9ebf714e2bbc154d7a045d27920f6c95f7cce6 100644 (file)
@@ -384,9 +384,6 @@ static struct irq_chip gic_chip = {
        .irq_unmask             = gic_unmask_irq,
        .irq_eoi                = gic_eoi_irq,
        .irq_set_type           = gic_set_type,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       = gic_set_affinity,
-#endif
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .flags                  = IRQCHIP_SET_TYPE_MASKED |
@@ -400,9 +397,6 @@ static struct irq_chip gic_eoimode1_chip = {
        .irq_unmask             = gic_unmask_irq,
        .irq_eoi                = gic_eoimode1_eoi_irq,
        .irq_set_type           = gic_set_type,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       = gic_set_affinity,
-#endif
        .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
        .irq_set_vcpu_affinity  = gic_irq_set_vcpu_affinity,
@@ -443,7 +437,7 @@ static void gic_cpu_if_up(struct gic_chip_data *gic)
        u32 bypass = 0;
        u32 mode = 0;
 
-       if (static_key_true(&supports_deactivate))
+       if (gic == &gic_data[0] && static_key_true(&supports_deactivate))
                mode = GIC_CPU_CTRL_EOImodeNS;
 
        /*
@@ -1039,6 +1033,11 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
                gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
        }
 
+#ifdef CONFIG_SMP
+       if (gic_nr == 0)
+               gic->chip.irq_set_affinity = gic_set_affinity;
+#endif
+
 #ifdef CONFIG_GIC_NON_BANKED
        if (percpu_offset) { /* Frankein-GIC without banked registers... */
                unsigned int cpu;
index 0704362f4c824c6ba2b87e42353f0481bcff36e5..376b28074e0d8937c43036b647de218ef45c14b7 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/of_irq.h>
 
 #include <asm/exception.h>
-#include <asm/mach/irq.h>
 
 #define SUN4I_IRQ_VECTOR_REG           0x00
 #define SUN4I_IRQ_PROTECTION_REG       0x08
index 2a506fe0c8a4500a16e83b1aba70a6ed2d192185..d1f8ab915b15cc69b5fc9564777d413dad0f8318 100644 (file)
@@ -373,13 +373,7 @@ static void gigaset_freecshw(struct cardstate *cs)
 
 static void gigaset_device_release(struct device *dev)
 {
-       struct cardstate *cs = dev_get_drvdata(dev);
-
-       if (!cs)
-               return;
-       dev_set_drvdata(dev, NULL);
-       kfree(cs->hw.ser);
-       cs->hw.ser = NULL;
+       kfree(container_of(dev, struct ser_cardstate, dev.dev));
 }
 
 /*
@@ -408,7 +402,6 @@ static int gigaset_initcshw(struct cardstate *cs)
                cs->hw.ser = NULL;
                return rc;
        }
-       dev_set_drvdata(&cs->hw.ser->dev.dev, cs);
 
        tasklet_init(&cs->write_tasklet,
                     gigaset_modem_fill, (unsigned long) cs);
index b5226af6ddecced751dfaf452d95f3b62fede822..576b7b4a32787017e44ed3f3ebf6f40dcc6a965c 100644 (file)
@@ -192,8 +192,6 @@ static diva_os_spin_lock_t dbg_q_lock;
 static diva_os_spin_lock_t dbg_adapter_lock;
 static int                 dbg_q_busy;
 static volatile dword      dbg_sequence;
-static dword               start_sec;
-static dword               start_usec;
 
 /*
   INTERFACE:
@@ -215,8 +213,6 @@ int diva_maint_init(byte *base, unsigned long length, int do_init) {
 
        dbg_base = base;
 
-       diva_os_get_time(&start_sec, &start_usec);
-
        *(dword *)base  = (dword)DBG_MAGIC; /* Store Magic */
        base   += sizeof(dword);
        length -= sizeof(dword);
index 48db08d0bb3dfe9ba4834752a4b0b7da8db0a654..0de29b7b712f8d8d0cd92792f76f20b828b3d016 100644 (file)
@@ -45,7 +45,6 @@ char *DRIVERRELEASE_MNT = "2.0";
 
 static wait_queue_head_t msgwaitq;
 static unsigned long opened;
-static struct timeval start_time;
 
 extern int mntfunc_init(int *, void **, unsigned long);
 extern void mntfunc_finit(void);
@@ -88,28 +87,12 @@ int diva_os_copy_from_user(void *os_handle, void *dst, const void __user *src,
  */
 void diva_os_get_time(dword *sec, dword *usec)
 {
-       struct timeval tv;
-
-       do_gettimeofday(&tv);
-
-       if (tv.tv_sec > start_time.tv_sec) {
-               if (start_time.tv_usec > tv.tv_usec) {
-                       tv.tv_sec--;
-                       tv.tv_usec += 1000000;
-               }
-               *sec = (dword) (tv.tv_sec - start_time.tv_sec);
-               *usec = (dword) (tv.tv_usec - start_time.tv_usec);
-       } else if (tv.tv_sec == start_time.tv_sec) {
-               *sec = 0;
-               if (start_time.tv_usec < tv.tv_usec) {
-                       *usec = (dword) (tv.tv_usec - start_time.tv_usec);
-               } else {
-                       *usec = 0;
-               }
-       } else {
-               *sec = (dword) tv.tv_sec;
-               *usec = (dword) tv.tv_usec;
-       }
+       struct timespec64 time;
+
+       ktime_get_ts64(&time);
+
+       *sec = (dword) time.tv_sec;
+       *usec = (dword) (time.tv_nsec / NSEC_PER_USEC);
 }
 
 /*
@@ -213,7 +196,6 @@ static int __init maint_init(void)
        int ret = 0;
        void *buffer = NULL;
 
-       do_gettimeofday(&start_time);
        init_waitqueue_head(&msgwaitq);
 
        printk(KERN_INFO "%s\n", DRIVERNAME);
index 8e2944784e0004e4fc933d691607c4e822c3bf66..afde4edef9ae895fa009fb5ad7305cc13af2c22e 100644 (file)
@@ -392,7 +392,7 @@ read_dma(struct tiger_ch *bc, u32 idx, int cnt)
        }
        stat = bchannel_get_rxbuf(&bc->bch, cnt);
        /* only transparent use the count here, HDLC overun is detected later */
-       if (stat == ENOMEM) {
+       if (stat == -ENOMEM) {
                pr_warning("%s.B%d: No memory for %d bytes\n",
                           card->name, bc->bch.nr, cnt);
                return;
index 33224cb91c5bb98ac7e464b4202dacbac71671c9..9f6acd5d1d2e9359730ad595f92d3e902bc40d17 100644 (file)
@@ -572,11 +572,13 @@ int nvm_register(struct request_queue *q, char *disk_name,
                }
        }
 
-       ret = nvm_get_sysblock(dev, &dev->sb);
-       if (!ret)
-               pr_err("nvm: device not initialized.\n");
-       else if (ret < 0)
-               pr_err("nvm: err (%d) on device initialization\n", ret);
+       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
+               ret = nvm_get_sysblock(dev, &dev->sb);
+               if (!ret)
+                       pr_err("nvm: device not initialized.\n");
+               else if (ret < 0)
+                       pr_err("nvm: err (%d) on device initialization\n", ret);
+       }
 
        /* register device with a supported media manager */
        down_write(&nvm_lock);
@@ -1055,9 +1057,11 @@ static long __nvm_ioctl_dev_init(struct nvm_ioctl_dev_init *init)
        strncpy(info.mmtype, init->mmtype, NVM_MMTYPE_LEN);
        info.fs_ppa.ppa = -1;
 
-       ret = nvm_init_sysblock(dev, &info);
-       if (ret)
-               return ret;
+       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) {
+               ret = nvm_init_sysblock(dev, &info);
+               if (ret)
+                       return ret;
+       }
 
        memcpy(&dev->sb, &info, sizeof(struct nvm_sb_info));
 
@@ -1117,7 +1121,10 @@ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg)
                dev->mt = NULL;
        }
 
-       return nvm_dev_factory(dev, fact.flags);
+       if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT)
+               return nvm_dev_factory(dev, fact.flags);
+
+       return 0;
 }
 
 static long nvm_ctl_ioctl(struct file *file, uint cmd, unsigned long arg)
index d8c75958ced346d5aede0398a8f4b50bd96fa749..307db1ea22defbcbddcfdc3d63cfe86bda43fa0c 100644 (file)
@@ -300,8 +300,10 @@ static int rrpc_move_valid_pages(struct rrpc *rrpc, struct rrpc_block *rblk)
        }
 
        page = mempool_alloc(rrpc->page_pool, GFP_NOIO);
-       if (!page)
+       if (!page) {
+               bio_put(bio);
                return -ENOMEM;
+       }
 
        while ((slot = find_first_zero_bit(rblk->invalid_pages,
                                            nr_pgs_per_blk)) < nr_pgs_per_blk) {
index ef13ac7700c80e352b8db97fed8c1e38ba504cc9..f7b37336353fd56771f776ed420ff07521f2b6d5 100644 (file)
@@ -174,8 +174,7 @@ static inline sector_t rrpc_get_sector(sector_t laddr)
 static inline int request_intersects(struct rrpc_inflight_rq *r,
                                sector_t laddr_start, sector_t laddr_end)
 {
-       return (laddr_end >= r->l_start && laddr_end <= r->l_end) &&
-               (laddr_start >= r->l_start && laddr_start <= r->l_end);
+       return (laddr_end >= r->l_start) && (laddr_start <= r->l_end);
 }
 
 static int __rrpc_lock_laddr(struct rrpc *rrpc, sector_t laddr,
@@ -184,6 +183,8 @@ static int __rrpc_lock_laddr(struct rrpc *rrpc, sector_t laddr,
        sector_t laddr_end = laddr + pages - 1;
        struct rrpc_inflight_rq *rtmp;
 
+       WARN_ON(irqs_disabled());
+
        spin_lock_irq(&rrpc->inflights.lock);
        list_for_each_entry(rtmp, &rrpc->inflights.reqs, list) {
                if (unlikely(request_intersects(rtmp, laddr, laddr_end))) {
index 546d05f4358a7c452ee80366b3ae782e685fd7ef..b2bbe8659beda5ad8182b5f4ff7bbefeda970459 100644 (file)
@@ -81,6 +81,7 @@ config STI_MBOX
 config MAILBOX_TEST
        tristate "Mailbox Test Client"
        depends on OF
+       depends on HAS_IOMEM
        help
          Test client to help with testing new Controller driver
          implementations.
index 45d85aea9955404d0c4567f33863e0e3f500674f..8f779a1ec99c4b248c9721fceef19b579432539b 100644 (file)
@@ -81,16 +81,10 @@ static struct mbox_controller pcc_mbox_ctrl = {};
  */
 static struct mbox_chan *get_pcc_channel(int id)
 {
-       struct mbox_chan *pcc_chan;
-
        if (id < 0 || id > pcc_mbox_ctrl.num_chans)
                return ERR_PTR(-ENOENT);
 
-       pcc_chan = (struct mbox_chan *)
-               (unsigned long) pcc_mbox_channels +
-               (id * sizeof(*pcc_chan));
-
-       return pcc_chan;
+       return &pcc_mbox_channels[id];
 }
 
 /**
index 4f22e919787aba1bcab7b8f6799a3c22a6b7ce28..d80cce499a56e595d1f2679170124ca5fc620315 100644 (file)
@@ -210,10 +210,6 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
        struct block_device *bdev;
        struct mddev *mddev = bitmap->mddev;
        struct bitmap_storage *store = &bitmap->storage;
-       int node_offset = 0;
-
-       if (mddev_is_clustered(bitmap->mddev))
-               node_offset = bitmap->cluster_slot * store->file_pages;
 
        while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
                int size = PAGE_SIZE;
index 5df40480228b7a26e3c73ac78e963ce47ed25448..dd834927bc66e87bf4ec433bc96889068d3bbb82 100644 (file)
@@ -1191,6 +1191,8 @@ static void dm_unprep_request(struct request *rq)
 
        if (clone)
                free_rq_clone(clone);
+       else if (!tio->md->queue->mq_ops)
+               free_rq_tio(tio);
 }
 
 /*
index 4a8e15058e8b56a8a9d89d9f0db50135df44c6d3..685aa2d77e2526935f8f2f416ad8d8681b6c7b14 100644 (file)
@@ -170,7 +170,7 @@ static void add_sector(struct faulty_conf *conf, sector_t start, int mode)
                conf->nfaults = n+1;
 }
 
-static void make_request(struct mddev *mddev, struct bio *bio)
+static void faulty_make_request(struct mddev *mddev, struct bio *bio)
 {
        struct faulty_conf *conf = mddev->private;
        int failit = 0;
@@ -226,7 +226,7 @@ static void make_request(struct mddev *mddev, struct bio *bio)
        generic_make_request(bio);
 }
 
-static void status(struct seq_file *seq, struct mddev *mddev)
+static void faulty_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct faulty_conf *conf = mddev->private;
        int n;
@@ -259,7 +259,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
 }
 
 
-static int reshape(struct mddev *mddev)
+static int faulty_reshape(struct mddev *mddev)
 {
        int mode = mddev->new_layout & ModeMask;
        int count = mddev->new_layout >> ModeShift;
@@ -299,7 +299,7 @@ static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disk
        return sectors;
 }
 
-static int run(struct mddev *mddev)
+static int faulty_run(struct mddev *mddev)
 {
        struct md_rdev *rdev;
        int i;
@@ -327,7 +327,7 @@ static int run(struct mddev *mddev)
        md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
        mddev->private = conf;
 
-       reshape(mddev);
+       faulty_reshape(mddev);
 
        return 0;
 }
@@ -344,11 +344,11 @@ static struct md_personality faulty_personality =
        .name           = "faulty",
        .level          = LEVEL_FAULTY,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = faulty_make_request,
+       .run            = faulty_run,
        .free           = faulty_free,
-       .status         = status,
-       .check_reshape  = reshape,
+       .status         = faulty_status,
+       .check_reshape  = faulty_reshape,
        .size           = faulty_size,
 };
 
index 0ded8e97751d270dbfdae0aac73a792043f10621..dd97d42458226b4b284b488983e218e01c814889 100644 (file)
@@ -293,6 +293,7 @@ static void recover_bitmaps(struct md_thread *thread)
 dlm_unlock:
                dlm_unlock_sync(bm_lockres);
 clear_bit:
+               lockres_free(bm_lockres);
                clear_bit(slot, &cinfo->recovery_map);
        }
 }
@@ -682,8 +683,10 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots)
                bm_lockres = lockres_init(mddev, str, NULL, 1);
                if (!bm_lockres)
                        return -ENOMEM;
-               if (i == (cinfo->slot_number - 1))
+               if (i == (cinfo->slot_number - 1)) {
+                       lockres_free(bm_lockres);
                        continue;
+               }
 
                bm_lockres->flags |= DLM_LKF_NOQUEUE;
                ret = dlm_lock_sync(bm_lockres, DLM_LOCK_PW);
@@ -858,6 +861,7 @@ static int leave(struct mddev *mddev)
        lockres_free(cinfo->token_lockres);
        lockres_free(cinfo->ack_lockres);
        lockres_free(cinfo->no_new_dev_lockres);
+       lockres_free(cinfo->resync_lockres);
        lockres_free(cinfo->bitmap_lockres);
        unlock_all_bitmaps(mddev);
        dlm_release_lockspace(cinfo->lockspace, 2);
index c4b9134092260f22939027a0a82945b146a4ebf9..4e3843f7d24592cc596df1fc6d6c4577a9a6f57f 100644 (file)
@@ -1044,7 +1044,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
        kfree(plug);
 }
 
-static void make_request(struct mddev *mddev, struct bio * bio)
+static void raid1_make_request(struct mddev *mddev, struct bio * bio)
 {
        struct r1conf *conf = mddev->private;
        struct raid1_info *mirror;
@@ -1422,7 +1422,7 @@ read_again:
        wake_up(&conf->wait_barrier);
 }
 
-static void status(struct seq_file *seq, struct mddev *mddev)
+static void raid1_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct r1conf *conf = mddev->private;
        int i;
@@ -1439,7 +1439,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
        seq_printf(seq, "]");
 }
 
-static void error(struct mddev *mddev, struct md_rdev *rdev)
+static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r1conf *conf = mddev->private;
@@ -2472,7 +2472,8 @@ static int init_resync(struct r1conf *conf)
  * that can be installed to exclude normal IO requests.
  */
 
-static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipped)
+static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
+                                  int *skipped)
 {
        struct r1conf *conf = mddev->private;
        struct r1bio *r1_bio;
@@ -2890,7 +2891,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
 }
 
 static void raid1_free(struct mddev *mddev, void *priv);
-static int run(struct mddev *mddev)
+static int raid1_run(struct mddev *mddev)
 {
        struct r1conf *conf;
        int i;
@@ -3170,15 +3171,15 @@ static struct md_personality raid1_personality =
        .name           = "raid1",
        .level          = 1,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = raid1_make_request,
+       .run            = raid1_run,
        .free           = raid1_free,
-       .status         = status,
-       .error_handler  = error,
+       .status         = raid1_status,
+       .error_handler  = raid1_error,
        .hot_add_disk   = raid1_add_disk,
        .hot_remove_disk= raid1_remove_disk,
        .spare_active   = raid1_spare_active,
-       .sync_request   = sync_request,
+       .sync_request   = raid1_sync_request,
        .resize         = raid1_resize,
        .size           = raid1_size,
        .check_reshape  = raid1_reshape,
index ce959b4ae4dfd9a09d33828f5706d3a6aadd7f71..1c1447dd3417cd3e27f7c097a004b5e9b17a10d5 100644 (file)
@@ -1442,7 +1442,7 @@ retry_write:
        one_write_done(r10_bio);
 }
 
-static void make_request(struct mddev *mddev, struct bio *bio)
+static void raid10_make_request(struct mddev *mddev, struct bio *bio)
 {
        struct r10conf *conf = mddev->private;
        sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
@@ -1484,7 +1484,7 @@ static void make_request(struct mddev *mddev, struct bio *bio)
        wake_up(&conf->wait_barrier);
 }
 
-static void status(struct seq_file *seq, struct mddev *mddev)
+static void raid10_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct r10conf *conf = mddev->private;
        int i;
@@ -1562,7 +1562,7 @@ static int enough(struct r10conf *conf, int ignore)
                _enough(conf, 1, ignore);
 }
 
-static void error(struct mddev *mddev, struct md_rdev *rdev)
+static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r10conf *conf = mddev->private;
@@ -2802,7 +2802,7 @@ static int init_resync(struct r10conf *conf)
  *
  */
 
-static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
+static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                             int *skipped)
 {
        struct r10conf *conf = mddev->private;
@@ -3523,7 +3523,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
        return ERR_PTR(err);
 }
 
-static int run(struct mddev *mddev)
+static int raid10_run(struct mddev *mddev)
 {
        struct r10conf *conf;
        int i, disk_idx, chunk_size;
@@ -4617,15 +4617,15 @@ static struct md_personality raid10_personality =
        .name           = "raid10",
        .level          = 10,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = raid10_make_request,
+       .run            = raid10_run,
        .free           = raid10_free,
-       .status         = status,
-       .error_handler  = error,
+       .status         = raid10_status,
+       .error_handler  = raid10_error,
        .hot_add_disk   = raid10_add_disk,
        .hot_remove_disk= raid10_remove_disk,
        .spare_active   = raid10_spare_active,
-       .sync_request   = sync_request,
+       .sync_request   = raid10_sync_request,
        .quiesce        = raid10_quiesce,
        .size           = raid10_size,
        .resize         = raid10_resize,
index a086014dcd49915d5dad8b2c57b9bbfa30b39e5c..b4f02c9959f23c1bb5e8feccb2b9bf6e1c59e862 100644 (file)
@@ -2496,7 +2496,7 @@ static void raid5_build_block(struct stripe_head *sh, int i, int previous)
        dev->sector = raid5_compute_blocknr(sh, i, previous);
 }
 
-static void error(struct mddev *mddev, struct md_rdev *rdev)
+static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
 {
        char b[BDEVNAME_SIZE];
        struct r5conf *conf = mddev->private;
@@ -2958,7 +2958,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx,
         * If several bio share a stripe. The bio bi_phys_segments acts as a
         * reference count to avoid race. The reference count should already be
         * increased before this function is called (for example, in
-        * make_request()), so other bio sharing this stripe will not free the
+        * raid5_make_request()), so other bio sharing this stripe will not free the
         * stripe. If a stripe is owned by one stripe, the stripe lock will
         * protect it.
         */
@@ -5135,7 +5135,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
        }
 }
 
-static void make_request(struct mddev *mddev, struct bio * bi)
+static void raid5_make_request(struct mddev *mddev, struct bio * bi)
 {
        struct r5conf *conf = mddev->private;
        int dd_idx;
@@ -5225,7 +5225,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                new_sector = raid5_compute_sector(conf, logical_sector,
                                                  previous,
                                                  &dd_idx, NULL);
-               pr_debug("raid456: make_request, sector %llu logical %llu\n",
+               pr_debug("raid456: raid5_make_request, sector %llu logical %llu\n",
                        (unsigned long long)new_sector,
                        (unsigned long long)logical_sector);
 
@@ -5575,7 +5575,8 @@ ret:
        return retn;
 }
 
-static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipped)
+static inline sector_t raid5_sync_request(struct mddev *mddev, sector_t sector_nr,
+                                         int *skipped)
 {
        struct r5conf *conf = mddev->private;
        struct stripe_head *sh;
@@ -6674,7 +6675,7 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded
        return 0;
 }
 
-static int run(struct mddev *mddev)
+static int raid5_run(struct mddev *mddev)
 {
        struct r5conf *conf;
        int working_disks = 0;
@@ -7048,7 +7049,7 @@ static void raid5_free(struct mddev *mddev, void *priv)
        mddev->to_remove = &raid5_attrs_group;
 }
 
-static void status(struct seq_file *seq, struct mddev *mddev)
+static void raid5_status(struct seq_file *seq, struct mddev *mddev)
 {
        struct r5conf *conf = mddev->private;
        int i;
@@ -7864,15 +7865,15 @@ static struct md_personality raid6_personality =
        .name           = "raid6",
        .level          = 6,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = raid5_make_request,
+       .run            = raid5_run,
        .free           = raid5_free,
-       .status         = status,
-       .error_handler  = error,
+       .status         = raid5_status,
+       .error_handler  = raid5_error,
        .hot_add_disk   = raid5_add_disk,
        .hot_remove_disk= raid5_remove_disk,
        .spare_active   = raid5_spare_active,
-       .sync_request   = sync_request,
+       .sync_request   = raid5_sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
        .check_reshape  = raid6_check_reshape,
@@ -7887,15 +7888,15 @@ static struct md_personality raid5_personality =
        .name           = "raid5",
        .level          = 5,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = raid5_make_request,
+       .run            = raid5_run,
        .free           = raid5_free,
-       .status         = status,
-       .error_handler  = error,
+       .status         = raid5_status,
+       .error_handler  = raid5_error,
        .hot_add_disk   = raid5_add_disk,
        .hot_remove_disk= raid5_remove_disk,
        .spare_active   = raid5_spare_active,
-       .sync_request   = sync_request,
+       .sync_request   = raid5_sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
        .check_reshape  = raid5_check_reshape,
@@ -7911,15 +7912,15 @@ static struct md_personality raid4_personality =
        .name           = "raid4",
        .level          = 4,
        .owner          = THIS_MODULE,
-       .make_request   = make_request,
-       .run            = run,
+       .make_request   = raid5_make_request,
+       .run            = raid5_run,
        .free           = raid5_free,
-       .status         = status,
-       .error_handler  = error,
+       .status         = raid5_status,
+       .error_handler  = raid5_error,
        .hot_add_disk   = raid5_add_disk,
        .hot_remove_disk= raid5_remove_disk,
        .spare_active   = raid5_spare_active,
-       .sync_request   = sync_request,
+       .sync_request   = raid5_sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
        .check_reshape  = raid5_check_reshape,
index 0e209b56c76c1c487007121e336e0438944acb93..c6abeb4fba9db51827fc815fde920b1a30faa1fa 100644 (file)
@@ -903,9 +903,18 @@ static int tda1004x_get_fe(struct dvb_frontend *fe)
 {
        struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache;
        struct tda1004x_state* state = fe->demodulator_priv;
+       int status;
 
        dprintk("%s\n", __func__);
 
+       status = tda1004x_read_byte(state, TDA1004X_STATUS_CD);
+       if (status == -1)
+               return -EIO;
+
+       /* Only update the properties cache if device is locked */
+       if (!(status & 8))
+               return 0;
+
        // inversion status
        fe_params->inversion = INVERSION_OFF;
        if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20)
index 7e9cbf757e956b817e465249669b148cd9b38cb0..fb7ed730d9322fae3c8887f0db71bf16de50efa0 100644 (file)
@@ -497,7 +497,7 @@ static int adp1653_probe(struct i2c_client *client,
                if (!client->dev.platform_data) {
                        dev_err(&client->dev,
                                "Neither DT not platform data provided\n");
-                       return EINVAL;
+                       return -EINVAL;
                }
                flash->platform_data = client->dev.platform_data;
        }
index f8dd7505b5294ff167352a1d3ce8823605916db7..e1719ffdfb3db12a1dc724b189b2c4544729d785 100644 (file)
@@ -1960,10 +1960,9 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        }
 
        /* tx 5v detect */
-       tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
+       tx_5v = irq_reg_0x70 & info->cable_det_mask;
        if (tx_5v) {
                v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
-               io_write(sd, 0x71, tx_5v);
                adv76xx_s_detect_tx_5v_ctrl(sd);
                if (handled)
                        *handled = true;
index 830491960add2d239d817e46db7c4f0d2dc8d00a..bf82726fd3f44f684ac5677286764255055cc9a7 100644 (file)
@@ -478,7 +478,6 @@ static const struct i2c_device_id ir_kbd_id[] = {
        { "ir_rx_z8f0811_hdpvr", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, ir_kbd_id);
 
 static struct i2c_driver ir_kbd_driver = {
        .driver = {
index b9e43ffa50859caeb4ce2b8343f660a598d249ff..cbe4711e9b31acfca212a8ef0a96867c03bb45fb 100644 (file)
@@ -144,8 +144,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd,
        mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which);
        if (mf) {
                mutex_lock(&sensor->lock);
-               if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-                       *mf = fmt->format;
+               *mf = fmt->format;
                mutex_unlock(&sensor->lock);
        }
        return 0;
index 1d2c310ce838e5fb415ebd4d3b533ac11b8c4b9b..94f8162444071ca3168af652b0c260acaeeab021 100644 (file)
@@ -1211,6 +1211,8 @@ static int alsa_device_init(struct saa7134_dev *dev)
 
 static int alsa_device_exit(struct saa7134_dev *dev)
 {
+       if (!snd_saa7134_cards[dev->nr])
+               return 1;
 
        snd_card_free(snd_saa7134_cards[dev->nr]);
        snd_saa7134_cards[dev->nr] = NULL;
@@ -1260,7 +1262,8 @@ static void saa7134_alsa_exit(void)
        int idx;
 
        for (idx = 0; idx < SNDRV_CARDS; idx++) {
-               snd_card_free(snd_saa7134_cards[idx]);
+               if (snd_saa7134_cards[idx])
+                       snd_card_free(snd_saa7134_cards[idx]);
        }
 
        saa7134_dmasound_init = NULL;
index 526359447ff90fda699b032e0dbed4d6a06e577e..8b89ebe16d94ace645d7401ece918b83cf92add6 100644 (file)
@@ -215,6 +215,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 config VIDEO_STI_BDISP
        tristate "STMicroelectronics BDISP 2D blitter driver"
        depends on VIDEO_DEV && VIDEO_V4L2
+       depends on HAS_DMA
        depends on ARCH_STI || COMPILE_TEST
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
index 40423c6c5324a8e1cf2573b2acffeb566ad74655..57d42c6172c576757b7724906852c7ec9ac34911 100644 (file)
@@ -1,6 +1,6 @@
 
 config VIDEO_SAMSUNG_EXYNOS4_IS
-       bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
+       tristate "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
        depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
        depends on OF && COMMON_CLK
index 49658ca39e5100d70ed9011eea6adb4cd02c3c55..979c388ebf60cdd1a497aac2570aab05c5e800a6 100644 (file)
@@ -631,6 +631,12 @@ static int fimc_is_hw_open_sensor(struct fimc_is *is,
 
        fimc_is_mem_barrier();
 
+       /*
+        * Some user space use cases hang up here without this
+        * empirically chosen delay.
+        */
+       udelay(100);
+
        mcuctl_write(HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0));
        mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
        mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2));
index bf9261eb57a15c37a8b82fb3197a94649e4cc9c6..c0816728cbfe1d2be7c6eb5c987a4ac3b8213a74 100644 (file)
@@ -218,8 +218,8 @@ static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
                                                        ivb->dma_addr[i];
 
                        isp_dbg(2, &video->ve.vdev,
-                               "dma_buf %pad (%d/%d/%d) addr: %pad\n",
-                               &buf_index, ivb->index, i, vb->index,
+                               "dma_buf %d (%d/%d/%d) addr: %pad\n",
+                               buf_index, ivb->index, i, vb->index,
                                &ivb->dma_addr[i]);
                }
 
index f3b2dd30ec7769b3199da9ed2694df5886004616..e79ddbb1e14fc0bd8c1b56504183a927edcdec83 100644 (file)
@@ -185,6 +185,37 @@ error:
        return ret;
 }
 
+/**
+ * __fimc_pipeline_enable - enable power of all pipeline subdevs
+ *                         and the sensor clock
+ * @ep: video pipeline structure
+ * @fmd: fimc media device
+ *
+ * Called with the graph mutex held.
+ */
+static int __fimc_pipeline_enable(struct exynos_media_pipeline *ep,
+                                 struct fimc_md *fmd)
+{
+       struct fimc_pipeline *p = to_fimc_pipeline(ep);
+       int ret;
+
+       /* Enable PXLASYNC clock if this pipeline includes FIMC-IS */
+       if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) {
+               ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = fimc_pipeline_s_power(p, 1);
+       if (!ret)
+               return 0;
+
+       if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
+               clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
+
+       return ret;
+}
+
 /**
  * __fimc_pipeline_open - update the pipeline information, enable power
  *                        of all pipeline subdevs and the sensor clock
@@ -199,7 +230,6 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
        struct fimc_md *fmd = entity_to_fimc_mdev(me);
        struct fimc_pipeline *p = to_fimc_pipeline(ep);
        struct v4l2_subdev *sd;
-       int ret;
 
        if (WARN_ON(p == NULL || me == NULL))
                return -EINVAL;
@@ -208,24 +238,16 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
                fimc_pipeline_prepare(p, me);
 
        sd = p->subdevs[IDX_SENSOR];
-       if (sd == NULL)
-               return -EINVAL;
-
-       /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
-       if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) {
-               ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]);
-               if (ret < 0)
-                       return ret;
-       }
-
-       ret = fimc_pipeline_s_power(p, 1);
-       if (!ret)
+       if (sd == NULL) {
+               pr_warn("%s(): No sensor subdev\n", __func__);
+               /*
+                * Pipeline open cannot fail so as to make it possible
+                * for the user space to configure the pipeline.
+                */
                return 0;
+       }
 
-       if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
-               clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
-
-       return ret;
+       return __fimc_pipeline_enable(ep, fmd);
 }
 
 /**
@@ -269,10 +291,43 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
                { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
        };
        struct fimc_pipeline *p = to_fimc_pipeline(ep);
+       struct fimc_md *fmd = entity_to_fimc_mdev(&p->subdevs[IDX_CSIS]->entity);
+       enum fimc_subdev_index sd_id;
        int i, ret = 0;
 
-       if (p->subdevs[IDX_SENSOR] == NULL)
-               return -ENODEV;
+       if (p->subdevs[IDX_SENSOR] == NULL) {
+               if (!fmd->user_subdev_api) {
+                       /*
+                        * Sensor must be already discovered if we
+                        * aren't in the user_subdev_api mode
+                        */
+                       return -ENODEV;
+               }
+
+               /* Get pipeline sink entity */
+               if (p->subdevs[IDX_FIMC])
+                       sd_id = IDX_FIMC;
+               else if (p->subdevs[IDX_IS_ISP])
+                       sd_id = IDX_IS_ISP;
+               else if (p->subdevs[IDX_FLITE])
+                       sd_id = IDX_FLITE;
+               else
+                       return -ENODEV;
+
+               /*
+                * Sensor could have been linked between open and STREAMON -
+                * check if this is the case.
+                */
+               fimc_pipeline_prepare(p, &p->subdevs[sd_id]->entity);
+
+               if (p->subdevs[IDX_SENSOR] == NULL)
+                       return -ENODEV;
+
+               ret = __fimc_pipeline_enable(ep, fmd);
+               if (ret < 0)
+                       return ret;
+
+       }
 
        for (i = 0; i < IDX_MAX; i++) {
                unsigned int idx = seq[on][i];
@@ -282,8 +337,10 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
                if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
                        goto error;
        }
+
        return 0;
 error:
+       fimc_pipeline_s_power(p, !on);
        for (; i >= 0; i--) {
                unsigned int idx = seq[on][i];
                v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on);
index c398b285180cda757ec291bb6cc0c004c3c27de4..1af779ee3c747f31aff5d79d7d3db66d65a41b03 100644 (file)
@@ -795,7 +795,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
                        xlate->host_fmt = &isi_camera_formats[i];
                        xlate->code     = code.code;
                        dev_dbg(icd->parent, "Providing format %s using code %d\n",
-                               isi_camera_formats[0].name, code.code);
+                               xlate->host_fmt->name, xlate->code);
                }
                break;
        default:
index cc84c6d6a701ce249722010ed514c1e4a4630def..46c7186f78679a5ca09a01d8709cbb77cf1332bc 100644 (file)
@@ -1493,6 +1493,8 @@ static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier,
                                        struct soc_camera_async_client, notifier);
        struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev);
 
+       icd->control = NULL;
+
        if (icd->clk) {
                v4l2_clk_unregister(icd->clk);
                icd->clk = NULL;
index 42dff9d020afaf66c70e528b58d2f005a53203f3..533bc796391ed3053a5f21c92e94eba92cdc46a4 100644 (file)
@@ -256,7 +256,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
 
        /* Create links. */
        list_for_each_entry(entity, &vsp1->entities, list_dev) {
-               if (entity->type == VSP1_ENTITY_LIF) {
+               if (entity->type == VSP1_ENTITY_WPF) {
                        ret = vsp1_wpf_create_links(vsp1, entity);
                        if (ret < 0)
                                goto done;
@@ -264,7 +264,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
                        ret = vsp1_rpf_create_links(vsp1, entity);
                        if (ret < 0)
                                goto done;
-               } else {
+               }
+
+               if (entity->type != VSP1_ENTITY_LIF &&
+                   entity->type != VSP1_ENTITY_RPF) {
                        ret = vsp1_create_links(vsp1, entity);
                        if (ret < 0)
                                goto done;
index 637d0d6f79fba5fb511b6fba37fb24875d913dbd..b4dca57d1ae3f6d78a3417251089939a7da15f77 100644 (file)
@@ -515,7 +515,7 @@ static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
        bool stopped;
 
        spin_lock_irqsave(&pipe->irqlock, flags);
-       stopped = pipe->state == VSP1_PIPELINE_STOPPED,
+       stopped = pipe->state == VSP1_PIPELINE_STOPPED;
        spin_unlock_irqrestore(&pipe->irqlock, flags);
 
        return stopped;
index 8c54fd21022e443ee03e2f1b852208c4a03b938e..a1362572284822e7b39a009ab227137dbd8b8595 100644 (file)
@@ -1843,8 +1843,7 @@ static void au0828_analog_create_entities(struct au0828_dev *dev)
                        ent->function = MEDIA_ENT_F_CONN_RF;
                        break;
                default: /* AU0828_VMUX_DEBUG */
-                       ent->function = MEDIA_ENT_F_CONN_TEST;
-                       break;
+                       continue;
                }
 
                ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
index c5d49d7a0d76d09c1ac5598a21ce7726d03190c1..ff8953ae52d142e654f30548d5ddf7bf08c45690 100644 (file)
@@ -1063,8 +1063,11 @@ EXPORT_SYMBOL_GPL(vb2_discard_done);
  */
 static int __qbuf_mmap(struct vb2_buffer *vb, const void *pb)
 {
-       int ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
-                       vb, pb, vb->planes);
+       int ret = 0;
+
+       if (pb)
+               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                                vb, pb, vb->planes);
        return ret ? ret : call_vb_qop(vb, buf_prepare, vb);
 }
 
@@ -1077,14 +1080,16 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb)
        struct vb2_queue *q = vb->vb2_queue;
        void *mem_priv;
        unsigned int plane;
-       int ret;
+       int ret = 0;
        enum dma_data_direction dma_dir =
                q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        bool reacquired = vb->planes[0].mem_priv == NULL;
 
        memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
        /* Copy relevant information provided by the userspace */
-       ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes);
+       if (pb)
+               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                                vb, pb, planes);
        if (ret)
                return ret;
 
@@ -1192,14 +1197,16 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
        struct vb2_queue *q = vb->vb2_queue;
        void *mem_priv;
        unsigned int plane;
-       int ret;
+       int ret = 0;
        enum dma_data_direction dma_dir =
                q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
        bool reacquired = vb->planes[0].mem_priv == NULL;
 
        memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
        /* Copy relevant information provided by the userspace */
-       ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes);
+       if (pb)
+               ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
+                                vb, pb, planes);
        if (ret)
                return ret;
 
@@ -1520,7 +1527,8 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
        q->waiting_for_buffers = false;
        vb->state = VB2_BUF_STATE_QUEUED;
 
-       call_void_bufop(q, copy_timestamp, vb, pb);
+       if (pb)
+               call_void_bufop(q, copy_timestamp, vb, pb);
 
        trace_vb2_qbuf(q, vb);
 
@@ -1532,7 +1540,8 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
                __enqueue_in_driver(vb);
 
        /* Fill buffer information for the userspace */
-       call_void_bufop(q, fill_user_buffer, vb, pb);
+       if (pb)
+               call_void_bufop(q, fill_user_buffer, vb, pb);
 
        /*
         * If streamon has been called, and we haven't yet called
@@ -1731,7 +1740,8 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
  * The return values from this function are intended to be directly returned
  * from vidioc_dqbuf handler in driver.
  */
-int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
+int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
+                  bool nonblocking)
 {
        struct vb2_buffer *vb = NULL;
        int ret;
@@ -1754,8 +1764,12 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
 
        call_void_vb_qop(vb, buf_finish, vb);
 
+       if (pindex)
+               *pindex = vb->index;
+
        /* Fill buffer information for the userspace */
-       call_void_bufop(q, fill_user_buffer, vb, pb);
+       if (pb)
+               call_void_bufop(q, fill_user_buffer, vb, pb);
 
        /* Remove from videobuf queue */
        list_del(&vb->queued_entry);
@@ -1828,7 +1842,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
         * that's done in dqbuf, but that's not going to happen when we
         * cancel the whole queue. Note: this code belongs here, not in
         * __vb2_dqbuf() since in vb2_internal_dqbuf() there is a critical
-        * call to __fill_v4l2_buffer() after buf_finish(). That order can't
+        * call to __fill_user_buffer() after buf_finish(). That order can't
         * be changed, so we can't move the buf_finish() to __vb2_dqbuf().
         */
        for (i = 0; i < q->num_buffers; ++i) {
@@ -2357,7 +2371,6 @@ struct vb2_fileio_data {
        unsigned int count;
        unsigned int type;
        unsigned int memory;
-       struct vb2_buffer *b;
        struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
        unsigned int cur_index;
        unsigned int initial_index;
@@ -2410,12 +2423,6 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
        if (fileio == NULL)
                return -ENOMEM;
 
-       fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL);
-       if (fileio->b == NULL) {
-               kfree(fileio);
-               return -ENOMEM;
-       }
-
        fileio->read_once = q->fileio_read_once;
        fileio->write_immediately = q->fileio_write_immediately;
 
@@ -2460,13 +2467,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
                 * Queue all buffers.
                 */
                for (i = 0; i < q->num_buffers; i++) {
-                       struct vb2_buffer *b = fileio->b;
-
-                       memset(b, 0, q->buf_struct_size);
-                       b->type = q->type;
-                       b->memory = q->memory;
-                       b->index = i;
-                       ret = vb2_core_qbuf(q, i, b);
+                       ret = vb2_core_qbuf(q, i, NULL);
                        if (ret)
                                goto err_reqbufs;
                        fileio->bufs[i].queued = 1;
@@ -2511,7 +2512,6 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q)
                q->fileio = NULL;
                fileio->count = 0;
                vb2_core_reqbufs(q, fileio->memory, &fileio->count);
-               kfree(fileio->b);
                kfree(fileio);
                dprintk(3, "file io emulator closed\n");
        }
@@ -2539,7 +2539,8 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
         * else is able to provide this information with the write() operation.
         */
        bool copy_timestamp = !read && q->copy_timestamp;
-       int ret, index;
+       unsigned index;
+       int ret;
 
        dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
                read ? "read" : "write", (long)*ppos, count,
@@ -2564,22 +2565,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
         */
        index = fileio->cur_index;
        if (index >= q->num_buffers) {
-               struct vb2_buffer *b = fileio->b;
+               struct vb2_buffer *b;
 
                /*
                 * Call vb2_dqbuf to get buffer back.
                 */
-               memset(b, 0, q->buf_struct_size);
-               b->type = q->type;
-               b->memory = q->memory;
-               ret = vb2_core_dqbuf(q, b, nonblock);
+               ret = vb2_core_dqbuf(q, &index, NULL, nonblock);
                dprintk(5, "vb2_dqbuf result: %d\n", ret);
                if (ret)
                        return ret;
                fileio->dq_count += 1;
 
-               fileio->cur_index = index = b->index;
+               fileio->cur_index = index;
                buf = &fileio->bufs[index];
+               b = q->bufs[index];
 
                /*
                 * Get number of bytes filled by the driver
@@ -2630,7 +2629,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
         * Queue next buffer if required.
         */
        if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
-               struct vb2_buffer *b = fileio->b;
+               struct vb2_buffer *b = q->bufs[index];
 
                /*
                 * Check if this is the last buffer to read.
@@ -2643,15 +2642,11 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                /*
                 * Call vb2_qbuf and give buffer to the driver.
                 */
-               memset(b, 0, q->buf_struct_size);
-               b->type = q->type;
-               b->memory = q->memory;
-               b->index = index;
                b->planes[0].bytesused = buf->pos;
 
                if (copy_timestamp)
                        b->timestamp = ktime_get_ns();
-               ret = vb2_core_qbuf(q, index, b);
+               ret = vb2_core_qbuf(q, index, NULL);
                dprintk(5, "vb2_dbuf result: %d\n", ret);
                if (ret)
                        return ret;
@@ -2713,10 +2708,9 @@ static int vb2_thread(void *data)
 {
        struct vb2_queue *q = data;
        struct vb2_threadio_data *threadio = q->threadio;
-       struct vb2_fileio_data *fileio = q->fileio;
        bool copy_timestamp = false;
-       int prequeue = 0;
-       int index = 0;
+       unsigned prequeue = 0;
+       unsigned index = 0;
        int ret = 0;
 
        if (q->is_output) {
@@ -2728,37 +2722,34 @@ static int vb2_thread(void *data)
 
        for (;;) {
                struct vb2_buffer *vb;
-               struct vb2_buffer *b = fileio->b;
 
                /*
                 * Call vb2_dqbuf to get buffer back.
                 */
-               memset(b, 0, q->buf_struct_size);
-               b->type = q->type;
-               b->memory = q->memory;
                if (prequeue) {
-                       b->index = index++;
+                       vb = q->bufs[index++];
                        prequeue--;
                } else {
                        call_void_qop(q, wait_finish, q);
                        if (!threadio->stop)
-                               ret = vb2_core_dqbuf(q, b, 0);
+                               ret = vb2_core_dqbuf(q, &index, NULL, 0);
                        call_void_qop(q, wait_prepare, q);
                        dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+                       if (!ret)
+                               vb = q->bufs[index];
                }
                if (ret || threadio->stop)
                        break;
                try_to_freeze();
 
-               vb = q->bufs[b->index];
-               if (b->state == VB2_BUF_STATE_DONE)
+               if (vb->state != VB2_BUF_STATE_ERROR)
                        if (threadio->fnc(vb, threadio->priv))
                                break;
                call_void_qop(q, wait_finish, q);
                if (copy_timestamp)
-                       b->timestamp = ktime_get_ns();;
+                       vb->timestamp = ktime_get_ns();;
                if (!threadio->stop)
-                       ret = vb2_core_qbuf(q, b->index, b);
+                       ret = vb2_core_qbuf(q, vb->index, NULL);
                call_void_qop(q, wait_prepare, q);
                if (ret || threadio->stop)
                        break;
index c9a28605511a71166af35a4ef11fb95ff0eb8fbd..91f552124050d2b3b91d2190af16fbdf2f9d7243 100644 (file)
@@ -625,7 +625,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
                return -EINVAL;
        }
 
-       ret = vb2_core_dqbuf(q, b, nonblocking);
+       ret = vb2_core_dqbuf(q, NULL, b, nonblocking);
 
        return ret;
 }
index e6e4bacb09ee5d2636576c3363c97a1a5c5f72c8..12099b09a9a71ee5f49e61608b24734e42ca58db 100644 (file)
@@ -2048,6 +2048,7 @@ int db8500_prcmu_config_hotmon(u8 low, u8 high)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_config_hotmon);
 
 static int config_hot_period(u16 val)
 {
@@ -2074,11 +2075,13 @@ int db8500_prcmu_start_temp_sense(u16 cycles32k)
 
        return config_hot_period(cycles32k);
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_start_temp_sense);
 
 int db8500_prcmu_stop_temp_sense(void)
 {
        return config_hot_period(0xFFFF);
 }
+EXPORT_SYMBOL_GPL(db8500_prcmu_stop_temp_sense);
 
 static int prcmu_a9wdog(u8 cmd, u8 d0, u8 d1, u8 d2, u8 d3)
 {
index 4c1903f781fc1793bb7ddf7205d138e60ea2133a..0c6c17a1c59e3a9417dde5ab842fffbab4f09e69 100644 (file)
@@ -415,7 +415,7 @@ static int cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
                delta = mftb() - psl_tb;
                if (delta < 0)
                        delta = -delta;
-       } while (cputime_to_usecs(delta) > 16);
+       } while (tb_to_ns(delta) > 16000);
 
        return 0;
 }
index 677d0362f334e842abb2c8c2439260978249b871..80f9afcb13823282a9859e08a96c36f55901efa6 100644 (file)
@@ -458,7 +458,11 @@ static int mei_ioctl_client_notify_request(struct file *file, u32 request)
 {
        struct mei_cl *cl = file->private_data;
 
-       return mei_cl_notify_request(cl, file, request);
+       if (request != MEI_HBM_NOTIFICATION_START &&
+           request != MEI_HBM_NOTIFICATION_STOP)
+               return -EINVAL;
+
+       return mei_cl_notify_request(cl, file, (u8)request);
 }
 
 /**
index 5914263090fc81447e26130baab143802504c088..fe207e5420324af3db9411902bcbedeb19e6f60f 100644 (file)
 #include "queue.h"
 
 MODULE_ALIAS("mmc:block");
-
-#ifdef KERNEL
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
-#endif
 
 #define INAND_CMD38_ARG_EXT_CSD  113
 #define INAND_CMD38_ARG_ERASE    0x00
@@ -655,8 +652,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
        }
 
        md = mmc_blk_get(bdev->bd_disk);
-       if (!md)
+       if (!md) {
+               err = -EINVAL;
                goto cmd_err;
+       }
 
        card = md->queue.card;
        if (IS_ERR(card)) {
index 1c1b45ef3faf847d4087d61904ed18c1a6f7ce5e..3446097a43c01ca6cf7f8e163cc75dbbb3911f3f 100644 (file)
@@ -925,6 +925,10 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
 
                        dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
                                                PAGE_SIZE, dir);
+                       if (dma_mapping_error(dma_dev, dma_addr)) {
+                               data->error = -EFAULT;
+                               break;
+                       }
                        if (direction == DMA_TO_DEVICE)
                                t->tx_dma = dma_addr + sg->offset;
                        else
@@ -1393,10 +1397,12 @@ static int mmc_spi_probe(struct spi_device *spi)
                host->dma_dev = dev;
                host->ones_dma = dma_map_single(dev, ones,
                                MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, host->ones_dma))
+                       goto fail_ones_dma;
                host->data_dma = dma_map_single(dev, host->data,
                                sizeof(*host->data), DMA_BIDIRECTIONAL);
-
-               /* REVISIT in theory those map operations can fail... */
+               if (dma_mapping_error(dev, host->data_dma))
+                       goto fail_data_dma;
 
                dma_sync_single_for_cpu(host->dma_dev,
                                host->data_dma, sizeof(*host->data),
@@ -1462,6 +1468,11 @@ fail_glue_init:
        if (host->dma_dev)
                dma_unmap_single(host->dma_dev, host->data_dma,
                                sizeof(*host->data), DMA_BIDIRECTIONAL);
+fail_data_dma:
+       if (host->dma_dev)
+               dma_unmap_single(host->dma_dev, host->ones_dma,
+                               MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+fail_ones_dma:
        kfree(host->data);
 
 fail_nobuf1:
index b6639ea0bf18dbd37ccf0d639073119353b418b6..f6e4d97180359c32066ffa36d1ae99fd0f612d3d 100644 (file)
@@ -2232,6 +2232,7 @@ err_irq:
                dma_release_channel(host->tx_chan);
        if (host->rx_chan)
                dma_release_channel(host->rx_chan);
+       pm_runtime_dont_use_autosuspend(host->dev);
        pm_runtime_put_sync(host->dev);
        pm_runtime_disable(host->dev);
        if (host->dbclk)
@@ -2253,6 +2254,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        dma_release_channel(host->tx_chan);
        dma_release_channel(host->rx_chan);
 
+       pm_runtime_dont_use_autosuspend(host->dev);
        pm_runtime_put_sync(host->dev);
        pm_runtime_disable(host->dev);
        device_init_wakeup(&pdev->dev, false);
index ce08896b9d696b00440fe7807aeddf72b922f320..da824772bbb4a37e29c33cb6c44a1be38b10c3a5 100644 (file)
@@ -86,7 +86,7 @@ struct pxamci_host {
 static inline void pxamci_init_ocr(struct pxamci_host *host)
 {
 #ifdef CONFIG_REGULATOR
-       host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc");
+       host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc");
 
        if (IS_ERR(host->vcc))
                host->vcc = NULL;
@@ -654,12 +654,8 @@ static int pxamci_probe(struct platform_device *pdev)
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
-       if (!r || irq < 0)
-               return -ENXIO;
-
-       r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
-       if (!r)
-               return -EBUSY;
+       if (irq < 0)
+               return irq;
 
        mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
        if (!mmc) {
@@ -695,7 +691,7 @@ static int pxamci_probe(struct platform_device *pdev)
        host->pdata = pdev->dev.platform_data;
        host->clkrt = CLKRT_OFF;
 
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                host->clk = NULL;
@@ -727,9 +723,9 @@ static int pxamci_probe(struct platform_device *pdev)
        host->irq = irq;
        host->imask = MMC_I_MASK_ALL;
 
-       host->base = ioremap(r->start, SZ_4K);
-       if (!host->base) {
-               ret = -ENOMEM;
+       host->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
                goto out;
        }
 
@@ -742,7 +738,8 @@ static int pxamci_probe(struct platform_device *pdev)
        writel(64, host->base + MMC_RESTO);
        writel(host->imask, host->base + MMC_I_MASK);
 
-       ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
+       ret = devm_request_irq(&pdev->dev, host->irq, pxamci_irq, 0,
+                              DRIVER_NAME, host);
        if (ret)
                goto out;
 
@@ -804,7 +801,7 @@ static int pxamci_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
                goto out;
        } else {
-               mmc->caps |= host->pdata->gpio_card_ro_invert ?
+               mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
                        0 : MMC_CAP2_RO_ACTIVE_HIGH;
        }
 
@@ -833,14 +830,9 @@ out:
                        dma_release_channel(host->dma_chan_rx);
                if (host->dma_chan_tx)
                        dma_release_channel(host->dma_chan_tx);
-               if (host->base)
-                       iounmap(host->base);
-               if (host->clk)
-                       clk_put(host->clk);
        }
        if (mmc)
                mmc_free_host(mmc);
-       release_resource(r);
        return ret;
 }
 
@@ -859,9 +851,6 @@ static int pxamci_remove(struct platform_device *pdev)
                        gpio_ro = host->pdata->gpio_card_ro;
                        gpio_power = host->pdata->gpio_power;
                }
-               if (host->vcc)
-                       regulator_put(host->vcc);
-
                if (host->pdata && host->pdata->exit)
                        host->pdata->exit(&pdev->dev, mmc);
 
@@ -870,16 +859,10 @@ static int pxamci_remove(struct platform_device *pdev)
                       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
                       host->base + MMC_I_MASK);
 
-               free_irq(host->irq, host);
                dmaengine_terminate_all(host->dma_chan_rx);
                dmaengine_terminate_all(host->dma_chan_tx);
                dma_release_channel(host->dma_chan_rx);
                dma_release_channel(host->dma_chan_tx);
-               iounmap(host->base);
-
-               clk_put(host->clk);
-
-               release_resource(host->res);
 
                mmc_free_host(mmc);
        }
index f6047fc9406204d6ee672b74544d0ec6866308cd..a5cda926d38eb23be20eece31c6b1ef0c44723a3 100644 (file)
@@ -146,6 +146,33 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
        .ops = &sdhci_acpi_ops_int,
 };
 
+static int bxt_get_cd(struct mmc_host *mmc)
+{
+       int gpio_cd = mmc_gpio_get_cd(mmc);
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       int ret = 0;
+
+       if (!gpio_cd)
+               return 0;
+
+       pm_runtime_get_sync(mmc->parent);
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->flags & SDHCI_DEVICE_DEAD)
+               goto out;
+
+       ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       pm_runtime_mark_last_busy(mmc->parent);
+       pm_runtime_put_autosuspend(mmc->parent);
+
+       return ret;
+}
+
 static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev,
                                      const char *hid, const char *uid)
 {
@@ -196,6 +223,9 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
 
        /* Platform specific code during sd probe slot goes here */
 
+       if (hid && !strcmp(hid, "80865ACA"))
+               host->mmc_host_ops.get_cd = bxt_get_cd;
+
        return 0;
 }
 
index 7e7d8f0c9438fe4ac41bfb1f1759ff4fde776089..9cb86fb25976f380530fe0029015bdfaf408d743 100644 (file)
@@ -217,6 +217,7 @@ static int sdhci_at91_probe(struct platform_device *pdev)
 pm_runtime_disable:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
+       pm_runtime_put_noidle(&pdev->dev);
 clocks_disable_unprepare:
        clk_disable_unprepare(priv->gck);
        clk_disable_unprepare(priv->mainck);
index cc851b065d0ae685d5297f7e4b8ac7a40b3e3465..df3b8eced8c4a50a727774404a066086d4ebe0f7 100644 (file)
@@ -330,6 +330,33 @@ static void spt_read_drive_strength(struct sdhci_host *host)
        sdhci_pci_spt_drive_strength = 0x10 | ((val >> 12) & 0xf);
 }
 
+static int bxt_get_cd(struct mmc_host *mmc)
+{
+       int gpio_cd = mmc_gpio_get_cd(mmc);
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+       int ret = 0;
+
+       if (!gpio_cd)
+               return 0;
+
+       pm_runtime_get_sync(mmc->parent);
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->flags & SDHCI_DEVICE_DEAD)
+               goto out;
+
+       ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       pm_runtime_mark_last_busy(mmc->parent);
+       pm_runtime_put_autosuspend(mmc->parent);
+
+       return ret;
+}
+
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
@@ -362,6 +389,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
        slot->cd_con_id = NULL;
        slot->cd_idx = 0;
        slot->cd_override_level = true;
+       if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
+           slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD)
+               slot->host->mmc_host_ops.get_cd = bxt_get_cd;
+
        return 0;
 }
 
index d622435d1bcc71e47e54cdb42cb847660b009a55..add9fdfd1d8feff619f70d58d581b877a668a88c 100644 (file)
@@ -1360,7 +1360,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sdhci_runtime_pm_get(host);
 
        /* Firstly check card presence */
-       present = sdhci_do_get_cd(host);
+       present = mmc->ops->get_cd(mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -2849,6 +2849,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
+       host->mmc_host_ops = sdhci_ops;
+       mmc->ops = &host->mmc_host_ops;
 
        return host;
 }
@@ -3037,7 +3039,6 @@ int sdhci_add_host(struct sdhci_host *host)
        /*
         * Set host parameters.
         */
-       mmc->ops = &sdhci_ops;
        max_clk = host->max_clk;
 
        if (host->ops->get_min_clock)
index 7654ae5d2b4e11b8b1814fa99b514223d4475d50..0115e9907bf8243aa394de60ac959e5876d5a3a9 100644 (file)
@@ -430,6 +430,7 @@ struct sdhci_host {
 
        /* Internal data */
        struct mmc_host *mmc;   /* MMC structure */
+       struct mmc_host_ops mmc_host_ops;       /* MMC host ops */
        u64 dma_mask;           /* custom DMA mask */
 
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
index 1ca8a1359cbc1efd6a35cefb596c1c4534c77920..6234eab38ff3efe8b22b8386f4d635496dad0d08 100644 (file)
@@ -445,7 +445,7 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host)
                                                        pdata->slave_id_rx);
        } else {
                host->chan_tx = dma_request_slave_channel(dev, "tx");
-               host->chan_tx = dma_request_slave_channel(dev, "rx");
+               host->chan_rx = dma_request_slave_channel(dev, "rx");
        }
        dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx,
                host->chan_rx);
index 2a1b6e037e1a1ced496ac446ca07d6037ef61d0e..0134ba32a05784b65d1a0e6d470eee7a857df74c 100644 (file)
@@ -193,7 +193,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
        vol->changing_leb = 1;
        vol->ch_lnum = req->lnum;
 
-       vol->upd_buf = vmalloc(req->bytes);
+       vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size));
        if (!vol->upd_buf)
                return -ENOMEM;
 
index f184fb5bd11046d814f0b03e122bc7419bc7cdf5..2a1ba62b7da20ff921ec36005a8b4d40ec17756b 100644 (file)
@@ -193,6 +193,13 @@ config GENEVE
          To compile this driver as a module, choose M here: the module
          will be called geneve.
 
+config MACSEC
+       tristate "IEEE 802.1AE MAC-level encryption (MACsec)"
+       select CRYPTO_AES
+       select CRYPTO_GCM
+       ---help---
+          MACsec is an encryption standard for Ethernet.
+
 config NETCONSOLE
        tristate "Network console logging support"
        ---help---
index 900b0c5320bb908a2496c6bbe5c49026631b17a3..1aa7cb845663152c272633667d3b1affe619f3dd 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_IPVLAN) += ipvlan/
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_EQUALIZER) += eql.o
 obj-$(CONFIG_IFB) += ifb.o
+obj-$(CONFIG_MACSEC) += macsec.o
 obj-$(CONFIG_MACVLAN) += macvlan.o
 obj-$(CONFIG_MACVTAP) += macvtap.o
 obj-$(CONFIG_MII) += mii.o
index 45bdd87d6b7a234d140d0f2979861aeda1387d37..b6236ff3dbdd97ffa7c94ad5d53a7a96d3883f02 100644 (file)
@@ -214,6 +214,8 @@ static void bond_uninit(struct net_device *bond_dev);
 static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                                                struct rtnl_link_stats64 *stats);
 static void bond_slave_arr_handler(struct work_struct *work);
+static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
+                                 int mod);
 
 /*---------------------------- General routines -----------------------------*/
 
@@ -374,22 +376,20 @@ down:
 static void bond_update_speed_duplex(struct slave *slave)
 {
        struct net_device *slave_dev = slave->dev;
-       struct ethtool_cmd ecmd;
-       u32 slave_speed;
+       struct ethtool_link_ksettings ecmd;
        int res;
 
        slave->speed = SPEED_UNKNOWN;
        slave->duplex = DUPLEX_UNKNOWN;
 
-       res = __ethtool_get_settings(slave_dev, &ecmd);
+       res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
        if (res < 0)
                return;
 
-       slave_speed = ethtool_cmd_speed(&ecmd);
-       if (slave_speed == 0 || slave_speed == ((__u32) -1))
+       if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1))
                return;
 
-       switch (ecmd.duplex) {
+       switch (ecmd.base.duplex) {
        case DUPLEX_FULL:
        case DUPLEX_HALF:
                break;
@@ -397,8 +397,8 @@ static void bond_update_speed_duplex(struct slave *slave)
                return;
        }
 
-       slave->speed = slave_speed;
-       slave->duplex = ecmd.duplex;
+       slave->speed = ecmd.base.speed;
+       slave->duplex = ecmd.base.duplex;
 
        return;
 }
@@ -2122,6 +2122,7 @@ static void bond_miimon_commit(struct bonding *bond)
                        continue;
 
                case BOND_LINK_UP:
+                       bond_update_speed_duplex(slave);
                        bond_set_slave_link_state(slave, BOND_LINK_UP,
                                                  BOND_SLAVE_NOTIFY_NOW);
                        slave->last_link_up = jiffies;
@@ -2454,7 +2455,7 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
                 struct slave *slave)
 {
        struct arphdr *arp = (struct arphdr *)skb->data;
-       struct slave *curr_active_slave;
+       struct slave *curr_active_slave, *curr_arp_slave;
        unsigned char *arp_ptr;
        __be32 sip, tip;
        int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
@@ -2501,26 +2502,41 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
                     &sip, &tip);
 
        curr_active_slave = rcu_dereference(bond->curr_active_slave);
+       curr_arp_slave = rcu_dereference(bond->current_arp_slave);
 
-       /* Backup slaves won't see the ARP reply, but do come through
-        * here for each ARP probe (so we swap the sip/tip to validate
-        * the probe).  In a "redundant switch, common router" type of
-        * configuration, the ARP probe will (hopefully) travel from
-        * the active, through one switch, the router, then the other
-        * switch before reaching the backup.
+       /* We 'trust' the received ARP enough to validate it if:
+        *
+        * (a) the slave receiving the ARP is active (which includes the
+        * current ARP slave, if any), or
+        *
+        * (b) the receiving slave isn't active, but there is a currently
+        * active slave and it received valid arp reply(s) after it became
+        * the currently active slave, or
+        *
+        * (c) there is an ARP slave that sent an ARP during the prior ARP
+        * interval, and we receive an ARP reply on any slave.  We accept
+        * these because switch FDB update delays may deliver the ARP
+        * reply to a slave other than the sender of the ARP request.
         *
-        * We 'trust' the arp requests if there is an active slave and
-        * it received valid arp reply(s) after it became active. This
-        * is done to avoid endless looping when we can't reach the
+        * Note: for (b), backup slaves are receiving the broadcast ARP
+        * request, not a reply.  This request passes from the sending
+        * slave through the L2 switch(es) to the receiving slave.  Since
+        * this is checking the request, sip/tip are swapped for
+        * validation.
+        *
+        * This is done to avoid endless looping when we can't reach the
         * arp_ip_target and fool ourselves with our own arp requests.
         */
-
        if (bond_is_active_slave(slave))
                bond_validate_arp(bond, slave, sip, tip);
        else if (curr_active_slave &&
                 time_after(slave_last_rx(bond, curr_active_slave),
                            curr_active_slave->last_link_up))
                bond_validate_arp(bond, slave, tip, sip);
+       else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) &&
+                bond_time_in_interval(bond,
+                                      dev_trans_start(curr_arp_slave->dev), 1))
+               bond_validate_arp(bond, slave, sip, tip);
 
 out_unlock:
        if (arp != (struct arphdr *)skb->data)
index 6d04183ed95528ee44905193ce4f975007de572f..0d40aef928e2a7b104e4e30e05ff87ee40756d44 100644 (file)
@@ -70,13 +70,6 @@ config CAN_AT91
          This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
          and AT91SAM9X5 processors.
 
-config CAN_TI_HECC
-       depends on ARM
-       tristate "TI High End CAN Controller"
-       ---help---
-         Driver for TI HECC (High End CAN Controller) module found on many
-         TI devices. The device specifications are available from www.ti.com
-
 config CAN_BFIN
        depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x
        tristate "Analog Devices Blackfin on-chip CAN"
@@ -86,30 +79,12 @@ config CAN_BFIN
          To compile this driver as a module, choose M here: the
          module will be called bfin_can.
 
-config CAN_JANZ_ICAN3
-       tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
-       depends on MFD_JANZ_CMODIO
-       ---help---
-         Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
-         connects to a MODULbus carrier board.
-
-         This driver can also be built as a module. If so, the module will be
-         called janz-ican3.ko.
-
 config CAN_FLEXCAN
        tristate "Support for Freescale FLEXCAN based chips"
        depends on ARM || PPC
        ---help---
          Say Y here if you want to support for Freescale FlexCAN.
 
-config PCH_CAN
-       tristate "Intel EG20T PCH CAN controller"
-       depends on PCI && (X86_32 || COMPILE_TEST)
-       ---help---
-         This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
-         is an IOH for x86 embedded processor (Intel Atom E6xx series).
-         This driver can access CAN bus.
-
 config CAN_GRCAN
        tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
        depends on OF && HAS_DMA
@@ -119,9 +94,19 @@ config CAN_GRCAN
          endian syntheses of the cores would need some modifications on
          the hardware level to work.
 
+config CAN_JANZ_ICAN3
+       tristate "Janz VMOD-ICAN3 Intelligent CAN controller"
+       depends on MFD_JANZ_CMODIO
+       ---help---
+         Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which
+         connects to a MODULbus carrier board.
+
+         This driver can also be built as a module. If so, the module will be
+         called janz-ican3.ko.
+
 config CAN_RCAR
        tristate "Renesas R-Car CAN controller"
-       depends on ARM
+       depends on ARCH_RENESAS || ARM
        ---help---
          Say Y here if you want to use CAN controller found on Renesas R-Car
          SoCs.
@@ -139,6 +124,13 @@ config CAN_SUN4I
          To compile this driver as a module, choose M here: the module will
          be called sun4i_can.
 
+config CAN_TI_HECC
+       depends on ARM
+       tristate "TI High End CAN Controller"
+       ---help---
+         Driver for TI HECC (High End CAN Controller) module found on many
+         TI devices. The device specifications are available from www.ti.com
+
 config CAN_XILINXCAN
        tristate "Xilinx CAN"
        depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST
@@ -147,22 +139,24 @@ config CAN_XILINXCAN
          Xilinx CAN driver. This driver supports both soft AXI CAN IP and
          Zynq CANPS IP.
 
-source "drivers/net/can/mscan/Kconfig"
-
-source "drivers/net/can/sja1000/Kconfig"
+config PCH_CAN
+       tristate "Intel EG20T PCH CAN controller"
+       depends on PCI && (X86_32 || COMPILE_TEST)
+       ---help---
+         This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which
+         is an IOH for x86 embedded processor (Intel Atom E6xx series).
+         This driver can access CAN bus.
 
 source "drivers/net/can/c_can/Kconfig"
-
-source "drivers/net/can/m_can/Kconfig"
-
 source "drivers/net/can/cc770/Kconfig"
-
+source "drivers/net/can/ifi_canfd/Kconfig"
+source "drivers/net/can/m_can/Kconfig"
+source "drivers/net/can/mscan/Kconfig"
+source "drivers/net/can/sja1000/Kconfig"
+source "drivers/net/can/softing/Kconfig"
 source "drivers/net/can/spi/Kconfig"
-
 source "drivers/net/can/usb/Kconfig"
 
-source "drivers/net/can/softing/Kconfig"
-
 endif
 
 config CAN_DEBUG_DEVICES
index 1f21cef1d458a293c15bcab1fdb9ea6a8f470443..e3db0c807f5528e748b7d1a66d22704b97f7cb13 100644 (file)
@@ -14,21 +14,22 @@ obj-y                               += spi/
 obj-y                          += usb/
 obj-y                          += softing/
 
-obj-$(CONFIG_CAN_SJA1000)      += sja1000/
-obj-$(CONFIG_CAN_MSCAN)                += mscan/
-obj-$(CONFIG_CAN_C_CAN)                += c_can/
-obj-$(CONFIG_CAN_M_CAN)                += m_can/
-obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_AT91)         += at91_can.o
-obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
 obj-$(CONFIG_CAN_BFIN)         += bfin_can.o
-obj-$(CONFIG_CAN_JANZ_ICAN3)   += janz-ican3.o
+obj-$(CONFIG_CAN_CC770)                += cc770/
+obj-$(CONFIG_CAN_C_CAN)                += c_can/
 obj-$(CONFIG_CAN_FLEXCAN)      += flexcan.o
-obj-$(CONFIG_PCH_CAN)          += pch_can.o
 obj-$(CONFIG_CAN_GRCAN)                += grcan.o
+obj-$(CONFIG_CAN_IFI_CANFD)    += ifi_canfd/
+obj-$(CONFIG_CAN_JANZ_ICAN3)   += janz-ican3.o
+obj-$(CONFIG_CAN_MSCAN)                += mscan/
+obj-$(CONFIG_CAN_M_CAN)                += m_can/
 obj-$(CONFIG_CAN_RCAR)         += rcar_can.o
+obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_SUN4I)                += sun4i_can.o
+obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
 obj-$(CONFIG_CAN_XILINXCAN)    += xilinx_can.o
+obj-$(CONFIG_PCH_CAN)          += pch_can.o
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
 subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG
diff --git a/drivers/net/can/ifi_canfd/Kconfig b/drivers/net/can/ifi_canfd/Kconfig
new file mode 100644 (file)
index 0000000..9e8934f
--- /dev/null
@@ -0,0 +1,8 @@
+config CAN_IFI_CANFD
+       depends on HAS_IOMEM
+       tristate "IFI CAN_FD IP"
+       ---help---
+         This driver adds support for the I/F/I CAN_FD soft IP block
+         connected to the "platform bus" (Linux abstraction for directly
+         to the processor attached devices). The CAN_FD is most often
+         synthesised into an FPGA or CPLD.
diff --git a/drivers/net/can/ifi_canfd/Makefile b/drivers/net/can/ifi_canfd/Makefile
new file mode 100644 (file)
index 0000000..b229960
--- /dev/null
@@ -0,0 +1,5 @@
+#
+#  Makefile for the IFI CANFD controller driver.
+#
+
+obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd.o
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
new file mode 100644 (file)
index 0000000..a1bd54f
--- /dev/null
@@ -0,0 +1,944 @@
+/*
+ * CAN bus driver for IFI CANFD controller
+ *
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Details about this controller can be found at
+ * http://www.ifi-pld.de/IP/CANFD/canfd.html
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+#define IFI_CANFD_STCMD                                0x0
+#define IFI_CANFD_STCMD_HARDRESET              0xDEADCAFD
+#define IFI_CANFD_STCMD_ENABLE                 BIT(0)
+#define IFI_CANFD_STCMD_ERROR_ACTIVE           BIT(2)
+#define IFI_CANFD_STCMD_ERROR_PASSIVE          BIT(3)
+#define IFI_CANFD_STCMD_BUSOFF                 BIT(4)
+#define IFI_CANFD_STCMD_BUSMONITOR             BIT(16)
+#define IFI_CANFD_STCMD_LOOPBACK               BIT(18)
+#define IFI_CANFD_STCMD_DISABLE_CANFD          BIT(24)
+#define IFI_CANFD_STCMD_ENABLE_ISO             BIT(25)
+#define IFI_CANFD_STCMD_NORMAL_MODE            ((u32)BIT(31))
+
+#define IFI_CANFD_RXSTCMD                      0x4
+#define IFI_CANFD_RXSTCMD_REMOVE_MSG           BIT(0)
+#define IFI_CANFD_RXSTCMD_RESET                        BIT(7)
+#define IFI_CANFD_RXSTCMD_EMPTY                        BIT(8)
+#define IFI_CANFD_RXSTCMD_OVERFLOW             BIT(13)
+
+#define IFI_CANFD_TXSTCMD                      0x8
+#define IFI_CANFD_TXSTCMD_ADD_MSG              BIT(0)
+#define IFI_CANFD_TXSTCMD_HIGH_PRIO            BIT(1)
+#define IFI_CANFD_TXSTCMD_RESET                        BIT(7)
+#define IFI_CANFD_TXSTCMD_EMPTY                        BIT(8)
+#define IFI_CANFD_TXSTCMD_FULL                 BIT(12)
+#define IFI_CANFD_TXSTCMD_OVERFLOW             BIT(13)
+
+#define IFI_CANFD_INTERRUPT                    0xc
+#define IFI_CANFD_INTERRUPT_ERROR_WARNING      ((u32)BIT(1))
+#define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY       BIT(16)
+#define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE      BIT(22)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY      BIT(24)
+#define IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER  BIT(25)
+#define IFI_CANFD_INTERRUPT_SET_IRQ            ((u32)BIT(31))
+
+#define IFI_CANFD_IRQMASK                      0x10
+#define IFI_CANFD_IRQMASK_SET_ERR              BIT(7)
+#define IFI_CANFD_IRQMASK_SET_TS               BIT(15)
+#define IFI_CANFD_IRQMASK_TXFIFO_EMPTY         BIT(16)
+#define IFI_CANFD_IRQMASK_SET_TX               BIT(23)
+#define IFI_CANFD_IRQMASK_RXFIFO_NEMPTY                BIT(24)
+#define IFI_CANFD_IRQMASK_SET_RX               ((u32)BIT(31))
+
+#define IFI_CANFD_TIME                         0x14
+#define IFI_CANFD_FTIME                                0x18
+#define IFI_CANFD_TIME_TIMEB_OFF               0
+#define IFI_CANFD_TIME_TIMEA_OFF               8
+#define IFI_CANFD_TIME_PRESCALE_OFF            16
+#define IFI_CANFD_TIME_SJW_OFF_ISO             25
+#define IFI_CANFD_TIME_SJW_OFF_BOSCH           28
+#define IFI_CANFD_TIME_SET_SJW_BOSCH           BIT(6)
+#define IFI_CANFD_TIME_SET_TIMEB_BOSCH         BIT(7)
+#define IFI_CANFD_TIME_SET_PRESC_BOSCH         BIT(14)
+#define IFI_CANFD_TIME_SET_TIMEA_BOSCH         BIT(15)
+
+#define IFI_CANFD_TDELAY                       0x1c
+
+#define IFI_CANFD_ERROR                                0x20
+#define IFI_CANFD_ERROR_TX_OFFSET              0
+#define IFI_CANFD_ERROR_TX_MASK                        0xff
+#define IFI_CANFD_ERROR_RX_OFFSET              16
+#define IFI_CANFD_ERROR_RX_MASK                        0xff
+
+#define IFI_CANFD_ERRCNT                       0x24
+
+#define IFI_CANFD_SUSPEND                      0x28
+
+#define IFI_CANFD_REPEAT                       0x2c
+
+#define IFI_CANFD_TRAFFIC                      0x30
+
+#define IFI_CANFD_TSCONTROL                    0x34
+
+#define IFI_CANFD_TSC                          0x38
+
+#define IFI_CANFD_TST                          0x3c
+
+#define IFI_CANFD_RES1                         0x40
+
+#define IFI_CANFD_RES2                         0x44
+
+#define IFI_CANFD_PAR                          0x48
+
+#define IFI_CANFD_CANCLOCK                     0x4c
+
+#define IFI_CANFD_SYSCLOCK                     0x50
+
+#define IFI_CANFD_VER                          0x54
+
+#define IFI_CANFD_IP_ID                                0x58
+#define IFI_CANFD_IP_ID_VALUE                  0xD073CAFD
+
+#define IFI_CANFD_TEST                         0x5c
+
+#define IFI_CANFD_RXFIFO_TS_63_32              0x60
+
+#define IFI_CANFD_RXFIFO_TS_31_0               0x64
+
+#define IFI_CANFD_RXFIFO_DLC                   0x68
+#define IFI_CANFD_RXFIFO_DLC_DLC_OFFSET                0
+#define IFI_CANFD_RXFIFO_DLC_DLC_MASK          0xf
+#define IFI_CANFD_RXFIFO_DLC_RTR               BIT(4)
+#define IFI_CANFD_RXFIFO_DLC_EDL               BIT(5)
+#define IFI_CANFD_RXFIFO_DLC_BRS               BIT(6)
+#define IFI_CANFD_RXFIFO_DLC_ESI               BIT(7)
+#define IFI_CANFD_RXFIFO_DLC_OBJ_OFFSET                8
+#define IFI_CANFD_RXFIFO_DLC_OBJ_MASK          0x1ff
+#define IFI_CANFD_RXFIFO_DLC_FNR_OFFSET                24
+#define IFI_CANFD_RXFIFO_DLC_FNR_MASK          0xff
+
+#define IFI_CANFD_RXFIFO_ID                    0x6c
+#define IFI_CANFD_RXFIFO_ID_ID_OFFSET          0
+#define IFI_CANFD_RXFIFO_ID_ID_STD_MASK                CAN_SFF_MASK
+#define IFI_CANFD_RXFIFO_ID_ID_STD_OFFSET      0
+#define IFI_CANFD_RXFIFO_ID_ID_STD_WIDTH       10
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_MASK                CAN_EFF_MASK
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET      11
+#define IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH       18
+#define IFI_CANFD_RXFIFO_ID_IDE                        BIT(29)
+
+#define IFI_CANFD_RXFIFO_DATA                  0x70    /* 0x70..0xac */
+
+#define IFI_CANFD_TXFIFO_SUSPEND_US            0xb0
+
+#define IFI_CANFD_TXFIFO_REPEATCOUNT           0xb4
+
+#define IFI_CANFD_TXFIFO_DLC                   0xb8
+#define IFI_CANFD_TXFIFO_DLC_DLC_OFFSET                0
+#define IFI_CANFD_TXFIFO_DLC_DLC_MASK          0xf
+#define IFI_CANFD_TXFIFO_DLC_RTR               BIT(4)
+#define IFI_CANFD_TXFIFO_DLC_EDL               BIT(5)
+#define IFI_CANFD_TXFIFO_DLC_BRS               BIT(6)
+#define IFI_CANFD_TXFIFO_DLC_FNR_OFFSET                24
+#define IFI_CANFD_TXFIFO_DLC_FNR_MASK          0xff
+
+#define IFI_CANFD_TXFIFO_ID                    0xbc
+#define IFI_CANFD_TXFIFO_ID_ID_OFFSET          0
+#define IFI_CANFD_TXFIFO_ID_ID_STD_MASK                CAN_SFF_MASK
+#define IFI_CANFD_TXFIFO_ID_ID_STD_OFFSET      0
+#define IFI_CANFD_TXFIFO_ID_ID_STD_WIDTH       10
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_MASK                CAN_EFF_MASK
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET      11
+#define IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH       18
+#define IFI_CANFD_TXFIFO_ID_IDE                        BIT(29)
+
+#define IFI_CANFD_TXFIFO_DATA                  0xc0    /* 0xb0..0xfc */
+
+#define IFI_CANFD_FILTER_MASK(n)               (0x800 + ((n) * 8) + 0)
+#define IFI_CANFD_FILTER_MASK_EXT              BIT(29)
+#define IFI_CANFD_FILTER_MASK_EDL              BIT(30)
+#define IFI_CANFD_FILTER_MASK_VALID            ((u32)BIT(31))
+
+#define IFI_CANFD_FILTER_IDENT(n)              (0x800 + ((n) * 8) + 4)
+#define IFI_CANFD_FILTER_IDENT_IDE             BIT(29)
+#define IFI_CANFD_FILTER_IDENT_CANFD           BIT(30)
+#define IFI_CANFD_FILTER_IDENT_VALID           ((u32)BIT(31))
+
+/* IFI CANFD private data structure */
+struct ifi_canfd_priv {
+       struct can_priv         can;    /* must be the first member */
+       struct napi_struct      napi;
+       struct net_device       *ndev;
+       void __iomem            *base;
+};
+
+static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       u32 enirq = 0;
+
+       if (enable) {
+               enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
+                       IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
+       }
+
+       writel(IFI_CANFD_IRQMASK_SET_ERR |
+              IFI_CANFD_IRQMASK_SET_TS |
+              IFI_CANFD_IRQMASK_SET_TX |
+              IFI_CANFD_IRQMASK_SET_RX | enirq,
+              priv->base + IFI_CANFD_IRQMASK);
+}
+
+static void ifi_canfd_read_fifo(struct net_device *ndev)
+{
+       struct net_device_stats *stats = &ndev->stats;
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       struct canfd_frame *cf;
+       struct sk_buff *skb;
+       const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
+                               IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
+       u32 rxdlc, rxid;
+       u32 dlc, id;
+       int i;
+
+       rxdlc = readl(priv->base + IFI_CANFD_RXFIFO_DLC);
+       if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+               skb = alloc_canfd_skb(ndev, &cf);
+       else
+               skb = alloc_can_skb(ndev, (struct can_frame **)&cf);
+
+       if (!skb) {
+               stats->rx_dropped++;
+               return;
+       }
+
+       dlc = (rxdlc >> IFI_CANFD_RXFIFO_DLC_DLC_OFFSET) &
+             IFI_CANFD_RXFIFO_DLC_DLC_MASK;
+       if (rxdlc & IFI_CANFD_RXFIFO_DLC_EDL)
+               cf->len = can_dlc2len(dlc);
+       else
+               cf->len = get_can_dlc(dlc);
+
+       rxid = readl(priv->base + IFI_CANFD_RXFIFO_ID);
+       id = (rxid >> IFI_CANFD_RXFIFO_ID_ID_OFFSET);
+       if (id & IFI_CANFD_RXFIFO_ID_IDE) {
+               id &= IFI_CANFD_RXFIFO_ID_ID_XTD_MASK;
+               /*
+                * In case the Extended ID frame is received, the standard
+                * and extended part of the ID are swapped in the register,
+                * so swap them back to obtain the correct ID.
+                */
+               id = (id >> IFI_CANFD_RXFIFO_ID_ID_XTD_OFFSET) |
+                    ((id & IFI_CANFD_RXFIFO_ID_ID_STD_MASK) <<
+                      IFI_CANFD_RXFIFO_ID_ID_XTD_WIDTH);
+               id |= CAN_EFF_FLAG;
+       } else {
+               id &= IFI_CANFD_RXFIFO_ID_ID_STD_MASK;
+       }
+       cf->can_id = id;
+
+       if (rxdlc & IFI_CANFD_RXFIFO_DLC_ESI) {
+               cf->flags |= CANFD_ESI;
+               netdev_dbg(ndev, "ESI Error\n");
+       }
+
+       if (!(rxdlc & IFI_CANFD_RXFIFO_DLC_EDL) &&
+           (rxdlc & IFI_CANFD_RXFIFO_DLC_RTR)) {
+               cf->can_id |= CAN_RTR_FLAG;
+       } else {
+               if (rxdlc & IFI_CANFD_RXFIFO_DLC_BRS)
+                       cf->flags |= CANFD_BRS;
+
+               for (i = 0; i < cf->len; i += 4) {
+                       *(u32 *)(cf->data + i) =
+                               readl(priv->base + IFI_CANFD_RXFIFO_DATA + i);
+               }
+       }
+
+       /* Remove the packet from FIFO */
+       writel(IFI_CANFD_RXSTCMD_REMOVE_MSG, priv->base + IFI_CANFD_RXSTCMD);
+       writel(rx_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->len;
+
+       netif_receive_skb(skb);
+}
+
+static int ifi_canfd_do_rx_poll(struct net_device *ndev, int quota)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       u32 pkts = 0;
+       u32 rxst;
+
+       rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+       if (rxst & IFI_CANFD_RXSTCMD_EMPTY) {
+               netdev_dbg(ndev, "No messages in RX FIFO\n");
+               return 0;
+       }
+
+       for (;;) {
+               if (rxst & IFI_CANFD_RXSTCMD_EMPTY)
+                       break;
+               if (quota <= 0)
+                       break;
+
+               ifi_canfd_read_fifo(ndev);
+               quota--;
+               pkts++;
+               rxst = readl(priv->base + IFI_CANFD_RXSTCMD);
+       }
+
+       if (pkts)
+               can_led_event(ndev, CAN_LED_EVENT_RX);
+
+       return pkts;
+}
+
+static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
+{
+       struct net_device_stats *stats = &ndev->stats;
+       struct sk_buff *skb;
+       struct can_frame *frame;
+
+       netdev_err(ndev, "RX FIFO overflow, message(s) lost.\n");
+
+       stats->rx_errors++;
+       stats->rx_over_errors++;
+
+       skb = alloc_can_err_skb(ndev, &frame);
+       if (unlikely(!skb))
+               return 0;
+
+       frame->can_id |= CAN_ERR_CRTL;
+       frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int ifi_canfd_get_berr_counter(const struct net_device *ndev,
+                                     struct can_berr_counter *bec)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       u32 err;
+
+       err = readl(priv->base + IFI_CANFD_ERROR);
+       bec->rxerr = (err >> IFI_CANFD_ERROR_RX_OFFSET) &
+                    IFI_CANFD_ERROR_RX_MASK;
+       bec->txerr = (err >> IFI_CANFD_ERROR_TX_OFFSET) &
+                    IFI_CANFD_ERROR_TX_MASK;
+
+       return 0;
+}
+
+static int ifi_canfd_handle_state_change(struct net_device *ndev,
+                                        enum can_state new_state)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       struct net_device_stats *stats = &ndev->stats;
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       struct can_berr_counter bec;
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               priv->can.can_stats.error_warning++;
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               priv->can.can_stats.error_passive++;
+               priv->can.state = CAN_STATE_ERROR_PASSIVE;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               priv->can.state = CAN_STATE_BUS_OFF;
+               ifi_canfd_irq_enable(ndev, 0);
+               priv->can.can_stats.bus_off++;
+               can_bus_off(ndev);
+               break;
+       default:
+               break;
+       }
+
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(ndev, &cf);
+       if (unlikely(!skb))
+               return 0;
+
+       ifi_canfd_get_berr_counter(ndev, &bec);
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = (bec.txerr > bec.rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+               if (bec.txerr > 127)
+                       cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               cf->can_id |= CAN_ERR_BUSOFF;
+               break;
+       default:
+               break;
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       int work_done = 0;
+       u32 isr;
+
+       /*
+        * The ErrWarn condition is a little special, since the bit is
+        * located in the INTERRUPT register instead of STCMD register.
+        */
+       isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+       if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
+           (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+               /* Clear the interrupt */
+               writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
+                      priv->base + IFI_CANFD_INTERRUPT);
+               netdev_dbg(ndev, "Error, entered warning state\n");
+               work_done += ifi_canfd_handle_state_change(ndev,
+                                               CAN_STATE_ERROR_WARNING);
+       }
+
+       if ((stcmd & IFI_CANFD_STCMD_ERROR_PASSIVE) &&
+           (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+               netdev_dbg(ndev, "Error, entered passive state\n");
+               work_done += ifi_canfd_handle_state_change(ndev,
+                                               CAN_STATE_ERROR_PASSIVE);
+       }
+
+       if ((stcmd & IFI_CANFD_STCMD_BUSOFF) &&
+           (priv->can.state != CAN_STATE_BUS_OFF)) {
+               netdev_dbg(ndev, "Error, entered bus-off state\n");
+               work_done += ifi_canfd_handle_state_change(ndev,
+                                               CAN_STATE_BUS_OFF);
+       }
+
+       return work_done;
+}
+
+static int ifi_canfd_poll(struct napi_struct *napi, int quota)
+{
+       struct net_device *ndev = napi->dev;
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
+                                    IFI_CANFD_STCMD_BUSOFF;
+       int work_done = 0;
+
+       u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
+       u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
+
+       /* Handle bus state changes */
+       if ((stcmd & stcmd_state_mask) ||
+           ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
+               work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
+
+       /* Handle lost messages on RX */
+       if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
+               work_done += ifi_canfd_handle_lost_msg(ndev);
+
+       /* Handle normal messages on RX */
+       if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
+               work_done += ifi_canfd_do_rx_poll(ndev, quota - work_done);
+
+       if (work_done < quota) {
+               napi_complete(napi);
+               ifi_canfd_irq_enable(ndev, 1);
+       }
+
+       return work_done;
+}
+
+static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
+{
+       struct net_device *ndev = (struct net_device *)dev_id;
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       struct net_device_stats *stats = &ndev->stats;
+       const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
+                               IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER;
+       const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
+                               IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
+       const u32 clr_irq_mask = ~(IFI_CANFD_INTERRUPT_SET_IRQ |
+                                  IFI_CANFD_INTERRUPT_ERROR_WARNING);
+       u32 isr;
+
+       isr = readl(priv->base + IFI_CANFD_INTERRUPT);
+
+       /* No interrupt */
+       if (isr == 0)
+               return IRQ_NONE;
+
+       /* Clear all pending interrupts but ErrWarn */
+       writel(clr_irq_mask, priv->base + IFI_CANFD_INTERRUPT);
+
+       /* RX IRQ, start NAPI */
+       if (isr & rx_irq_mask) {
+               ifi_canfd_irq_enable(ndev, 0);
+               napi_schedule(&priv->napi);
+       }
+
+       /* TX IRQ */
+       if (isr & tx_irq_mask) {
+               stats->tx_bytes += can_get_echo_skb(ndev, 0);
+               stats->tx_packets++;
+               can_led_event(ndev, CAN_LED_EVENT_TX);
+               netif_wake_queue(ndev);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const ifi_canfd_bittiming_const = {
+       .name           = KBUILD_MODNAME,
+       .tseg1_min      = 1,    /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max      = 64,
+       .tseg2_min      = 2,    /* Time segment 2 = phase_seg2 */
+       .tseg2_max      = 64,
+       .sjw_max        = 16,
+       .brp_min        = 2,
+       .brp_max        = 256,
+       .brp_inc        = 1,
+};
+
+static const struct can_bittiming_const ifi_canfd_data_bittiming_const = {
+       .name           = KBUILD_MODNAME,
+       .tseg1_min      = 1,    /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max      = 64,
+       .tseg2_min      = 2,    /* Time segment 2 = phase_seg2 */
+       .tseg2_max      = 64,
+       .sjw_max        = 16,
+       .brp_min        = 2,
+       .brp_max        = 256,
+       .brp_inc        = 1,
+};
+
+static void ifi_canfd_set_bittiming(struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       const struct can_bittiming *bt = &priv->can.bittiming;
+       const struct can_bittiming *dbt = &priv->can.data_bittiming;
+       u16 brp, sjw, tseg1, tseg2;
+       u32 noniso_arg = 0;
+       u32 time_off;
+
+       if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
+           !(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) {
+               time_off = IFI_CANFD_TIME_SJW_OFF_ISO;
+       } else {
+               noniso_arg = IFI_CANFD_TIME_SET_TIMEB_BOSCH |
+                            IFI_CANFD_TIME_SET_TIMEA_BOSCH |
+                            IFI_CANFD_TIME_SET_PRESC_BOSCH |
+                            IFI_CANFD_TIME_SET_SJW_BOSCH;
+               time_off = IFI_CANFD_TIME_SJW_OFF_BOSCH;
+       }
+
+       /* Configure bit timing */
+       brp = bt->brp - 2;
+       sjw = bt->sjw - 1;
+       tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+       tseg2 = bt->phase_seg2 - 2;
+       writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+              (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+              (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+              (sjw << time_off) |
+              noniso_arg,
+              priv->base + IFI_CANFD_TIME);
+
+       /* Configure data bit timing */
+       brp = dbt->brp - 2;
+       sjw = dbt->sjw - 1;
+       tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
+       tseg2 = dbt->phase_seg2 - 2;
+       writel((tseg2 << IFI_CANFD_TIME_TIMEB_OFF) |
+              (tseg1 << IFI_CANFD_TIME_TIMEA_OFF) |
+              (brp << IFI_CANFD_TIME_PRESCALE_OFF) |
+              (sjw << time_off) |
+              noniso_arg,
+              priv->base + IFI_CANFD_FTIME);
+}
+
+static void ifi_canfd_set_filter(struct net_device *ndev, const u32 id,
+                                const u32 mask, const u32 ident)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+       writel(mask, priv->base + IFI_CANFD_FILTER_MASK(id));
+       writel(ident, priv->base + IFI_CANFD_FILTER_IDENT(id));
+}
+
+static void ifi_canfd_set_filters(struct net_device *ndev)
+{
+       /* Receive all CAN frames (standard ID) */
+       ifi_canfd_set_filter(ndev, 0,
+                            IFI_CANFD_FILTER_MASK_VALID |
+                            IFI_CANFD_FILTER_MASK_EXT,
+                            IFI_CANFD_FILTER_IDENT_VALID);
+
+       /* Receive all CAN frames (extended ID) */
+       ifi_canfd_set_filter(ndev, 1,
+                            IFI_CANFD_FILTER_MASK_VALID |
+                            IFI_CANFD_FILTER_MASK_EXT,
+                            IFI_CANFD_FILTER_IDENT_VALID |
+                            IFI_CANFD_FILTER_IDENT_IDE);
+
+       /* Receive all CANFD frames */
+       ifi_canfd_set_filter(ndev, 2,
+                            IFI_CANFD_FILTER_MASK_VALID |
+                            IFI_CANFD_FILTER_MASK_EDL |
+                            IFI_CANFD_FILTER_MASK_EXT,
+                            IFI_CANFD_FILTER_IDENT_VALID |
+                            IFI_CANFD_FILTER_IDENT_CANFD |
+                            IFI_CANFD_FILTER_IDENT_IDE);
+}
+
+static void ifi_canfd_start(struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       u32 stcmd;
+
+       /* Reset the IP */
+       writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+       writel(0, priv->base + IFI_CANFD_STCMD);
+
+       ifi_canfd_set_bittiming(ndev);
+       ifi_canfd_set_filters(ndev);
+
+       /* Reset FIFOs */
+       writel(IFI_CANFD_RXSTCMD_RESET, priv->base + IFI_CANFD_RXSTCMD);
+       writel(0, priv->base + IFI_CANFD_RXSTCMD);
+       writel(IFI_CANFD_TXSTCMD_RESET, priv->base + IFI_CANFD_TXSTCMD);
+       writel(0, priv->base + IFI_CANFD_TXSTCMD);
+
+       /* Repeat transmission until successful */
+       writel(0, priv->base + IFI_CANFD_REPEAT);
+       writel(0, priv->base + IFI_CANFD_SUSPEND);
+
+       /* Clear all pending interrupts */
+       writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+              priv->base + IFI_CANFD_INTERRUPT);
+
+       stcmd = IFI_CANFD_STCMD_ENABLE | IFI_CANFD_STCMD_NORMAL_MODE;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               stcmd |= IFI_CANFD_STCMD_BUSMONITOR;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
+               stcmd |= IFI_CANFD_STCMD_LOOPBACK;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+               stcmd |= IFI_CANFD_STCMD_ENABLE_ISO;
+
+       if (!(priv->can.ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)))
+               stcmd |= IFI_CANFD_STCMD_DISABLE_CANFD;
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       ifi_canfd_irq_enable(ndev, 1);
+
+       /* Enable controller */
+       writel(stcmd, priv->base + IFI_CANFD_STCMD);
+}
+
+static void ifi_canfd_stop(struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+       /* Reset the IP */
+       writel(IFI_CANFD_STCMD_HARDRESET, priv->base + IFI_CANFD_STCMD);
+
+       /* Mask all interrupts */
+       writel(~0, priv->base + IFI_CANFD_IRQMASK);
+
+       /* Clear all pending interrupts */
+       writel((u32)(~IFI_CANFD_INTERRUPT_SET_IRQ),
+              priv->base + IFI_CANFD_INTERRUPT);
+
+       /* Set the state as STOPPED */
+       priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int ifi_canfd_set_mode(struct net_device *ndev, enum can_mode mode)
+{
+       switch (mode) {
+       case CAN_MODE_START:
+               ifi_canfd_start(ndev);
+               netif_wake_queue(ndev);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int ifi_canfd_open(struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       int ret;
+
+       ret = open_candev(ndev);
+       if (ret) {
+               netdev_err(ndev, "Failed to open CAN device\n");
+               return ret;
+       }
+
+       /* Register interrupt handler */
+       ret = request_irq(ndev->irq, ifi_canfd_isr, IRQF_SHARED,
+                         ndev->name, ndev);
+       if (ret < 0) {
+               netdev_err(ndev, "Failed to request interrupt\n");
+               goto err_irq;
+       }
+
+       ifi_canfd_start(ndev);
+
+       can_led_event(ndev, CAN_LED_EVENT_OPEN);
+       napi_enable(&priv->napi);
+       netif_start_queue(ndev);
+
+       return 0;
+err_irq:
+       close_candev(ndev);
+       return ret;
+}
+
+static int ifi_canfd_close(struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+
+       netif_stop_queue(ndev);
+       napi_disable(&priv->napi);
+
+       ifi_canfd_stop(ndev);
+
+       free_irq(ndev->irq, ndev);
+
+       close_candev(ndev);
+
+       can_led_event(ndev, CAN_LED_EVENT_STOP);
+
+       return 0;
+}
+
+static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
+                                       struct net_device *ndev)
+{
+       struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+       u32 txst, txid, txdlc;
+       int i;
+
+       if (can_dropped_invalid_skb(ndev, skb))
+               return NETDEV_TX_OK;
+
+       /* Check if the TX buffer is full */
+       txst = readl(priv->base + IFI_CANFD_TXSTCMD);
+       if (txst & IFI_CANFD_TXSTCMD_FULL) {
+               netif_stop_queue(ndev);
+               netdev_err(ndev, "BUG! TX FIFO full when queue awake!\n");
+               return NETDEV_TX_BUSY;
+       }
+
+       netif_stop_queue(ndev);
+
+       if (cf->can_id & CAN_EFF_FLAG) {
+               txid = cf->can_id & CAN_EFF_MASK;
+               /*
+                * In case the Extended ID frame is transmitted, the
+                * standard and extended part of the ID are swapped
+                * in the register, so swap them back to send the
+                * correct ID.
+                */
+               txid = (txid >> IFI_CANFD_TXFIFO_ID_ID_XTD_WIDTH) |
+                      ((txid & IFI_CANFD_TXFIFO_ID_ID_XTD_MASK) <<
+                        IFI_CANFD_TXFIFO_ID_ID_XTD_OFFSET);
+               txid |= IFI_CANFD_TXFIFO_ID_IDE;
+       } else {
+               txid = cf->can_id & CAN_SFF_MASK;
+       }
+
+       txdlc = can_len2dlc(cf->len);
+       if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) && can_is_canfd_skb(skb)) {
+               txdlc |= IFI_CANFD_TXFIFO_DLC_EDL;
+               if (cf->flags & CANFD_BRS)
+                       txdlc |= IFI_CANFD_TXFIFO_DLC_BRS;
+       }
+
+       if (cf->can_id & CAN_RTR_FLAG)
+               txdlc |= IFI_CANFD_TXFIFO_DLC_RTR;
+
+       /* message ram configuration */
+       writel(txid, priv->base + IFI_CANFD_TXFIFO_ID);
+       writel(txdlc, priv->base + IFI_CANFD_TXFIFO_DLC);
+
+       for (i = 0; i < cf->len; i += 4) {
+               writel(*(u32 *)(cf->data + i),
+                      priv->base + IFI_CANFD_TXFIFO_DATA + i);
+       }
+
+       writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
+       writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
+
+       can_put_echo_skb(skb, ndev, 0);
+
+       /* Start the transmission */
+       writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
+
+       return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops ifi_canfd_netdev_ops = {
+       .ndo_open       = ifi_canfd_open,
+       .ndo_stop       = ifi_canfd_close,
+       .ndo_start_xmit = ifi_canfd_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
+};
+
+static int ifi_canfd_plat_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct net_device *ndev;
+       struct ifi_canfd_priv *priv;
+       struct resource *res;
+       void __iomem *addr;
+       int irq, ret;
+       u32 id;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       addr = devm_ioremap_resource(dev, res);
+       irq = platform_get_irq(pdev, 0);
+       if (IS_ERR(addr) || irq < 0)
+               return -EINVAL;
+
+       id = readl(addr + IFI_CANFD_IP_ID);
+       if (id != IFI_CANFD_IP_ID_VALUE) {
+               dev_err(dev, "This block is not IFI CANFD, id=%08x\n", id);
+               return -EINVAL;
+       }
+
+       ndev = alloc_candev(sizeof(*priv), 1);
+       if (!ndev)
+               return -ENOMEM;
+
+       ndev->irq = irq;
+       ndev->flags |= IFF_ECHO;        /* we support local echo */
+       ndev->netdev_ops = &ifi_canfd_netdev_ops;
+
+       priv = netdev_priv(ndev);
+       priv->ndev = ndev;
+       priv->base = addr;
+
+       netif_napi_add(ndev, &priv->napi, ifi_canfd_poll, 64);
+
+       priv->can.state = CAN_STATE_STOPPED;
+
+       priv->can.clock.freq = readl(addr + IFI_CANFD_CANCLOCK);
+
+       priv->can.bittiming_const       = &ifi_canfd_bittiming_const;
+       priv->can.data_bittiming_const  = &ifi_canfd_data_bittiming_const;
+       priv->can.do_set_mode           = ifi_canfd_set_mode;
+       priv->can.do_get_berr_counter   = ifi_canfd_get_berr_counter;
+
+       /* IFI CANFD can do both Bosch FD and ISO FD */
+       priv->can.ctrlmode = CAN_CTRLMODE_FD;
+
+       /* IFI CANFD can do both Bosch FD and ISO FD */
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+                                      CAN_CTRLMODE_LISTENONLY |
+                                      CAN_CTRLMODE_FD |
+                                      CAN_CTRLMODE_FD_NON_ISO;
+
+       platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, dev);
+
+       ret = register_candev(ndev);
+       if (ret) {
+               dev_err(dev, "Failed to register (ret=%d)\n", ret);
+               goto err_reg;
+       }
+
+       devm_can_led_init(ndev);
+
+       dev_info(dev, "Driver registered: regs=%p, irq=%d, clock=%d\n",
+                priv->base, ndev->irq, priv->can.clock.freq);
+
+       return 0;
+
+err_reg:
+       free_candev(ndev);
+       return ret;
+}
+
+static int ifi_canfd_plat_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       unregister_candev(ndev);
+       platform_set_drvdata(pdev, NULL);
+       free_candev(ndev);
+
+       return 0;
+}
+
+static const struct of_device_id ifi_canfd_of_table[] = {
+       { .compatible = "ifi,canfd-1.0", .data = NULL },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ifi_canfd_of_table);
+
+static struct platform_driver ifi_canfd_plat_driver = {
+       .driver = {
+               .name           = KBUILD_MODNAME,
+               .of_match_table = ifi_canfd_of_table,
+       },
+       .probe  = ifi_canfd_plat_probe,
+       .remove = ifi_canfd_plat_remove,
+};
+
+module_platform_driver(ifi_canfd_plat_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for IFI CANFD controller");
index bc46be39549d2ab317862ba376ccb063be65b7be..788459f6bf5cc6a71c5e914d282a0e7bd5542791 100644 (file)
@@ -904,6 +904,9 @@ static const struct of_device_id rcar_can_of_table[] __maybe_unused = {
        { .compatible = "renesas,can-r8a7779" },
        { .compatible = "renesas,can-r8a7790" },
        { .compatible = "renesas,can-r8a7791" },
+       { .compatible = "renesas,rcar-gen1-can" },
+       { .compatible = "renesas,rcar-gen2-can" },
+       { .compatible = "renesas,rcar-gen3-can" },
        { }
 };
 MODULE_DEVICE_TABLE(of, rcar_can_of_table);
index 0552ed46a206c5af03785bb63adbf3c2b0b43f69..dc9c6db96c3caeee4965aed9bfb487fec2b791a2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/can/platform/sja1000.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_irq.h>
 
 #include "sja1000.h"
@@ -40,6 +41,15 @@ MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_LICENSE("GPL v2");
 
+struct sja1000_of_data {
+       size_t  priv_sz;
+       int     (*init)(struct sja1000_priv *priv, struct device_node *of);
+};
+
+struct technologic_priv {
+       spinlock_t      io_lock;
+};
+
 static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
 {
        return ioread8(priv->reg_base + reg);
@@ -70,6 +80,43 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
        iowrite8(val, priv->reg_base + reg * 4);
 }
 
+static u8 sp_technologic_read_reg16(const struct sja1000_priv *priv, int reg)
+{
+       struct technologic_priv *tp = priv->priv;
+       unsigned long flags;
+       u8 val;
+
+       spin_lock_irqsave(&tp->io_lock, flags);
+       iowrite16(reg, priv->reg_base + 0);
+       val = ioread16(priv->reg_base + 2);
+       spin_unlock_irqrestore(&tp->io_lock, flags);
+
+       return val;
+}
+
+static void sp_technologic_write_reg16(const struct sja1000_priv *priv,
+                                      int reg, u8 val)
+{
+       struct technologic_priv *tp = priv->priv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tp->io_lock, flags);
+       iowrite16(reg, priv->reg_base + 0);
+       iowrite16(val, priv->reg_base + 2);
+       spin_unlock_irqrestore(&tp->io_lock, flags);
+}
+
+static int sp_technologic_init(struct sja1000_priv *priv, struct device_node *of)
+{
+       struct technologic_priv *tp = priv->priv;
+
+       priv->read_reg = sp_technologic_read_reg16;
+       priv->write_reg = sp_technologic_write_reg16;
+       spin_lock_init(&tp->io_lock);
+
+       return 0;
+}
+
 static void sp_populate(struct sja1000_priv *priv,
                        struct sja1000_platform_data *pdata,
                        unsigned long resource_mem_flags)
@@ -154,6 +201,18 @@ static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
                priv->cdr |= CDR_CBP; /* default */
 }
 
+static struct sja1000_of_data technologic_data = {
+       .priv_sz = sizeof(struct technologic_priv),
+       .init = sp_technologic_init,
+};
+
+static const struct of_device_id sp_of_table[] = {
+       { .compatible = "nxp,sja1000", .data = NULL, },
+       { .compatible = "technologic,sja1000", .data = &technologic_data, },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sp_of_table);
+
 static int sp_probe(struct platform_device *pdev)
 {
        int err, irq = 0;
@@ -163,6 +222,9 @@ static int sp_probe(struct platform_device *pdev)
        struct resource *res_mem, *res_irq = NULL;
        struct sja1000_platform_data *pdata;
        struct device_node *of = pdev->dev.of_node;
+       const struct of_device_id *of_id;
+       const struct sja1000_of_data *of_data = NULL;
+       size_t priv_sz = 0;
 
        pdata = dev_get_platdata(&pdev->dev);
        if (!pdata && !of) {
@@ -191,7 +253,13 @@ static int sp_probe(struct platform_device *pdev)
        if (!irq && !res_irq)
                return -ENODEV;
 
-       dev = alloc_sja1000dev(0);
+       of_id = of_match_device(sp_of_table, &pdev->dev);
+       if (of_id && of_id->data) {
+               of_data = of_id->data;
+               priv_sz = of_data->priv_sz;
+       }
+
+       dev = alloc_sja1000dev(priv_sz);
        if (!dev)
                return -ENOMEM;
        priv = netdev_priv(dev);
@@ -208,10 +276,17 @@ static int sp_probe(struct platform_device *pdev)
        dev->irq = irq;
        priv->reg_base = addr;
 
-       if (of)
+       if (of) {
                sp_populate_of(priv, of);
-       else
+
+               if (of_data && of_data->init) {
+                       err = of_data->init(priv, of);
+                       if (err)
+                               goto exit_free;
+               }
+       } else {
                sp_populate(priv, pdata, res_mem->flags);
+       }
 
        platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
@@ -242,12 +317,6 @@ static int sp_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id sp_of_table[] = {
-       {.compatible = "nxp,sja1000"},
-       {},
-};
-MODULE_DEVICE_TABLE(of, sp_of_table);
-
 static struct platform_driver sp_driver = {
        .probe = sp_probe,
        .remove = sp_remove,
index 575790e8a75af8e6184f5611fe133b1d73825679..74a7dfecee2783ac609b9fefbd32f7817b48c43c 100644 (file)
@@ -843,7 +843,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
                if (clear_intf)
                        mcp251x_write_bits(spi, CANINTF, clear_intf, 0x00);
 
-               if (eflag)
+               if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR))
                        mcp251x_write_bits(spi, EFLG, eflag, 0x00);
 
                /* Update can state */
index fc5b75675cd8b6dbebbbc79d357001676900fefa..3400fd1cada7152dbd0ad2c5df4626b52c8bd1a0 100644 (file)
@@ -117,6 +117,9 @@ MODULE_LICENSE("GPL v2");
  */
 #define EMS_USB_ARM7_CLOCK 8000000
 
+#define CPC_TX_QUEUE_TRIGGER_LOW       25
+#define CPC_TX_QUEUE_TRIGGER_HIGH      35
+
 /*
  * CAN-Message representation in a CPC_MSG. Message object type is
  * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or
@@ -278,6 +281,9 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
        switch (urb->status) {
        case 0:
                dev->free_slots = dev->intr_in_buffer[1];
+               if (dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH &&
+                   netif_queue_stopped(netdev))
+                       netif_wake_queue(netdev);
                break;
 
        case -ECONNRESET: /* unlink */
@@ -526,8 +532,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
        /* Release context */
        context->echo_index = MAX_TX_URBS;
 
-       if (netif_queue_stopped(netdev))
-               netif_wake_queue(netdev);
 }
 
 /*
@@ -587,7 +591,7 @@ static int ems_usb_start(struct ems_usb *dev)
        int err, i;
 
        dev->intr_in_buffer[0] = 0;
-       dev->free_slots = 15; /* initial size */
+       dev->free_slots = 50; /* initial size */
 
        for (i = 0; i < MAX_RX_URBS; i++) {
                struct urb *urb = NULL;
@@ -835,7 +839,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
 
                /* Slow down tx path */
                if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS ||
-                   dev->free_slots < 5) {
+                   dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) {
                        netif_stop_queue(netdev);
                }
        }
index 5eee62badf45457798c2fabe5005faa26c6286e2..cbc99d5649afa3877158a0ac37a50b8865a7e8ac 100644 (file)
@@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface
 static void gs_destroy_candev(struct gs_can *dev)
 {
        unregister_candev(dev->netdev);
-       free_candev(dev->netdev);
        usb_kill_anchored_urbs(&dev->tx_submitted);
-       kfree(dev);
+       free_candev(dev->netdev);
 }
 
 static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        for (i = 0; i < icount; i++) {
                dev->canch[i] = gs_make_candev(i, intf);
                if (IS_ERR_OR_NULL(dev->canch[i])) {
+                       /* save error code to return later */
+                       rc = PTR_ERR(dev->canch[i]);
+
                        /* on failure destroy previously created candevs */
                        icount = i;
-                       for (i = 0; i < icount; i++) {
+                       for (i = 0; i < icount; i++)
                                gs_destroy_candev(dev->canch[i]);
-                               dev->canch[i] = NULL;
-                       }
+
+                       usb_kill_anchored_urbs(&dev->rx_submitted);
                        kfree(dev);
                        return rc;
                }
@@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf)
                return;
        }
 
-       for (i = 0; i < GS_MAX_INTF; i++) {
-               struct gs_can *can = dev->canch[i];
-
-               if (!can)
-                       continue;
-
-               gs_destroy_candev(can);
-       }
+       for (i = 0; i < GS_MAX_INTF; i++)
+               if (dev->canch[i])
+                       gs_destroy_candev(dev->canch[i]);
 
        usb_kill_anchored_urbs(&dev->rx_submitted);
+       kfree(dev);
 }
 
 static const struct usb_device_id gs_usb_table[] = {
index 6f946fedbb77c1943770b31665a0f5e1e6e4d889..3f627598f277924b0f418ab23da7b4ac11737e9c 100644 (file)
@@ -483,16 +483,17 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch  *ds, int port)
 }
 
 static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
-                             u32 br_port_mask)
+                             struct net_device *bridge)
 {
        struct bcm_sf2_priv *priv = ds_to_priv(ds);
        unsigned int i;
        u32 reg, p_ctl;
 
+       priv->port_sts[port].bridge_dev = bridge;
        p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
 
        for (i = 0; i < priv->hw_params.num_ports; i++) {
-               if (!((1 << i) & br_port_mask))
+               if (priv->port_sts[i].bridge_dev != bridge)
                        continue;
 
                /* Add this local port to the remote port VLAN control
@@ -515,10 +516,10 @@ static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
-                              u32 br_port_mask)
+static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
 {
        struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       struct net_device *bridge = priv->port_sts[port].bridge_dev;
        unsigned int i;
        u32 reg, p_ctl;
 
@@ -526,7 +527,7 @@ static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
 
        for (i = 0; i < priv->hw_params.num_ports; i++) {
                /* Don't touch the remaining ports */
-               if (!((1 << i) & br_port_mask))
+               if (priv->port_sts[i].bridge_dev != bridge)
                        continue;
 
                reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
@@ -541,6 +542,7 @@ static int bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port,
 
        core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
        priv->port_sts[port].vlan_ctl_mask = p_ctl;
+       priv->port_sts[port].bridge_dev = NULL;
 
        return 0;
 }
index 6bba1c98d764cf2b4222c82211677e30c448a4f0..200b1f5fdb5679ad45b7c1c9fa30a9d381e62b72 100644 (file)
@@ -50,6 +50,8 @@ struct bcm_sf2_port_status {
        struct ethtool_eee eee;
 
        u32 vlan_ctl_mask;
+
+       struct net_device *bridge_dev;
 };
 
 struct bcm_sf2_arl_entry {
index 6e18213b9c04434a1feaae0c87da255859632732..d72ccbdf53ec832cdc123960821e09e46c5b6d8c 100644 (file)
@@ -106,11 +106,11 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
        .port_join_bridge       = mv88e6xxx_port_bridge_join,
        .port_leave_bridge      = mv88e6xxx_port_bridge_leave,
        .port_stp_update        = mv88e6xxx_port_stp_update,
-       .port_pvid_get          = mv88e6xxx_port_pvid_get,
+       .port_vlan_filtering    = mv88e6xxx_port_vlan_filtering,
        .port_vlan_prepare      = mv88e6xxx_port_vlan_prepare,
        .port_vlan_add          = mv88e6xxx_port_vlan_add,
        .port_vlan_del          = mv88e6xxx_port_vlan_del,
-       .vlan_getnext           = mv88e6xxx_vlan_getnext,
+       .port_vlan_dump         = mv88e6xxx_port_vlan_dump,
        .port_fdb_prepare       = mv88e6xxx_port_fdb_prepare,
        .port_fdb_add           = mv88e6xxx_port_fdb_add,
        .port_fdb_del           = mv88e6xxx_port_fdb_del,
index cc6c5455341839eb91ba55dfd23e96e954c41fb7..a41fa5043d77a883a45351044db6ee605ea5d25e 100644 (file)
@@ -25,6 +25,7 @@
 static const struct mv88e6xxx_switch_id mv88e6352_table[] = {
        { PORT_SWITCH_ID_6172, "Marvell 88E6172" },
        { PORT_SWITCH_ID_6176, "Marvell 88E6176" },
+       { PORT_SWITCH_ID_6240, "Marvell 88E6240" },
        { PORT_SWITCH_ID_6320, "Marvell 88E6320" },
        { PORT_SWITCH_ID_6320_A1, "Marvell 88E6320 (A1)" },
        { PORT_SWITCH_ID_6320_A2, "Marvell 88e6320 (A2)" },
@@ -326,11 +327,11 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
        .port_join_bridge       = mv88e6xxx_port_bridge_join,
        .port_leave_bridge      = mv88e6xxx_port_bridge_leave,
        .port_stp_update        = mv88e6xxx_port_stp_update,
-       .port_pvid_get          = mv88e6xxx_port_pvid_get,
+       .port_vlan_filtering    = mv88e6xxx_port_vlan_filtering,
        .port_vlan_prepare      = mv88e6xxx_port_vlan_prepare,
        .port_vlan_add          = mv88e6xxx_port_vlan_add,
        .port_vlan_del          = mv88e6xxx_port_vlan_del,
-       .vlan_getnext           = mv88e6xxx_vlan_getnext,
+       .port_vlan_dump         = mv88e6xxx_port_vlan_dump,
        .port_fdb_prepare       = mv88e6xxx_port_fdb_prepare,
        .port_fdb_add           = mv88e6xxx_port_fdb_add,
        .port_fdb_del           = mv88e6xxx_port_fdb_del,
index cf34681af4f625d07bc43c77d528d632325bdc0d..5f07524083c33a6164d42c8c15b2091ef4b3361f 100644 (file)
@@ -1051,48 +1051,78 @@ static int _mv88e6xxx_atu_remove(struct dsa_switch *ds, u16 fid, int port,
        return _mv88e6xxx_atu_move(ds, fid, port, 0x0f, static_too);
 }
 
-static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
+static const char * const mv88e6xxx_port_state_names[] = {
+       [PORT_CONTROL_STATE_DISABLED] = "Disabled",
+       [PORT_CONTROL_STATE_BLOCKING] = "Blocking/Listening",
+       [PORT_CONTROL_STATE_LEARNING] = "Learning",
+       [PORT_CONTROL_STATE_FORWARDING] = "Forwarding",
+};
+
+static int _mv88e6xxx_port_state(struct dsa_switch *ds, int port, u8 state)
 {
-       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        int reg, ret = 0;
        u8 oldstate;
 
-       mutex_lock(&ps->smi_mutex);
-
        reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL);
-       if (reg < 0) {
-               ret = reg;
-               goto abort;
-       }
+       if (reg < 0)
+               return reg;
 
        oldstate = reg & PORT_CONTROL_STATE_MASK;
+
        if (oldstate != state) {
                /* Flush forwarding database if we're moving a port
                 * from Learning or Forwarding state to Disabled or
                 * Blocking or Listening state.
                 */
-               if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
-                   state <= PORT_CONTROL_STATE_BLOCKING) {
+               if ((oldstate == PORT_CONTROL_STATE_LEARNING ||
+                    oldstate == PORT_CONTROL_STATE_FORWARDING)
+                   && (state == PORT_CONTROL_STATE_DISABLED ||
+                       state == PORT_CONTROL_STATE_BLOCKING)) {
                        ret = _mv88e6xxx_atu_remove(ds, 0, port, false);
                        if (ret)
-                               goto abort;
+                               return ret;
                }
+
                reg = (reg & ~PORT_CONTROL_STATE_MASK) | state;
                ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL,
                                           reg);
+               if (ret)
+                       return ret;
+
+               netdev_dbg(ds->ports[port], "PortState %s (was %s)\n",
+                          mv88e6xxx_port_state_names[state],
+                          mv88e6xxx_port_state_names[oldstate]);
        }
 
-abort:
-       mutex_unlock(&ps->smi_mutex);
        return ret;
 }
 
-static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
-                                       u16 output_ports)
+static int _mv88e6xxx_port_based_vlan_map(struct dsa_switch *ds, int port)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       struct net_device *bridge = ps->ports[port].bridge_dev;
        const u16 mask = (1 << ps->num_ports) - 1;
+       u16 output_ports = 0;
        int reg;
+       int i;
+
+       /* allow CPU port or DSA link(s) to send frames to every port */
+       if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
+               output_ports = mask;
+       } else {
+               for (i = 0; i < ps->num_ports; ++i) {
+                       /* allow sending frames to every group member */
+                       if (bridge && ps->ports[i].bridge_dev == bridge)
+                               output_ports |= BIT(i);
+
+                       /* allow sending frames to CPU port and DSA link(s) */
+                       if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
+                               output_ports |= BIT(i);
+               }
+       }
+
+       /* prevent frames from going back out of the port they came in on */
+       output_ports &= ~BIT(port);
 
        reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
        if (reg < 0)
@@ -1126,48 +1156,55 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state)
                break;
        }
 
-       netdev_dbg(ds->ports[port], "port state %d [%d]\n", state, stp_state);
-
        /* mv88e6xxx_port_stp_update may be called with softirqs disabled,
         * so we can not update the port state directly but need to schedule it.
         */
-       ps->port_state[port] = stp_state;
-       set_bit(port, &ps->port_state_update_mask);
+       ps->ports[port].state = stp_state;
+       set_bit(port, ps->port_state_update_mask);
        schedule_work(&ps->bridge_work);
 
        return 0;
 }
 
-static int _mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
+static int _mv88e6xxx_port_pvid(struct dsa_switch *ds, int port, u16 *new,
+                               u16 *old)
 {
+       u16 pvid;
        int ret;
 
        ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
        if (ret < 0)
                return ret;
 
-       *pvid = ret & PORT_DEFAULT_VLAN_MASK;
+       pvid = ret & PORT_DEFAULT_VLAN_MASK;
 
-       return 0;
-}
+       if (new) {
+               ret &= ~PORT_DEFAULT_VLAN_MASK;
+               ret |= *new & PORT_DEFAULT_VLAN_MASK;
 
-int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
-{
-       int ret;
+               ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
+                                          PORT_DEFAULT_VLAN, ret);
+               if (ret < 0)
+                       return ret;
 
-       ret = mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_DEFAULT_VLAN);
-       if (ret < 0)
-               return ret;
+               netdev_dbg(ds->ports[port], "DefaultVID %d (was %d)\n", *new,
+                          pvid);
+       }
 
-       *pvid = ret & PORT_DEFAULT_VLAN_MASK;
+       if (old)
+               *old = pvid;
 
        return 0;
 }
 
+static int _mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *pvid)
+{
+       return _mv88e6xxx_port_pvid(ds, port, NULL, pvid);
+}
+
 static int _mv88e6xxx_port_pvid_set(struct dsa_switch *ds, int port, u16 pvid)
 {
-       return _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_DEFAULT_VLAN,
-                                  pvid & PORT_DEFAULT_VLAN_MASK);
+       return _mv88e6xxx_port_pvid(ds, port, &pvid, NULL);
 }
 
 static int _mv88e6xxx_vtu_wait(struct dsa_switch *ds)
@@ -1306,6 +1343,57 @@ static int _mv88e6xxx_vtu_getnext(struct dsa_switch *ds,
        return 0;
 }
 
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
+                            struct switchdev_obj_port_vlan *vlan,
+                            int (*cb)(struct switchdev_obj *obj))
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       struct mv88e6xxx_vtu_stu_entry next;
+       u16 pvid;
+       int err;
+
+       mutex_lock(&ps->smi_mutex);
+
+       err = _mv88e6xxx_port_pvid_get(ds, port, &pvid);
+       if (err)
+               goto unlock;
+
+       err = _mv88e6xxx_vtu_vid_write(ds, GLOBAL_VTU_VID_MASK);
+       if (err)
+               goto unlock;
+
+       do {
+               err = _mv88e6xxx_vtu_getnext(ds, &next);
+               if (err)
+                       break;
+
+               if (!next.valid)
+                       break;
+
+               if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+                       continue;
+
+               /* reinit and dump this VLAN obj */
+               vlan->vid_begin = vlan->vid_end = next.vid;
+               vlan->flags = 0;
+
+               if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
+                       vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
+
+               if (next.vid == pvid)
+                       vlan->flags |= BRIDGE_VLAN_INFO_PVID;
+
+               err = cb(&vlan->obj);
+               if (err)
+                       break;
+       } while (next.vid < GLOBAL_VTU_VID_MASK);
+
+unlock:
+       mutex_unlock(&ps->smi_mutex);
+
+       return err;
+}
+
 static int _mv88e6xxx_vtu_loadpurge(struct dsa_switch *ds,
                                    struct mv88e6xxx_vtu_stu_entry *entry)
 {
@@ -1420,16 +1508,122 @@ loadpurge:
        return _mv88e6xxx_vtu_cmd(ds, GLOBAL_VTU_OP_STU_LOAD_PURGE);
 }
 
-static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
-                               struct mv88e6xxx_vtu_stu_entry *entry)
+static int _mv88e6xxx_port_fid(struct dsa_switch *ds, int port, u16 *new,
+                              u16 *old)
+{
+       u16 fid;
+       int ret;
+
+       /* Port's default FID bits 3:0 are located in reg 0x06, offset 12 */
+       ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
+       if (ret < 0)
+               return ret;
+
+       fid = (ret & PORT_BASE_VLAN_FID_3_0_MASK) >> 12;
+
+       if (new) {
+               ret &= ~PORT_BASE_VLAN_FID_3_0_MASK;
+               ret |= (*new << 12) & PORT_BASE_VLAN_FID_3_0_MASK;
+
+               ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_BASE_VLAN,
+                                          ret);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Port's default FID bits 11:4 are located in reg 0x05, offset 0 */
+       ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL_1);
+       if (ret < 0)
+               return ret;
+
+       fid |= (ret & PORT_CONTROL_1_FID_11_4_MASK) << 4;
+
+       if (new) {
+               ret &= ~PORT_CONTROL_1_FID_11_4_MASK;
+               ret |= (*new >> 4) & PORT_CONTROL_1_FID_11_4_MASK;
+
+               ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_1,
+                                          ret);
+               if (ret < 0)
+                       return ret;
+
+               netdev_dbg(ds->ports[port], "FID %d (was %d)\n", *new, fid);
+       }
+
+       if (old)
+               *old = fid;
+
+       return 0;
+}
+
+static int _mv88e6xxx_port_fid_get(struct dsa_switch *ds, int port, u16 *fid)
+{
+       return _mv88e6xxx_port_fid(ds, port, NULL, fid);
+}
+
+static int _mv88e6xxx_port_fid_set(struct dsa_switch *ds, int port, u16 fid)
+{
+       return _mv88e6xxx_port_fid(ds, port, &fid, NULL);
+}
+
+static int _mv88e6xxx_fid_new(struct dsa_switch *ds, u16 *fid)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
+       struct mv88e6xxx_vtu_stu_entry vlan;
+       int i, err;
+
+       bitmap_zero(fid_bitmap, MV88E6XXX_N_FID);
+
+       /* Set every FID bit used by the (un)bridged ports */
+       for (i = 0; i < ps->num_ports; ++i) {
+               err = _mv88e6xxx_port_fid_get(ds, i, fid);
+               if (err)
+                       return err;
+
+               set_bit(*fid, fid_bitmap);
+       }
+
+       /* Set every FID bit used by the VLAN entries */
+       err = _mv88e6xxx_vtu_vid_write(ds, GLOBAL_VTU_VID_MASK);
+       if (err)
+               return err;
+
+       do {
+               err = _mv88e6xxx_vtu_getnext(ds, &vlan);
+               if (err)
+                       return err;
+
+               if (!vlan.valid)
+                       break;
+
+               set_bit(vlan.fid, fid_bitmap);
+       } while (vlan.vid < GLOBAL_VTU_VID_MASK);
+
+       /* The reset value 0x000 is used to indicate that multiple address
+        * databases are not needed. Return the next positive available.
+        */
+       *fid = find_next_zero_bit(fid_bitmap, MV88E6XXX_N_FID, 1);
+       if (unlikely(*fid == MV88E6XXX_N_FID))
+               return -ENOSPC;
+
+       /* Clear the database */
+       return _mv88e6xxx_atu_flush(ds, *fid, true);
+}
+
+static int _mv88e6xxx_vtu_new(struct dsa_switch *ds, u16 vid,
+                             struct mv88e6xxx_vtu_stu_entry *entry)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
        struct mv88e6xxx_vtu_stu_entry vlan = {
                .valid = true,
                .vid = vid,
-               .fid = vid, /* We use one FID per VLAN */
        };
-       int i;
+       int i, err;
+
+       err = _mv88e6xxx_fid_new(ds, &vlan.fid);
+       if (err)
+               return err;
 
        /* exclude all ports except the CPU and DSA ports */
        for (i = 0; i < ps->num_ports; ++i)
@@ -1440,7 +1634,6 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
        if (mv88e6xxx_6097_family(ds) || mv88e6xxx_6165_family(ds) ||
            mv88e6xxx_6351_family(ds) || mv88e6xxx_6352_family(ds)) {
                struct mv88e6xxx_vtu_stu_entry vstp;
-               int err;
 
                /* Adding a VTU entry requires a valid STU entry. As VSTP is not
                 * implemented, only one STU entry is needed to cover all VTU
@@ -1460,24 +1653,152 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
                        if (err)
                                return err;
                }
-
-               /* Clear all MAC addresses from the new database */
-               err = _mv88e6xxx_atu_flush(ds, vlan.fid, true);
-               if (err)
-                       return err;
        }
 
        *entry = vlan;
        return 0;
 }
 
+static int _mv88e6xxx_vtu_get(struct dsa_switch *ds, u16 vid,
+                             struct mv88e6xxx_vtu_stu_entry *entry, bool creat)
+{
+       int err;
+
+       if (!vid)
+               return -EINVAL;
+
+       err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
+       if (err)
+               return err;
+
+       err = _mv88e6xxx_vtu_getnext(ds, entry);
+       if (err)
+               return err;
+
+       if (entry->vid != vid || !entry->valid) {
+               if (!creat)
+                       return -EOPNOTSUPP;
+               /* -ENOENT would've been more appropriate, but switchdev expects
+                * -EOPNOTSUPP to inform bridge about an eventual software VLAN.
+                */
+
+               err = _mv88e6xxx_vtu_new(ds, vid, entry);
+       }
+
+       return err;
+}
+
+static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
+                                       u16 vid_begin, u16 vid_end)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       struct mv88e6xxx_vtu_stu_entry vlan;
+       int i, err;
+
+       if (!vid_begin)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&ps->smi_mutex);
+
+       err = _mv88e6xxx_vtu_vid_write(ds, vid_begin - 1);
+       if (err)
+               goto unlock;
+
+       do {
+               err = _mv88e6xxx_vtu_getnext(ds, &vlan);
+               if (err)
+                       goto unlock;
+
+               if (!vlan.valid)
+                       break;
+
+               if (vlan.vid > vid_end)
+                       break;
+
+               for (i = 0; i < ps->num_ports; ++i) {
+                       if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i))
+                               continue;
+
+                       if (vlan.data[i] ==
+                           GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+                               continue;
+
+                       if (ps->ports[i].bridge_dev ==
+                           ps->ports[port].bridge_dev)
+                               break; /* same bridge, check next VLAN */
+
+                       netdev_warn(ds->ports[port],
+                                   "hardware VLAN %d already used by %s\n",
+                                   vlan.vid,
+                                   netdev_name(ps->ports[i].bridge_dev));
+                       err = -EOPNOTSUPP;
+                       goto unlock;
+               }
+       } while (vlan.vid < vid_end);
+
+unlock:
+       mutex_unlock(&ps->smi_mutex);
+
+       return err;
+}
+
+static const char * const mv88e6xxx_port_8021q_mode_names[] = {
+       [PORT_CONTROL_2_8021Q_DISABLED] = "Disabled",
+       [PORT_CONTROL_2_8021Q_FALLBACK] = "Fallback",
+       [PORT_CONTROL_2_8021Q_CHECK] = "Check",
+       [PORT_CONTROL_2_8021Q_SECURE] = "Secure",
+};
+
+int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
+                                 bool vlan_filtering)
+{
+       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+       u16 old, new = vlan_filtering ? PORT_CONTROL_2_8021Q_SECURE :
+               PORT_CONTROL_2_8021Q_DISABLED;
+       int ret;
+
+       mutex_lock(&ps->smi_mutex);
+
+       ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_CONTROL_2);
+       if (ret < 0)
+               goto unlock;
+
+       old = ret & PORT_CONTROL_2_8021Q_MASK;
+
+       if (new != old) {
+               ret &= ~PORT_CONTROL_2_8021Q_MASK;
+               ret |= new & PORT_CONTROL_2_8021Q_MASK;
+
+               ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_CONTROL_2,
+                                          ret);
+               if (ret < 0)
+                       goto unlock;
+
+               netdev_dbg(ds->ports[port], "802.1Q Mode %s (was %s)\n",
+                          mv88e6xxx_port_8021q_mode_names[new],
+                          mv88e6xxx_port_8021q_mode_names[old]);
+       }
+
+       ret = 0;
+unlock:
+       mutex_unlock(&ps->smi_mutex);
+
+       return ret;
+}
+
 int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
                                const struct switchdev_obj_port_vlan *vlan,
                                struct switchdev_trans *trans)
 {
-       /* We reserve a few VLANs to isolate unbridged ports */
-       if (vlan->vid_end >= 4000)
-               return -EOPNOTSUPP;
+       int err;
+
+       /* If the requested port doesn't belong to the same bridge as the VLAN
+        * members, do not support it (yet) and fallback to software VLAN.
+        */
+       err = mv88e6xxx_port_check_hw_vlan(ds, port, vlan->vid_begin,
+                                          vlan->vid_end);
+       if (err)
+               return err;
 
        /* We don't need any dynamic resource from the kernel (yet),
         * so skip the prepare phase.
@@ -1491,20 +1812,10 @@ static int _mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, u16 vid,
        struct mv88e6xxx_vtu_stu_entry vlan;
        int err;
 
-       err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
+       err = _mv88e6xxx_vtu_get(ds, vid, &vlan, true);
        if (err)
                return err;
 
-       err = _mv88e6xxx_vtu_getnext(ds, &vlan);
-       if (err)
-               return err;
-
-       if (vlan.vid != vid || !vlan.valid) {
-               err = _mv88e6xxx_vlan_init(ds, vid, &vlan);
-               if (err)
-                       return err;
-       }
-
        vlan.data[port] = untagged ?
                GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
                GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
@@ -1545,17 +1856,13 @@ static int _mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
        struct mv88e6xxx_vtu_stu_entry vlan;
        int i, err;
 
-       err = _mv88e6xxx_vtu_vid_write(ds, vid - 1);
-       if (err)
-               return err;
-
-       err = _mv88e6xxx_vtu_getnext(ds, &vlan);
+       err = _mv88e6xxx_vtu_get(ds, vid, &vlan, false);
        if (err)
                return err;
 
-       if (vlan.vid != vid || !vlan.valid ||
-           vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
-               return -ENOENT;
+       /* Tell switchdev if this VLAN is handled in software */
+       if (vlan.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER)
+               return -EOPNOTSUPP;
 
        vlan.data[port] = GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
 
@@ -1609,52 +1916,6 @@ unlock:
        return err;
 }
 
-int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
-                          unsigned long *ports, unsigned long *untagged)
-{
-       struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       struct mv88e6xxx_vtu_stu_entry next;
-       int port;
-       int err;
-
-       if (*vid == 4095)
-               return -ENOENT;
-
-       mutex_lock(&ps->smi_mutex);
-       err = _mv88e6xxx_vtu_vid_write(ds, *vid);
-       if (err)
-               goto unlock;
-
-       err = _mv88e6xxx_vtu_getnext(ds, &next);
-unlock:
-       mutex_unlock(&ps->smi_mutex);
-
-       if (err)
-               return err;
-
-       if (!next.valid)
-               return -ENOENT;
-
-       *vid = next.vid;
-
-       for (port = 0; port < ps->num_ports; ++port) {
-               clear_bit(port, ports);
-               clear_bit(port, untagged);
-
-               if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
-                       continue;
-
-               if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED ||
-                   next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
-                       set_bit(port, ports);
-
-               if (next.data[port] == GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED)
-                       set_bit(port, untagged);
-       }
-
-       return 0;
-}
-
 static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds,
                                    const unsigned char *addr)
 {
@@ -1716,8 +1977,18 @@ static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port,
                                    u8 state)
 {
        struct mv88e6xxx_atu_entry entry = { 0 };
+       struct mv88e6xxx_vtu_stu_entry vlan;
+       int err;
+
+       /* Null VLAN ID corresponds to the port private database */
+       if (vid == 0)
+               err = _mv88e6xxx_port_fid_get(ds, port, &vlan.fid);
+       else
+               err = _mv88e6xxx_vtu_get(ds, vid, &vlan, false);
+       if (err)
+               return err;
 
-       entry.fid = vid; /* We use one FID per VLAN */
+       entry.fid = vlan.fid;
        entry.state = state;
        ether_addr_copy(entry.mac, addr);
        if (state != GLOBAL_ATU_DATA_STATE_UNUSED) {
@@ -1732,10 +2003,6 @@ int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
                               const struct switchdev_obj_port_fdb *fdb,
                               struct switchdev_trans *trans)
 {
-       /* We don't use per-port FDB */
-       if (fdb->vid == 0)
-               return -EOPNOTSUPP;
-
        /* We don't need any dynamic resource from the kernel (yet),
         * so skip the prepare phase.
         */
@@ -1822,6 +2089,47 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
        return 0;
 }
 
+static int _mv88e6xxx_port_fdb_dump_one(struct dsa_switch *ds, u16 fid, u16 vid,
+                                       int port,
+                                       struct switchdev_obj_port_fdb *fdb,
+                                       int (*cb)(struct switchdev_obj *obj))
+{
+       struct mv88e6xxx_atu_entry addr = {
+               .mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+       };
+       int err;
+
+       err = _mv88e6xxx_atu_mac_write(ds, addr.mac);
+       if (err)
+               return err;
+
+       do {
+               err = _mv88e6xxx_atu_getnext(ds, fid, &addr);
+               if (err)
+                       break;
+
+               if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
+                       break;
+
+               if (!addr.trunk && addr.portv_trunkid & BIT(port)) {
+                       bool is_static = addr.state ==
+                               (is_multicast_ether_addr(addr.mac) ?
+                                GLOBAL_ATU_DATA_STATE_MC_STATIC :
+                                GLOBAL_ATU_DATA_STATE_UC_STATIC);
+
+                       fdb->vid = vid;
+                       ether_addr_copy(fdb->addr, addr.mac);
+                       fdb->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE;
+
+                       err = cb(&fdb->obj);
+                       if (err)
+                               break;
+               }
+       } while (!is_broadcast_ether_addr(addr.mac));
+
+       return err;
+}
+
 int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
                            struct switchdev_obj_port_fdb *fdb,
                            int (*cb)(struct switchdev_obj *obj))
@@ -1830,55 +2138,37 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
        struct mv88e6xxx_vtu_stu_entry vlan = {
                .vid = GLOBAL_VTU_VID_MASK, /* all ones */
        };
+       u16 fid;
        int err;
 
        mutex_lock(&ps->smi_mutex);
 
+       /* Dump port's default Filtering Information Database (VLAN ID 0) */
+       err = _mv88e6xxx_port_fid_get(ds, port, &fid);
+       if (err)
+               goto unlock;
+
+       err = _mv88e6xxx_port_fdb_dump_one(ds, fid, 0, port, fdb, cb);
+       if (err)
+               goto unlock;
+
+       /* Dump VLANs' Filtering Information Databases */
        err = _mv88e6xxx_vtu_vid_write(ds, vlan.vid);
        if (err)
                goto unlock;
 
        do {
-               struct mv88e6xxx_atu_entry addr = {
-                       .mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
-               };
-
                err = _mv88e6xxx_vtu_getnext(ds, &vlan);
                if (err)
-                       goto unlock;
+                       break;
 
                if (!vlan.valid)
                        break;
 
-               err = _mv88e6xxx_atu_mac_write(ds, addr.mac);
+               err = _mv88e6xxx_port_fdb_dump_one(ds, vlan.fid, vlan.vid, port,
+                                                  fdb, cb);
                if (err)
-                       goto unlock;
-
-               do {
-                       err = _mv88e6xxx_atu_getnext(ds, vlan.fid, &addr);
-                       if (err)
-                               goto unlock;
-
-                       if (addr.state == GLOBAL_ATU_DATA_STATE_UNUSED)
-                               break;
-
-                       if (!addr.trunk && addr.portv_trunkid & BIT(port)) {
-                               bool is_static = addr.state ==
-                                       (is_multicast_ether_addr(addr.mac) ?
-                                        GLOBAL_ATU_DATA_STATE_MC_STATIC :
-                                        GLOBAL_ATU_DATA_STATE_UC_STATIC);
-
-                               fdb->vid = vlan.vid;
-                               ether_addr_copy(fdb->addr, addr.mac);
-                               fdb->ndm_state = is_static ? NUD_NOARP :
-                                       NUD_REACHABLE;
-
-                               err = cb(&fdb->obj);
-                               if (err)
-                                       goto unlock;
-                       }
-               } while (!is_broadcast_ether_addr(addr.mac));
-
+                       break;
        } while (vlan.vid < GLOBAL_VTU_VID_MASK);
 
 unlock:
@@ -1887,33 +2177,80 @@ unlock:
        return err;
 }
 
-int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
+                              struct net_device *bridge)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
-       int err;
+       u16 fid;
+       int i, err;
 
-       /* The port joined a bridge, so leave its reserved VLAN */
        mutex_lock(&ps->smi_mutex);
-       err = _mv88e6xxx_port_vlan_del(ds, port, pvid);
-       if (!err)
-               err = _mv88e6xxx_port_pvid_set(ds, port, 0);
+
+       /* Get or create the bridge FID and assign it to the port */
+       for (i = 0; i < ps->num_ports; ++i)
+               if (ps->ports[i].bridge_dev == bridge)
+                       break;
+
+       if (i < ps->num_ports)
+               err = _mv88e6xxx_port_fid_get(ds, i, &fid);
+       else
+               err = _mv88e6xxx_fid_new(ds, &fid);
+       if (err)
+               goto unlock;
+
+       err = _mv88e6xxx_port_fid_set(ds, port, fid);
+       if (err)
+               goto unlock;
+
+       /* Assign the bridge and remap each port's VLANTable */
+       ps->ports[port].bridge_dev = bridge;
+
+       for (i = 0; i < ps->num_ports; ++i) {
+               if (ps->ports[i].bridge_dev == bridge) {
+                       err = _mv88e6xxx_port_based_vlan_map(ds, i);
+                       if (err)
+                               break;
+               }
+       }
+
+unlock:
        mutex_unlock(&ps->smi_mutex);
+
        return err;
 }
 
-int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
+int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
 {
        struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
-       const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
-       int err;
+       struct net_device *bridge = ps->ports[port].bridge_dev;
+       u16 fid;
+       int i, err;
 
-       /* The port left the bridge, so join its reserved VLAN */
        mutex_lock(&ps->smi_mutex);
-       err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
-       if (!err)
-               err = _mv88e6xxx_port_pvid_set(ds, port, pvid);
+
+       /* Give the port a fresh Filtering Information Database */
+       err = _mv88e6xxx_fid_new(ds, &fid);
+       if (err)
+               goto unlock;
+
+       err = _mv88e6xxx_port_fid_set(ds, port, fid);
+       if (err)
+               goto unlock;
+
+       /* Unassign the bridge and remap each port's VLANTable */
+       ps->ports[port].bridge_dev = NULL;
+
+       for (i = 0; i < ps->num_ports; ++i) {
+               if (i == port || ps->ports[i].bridge_dev == bridge) {
+                       err = _mv88e6xxx_port_based_vlan_map(ds, i);
+                       if (err)
+                               break;
+               }
+       }
+
+unlock:
        mutex_unlock(&ps->smi_mutex);
+
        return err;
 }
 
@@ -1926,11 +2263,15 @@ static void mv88e6xxx_bridge_work(struct work_struct *work)
        ps = container_of(work, struct mv88e6xxx_priv_state, bridge_work);
        ds = ((struct dsa_switch *)ps) - 1;
 
-       while (ps->port_state_update_mask) {
-               port = __ffs(ps->port_state_update_mask);
-               clear_bit(port, &ps->port_state_update_mask);
-               mv88e6xxx_set_port_state(ds, port, ps->port_state[port]);
-       }
+       mutex_lock(&ps->smi_mutex);
+
+       for (port = 0; port < ps->num_ports; ++port)
+               if (test_and_clear_bit(port, ps->port_state_update_mask) &&
+                   _mv88e6xxx_port_state(ds, port, ps->ports[port].state))
+                       netdev_warn(ds->ports[port], "failed to update state to %s\n",
+                                   mv88e6xxx_port_state_names[ps->ports[port].state]);
+
+       mutex_unlock(&ps->smi_mutex);
 }
 
 static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
@@ -2037,7 +2378,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
        }
 
        /* Port Control 2: don't force a good FCS, set the maximum frame size to
-        * 10240 bytes, enable secure 802.1q tags, don't discard tagged or
+        * 10240 bytes, disable 802.1q tags checking, don't discard tagged or
         * untagged frames on this port, do a destination address lookup on all
         * received packets as usual, disable ARP mirroring and don't send a
         * copy of all transmitted/received frames on this port to the CPU.
@@ -2062,7 +2403,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
                        reg |= PORT_CONTROL_2_FORWARD_UNKNOWN;
        }
 
-       reg |= PORT_CONTROL_2_8021Q_SECURE;
+       reg |= PORT_CONTROL_2_8021Q_DISABLED;
 
        if (reg) {
                ret = _mv88e6xxx_reg_write(ds, REG_PORT(port),
@@ -2159,12 +2500,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
        if (ret)
                goto abort;
 
-       /* Port based VLAN map: do not give each port its own address
-        * database, and allow every port to egress frames on all other ports.
+       /* Port based VLAN map: give each port its own address
+        * database, and allow bidirectional communication between the
+        * CPU and DSA port(s), and the other ports.
         */
-       reg = BIT(ps->num_ports) - 1; /* all ports */
-       reg &= ~BIT(port); /* except itself */
-       ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);
+       ret = _mv88e6xxx_port_fid_set(ds, port, port + 1);
+       if (ret)
+               goto abort;
+
+       ret = _mv88e6xxx_port_based_vlan_map(ds, port);
        if (ret)
                goto abort;
 
@@ -2188,14 +2532,6 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds)
                ret = mv88e6xxx_setup_port(ds, i);
                if (ret < 0)
                        return ret;
-
-               if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
-                       continue;
-
-               /* setup the unbridged state */
-               ret = mv88e6xxx_port_bridge_leave(ds, i, 0);
-               if (ret < 0)
-                       return ret;
        }
        return 0;
 }
index ca08f913d302c8226b4bff5fc546837114893579..3425616987ed5d9acda6759e92429ed3c343d636 100644 (file)
 #define PORT_CONTROL_STATE_LEARNING    0x02
 #define PORT_CONTROL_STATE_FORWARDING  0x03
 #define PORT_CONTROL_1         0x05
+#define PORT_CONTROL_1_FID_11_4_MASK   (0xff << 0)
 #define PORT_BASE_VLAN         0x06
+#define PORT_BASE_VLAN_FID_3_0_MASK    (0xf << 12)
 #define PORT_DEFAULT_VLAN      0x07
 #define PORT_DEFAULT_VLAN_MASK 0xfff
 #define PORT_CONTROL_2         0x08
 #define GLOBAL2_QOS_WEIGHT     0x1c
 #define GLOBAL2_MISC           0x1d
 
+#define MV88E6XXX_N_FID                4096
+
 struct mv88e6xxx_switch_id {
        u16 id;
        char *name;
@@ -379,6 +383,11 @@ struct mv88e6xxx_vtu_stu_entry {
        u8      data[DSA_MAX_PORTS];
 };
 
+struct mv88e6xxx_priv_port {
+       struct net_device *bridge_dev;
+       u8 state;
+};
+
 struct mv88e6xxx_priv_state {
        /* When using multi-chip addressing, this mutex protects
         * access to the indirect access registers.  (In single-chip
@@ -415,8 +424,9 @@ struct mv88e6xxx_priv_state {
        int             id; /* switch product id */
        int             num_ports;      /* number of switch ports */
 
-       unsigned long port_state_update_mask;
-       u8 port_state[DSA_MAX_PORTS];
+       struct mv88e6xxx_priv_port      ports[DSA_MAX_PORTS];
+
+       DECLARE_BITMAP(port_state_update_mask, DSA_MAX_PORTS);
 
        struct work_struct bridge_work;
 };
@@ -476,9 +486,12 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
 int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
 int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
                      struct phy_device *phydev, struct ethtool_eee *e);
-int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members);
-int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members);
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
+                              struct net_device *bridge);
+int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port);
 int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state);
+int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
+                                 bool vlan_filtering);
 int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
                                const struct switchdev_obj_port_vlan *vlan,
                                struct switchdev_trans *trans);
@@ -487,9 +500,9 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
                            struct switchdev_trans *trans);
 int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
                            const struct switchdev_obj_port_vlan *vlan);
-int mv88e6xxx_port_pvid_get(struct dsa_switch *ds, int port, u16 *vid);
-int mv88e6xxx_vlan_getnext(struct dsa_switch *ds, u16 *vid,
-                          unsigned long *ports, unsigned long *untagged);
+int mv88e6xxx_port_vlan_dump(struct dsa_switch *ds, int port,
+                            struct switchdev_obj_port_vlan *vlan,
+                            int (*cb)(struct switchdev_obj *obj));
 int mv88e6xxx_port_fdb_prepare(struct dsa_switch *ds, int port,
                               const struct switchdev_obj_port_fdb *fdb,
                               struct switchdev_trans *trans);
index 79e1a0282163db200916e0f862fa1560eab2fd03..d81fceddbe0e86d2f6489c3210051fe7265a6560 100644 (file)
@@ -1601,15 +1601,9 @@ vortex_up(struct net_device *dev)
                                dev->name, media_tbl[dev->if_port].name);
        }
 
-       init_timer(&vp->timer);
-       vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);
-       vp->timer.data = (unsigned long)dev;
-       vp->timer.function = vortex_timer;              /* timer handler */
-       add_timer(&vp->timer);
-
-       init_timer(&vp->rx_oom_timer);
-       vp->rx_oom_timer.data = (unsigned long)dev;
-       vp->rx_oom_timer.function = rx_oom_timer;
+       setup_timer(&vp->timer, vortex_timer, (unsigned long)dev);
+       mod_timer(&vp->timer, RUN_AT(media_tbl[dev->if_port].wait));
+       setup_timer(&vp->rx_oom_timer, rx_oom_timer, (unsigned long)dev);
 
        if (vortex_debug > 1)
                pr_debug("%s: Initial media type %s.\n",
@@ -2461,7 +2455,7 @@ boomerang_interrupt(int irq, void *dev_id)
                                        int i;
                                        pci_unmap_single(VORTEX_PCI(vp),
                                                        le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
-                                                       le32_to_cpu(vp->tx_ring[entry].frag[0].length),
+                                                       le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF,
                                                        PCI_DMA_TODEVICE);
 
                                        for (i=1; i<=skb_shinfo(skb)->nr_frags; i++)
index 2777289a26c0419f855926ef028942074ca62a2f..2f79d29f17f2f0fae388f9cd4b4d9da201793775 100644 (file)
@@ -1501,6 +1501,7 @@ static const struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
        PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
        PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
+       PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0009),
        PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
        PCMCIA_DEVICE_PROD_ID1234("Socket", "CF 10/100 Ethernet Card", "Revision B", "05/11/06", 0xb38bcc2e, 0x4de88352, 0xeaca6c8d, 0x7e57c22e),
        PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
index 0b13af8e40701747a063f3a7e1518dc1cd66d966..be67a19e01b90f6c173f45a32dff41919b8a81f6 100644 (file)
@@ -106,6 +106,7 @@ config LANTIQ_ETOP
          Support for the MII0 inside the Lantiq SoC
 
 source "drivers/net/ethernet/marvell/Kconfig"
+source "drivers/net/ethernet/mediatek/Kconfig"
 source "drivers/net/ethernet/mellanox/Kconfig"
 source "drivers/net/ethernet/micrel/Kconfig"
 source "drivers/net/ethernet/microchip/Kconfig"
index 38dc1a776a2bd60d67b87ce1135c6d85b1c0a87e..6ffcc801d37ef0ad2c374d3793dcfe7723aedc73 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_JME) += jme.o
 obj-$(CONFIG_KORINA) += korina.o
 obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
 obj-$(CONFIG_NET_VENDOR_MARVELL) += marvell/
+obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/
 obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/
 obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/
 obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/
index 3f3bcbea15bd7a6caf7c8296e6c5bc0bef14c6f1..0907ab6ff309e65ac4ff56250443dc23d6904b1c 100644 (file)
@@ -2380,7 +2380,7 @@ static int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter)
                                                    sizeof(u32),
                                                    &tx_ring->tx_status_pa,
                                                    GFP_KERNEL);
-       if (!tx_ring->tx_status_pa) {
+       if (!tx_ring->tx_status) {
                dev_err(&adapter->pdev->dev,
                        "Cannot alloc memory for Tx status block\n");
                return -ENOMEM;
index 17472851674f19f949f97e04fccdc5a6fb874a3d..f749e4d389eb163132d5ab51ad7a9821c07577e4 100644 (file)
@@ -193,7 +193,6 @@ static void altera_tse_mdio_destroy(struct net_device *dev)
                            priv->mdio->id);
 
        mdiobus_unregister(priv->mdio);
-       kfree(priv->mdio->irq);
        mdiobus_free(priv->mdio);
        priv->mdio = NULL;
 }
index 87e727b921dc0a20f99a6bdb084d2a6e3b168f9e..fcdf5dda448f9c7acf5a0a537cbbcb0de76b09df 100644 (file)
@@ -50,8 +50,8 @@ static const char version[] =
 static void write_rreg(u_long base, u_int reg, u_int val)
 {
        asm volatile(
-       "str%?h %1, [%2]        @ NET_RAP\n\t"
-       "str%?h %0, [%2, #-4]   @ NET_RDP"
+       "strh   %1, [%2]        @ NET_RAP\n\t"
+       "strh   %0, [%2, #-4]   @ NET_RDP"
        :
        : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
@@ -60,8 +60,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 {
        unsigned short v;
        asm volatile(
-       "str%?h %1, [%2]        @ NET_RAP\n\t"
-       "ldr%?h %0, [%2, #-4]   @ NET_RDP"
+       "strh   %1, [%2]        @ NET_RAP\n\t"
+       "ldrh   %0, [%2, #-4]   @ NET_RDP"
        : "=r" (v)
        : "r" (reg), "r" (ISAIO_BASE + 0x0464));
        return v;
@@ -70,8 +70,8 @@ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 static inline void write_ireg(u_long base, u_int reg, u_int val)
 {
        asm volatile(
-       "str%?h %1, [%2]        @ NET_RAP\n\t"
-       "str%?h %0, [%2, #8]    @ NET_IDP"
+       "strh   %1, [%2]        @ NET_RAP\n\t"
+       "strh   %0, [%2, #8]    @ NET_IDP"
        :
        : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
@@ -80,8 +80,8 @@ static inline unsigned short read_ireg(u_long base_addr, u_int reg)
 {
        u_short v;
        asm volatile(
-       "str%?h %1, [%2]        @ NAT_RAP\n\t"
-       "ldr%?h %0, [%2, #8]    @ NET_IDP\n\t"
+       "strh   %1, [%2]        @ NAT_RAP\n\t"
+       "ldrh   %0, [%2, #8]    @ NET_IDP\n\t"
        : "=r" (v)
        : "r" (reg), "r" (ISAIO_BASE + 0x0464));
        return v;
@@ -96,7 +96,7 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
        offset = ISAMEM_BASE + (offset << 1);
        length = (length + 1) & ~1;
        if ((int)buf & 2) {
-               asm volatile("str%?h    %2, [%0], #4"
+               asm volatile("strh      %2, [%0], #4"
                 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
                buf += 2;
                length -= 2;
@@ -104,20 +104,20 @@ am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigne
        while (length > 8) {
                register unsigned int tmp asm("r2"), tmp2 asm("r3");
                asm volatile(
-                       "ldm%?ia        %0!, {%1, %2}"
+                       "ldmia  %0!, {%1, %2}"
                        : "+r" (buf), "=&r" (tmp), "=&r" (tmp2));
                length -= 8;
                asm volatile(
-                       "str%?h %1, [%0], #4\n\t"
-                       "mov%?  %1, %1, lsr #16\n\t"
-                       "str%?h %1, [%0], #4\n\t"
-                       "str%?h %2, [%0], #4\n\t"
-                       "mov%?  %2, %2, lsr #16\n\t"
-                       "str%?h %2, [%0], #4"
+                       "strh   %1, [%0], #4\n\t"
+                       "mov    %1, %1, lsr #16\n\t"
+                       "strh   %1, [%0], #4\n\t"
+                       "strh   %2, [%0], #4\n\t"
+                       "mov    %2, %2, lsr #16\n\t"
+                       "strh   %2, [%0], #4"
                : "+r" (offset), "=&r" (tmp), "=&r" (tmp2));
        }
        while (length > 0) {
-               asm volatile("str%?h    %2, [%0], #4"
+               asm volatile("strh      %2, [%0], #4"
                 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
                buf += 2;
                length -= 2;
@@ -132,23 +132,23 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
        if ((int)buf & 2) {
                unsigned int tmp;
                asm volatile(
-                       "ldr%?h %2, [%0], #4\n\t"
-                       "str%?b %2, [%1], #1\n\t"
-                       "mov%?  %2, %2, lsr #8\n\t"
-                       "str%?b %2, [%1], #1"
+                       "ldrh   %2, [%0], #4\n\t"
+                       "strb   %2, [%1], #1\n\t"
+                       "mov    %2, %2, lsr #8\n\t"
+                       "strb   %2, [%1], #1"
                : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
                length -= 2;
        }
        while (length > 8) {
                register unsigned int tmp asm("r2"), tmp2 asm("r3"), tmp3;
                asm volatile(
-                       "ldr%?h %2, [%0], #4\n\t"
-                       "ldr%?h %4, [%0], #4\n\t"
-                       "ldr%?h %3, [%0], #4\n\t"
-                       "orr%?  %2, %2, %4, lsl #16\n\t"
-                       "ldr%?h %4, [%0], #4\n\t"
-                       "orr%?  %3, %3, %4, lsl #16\n\t"
-                       "stm%?ia        %1!, {%2, %3}"
+                       "ldrh   %2, [%0], #4\n\t"
+                       "ldrh   %4, [%0], #4\n\t"
+                       "ldrh   %3, [%0], #4\n\t"
+                       "orr    %2, %2, %4, lsl #16\n\t"
+                       "ldrh   %4, [%0], #4\n\t"
+                       "orr    %3, %3, %4, lsl #16\n\t"
+                       "stmia  %1!, {%2, %3}"
                : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
                : "0" (offset), "1" (buf));
                length -= 8;
@@ -156,10 +156,10 @@ am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned
        while (length > 0) {
                unsigned int tmp;
                asm volatile(
-                       "ldr%?h %2, [%0], #4\n\t"
-                       "str%?b %2, [%1], #1\n\t"
-                       "mov%?  %2, %2, lsr #8\n\t"
-                       "str%?b %2, [%1], #1"
+                       "ldrh   %2, [%0], #4\n\t"
+                       "strb   %2, [%1], #1\n\t"
+                       "mov    %2, %2, lsr #8\n\t"
+                       "strb   %2, [%1], #1"
                : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
                length -= 2;
        }
index 256f590f6bb1a6db167f4375b3ed2719d2ad5073..3a7ebfdda57dee33cbde71cf3440e5eb70aa262a 100644 (file)
@@ -547,8 +547,8 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
        /* Make certain the data structures used by the LANCE are aligned and DMAble. */
 
        lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
-       if(lp==NULL)
-               return -ENODEV;
+       if (!lp)
+               return -ENOMEM;
        if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
        dev->ml_priv = lp;
        lp->name = chipname;
index b6fa89102526b95e579d5dd16cbecad3fe9226d2..bbef95973c27355cad33c3e7ffc7c53d15964f24 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define MTL_Q_TQDR                     0x08
 #define MTL_Q_RQOMR                    0x40
 #define MTL_Q_RQMPOCR                  0x44
-#define MTL_Q_RQDR                     0x4c
+#define MTL_Q_RQDR                     0x48
 #define MTL_Q_RQFCR                    0x50
 #define MTL_Q_IER                      0x70
 #define MTL_Q_ISR                      0x74
 
 /* MTL queue register entry bit positions and sizes */
+#define MTL_Q_RQDR_PRXQ_INDEX          16
+#define MTL_Q_RQDR_PRXQ_WIDTH          14
+#define MTL_Q_RQDR_RXQSTS_INDEX                4
+#define MTL_Q_RQDR_RXQSTS_WIDTH                2
 #define MTL_Q_RQFCR_RFA_INDEX          1
 #define MTL_Q_RQFCR_RFA_WIDTH          6
 #define MTL_Q_RQFCR_RFD_INDEX          17
index a6b9899e285fd4ffae7cf061aa65c71afc2d2818..895d3563912911ed6a50ca22555076b4f7e512c8 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -146,6 +146,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
        unsigned int i, tc_ets, tc_ets_weight;
+       u8 max_tc = 0;
 
        tc_ets = 0;
        tc_ets_weight = 0;
@@ -157,12 +158,9 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
                netif_dbg(pdata, drv, netdev, "PRIO%u: TC=%hhu\n", i,
                          ets->prio_tc[i]);
 
-               if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) &&
-                   (i >= pdata->hw_feat.tc_cnt))
-                               return -EINVAL;
-
-               if (ets->prio_tc[i] >= pdata->hw_feat.tc_cnt)
-                       return -EINVAL;
+               max_tc = max_t(u8, max_tc, ets->prio_tc[i]);
+               if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]))
+                       max_tc = max_t(u8, max_tc, i);
 
                switch (ets->tc_tsa[i]) {
                case IEEE_8021QAZ_TSA_STRICT:
@@ -171,15 +169,28 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
                        tc_ets = 1;
                        tc_ets_weight += ets->tc_tx_bw[i];
                        break;
-
                default:
+                       netif_err(pdata, drv, netdev,
+                                 "unsupported TSA algorithm (%hhu)\n",
+                                 ets->tc_tsa[i]);
                        return -EINVAL;
                }
        }
 
+       /* Check maximum traffic class requested */
+       if (max_tc >= pdata->hw_feat.tc_cnt) {
+               netif_err(pdata, drv, netdev,
+                         "exceeded number of supported traffic classes\n");
+               return -EINVAL;
+       }
+
        /* Weights must add up to 100% */
-       if (tc_ets && (tc_ets_weight != 100))
+       if (tc_ets && (tc_ets_weight != 100)) {
+               netif_err(pdata, drv, netdev,
+                         "sum of ETS algorithm weights is not 100 (%u)\n",
+                         tc_ets_weight);
                return -EINVAL;
+       }
 
        if (!pdata->ets) {
                pdata->ets = devm_kzalloc(pdata->dev, sizeof(*pdata->ets),
@@ -188,6 +199,7 @@ static int xgbe_dcb_ieee_setets(struct net_device *netdev,
                        return -ENOMEM;
        }
 
+       pdata->num_tcs = max_tc + 1;
        memcpy(pdata->ets, ets, sizeof(*pdata->ets));
 
        pdata->hw_if.config_dcb_tc(pdata);
@@ -221,6 +233,13 @@ static int xgbe_dcb_ieee_setpfc(struct net_device *netdev,
                  "cap=%hhu, en=%#hhx, mbc=%hhu, delay=%hhu\n",
                  pfc->pfc_cap, pfc->pfc_en, pfc->mbc, pfc->delay);
 
+       /* Check PFC for supported number of traffic classes */
+       if (pfc->pfc_en & ~((1 << pdata->hw_feat.tc_cnt) - 1)) {
+               netif_err(pdata, drv, netdev,
+                         "PFC requested for unsupported traffic class\n");
+               return -EINVAL;
+       }
+
        if (!pdata->pfc) {
                pdata->pfc = devm_kzalloc(pdata->dev, sizeof(*pdata->pfc),
                                          GFP_KERNEL);
index f6a7161e3b85297eda9503a27280cab93b2ae70b..1babcc11a2488b57a57fb9eec8b0d86638ff5df4 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -518,13 +518,45 @@ static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
 
 static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
 {
+       struct ieee_pfc *pfc = pdata->pfc;
+       struct ieee_ets *ets = pdata->ets;
        unsigned int max_q_count, q_count;
        unsigned int reg, reg_val;
        unsigned int i;
 
        /* Set MTL flow control */
-       for (i = 0; i < pdata->rx_q_count; i++)
-               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, 1);
+       for (i = 0; i < pdata->rx_q_count; i++) {
+               unsigned int ehfc = 0;
+
+               if (pfc && ets) {
+                       unsigned int prio;
+
+                       for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
+                               unsigned int tc;
+
+                               /* Does this queue handle the priority? */
+                               if (pdata->prio2q_map[prio] != i)
+                                       continue;
+
+                               /* Get the Traffic Class for this priority */
+                               tc = ets->prio_tc[prio];
+
+                               /* Check if flow control should be enabled */
+                               if (pfc->pfc_en & (1 << tc)) {
+                                       ehfc = 1;
+                                       break;
+                               }
+                       }
+               } else {
+                       ehfc = 1;
+               }
+
+               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, EHFC, ehfc);
+
+               netif_dbg(pdata, drv, pdata->netdev,
+                         "flow control %s for RXq%u\n",
+                         ehfc ? "enabled" : "disabled", i);
+       }
 
        /* Set MAC flow control */
        max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
@@ -702,6 +734,113 @@ static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata)
        return 0;
 }
 
+static int xgbe_enable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
+{
+       /* Put the VLAN tag in the Rx descriptor */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLRXS, 1);
+
+       /* Don't check the VLAN type */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, DOVLTC, 1);
+
+       /* Check only C-TAG (0x8100) packets */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ERSVLM, 0);
+
+       /* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ESVL, 0);
+
+       /* Enable VLAN tag stripping */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0x3);
+
+       return 0;
+}
+
+static int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
+{
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0);
+
+       return 0;
+}
+
+static int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
+{
+       /* Enable VLAN filtering */
+       XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1);
+
+       /* Enable VLAN Hash Table filtering */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1);
+
+       /* Disable VLAN tag inverse matching */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0);
+
+       /* Only filter on the lower 12-bits of the VLAN tag */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1);
+
+       /* In order for the VLAN Hash Table filtering to be effective,
+        * the VLAN tag identifier in the VLAN Tag Register must not
+        * be zero.  Set the VLAN tag identifier to "1" to enable the
+        * VLAN Hash Table filtering.  This implies that a VLAN tag of
+        * 1 will always pass filtering.
+        */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1);
+
+       return 0;
+}
+
+static int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
+{
+       /* Disable VLAN filtering */
+       XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0);
+
+       return 0;
+}
+
+static u32 xgbe_vid_crc32_le(__le16 vid_le)
+{
+       u32 poly = 0xedb88320;  /* CRCPOLY_LE */
+       u32 crc = ~0;
+       u32 temp = 0;
+       unsigned char *data = (unsigned char *)&vid_le;
+       unsigned char data_byte = 0;
+       int i, bits;
+
+       bits = get_bitmask_order(VLAN_VID_MASK);
+       for (i = 0; i < bits; i++) {
+               if ((i % 8) == 0)
+                       data_byte = data[i / 8];
+
+               temp = ((crc & 1) ^ data_byte) & 1;
+               crc >>= 1;
+               data_byte >>= 1;
+
+               if (temp)
+                       crc ^= poly;
+       }
+
+       return crc;
+}
+
+static int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata)
+{
+       u32 crc;
+       u16 vid;
+       __le16 vid_le;
+       u16 vlan_hash_table = 0;
+
+       /* Generate the VLAN Hash Table value */
+       for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) {
+               /* Get the CRC32 value of the VLAN ID */
+               vid_le = cpu_to_le16(vid);
+               crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28;
+
+               vlan_hash_table |= (1 << crc);
+       }
+
+       /* Set the VLAN Hash Table filtering register */
+       XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table);
+
+       return 0;
+}
+
 static int xgbe_set_promiscuous_mode(struct xgbe_prv_data *pdata,
                                     unsigned int enable)
 {
@@ -714,6 +853,14 @@ static int xgbe_set_promiscuous_mode(struct xgbe_prv_data *pdata,
                  enable ? "entering" : "leaving");
        XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, val);
 
+       /* Hardware will still perform VLAN filtering in promiscuous mode */
+       if (enable) {
+               xgbe_disable_rx_vlan_filtering(pdata);
+       } else {
+               if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+                       xgbe_enable_rx_vlan_filtering(pdata);
+       }
+
        return 0;
 }
 
@@ -875,6 +1022,7 @@ static int xgbe_config_rx_mode(struct xgbe_prv_data *pdata)
 static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
                              int mmd_reg)
 {
+       unsigned long flags;
        unsigned int mmd_address;
        int mmd_data;
 
@@ -892,10 +1040,10 @@ static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
         * register offsets must therefore be adjusted by left shifting the
         * offset 2 bits and reading 32 bits of data.
         */
-       mutex_lock(&pdata->xpcs_mutex);
+       spin_lock_irqsave(&pdata->xpcs_lock, flags);
        XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8);
        mmd_data = XPCS_IOREAD(pdata, (mmd_address & 0xff) << 2);
-       mutex_unlock(&pdata->xpcs_mutex);
+       spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
 
        return mmd_data;
 }
@@ -904,6 +1052,7 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
                                int mmd_reg, int mmd_data)
 {
        unsigned int mmd_address;
+       unsigned long flags;
 
        if (mmd_reg & MII_ADDR_C45)
                mmd_address = mmd_reg & ~MII_ADDR_C45;
@@ -919,10 +1068,10 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
         * register offsets must therefore be adjusted by left shifting the
         * offset 2 bits and reading 32 bits of data.
         */
-       mutex_lock(&pdata->xpcs_mutex);
+       spin_lock_irqsave(&pdata->xpcs_lock, flags);
        XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8);
        XPCS_IOWRITE(pdata, (mmd_address & 0xff) << 2, mmd_data);
-       mutex_unlock(&pdata->xpcs_mutex);
+       spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
 }
 
 static int xgbe_tx_complete(struct xgbe_ring_desc *rdesc)
@@ -944,116 +1093,6 @@ static int xgbe_enable_rx_csum(struct xgbe_prv_data *pdata)
        return 0;
 }
 
-static int xgbe_enable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
-{
-       /* Put the VLAN tag in the Rx descriptor */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLRXS, 1);
-
-       /* Don't check the VLAN type */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, DOVLTC, 1);
-
-       /* Check only C-TAG (0x8100) packets */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ERSVLM, 0);
-
-       /* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ESVL, 0);
-
-       /* Enable VLAN tag stripping */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0x3);
-
-       return 0;
-}
-
-static int xgbe_disable_rx_vlan_stripping(struct xgbe_prv_data *pdata)
-{
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, EVLS, 0);
-
-       return 0;
-}
-
-static int xgbe_enable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
-{
-       /* Enable VLAN filtering */
-       XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1);
-
-       /* Enable VLAN Hash Table filtering */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTHM, 1);
-
-       /* Disable VLAN tag inverse matching */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VTIM, 0);
-
-       /* Only filter on the lower 12-bits of the VLAN tag */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, ETV, 1);
-
-       /* In order for the VLAN Hash Table filtering to be effective,
-        * the VLAN tag identifier in the VLAN Tag Register must not
-        * be zero.  Set the VLAN tag identifier to "1" to enable the
-        * VLAN Hash Table filtering.  This implies that a VLAN tag of
-        * 1 will always pass filtering.
-        */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANTR, VL, 1);
-
-       return 0;
-}
-
-static int xgbe_disable_rx_vlan_filtering(struct xgbe_prv_data *pdata)
-{
-       /* Disable VLAN filtering */
-       XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0);
-
-       return 0;
-}
-
-#ifndef CRCPOLY_LE
-#define CRCPOLY_LE 0xedb88320
-#endif
-static u32 xgbe_vid_crc32_le(__le16 vid_le)
-{
-       u32 poly = CRCPOLY_LE;
-       u32 crc = ~0;
-       u32 temp = 0;
-       unsigned char *data = (unsigned char *)&vid_le;
-       unsigned char data_byte = 0;
-       int i, bits;
-
-       bits = get_bitmask_order(VLAN_VID_MASK);
-       for (i = 0; i < bits; i++) {
-               if ((i % 8) == 0)
-                       data_byte = data[i / 8];
-
-               temp = ((crc & 1) ^ data_byte) & 1;
-               crc >>= 1;
-               data_byte >>= 1;
-
-               if (temp)
-                       crc ^= poly;
-       }
-
-       return crc;
-}
-
-static int xgbe_update_vlan_hash_table(struct xgbe_prv_data *pdata)
-{
-       u32 crc;
-       u16 vid;
-       __le16 vid_le;
-       u16 vlan_hash_table = 0;
-
-       /* Generate the VLAN Hash Table value */
-       for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) {
-               /* Get the CRC32 value of the VLAN ID */
-               vid_le = cpu_to_le16(vid);
-               crc = bitrev32(~xgbe_vid_crc32_le(vid_le)) >> 28;
-
-               vlan_hash_table |= (1 << crc);
-       }
-
-       /* Set the VLAN Hash Table filtering register */
-       XGMAC_IOWRITE_BITS(pdata, MAC_VLANHTR, VLHT, vlan_hash_table);
-
-       return 0;
-}
-
 static void xgbe_tx_desc_reset(struct xgbe_ring_data *rdata)
 {
        struct xgbe_ring_desc *rdesc = rdata->rdesc;
@@ -1288,11 +1327,42 @@ static int xgbe_config_tstamp(struct xgbe_prv_data *pdata,
        return 0;
 }
 
+static void xgbe_config_tc(struct xgbe_prv_data *pdata)
+{
+       unsigned int offset, queue, prio;
+       u8 i;
+
+       netdev_reset_tc(pdata->netdev);
+       if (!pdata->num_tcs)
+               return;
+
+       netdev_set_num_tc(pdata->netdev, pdata->num_tcs);
+
+       for (i = 0, queue = 0, offset = 0; i < pdata->num_tcs; i++) {
+               while ((queue < pdata->tx_q_count) &&
+                      (pdata->q2tc_map[queue] == i))
+                       queue++;
+
+               netif_dbg(pdata, drv, pdata->netdev, "TC%u using TXq%u-%u\n",
+                         i, offset, queue - 1);
+               netdev_set_tc_queue(pdata->netdev, i, queue - offset, offset);
+               offset = queue;
+       }
+
+       if (!pdata->ets)
+               return;
+
+       for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++)
+               netdev_set_prio_tc_map(pdata->netdev, prio,
+                                      pdata->ets->prio_tc[prio]);
+}
+
 static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
 {
        struct ieee_ets *ets = pdata->ets;
        unsigned int total_weight, min_weight, weight;
-       unsigned int i;
+       unsigned int mask, reg, reg_val;
+       unsigned int i, prio;
 
        if (!ets)
                return;
@@ -1309,6 +1379,25 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
                min_weight = 1;
 
        for (i = 0; i < pdata->hw_feat.tc_cnt; i++) {
+               /* Map the priorities to the traffic class */
+               mask = 0;
+               for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
+                       if (ets->prio_tc[prio] == i)
+                               mask |= (1 << prio);
+               }
+               mask &= 0xff;
+
+               netif_dbg(pdata, drv, pdata->netdev, "TC%u PRIO mask=%#x\n",
+                         i, mask);
+               reg = MTL_TCPM0R + (MTL_TCPM_INC * (i / MTL_TCPM_TC_PER_REG));
+               reg_val = XGMAC_IOREAD(pdata, reg);
+
+               reg_val &= ~(0xff << ((i % MTL_TCPM_TC_PER_REG) << 3));
+               reg_val |= (mask << ((i % MTL_TCPM_TC_PER_REG) << 3));
+
+               XGMAC_IOWRITE(pdata, reg, reg_val);
+
+               /* Set the traffic class algorithm */
                switch (ets->tc_tsa[i]) {
                case IEEE_8021QAZ_TSA_STRICT:
                        netif_dbg(pdata, drv, pdata->netdev,
@@ -1329,38 +1418,12 @@ static void xgbe_config_dcb_tc(struct xgbe_prv_data *pdata)
                        break;
                }
        }
+
+       xgbe_config_tc(pdata);
 }
 
 static void xgbe_config_dcb_pfc(struct xgbe_prv_data *pdata)
 {
-       struct ieee_pfc *pfc = pdata->pfc;
-       struct ieee_ets *ets = pdata->ets;
-       unsigned int mask, reg, reg_val;
-       unsigned int tc, prio;
-
-       if (!pfc || !ets)
-               return;
-
-       for (tc = 0; tc < pdata->hw_feat.tc_cnt; tc++) {
-               mask = 0;
-               for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; prio++) {
-                       if ((pfc->pfc_en & (1 << prio)) &&
-                           (ets->prio_tc[prio] == tc))
-                               mask |= (1 << prio);
-               }
-               mask &= 0xff;
-
-               netif_dbg(pdata, drv, pdata->netdev, "TC%u PFC mask=%#x\n",
-                         tc, mask);
-               reg = MTL_TCPM0R + (MTL_TCPM_INC * (tc / MTL_TCPM_TC_PER_REG));
-               reg_val = XGMAC_IOREAD(pdata, reg);
-
-               reg_val &= ~(0xff << ((tc % MTL_TCPM_TC_PER_REG) << 3));
-               reg_val |= (mask << ((tc % MTL_TCPM_TC_PER_REG) << 3));
-
-               XGMAC_IOWRITE(pdata, reg, reg_val);
-       }
-
        xgbe_config_flow_control(pdata);
 }
 
@@ -2595,6 +2658,32 @@ static void xgbe_disable_tx(struct xgbe_prv_data *pdata)
        }
 }
 
+static void xgbe_prepare_rx_stop(struct xgbe_prv_data *pdata,
+                                unsigned int queue)
+{
+       unsigned int rx_status;
+       unsigned long rx_timeout;
+
+       /* The Rx engine cannot be stopped if it is actively processing
+        * packets. Wait for the Rx queue to empty the Rx fifo.  Don't
+        * wait forever though...
+        */
+       rx_timeout = jiffies + (XGBE_DMA_STOP_TIMEOUT * HZ);
+       while (time_before(jiffies, rx_timeout)) {
+               rx_status = XGMAC_MTL_IOREAD(pdata, queue, MTL_Q_RQDR);
+               if ((XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, PRXQ) == 0) &&
+                   (XGMAC_GET_BITS(rx_status, MTL_Q_RQDR, RXQSTS) == 0))
+                       break;
+
+               usleep_range(500, 1000);
+       }
+
+       if (!time_before(jiffies, rx_timeout))
+               netdev_info(pdata->netdev,
+                           "timed out waiting for Rx queue %u to empty\n",
+                           queue);
+}
+
 static void xgbe_enable_rx(struct xgbe_prv_data *pdata)
 {
        struct xgbe_channel *channel;
@@ -2633,6 +2722,10 @@ static void xgbe_disable_rx(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE_BITS(pdata, MAC_RCR, ACS, 0);
        XGMAC_IOWRITE_BITS(pdata, MAC_RCR, RE, 0);
 
+       /* Prepare for Rx DMA channel stop */
+       for (i = 0; i < pdata->rx_q_count; i++)
+               xgbe_prepare_rx_stop(pdata, i);
+
        /* Disable each Rx queue */
        XGMAC_IOWRITE(pdata, MAC_RQC0R, 0);
 
@@ -2881,6 +2974,7 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if)
        hw_if->get_tx_tstamp = xgbe_get_tx_tstamp;
 
        /* For Data Center Bridging config */
+       hw_if->config_tc = xgbe_config_tc;
        hw_if->config_dcb_tc = xgbe_config_dcb_tc;
        hw_if->config_dcb_pfc = xgbe_config_dcb_pfc;
 
index 8a9b493566c90f9443099f94146945931f61c3b4..ebf9224b2d312fa1ecc4d43434bde81d751c8df0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -356,7 +356,7 @@ static irqreturn_t xgbe_isr(int irq, void *data)
                                xgbe_disable_rx_tx_ints(pdata);
 
                                /* Turn on polling */
-                               __napi_schedule(&pdata->napi);
+                               __napi_schedule_irqoff(&pdata->napi);
                        }
                }
 
@@ -409,7 +409,7 @@ static irqreturn_t xgbe_dma_isr(int irq, void *data)
                disable_irq_nosync(channel->dma_irq);
 
                /* Turn on polling */
-               __napi_schedule(&channel->napi);
+               __napi_schedule_irqoff(&channel->napi);
        }
 
        return IRQ_HANDLED;
@@ -1626,30 +1626,22 @@ static void xgbe_poll_controller(struct net_device *netdev)
 }
 #endif /* End CONFIG_NET_POLL_CONTROLLER */
 
-static int xgbe_setup_tc(struct net_device *netdev, u8 tc)
+static int xgbe_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+                        struct tc_to_netdev *tc_to_netdev)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
-       unsigned int offset, queue;
-       u8 i;
+       u8 tc;
 
-       if (tc && (tc != pdata->hw_feat.tc_cnt))
+       if (tc_to_netdev->type != TC_SETUP_MQPRIO)
                return -EINVAL;
 
-       if (tc) {
-               netdev_set_num_tc(netdev, tc);
-               for (i = 0, queue = 0, offset = 0; i < tc; i++) {
-                       while ((queue < pdata->tx_q_count) &&
-                              (pdata->q2tc_map[queue] == i))
-                               queue++;
-
-                       netif_dbg(pdata, drv, netdev, "TC%u using TXq%u-%u\n",
-                                 i, offset, queue - 1);
-                       netdev_set_tc_queue(netdev, i, queue - offset, offset);
-                       offset = queue;
-               }
-       } else {
-               netdev_reset_tc(netdev);
-       }
+       tc = tc_to_netdev->tc;
+
+       if (tc > pdata->hw_feat.tc_cnt)
+               return -EINVAL;
+
+       pdata->num_tcs = tc;
+       pdata->hw_if.config_tc(pdata);
 
        return 0;
 }
@@ -2062,7 +2054,7 @@ static int xgbe_one_poll(struct napi_struct *napi, int budget)
        /* If we processed everything, we are done */
        if (processed < budget) {
                /* Turn off polling */
-               napi_complete(napi);
+               napi_complete_done(napi, processed);
 
                /* Enable Tx and Rx interrupts */
                enable_irq(channel->dma_irq);
@@ -2104,7 +2096,7 @@ static int xgbe_all_poll(struct napi_struct *napi, int budget)
        /* If we processed everything, we are done */
        if (processed < budget) {
                /* Turn off polling */
-               napi_complete(napi);
+               napi_complete_done(napi, processed);
 
                /* Enable Tx and Rx interrupts */
                xgbe_enable_rx_tx_ints(pdata);
index 6040293db9c1694083ace197771a09245feea637..11d9f0c5b78bf819e59a1d71b385fbfaf7ed97bc 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -318,8 +318,20 @@ static int xgbe_set_settings(struct net_device *netdev,
        if (cmd->autoneg == AUTONEG_DISABLE) {
                switch (speed) {
                case SPEED_10000:
+                       break;
                case SPEED_2500:
+                       if (pdata->speed_set != XGBE_SPEEDSET_2500_10000) {
+                               netdev_err(netdev, "unsupported speed %u\n",
+                                          speed);
+                               return -EINVAL;
+                       }
+                       break;
                case SPEED_1000:
+                       if (pdata->speed_set != XGBE_SPEEDSET_1000_10000) {
+                               netdev_err(netdev, "unsupported speed %u\n",
+                                          speed);
+                               return -EINVAL;
+                       }
                        break;
                default:
                        netdev_err(netdev, "unsupported speed %u\n", speed);
index 618d952c2984c3756cee516fb4623f0cb6a80afd..3eee3201b58fe53edad393d491eaa712daf7fba6 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -363,7 +363,7 @@ static int xgbe_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, netdev);
 
        spin_lock_init(&pdata->lock);
-       mutex_init(&pdata->xpcs_mutex);
+       spin_lock_init(&pdata->xpcs_lock);
        mutex_init(&pdata->rss_mutex);
        spin_lock_init(&pdata->tstamp_lock);
 
index 4460580818665d80e04ad6e53039d7d7e7f5fc99..84c5d296d13e85b2ee7425ac75833312cf6819e5 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -626,10 +626,22 @@ static irqreturn_t xgbe_an_isr(int irq, void *data)
 
        netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
 
-       /* Interrupt reason must be read and cleared outside of IRQ context */
-       disable_irq_nosync(pdata->an_irq);
+       /* Disable AN interrupts */
+       XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+
+       /* Save the interrupt(s) that fired */
+       pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
 
-       queue_work(pdata->an_workqueue, &pdata->an_irq_work);
+       if (pdata->an_int) {
+               /* Clear the interrupt(s) that fired and process them */
+               XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
+
+               queue_work(pdata->an_workqueue, &pdata->an_irq_work);
+       } else {
+               /* Enable AN interrupts */
+               XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK,
+                           XGBE_AN_INT_MASK);
+       }
 
        return IRQ_HANDLED;
 }
@@ -673,34 +685,26 @@ static void xgbe_an_state_machine(struct work_struct *work)
                                                   struct xgbe_prv_data,
                                                   an_work);
        enum xgbe_an cur_state = pdata->an_state;
-       unsigned int int_reg, int_mask;
 
        mutex_lock(&pdata->an_mutex);
 
-       /* Read the interrupt */
-       int_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
-       if (!int_reg)
+       if (!pdata->an_int)
                goto out;
 
 next_int:
-       if (int_reg & XGBE_AN_PG_RCV) {
+       if (pdata->an_int & XGBE_AN_PG_RCV) {
                pdata->an_state = XGBE_AN_PAGE_RECEIVED;
-               int_mask = XGBE_AN_PG_RCV;
-       } else if (int_reg & XGBE_AN_INC_LINK) {
+               pdata->an_int &= ~XGBE_AN_PG_RCV;
+       } else if (pdata->an_int & XGBE_AN_INC_LINK) {
                pdata->an_state = XGBE_AN_INCOMPAT_LINK;
-               int_mask = XGBE_AN_INC_LINK;
-       } else if (int_reg & XGBE_AN_INT_CMPLT) {
+               pdata->an_int &= ~XGBE_AN_INC_LINK;
+       } else if (pdata->an_int & XGBE_AN_INT_CMPLT) {
                pdata->an_state = XGBE_AN_COMPLETE;
-               int_mask = XGBE_AN_INT_CMPLT;
+               pdata->an_int &= ~XGBE_AN_INT_CMPLT;
        } else {
                pdata->an_state = XGBE_AN_ERROR;
-               int_mask = 0;
        }
 
-       /* Clear the interrupt to be processed */
-       int_reg &= ~int_mask;
-       XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, int_reg);
-
        pdata->an_result = pdata->an_state;
 
 again:
@@ -740,14 +744,14 @@ again:
        }
 
        if (pdata->an_state == XGBE_AN_NO_LINK) {
-               int_reg = 0;
+               pdata->an_int = 0;
                XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
        } else if (pdata->an_state == XGBE_AN_ERROR) {
                netdev_err(pdata->netdev,
                           "error during auto-negotiation, state=%u\n",
                           cur_state);
 
-               int_reg = 0;
+               pdata->an_int = 0;
                XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
        }
 
@@ -765,11 +769,12 @@ again:
        if (cur_state != pdata->an_state)
                goto again;
 
-       if (int_reg)
+       if (pdata->an_int)
                goto next_int;
 
 out:
-       enable_irq(pdata->an_irq);
+       /* Enable AN interrupts on the way out */
+       XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_INT_MASK);
 
        mutex_unlock(&pdata->an_mutex);
 }
index e234b9970318a37ec1e5f3048fe86c8aa4dcf919..98d9d63c4353370c464e06a210b9af3b37e83133 100644 (file)
@@ -6,7 +6,7 @@
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,7 +56,7 @@
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -673,6 +673,7 @@ struct xgbe_hw_if {
        u64 (*get_tx_tstamp)(struct xgbe_prv_data *);
 
        /* For Data Center Bridging config */
+       void (*config_tc)(struct xgbe_prv_data *);
        void (*config_dcb_tc)(struct xgbe_prv_data *);
        void (*config_dcb_pfc)(struct xgbe_prv_data *);
 
@@ -773,8 +774,8 @@ struct xgbe_prv_data {
        /* Overall device lock */
        spinlock_t lock;
 
-       /* XPCS indirect addressing mutex */
-       struct mutex xpcs_mutex;
+       /* XPCS indirect addressing lock */
+       spinlock_t xpcs_lock;
 
        /* RSS addressing mutex */
        struct mutex rss_mutex;
@@ -880,6 +881,7 @@ struct xgbe_prv_data {
        struct ieee_pfc *pfc;
        unsigned int q2tc_map[XGBE_MAX_QUEUES];
        unsigned int prio2q_map[IEEE_8021QAZ_MAX_TCS];
+       u8 num_tcs;
 
        /* Hardware features of the device */
        struct xgbe_hw_features hw_feat;
@@ -925,6 +927,7 @@ struct xgbe_prv_data {
        u32 serdes_dfe_tap_ena[XGBE_SPEEDS];
 
        /* Auto-negotiation state machine support */
+       unsigned int an_int;
        struct mutex an_mutex;
        enum xgbe_an an_result;
        enum xgbe_an an_state;
index 700b5abe5de5f5fe95c1c5fcf45b1413b4253cc6..f46321f6831554d90f6ab86751de92102dd573a9 100644 (file)
@@ -3,5 +3,6 @@
 #
 
 xgene-enet-objs := xgene_enet_hw.o xgene_enet_sgmac.o xgene_enet_xgmac.o \
-                  xgene_enet_main.o xgene_enet_ring2.o xgene_enet_ethtool.o
+                  xgene_enet_main.o xgene_enet_ring2.o xgene_enet_ethtool.o \
+                  xgene_enet_cle.o
 obj-$(CONFIG_NET_XGENE) += xgene-enet.o
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_cle.c b/drivers/net/ethernet/apm/xgene/xgene_enet_cle.c
new file mode 100644 (file)
index 0000000..b212488
--- /dev/null
@@ -0,0 +1,734 @@
+/* Applied Micro X-Gene SoC Ethernet Classifier structures
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Authors: Khuong Dinh <kdinh@apm.com>
+ *          Tanmay Inamdar <tinamdar@apm.com>
+ *          Iyappan Subramanian <isubramanian@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "xgene_enet_main.h"
+
+/* interfaces to convert structures to HW recognized bit formats */
+static void xgene_cle_sband_to_hw(u8 frag, enum xgene_cle_prot_version ver,
+                                 enum xgene_cle_prot_type type, u32 len,
+                                 u32 *reg)
+{
+       *reg =  SET_VAL(SB_IPFRAG, frag) |
+               SET_VAL(SB_IPPROT, type) |
+               SET_VAL(SB_IPVER, ver) |
+               SET_VAL(SB_HDRLEN, len);
+}
+
+static void xgene_cle_idt_to_hw(u32 dstqid, u32 fpsel,
+                               u32 nfpsel, u32 *idt_reg)
+{
+       *idt_reg =  SET_VAL(IDT_DSTQID, dstqid) |
+                   SET_VAL(IDT_FPSEL, fpsel) |
+                   SET_VAL(IDT_NFPSEL, nfpsel);
+}
+
+static void xgene_cle_dbptr_to_hw(struct xgene_enet_pdata *pdata,
+                                 struct xgene_cle_dbptr *dbptr, u32 *buf)
+{
+       buf[4] = SET_VAL(CLE_FPSEL, dbptr->fpsel) |
+                SET_VAL(CLE_DSTQIDL, dbptr->dstqid);
+
+       buf[5] = SET_VAL(CLE_DSTQIDH, (u32)dbptr->dstqid >> CLE_DSTQIDL_LEN) |
+                SET_VAL(CLE_PRIORITY, dbptr->cle_priority);
+}
+
+static void xgene_cle_kn_to_hw(struct xgene_cle_ptree_kn *kn, u32 *buf)
+{
+       u32 i, j = 0;
+       u32 data;
+
+       buf[j++] = SET_VAL(CLE_TYPE, kn->node_type);
+       for (i = 0; i < kn->num_keys; i++) {
+               struct xgene_cle_ptree_key *key = &kn->key[i];
+
+               if (!(i % 2)) {
+                       buf[j] = SET_VAL(CLE_KN_PRIO, key->priority) |
+                                SET_VAL(CLE_KN_RPTR, key->result_pointer);
+               } else {
+                       data = SET_VAL(CLE_KN_PRIO, key->priority) |
+                              SET_VAL(CLE_KN_RPTR, key->result_pointer);
+                       buf[j++] |= (data << 16);
+               }
+       }
+}
+
+static void xgene_cle_dn_to_hw(struct xgene_cle_ptree_ewdn *dn,
+                              u32 *buf, u32 jb)
+{
+       struct xgene_cle_ptree_branch *br;
+       u32 i, j = 0;
+       u32 npp;
+
+       buf[j++] = SET_VAL(CLE_DN_TYPE, dn->node_type) |
+                  SET_VAL(CLE_DN_LASTN, dn->last_node) |
+                  SET_VAL(CLE_DN_HLS, dn->hdr_len_store) |
+                  SET_VAL(CLE_DN_EXT, dn->hdr_extn) |
+                  SET_VAL(CLE_DN_BSTOR, dn->byte_store) |
+                  SET_VAL(CLE_DN_SBSTOR, dn->search_byte_store) |
+                  SET_VAL(CLE_DN_RPTR, dn->result_pointer);
+
+       for (i = 0; i < dn->num_branches; i++) {
+               br = &dn->branch[i];
+               npp = br->next_packet_pointer;
+
+               if ((br->jump_rel == JMP_ABS) && (npp < CLE_PKTRAM_SIZE))
+                       npp += jb;
+
+               buf[j++] = SET_VAL(CLE_BR_VALID, br->valid) |
+                          SET_VAL(CLE_BR_NPPTR, npp) |
+                          SET_VAL(CLE_BR_JB, br->jump_bw) |
+                          SET_VAL(CLE_BR_JR, br->jump_rel) |
+                          SET_VAL(CLE_BR_OP, br->operation) |
+                          SET_VAL(CLE_BR_NNODE, br->next_node) |
+                          SET_VAL(CLE_BR_NBR, br->next_branch);
+
+               buf[j++] = SET_VAL(CLE_BR_DATA, br->data) |
+                          SET_VAL(CLE_BR_MASK, br->mask);
+       }
+}
+
+static int xgene_cle_poll_cmd_done(void __iomem *base,
+                                  enum xgene_cle_cmd_type cmd)
+{
+       u32 status, loop = 10;
+       int ret = -EBUSY;
+
+       while (loop--) {
+               status = ioread32(base + INDCMD_STATUS);
+               if (status & cmd) {
+                       ret = 0;
+                       break;
+               }
+               usleep_range(1000, 2000);
+       }
+
+       return ret;
+}
+
+static int xgene_cle_dram_wr(struct xgene_enet_cle *cle, u32 *data, u8 nregs,
+                            u32 index, enum xgene_cle_dram_type type,
+                            enum xgene_cle_cmd_type cmd)
+{
+       enum xgene_cle_parser parser = cle->active_parser;
+       void __iomem *base = cle->base;
+       u32 i, j, ind_addr;
+       u8 port, nparsers;
+       int ret = 0;
+
+       /* PTREE_RAM onwards, DRAM regions are common for all parsers */
+       nparsers = (type >= PTREE_RAM) ? 1 : cle->parsers;
+
+       for (i = 0; i < nparsers; i++) {
+               port = i;
+               if ((type < PTREE_RAM) && (parser != PARSER_ALL))
+                       port = parser;
+
+               ind_addr = XGENE_CLE_DRAM(type + (port * 4)) | index;
+               iowrite32(ind_addr, base + INDADDR);
+               for (j = 0; j < nregs; j++)
+                       iowrite32(data[j], base + DATA_RAM0 + (j * 4));
+               iowrite32(cmd, base + INDCMD);
+
+               ret = xgene_cle_poll_cmd_done(base, cmd);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static void xgene_cle_enable_ptree(struct xgene_enet_pdata *pdata,
+                                  struct xgene_enet_cle *cle)
+{
+       struct xgene_cle_ptree *ptree = &cle->ptree;
+       void __iomem *addr, *base = cle->base;
+       u32 offset = CLE_PORT_OFFSET;
+       u32 i;
+
+       /* 1G port has to advance 4 bytes and 10G has to advance 8 bytes */
+       ptree->start_pkt += cle->jump_bytes;
+       for (i = 0; i < cle->parsers; i++) {
+               if (cle->active_parser != PARSER_ALL)
+                       addr = base + cle->active_parser * offset;
+               else
+                       addr = base + (i * offset);
+
+               iowrite32(ptree->start_node & 0x3fff, addr + SNPTR0);
+               iowrite32(ptree->start_pkt & 0x1ff, addr + SPPTR0);
+       }
+}
+
+static int xgene_cle_setup_dbptr(struct xgene_enet_pdata *pdata,
+                                struct xgene_enet_cle *cle)
+{
+       struct xgene_cle_ptree *ptree = &cle->ptree;
+       u32 buf[CLE_DRAM_REGS];
+       u32 i;
+       int ret;
+
+       memset(buf, 0, sizeof(buf));
+       for (i = 0; i < ptree->num_dbptr; i++) {
+               xgene_cle_dbptr_to_hw(pdata, &ptree->dbptr[i], buf);
+               ret = xgene_cle_dram_wr(cle, buf, 6, i + ptree->start_dbptr,
+                                       DB_RAM, CLE_CMD_WR);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int xgene_cle_setup_node(struct xgene_enet_pdata *pdata,
+                               struct xgene_enet_cle *cle)
+{
+       struct xgene_cle_ptree *ptree = &cle->ptree;
+       struct xgene_cle_ptree_ewdn *dn = ptree->dn;
+       struct xgene_cle_ptree_kn *kn = ptree->kn;
+       u32 buf[CLE_DRAM_REGS];
+       int i, j, ret;
+
+       memset(buf, 0, sizeof(buf));
+       for (i = 0; i < ptree->num_dn; i++) {
+               xgene_cle_dn_to_hw(&dn[i], buf, cle->jump_bytes);
+               ret = xgene_cle_dram_wr(cle, buf, 17, i + ptree->start_node,
+                                       PTREE_RAM, CLE_CMD_WR);
+               if (ret)
+                       return ret;
+       }
+
+       /* continue node index for key node */
+       memset(buf, 0, sizeof(buf));
+       for (j = i; j < (ptree->num_kn + ptree->num_dn); j++) {
+               xgene_cle_kn_to_hw(&kn[j - ptree->num_dn], buf);
+               ret = xgene_cle_dram_wr(cle, buf, 17, j + ptree->start_node,
+                                       PTREE_RAM, CLE_CMD_WR);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int xgene_cle_setup_ptree(struct xgene_enet_pdata *pdata,
+                                struct xgene_enet_cle *cle)
+{
+       int ret;
+
+       ret = xgene_cle_setup_node(pdata, cle);
+       if (ret)
+               return ret;
+
+       ret = xgene_cle_setup_dbptr(pdata, cle);
+       if (ret)
+               return ret;
+
+       xgene_cle_enable_ptree(pdata, cle);
+
+       return 0;
+}
+
+static void xgene_cle_setup_def_dbptr(struct xgene_enet_pdata *pdata,
+                                     struct xgene_enet_cle *enet_cle,
+                                     struct xgene_cle_dbptr *dbptr,
+                                     u32 index, u8 priority)
+{
+       void __iomem *base = enet_cle->base;
+       void __iomem *base_addr;
+       u32 buf[CLE_DRAM_REGS];
+       u32 def_cls, offset;
+       u32 i, j;
+
+       memset(buf, 0, sizeof(buf));
+       xgene_cle_dbptr_to_hw(pdata, dbptr, buf);
+
+       for (i = 0; i < enet_cle->parsers; i++) {
+               if (enet_cle->active_parser != PARSER_ALL) {
+                       offset = enet_cle->active_parser *
+                               CLE_PORT_OFFSET;
+               } else {
+                       offset = i * CLE_PORT_OFFSET;
+               }
+
+               base_addr = base + DFCLSRESDB00 + offset;
+               for (j = 0; j < 6; j++)
+                       iowrite32(buf[j], base_addr + (j * 4));
+
+               def_cls = ((priority & 0x7) << 10) | (index & 0x3ff);
+               iowrite32(def_cls, base + DFCLSRESDBPTR0 + offset);
+       }
+}
+
+static int xgene_cle_set_rss_sband(struct xgene_enet_cle *cle)
+{
+       u32 idx = CLE_PKTRAM_SIZE / sizeof(u32);
+       u32 mac_hdr_len = ETH_HLEN;
+       u32 sband, reg = 0;
+       u32 ipv4_ihl = 5;
+       u32 hdr_len;
+       int ret;
+
+       /* Sideband: IPV4/TCP packets */
+       hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+       xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_TCP, hdr_len, &reg);
+       sband = reg;
+
+       /* Sideband: IPv4/UDP packets */
+       hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+       xgene_cle_sband_to_hw(1, XGENE_CLE_IPV4, XGENE_CLE_UDP, hdr_len, &reg);
+       sband |= (reg << 16);
+
+       ret = xgene_cle_dram_wr(cle, &sband, 1, idx, PKT_RAM, CLE_CMD_WR);
+       if (ret)
+               return ret;
+
+       /* Sideband: IPv4/RAW packets */
+       hdr_len = (mac_hdr_len << 5) | ipv4_ihl;
+       xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
+                             hdr_len, &reg);
+       sband = reg;
+
+       /* Sideband: Ethernet II/RAW packets */
+       hdr_len = (mac_hdr_len << 5);
+       xgene_cle_sband_to_hw(0, XGENE_CLE_IPV4, XGENE_CLE_OTHER,
+                             hdr_len, &reg);
+       sband |= (reg << 16);
+
+       ret = xgene_cle_dram_wr(cle, &sband, 1, idx + 1, PKT_RAM, CLE_CMD_WR);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int xgene_cle_set_rss_skeys(struct xgene_enet_cle *cle)
+{
+       u32 secret_key_ipv4[4];  /* 16 Bytes*/
+       int ret = 0;
+
+       get_random_bytes(secret_key_ipv4, 16);
+       ret = xgene_cle_dram_wr(cle, secret_key_ipv4, 4, 0,
+                               RSS_IPV4_HASH_SKEY, CLE_CMD_WR);
+       return ret;
+}
+
+static int xgene_cle_set_rss_idt(struct xgene_enet_pdata *pdata)
+{
+       u32 fpsel, dstqid, nfpsel, idt_reg, idx;
+       int i, ret = 0;
+       u16 pool_id;
+
+       for (i = 0; i < XGENE_CLE_IDT_ENTRIES; i++) {
+               idx = i % pdata->rxq_cnt;
+               pool_id = pdata->rx_ring[idx]->buf_pool->id;
+               fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
+               dstqid = xgene_enet_dst_ring_num(pdata->rx_ring[idx]);
+               nfpsel = 0;
+               idt_reg = 0;
+
+               xgene_cle_idt_to_hw(dstqid, fpsel, nfpsel, &idt_reg);
+               ret = xgene_cle_dram_wr(&pdata->cle, &idt_reg, 1, i,
+                                       RSS_IDT, CLE_CMD_WR);
+               if (ret)
+                       return ret;
+       }
+
+       ret = xgene_cle_set_rss_skeys(&pdata->cle);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int xgene_cle_setup_rss(struct xgene_enet_pdata *pdata)
+{
+       struct xgene_enet_cle *cle = &pdata->cle;
+       void __iomem *base = cle->base;
+       u32 offset, val = 0;
+       int i, ret = 0;
+
+       offset = CLE_PORT_OFFSET;
+       for (i = 0; i < cle->parsers; i++) {
+               if (cle->active_parser != PARSER_ALL)
+                       offset = cle->active_parser * CLE_PORT_OFFSET;
+               else
+                       offset = i * CLE_PORT_OFFSET;
+
+               /* enable RSS */
+               val = (RSS_IPV4_12B << 1) | 0x1;
+               writel(val, base + RSS_CTRL0 + offset);
+       }
+
+       /* setup sideband data */
+       ret = xgene_cle_set_rss_sband(cle);
+       if (ret)
+               return ret;
+
+       /* setup indirection table */
+       ret = xgene_cle_set_rss_idt(pdata);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int xgene_enet_cle_init(struct xgene_enet_pdata *pdata)
+{
+       struct xgene_enet_cle *enet_cle = &pdata->cle;
+       struct xgene_cle_dbptr dbptr[DB_MAX_PTRS];
+       struct xgene_cle_ptree_branch *br;
+       u32 def_qid, def_fpsel, pool_id;
+       struct xgene_cle_ptree *ptree;
+       struct xgene_cle_ptree_kn kn;
+       int ret;
+       struct xgene_cle_ptree_ewdn ptree_dn[] = {
+               {
+                       /* PKT_TYPE_NODE */
+                       .node_type = EWDN,
+                       .last_node = 0,
+                       .hdr_len_store = 1,
+                       .hdr_extn = NO_BYTE,
+                       .byte_store = NO_BYTE,
+                       .search_byte_store = NO_BYTE,
+                       .result_pointer = DB_RES_DROP,
+                       .num_branches = 2,
+                       .branch = {
+                               {
+                                       /* IPV4 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 22,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = PKT_PROT_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x8,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       .valid = 0,
+                                       .next_packet_pointer = 262,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = LAST_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               }
+                       },
+               },
+               {
+                       /* PKT_PROT_NODE */
+                       .node_type = EWDN,
+                       .last_node = 0,
+                       .hdr_len_store = 1,
+                       .hdr_extn = NO_BYTE,
+                       .byte_store = NO_BYTE,
+                       .search_byte_store = NO_BYTE,
+                       .result_pointer = DB_RES_DROP,
+                       .num_branches = 3,
+                       .branch = {
+                               {
+                                       /* TCP */
+                                       .valid = 1,
+                                       .next_packet_pointer = 26,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x0600,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* UDP */
+                                       .valid = 1,
+                                       .next_packet_pointer = 26,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x1100,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       .valid = 0,
+                                       .next_packet_pointer = 260,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = LAST_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               }
+                       }
+               },
+               {
+                       /* RSS_IPV4_TCP_NODE */
+                       .node_type = EWDN,
+                       .last_node = 0,
+                       .hdr_len_store = 1,
+                       .hdr_extn = NO_BYTE,
+                       .byte_store = NO_BYTE,
+                       .search_byte_store = BOTH_BYTES,
+                       .result_pointer = DB_RES_DROP,
+                       .num_branches = 6,
+                       .branch = {
+                               {
+                                       /* SRC IPV4 B01 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 28,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 1,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* SRC IPV4 B23 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 30,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 2,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* DST IPV4 B01 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 32,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 3,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* DST IPV4 B23 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 34,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 4,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* TCP SRC Port */
+                                       .valid = 0,
+                                       .next_packet_pointer = 36,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_TCP_NODE,
+                                       .next_branch = 5,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* TCP DST Port */
+                                       .valid = 0,
+                                       .next_packet_pointer = 256,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = LAST_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               }
+                       }
+               },
+               {
+                       /* RSS_IPV4_UDP_NODE */
+                       .node_type = EWDN,
+                       .last_node = 0,
+                       .hdr_len_store = 1,
+                       .hdr_extn = NO_BYTE,
+                       .byte_store = NO_BYTE,
+                       .search_byte_store = BOTH_BYTES,
+                       .result_pointer = DB_RES_DROP,
+                       .num_branches = 6,
+                       .branch = {
+                               {
+                                       /* SRC IPV4 B01 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 28,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 1,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* SRC IPV4 B23 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 30,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 2,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* DST IPV4 B01 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 32,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 3,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* DST IPV4 B23 */
+                                       .valid = 0,
+                                       .next_packet_pointer = 34,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 4,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* TCP SRC Port */
+                                       .valid = 0,
+                                       .next_packet_pointer = 36,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = RSS_IPV4_UDP_NODE,
+                                       .next_branch = 5,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               },
+                               {
+                                       /* TCP DST Port */
+                                       .valid = 0,
+                                       .next_packet_pointer = 256,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = LAST_NODE,
+                                       .next_branch = 0,
+                                       .data = 0x0,
+                                       .mask = 0xffff
+                               }
+                       }
+               },
+               {
+                       /* LAST NODE */
+                       .node_type = EWDN,
+                       .last_node = 1,
+                       .hdr_len_store = 1,
+                       .hdr_extn = NO_BYTE,
+                       .byte_store = NO_BYTE,
+                       .search_byte_store = NO_BYTE,
+                       .result_pointer = DB_RES_DROP,
+                       .num_branches = 1,
+                       .branch = {
+                               {
+                                       .valid = 0,
+                                       .next_packet_pointer = 0,
+                                       .jump_bw = JMP_FW,
+                                       .jump_rel = JMP_ABS,
+                                       .operation = EQT,
+                                       .next_node = MAX_NODES,
+                                       .next_branch = 0,
+                                       .data = 0,
+                                       .mask = 0xffff
+                               }
+                       }
+               }
+       };
+
+       ptree = &enet_cle->ptree;
+       ptree->start_pkt = 12; /* Ethertype */
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+               ret = xgene_cle_setup_rss(pdata);
+               if (ret) {
+                       netdev_err(pdata->ndev, "RSS initialization failed\n");
+                       return ret;
+               }
+       } else {
+               br = &ptree_dn[PKT_PROT_NODE].branch[0];
+               br->valid = 0;
+               br->next_packet_pointer = 260;
+               br->next_node = LAST_NODE;
+               br->data = 0x0000;
+               br->mask = 0xffff;
+       }
+
+       def_qid = xgene_enet_dst_ring_num(pdata->rx_ring[0]);
+       pool_id = pdata->rx_ring[0]->buf_pool->id;
+       def_fpsel = xgene_enet_ring_bufnum(pool_id) - 0x20;
+
+       memset(dbptr, 0, sizeof(struct xgene_cle_dbptr) * DB_MAX_PTRS);
+       dbptr[DB_RES_ACCEPT].fpsel =  def_fpsel;
+       dbptr[DB_RES_ACCEPT].dstqid = def_qid;
+       dbptr[DB_RES_ACCEPT].cle_priority = 1;
+
+       dbptr[DB_RES_DEF].fpsel = def_fpsel;
+       dbptr[DB_RES_DEF].dstqid = def_qid;
+       dbptr[DB_RES_DEF].cle_priority = 7;
+       xgene_cle_setup_def_dbptr(pdata, enet_cle, &dbptr[DB_RES_DEF],
+                                 DB_RES_ACCEPT, 7);
+
+       dbptr[DB_RES_DROP].drop = 1;
+
+       memset(&kn, 0, sizeof(kn));
+       kn.node_type = KN;
+       kn.num_keys = 1;
+       kn.key[0].priority = 0;
+       kn.key[0].result_pointer = DB_RES_ACCEPT;
+
+       ptree->dn = ptree_dn;
+       ptree->kn = &kn;
+       ptree->dbptr = dbptr;
+       ptree->num_dn = MAX_NODES;
+       ptree->num_kn = 1;
+       ptree->num_dbptr = DB_MAX_PTRS;
+
+       return xgene_cle_setup_ptree(pdata, enet_cle);
+}
+
+struct xgene_cle_ops xgene_cle3in_ops = {
+       .cle_init = xgene_enet_cle_init,
+};
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_cle.h b/drivers/net/ethernet/apm/xgene/xgene_enet_cle.h
new file mode 100644 (file)
index 0000000..29a17ab
--- /dev/null
@@ -0,0 +1,295 @@
+/* Applied Micro X-Gene SoC Ethernet Classifier structures
+ *
+ * Copyright (c) 2016, Applied Micro Circuits Corporation
+ * Authors: Khuong Dinh <kdinh@apm.com>
+ *          Tanmay Inamdar <tinamdar@apm.com>
+ *          Iyappan Subramanian <isubramanian@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XGENE_ENET_CLE_H__
+#define __XGENE_ENET_CLE_H__
+
+#include <linux/io.h>
+#include <linux/random.h>
+
+/* Register offsets */
+#define INDADDR                        0x04
+#define INDCMD                 0x08
+#define INDCMD_STATUS          0x0c
+#define DATA_RAM0              0x10
+#define SNPTR0                 0x0100
+#define SPPTR0                 0x0104
+#define DFCLSRESDBPTR0         0x0108
+#define DFCLSRESDB00           0x010c
+#define RSS_CTRL0              0x0000013c
+
+#define CLE_CMD_TO             10      /* ms */
+#define CLE_PKTRAM_SIZE                256     /* bytes */
+#define CLE_PORT_OFFSET                0x200
+#define CLE_DRAM_REGS          17
+
+#define CLE_DN_TYPE_LEN                2
+#define CLE_DN_TYPE_POS                0
+#define CLE_DN_LASTN_LEN       1
+#define CLE_DN_LASTN_POS       2
+#define CLE_DN_HLS_LEN         1
+#define CLE_DN_HLS_POS         3
+#define CLE_DN_EXT_LEN         2
+#define        CLE_DN_EXT_POS          4
+#define CLE_DN_BSTOR_LEN       2
+#define CLE_DN_BSTOR_POS       6
+#define CLE_DN_SBSTOR_LEN      2
+#define CLE_DN_SBSTOR_POS      8
+#define CLE_DN_RPTR_LEN                12
+#define CLE_DN_RPTR_POS                12
+
+#define CLE_BR_VALID_LEN       1
+#define CLE_BR_VALID_POS       0
+#define CLE_BR_NPPTR_LEN       9
+#define CLE_BR_NPPTR_POS       1
+#define CLE_BR_JB_LEN          1
+#define CLE_BR_JB_POS          10
+#define CLE_BR_JR_LEN          1
+#define CLE_BR_JR_POS          11
+#define CLE_BR_OP_LEN          3
+#define CLE_BR_OP_POS          12
+#define CLE_BR_NNODE_LEN       9
+#define CLE_BR_NNODE_POS       15
+#define CLE_BR_NBR_LEN         5
+#define CLE_BR_NBR_POS         24
+
+#define CLE_BR_DATA_LEN                16
+#define CLE_BR_DATA_POS                0
+#define CLE_BR_MASK_LEN                16
+#define CLE_BR_MASK_POS                16
+
+#define CLE_KN_PRIO_POS                0
+#define CLE_KN_PRIO_LEN                3
+#define CLE_KN_RPTR_POS                3
+#define CLE_KN_RPTR_LEN                10
+#define CLE_TYPE_POS           0
+#define CLE_TYPE_LEN           2
+
+#define CLE_DSTQIDL_POS                25
+#define CLE_DSTQIDL_LEN                7
+#define CLE_DSTQIDH_POS                0
+#define CLE_DSTQIDH_LEN                5
+#define CLE_FPSEL_POS          21
+#define CLE_FPSEL_LEN          4
+#define CLE_PRIORITY_POS       5
+#define CLE_PRIORITY_LEN       3
+
+#define JMP_ABS                        0
+#define JMP_REL                        1
+#define JMP_FW                 0
+#define JMP_BW                 1
+
+enum xgene_cle_ptree_nodes {
+       PKT_TYPE_NODE,
+       PKT_PROT_NODE,
+       RSS_IPV4_TCP_NODE,
+       RSS_IPV4_UDP_NODE,
+       LAST_NODE,
+       MAX_NODES
+};
+
+enum xgene_cle_byte_store {
+       NO_BYTE,
+       FIRST_BYTE,
+       SECOND_BYTE,
+       BOTH_BYTES
+};
+
+/* Preclassification operation types */
+enum xgene_cle_node_type {
+       INV,
+       KN,
+       EWDN,
+       RES_NODE
+};
+
+/* Preclassification operation types */
+enum xgene_cle_op_type {
+       EQT,
+       NEQT,
+       LTEQT,
+       GTEQT,
+       AND,
+       NAND
+};
+
+enum xgene_cle_parser {
+       PARSER0,
+       PARSER1,
+       PARSER2,
+       PARSER_ALL
+};
+
+#define XGENE_CLE_DRAM(type)   (((type) & 0xf) << 28)
+enum xgene_cle_dram_type {
+       PKT_RAM,
+       RSS_IDT,
+       RSS_IPV4_HASH_SKEY,
+       PTREE_RAM = 0xc,
+       AVL_RAM,
+       DB_RAM
+};
+
+enum xgene_cle_cmd_type {
+       CLE_CMD_WR = 1,
+       CLE_CMD_RD = 2,
+       CLE_CMD_AVL_ADD = 8,
+       CLE_CMD_AVL_DEL = 16,
+       CLE_CMD_AVL_SRCH = 32
+};
+
+enum xgene_cle_ipv4_rss_hashtype {
+       RSS_IPV4_8B,
+       RSS_IPV4_12B,
+};
+
+enum xgene_cle_prot_type {
+       XGENE_CLE_TCP,
+       XGENE_CLE_UDP,
+       XGENE_CLE_ESP,
+       XGENE_CLE_OTHER
+};
+
+enum xgene_cle_prot_version {
+       XGENE_CLE_IPV4,
+};
+
+enum xgene_cle_ptree_dbptrs {
+       DB_RES_DROP,
+       DB_RES_DEF,
+       DB_RES_ACCEPT,
+       DB_MAX_PTRS
+};
+
+/* RSS sideband signal info */
+#define SB_IPFRAG_POS  0
+#define SB_IPFRAG_LEN  1
+#define SB_IPPROT_POS  1
+#define SB_IPPROT_LEN  2
+#define SB_IPVER_POS   3
+#define SB_IPVER_LEN   1
+#define SB_HDRLEN_POS  4
+#define SB_HDRLEN_LEN  12
+
+/* RSS indirection table */
+#define XGENE_CLE_IDT_ENTRIES  128
+#define IDT_DSTQID_POS         0
+#define IDT_DSTQID_LEN         12
+#define IDT_FPSEL_POS          12
+#define IDT_FPSEL_LEN          4
+#define IDT_NFPSEL_POS         16
+#define IDT_NFPSEL_LEN         4
+
+struct xgene_cle_ptree_branch {
+       bool valid;
+       u16 next_packet_pointer;
+       bool jump_bw;
+       bool jump_rel;
+       u8 operation;
+       u16 next_node;
+       u8 next_branch;
+       u16 data;
+       u16 mask;
+};
+
+struct xgene_cle_ptree_ewdn {
+       u8 node_type;
+       bool last_node;
+       bool hdr_len_store;
+       u8 hdr_extn;
+       u8 byte_store;
+       u8 search_byte_store;
+       u16 result_pointer;
+       u8 num_branches;
+       struct xgene_cle_ptree_branch branch[6];
+};
+
+struct xgene_cle_ptree_key {
+       u8 priority;
+       u16 result_pointer;
+};
+
+struct xgene_cle_ptree_kn {
+       u8 node_type;
+       u8 num_keys;
+       struct xgene_cle_ptree_key key[32];
+};
+
+struct xgene_cle_dbptr {
+       u8 split_boundary;
+       u8 mirror_nxtfpsel;
+       u8 mirror_fpsel;
+       u16 mirror_dstqid;
+       u8 drop;
+       u8 mirror;
+       u8 hdr_data_split;
+       u64 hopinfomsbs;
+       u8 DR;
+       u8 HR;
+       u64 hopinfomlsbs;
+       u16 h0enq_num;
+       u8 h0fpsel;
+       u8 nxtfpsel;
+       u8 fpsel;
+       u16 dstqid;
+       u8 cle_priority;
+       u8 cle_flowgroup;
+       u8 cle_perflow;
+       u8 cle_insert_timestamp;
+       u8 stash;
+       u8 in;
+       u8 perprioen;
+       u8 perflowgroupen;
+       u8 perflowen;
+       u8 selhash;
+       u8 selhdrext;
+       u8 mirror_nxtfpsel_msb;
+       u8 mirror_fpsel_msb;
+       u8 hfpsel_msb;
+       u8 nxtfpsel_msb;
+       u8 fpsel_msb;
+};
+
+struct xgene_cle_ptree {
+       struct xgene_cle_ptree_ewdn *dn;
+       struct xgene_cle_ptree_kn *kn;
+       struct xgene_cle_dbptr *dbptr;
+       u32 num_dn;
+       u32 num_kn;
+       u32 num_dbptr;
+       u32 start_node;
+       u32 start_pkt;
+       u32 start_dbptr;
+};
+
+struct xgene_enet_cle {
+       void __iomem *base;
+       struct xgene_cle_ptree ptree;
+       enum xgene_cle_parser active_parser;
+       u32 parsers;
+       u32 max_nodes;
+       u32 max_dbptrs;
+       u32 jump_bytes;
+};
+
+extern struct xgene_cle_ops xgene_cle3in_ops;
+
+#endif /* __XGENE_ENET_CLE_H__ */
index db55c9f6e8e13006a012f096cc4259718a525351..39e081a70f5b4f5bb9b674d7fe9c470f6d807b80 100644 (file)
@@ -204,6 +204,17 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
        return num_msgs;
 }
 
+static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+{
+       u32 data = 0x7777;
+
+       xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+}
+
 void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
                            struct xgene_enet_pdata *pdata,
                            enum xgene_enet_err_code status)
@@ -892,4 +903,5 @@ struct xgene_ring_ops xgene_ring1_ops = {
        .clear = xgene_enet_clear_ring,
        .wr_cmd = xgene_enet_wr_cmd,
        .len = xgene_enet_ring_len,
+       .coalesce = xgene_enet_setup_coalescing,
 };
index 8a9091039ab4494f0be860c9016d064f65411ecb..ba7da98af2efb48c2a5811244ea4776185ce2534 100644 (file)
@@ -54,6 +54,11 @@ enum xgene_enet_rm {
 #define IS_BUFFER_POOL         BIT(20)
 #define PREFETCH_BUF_EN                BIT(21)
 #define CSR_RING_ID_BUF                0x000c
+#define CSR_PBM_COAL           0x0014
+#define CSR_PBM_CTICK1         0x001c
+#define CSR_PBM_CTICK2         0x0020
+#define CSR_THRESHOLD0_SET1    0x0030
+#define CSR_THRESHOLD1_SET1    0x0034
 #define CSR_RING_NE_INT_MODE   0x017c
 #define CSR_RING_CONFIG                0x006c
 #define CSR_RING_WR_BASE       0x0070
@@ -101,6 +106,7 @@ enum xgene_enet_rm {
 #define MAC_OFFSET                     0x30
 
 #define BLOCK_ETH_CSR_OFFSET           0x2000
+#define BLOCK_ETH_CLE_CSR_OFFSET       0x6000
 #define BLOCK_ETH_RING_IF_OFFSET       0x9000
 #define BLOCK_ETH_CLKRST_CSR_OFFSET    0xc000
 #define BLOCK_ETH_DIAG_CSR_OFFSET      0xD000
index 5eb9b20c0eeab09954a909290ac5bd9bf3fdcb06..8d4c1ad2fc6051f66ffc059456927511e9dd2fe3 100644 (file)
@@ -93,13 +93,6 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
        return 0;
 }
 
-static u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
-{
-       struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
-
-       return ((u16)pdata->rm << 10) | ring->num;
-}
-
 static u8 xgene_enet_hdr_len(const void *data)
 {
        const struct ethhdr *eth = data;
@@ -189,7 +182,6 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
 static u64 xgene_enet_work_msg(struct sk_buff *skb)
 {
        struct net_device *ndev = skb->dev;
-       struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct iphdr *iph;
        u8 l3hlen = 0, l4hlen = 0;
        u8 ethhdr, proto = 0, csum_enable = 0;
@@ -235,10 +227,6 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
                        if (!mss || ((skb->len - hdr_len) <= mss))
                                goto out;
 
-                       if (mss != pdata->mss) {
-                               pdata->mss = mss;
-                               pdata->mac_ops->set_mss(pdata);
-                       }
                        hopinfo |= SET_BIT(ET);
                }
        } else if (iph->protocol == IPPROTO_UDP) {
@@ -420,7 +408,7 @@ out:
        raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) |
                                   SET_VAL(USERINFO, tx_ring->tail));
        tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb;
-       pdata->tx_level += count;
+       pdata->tx_level[tx_ring->cp_ring->index] += count;
        tx_ring->tail = tail;
 
        return count;
@@ -430,15 +418,17 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
                                         struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
-       struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
-       u32 tx_level = pdata->tx_level;
+       struct xgene_enet_desc_ring *tx_ring;
+       int index = skb->queue_mapping;
+       u32 tx_level = pdata->tx_level[index];
        int count;
 
-       if (tx_level < pdata->txc_level)
-               tx_level += ((typeof(pdata->tx_level))~0U);
+       tx_ring = pdata->tx_ring[index];
+       if (tx_level < pdata->txc_level[index])
+               tx_level += ((typeof(pdata->tx_level[index]))~0U);
 
-       if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) {
-               netif_stop_queue(ndev);
+       if ((tx_level - pdata->txc_level[index]) > pdata->tx_qcnt_hi) {
+               netif_stop_subqueue(ndev, index);
                return NETDEV_TX_BUSY;
        }
 
@@ -536,7 +526,8 @@ static bool is_rx_desc(struct xgene_enet_raw_desc *raw_desc)
 static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                                   int budget)
 {
-       struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+       struct net_device *ndev = ring->ndev;
+       struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct xgene_enet_raw_desc *raw_desc, *exp_desc;
        u16 head = ring->head;
        u16 slots = ring->slots - 1;
@@ -580,7 +571,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                desc_count++;
                processed++;
                if (is_completion)
-                       pdata->txc_level += desc_count;
+                       pdata->txc_level[ring->index] += desc_count;
 
                if (ret)
                        break;
@@ -590,8 +581,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                pdata->ring_ops->wr_cmd(ring, -count);
                ring->head = head;
 
-               if (netif_queue_stopped(ring->ndev))
-                       netif_start_queue(ring->ndev);
+               if (__netif_subqueue_stopped(ndev, ring->index))
+                       netif_start_subqueue(ndev, ring->index);
        }
 
        return processed;
@@ -616,8 +607,16 @@ static int xgene_enet_napi(struct napi_struct *napi, const int budget)
 static void xgene_enet_timeout(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
+       struct netdev_queue *txq;
+       int i;
 
        pdata->mac_ops->reset(pdata);
+
+       for (i = 0; i < pdata->txq_cnt; i++) {
+               txq = netdev_get_tx_queue(ndev, i);
+               txq->trans_start = jiffies;
+               netif_tx_start_queue(txq);
+       }
 }
 
 static int xgene_enet_register_irq(struct net_device *ndev)
@@ -625,17 +624,21 @@ static int xgene_enet_register_irq(struct net_device *ndev)
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct device *dev = ndev_to_dev(ndev);
        struct xgene_enet_desc_ring *ring;
-       int ret;
+       int ret = 0, i;
 
-       ring = pdata->rx_ring;
-       irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
-       ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
-                              IRQF_SHARED, ring->irq_name, ring);
-       if (ret)
-               netdev_err(ndev, "Failed to request irq %s\n", ring->irq_name);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               ring = pdata->rx_ring[i];
+               irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
+               ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
+                                      IRQF_SHARED, ring->irq_name, ring);
+               if (ret) {
+                       netdev_err(ndev, "Failed to request irq %s\n",
+                                  ring->irq_name);
+               }
+       }
 
-       if (pdata->cq_cnt) {
-               ring = pdata->tx_ring->cp_ring;
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               ring = pdata->tx_ring[i]->cp_ring;
                irq_set_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
                ret = devm_request_irq(dev, ring->irq, xgene_enet_rx_irq,
                                       IRQF_SHARED, ring->irq_name, ring);
@@ -653,15 +656,19 @@ static void xgene_enet_free_irq(struct net_device *ndev)
        struct xgene_enet_pdata *pdata;
        struct xgene_enet_desc_ring *ring;
        struct device *dev;
+       int i;
 
        pdata = netdev_priv(ndev);
        dev = ndev_to_dev(ndev);
-       ring = pdata->rx_ring;
-       irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
-       devm_free_irq(dev, ring->irq, ring);
 
-       if (pdata->cq_cnt) {
-               ring = pdata->tx_ring->cp_ring;
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               ring = pdata->rx_ring[i];
+               irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
+               devm_free_irq(dev, ring->irq, ring);
+       }
+
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               ring = pdata->tx_ring[i]->cp_ring;
                irq_clear_status_flags(ring->irq, IRQ_DISABLE_UNLAZY);
                devm_free_irq(dev, ring->irq, ring);
        }
@@ -670,12 +677,15 @@ static void xgene_enet_free_irq(struct net_device *ndev)
 static void xgene_enet_napi_enable(struct xgene_enet_pdata *pdata)
 {
        struct napi_struct *napi;
+       int i;
 
-       napi = &pdata->rx_ring->napi;
-       napi_enable(napi);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               napi = &pdata->rx_ring[i]->napi;
+               napi_enable(napi);
+       }
 
-       if (pdata->cq_cnt) {
-               napi = &pdata->tx_ring->cp_ring->napi;
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               napi = &pdata->tx_ring[i]->cp_ring->napi;
                napi_enable(napi);
        }
 }
@@ -683,12 +693,15 @@ static void xgene_enet_napi_enable(struct xgene_enet_pdata *pdata)
 static void xgene_enet_napi_disable(struct xgene_enet_pdata *pdata)
 {
        struct napi_struct *napi;
+       int i;
 
-       napi = &pdata->rx_ring->napi;
-       napi_disable(napi);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               napi = &pdata->rx_ring[i]->napi;
+               napi_disable(napi);
+       }
 
-       if (pdata->cq_cnt) {
-               napi = &pdata->tx_ring->cp_ring->napi;
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               napi = &pdata->tx_ring[i]->cp_ring->napi;
                napi_disable(napi);
        }
 }
@@ -699,6 +712,14 @@ static int xgene_enet_open(struct net_device *ndev)
        const struct xgene_mac_ops *mac_ops = pdata->mac_ops;
        int ret;
 
+       ret = netif_set_real_num_tx_queues(ndev, pdata->txq_cnt);
+       if (ret)
+               return ret;
+
+       ret = netif_set_real_num_rx_queues(ndev, pdata->rxq_cnt);
+       if (ret)
+               return ret;
+
        mac_ops->tx_enable(pdata);
        mac_ops->rx_enable(pdata);
 
@@ -721,6 +742,7 @@ static int xgene_enet_close(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        const struct xgene_mac_ops *mac_ops = pdata->mac_ops;
+       int i;
 
        netif_stop_queue(ndev);
 
@@ -734,7 +756,8 @@ static int xgene_enet_close(struct net_device *ndev)
 
        xgene_enet_free_irq(ndev);
        xgene_enet_napi_disable(pdata);
-       xgene_enet_process_ring(pdata->rx_ring, -1);
+       for (i = 0; i < pdata->rxq_cnt; i++)
+               xgene_enet_process_ring(pdata->rx_ring[i], -1);
 
        return 0;
 }
@@ -754,18 +777,26 @@ static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
 static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata)
 {
        struct xgene_enet_desc_ring *buf_pool;
+       struct xgene_enet_desc_ring *ring;
+       int i;
 
-       if (pdata->tx_ring) {
-               xgene_enet_delete_ring(pdata->tx_ring);
-               pdata->tx_ring = NULL;
+       for (i = 0; i < pdata->txq_cnt; i++) {
+               ring = pdata->tx_ring[i];
+               if (ring) {
+                       xgene_enet_delete_ring(ring);
+                       pdata->tx_ring[i] = NULL;
+               }
        }
 
-       if (pdata->rx_ring) {
-               buf_pool = pdata->rx_ring->buf_pool;
-               xgene_enet_delete_bufpool(buf_pool);
-               xgene_enet_delete_ring(buf_pool);
-               xgene_enet_delete_ring(pdata->rx_ring);
-               pdata->rx_ring = NULL;
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               ring = pdata->rx_ring[i];
+               if (ring) {
+                       buf_pool = ring->buf_pool;
+                       xgene_enet_delete_bufpool(buf_pool);
+                       xgene_enet_delete_ring(buf_pool);
+                       xgene_enet_delete_ring(ring);
+                       pdata->rx_ring[i] = NULL;
+               }
        }
 }
 
@@ -820,24 +851,29 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
 {
        struct device *dev = &pdata->pdev->dev;
        struct xgene_enet_desc_ring *ring;
+       int i;
+
+       for (i = 0; i < pdata->txq_cnt; i++) {
+               ring = pdata->tx_ring[i];
+               if (ring) {
+                       if (ring->cp_ring && ring->cp_ring->cp_skb)
+                               devm_kfree(dev, ring->cp_ring->cp_skb);
+                       if (ring->cp_ring && pdata->cq_cnt)
+                               xgene_enet_free_desc_ring(ring->cp_ring);
+                       xgene_enet_free_desc_ring(ring);
+               }
+       }
 
-       ring = pdata->tx_ring;
-       if (ring) {
-               if (ring->cp_ring && ring->cp_ring->cp_skb)
-                       devm_kfree(dev, ring->cp_ring->cp_skb);
-               if (ring->cp_ring && pdata->cq_cnt)
-                       xgene_enet_free_desc_ring(ring->cp_ring);
-               xgene_enet_free_desc_ring(ring);
-       }
-
-       ring = pdata->rx_ring;
-       if (ring) {
-               if (ring->buf_pool) {
-                       if (ring->buf_pool->rx_skb)
-                               devm_kfree(dev, ring->buf_pool->rx_skb);
-                       xgene_enet_free_desc_ring(ring->buf_pool);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               ring = pdata->rx_ring[i];
+               if (ring) {
+                       if (ring->buf_pool) {
+                               if (ring->buf_pool->rx_skb)
+                                       devm_kfree(dev, ring->buf_pool->rx_skb);
+                               xgene_enet_free_desc_ring(ring->buf_pool);
+                       }
+                       xgene_enet_free_desc_ring(ring);
                }
-               xgene_enet_free_desc_ring(ring);
        }
 }
 
@@ -950,104 +986,120 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
        u8 bp_bufnum = pdata->bp_bufnum;
        u16 ring_num = pdata->ring_num;
        u16 ring_id;
-       int ret, size;
-
-       /* allocate rx descriptor ring */
-       owner = xgene_derive_ring_owner(pdata);
-       ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
-       rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-                                             RING_CFGSIZE_16KB, ring_id);
-       if (!rx_ring) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       int i, ret, size;
 
-       /* allocate buffer pool for receiving packets */
-       owner = xgene_derive_ring_owner(pdata);
-       ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
-       buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
-                                              RING_CFGSIZE_2KB, ring_id);
-       if (!buf_pool) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       rx_ring->nbufpool = NUM_BUFPOOL;
-       rx_ring->buf_pool = buf_pool;
-       rx_ring->irq = pdata->rx_irq;
-       if (!pdata->cq_cnt) {
-               snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
-                        ndev->name);
-       } else {
-               snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx", ndev->name);
-       }
-       buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
-                                       sizeof(struct sk_buff *), GFP_KERNEL);
-       if (!buf_pool->rx_skb) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool);
-       rx_ring->buf_pool = buf_pool;
-       pdata->rx_ring = rx_ring;
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               /* allocate rx descriptor ring */
+               owner = xgene_derive_ring_owner(pdata);
+               ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
+               rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+                                                     RING_CFGSIZE_16KB,
+                                                     ring_id);
+               if (!rx_ring) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
-       /* allocate tx descriptor ring */
-       owner = xgene_derive_ring_owner(pdata);
-       ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
-       tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
-                                             RING_CFGSIZE_16KB, ring_id);
-       if (!tx_ring) {
-               ret = -ENOMEM;
-               goto err;
-       }
+               /* allocate buffer pool for receiving packets */
+               owner = xgene_derive_ring_owner(pdata);
+               ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
+               buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
+                                                      RING_CFGSIZE_2KB,
+                                                      ring_id);
+               if (!buf_pool) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
-       size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
-       tx_ring->exp_bufs = dma_zalloc_coherent(dev, size, &dma_exp_bufs,
+               rx_ring->nbufpool = NUM_BUFPOOL;
+               rx_ring->buf_pool = buf_pool;
+               rx_ring->irq = pdata->irqs[i];
+               if (!pdata->cq_cnt) {
+                       snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx-txc",
+                                ndev->name);
+               } else {
+                       snprintf(rx_ring->irq_name, IRQ_ID_SIZE, "%s-rx%d",
+                                ndev->name, i);
+               }
+               buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots,
+                                               sizeof(struct sk_buff *),
                                                GFP_KERNEL);
-       if (!tx_ring->exp_bufs) {
-               ret = -ENOMEM;
-               goto err;
-       }
+               if (!buf_pool->rx_skb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
-       pdata->tx_ring = tx_ring;
+               buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool);
+               rx_ring->buf_pool = buf_pool;
+               pdata->rx_ring[i] = rx_ring;
+       }
 
-       if (!pdata->cq_cnt) {
-               cp_ring = pdata->rx_ring;
-       } else {
-               /* allocate tx completion descriptor ring */
-               ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
-               cp_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+       for (i = 0; i < pdata->txq_cnt; i++) {
+               /* allocate tx descriptor ring */
+               owner = xgene_derive_ring_owner(pdata);
+               ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
+               tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
                                                      RING_CFGSIZE_16KB,
                                                      ring_id);
-               if (!cp_ring) {
+               if (!tx_ring) {
                        ret = -ENOMEM;
                        goto err;
                }
-               cp_ring->irq = pdata->txc_irq;
-               snprintf(cp_ring->irq_name, IRQ_ID_SIZE, "%s-txc", ndev->name);
-       }
 
-       cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
-                                      sizeof(struct sk_buff *), GFP_KERNEL);
-       if (!cp_ring->cp_skb) {
-               ret = -ENOMEM;
-               goto err;
-       }
+               size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
+               tx_ring->exp_bufs = dma_zalloc_coherent(dev, size,
+                                                       &dma_exp_bufs,
+                                                       GFP_KERNEL);
+               if (!tx_ring->exp_bufs) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
 
-       size = sizeof(dma_addr_t) * MAX_SKB_FRAGS;
-       cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots,
-                                             size, GFP_KERNEL);
-       if (!cp_ring->frag_dma_addr) {
-               devm_kfree(dev, cp_ring->cp_skb);
-               ret = -ENOMEM;
-               goto err;
-       }
+               pdata->tx_ring[i] = tx_ring;
 
-       pdata->tx_ring->cp_ring = cp_ring;
-       pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+               if (!pdata->cq_cnt) {
+                       cp_ring = pdata->rx_ring[i];
+               } else {
+                       /* allocate tx completion descriptor ring */
+                       ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU,
+                                                        cpu_bufnum++);
+                       cp_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
+                                                             RING_CFGSIZE_16KB,
+                                                             ring_id);
+                       if (!cp_ring) {
+                               ret = -ENOMEM;
+                               goto err;
+                       }
 
-       pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128;
+                       cp_ring->irq = pdata->irqs[pdata->rxq_cnt + i];
+                       cp_ring->index = i;
+                       snprintf(cp_ring->irq_name, IRQ_ID_SIZE, "%s-txc%d",
+                                ndev->name, i);
+               }
+
+               cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots,
+                                              sizeof(struct sk_buff *),
+                                              GFP_KERNEL);
+               if (!cp_ring->cp_skb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               size = sizeof(dma_addr_t) * MAX_SKB_FRAGS;
+               cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots,
+                                                     size, GFP_KERNEL);
+               if (!cp_ring->frag_dma_addr) {
+                       devm_kfree(dev, cp_ring->cp_skb);
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               tx_ring->cp_ring = cp_ring;
+               tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
+       }
+
+       pdata->ring_ops->coalesce(pdata->tx_ring[0]);
+       pdata->tx_qcnt_hi = pdata->tx_ring[0]->slots - 128;
 
        return 0;
 
@@ -1166,6 +1218,32 @@ static int xgene_get_rx_delay(struct xgene_enet_pdata *pdata)
        return 0;
 }
 
+static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
+{
+       struct platform_device *pdev = pdata->pdev;
+       struct device *dev = &pdev->dev;
+       int i, ret, max_irqs;
+
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+               max_irqs = 1;
+       else if (pdata->phy_mode == PHY_INTERFACE_MODE_SGMII)
+               max_irqs = 2;
+       else
+               max_irqs = XGENE_MAX_ENET_IRQ;
+
+       for (i = 0; i < max_irqs; i++) {
+               ret = platform_get_irq(pdev, i);
+               if (ret <= 0) {
+                       dev_err(dev, "Unable to get ENET IRQ\n");
+                       ret = ret ? : -ENXIO;
+                       return ret;
+               }
+               pdata->irqs[i] = ret;
+       }
+
+       return 0;
+}
+
 static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
 {
        struct platform_device *pdev;
@@ -1247,25 +1325,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        if (ret)
                return ret;
 
-       ret = platform_get_irq(pdev, 0);
-       if (ret <= 0) {
-               dev_err(dev, "Unable to get ENET Rx IRQ\n");
-               ret = ret ? : -ENXIO;
+       ret = xgene_enet_get_irqs(pdata);
+       if (ret)
                return ret;
-       }
-       pdata->rx_irq = ret;
-
-       if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII) {
-               ret = platform_get_irq(pdev, 1);
-               if (ret <= 0) {
-                       pdata->cq_cnt = 0;
-                       dev_info(dev, "Unable to get Tx completion IRQ,"
-                                "using Rx IRQ instead\n");
-               } else {
-                       pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
-                       pdata->txc_irq = ret;
-               }
-       }
 
        pdata->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pdata->clk)) {
@@ -1278,6 +1340,7 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        else
                base_addr = pdata->base_addr;
        pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
+       pdata->cle.base = base_addr + BLOCK_ETH_CLE_CSR_OFFSET;
        pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
        pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
        if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
@@ -1298,10 +1361,11 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
 
 static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
 {
+       struct xgene_enet_cle *enet_cle = &pdata->cle;
        struct net_device *ndev = pdata->ndev;
        struct xgene_enet_desc_ring *buf_pool;
        u16 dst_ring_num;
-       int ret;
+       int i, ret;
 
        ret = pdata->port_ops->reset(pdata);
        if (ret)
@@ -1314,16 +1378,36 @@ static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata)
        }
 
        /* setup buffer pool */
-       buf_pool = pdata->rx_ring->buf_pool;
-       xgene_enet_init_bufpool(buf_pool);
-       ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt);
-       if (ret) {
-               xgene_enet_delete_desc_rings(pdata);
-               return ret;
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               buf_pool = pdata->rx_ring[i]->buf_pool;
+               xgene_enet_init_bufpool(buf_pool);
+               ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt);
+               if (ret) {
+                       xgene_enet_delete_desc_rings(pdata);
+                       return ret;
+               }
+       }
+
+       dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring[0]);
+       buf_pool = pdata->rx_ring[0]->buf_pool;
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+               /* Initialize and Enable  PreClassifier Tree */
+               enet_cle->max_nodes = 512;
+               enet_cle->max_dbptrs = 1024;
+               enet_cle->parsers = 3;
+               enet_cle->active_parser = PARSER_ALL;
+               enet_cle->ptree.start_node = 0;
+               enet_cle->ptree.start_dbptr = 0;
+               enet_cle->jump_bytes = 8;
+               ret = pdata->cle_ops->cle_init(pdata);
+               if (ret) {
+                       netdev_err(ndev, "Preclass Tree init error\n");
+                       return ret;
+               }
+       } else {
+               pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
        }
 
-       dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring);
-       pdata->port_ops->cle_bypass(pdata, dst_ring_num, buf_pool->id);
        pdata->mac_ops->init(pdata);
 
        return ret;
@@ -1336,16 +1420,26 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
                pdata->mac_ops = &xgene_gmac_ops;
                pdata->port_ops = &xgene_gport_ops;
                pdata->rm = RM3;
+               pdata->rxq_cnt = 1;
+               pdata->txq_cnt = 1;
+               pdata->cq_cnt = 0;
                break;
        case PHY_INTERFACE_MODE_SGMII:
                pdata->mac_ops = &xgene_sgmac_ops;
                pdata->port_ops = &xgene_sgport_ops;
                pdata->rm = RM1;
+               pdata->rxq_cnt = 1;
+               pdata->txq_cnt = 1;
+               pdata->cq_cnt = 1;
                break;
        default:
                pdata->mac_ops = &xgene_xgmac_ops;
                pdata->port_ops = &xgene_xgport_ops;
+               pdata->cle_ops = &xgene_cle3in_ops;
                pdata->rm = RM0;
+               pdata->rxq_cnt = XGENE_NUM_RX_RING;
+               pdata->txq_cnt = XGENE_NUM_TX_RING;
+               pdata->cq_cnt = XGENE_NUM_TXC_RING;
                break;
        }
 
@@ -1399,12 +1493,16 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
 static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
 {
        struct napi_struct *napi;
+       int i;
 
-       napi = &pdata->rx_ring->napi;
-       netif_napi_add(pdata->ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               napi = &pdata->rx_ring[i]->napi;
+               netif_napi_add(pdata->ndev, napi, xgene_enet_napi,
+                              NAPI_POLL_WEIGHT);
+       }
 
-       if (pdata->cq_cnt) {
-               napi = &pdata->tx_ring->cp_ring->napi;
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               napi = &pdata->tx_ring[i]->cp_ring->napi;
                netif_napi_add(pdata->ndev, napi, xgene_enet_napi,
                               NAPI_POLL_WEIGHT);
        }
@@ -1413,12 +1511,15 @@ static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
 static void xgene_enet_napi_del(struct xgene_enet_pdata *pdata)
 {
        struct napi_struct *napi;
+       int i;
 
-       napi = &pdata->rx_ring->napi;
-       netif_napi_del(napi);
+       for (i = 0; i < pdata->rxq_cnt; i++) {
+               napi = &pdata->rx_ring[i]->napi;
+               netif_napi_del(napi);
+       }
 
-       if (pdata->cq_cnt) {
-               napi = &pdata->tx_ring->cp_ring->napi;
+       for (i = 0; i < pdata->cq_cnt; i++) {
+               napi = &pdata->tx_ring[i]->cp_ring->napi;
                netif_napi_del(napi);
        }
 }
@@ -1432,7 +1533,8 @@ static int xgene_enet_probe(struct platform_device *pdev)
        const struct of_device_id *of_id;
        int ret;
 
-       ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata));
+       ndev = alloc_etherdev_mqs(sizeof(struct xgene_enet_pdata),
+                                 XGENE_NUM_RX_RING, XGENE_NUM_TX_RING);
        if (!ndev)
                return -ENOMEM;
 
index 248dfc40a7611a0b298336c0aa552665da165ba7..175d18890c7a7da01895d7970ef653ce0170c01a 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/if_vlan.h>
 #include <linux/phy.h>
 #include "xgene_enet_hw.h"
+#include "xgene_enet_cle.h"
 #include "xgene_enet_ring2.h"
 
 #define XGENE_DRV_VERSION      "v1.0"
 #define XGENE_ENET_MSS 1448
 #define XGENE_MIN_ENET_FRAME_SIZE      60
 
+#define XGENE_MAX_ENET_IRQ     8
+#define XGENE_NUM_RX_RING      4
+#define XGENE_NUM_TX_RING      4
+#define XGENE_NUM_TXC_RING     4
+
 #define START_CPU_BUFNUM_0     0
 #define START_ETH_BUFNUM_0     2
 #define START_BP_BUFNUM_0      0x22
@@ -72,7 +78,6 @@
 #define X2_START_RING_NUM_1    256
 
 #define IRQ_ID_SIZE            16
-#define XGENE_MAX_TXC_RINGS    1
 
 #define PHY_POLL_LINK_ON       (10 * HZ)
 #define PHY_POLL_LINK_OFF      (PHY_POLL_LINK_ON / 5)
@@ -102,6 +107,7 @@ struct xgene_enet_desc_ring {
        void *irq_mbox_addr;
        u16 dst_ring_num;
        u8 nbufpool;
+       u8 index;
        struct sk_buff *(*rx_skb);
        struct sk_buff *(*cp_skb);
        dma_addr_t *frag_dma_addr;
@@ -143,6 +149,11 @@ struct xgene_ring_ops {
        void (*clear)(struct xgene_enet_desc_ring *);
        void (*wr_cmd)(struct xgene_enet_desc_ring *, int);
        u32 (*len)(struct xgene_enet_desc_ring *);
+       void (*coalesce)(struct xgene_enet_desc_ring *);
+};
+
+struct xgene_cle_ops {
+       int (*cle_init)(struct xgene_enet_pdata *pdata);
 };
 
 /* ethernet private data */
@@ -154,15 +165,16 @@ struct xgene_enet_pdata {
        struct clk *clk;
        struct platform_device *pdev;
        enum xgene_enet_id enet_id;
-       struct xgene_enet_desc_ring *tx_ring;
-       struct xgene_enet_desc_ring *rx_ring;
-       u16 tx_level;
-       u16 txc_level;
+       struct xgene_enet_desc_ring *tx_ring[XGENE_NUM_TX_RING];
+       struct xgene_enet_desc_ring *rx_ring[XGENE_NUM_RX_RING];
+       u16 tx_level[XGENE_NUM_TX_RING];
+       u16 txc_level[XGENE_NUM_TX_RING];
        char *dev_name;
        u32 rx_buff_cnt;
        u32 tx_qcnt_hi;
-       u32 rx_irq;
-       u32 txc_irq;
+       u32 irqs[XGENE_MAX_ENET_IRQ];
+       u8 rxq_cnt;
+       u8 txq_cnt;
        u8 cq_cnt;
        void __iomem *eth_csr_addr;
        void __iomem *eth_ring_if_addr;
@@ -174,10 +186,12 @@ struct xgene_enet_pdata {
        void __iomem *ring_cmd_addr;
        int phy_mode;
        enum xgene_enet_rm rm;
+       struct xgene_enet_cle cle;
        struct rtnl_link_stats64 stats;
        const struct xgene_mac_ops *mac_ops;
        const struct xgene_port_ops *port_ops;
        struct xgene_ring_ops *ring_ops;
+       struct xgene_cle_ops *cle_ops;
        struct delayed_work link_work;
        u32 port_id;
        u8 cpu_bufnum;
@@ -229,6 +243,13 @@ static inline struct device *ndev_to_dev(struct net_device *ndev)
        return ndev->dev.parent;
 }
 
+static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
+{
+       struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
+
+       return ((u16)pdata->rm << 10) | ring->num;
+}
+
 void xgene_enet_set_ethtool_ops(struct net_device *netdev);
 
 #endif /* __XGENE_ENET_MAIN_H__ */
index 0b6896bb351e10f8028ef7a71b6e189fa79d679c..2b76732add5dbbd6d25fd6fd6e1b887c317d167a 100644 (file)
@@ -190,6 +190,17 @@ static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
        return num_msgs;
 }
 
+static void xgene_enet_setup_coalescing(struct xgene_enet_desc_ring *ring)
+{
+       u32 data = 0x7777;
+
+       xgene_enet_ring_wr32(ring, CSR_PBM_COAL, 0x8e);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK1, data);
+       xgene_enet_ring_wr32(ring, CSR_PBM_CTICK2, data << 16);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD0_SET1, 0x40);
+       xgene_enet_ring_wr32(ring, CSR_THRESHOLD1_SET1, 0x80);
+}
+
 struct xgene_ring_ops xgene_ring2_ops = {
        .num_ring_config = X2_NUM_RING_CONFIG,
        .num_ring_id_shift = 13,
@@ -197,4 +208,5 @@ struct xgene_ring_ops xgene_ring2_ops = {
        .clear = xgene_enet_clear_ring,
        .wr_cmd = xgene_enet_wr_cmd,
        .len = xgene_enet_ring_len,
+       .coalesce = xgene_enet_setup_coalescing,
 };
index abe1eabc017177ede3d1bdc7df6bec5a8ded86da..6446af1403f70be8101625ed9a8b03d3de17b792 100644 (file)
@@ -163,7 +163,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
                struct sk_buff *skb = tx_buff->skb;
                unsigned int info = le32_to_cpu(txbd->info);
 
-               if ((info & FOR_EMAC) || !txbd->data)
+               if ((info & FOR_EMAC) || !txbd->data || !skb)
                        break;
 
                if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
@@ -191,6 +191,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 
                txbd->data = 0;
                txbd->info = 0;
+               tx_buff->skb = NULL;
 
                *txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
        }
@@ -446,6 +447,9 @@ static int arc_emac_open(struct net_device *ndev)
                *last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;
        }
 
+       priv->txbd_curr = 0;
+       priv->txbd_dirty = 0;
+
        /* Clean Tx BD's */
        memset(priv->txbd, 0, TX_RING_SZ);
 
@@ -513,6 +517,64 @@ static void arc_emac_set_rx_mode(struct net_device *ndev)
        }
 }
 
+/**
+ * arc_free_tx_queue - free skb from tx queue
+ * @ndev:      Pointer to the network device.
+ *
+ * This function must be called while EMAC disable
+ */
+static void arc_free_tx_queue(struct net_device *ndev)
+{
+       struct arc_emac_priv *priv = netdev_priv(ndev);
+       unsigned int i;
+
+       for (i = 0; i < TX_BD_NUM; i++) {
+               struct arc_emac_bd *txbd = &priv->txbd[i];
+               struct buffer_state *tx_buff = &priv->tx_buff[i];
+
+               if (tx_buff->skb) {
+                       dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr),
+                                        dma_unmap_len(tx_buff, len), DMA_TO_DEVICE);
+
+                       /* return the sk_buff to system */
+                       dev_kfree_skb_irq(tx_buff->skb);
+               }
+
+               txbd->info = 0;
+               txbd->data = 0;
+               tx_buff->skb = NULL;
+       }
+}
+
+/**
+ * arc_free_rx_queue - free skb from rx queue
+ * @ndev:      Pointer to the network device.
+ *
+ * This function must be called while EMAC disable
+ */
+static void arc_free_rx_queue(struct net_device *ndev)
+{
+       struct arc_emac_priv *priv = netdev_priv(ndev);
+       unsigned int i;
+
+       for (i = 0; i < RX_BD_NUM; i++) {
+               struct arc_emac_bd *rxbd = &priv->rxbd[i];
+               struct buffer_state *rx_buff = &priv->rx_buff[i];
+
+               if (rx_buff->skb) {
+                       dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
+                                       dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
+
+                       /* return the sk_buff to system */
+                       dev_kfree_skb_irq(rx_buff->skb);
+               }
+
+               rxbd->info = 0;
+               rxbd->data = 0;
+               rx_buff->skb = NULL;
+       }
+}
+
 /**
  * arc_emac_stop - Close the network device.
  * @ndev:      Pointer to the network device.
@@ -534,6 +596,10 @@ static int arc_emac_stop(struct net_device *ndev)
        /* Disable EMAC */
        arc_reg_clr(priv, R_CTRL, EN_MASK);
 
+       /* Return the sk_buff to system */
+       arc_free_tx_queue(ndev);
+       arc_free_rx_queue(ndev);
+
        return 0;
 }
 
@@ -610,7 +676,6 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
        dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
        dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
-       priv->tx_buff[*txbd_curr].skb = skb;
        priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
 
        /* Make sure pointer to data buffer is set */
@@ -620,6 +685,11 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 
        *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
+       /* Make sure info word is set */
+       wmb();
+
+       priv->tx_buff[*txbd_curr].skb = skb;
+
        /* Increment index to point to the next BD */
        *txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
index 8b5988e210d55bcae21f4c6bb8614696cb7b0b64..d0084d4d1a9b718773ca2e6ecae238d285392999 100644 (file)
@@ -65,10 +65,6 @@ static void atl1c_reset_dma_ring(struct atl1c_adapter *adapter);
 static int atl1c_configure(struct atl1c_adapter *adapter);
 static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter);
 
-static const u16 atl1c_pay_load_size[] = {
-       128, 256, 512, 1024, 2048, 4096,
-};
-
 
 static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
        NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
index f71ab2647a3bc1f62f6b7450b34dd325c710549d..08a23e6b60e947894783f2115c2fe16abece84bc 100644 (file)
@@ -1460,7 +1460,19 @@ static int nb8800_probe(struct platform_device *pdev)
                goto err_disable_clk;
        }
 
-       priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+       if (of_phy_is_fixed_link(pdev->dev.of_node)) {
+               ret = of_phy_register_fixed_link(pdev->dev.of_node);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "bad fixed-link spec\n");
+                       goto err_free_bus;
+               }
+               priv->phy_node = of_node_get(pdev->dev.of_node);
+       }
+
+       if (!priv->phy_node)
+               priv->phy_node = of_parse_phandle(pdev->dev.of_node,
+                                                 "phy-handle", 0);
+
        if (!priv->phy_node) {
                dev_err(&pdev->dev, "no PHY specified\n");
                ret = -ENODEV;
index 19f7cd02e08527ec234b1e8de426bad1fd37cadb..18042c2460bdae7c53e038d4ed4cdcd4ee2d92c6 100644 (file)
@@ -149,6 +149,16 @@ config BNX2X_VXLAN
          Say Y here if you want to enable hardware offload support for
          Virtual eXtensible Local Area Network (VXLAN) in the driver.
 
+config BNX2X_GENEVE
+       bool "Generic Network Virtualization Encapsulation (GENEVE) support"
+       depends on BNX2X && GENEVE && !(BNX2X=y && GENEVE=m)
+       ---help---
+          This allows one to create GENEVE virtual interfaces that provide
+          Layer 2 Networks over Layer 3 Networks. GENEVE is often used
+          to tunnel virtual network infrastructure in virtualized environments.
+         Say Y here if you want to enable hardware offload support for
+         Generic Network Virtualization Encapsulation (GENEVE) in the driver.
+
 config BGMAC
        tristate "BCMA bus GBit core support"
        depends on BCMA && BCMA_HOST_SOC
index 230f8e6209e57f22e1c5fc4c3cf3a6ade4aca95f..99b30a952b38736a825efc5149aa9027f6fae64d 100644 (file)
@@ -30,6 +30,7 @@ static inline bool bgmac_is_bcm4707_family(struct bgmac *bgmac)
 {
        switch (bgmac->core->bus->chipinfo.id) {
        case BCMA_CHIP_ID_BCM4707:
+       case BCMA_CHIP_ID_BCM47094:
        case BCMA_CHIP_ID_BCM53018:
                return true;
        default:
@@ -1052,8 +1053,9 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
            (ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg == BCMA_PKG_ID_BCM47188))
                iost &= ~BGMAC_BCMA_IOST_ATTACHED;
 
-       /* 3GMAC: for BCM4707, only do core reset at bgmac_probe() */
-       if (ci->id != BCMA_CHIP_ID_BCM4707) {
+       /* 3GMAC: for BCM4707 & BCM47094, only do core reset at bgmac_probe() */
+       if (ci->id != BCMA_CHIP_ID_BCM4707 &&
+           ci->id != BCMA_CHIP_ID_BCM47094) {
                flags = 0;
                if (iost & BGMAC_BCMA_IOST_ATTACHED) {
                        flags = BGMAC_BCMA_IOCTL_SW_CLKEN;
index cae0956186ce9863df8bcaf5368eb222d7c98da5..7dd7490fdac1fd1d8429bfcf90fa5a2147769d37 100644 (file)
@@ -1277,8 +1277,7 @@ enum sp_rtnl_flag {
        BNX2X_SP_RTNL_HYPERVISOR_VLAN,
        BNX2X_SP_RTNL_TX_STOP,
        BNX2X_SP_RTNL_GET_DRV_VERSION,
-       BNX2X_SP_RTNL_ADD_VXLAN_PORT,
-       BNX2X_SP_RTNL_DEL_VXLAN_PORT,
+       BNX2X_SP_RTNL_CHANGE_UDP_PORT,
 };
 
 enum bnx2x_iov_flag {
@@ -1327,6 +1326,17 @@ struct bnx2x_vlan_entry {
        bool hw;
 };
 
+enum bnx2x_udp_port_type {
+       BNX2X_UDP_PORT_VXLAN,
+       BNX2X_UDP_PORT_GENEVE,
+       BNX2X_UDP_PORT_MAX,
+};
+
+struct bnx2x_udp_tunnel {
+       u16 dst_port;
+       u8 count;
+};
+
 struct bnx2x {
        /* Fields used in the tx and intr/napi performance paths
         * are grouped together in the beginning of the structure
@@ -1830,9 +1840,10 @@ struct bnx2x {
        struct list_head vlan_reg;
        u16 vlan_cnt;
        u16 vlan_credit;
-       u16 vxlan_dst_port;
-       u8 vxlan_dst_port_count;
        bool accept_any_vlan;
+
+       /* Vxlan/Geneve related information */
+       struct bnx2x_udp_tunnel udp_tunnel_ports[BNX2X_UDP_PORT_MAX];
 };
 
 /* Tx queues may be less or equal to Rx queues */
index 9695a4c4a434a1c33adc24f9642242591a74798d..a949783c8fc3bbb4c2ba1926492bf4de376ca166 100644 (file)
@@ -4272,6 +4272,14 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
        return 0;
 }
 
+int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                    struct tc_to_netdev *tc)
+{
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+       return bnx2x_setup_tc(dev, tc->tc);
+}
+
 /* called with rtnl_lock */
 int bnx2x_change_mac_addr(struct net_device *dev, void *p)
 {
@@ -5086,4 +5094,3 @@ void bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag,
           flag);
        schedule_delayed_work(&bp->sp_rtnl_task, 0);
 }
-EXPORT_SYMBOL(bnx2x_schedule_sp_rtnl);
index 4cbb03f87b5a77924c919c2341fbd0374c8dac94..0e68fadecfdb83e8acdd88681016a4828496c1be 100644 (file)
@@ -486,6 +486,8 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* setup_tc callback */
 int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
+int __bnx2x_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                    struct tc_to_netdev *tc);
 
 int bnx2x_get_vf_config(struct net_device *dev, int vf,
                        struct ifla_vf_info *ivi);
@@ -923,6 +925,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
        struct bnx2x_func_state_params func_params = {NULL};
        struct bnx2x_func_start_params *start_params =
                &func_params.params.start;
+       u16 port;
 
        /* Prepare parameters for function state transitions */
        __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
@@ -959,8 +962,14 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
                start_params->network_cos_mode = STATIC_COS;
        else /* CHIP_IS_E1X */
                start_params->network_cos_mode = FW_WRR;
-
-       start_params->vxlan_dst_port = bp->vxlan_dst_port;
+       if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count) {
+               port = bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].dst_port;
+               start_params->vxlan_dst_port = port;
+       }
+       if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count) {
+               port = bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].dst_port;
+               start_params->geneve_dst_port = port;
+       }
 
        start_params->inner_rss = 1;
 
index 7ccf6684e0a32d3b4a6caa78fa1fbff8dbbef460..2c6ba046d2a869abaacece4ad7d6ead66295d642 100644 (file)
@@ -195,6 +195,7 @@ static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
                                   u32 error) {
        u8 index;
        u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
+       u8 iscsi_pri_found = 0, fcoe_pri_found = 0;
 
        if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR))
                DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_ERROR\n");
@@ -210,29 +211,57 @@ static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp,
 
                bp->dcbx_port_params.app.enabled = true;
 
+               /* Use 0 as the default application priority for all. */
                for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++)
                        ttp[index] = 0;
 
-               if (app->default_pri < MAX_PFC_PRIORITIES)
-                       ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri;
-
                for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) {
                        struct dcbx_app_priority_entry *entry =
                                                        app->app_pri_tbl;
+                       enum traffic_type type = MAX_TRAFFIC_TYPE;
 
                        if (GET_FLAGS(entry[index].appBitfield,
-                                    DCBX_APP_SF_ETH_TYPE) &&
-                          ETH_TYPE_FCOE == entry[index].app_id)
-                               bnx2x_dcbx_get_ap_priority(bp,
-                                               entry[index].pri_bitmap,
-                                               LLFC_TRAFFIC_TYPE_FCOE);
+                                     DCBX_APP_SF_DEFAULT) &&
+                           GET_FLAGS(entry[index].appBitfield,
+                                     DCBX_APP_SF_ETH_TYPE)) {
+                               type = LLFC_TRAFFIC_TYPE_NW;
+                       } else if (GET_FLAGS(entry[index].appBitfield,
+                                            DCBX_APP_SF_PORT) &&
+                                  TCP_PORT_ISCSI == entry[index].app_id) {
+                               type = LLFC_TRAFFIC_TYPE_ISCSI;
+                               iscsi_pri_found = 1;
+                       } else if (GET_FLAGS(entry[index].appBitfield,
+                                            DCBX_APP_SF_ETH_TYPE) &&
+                                  ETH_TYPE_FCOE == entry[index].app_id) {
+                               type = LLFC_TRAFFIC_TYPE_FCOE;
+                               fcoe_pri_found = 1;
+                       }
 
-                       if (GET_FLAGS(entry[index].appBitfield,
-                                    DCBX_APP_SF_PORT) &&
-                          TCP_PORT_ISCSI == entry[index].app_id)
-                               bnx2x_dcbx_get_ap_priority(bp,
-                                               entry[index].pri_bitmap,
-                                               LLFC_TRAFFIC_TYPE_ISCSI);
+                       if (type == MAX_TRAFFIC_TYPE)
+                               continue;
+
+                       bnx2x_dcbx_get_ap_priority(bp,
+                                                  entry[index].pri_bitmap,
+                                                  type);
+               }
+
+               /* If we have received a non-zero default application
+                * priority, then use that for applications which are
+                * not configured with any priority.
+                */
+               if (ttp[LLFC_TRAFFIC_TYPE_NW] != 0) {
+                       if (!iscsi_pri_found) {
+                               ttp[LLFC_TRAFFIC_TYPE_ISCSI] =
+                                       ttp[LLFC_TRAFFIC_TYPE_NW];
+                               DP(BNX2X_MSG_DCB,
+                                  "ISCSI is using default priority.\n");
+                       }
+                       if (!fcoe_pri_found) {
+                               ttp[LLFC_TRAFFIC_TYPE_FCOE] =
+                                       ttp[LLFC_TRAFFIC_TYPE_NW];
+                               DP(BNX2X_MSG_DCB,
+                                  "FCoE is using default priority.\n");
+                       }
                }
        } else {
                DP(BNX2X_MSG_DCB, "DCBX_LOCAL_APP_DISABLED\n");
index 820b7e04bb5f3c296de6f2d57567416edfd7292a..85a7800bfc128e56b5a3886cba65b707ed5db57b 100644 (file)
@@ -981,6 +981,11 @@ static void bnx2x_get_regs(struct net_device *dev,
        memcpy(p, &dump_hdr, sizeof(struct dump_header));
        p += dump_hdr.header_size + 1;
 
+       /* This isn't really an error, but since attention handling is going
+        * to print the GRC timeouts using this macro, we use the same.
+        */
+       BNX2X_ERR("Generating register dump. Might trigger harmless GRC timeouts\n");
+
        /* Actually read the registers */
        __bnx2x_get_regs(bp, p);
 
index 27aa0802d87d5f46d813184649dd9107fdeb541b..f8b8103130947a5c47d760ce70eb4e1e7af083b6 100644 (file)
@@ -1824,17 +1824,22 @@ struct dcbx_app_priority_entry {
        u8  pri_bitmap;
        u8  appBitfield;
        #define DCBX_APP_ENTRY_VALID         0x01
-       #define DCBX_APP_ENTRY_SF_MASK       0x30
+       #define DCBX_APP_ENTRY_SF_MASK       0xF0
        #define DCBX_APP_ENTRY_SF_SHIFT      4
        #define DCBX_APP_SF_ETH_TYPE         0x10
        #define DCBX_APP_SF_PORT             0x20
+       #define DCBX_APP_SF_UDP              0x40
+       #define DCBX_APP_SF_DEFAULT          0x80
 #elif defined(__LITTLE_ENDIAN)
        u8 appBitfield;
        #define DCBX_APP_ENTRY_VALID         0x01
-       #define DCBX_APP_ENTRY_SF_MASK       0x30
+       #define DCBX_APP_ENTRY_SF_MASK       0xF0
        #define DCBX_APP_ENTRY_SF_SHIFT      4
+       #define DCBX_APP_ENTRY_VALID         0x01
        #define DCBX_APP_SF_ETH_TYPE         0x10
        #define DCBX_APP_SF_PORT             0x20
+       #define DCBX_APP_SF_UDP              0x40
+       #define DCBX_APP_SF_DEFAULT          0x80
        u8  pri_bitmap;
        u16  app_id;
 #endif
@@ -4896,9 +4901,9 @@ struct c2s_pri_trans_table_entry {
  * cfc delete event data
  */
 struct cfc_del_event_data {
-       u32 cid;
-       u32 reserved0;
-       u32 reserved1;
+       __le32 cid;
+       __le32 reserved0;
+       __le32 reserved1;
 };
 
 
@@ -5114,15 +5119,9 @@ struct vf_pf_channel_zone_trigger {
  * zone that triggers the in-bound interrupt
  */
 struct trigger_vf_zone {
-#if defined(__BIG_ENDIAN)
-       u16 reserved1;
-       u8 reserved0;
-       struct vf_pf_channel_zone_trigger vf_pf_channel;
-#elif defined(__LITTLE_ENDIAN)
        struct vf_pf_channel_zone_trigger vf_pf_channel;
        u8 reserved0;
        u16 reserved1;
-#endif
        u32 reserved2;
 };
 
@@ -5207,9 +5206,9 @@ struct e2_integ_data {
  * set mac event data
  */
 struct eth_event_data {
-       u32 echo;
-       u32 reserved0;
-       u32 reserved1;
+       __le32 echo;
+       __le32 reserved0;
+       __le32 reserved1;
 };
 
 
@@ -5219,9 +5218,9 @@ struct eth_event_data {
 struct vf_pf_event_data {
        u8 vf_id;
        u8 reserved0;
-       u16 reserved1;
-       u32 msg_addr_lo;
-       u32 msg_addr_hi;
+       __le16 reserved1;
+       __le32 msg_addr_lo;
+       __le32 msg_addr_hi;
 };
 
 /*
@@ -5230,9 +5229,9 @@ struct vf_pf_event_data {
 struct vf_flr_event_data {
        u8 vf_id;
        u8 reserved0;
-       u16 reserved1;
-       u32 reserved2;
-       u32 reserved3;
+       __le16 reserved1;
+       __le32 reserved2;
+       __le32 reserved3;
 };
 
 /*
@@ -5241,9 +5240,9 @@ struct vf_flr_event_data {
 struct malicious_vf_event_data {
        u8 vf_id;
        u8 err_id;
-       u16 reserved1;
-       u32 reserved2;
-       u32 reserved3;
+       __le16 reserved1;
+       __le32 reserved2;
+       __le32 reserved3;
 };
 
 /*
index d946bba43726f94b0d8a62973978a19d07959390..1fb80100e5e7d753b2ddd8ae741e0120ac161f42 100644 (file)
@@ -6185,26 +6185,80 @@ static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
                shift -= 4;
                digit = ((num & mask) >> shift);
                if (digit == 0 && remove_leading_zeros) {
-                       mask = mask >> 4;
-                       continue;
-               } else if (digit < 0xa)
-                       *str_ptr = digit + '0';
-               else
-                       *str_ptr = digit - 0xa + 'a';
-               remove_leading_zeros = 0;
-               str_ptr++;
-               (*len)--;
+                       *str_ptr = '0';
+               } else {
+                       if (digit < 0xa)
+                               *str_ptr = digit + '0';
+                       else
+                               *str_ptr = digit - 0xa + 'a';
+
+                       remove_leading_zeros = 0;
+                       str_ptr++;
+                       (*len)--;
+               }
                mask = mask >> 4;
                if (shift == 4*4) {
+                       if (remove_leading_zeros) {
+                               str_ptr++;
+                               (*len)--;
+                       }
                        *str_ptr = '.';
                        str_ptr++;
                        (*len)--;
                        remove_leading_zeros = 1;
                }
        }
+       if (remove_leading_zeros)
+               (*len)--;
        return 0;
 }
 
+static int bnx2x_3_seq_format_ver(u32 num, u8 *str, u16 *len)
+{
+       u8 *str_ptr = str;
+       u32 mask = 0x00f00000;
+       u8 shift = 8*3;
+       u8 digit;
+       u8 remove_leading_zeros = 1;
+
+       if (*len < 10) {
+               /* Need more than 10chars for this format */
+               *str_ptr = '\0';
+               (*len)--;
+               return -EINVAL;
+       }
+
+       while (shift > 0) {
+               shift -= 4;
+               digit = ((num & mask) >> shift);
+               if (digit == 0 && remove_leading_zeros) {
+                       *str_ptr = '0';
+               } else {
+                       if (digit < 0xa)
+                               *str_ptr = digit + '0';
+                       else
+                               *str_ptr = digit - 0xa + 'a';
+
+                       remove_leading_zeros = 0;
+                       str_ptr++;
+                       (*len)--;
+               }
+               mask = mask >> 4;
+               if ((shift == 4*4) || (shift == 4*2)) {
+                       if (remove_leading_zeros) {
+                               str_ptr++;
+                               (*len)--;
+                       }
+                       *str_ptr = '.';
+                       str_ptr++;
+                       (*len)--;
+                       remove_leading_zeros = 1;
+               }
+       }
+       if (remove_leading_zeros)
+               (*len)--;
+       return 0;
+}
 
 static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
 {
@@ -9677,8 +9731,9 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
 
        if (bnx2x_is_8483x_8485x(phy)) {
                bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1);
-               bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff,
-                               phy->ver_addr);
+               if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+                       fw_ver1 &= 0xfff;
+               bnx2x_save_spirom_version(bp, port, fw_ver1, phy->ver_addr);
        } else {
                /* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
                /* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
@@ -9732,16 +9787,32 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
 static void bnx2x_848xx_set_led(struct bnx2x *bp,
                                struct bnx2x_phy *phy)
 {
-       u16 val, offset, i;
+       u16 val, led3_blink_rate, offset, i;
        static struct bnx2x_reg_set reg_set[] = {
                {MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED1_MASK, 0x0080},
                {MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED2_MASK, 0x0018},
                {MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_MASK, 0x0006},
-               {MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_LED3_BLINK, 0x0000},
                {MDIO_PMA_DEVAD, MDIO_PMA_REG_84823_CTL_SLOW_CLK_CNT_HIGH,
                        MDIO_PMA_REG_84823_BLINK_RATE_VAL_15P9HZ},
                {MDIO_AN_DEVAD, 0xFFFB, 0xFFFD}
        };
+
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+               /* Set LED5 source */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD,
+                                MDIO_PMA_REG_8481_LED5_MASK,
+                                0x90);
+               led3_blink_rate = 0x000f;
+       } else {
+               led3_blink_rate = 0x0000;
+       }
+       /* Set LED3 BLINK */
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD,
+                        MDIO_PMA_REG_8481_LED3_BLINK,
+                        led3_blink_rate);
+
        /* PHYC_CTL_LED_CTL */
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD,
@@ -9749,6 +9820,9 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
        val &= 0xFE00;
        val |= 0x0092;
 
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+               val |= 2 << 12; /* LED5 ON based on source */
+
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
                         MDIO_PMA_REG_8481_LINK_SIGNAL, val);
@@ -9762,10 +9836,17 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
        else
                offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1;
 
-       /* stretch_en for LED3*/
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)
+               val = MDIO_PMA_REG_84858_ALLOW_GPHY_ACT |
+                     MDIO_PMA_REG_84823_LED3_STRETCH_EN;
+       else
+               val = MDIO_PMA_REG_84823_LED3_STRETCH_EN;
+
+       /* stretch_en for LEDs */
        bnx2x_cl45_read_or_write(bp, phy,
-                                MDIO_PMA_DEVAD, offset,
-                                MDIO_PMA_REG_84823_LED3_STRETCH_EN);
+                                MDIO_PMA_DEVAD,
+                                offset,
+                                val);
 }
 
 static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,
@@ -9775,7 +9856,7 @@ static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        switch (action) {
        case PHY_INIT:
-               if (!bnx2x_is_8483x_8485x(phy)) {
+               if (bnx2x_is_8483x_8485x(phy)) {
                        /* Save spirom version */
                        bnx2x_save_848xx_spirom_version(phy, bp, params->port);
                }
@@ -10036,15 +10117,20 @@ static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy,
 
 static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
                                struct link_params *params, u16 fw_cmd,
-                               u16 cmd_args[], int argc)
+                               u16 cmd_args[], int argc, int process)
 {
        int idx;
        u16 val;
        struct bnx2x *bp = params->bp;
-       /* Write CMD_OPEN_OVERRIDE to STATUS reg */
-       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
-                       MDIO_848xx_CMD_HDLR_STATUS,
-                       PHY84833_STATUS_CMD_OPEN_OVERRIDE);
+       int rc = 0;
+
+       if (process == PHY84833_MB_PROCESS2) {
+               /* Write CMD_OPEN_OVERRIDE to STATUS reg */
+               bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                                MDIO_848xx_CMD_HDLR_STATUS,
+                                PHY84833_STATUS_CMD_OPEN_OVERRIDE);
+       }
+
        for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
                bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
                                MDIO_848xx_CMD_HDLR_STATUS, &val);
@@ -10054,15 +10140,27 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
        }
        if (idx >= PHY848xx_CMDHDLR_WAIT) {
                DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n");
+               /* if the status is CMD_COMPLETE_PASS or CMD_COMPLETE_ERROR
+                * clear the status to CMD_CLEAR_COMPLETE
+                */
+               if (val == PHY84833_STATUS_CMD_COMPLETE_PASS ||
+                   val == PHY84833_STATUS_CMD_COMPLETE_ERROR) {
+                       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                                        MDIO_848xx_CMD_HDLR_STATUS,
+                                        PHY84833_STATUS_CMD_CLEAR_COMPLETE);
+               }
                return -EINVAL;
        }
-
-       /* Prepare argument(s) and issue command */
-       for (idx = 0; idx < argc; idx++) {
-               bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
-                               MDIO_848xx_CMD_HDLR_DATA1 + idx,
-                               cmd_args[idx]);
+       if (process == PHY84833_MB_PROCESS1 ||
+           process == PHY84833_MB_PROCESS2) {
+               /* Prepare argument(s) */
+               for (idx = 0; idx < argc; idx++) {
+                       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                                        MDIO_848xx_CMD_HDLR_DATA1 + idx,
+                                        cmd_args[idx]);
+               }
        }
+
        bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
                        MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd);
        for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) {
@@ -10076,24 +10174,30 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy,
        if ((idx >= PHY848xx_CMDHDLR_WAIT) ||
            (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) {
                DP(NETIF_MSG_LINK, "FW cmd failed.\n");
-               return -EINVAL;
+               rc = -EINVAL;
        }
-       /* Gather returning data */
-       for (idx = 0; idx < argc; idx++) {
-               bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
-                               MDIO_848xx_CMD_HDLR_DATA1 + idx,
-                               &cmd_args[idx]);
+       if (process == PHY84833_MB_PROCESS3 && rc == 0) {
+               /* Gather returning data */
+               for (idx = 0; idx < argc; idx++) {
+                       bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+                                       MDIO_848xx_CMD_HDLR_DATA1 + idx,
+                                       &cmd_args[idx]);
+               }
        }
-       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
-                       MDIO_848xx_CMD_HDLR_STATUS,
-                       PHY84833_STATUS_CMD_CLEAR_COMPLETE);
-       return 0;
+       if (val == PHY84833_STATUS_CMD_COMPLETE_ERROR ||
+           val == PHY84833_STATUS_CMD_COMPLETE_PASS) {
+               bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                                MDIO_848xx_CMD_HDLR_STATUS,
+                                PHY84833_STATUS_CMD_CLEAR_COMPLETE);
+       }
+       return rc;
 }
 
 static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,
                                struct link_params *params,
                                u16 fw_cmd,
-                               u16 cmd_args[], int argc)
+                                          u16 cmd_args[], int argc,
+                                          int process)
 {
        struct bnx2x *bp = params->bp;
 
@@ -10106,7 +10210,7 @@ static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy,
                                            argc);
        } else {
                return bnx2x_84833_cmd_hdlr(phy, params, fw_cmd, cmd_args,
-                                           argc);
+                                           argc, process);
        }
 }
 
@@ -10133,7 +10237,7 @@ static int bnx2x_848xx_pair_swap_cfg(struct bnx2x_phy *phy,
 
        status = bnx2x_848xx_cmd_hdlr(phy, params,
                                      PHY848xx_CMD_SET_PAIR_SWAP, data,
-                                     PHY848xx_CMDHDLR_MAX_ARGS);
+                                     2, PHY84833_MB_PROCESS2);
        if (status == 0)
                DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]);
 
@@ -10222,8 +10326,8 @@ static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n");
 
        /* Prevent Phy from working in EEE and advertising it */
-       rc = bnx2x_848xx_cmd_hdlr(phy, params,
-                                 PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1);
+       rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE,
+                                 &cmd_args, 1, PHY84833_MB_PROCESS1);
        if (rc) {
                DP(NETIF_MSG_LINK, "EEE disable failed.\n");
                return rc;
@@ -10240,8 +10344,8 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy,
        struct bnx2x *bp = params->bp;
        u16 cmd_args = 1;
 
-       rc = bnx2x_848xx_cmd_hdlr(phy, params,
-                                 PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1);
+       rc = bnx2x_848xx_cmd_hdlr(phy, params, PHY848xx_CMD_SET_EEE_MODE,
+                                 &cmd_args, 1, PHY84833_MB_PROCESS1);
        if (rc) {
                DP(NETIF_MSG_LINK, "EEE enable failed.\n");
                return rc;
@@ -10362,7 +10466,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                cmd_args[3] = PHY84833_CONSTANT_LATENCY;
                rc = bnx2x_848xx_cmd_hdlr(phy, params,
                                          PHY848xx_CMD_SET_EEE_MODE, cmd_args,
-                                         PHY848xx_CMDHDLR_MAX_ARGS);
+                                         4, PHY84833_MB_PROCESS1);
                if (rc)
                        DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n");
        }
@@ -10416,6 +10520,32 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK;
        }
 
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+               /* Additional settings for jumbo packets in 1000BASE-T mode */
+               /* Allow rx extended length */
+               bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8481_AUX_CTRL, &val);
+               val |= 0x4000;
+               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_AUX_CTRL, val);
+               /* TX FIFO Elasticity LSB */
+               bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8481_1G_100T_EXT_CTRL, &val);
+               val |= 0x1;
+               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_1G_100T_EXT_CTRL, val);
+               /* TX FIFO Elasticity MSB */
+               /* Enable expansion register 0x46 (Pattern Generator status) */
+               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf46);
+
+               bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, &val);
+               val |= 0x4000;
+               bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, val);
+       }
+
        if (bnx2x_is_8483x_8485x(phy)) {
                /* Bring PHY out of super isolate mode as the final step. */
                bnx2x_cl45_read_and_write(bp, phy,
@@ -10555,6 +10685,17 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
        return link_up;
 }
 
+static int bnx2x_8485x_format_ver(u32 raw_ver, u8 *str, u16 *len)
+{
+       int status = 0;
+       u32 num;
+
+       num = ((raw_ver & 0xF80) >> 7) << 16 | ((raw_ver & 0x7F) << 8) |
+             ((raw_ver & 0xF000) >> 12);
+       status = bnx2x_3_seq_format_ver(num, str, len);
+       return status;
+}
+
 static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
 {
        int status = 0;
@@ -10651,10 +10792,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                        0x0);
 
                } else {
+                       /* LED 1 OFF */
                        bnx2x_cl45_write(bp, phy,
                                         MDIO_PMA_DEVAD,
                                         MDIO_PMA_REG_8481_LED1_MASK,
                                         0x0);
+
+                       if (phy->type ==
+                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+                               /* LED 2 OFF */
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED2_MASK,
+                                                0x0);
+                               /* LED 3 OFF */
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED3_MASK,
+                                                0x0);
+                       }
                }
                break;
        case LED_MODE_FRONT_PANEL_OFF:
@@ -10713,6 +10869,19 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                                 MDIO_PMA_REG_8481_SIGNAL_MASK,
                                                 0x0);
                        }
+                       if (phy->type ==
+                               PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+                               /* LED 2 OFF */
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED2_MASK,
+                                                0x0);
+                               /* LED 3 OFF */
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED3_MASK,
+                                                0x0);
+                       }
                }
                break;
        case LED_MODE_ON:
@@ -10776,6 +10945,25 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                                params->port*4,
                                                NIG_MASK_MI_INT);
                                }
+                       }
+                       if (phy->type ==
+                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+                               /* Tell LED3 to constant on */
+                               bnx2x_cl45_read(bp, phy,
+                                               MDIO_PMA_DEVAD,
+                                               MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                               &val);
+                               val &= ~(7<<6);
+                               val |= (2<<6);  /* A83B[8:6]= 2 */
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LINK_SIGNAL,
+                                                val);
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED3_MASK,
+                                                0x20);
+                       } else {
                                bnx2x_cl45_write(bp, phy,
                                                 MDIO_PMA_DEVAD,
                                                 MDIO_PMA_REG_8481_SIGNAL_MASK,
@@ -10853,6 +11041,17 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                                         MDIO_PMA_DEVAD,
                                         MDIO_PMA_REG_8481_LINK_SIGNAL,
                                         val);
+                       if (phy->type ==
+                           PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) {
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED2_MASK,
+                                                0x18);
+                               bnx2x_cl45_write(bp, phy,
+                                                MDIO_PMA_DEVAD,
+                                                MDIO_PMA_REG_8481_LED3_MASK,
+                                                0x06);
+                       }
                        if (phy->type ==
                            PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
                                /* Restore LED4 source to external link,
@@ -11982,7 +12181,7 @@ static const struct bnx2x_phy phy_84858 = {
        .read_status    = (read_status_t)bnx2x_848xx_read_status,
        .link_reset     = (link_reset_t)bnx2x_848x3_link_reset,
        .config_loopback = (config_loopback_t)NULL,
-       .format_fw_ver  = (format_fw_ver_t)bnx2x_848xx_format_ver,
+       .format_fw_ver  = (format_fw_ver_t)bnx2x_8485x_format_ver,
        .hw_reset       = (hw_reset_t)bnx2x_84833_hw_reset_phy,
        .set_link_led   = (set_link_led_t)bnx2x_848xx_set_link_led,
        .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func
@@ -13807,8 +14006,10 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
        if (CHIP_IS_E3(bp)) {
                struct bnx2x_phy *phy = &params->phy[INT_PHY];
                bnx2x_set_aer_mmd(params, phy);
-               if ((phy->supported & SUPPORTED_20000baseKR2_Full) &&
-                   (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G))
+               if (((phy->req_line_speed == SPEED_AUTO_NEG) &&
+                    (phy->speed_cap_mask &
+                     PORT_HW_CFG_SPEED_CAPABILITY_D0_20G)) ||
+                   (phy->req_line_speed == SPEED_20000))
                        bnx2x_check_kr2_wa(params, vars, phy);
                bnx2x_check_over_curr(params, vars);
                if (vars->rx_tx_asic_rst)
index 6c4e3a69976fcaf4ecc0bafcebbcb2e725a40575..b597c32275aa05797d3e9604a214577d623671d5 100644 (file)
@@ -59,7 +59,9 @@
 #include <linux/semaphore.h>
 #include <linux/stringify.h>
 #include <linux/vmalloc.h>
-
+#if IS_ENABLED(CONFIG_BNX2X_GENEVE)
+#include <net/geneve.h>
+#endif
 #include "bnx2x.h"
 #include "bnx2x_init.h"
 #include "bnx2x_init_ops.h"
@@ -5280,14 +5282,14 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
 {
        unsigned long ramrod_flags = 0;
        int rc = 0;
-       u32 cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK;
+       u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);
+       u32 cid = echo & BNX2X_SWCID_MASK;
        struct bnx2x_vlan_mac_obj *vlan_mac_obj;
 
        /* Always push next commands out, don't wait here */
        __set_bit(RAMROD_CONT, &ramrod_flags);
 
-       switch (le32_to_cpu((__force __le32)elem->message.data.eth_event.echo)
-                           >> BNX2X_SWCID_SHIFT) {
+       switch (echo >> BNX2X_SWCID_SHIFT) {
        case BNX2X_FILTER_MAC_PENDING:
                DP(BNX2X_MSG_SP, "Got SETUP_MAC completions\n");
                if (CNIC_LOADED(bp) && (cid == BNX2X_ISCSI_ETH_CID(bp)))
@@ -5308,8 +5310,7 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
                bnx2x_handle_mcast_eqe(bp);
                return;
        default:
-               BNX2X_ERR("Unsupported classification command: %d\n",
-                         elem->message.data.eth_event.echo);
+               BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);
                return;
        }
 
@@ -5478,9 +5479,6 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                        goto next_spqe;
                }
 
-               /* elem CID originates from FW; actually LE */
-               cid = SW_CID((__force __le32)
-                            elem->message.data.cfc_del_event.cid);
                opcode = elem->message.opcode;
 
                /* handle eq element */
@@ -5503,6 +5501,10 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                         * we may want to verify here that the bp state is
                         * HALTING
                         */
+
+                       /* elem CID originates from FW; actually LE */
+                       cid = SW_CID(elem->message.data.cfc_del_event.cid);
+
                        DP(BNX2X_MSG_SP,
                           "got delete ramrod for MULTI[%d]\n", cid);
 
@@ -5596,10 +5598,8 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                      BNX2X_STATE_OPENING_WAIT4_PORT):
                case (EVENT_RING_OPCODE_RSS_UPDATE_RULES |
                      BNX2X_STATE_CLOSING_WAIT4_HALT):
-                       cid = elem->message.data.eth_event.echo &
-                               BNX2X_SWCID_MASK;
                        DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n",
-                          cid);
+                          SW_CID(elem->message.data.eth_event.echo));
                        rss_raw->clear_pending(rss_raw);
                        break;
 
@@ -5684,7 +5684,7 @@ static void bnx2x_sp_task(struct work_struct *work)
                if (status & BNX2X_DEF_SB_IDX) {
                        struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
 
-               if (FCOE_INIT(bp) &&
+                       if (FCOE_INIT(bp) &&
                            (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
                                /* Prevent local bottom-halves from running as
                                 * we are going to change the local NAPI list.
@@ -10076,11 +10076,13 @@ static void bnx2x_parity_recover(struct bnx2x *bp)
        }
 }
 
-#ifdef CONFIG_BNX2X_VXLAN
-static int bnx2x_vxlan_port_update(struct bnx2x *bp, u16 port)
+#if defined(CONFIG_BNX2X_VXLAN) || IS_ENABLED(CONFIG_BNX2X_GENEVE)
+static int bnx2x_udp_port_update(struct bnx2x *bp)
 {
        struct bnx2x_func_switch_update_params *switch_update_params;
        struct bnx2x_func_state_params func_params = {NULL};
+       struct bnx2x_udp_tunnel *udp_tunnel;
+       u16 vxlan_port = 0, geneve_port = 0;
        int rc;
 
        switch_update_params = &func_params.params.switch_update;
@@ -10095,69 +10097,125 @@ static int bnx2x_vxlan_port_update(struct bnx2x *bp, u16 port)
        /* Function parameters */
        __set_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
                  &switch_update_params->changes);
-       switch_update_params->vxlan_dst_port = port;
+
+       if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count) {
+               udp_tunnel = &bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE];
+               geneve_port = udp_tunnel->dst_port;
+               switch_update_params->geneve_dst_port = geneve_port;
+       }
+
+       if (bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count) {
+               udp_tunnel = &bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN];
+               vxlan_port = udp_tunnel->dst_port;
+               switch_update_params->vxlan_dst_port = vxlan_port;
+       }
+
+       /* Re-enable inner-rss for the offloaded UDP tunnels */
+       __set_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS,
+                 &switch_update_params->changes);
+
        rc = bnx2x_func_state_change(bp, &func_params);
        if (rc)
-               BNX2X_ERR("failed to change vxlan dst port to %d (rc = 0x%x)\n",
-                         port, rc);
+               BNX2X_ERR("failed to set UDP dst port to %04x %04x (rc = 0x%x)\n",
+                         vxlan_port, geneve_port, rc);
+       else
+               DP(BNX2X_MSG_SP,
+                  "Configured UDP ports: Vxlan [%04x] Geneve [%04x]\n",
+                  vxlan_port, geneve_port);
+
        return rc;
 }
 
-static void __bnx2x_add_vxlan_port(struct bnx2x *bp, u16 port)
+static void __bnx2x_add_udp_port(struct bnx2x *bp, u16 port,
+                                enum bnx2x_udp_port_type type)
 {
-       if (!netif_running(bp->dev))
+       struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
+
+       if (!netif_running(bp->dev) || !IS_PF(bp))
                return;
 
-       if (bp->vxlan_dst_port_count && bp->vxlan_dst_port == port) {
-               bp->vxlan_dst_port_count++;
+       if (udp_port->count && udp_port->dst_port == port) {
+               udp_port->count++;
                return;
        }
 
-       if (bp->vxlan_dst_port_count || !IS_PF(bp)) {
-               DP(BNX2X_MSG_SP, "Vxlan destination port limit reached\n");
+       if (udp_port->count) {
+               DP(BNX2X_MSG_SP,
+                  "UDP tunnel [%d] -  destination port limit reached\n",
+                  type);
+               return;
+       }
+
+       udp_port->dst_port = port;
+       udp_port->count = 1;
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_CHANGE_UDP_PORT, 0);
+}
+
+static void __bnx2x_del_udp_port(struct bnx2x *bp, u16 port,
+                                enum bnx2x_udp_port_type type)
+{
+       struct bnx2x_udp_tunnel *udp_port = &bp->udp_tunnel_ports[type];
+
+       if (!IS_PF(bp))
+               return;
+
+       if (!udp_port->count || udp_port->dst_port != port) {
+               DP(BNX2X_MSG_SP, "Invalid UDP tunnel [%d] port\n",
+                  type);
                return;
        }
 
-       bp->vxlan_dst_port = port;
-       bp->vxlan_dst_port_count = 1;
-       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_ADD_VXLAN_PORT, 0);
+       /* Remove reference, and make certain it's no longer in use */
+       udp_port->count--;
+       if (udp_port->count)
+               return;
+       udp_port->dst_port = 0;
+
+       if (netif_running(bp->dev))
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_CHANGE_UDP_PORT, 0);
+       else
+               DP(BNX2X_MSG_SP, "Deleted UDP tunnel [%d] port %d\n",
+                  type, port);
 }
+#endif
 
+#ifdef CONFIG_BNX2X_VXLAN
 static void bnx2x_add_vxlan_port(struct net_device *netdev,
                                 sa_family_t sa_family, __be16 port)
 {
        struct bnx2x *bp = netdev_priv(netdev);
        u16 t_port = ntohs(port);
 
-       __bnx2x_add_vxlan_port(bp, t_port);
+       __bnx2x_add_udp_port(bp, t_port, BNX2X_UDP_PORT_VXLAN);
 }
 
-static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port)
+static void bnx2x_del_vxlan_port(struct net_device *netdev,
+                                sa_family_t sa_family, __be16 port)
 {
-       if (!bp->vxlan_dst_port_count || bp->vxlan_dst_port != port ||
-           !IS_PF(bp)) {
-               DP(BNX2X_MSG_SP, "Invalid vxlan port\n");
-               return;
-       }
-       bp->vxlan_dst_port_count--;
-       if (bp->vxlan_dst_port_count)
-               return;
+       struct bnx2x *bp = netdev_priv(netdev);
+       u16 t_port = ntohs(port);
 
-       if (netif_running(bp->dev)) {
-               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_DEL_VXLAN_PORT, 0);
-       } else {
-               bp->vxlan_dst_port = 0;
-               netdev_info(bp->dev, "Deleted vxlan dest port %d", port);
-       }
+       __bnx2x_del_udp_port(bp, t_port, BNX2X_UDP_PORT_VXLAN);
 }
+#endif
 
-static void bnx2x_del_vxlan_port(struct net_device *netdev,
-                                sa_family_t sa_family, __be16 port)
+#if IS_ENABLED(CONFIG_BNX2X_GENEVE)
+static void bnx2x_add_geneve_port(struct net_device *netdev,
+                                 sa_family_t sa_family, __be16 port)
+{
+       struct bnx2x *bp = netdev_priv(netdev);
+       u16 t_port = ntohs(port);
+
+       __bnx2x_add_udp_port(bp, t_port, BNX2X_UDP_PORT_GENEVE);
+}
+
+static void bnx2x_del_geneve_port(struct net_device *netdev,
+                                 sa_family_t sa_family, __be16 port)
 {
        struct bnx2x *bp = netdev_priv(netdev);
        u16 t_port = ntohs(port);
 
-       __bnx2x_del_vxlan_port(bp, t_port);
+       __bnx2x_del_udp_port(bp, t_port, BNX2X_UDP_PORT_GENEVE);
 }
 #endif
 
@@ -10169,9 +10227,6 @@ static int bnx2x_close(struct net_device *dev);
 static void bnx2x_sp_rtnl_task(struct work_struct *work)
 {
        struct bnx2x *bp = container_of(work, struct bnx2x, sp_rtnl_task.work);
-#ifdef CONFIG_BNX2X_VXLAN
-       u16 port;
-#endif
 
        rtnl_lock();
 
@@ -10270,23 +10325,27 @@ sp_rtnl_not_reset:
                               &bp->sp_rtnl_state))
                bnx2x_update_mng_version(bp);
 
-#ifdef CONFIG_BNX2X_VXLAN
-       port = bp->vxlan_dst_port;
-       if (test_and_clear_bit(BNX2X_SP_RTNL_ADD_VXLAN_PORT,
-                              &bp->sp_rtnl_state)) {
-               if (!bnx2x_vxlan_port_update(bp, port))
-                       netdev_info(bp->dev, "Added vxlan dest port %d", port);
-               else
-                       bp->vxlan_dst_port = 0;
-       }
-
-       if (test_and_clear_bit(BNX2X_SP_RTNL_DEL_VXLAN_PORT,
+#if defined(CONFIG_BNX2X_VXLAN) || IS_ENABLED(CONFIG_BNX2X_GENEVE)
+       if (test_and_clear_bit(BNX2X_SP_RTNL_CHANGE_UDP_PORT,
                               &bp->sp_rtnl_state)) {
-               if (!bnx2x_vxlan_port_update(bp, 0)) {
-                       netdev_info(bp->dev,
-                                   "Deleted vxlan dest port %d", port);
-                       bp->vxlan_dst_port = 0;
-                       vxlan_get_rx_port(bp->dev);
+               if (bnx2x_udp_port_update(bp)) {
+                       /* On error, forget configuration */
+                       memset(bp->udp_tunnel_ports, 0,
+                              sizeof(struct bnx2x_udp_tunnel) *
+                              BNX2X_UDP_PORT_MAX);
+               } else {
+                       /* Since we don't store additional port information,
+                        * if no port is configured for any feature ask for
+                        * information about currently configured ports.
+                        */
+#ifdef CONFIG_BNX2X_VXLAN
+                       if (!bp->udp_tunnel_ports[BNX2X_UDP_PORT_VXLAN].count)
+                               vxlan_get_rx_port(bp->dev);
+#endif
+#if IS_ENABLED(CONFIG_BNX2X_GENEVE)
+                       if (!bp->udp_tunnel_ports[BNX2X_UDP_PORT_GENEVE].count)
+                               geneve_get_rx_port(bp->dev);
+#endif
                }
        }
 #endif
@@ -12368,8 +12427,10 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        if (SHMEM2_HAS(bp, dcbx_lldp_params_offset) &&
            SHMEM2_HAS(bp, dcbx_lldp_dcbx_stat_offset) &&
+           SHMEM2_HAS(bp, dcbx_en) &&
            SHMEM2_RD(bp, dcbx_lldp_params_offset) &&
-           SHMEM2_RD(bp, dcbx_lldp_dcbx_stat_offset)) {
+           SHMEM2_RD(bp, dcbx_lldp_dcbx_stat_offset) &&
+           SHMEM2_RD(bp, dcbx_en[BP_PORT(bp)])) {
                bnx2x_dcbx_set_state(bp, true, BNX2X_DCBX_ENABLED_ON_NEG_ON);
                bnx2x_dcbx_init_params(bp);
        } else {
@@ -12494,6 +12555,10 @@ static int bnx2x_open(struct net_device *dev)
        if (IS_PF(bp))
                vxlan_get_rx_port(dev);
 #endif
+#if IS_ENABLED(CONFIG_BNX2X_GENEVE)
+       if (IS_PF(bp))
+               geneve_get_rx_port(dev);
+#endif
 
        return 0;
 }
@@ -12994,7 +13059,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = poll_bnx2x,
 #endif
-       .ndo_setup_tc           = bnx2x_setup_tc,
+       .ndo_setup_tc           = __bnx2x_setup_tc,
 #ifdef CONFIG_BNX2X_SRIOV
        .ndo_set_vf_mac         = bnx2x_set_vf_mac,
        .ndo_set_vf_vlan        = bnx2x_set_vf_vlan,
@@ -13011,6 +13076,10 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_add_vxlan_port     = bnx2x_add_vxlan_port,
        .ndo_del_vxlan_port     = bnx2x_del_vxlan_port,
 #endif
+#if IS_ENABLED(CONFIG_BNX2X_GENEVE)
+       .ndo_add_geneve_port    = bnx2x_add_geneve_port,
+       .ndo_del_geneve_port    = bnx2x_del_geneve_port,
+#endif
 };
 
 static int bnx2x_set_coherency_mask(struct bnx2x *bp)
index 4dead49bd5cb0866ff89db2c5f2e149536b1ea3c..a43dea259b1290168c43f2713f51a2ba1c62652b 100644 (file)
@@ -7296,6 +7296,8 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_84823_CTL_LED_CTL_1                       0xa8e3
 #define MDIO_PMA_REG_84833_CTL_LED_CTL_1                       0xa8ec
 #define MDIO_PMA_REG_84823_LED3_STRETCH_EN                     0x0080
+/* BCM84858 only */
+#define MDIO_PMA_REG_84858_ALLOW_GPHY_ACT                      0x8000
 
 /* BCM84833 only */
 #define MDIO_84833_TOP_CFG_FW_REV                      0x400f
@@ -7337,6 +7339,10 @@ Theotherbitsarereservedandshouldbezero*/
 #define PHY84833_STATUS_CMD_NOT_OPEN_FOR_CMDS          0x0040
 #define PHY84833_STATUS_CMD_CLEAR_COMPLETE             0x0080
 #define PHY84833_STATUS_CMD_OPEN_OVERRIDE              0xa5a5
+/* Mailbox Process */
+#define PHY84833_MB_PROCESS1                           1
+#define PHY84833_MB_PROCESS2                           2
+#define PHY84833_MB_PROCESS3                           3
 
 /* Mailbox status set used by 84858 only */
 #define PHY84858_STATUS_CMD_RECEIVED                   0x0001
index 9d027348cd09b90fcca14843f13e278d54dd89e6..632daff117d305a822f95cc1bcd84b47437b2334 100644 (file)
@@ -1672,11 +1672,12 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
 {
        unsigned long ramrod_flags = 0;
        int rc = 0;
+       u32 echo = le32_to_cpu(elem->message.data.eth_event.echo);
 
        /* Always push next commands out, don't wait here */
        set_bit(RAMROD_CONT, &ramrod_flags);
 
-       switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) {
+       switch (echo >> BNX2X_SWCID_SHIFT) {
        case BNX2X_FILTER_MAC_PENDING:
                rc = vfq->mac_obj.complete(bp, &vfq->mac_obj, elem,
                                           &ramrod_flags);
@@ -1686,8 +1687,7 @@ void bnx2x_vf_handle_classification_eqe(struct bnx2x *bp,
                                            &ramrod_flags);
                break;
        default:
-               BNX2X_ERR("Unsupported classification command: %d\n",
-                         elem->message.data.eth_event.echo);
+               BNX2X_ERR("Unsupported classification command: 0x%x\n", echo);
                return;
        }
        if (rc < 0)
@@ -1747,16 +1747,14 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
 
        switch (opcode) {
        case EVENT_RING_OPCODE_CFC_DEL:
-               cid = SW_CID((__force __le32)
-                            elem->message.data.cfc_del_event.cid);
+               cid = SW_CID(elem->message.data.cfc_del_event.cid);
                DP(BNX2X_MSG_IOV, "checking cfc-del comp cid=%d\n", cid);
                break;
        case EVENT_RING_OPCODE_CLASSIFICATION_RULES:
        case EVENT_RING_OPCODE_MULTICAST_RULES:
        case EVENT_RING_OPCODE_FILTERS_RULES:
        case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
-               cid = (elem->message.data.eth_event.echo &
-                      BNX2X_SWCID_MASK);
+               cid = SW_CID(elem->message.data.eth_event.echo);
                DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
                break;
        case EVENT_RING_OPCODE_VF_FLR:
index 1374e5394a7970ba20ad54ddfc6271ce09e40744..bfae300cf25ff881292dc36ad56e51e37132cd76 100644 (file)
@@ -2187,8 +2187,10 @@ void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
 
        /* Update VFDB with current message and schedule its handling */
        mutex_lock(&BP_VFDB(bp)->event_mutex);
-       BP_VF_MBX(bp, vf_idx)->vf_addr_hi = vfpf_event->msg_addr_hi;
-       BP_VF_MBX(bp, vf_idx)->vf_addr_lo = vfpf_event->msg_addr_lo;
+       BP_VF_MBX(bp, vf_idx)->vf_addr_hi =
+               le32_to_cpu(vfpf_event->msg_addr_hi);
+       BP_VF_MBX(bp, vf_idx)->vf_addr_lo =
+               le32_to_cpu(vfpf_event->msg_addr_lo);
        BP_VFDB(bp)->event_occur |= (1ULL << vf_idx);
        mutex_unlock(&BP_VFDB(bp)->event_mutex);
 
index 5dc89e527e7deefe04c831d9ec556ed76ac40d26..aabbd51db981d270df258b1e0bf10a64488eb2b2 100644 (file)
@@ -69,7 +69,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
 #define BNXT_RX_DMA_OFFSET NET_SKB_PAD
 #define BNXT_RX_COPY_THRESH 256
 
-#define BNXT_TX_PUSH_THRESH 92
+#define BNXT_TX_PUSH_THRESH 164
 
 enum board_idx {
        BCM57301,
@@ -223,11 +223,12 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) {
-               struct tx_push_bd *push = txr->tx_push;
-               struct tx_bd *tx_push = &push->txbd1;
-               struct tx_bd_ext *tx_push1 = &push->txbd2;
-               void *pdata = tx_push1 + 1;
-               int j;
+               struct tx_push_buffer *tx_push_buf = txr->tx_push;
+               struct tx_push_bd *tx_push = &tx_push_buf->push_bd;
+               struct tx_bd_ext *tx_push1 = &tx_push->txbd2;
+               void *pdata = tx_push_buf->data;
+               u64 *end;
+               int j, push_len;
 
                /* Set COAL_NOW to be ready quickly for the next push */
                tx_push->tx_bd_len_flags_type =
@@ -247,6 +248,10 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
                tx_push1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);
                tx_push1->tx_bd_cfa_action = cpu_to_le32(cfa_action);
 
+               end = pdata + length;
+               end = PTR_ALIGN(end, 8) - 1;
+               *end = 0;
+
                skb_copy_from_linear_data(skb, pdata, len);
                pdata += len;
                for (j = 0; j < last_frag; j++) {
@@ -261,22 +266,29 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        pdata += skb_frag_size(frag);
                }
 
-               memcpy(txbd, tx_push, sizeof(*txbd));
+               txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type;
+               txbd->tx_bd_haddr = txr->data_mapping;
                prod = NEXT_TX(prod);
                txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
                memcpy(txbd, tx_push1, sizeof(*txbd));
                prod = NEXT_TX(prod);
-               push->doorbell =
+               tx_push->doorbell =
                        cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | prod);
                txr->tx_prod = prod;
 
                netdev_tx_sent_queue(txq, skb->len);
 
-               __iowrite64_copy(txr->tx_doorbell, push,
-                                (length + sizeof(*push) + 8) / 8);
+               push_len = (length + sizeof(*tx_push) + 7) / 8;
+               if (push_len > 16) {
+                       __iowrite64_copy(txr->tx_doorbell, tx_push_buf, 16);
+                       __iowrite64_copy(txr->tx_doorbell + 4, tx_push_buf + 1,
+                                        push_len - 16);
+               } else {
+                       __iowrite64_copy(txr->tx_doorbell, tx_push_buf,
+                                        push_len);
+               }
 
                tx_buf->is_push = 1;
-
                goto tx_done;
        }
 
@@ -1228,13 +1240,17 @@ static int bnxt_async_event_process(struct bnxt *bp,
        switch (event_id) {
        case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE:
                set_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event);
-               schedule_work(&bp->sp_task);
+               break;
+       case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD:
+               set_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event);
                break;
        default:
                netdev_err(bp->dev, "unhandled ASYNC event (id 0x%x)\n",
                           event_id);
-               break;
+               goto async_event_process_exit;
        }
+       schedule_work(&bp->sp_task);
+async_event_process_exit:
        return 0;
 }
 
@@ -1753,7 +1769,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
                push_size  = L1_CACHE_ALIGN(sizeof(struct tx_push_bd) +
                                        bp->tx_push_thresh);
 
-               if (push_size > 128) {
+               if (push_size > 256) {
                        push_size = 0;
                        bp->tx_push_thresh = 0;
                }
@@ -1772,7 +1788,6 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
                        return rc;
 
                if (bp->tx_push_size) {
-                       struct tx_bd *txbd;
                        dma_addr_t mapping;
 
                        /* One pre-allocated DMA buffer to backup
@@ -1786,13 +1801,11 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
                        if (!txr->tx_push)
                                return -ENOMEM;
 
-                       txbd = &txr->tx_push->txbd1;
-
                        mapping = txr->tx_push_mapping +
                                sizeof(struct tx_push_bd);
-                       txbd->tx_bd_haddr = cpu_to_le64(mapping);
+                       txr->data_mapping = cpu_to_le64(mapping);
 
-                       memset(txbd + 1, 0, sizeof(struct tx_bd_ext));
+                       memset(txr->tx_push, 0, sizeof(struct tx_push_bd));
                }
                ring->queue_id = bp->q_info[j].queue_id;
                if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1))
@@ -2349,6 +2362,14 @@ static void bnxt_free_stats(struct bnxt *bp)
        u32 size, i;
        struct pci_dev *pdev = bp->pdev;
 
+       if (bp->hw_rx_port_stats) {
+               dma_free_coherent(&pdev->dev, bp->hw_port_stats_size,
+                                 bp->hw_rx_port_stats,
+                                 bp->hw_rx_port_stats_map);
+               bp->hw_rx_port_stats = NULL;
+               bp->flags &= ~BNXT_FLAG_PORT_STATS;
+       }
+
        if (!bp->bnapi)
                return;
 
@@ -2385,6 +2406,24 @@ static int bnxt_alloc_stats(struct bnxt *bp)
 
                cpr->hw_stats_ctx_id = INVALID_STATS_CTX_ID;
        }
+
+       if (BNXT_PF(bp)) {
+               bp->hw_port_stats_size = sizeof(struct rx_port_stats) +
+                                        sizeof(struct tx_port_stats) + 1024;
+
+               bp->hw_rx_port_stats =
+                       dma_alloc_coherent(&pdev->dev, bp->hw_port_stats_size,
+                                          &bp->hw_rx_port_stats_map,
+                                          GFP_KERNEL);
+               if (!bp->hw_rx_port_stats)
+                       return -ENOMEM;
+
+               bp->hw_tx_port_stats = (void *)(bp->hw_rx_port_stats + 1) +
+                                      512;
+               bp->hw_tx_port_stats_map = bp->hw_rx_port_stats_map +
+                                          sizeof(struct rx_port_stats) + 512;
+               bp->flags |= BNXT_FLAG_PORT_STATS;
+       }
        return 0;
 }
 
@@ -2588,28 +2627,27 @@ alloc_mem_err:
 void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type,
                            u16 cmpl_ring, u16 target_id)
 {
-       struct hwrm_cmd_req_hdr *req = request;
+       struct input *req = request;
 
-       req->cmpl_ring_req_type =
-               cpu_to_le32(req_type | (cmpl_ring << HWRM_CMPL_RING_SFT));
-       req->target_id_seq_id = cpu_to_le32(target_id << HWRM_TARGET_FID_SFT);
+       req->req_type = cpu_to_le16(req_type);
+       req->cmpl_ring = cpu_to_le16(cmpl_ring);
+       req->target_id = cpu_to_le16(target_id);
        req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
 }
 
-int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
+static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
+                                int timeout, bool silent)
 {
        int i, intr_process, rc;
-       struct hwrm_cmd_req_hdr *req = msg;
+       struct input *req = msg;
        u32 *data = msg;
        __le32 *resp_len, *valid;
        u16 cp_ring_id, len = 0;
        struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
 
-       req->target_id_seq_id |= cpu_to_le32(bp->hwrm_cmd_seq++);
+       req->seq_id = cpu_to_le16(bp->hwrm_cmd_seq++);
        memset(resp, 0, PAGE_SIZE);
-       cp_ring_id = (le32_to_cpu(req->cmpl_ring_req_type) &
-                     HWRM_CMPL_RING_MASK) >>
-                    HWRM_CMPL_RING_SFT;
+       cp_ring_id = le16_to_cpu(req->cmpl_ring);
        intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
 
        /* Write request msg to hwrm channel */
@@ -2620,12 +2658,14 @@ int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 
        /* currently supports only one outstanding message */
        if (intr_process)
-               bp->hwrm_intr_seq_id = le32_to_cpu(req->target_id_seq_id) &
-                                      HWRM_SEQ_ID_MASK;
+               bp->hwrm_intr_seq_id = le16_to_cpu(req->seq_id);
 
        /* Ring channel doorbell */
        writel(1, bp->bar0 + 0x100);
 
+       if (!timeout)
+               timeout = DFLT_HWRM_CMD_TIMEOUT;
+
        i = 0;
        if (intr_process) {
                /* Wait until hwrm response cmpl interrupt is processed */
@@ -2636,7 +2676,7 @@ int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 
                if (bp->hwrm_intr_seq_id != HWRM_SEQ_ID_INVALID) {
                        netdev_err(bp->dev, "Resp cmpl intr err msg: 0x%x\n",
-                                  req->cmpl_ring_req_type);
+                                  le16_to_cpu(req->req_type));
                        return -1;
                }
        } else {
@@ -2652,8 +2692,8 @@ int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 
                if (i >= timeout) {
                        netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n",
-                                  timeout, req->cmpl_ring_req_type,
-                                  req->target_id_seq_id, *resp_len);
+                                  timeout, le16_to_cpu(req->req_type),
+                                  le16_to_cpu(req->seq_id), *resp_len);
                        return -1;
                }
 
@@ -2667,20 +2707,23 @@ int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
 
                if (i >= timeout) {
                        netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d v:%d\n",
-                                  timeout, req->cmpl_ring_req_type,
-                                  req->target_id_seq_id, len, *valid);
+                                  timeout, le16_to_cpu(req->req_type),
+                                  le16_to_cpu(req->seq_id), len, *valid);
                        return -1;
                }
        }
 
        rc = le16_to_cpu(resp->error_code);
-       if (rc) {
+       if (rc && !silent)
                netdev_err(bp->dev, "hwrm req_type 0x%x seq id 0x%x error 0x%x\n",
                           le16_to_cpu(resp->req_type),
                           le16_to_cpu(resp->seq_id), rc);
-               return rc;
-       }
-       return 0;
+       return rc;
+}
+
+int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
+{
+       return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, false);
 }
 
 int hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
@@ -2693,6 +2736,17 @@ int hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
        return rc;
 }
 
+int hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
+                            int timeout)
+{
+       int rc;
+
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       return rc;
+}
+
 static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
 {
        struct hwrm_func_drv_rgtr_input req = {0};
@@ -3509,47 +3563,82 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
        }
 }
 
+static void bnxt_hwrm_set_coal_params(struct bnxt *bp, u32 max_bufs,
+       u32 buf_tmrs, u16 flags,
+       struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
+{
+       req->flags = cpu_to_le16(flags);
+       req->num_cmpl_dma_aggr = cpu_to_le16((u16)max_bufs);
+       req->num_cmpl_dma_aggr_during_int = cpu_to_le16(max_bufs >> 16);
+       req->cmpl_aggr_dma_tmr = cpu_to_le16((u16)buf_tmrs);
+       req->cmpl_aggr_dma_tmr_during_int = cpu_to_le16(buf_tmrs >> 16);
+       /* Minimum time between 2 interrupts set to buf_tmr x 2 */
+       req->int_lat_tmr_min = cpu_to_le16((u16)buf_tmrs * 2);
+       req->int_lat_tmr_max = cpu_to_le16((u16)buf_tmrs * 4);
+       req->num_cmpl_aggr_int = cpu_to_le16((u16)max_bufs * 4);
+}
+
 int bnxt_hwrm_set_coal(struct bnxt *bp)
 {
        int i, rc = 0;
-       struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req = {0};
+       struct hwrm_ring_cmpl_ring_cfg_aggint_params_input req_rx = {0},
+                                                          req_tx = {0}, *req;
        u16 max_buf, max_buf_irq;
        u16 buf_tmr, buf_tmr_irq;
        u32 flags;
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS,
-                              -1, -1);
+       bnxt_hwrm_cmd_hdr_init(bp, &req_rx,
+                              HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1);
+       bnxt_hwrm_cmd_hdr_init(bp, &req_tx,
+                              HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS, -1, -1);
 
-       /* Each rx completion (2 records) should be DMAed immediately */
-       max_buf = min_t(u16, bp->coal_bufs / 4, 2);
+       /* Each rx completion (2 records) should be DMAed immediately.
+        * DMA 1/4 of the completion buffers at a time.
+        */
+       max_buf = min_t(u16, bp->rx_coal_bufs / 4, 2);
        /* max_buf must not be zero */
        max_buf = clamp_t(u16, max_buf, 1, 63);
-       max_buf_irq = clamp_t(u16, bp->coal_bufs_irq, 1, 63);
-       buf_tmr = max_t(u16, bp->coal_ticks / 4, 1);
-       buf_tmr_irq = max_t(u16, bp->coal_ticks_irq, 1);
+       max_buf_irq = clamp_t(u16, bp->rx_coal_bufs_irq, 1, 63);
+       buf_tmr = BNXT_USEC_TO_COAL_TIMER(bp->rx_coal_ticks);
+       /* buf timer set to 1/4 of interrupt timer */
+       buf_tmr = max_t(u16, buf_tmr / 4, 1);
+       buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(bp->rx_coal_ticks_irq);
+       buf_tmr_irq = max_t(u16, buf_tmr_irq, 1);
 
        flags = RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
 
        /* RING_IDLE generates more IRQs for lower latency.  Enable it only
         * if coal_ticks is less than 25 us.
         */
-       if (BNXT_COAL_TIMER_TO_USEC(bp->coal_ticks) < 25)
+       if (bp->rx_coal_ticks < 25)
                flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_RING_IDLE;
 
-       req.flags = cpu_to_le16(flags);
-       req.num_cmpl_dma_aggr = cpu_to_le16(max_buf);
-       req.num_cmpl_dma_aggr_during_int = cpu_to_le16(max_buf_irq);
-       req.cmpl_aggr_dma_tmr = cpu_to_le16(buf_tmr);
-       req.cmpl_aggr_dma_tmr_during_int = cpu_to_le16(buf_tmr_irq);
-       req.int_lat_tmr_min = cpu_to_le16(buf_tmr);
-       req.int_lat_tmr_max = cpu_to_le16(bp->coal_ticks);
-       req.num_cmpl_aggr_int = cpu_to_le16(bp->coal_bufs);
+       bnxt_hwrm_set_coal_params(bp, max_buf_irq << 16 | max_buf,
+                                 buf_tmr_irq << 16 | buf_tmr, flags, &req_rx);
+
+       /* max_buf must not be zero */
+       max_buf = clamp_t(u16, bp->tx_coal_bufs, 1, 63);
+       max_buf_irq = clamp_t(u16, bp->tx_coal_bufs_irq, 1, 63);
+       buf_tmr = BNXT_USEC_TO_COAL_TIMER(bp->tx_coal_ticks);
+       /* buf timer set to 1/4 of interrupt timer */
+       buf_tmr = max_t(u16, buf_tmr / 4, 1);
+       buf_tmr_irq = BNXT_USEC_TO_COAL_TIMER(bp->tx_coal_ticks_irq);
+       buf_tmr_irq = max_t(u16, buf_tmr_irq, 1);
+
+       flags = RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET;
+       bnxt_hwrm_set_coal_params(bp, max_buf_irq << 16 | max_buf,
+                                 buf_tmr_irq << 16 | buf_tmr, flags, &req_tx);
 
        mutex_lock(&bp->hwrm_cmd_lock);
        for (i = 0; i < bp->cp_nr_rings; i++) {
-               req.ring_id = cpu_to_le16(bp->grp_info[i].cp_fw_ring_id);
+               struct bnxt_napi *bnapi = bp->bnapi[i];
 
-               rc = _hwrm_send_message(bp, &req, sizeof(req),
+               req = &req_rx;
+               if (!bnapi->rx_ring)
+                       req = &req_tx;
+               req->ring_id = cpu_to_le16(bp->grp_info[i].cp_fw_ring_id);
+
+               rc = _hwrm_send_message(bp, req, sizeof(*req),
                                        HWRM_CMD_TIMEOUT);
                if (rc)
                        break;
@@ -3758,15 +3847,36 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp)
                            resp->hwrm_intf_upd);
                netdev_warn(bp->dev, "Please update firmware with HWRM interface 1.0.0 or newer.\n");
        }
-       snprintf(bp->fw_ver_str, BC_HWRM_STR_LEN, "bc %d.%d.%d rm %d.%d.%d",
+       snprintf(bp->fw_ver_str, BC_HWRM_STR_LEN, "%d.%d.%d/%d.%d.%d",
                 resp->hwrm_fw_maj, resp->hwrm_fw_min, resp->hwrm_fw_bld,
                 resp->hwrm_intf_maj, resp->hwrm_intf_min, resp->hwrm_intf_upd);
 
+       bp->hwrm_cmd_timeout = le16_to_cpu(resp->def_req_timeout);
+       if (!bp->hwrm_cmd_timeout)
+               bp->hwrm_cmd_timeout = DFLT_HWRM_CMD_TIMEOUT;
+
 hwrm_ver_get_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
        return rc;
 }
 
+static int bnxt_hwrm_port_qstats(struct bnxt *bp)
+{
+       int rc;
+       struct bnxt_pf_info *pf = &bp->pf;
+       struct hwrm_port_qstats_input req = {0};
+
+       if (!(bp->flags & BNXT_FLAG_PORT_STATS))
+               return 0;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_QSTATS, -1, -1);
+       req.port_id = cpu_to_le16(pf->port_id);
+       req.tx_stat_host_addr = cpu_to_le64(bp->hw_tx_port_stats_map);
+       req.rx_stat_host_addr = cpu_to_le64(bp->hw_rx_port_stats_map);
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       return rc;
+}
+
 static void bnxt_hwrm_free_tunnel_ports(struct bnxt *bp)
 {
        if (bp->vxlan_port_cnt) {
@@ -4401,6 +4511,7 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
        link_info->pause = resp->pause;
        link_info->auto_mode = resp->auto_mode;
        link_info->auto_pause_setting = resp->auto_pause;
+       link_info->lp_pause = resp->link_partner_adv_pause;
        link_info->force_pause_setting = resp->force_pause;
        link_info->duplex_setting = resp->duplex;
        if (link_info->phy_link_status == BNXT_LINK_LINK)
@@ -4411,6 +4522,8 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
        link_info->auto_link_speed = le16_to_cpu(resp->auto_link_speed);
        link_info->support_speeds = le16_to_cpu(resp->support_speeds);
        link_info->auto_link_speeds = le16_to_cpu(resp->auto_link_speed_mask);
+       link_info->lp_auto_link_speeds =
+               le16_to_cpu(resp->link_partner_adv_speeds);
        link_info->preemphasis = le32_to_cpu(resp->preemphasis);
        link_info->phy_ver[0] = resp->phy_maj;
        link_info->phy_ver[1] = resp->phy_min;
@@ -4546,20 +4659,18 @@ static int bnxt_update_phy_setting(struct bnxt *bp)
        if (!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) &&
            link_info->force_pause_setting != link_info->req_flow_ctrl)
                update_pause = true;
-       if (link_info->req_duplex != link_info->duplex_setting)
-               update_link = true;
        if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
                if (BNXT_AUTO_MODE(link_info->auto_mode))
                        update_link = true;
                if (link_info->req_link_speed != link_info->force_link_speed)
                        update_link = true;
+               if (link_info->req_duplex != link_info->duplex_setting)
+                       update_link = true;
        } else {
                if (link_info->auto_mode == BNXT_LINK_AUTO_NONE)
                        update_link = true;
                if (link_info->advertising != link_info->auto_link_speeds)
                        update_link = true;
-               if (link_info->req_link_speed != link_info->auto_link_speed)
-                       update_link = true;
        }
 
        if (update_link)
@@ -4636,7 +4747,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        if (link_re_init) {
                rc = bnxt_update_phy_setting(bp);
                if (rc)
-                       goto open_err;
+                       netdev_warn(bp->dev, "failed to update phy settings\n");
        }
 
        if (irq_re_init) {
@@ -4654,6 +4765,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
        /* Enable TX queues */
        bnxt_tx_enable(bp);
        mod_timer(&bp->timer, jiffies + bp->current_interval);
+       bnxt_update_link(bp, true);
 
        return 0;
 
@@ -4823,6 +4935,22 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                stats->tx_dropped += le64_to_cpu(hw_stats->tx_drop_pkts);
        }
 
+       if (bp->flags & BNXT_FLAG_PORT_STATS) {
+               struct rx_port_stats *rx = bp->hw_rx_port_stats;
+               struct tx_port_stats *tx = bp->hw_tx_port_stats;
+
+               stats->rx_crc_errors = le64_to_cpu(rx->rx_fcs_err_frames);
+               stats->rx_frame_errors = le64_to_cpu(rx->rx_align_err_frames);
+               stats->rx_length_errors = le64_to_cpu(rx->rx_undrsz_frames) +
+                                         le64_to_cpu(rx->rx_ovrsz_frames) +
+                                         le64_to_cpu(rx->rx_runt_frames);
+               stats->rx_errors = le64_to_cpu(rx->rx_false_carrier_frames) +
+                                  le64_to_cpu(rx->rx_jbr_frames);
+               stats->collisions = le64_to_cpu(tx->tx_total_collisions);
+               stats->tx_fifo_errors = le64_to_cpu(tx->tx_fifo_underruns);
+               stats->tx_errors = le64_to_cpu(tx->tx_err);
+       }
+
        return stats;
 }
 
@@ -5163,6 +5291,10 @@ static void bnxt_timer(unsigned long data)
        if (atomic_read(&bp->intr_sem) != 0)
                goto bnxt_restart_timer;
 
+       if (bp->link_info.link_up && (bp->flags & BNXT_FLAG_PORT_STATS)) {
+               set_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event);
+               schedule_work(&bp->sp_task);
+       }
 bnxt_restart_timer:
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 }
@@ -5214,6 +5346,9 @@ static void bnxt_sp_task(struct work_struct *work)
                rtnl_unlock();
        }
 
+       if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event))
+               bnxt_hwrm_port_qstats(bp);
+
        smp_mb__before_atomic();
        clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
 }
@@ -5277,6 +5412,8 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
                goto init_err_release;
        }
 
+       pci_enable_pcie_error_reporting(pdev);
+
        INIT_WORK(&bp->sp_task, bnxt_sp_task);
 
        spin_lock_init(&bp->ntp_fltr_lock);
@@ -5284,10 +5421,16 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->rx_ring_size = BNXT_DEFAULT_RX_RING_SIZE;
        bp->tx_ring_size = BNXT_DEFAULT_TX_RING_SIZE;
 
-       bp->coal_ticks = BNXT_USEC_TO_COAL_TIMER(4);
-       bp->coal_bufs = 20;
-       bp->coal_ticks_irq = BNXT_USEC_TO_COAL_TIMER(1);
-       bp->coal_bufs_irq = 2;
+       /* tick values in micro seconds */
+       bp->rx_coal_ticks = 12;
+       bp->rx_coal_bufs = 30;
+       bp->rx_coal_ticks_irq = 1;
+       bp->rx_coal_bufs_irq = 2;
+
+       bp->tx_coal_ticks = 25;
+       bp->tx_coal_bufs = 30;
+       bp->tx_coal_ticks_irq = 2;
+       bp->tx_coal_bufs_irq = 2;
 
        init_timer(&bp->timer);
        bp->timer.data = (unsigned long)bp;
@@ -5370,9 +5513,16 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static int bnxt_setup_tc(struct net_device *dev, u8 tc)
+static int bnxt_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                        struct tc_to_netdev *ntc)
 {
        struct bnxt *bp = netdev_priv(dev);
+       u8 tc;
+
+       if (ntc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       tc = ntc->tc;
 
        if (tc > bp->max_tc) {
                netdev_err(dev, "too many traffic classes requested: %d Max supported is %d\n",
@@ -5545,6 +5695,8 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
                        }
                }
        }
+       if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event))
+               netdev_info(bp->dev, "Receive PF driver unload event!");
 }
 
 #else
@@ -5641,6 +5793,7 @@ static void bnxt_remove_one(struct pci_dev *pdev)
        if (BNXT_PF(bp))
                bnxt_sriov_disable(bp);
 
+       pci_disable_pcie_error_reporting(pdev);
        unregister_netdev(dev);
        cancel_work_sync(&bp->sp_task);
        bp->sp_event = 0;
@@ -5660,7 +5813,6 @@ static int bnxt_probe_phy(struct bnxt *bp)
 {
        int rc = 0;
        struct bnxt_link_info *link_info = &bp->link_info;
-       char phy_ver[PHY_VER_STR_LEN];
 
        rc = bnxt_update_link(bp, false);
        if (rc) {
@@ -5670,27 +5822,16 @@ static int bnxt_probe_phy(struct bnxt *bp)
        }
 
        /*initialize the ethool setting copy with NVM settings */
-       if (BNXT_AUTO_MODE(link_info->auto_mode))
-               link_info->autoneg |= BNXT_AUTONEG_SPEED;
-
-       if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) {
-               if (link_info->auto_pause_setting == BNXT_LINK_PAUSE_BOTH)
-                       link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
+       if (BNXT_AUTO_MODE(link_info->auto_mode)) {
+               link_info->autoneg = BNXT_AUTONEG_SPEED |
+                                    BNXT_AUTONEG_FLOW_CTRL;
+               link_info->advertising = link_info->auto_link_speeds;
                link_info->req_flow_ctrl = link_info->auto_pause_setting;
-       } else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) {
+       } else {
+               link_info->req_link_speed = link_info->force_link_speed;
+               link_info->req_duplex = link_info->duplex_setting;
                link_info->req_flow_ctrl = link_info->force_pause_setting;
        }
-       link_info->req_duplex = link_info->duplex_setting;
-       if (link_info->autoneg & BNXT_AUTONEG_SPEED)
-               link_info->req_link_speed = link_info->auto_link_speed;
-       else
-               link_info->req_link_speed = link_info->force_link_speed;
-       link_info->advertising = link_info->auto_link_speeds;
-       snprintf(phy_ver, PHY_VER_STR_LEN, " ph %d.%d.%d",
-                link_info->phy_ver[0],
-                link_info->phy_ver[1],
-                link_info->phy_ver[2]);
-       strcat(bp->fw_ver_str, phy_ver);
        return rc;
 }
 
@@ -5892,11 +6033,117 @@ init_err_free:
        return rc;
 }
 
+/**
+ * bnxt_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
+                                              pci_channel_state_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+
+       netdev_info(netdev, "PCI I/O error detected\n");
+
+       rtnl_lock();
+       netif_device_detach(netdev);
+
+       if (state == pci_channel_io_perm_failure) {
+               rtnl_unlock();
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       if (netif_running(netdev))
+               bnxt_close(netdev);
+
+       pci_disable_device(pdev);
+       rtnl_unlock();
+
+       /* Request a slot slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * bnxt_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct bnxt *bp = netdev_priv(netdev);
+       int err = 0;
+       pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
+
+       netdev_info(bp->dev, "PCI Slot Reset\n");
+
+       rtnl_lock();
+
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
+       } else {
+               pci_set_master(pdev);
+
+               if (netif_running(netdev))
+                       err = bnxt_open(netdev);
+
+               if (!err)
+                       result = PCI_ERS_RESULT_RECOVERED;
+       }
+
+       if (result != PCI_ERS_RESULT_RECOVERED && netif_running(netdev))
+               dev_close(netdev);
+
+       rtnl_unlock();
+
+       err = pci_cleanup_aer_uncorrect_error_status(pdev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+                        err); /* non-fatal, continue */
+       }
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * bnxt_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void bnxt_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+
+       rtnl_lock();
+
+       netif_device_attach(netdev);
+
+       rtnl_unlock();
+}
+
+static const struct pci_error_handlers bnxt_err_handler = {
+       .error_detected = bnxt_io_error_detected,
+       .slot_reset     = bnxt_io_slot_reset,
+       .resume         = bnxt_io_resume
+};
+
 static struct pci_driver bnxt_pci_driver = {
        .name           = DRV_MODULE_NAME,
        .id_table       = bnxt_pci_tbl,
        .probe          = bnxt_init_one,
        .remove         = bnxt_remove_one,
+       .err_handler    = &bnxt_err_handler,
 #if defined(CONFIG_BNXT_SRIOV)
        .sriov_configure = bnxt_sriov_configure,
 #endif
index 8af3ca8efcef9ac275f2daac4e44a06d108eed61..ec04c47172b7f33e338a000d07140892f6c72cb5 100644 (file)
@@ -411,8 +411,8 @@ struct rx_tpa_end_cmp_ext {
 
 #define BNXT_NUM_TESTS(bp)     0
 
-#define BNXT_DEFAULT_RX_RING_SIZE      1023
-#define BNXT_DEFAULT_TX_RING_SIZE      512
+#define BNXT_DEFAULT_RX_RING_SIZE      511
+#define BNXT_DEFAULT_TX_RING_SIZE      511
 
 #define MAX_TPA                64
 
@@ -477,12 +477,15 @@ struct rx_tpa_end_cmp_ext {
 #define RING_CMP(idx)          ((idx) & bp->cp_ring_mask)
 #define NEXT_CMP(idx)          RING_CMP(ADV_RAW_CMP(idx, 1))
 
-#define HWRM_CMD_TIMEOUT               500
+#define DFLT_HWRM_CMD_TIMEOUT          500
+#define HWRM_CMD_TIMEOUT               (bp->hwrm_cmd_timeout)
 #define HWRM_RESET_TIMEOUT             ((HWRM_CMD_TIMEOUT) * 4)
 #define HWRM_RESP_ERR_CODE_MASK                0xffff
+#define HWRM_RESP_LEN_OFFSET           4
 #define HWRM_RESP_LEN_MASK             0xffff0000
 #define HWRM_RESP_LEN_SFT              16
 #define HWRM_RESP_VALID_MASK           0xff000000
+#define HWRM_SEQ_ID_INVALID            -1
 #define BNXT_HWRM_REQ_MAX_SIZE         128
 #define BNXT_HWRM_REQS_PER_PAGE                (BNXT_PAGE_SIZE /       \
                                         BNXT_HWRM_REQ_MAX_SIZE)
@@ -523,10 +526,16 @@ struct bnxt_ring_struct {
 
 struct tx_push_bd {
        __le32                  doorbell;
-       struct tx_bd            txbd1;
+       __le32                  tx_bd_len_flags_type;
+       u32                     tx_bd_opaque;
        struct tx_bd_ext        txbd2;
 };
 
+struct tx_push_buffer {
+       struct tx_push_bd       push_bd;
+       u32                     data[25];
+};
+
 struct bnxt_tx_ring_info {
        struct bnxt_napi        *bnapi;
        u16                     tx_prod;
@@ -538,8 +547,9 @@ struct bnxt_tx_ring_info {
 
        dma_addr_t              tx_desc_mapping[MAX_TX_PAGES];
 
-       struct tx_push_bd       *tx_push;
+       struct tx_push_buffer   *tx_push;
        dma_addr_t              tx_push_mapping;
+       __le64                  data_mapping;
 
 #define BNXT_DEV_STATE_CLOSING 0x1
        u32                     dev_state;
@@ -637,19 +647,6 @@ struct bnxt_irq {
 
 #define INVALID_STATS_CTX_ID   -1
 
-struct hwrm_cmd_req_hdr {
-#define HWRM_CMPL_RING_MASK    0xffff0000
-#define HWRM_CMPL_RING_SFT     16
-       __le32  cmpl_ring_req_type;
-#define HWRM_SEQ_ID_MASK       0xffff
-#define HWRM_SEQ_ID_INVALID -1
-#define HWRM_RESP_LEN_OFFSET   4
-#define HWRM_TARGET_FID_MASK   0xffff0000
-#define HWRM_TARGET_FID_SFT    16
-       __le32  target_id_seq_id;
-       __le64  resp_addr;
-};
-
 struct bnxt_ring_grp_info {
        u16     fw_stats_ctx;
        u16     fw_grp_id;
@@ -760,10 +757,6 @@ struct bnxt_ntuple_filter {
 #define BNXT_FLTR_UPDATE       1
 };
 
-#define BNXT_ALL_COPPER_ETHTOOL_SPEED                          \
-       (ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full | \
-        ADVERTISED_10000baseT_Full)
-
 struct bnxt_link_info {
        u8                      media_type;
        u8                      transceiver;
@@ -783,6 +776,7 @@ struct bnxt_link_info {
 #define BNXT_LINK_PAUSE_RX     PORT_PHY_QCFG_RESP_PAUSE_RX
 #define BNXT_LINK_PAUSE_BOTH   (PORT_PHY_QCFG_RESP_PAUSE_RX | \
                                 PORT_PHY_QCFG_RESP_PAUSE_TX)
+       u8                      lp_pause;
        u8                      auto_pause_setting;
        u8                      force_pause_setting;
        u8                      duplex_setting;
@@ -817,6 +811,7 @@ struct bnxt_link_info {
 #define BNXT_LINK_SPEED_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_25GB
 #define BNXT_LINK_SPEED_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_40GB
 #define BNXT_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB
+       u16                     lp_auto_link_speeds;
        u16                     auto_link_speed;
        u16                     force_link_speed;
        u32                     preemphasis;
@@ -878,6 +873,7 @@ struct bnxt {
        #define BNXT_FLAG_MSIX_CAP      0x80
        #define BNXT_FLAG_RFS           0x100
        #define BNXT_FLAG_SHARED_RINGS  0x200
+       #define BNXT_FLAG_PORT_STATS    0x400
 
        #define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA |             \
                                            BNXT_FLAG_RFS |             \
@@ -930,7 +926,7 @@ struct bnxt {
        struct bnxt_queue_info  q_info[BNXT_MAX_QUEUE];
 
        unsigned int            current_interval;
-#define BNXT_TIMER_INTERVAL    (HZ / 2)
+#define BNXT_TIMER_INTERVAL    HZ
 
        struct timer_list       timer;
 
@@ -950,6 +946,14 @@ struct bnxt {
        void                    *hwrm_dbg_resp_addr;
        dma_addr_t              hwrm_dbg_resp_dma_addr;
 #define HWRM_DBG_REG_BUF_SIZE  128
+
+       struct rx_port_stats    *hw_rx_port_stats;
+       struct tx_port_stats    *hw_tx_port_stats;
+       dma_addr_t              hw_rx_port_stats_map;
+       dma_addr_t              hw_tx_port_stats_map;
+       int                     hw_port_stats_size;
+
+       int                     hwrm_cmd_timeout;
        struct mutex            hwrm_cmd_lock;  /* serialize hwrm messages */
        struct hwrm_ver_get_output      ver_resp;
 #define FW_VER_STR_LEN         32
@@ -961,13 +965,17 @@ struct bnxt {
        __le16                  vxlan_fw_dst_port_id;
        u8                      nge_port_cnt;
        __le16                  nge_fw_dst_port_id;
-       u16                     coal_ticks;
-       u16                     coal_ticks_irq;
-       u16                     coal_bufs;
-       u16                     coal_bufs_irq;
+
+       u16                     rx_coal_ticks;
+       u16                     rx_coal_ticks_irq;
+       u16                     rx_coal_bufs;
+       u16                     rx_coal_bufs_irq;
+       u16                     tx_coal_ticks;
+       u16                     tx_coal_ticks_irq;
+       u16                     tx_coal_bufs;
+       u16                     tx_coal_bufs_irq;
 
 #define BNXT_USEC_TO_COAL_TIMER(x)     ((x) * 25 / 2)
-#define BNXT_COAL_TIMER_TO_USEC(x) ((x) * 2 / 25)
 
        struct work_struct      sp_task;
        unsigned long           sp_event;
@@ -979,6 +987,8 @@ struct bnxt {
 #define BNXT_VXLAN_DEL_PORT_SP_EVENT   5
 #define BNXT_RESET_TASK_SP_EVENT       6
 #define BNXT_RST_RING_SP_EVENT         7
+#define BNXT_HWRM_PF_UNLOAD_SP_EVENT   8
+#define BNXT_PERIODIC_STATS_SP_EVENT   9
 
        struct bnxt_pf_info     pf;
 #ifdef CONFIG_BNXT_SRIOV
@@ -1092,6 +1102,7 @@ void bnxt_set_ring_params(struct bnxt *);
 void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
 int _hwrm_send_message(struct bnxt *, void *, u32, int);
 int hwrm_send_message(struct bnxt *, void *, u32, int);
+int hwrm_send_message_silent(struct bnxt *, void *, u32, int);
 int bnxt_hwrm_set_coal(struct bnxt *);
 int bnxt_hwrm_func_qcaps(struct bnxt *);
 int bnxt_hwrm_set_pause(struct bnxt *);
index 922b898e7a320e39da102a27818a68c84af08e79..9ada1662b65149c81617181772f406a4716042c1 100644 (file)
@@ -7,6 +7,8 @@
  * the Free Software Foundation.
  */
 
+#include <linux/ctype.h>
+#include <linux/stringify.h>
 #include <linux/ethtool.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
@@ -20,6 +22,8 @@
 #include "bnxt_fw_hdr.h"       /* Firmware hdr constant and structure defs */
 #define FLASH_NVRAM_TIMEOUT    ((HWRM_CMD_TIMEOUT) * 100)
 
+static char *bnxt_get_pkgver(struct net_device *dev, char *buf, size_t buflen);
+
 static u32 bnxt_get_msglevel(struct net_device *dev)
 {
        struct bnxt *bp = netdev_priv(dev);
@@ -41,12 +45,16 @@ static int bnxt_get_coalesce(struct net_device *dev,
 
        memset(coal, 0, sizeof(*coal));
 
-       coal->rx_coalesce_usecs =
-               max_t(u16, BNXT_COAL_TIMER_TO_USEC(bp->coal_ticks), 1);
-       coal->rx_max_coalesced_frames = bp->coal_bufs / 2;
-       coal->rx_coalesce_usecs_irq =
-               max_t(u16, BNXT_COAL_TIMER_TO_USEC(bp->coal_ticks_irq), 1);
-       coal->rx_max_coalesced_frames_irq = bp->coal_bufs_irq / 2;
+       coal->rx_coalesce_usecs = bp->rx_coal_ticks;
+       /* 2 completion records per rx packet */
+       coal->rx_max_coalesced_frames = bp->rx_coal_bufs / 2;
+       coal->rx_coalesce_usecs_irq = bp->rx_coal_ticks_irq;
+       coal->rx_max_coalesced_frames_irq = bp->rx_coal_bufs_irq / 2;
+
+       coal->tx_coalesce_usecs = bp->tx_coal_ticks;
+       coal->tx_max_coalesced_frames = bp->tx_coal_bufs;
+       coal->tx_coalesce_usecs_irq = bp->tx_coal_ticks_irq;
+       coal->tx_max_coalesced_frames_irq = bp->tx_coal_bufs_irq;
 
        return 0;
 }
@@ -57,11 +65,16 @@ static int bnxt_set_coalesce(struct net_device *dev,
        struct bnxt *bp = netdev_priv(dev);
        int rc = 0;
 
-       bp->coal_ticks = BNXT_USEC_TO_COAL_TIMER(coal->rx_coalesce_usecs);
-       bp->coal_bufs = coal->rx_max_coalesced_frames * 2;
-       bp->coal_ticks_irq =
-               BNXT_USEC_TO_COAL_TIMER(coal->rx_coalesce_usecs_irq);
-       bp->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * 2;
+       bp->rx_coal_ticks = coal->rx_coalesce_usecs;
+       /* 2 completion records per rx packet */
+       bp->rx_coal_bufs = coal->rx_max_coalesced_frames * 2;
+       bp->rx_coal_ticks_irq = coal->rx_coalesce_usecs_irq;
+       bp->rx_coal_bufs_irq = coal->rx_max_coalesced_frames_irq * 2;
+
+       bp->tx_coal_ticks = coal->tx_coalesce_usecs;
+       bp->tx_coal_bufs = coal->tx_max_coalesced_frames;
+       bp->tx_coal_ticks_irq = coal->tx_coalesce_usecs_irq;
+       bp->tx_coal_bufs_irq = coal->tx_max_coalesced_frames_irq;
 
        if (netif_running(dev))
                rc = bnxt_hwrm_set_coal(bp);
@@ -71,13 +84,99 @@ static int bnxt_set_coalesce(struct net_device *dev,
 
 #define BNXT_NUM_STATS 21
 
+#define BNXT_RX_STATS_OFFSET(counter)  \
+       (offsetof(struct rx_port_stats, counter) / 8)
+
+#define BNXT_RX_STATS_ENTRY(counter)   \
+       { BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
+
+#define BNXT_TX_STATS_OFFSET(counter)                  \
+       ((offsetof(struct tx_port_stats, counter) +     \
+         sizeof(struct rx_port_stats) + 512) / 8)
+
+#define BNXT_TX_STATS_ENTRY(counter)   \
+       { BNXT_TX_STATS_OFFSET(counter), __stringify(counter) }
+
+static const struct {
+       long offset;
+       char string[ETH_GSTRING_LEN];
+} bnxt_port_stats_arr[] = {
+       BNXT_RX_STATS_ENTRY(rx_64b_frames),
+       BNXT_RX_STATS_ENTRY(rx_65b_127b_frames),
+       BNXT_RX_STATS_ENTRY(rx_128b_255b_frames),
+       BNXT_RX_STATS_ENTRY(rx_256b_511b_frames),
+       BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames),
+       BNXT_RX_STATS_ENTRY(rx_1024b_1518_frames),
+       BNXT_RX_STATS_ENTRY(rx_good_vlan_frames),
+       BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames),
+       BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames),
+       BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames),
+       BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames),
+       BNXT_RX_STATS_ENTRY(rx_total_frames),
+       BNXT_RX_STATS_ENTRY(rx_ucast_frames),
+       BNXT_RX_STATS_ENTRY(rx_mcast_frames),
+       BNXT_RX_STATS_ENTRY(rx_bcast_frames),
+       BNXT_RX_STATS_ENTRY(rx_fcs_err_frames),
+       BNXT_RX_STATS_ENTRY(rx_ctrl_frames),
+       BNXT_RX_STATS_ENTRY(rx_pause_frames),
+       BNXT_RX_STATS_ENTRY(rx_pfc_frames),
+       BNXT_RX_STATS_ENTRY(rx_align_err_frames),
+       BNXT_RX_STATS_ENTRY(rx_ovrsz_frames),
+       BNXT_RX_STATS_ENTRY(rx_jbr_frames),
+       BNXT_RX_STATS_ENTRY(rx_mtu_err_frames),
+       BNXT_RX_STATS_ENTRY(rx_tagged_frames),
+       BNXT_RX_STATS_ENTRY(rx_double_tagged_frames),
+       BNXT_RX_STATS_ENTRY(rx_good_frames),
+       BNXT_RX_STATS_ENTRY(rx_undrsz_frames),
+       BNXT_RX_STATS_ENTRY(rx_eee_lpi_events),
+       BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration),
+       BNXT_RX_STATS_ENTRY(rx_bytes),
+       BNXT_RX_STATS_ENTRY(rx_runt_bytes),
+       BNXT_RX_STATS_ENTRY(rx_runt_frames),
+
+       BNXT_TX_STATS_ENTRY(tx_64b_frames),
+       BNXT_TX_STATS_ENTRY(tx_65b_127b_frames),
+       BNXT_TX_STATS_ENTRY(tx_128b_255b_frames),
+       BNXT_TX_STATS_ENTRY(tx_256b_511b_frames),
+       BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames),
+       BNXT_TX_STATS_ENTRY(tx_1024b_1518_frames),
+       BNXT_TX_STATS_ENTRY(tx_good_vlan_frames),
+       BNXT_TX_STATS_ENTRY(tx_1519b_2047_frames),
+       BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames),
+       BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames),
+       BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames),
+       BNXT_TX_STATS_ENTRY(tx_good_frames),
+       BNXT_TX_STATS_ENTRY(tx_total_frames),
+       BNXT_TX_STATS_ENTRY(tx_ucast_frames),
+       BNXT_TX_STATS_ENTRY(tx_mcast_frames),
+       BNXT_TX_STATS_ENTRY(tx_bcast_frames),
+       BNXT_TX_STATS_ENTRY(tx_pause_frames),
+       BNXT_TX_STATS_ENTRY(tx_pfc_frames),
+       BNXT_TX_STATS_ENTRY(tx_jabber_frames),
+       BNXT_TX_STATS_ENTRY(tx_fcs_err_frames),
+       BNXT_TX_STATS_ENTRY(tx_err),
+       BNXT_TX_STATS_ENTRY(tx_fifo_underruns),
+       BNXT_TX_STATS_ENTRY(tx_eee_lpi_events),
+       BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration),
+       BNXT_TX_STATS_ENTRY(tx_total_collisions),
+       BNXT_TX_STATS_ENTRY(tx_bytes),
+};
+
+#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
+
 static int bnxt_get_sset_count(struct net_device *dev, int sset)
 {
        struct bnxt *bp = netdev_priv(dev);
 
        switch (sset) {
-       case ETH_SS_STATS:
-               return BNXT_NUM_STATS * bp->cp_nr_rings;
+       case ETH_SS_STATS: {
+               int num_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
+
+               if (bp->flags & BNXT_FLAG_PORT_STATS)
+                       num_stats += BNXT_NUM_PORT_STATS;
+
+               return num_stats;
+       }
        default:
                return -EOPNOTSUPP;
        }
@@ -106,6 +205,14 @@ static void bnxt_get_ethtool_stats(struct net_device *dev,
                        buf[j] = le64_to_cpu(hw_stats[k]);
                buf[j++] = cpr->rx_l4_csum_errors;
        }
+       if (bp->flags & BNXT_FLAG_PORT_STATS) {
+               __le64 *port_stats = (__le64 *)bp->hw_rx_port_stats;
+
+               for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) {
+                       buf[j] = le64_to_cpu(*(port_stats +
+                                              bnxt_port_stats_arr[i].offset));
+               }
+       }
 }
 
 static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -160,6 +267,12 @@ static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
                        sprintf(buf, "[%d]: rx_l4_csum_errors", i);
                        buf += ETH_GSTRING_LEN;
                }
+               if (bp->flags & BNXT_FLAG_PORT_STATS) {
+                       for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
+                               strcpy(buf, bnxt_port_stats_arr[i].string);
+                               buf += ETH_GSTRING_LEN;
+                       }
+               }
                break;
        default:
                netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
@@ -460,10 +573,20 @@ static void bnxt_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
        struct bnxt *bp = netdev_priv(dev);
+       char *pkglog;
+       char *pkgver = NULL;
 
+       pkglog = kmalloc(BNX_PKG_LOG_MAX_LENGTH, GFP_KERNEL);
+       if (pkglog)
+               pkgver = bnxt_get_pkgver(dev, pkglog, BNX_PKG_LOG_MAX_LENGTH);
        strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
-       strlcpy(info->fw_version, bp->fw_ver_str, sizeof(info->fw_version));
+       if (pkgver && *pkgver != 0 && isdigit(*pkgver))
+               snprintf(info->fw_version, sizeof(info->fw_version) - 1,
+                        "%s pkg %s", bp->fw_ver_str, pkgver);
+       else
+               strlcpy(info->fw_version, bp->fw_ver_str,
+                       sizeof(info->fw_version));
        strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
        info->n_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
        info->testinfo_len = BNXT_NUM_TESTS(bp);
@@ -471,30 +594,32 @@ static void bnxt_get_drvinfo(struct net_device *dev,
        info->eedump_len = 0;
        /* TODO CHIMP FW: reg dump details */
        info->regdump_len = 0;
+       kfree(pkglog);
 }
 
-static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
+static u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
 {
-       u16 fw_speeds = link_info->support_speeds;
        u32 speed_mask = 0;
 
+       /* TODO: support 25GB, 40GB, 50GB with different cable type */
+       /* set the advertised speeds */
        if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
-               speed_mask |= SUPPORTED_100baseT_Full;
+               speed_mask |= ADVERTISED_100baseT_Full;
        if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
-               speed_mask |= SUPPORTED_1000baseT_Full;
+               speed_mask |= ADVERTISED_1000baseT_Full;
        if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
-               speed_mask |= SUPPORTED_2500baseX_Full;
+               speed_mask |= ADVERTISED_2500baseX_Full;
        if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
-               speed_mask |= SUPPORTED_10000baseT_Full;
-       /* TODO: support 25GB, 50GB with different cable type */
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
-               speed_mask |= SUPPORTED_20000baseMLD2_Full |
-                       SUPPORTED_20000baseKR2_Full;
+               speed_mask |= ADVERTISED_10000baseT_Full;
        if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
-               speed_mask |= SUPPORTED_40000baseKR4_Full |
-                       SUPPORTED_40000baseCR4_Full |
-                       SUPPORTED_40000baseSR4_Full |
-                       SUPPORTED_40000baseLR4_Full;
+               speed_mask |= ADVERTISED_40000baseCR4_Full;
+
+       if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH)
+               speed_mask |= ADVERTISED_Pause;
+       else if (fw_pause & BNXT_LINK_PAUSE_TX)
+               speed_mask |= ADVERTISED_Asym_Pause;
+       else if (fw_pause & BNXT_LINK_PAUSE_RX)
+               speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
 
        return speed_mask;
 }
@@ -502,28 +627,32 @@ static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
 static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
 {
        u16 fw_speeds = link_info->auto_link_speeds;
-       u32 speed_mask = 0;
+       u8 fw_pause = 0;
 
-       /* TODO: support 25GB, 40GB, 50GB with different cable type */
-       /* set the advertised speeds */
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
-               speed_mask |= ADVERTISED_100baseT_Full;
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
-               speed_mask |= ADVERTISED_1000baseT_Full;
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
-               speed_mask |= ADVERTISED_2500baseX_Full;
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
-               speed_mask |= ADVERTISED_10000baseT_Full;
-       /* TODO: how to advertise 20, 25, 40, 50GB with different cable type ?*/
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_20GB)
-               speed_mask |= ADVERTISED_20000baseMLD2_Full |
-                             ADVERTISED_20000baseKR2_Full;
-       if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
-               speed_mask |= ADVERTISED_40000baseKR4_Full |
-                             ADVERTISED_40000baseCR4_Full |
-                             ADVERTISED_40000baseSR4_Full |
-                             ADVERTISED_40000baseLR4_Full;
-       return speed_mask;
+       if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
+               fw_pause = link_info->auto_pause_setting;
+
+       return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
+}
+
+static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info)
+{
+       u16 fw_speeds = link_info->lp_auto_link_speeds;
+       u8 fw_pause = 0;
+
+       if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
+               fw_pause = link_info->lp_pause;
+
+       return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
+}
+
+static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
+{
+       u16 fw_speeds = link_info->support_speeds;
+       u32 supported;
+
+       supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
+       return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
 }
 
 u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
@@ -561,38 +690,18 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (link_info->auto_link_speeds)
                cmd->supported |= SUPPORTED_Autoneg;
 
-       if (BNXT_AUTO_MODE(link_info->auto_mode)) {
+       if (link_info->autoneg) {
                cmd->advertising =
                        bnxt_fw_to_ethtool_advertised_spds(link_info);
                cmd->advertising |= ADVERTISED_Autoneg;
                cmd->autoneg = AUTONEG_ENABLE;
+               if (link_info->phy_link_status == BNXT_LINK_LINK)
+                       cmd->lp_advertising =
+                               bnxt_fw_to_ethtool_lp_adv(link_info);
        } else {
                cmd->autoneg = AUTONEG_DISABLE;
                cmd->advertising = 0;
        }
-       if (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) {
-               if ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
-                   BNXT_LINK_PAUSE_BOTH) {
-                       cmd->advertising |= ADVERTISED_Pause;
-                       cmd->supported |= SUPPORTED_Pause;
-               } else {
-                       cmd->advertising |= ADVERTISED_Asym_Pause;
-                       cmd->supported |= SUPPORTED_Asym_Pause;
-                       if (link_info->auto_pause_setting &
-                           BNXT_LINK_PAUSE_RX)
-                               cmd->advertising |= ADVERTISED_Pause;
-               }
-       } else if (link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) {
-               if ((link_info->force_pause_setting & BNXT_LINK_PAUSE_BOTH) ==
-                   BNXT_LINK_PAUSE_BOTH) {
-                       cmd->supported |= SUPPORTED_Pause;
-               } else {
-                       cmd->supported |= SUPPORTED_Asym_Pause;
-                       if (link_info->force_pause_setting &
-                           BNXT_LINK_PAUSE_RX)
-                               cmd->supported |= SUPPORTED_Pause;
-               }
-       }
 
        cmd->port = PORT_NONE;
        if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
@@ -670,6 +779,9 @@ static u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
        if (advertising & ADVERTISED_10000baseT_Full)
                fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
 
+       if (advertising & ADVERTISED_40000baseCR4_Full)
+               fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB;
+
        return fw_speed_mask;
 }
 
@@ -685,16 +797,10 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                return rc;
 
        if (cmd->autoneg == AUTONEG_ENABLE) {
-               if (link_info->media_type != PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
-                       netdev_err(dev, "Media type doesn't support autoneg\n");
-                       rc = -EINVAL;
-                       goto set_setting_exit;
-               }
-               if (cmd->advertising & ~(BNXT_ALL_COPPER_ETHTOOL_SPEED |
-                                        ADVERTISED_Autoneg |
-                                        ADVERTISED_TP |
-                                        ADVERTISED_Pause |
-                                        ADVERTISED_Asym_Pause)) {
+               u32 supported_spds = bnxt_fw_to_ethtool_support_spds(link_info);
+
+               if (cmd->advertising & ~(supported_spds | ADVERTISED_Autoneg |
+                                        ADVERTISED_TP | ADVERTISED_FIBRE)) {
                        netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n",
                                   cmd->advertising);
                        rc = -EINVAL;
@@ -729,7 +835,7 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                speed = ethtool_cmd_speed(cmd);
                link_info->req_link_speed = bnxt_get_fw_speed(dev, speed);
                link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
-               link_info->autoneg &= ~BNXT_AUTONEG_SPEED;
+               link_info->autoneg = 0;
                link_info->advertising = 0;
        }
 
@@ -748,10 +854,11 @@ static void bnxt_get_pauseparam(struct net_device *dev,
 
        if (BNXT_VF(bp))
                return;
-       epause->autoneg = !!(link_info->auto_pause_setting &
-                            BNXT_LINK_PAUSE_BOTH);
-       epause->rx_pause = ((link_info->pause & BNXT_LINK_PAUSE_RX) != 0);
-       epause->tx_pause = ((link_info->pause & BNXT_LINK_PAUSE_TX) != 0);
+       epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);
+       epause->rx_pause =
+               ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_RX) != 0);
+       epause->tx_pause =
+               ((link_info->auto_pause_setting & BNXT_LINK_PAUSE_TX) != 0);
 }
 
 static int bnxt_set_pauseparam(struct net_device *dev,
@@ -765,6 +872,9 @@ static int bnxt_set_pauseparam(struct net_device *dev,
                return rc;
 
        if (epause->autoneg) {
+               if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
+                       return -EINVAL;
+
                link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
                link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_BOTH;
        } else {
@@ -1122,6 +1232,85 @@ static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset,
        return rc;
 }
 
+static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
+                               u16 ext, u16 *index, u32 *item_length,
+                               u32 *data_length)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       int rc;
+       struct hwrm_nvm_find_dir_entry_input req = {0};
+       struct hwrm_nvm_find_dir_entry_output *output = bp->hwrm_cmd_resp_addr;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_FIND_DIR_ENTRY, -1, -1);
+       req.enables = 0;
+       req.dir_idx = 0;
+       req.dir_type = cpu_to_le16(type);
+       req.dir_ordinal = cpu_to_le16(ordinal);
+       req.dir_ext = cpu_to_le16(ext);
+       req.opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ;
+       rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc == 0) {
+               if (index)
+                       *index = le16_to_cpu(output->dir_idx);
+               if (item_length)
+                       *item_length = le32_to_cpu(output->dir_item_length);
+               if (data_length)
+                       *data_length = le32_to_cpu(output->dir_data_length);
+       }
+       return rc;
+}
+
+static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen)
+{
+       char    *retval = NULL;
+       char    *p;
+       char    *value;
+       int     field = 0;
+
+       if (datalen < 1)
+               return NULL;
+       /* null-terminate the log data (removing last '\n'): */
+       data[datalen - 1] = 0;
+       for (p = data; *p != 0; p++) {
+               field = 0;
+               retval = NULL;
+               while (*p != 0 && *p != '\n') {
+                       value = p;
+                       while (*p != 0 && *p != '\t' && *p != '\n')
+                               p++;
+                       if (field == desired_field)
+                               retval = value;
+                       if (*p != '\t')
+                               break;
+                       *p = 0;
+                       field++;
+                       p++;
+               }
+               if (*p == 0)
+                       break;
+               *p = 0;
+       }
+       return retval;
+}
+
+static char *bnxt_get_pkgver(struct net_device *dev, char *buf, size_t buflen)
+{
+       u16 index = 0;
+       u32 datalen;
+
+       if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG,
+                                BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
+                                &index, NULL, &datalen) != 0)
+               return NULL;
+
+       memset(buf, 0, buflen);
+       if (bnxt_get_nvram_item(dev, index, 0, datalen, buf) != 0)
+               return NULL;
+
+       return bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, buf,
+               datalen);
+}
+
 static int bnxt_get_eeprom(struct net_device *dev,
                           struct ethtool_eeprom *eeprom,
                           u8 *data)
index 3cf3e1b70b64711d1d51c351f1b77c4aeaac43bc..43ef392c858841ac2e806cf3b7b711b3a5a28b81 100644 (file)
@@ -50,10 +50,24 @@ enum bnxt_nvm_directory_type {
 
 #define BNX_DIR_ORDINAL_FIRST                  0
 
+#define BNX_DIR_EXT_NONE                       0
 #define BNX_DIR_EXT_INACTIVE                   (1 << 0)
 #define BNX_DIR_EXT_UPDATE                     (1 << 1)
 
+#define BNX_DIR_ATTR_NONE                      0
 #define BNX_DIR_ATTR_NO_CHKSUM                 (1 << 0)
 #define BNX_DIR_ATTR_PROP_STREAM               (1 << 1)
 
+#define BNX_PKG_LOG_MAX_LENGTH                 4096
+
+enum bnxnvm_pkglog_field_index {
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP       = 0,
+       BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION           = 1,
+       BNX_PKG_LOG_FIELD_IDX_PKG_VERSION               = 2,
+       BNX_PKG_LOG_FIELD_IDX_PKG_TIMESTAMP             = 3,
+       BNX_PKG_LOG_FIELD_IDX_PKG_CHECKSUM              = 4,
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_ITEMS           = 5,
+       BNX_PKG_LOG_FIELD_IDX_INSTALLED_MASK            = 6
+};
+
 #endif                         /* Don't add anything after this line */
index c1cc83d7e38c69362d00038feb2294aee2ab636c..0c5f510492f146d270aae93b0b124f54815cb3f4 100644 (file)
@@ -522,6 +522,46 @@ err_out1:
        return rc;
 }
 
+static int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp,
+                                         struct bnxt_vf_info *vf,
+                                         u16 event_id)
+{
+       int rc = 0;
+       struct hwrm_fwd_async_event_cmpl_input req = {0};
+       struct hwrm_fwd_async_event_cmpl_output *resp = bp->hwrm_cmd_resp_addr;
+       struct hwrm_async_event_cmpl *async_cmpl;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_ASYNC_EVENT_CMPL, -1, -1);
+       if (vf)
+               req.encap_async_event_target_id = cpu_to_le16(vf->fw_fid);
+       else
+               /* broadcast this async event to all VFs */
+               req.encap_async_event_target_id = cpu_to_le16(0xffff);
+       async_cmpl = (struct hwrm_async_event_cmpl *)req.encap_async_event_cmpl;
+       async_cmpl->type =
+               cpu_to_le16(HWRM_ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT);
+       async_cmpl->event_id = cpu_to_le16(event_id);
+
+       mutex_lock(&bp->hwrm_cmd_lock);
+       rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+
+       if (rc) {
+               netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl failed. rc:%d\n",
+                          rc);
+               goto fwd_async_event_cmpl_exit;
+       }
+
+       if (resp->error_code) {
+               netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl error %d\n",
+                          resp->error_code);
+               rc = -1;
+       }
+
+fwd_async_event_cmpl_exit:
+       mutex_unlock(&bp->hwrm_cmd_lock);
+       return rc;
+}
+
 void bnxt_sriov_disable(struct bnxt *bp)
 {
        u16 num_vfs = pci_num_vf(bp->pdev);
@@ -530,6 +570,9 @@ void bnxt_sriov_disable(struct bnxt *bp)
                return;
 
        if (pci_vfs_assigned(bp->pdev)) {
+               bnxt_hwrm_fwd_async_event_cmpl(
+                       bp, NULL,
+                       HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
                netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n",
                            num_vfs);
        } else {
@@ -758,8 +801,8 @@ static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
 static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf)
 {
        int rc = 0;
-       struct hwrm_cmd_req_hdr *encap_req = vf->hwrm_cmd_req_addr;
-       u32 req_type = le32_to_cpu(encap_req->cmpl_ring_req_type) & 0xffff;
+       struct input *encap_req = vf->hwrm_cmd_req_addr;
+       u32 req_type = le16_to_cpu(encap_req->req_type);
 
        switch (req_type) {
        case HWRM_CFA_L2_FILTER_ALLOC:
@@ -809,13 +852,19 @@ void bnxt_update_vf_mac(struct bnxt *bp)
        if (_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
                goto update_vf_mac_exit;
 
-       if (!is_valid_ether_addr(resp->perm_mac_address))
-               goto update_vf_mac_exit;
-
+       /* Store MAC address from the firmware.  There are 2 cases:
+        * 1. MAC address is valid.  It is assigned from the PF and we
+        *    need to override the current VF MAC address with it.
+        * 2. MAC address is zero.  The VF will use a random MAC address by
+        *    default but the stored zero MAC will allow the VF user to change
+        *    the random MAC address using ndo_set_mac_address() if he wants.
+        */
        if (!ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr))
                memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN);
-       /* overwrite netdev dev_adr with admin VF MAC */
-       memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
+
+       /* overwrite netdev dev_addr with admin VF MAC */
+       if (is_valid_ether_addr(bp->vf.mac_addr))
+               memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
 update_vf_mac_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
 }
index b15a60d787c70354b780d9214e026dd2fbaebdec..d7e01a74e9275b29a915e4c5417c7116ffddcabf 100644 (file)
@@ -2445,8 +2445,7 @@ static void bcmgenet_irq_task(struct work_struct *work)
        }
 
        /* Link UP/DOWN event */
-       if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
-           (priv->irq0_stat & UMAC_IRQ_LINK_EVENT)) {
+       if (priv->irq0_stat & UMAC_IRQ_LINK_EVENT) {
                phy_mac_interrupt(priv->phydev,
                                  !!(priv->irq0_stat & UMAC_IRQ_LINK_UP));
                priv->irq0_stat &= ~UMAC_IRQ_LINK_EVENT;
index 49eea8981332d679b31614aa4d284e258abd97d6..3010080cfeee350a2e523ce0c26aeb427953f21a 100644 (file)
@@ -7831,6 +7831,14 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
        return ret;
 }
 
+static bool tg3_tso_bug_gso_check(struct tg3_napi *tnapi, struct sk_buff *skb)
+{
+       /* Check if we will never have enough descriptors,
+        * as gso_segs can be more than current ring size
+        */
+       return skb_shinfo(skb)->gso_segs < tnapi->tx_pending / 3;
+}
+
 static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);
 
 /* Use GSO to workaround all TSO packets that meet HW bug conditions
@@ -7934,14 +7942,19 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * vlan encapsulated.
                 */
                if (skb->protocol == htons(ETH_P_8021Q) ||
-                   skb->protocol == htons(ETH_P_8021AD))
-                       return tg3_tso_bug(tp, tnapi, txq, skb);
+                   skb->protocol == htons(ETH_P_8021AD)) {
+                       if (tg3_tso_bug_gso_check(tnapi, skb))
+                               return tg3_tso_bug(tp, tnapi, txq, skb);
+                       goto drop;
+               }
 
                if (!skb_is_gso_v6(skb)) {
                        if (unlikely((ETH_HLEN + hdr_len) > 80) &&
-                           tg3_flag(tp, TSO_BUG))
-                               return tg3_tso_bug(tp, tnapi, txq, skb);
-
+                           tg3_flag(tp, TSO_BUG)) {
+                               if (tg3_tso_bug_gso_check(tnapi, skb))
+                                       return tg3_tso_bug(tp, tnapi, txq, skb);
+                               goto drop;
+                       }
                        ip_csum = iph->check;
                        ip_tot_len = iph->tot_len;
                        iph->check = 0;
@@ -8073,7 +8086,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (would_hit_hwbug) {
                tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i);
 
-               if (mss) {
+               if (mss && tg3_tso_bug_gso_check(tnapi, skb)) {
                        /* If it's a TSO packet, do GSO instead of
                         * allocating and copying to a large linear SKB
                         */
index 04b0d16b210e89dd6eae3aa6704987e8543edeca..95bc470ae441af824f7b6ce29df5ff17842d7fee 100644 (file)
@@ -987,7 +987,7 @@ bna_rxf_ucast_cfg_apply(struct bna_rxf *rxf)
        if (!list_empty(&rxf->ucast_pending_add_q)) {
                mac = list_first_entry(&rxf->ucast_pending_add_q,
                                       struct bna_mac, qe);
-               list_add_tail(&mac->qe, &rxf->ucast_active_q);
+               list_move_tail(&mac->qe, &rxf->ucast_active_q);
                bna_bfi_ucast_req(rxf, mac, BFI_ENET_H2I_MAC_UCAST_ADD_REQ);
                return 1;
        }
index 69af049e55a8a9eb27b70777eb80705aea061d55..3ce6095ced3df9b72a47e054dea98a11e97a6f98 100644 (file)
@@ -2440,9 +2440,9 @@ static int macb_init(struct platform_device *pdev)
                if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII)
                        val = GEM_BIT(RGMII);
                else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII &&
-                        (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII))
+                        (bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
                        val = MACB_BIT(RMII);
-               else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII))
+               else if (!(bp->caps & MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII))
                        val = MACB_BIT(MII);
 
                if (bp->caps & MACB_CAPS_USRIO_HAS_CLKEN)
@@ -2774,7 +2774,7 @@ static int at91ether_init(struct platform_device *pdev)
 }
 
 static const struct macb_config at91sam9260_config = {
-       .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII,
+       .caps = MACB_CAPS_USRIO_HAS_CLKEN | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
        .clk_init = macb_clk_init,
        .init = macb_init,
 };
@@ -2787,21 +2787,22 @@ static const struct macb_config pc302gem_config = {
 };
 
 static const struct macb_config sama5d2_config = {
-       .caps = 0,
+       .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
        .dma_burst_length = 16,
        .clk_init = macb_clk_init,
        .init = macb_init,
 };
 
 static const struct macb_config sama5d3_config = {
-       .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
+       .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
+             | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
        .dma_burst_length = 16,
        .clk_init = macb_clk_init,
        .init = macb_init,
 };
 
 static const struct macb_config sama5d4_config = {
-       .caps = 0,
+       .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
        .dma_burst_length = 4,
        .clk_init = macb_clk_init,
        .init = macb_init,
@@ -2929,7 +2930,7 @@ static int macb_probe(struct platform_device *pdev)
                bp->jumbo_max_len = macb_config->jumbo_max_len;
 
        bp->wol = 0;
-       if (of_get_property(np, "cdns,magic-packet", NULL))
+       if (of_get_property(np, "magic-packet", NULL))
                bp->wol |= MACB_WOL_HAS_MAGIC_PACKET;
        device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
 
index 9ba416d5afff8b6ba7bd527ad4c5523762878902..8a13824ef8024365747b28251468cc04a97ffe22 100644 (file)
 /* Capability mask bits */
 #define MACB_CAPS_ISR_CLEAR_ON_WRITE           0x00000001
 #define MACB_CAPS_USRIO_HAS_CLKEN              0x00000002
-#define MACB_CAPS_USRIO_DEFAULT_IS_MII         0x00000004
+#define MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII    0x00000004
 #define MACB_CAPS_NO_GIGABIT_HALF              0x00000008
 #define MACB_CAPS_USRIO_DISABLED               0x00000010
 #define MACB_CAPS_FIFO_MODE                    0x10000000
index 872765527081ab3d48d7701f8a9d8705553640fc..34d269cd5579b7e0f1c1afd29bffb04c8711d71d 100644 (file)
@@ -1683,7 +1683,7 @@ static int octeon_setup_droq(struct octeon_device *oct, int q_no, int num_descs,
        dev_dbg(&oct->pci_dev->dev, "Creating Droq: %d\n", q_no);
        /* droq creation and local register settings. */
        ret_val = octeon_create_droq(oct, q_no, num_descs, desc_size, app_ctx);
-       if (ret_val == -1)
+       if (ret_val < 0)
                return ret_val;
 
        if (ret_val == 1) {
@@ -2524,7 +2524,7 @@ static void handle_timestamp(struct octeon_device *oct,
 
        octeon_swap_8B_data(&resp->timestamp, 1);
 
-       if (unlikely((skb_shinfo(skb)->tx_flags | SKBTX_IN_PROGRESS) != 0)) {
+       if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) != 0)) {
                struct skb_shared_hwtstamps ts;
                u64 ns = resp->timestamp;
 
index 4dba86eaa04559649b012cbeff8707c47a176927..174072b3740b4a15f86f292a51a28d8239ee8c0a 100644 (file)
@@ -983,5 +983,5 @@ int octeon_create_droq(struct octeon_device *oct,
 
 create_droq_fail:
        octeon_delete_droq(oct, q_no);
-       return -1;
+       return -ENOMEM;
 }
index 00cc9156abbbc06263a0ca146c7d94b1d75710f1..092f097a59432ee30e207d355031a722a682517a 100644 (file)
 #define NIC_PF_INTR_ID_MBOX0           8
 #define NIC_PF_INTR_ID_MBOX1           9
 
+/* Minimum FIFO level before all packets for the CQ are dropped
+ *
+ * This value ensures that once a packet has been "accepted"
+ * for reception it will not get dropped due to non-availability
+ * of CQ descriptor. An errata in HW mandates this value to be
+ * atleast 0x100.
+ */
+#define NICPF_CQM_MIN_DROP_LEVEL       0x100
+
 /* Global timer for CQ timer thresh interrupts
  * Calculated for SCLK of 700Mhz
  * value written should be a 1/16th of what is expected
index 4dded90076c8783b95c7944131e6b2cd3b828e40..95f17f8cadacc08637c485e555242e78aafb48c5 100644 (file)
@@ -304,6 +304,7 @@ static void nic_set_lmac_vf_mapping(struct nicpf *nic)
 static void nic_init_hw(struct nicpf *nic)
 {
        int i;
+       u64 cqm_cfg;
 
        /* Enable NIC HW block */
        nic_reg_write(nic, NIC_PF_CFG, 0x3);
@@ -340,6 +341,11 @@ static void nic_init_hw(struct nicpf *nic)
        /* Enable VLAN ethertype matching and stripping */
        nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7,
                      (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q);
+
+       /* Check if HW expected value is higher (could be in future chips) */
+       cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG);
+       if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL)
+               nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL);
 }
 
 /* Channel parse index configuration */
index dd536be20193119c3465cd772a4bff6d649e3319..afb10e326b4fc46043b4d3f4cddb7d17f1cc341c 100644 (file)
@@ -21,7 +21,7 @@
 #define   NIC_PF_TCP_TIMER                     (0x0060)
 #define   NIC_PF_BP_CFG                                (0x0080)
 #define   NIC_PF_RRM_CFG                       (0x0088)
-#define   NIC_PF_CQM_CF                                (0x00A0)
+#define   NIC_PF_CQM_CFG                       (0x00A0)
 #define   NIC_PF_CNM_CF                                (0x00A8)
 #define   NIC_PF_CNM_STATUS                    (0x00B0)
 #define   NIC_PF_CQ_AVG_CFG                    (0x00C0)
index 90ce93e380e11041b70602546e3807b15992c82c..bfee298fc02abc96e16cae7854d9de3036172542 100644 (file)
@@ -574,8 +574,7 @@ static inline void nicvf_set_rxhash(struct net_device *netdev,
 
 static void nicvf_rcv_pkt_handler(struct net_device *netdev,
                                  struct napi_struct *napi,
-                                 struct cmp_queue *cq,
-                                 struct cqe_rx_t *cqe_rx, int cqe_type)
+                                 struct cqe_rx_t *cqe_rx)
 {
        struct sk_buff *skb;
        struct nicvf *nic = netdev_priv(netdev);
@@ -591,7 +590,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev,
        }
 
        /* Check for errors */
-       err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx);
+       err = nicvf_check_cqe_rx_errs(nic, cqe_rx);
        if (err && !cqe_rx->rb_cnt)
                return;
 
@@ -682,8 +681,7 @@ loop:
                           cq_idx, cq_desc->cqe_type);
                switch (cq_desc->cqe_type) {
                case CQE_TYPE_RX:
-                       nicvf_rcv_pkt_handler(netdev, napi, cq,
-                                             cq_desc, CQE_TYPE_RX);
+                       nicvf_rcv_pkt_handler(netdev, napi, cq_desc);
                        work_done++;
                break;
                case CQE_TYPE_SEND:
@@ -1158,7 +1156,6 @@ int nicvf_stop(struct net_device *netdev)
 
        /* Clear multiqset info */
        nic->pnicvf = nic;
-       nic->sqs_count = 0;
 
        return 0;
 }
@@ -1387,6 +1384,9 @@ void nicvf_update_stats(struct nicvf *nic)
        drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok +
                                  stats->tx_bcast_frames_ok +
                                  stats->tx_mcast_frames_ok;
+       drv_stats->rx_frames_ok = stats->rx_ucast_frames +
+                                 stats->rx_bcast_frames +
+                                 stats->rx_mcast_frames;
        drv_stats->rx_drops = stats->rx_drop_red +
                              stats->rx_drop_overrun;
        drv_stats->tx_drops = stats->tx_drops;
@@ -1572,6 +1572,9 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        nicvf_send_vf_struct(nic);
 
+       if (!pass1_silicon(nic->pdev))
+               nic->hw_tso = true;
+
        /* Check if this VF is in QS only mode */
        if (nic->sqs_mode)
                return 0;
@@ -1591,9 +1594,6 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
 
-       if (!pass1_silicon(nic->pdev))
-               nic->hw_tso = true;
-
        netdev->netdev_ops = &nicvf_netdev_ops;
        netdev->watchdog_timeo = NICVF_TX_TIMEOUT;
 
index 5adb208c1ad2f3ff57f7641d7dde049cbec7798f..0dd1abf86079b4258360d522737b590b06f67036 100644 (file)
@@ -1328,16 +1328,12 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx)
 }
 
 /* Check for errors in the receive cmp.queue entry */
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_rx_t *cqe_rx)
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
 {
        struct nicvf_hw_stats *stats = &nic->hw_stats;
-       struct nicvf_drv_stats *drv_stats = &nic->drv_stats;
 
-       if (!cqe_rx->err_level && !cqe_rx->err_opcode) {
-               drv_stats->rx_frames_ok++;
+       if (!cqe_rx->err_level && !cqe_rx->err_opcode)
                return 0;
-       }
 
        if (netif_msg_rx_err(nic))
                netdev_err(nic->netdev,
index c5030a7f213ae57e9799142958e5d4fe64a8fbf5..6673e1133523881a4c1719e7d6ca4c123f7a8e1e 100644 (file)
@@ -338,8 +338,7 @@ u64  nicvf_queue_reg_read(struct nicvf *nic,
 /* Stats */
 void nicvf_update_rq_stats(struct nicvf *nic, int rq_idx);
 void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx);
-int nicvf_check_cqe_rx_errs(struct nicvf *nic,
-                           struct cmp_queue *cq, struct cqe_rx_t *cqe_rx);
+int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cqe_rx_t *cqe_rx);
 int nicvf_check_cqe_tx_errs(struct nicvf *nic,
                            struct cmp_queue *cq, struct cqe_send_t *cqe_tx);
 #endif /* NICVF_QUEUES_H */
index ee04caa6c4d8522d0cc34ec15ec7575bfbdc4afa..a89721fad633ec75a3ed46a7fc22d8988cbdada4 100644 (file)
@@ -681,6 +681,24 @@ int t3_seeprom_wp(struct adapter *adapter, int enable)
        return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
 }
 
+static int vpdstrtouint(char *s, int len, unsigned int base, unsigned int *val)
+{
+       char tok[len + 1];
+
+       memcpy(tok, s, len);
+       tok[len] = 0;
+       return kstrtouint(strim(tok), base, val);
+}
+
+static int vpdstrtou16(char *s, int len, unsigned int base, u16 *val)
+{
+       char tok[len + 1];
+
+       memcpy(tok, s, len);
+       tok[len] = 0;
+       return kstrtou16(strim(tok), base, val);
+}
+
 /**
  *     get_vpd_params - read VPD parameters from VPD EEPROM
  *     @adapter: adapter to read
@@ -709,19 +727,19 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
                        return ret;
        }
 
-       ret = kstrtouint(vpd.cclk_data, 10, &p->cclk);
+       ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
        if (ret)
                return ret;
-       ret = kstrtouint(vpd.mclk_data, 10, &p->mclk);
+       ret = vpdstrtouint(vpd.mclk_data, vpd.mclk_len, 10, &p->mclk);
        if (ret)
                return ret;
-       ret = kstrtouint(vpd.uclk_data, 10, &p->uclk);
+       ret = vpdstrtouint(vpd.uclk_data, vpd.uclk_len, 10, &p->uclk);
        if (ret)
                return ret;
-       ret = kstrtouint(vpd.mdc_data, 10, &p->mdc);
+       ret = vpdstrtouint(vpd.mdc_data, vpd.mdc_len, 10, &p->mdc);
        if (ret)
                return ret;
-       ret = kstrtouint(vpd.mt_data, 10, &p->mem_timing);
+       ret = vpdstrtouint(vpd.mt_data, vpd.mt_len, 10, &p->mem_timing);
        if (ret)
                return ret;
        memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
@@ -733,10 +751,12 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        } else {
                p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
                p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
-               ret = kstrtou16(vpd.xaui0cfg_data, 16, &p->xauicfg[0]);
+               ret = vpdstrtou16(vpd.xaui0cfg_data, vpd.xaui0cfg_len, 16,
+                                 &p->xauicfg[0]);
                if (ret)
                        return ret;
-               ret = kstrtou16(vpd.xaui1cfg_data, 16, &p->xauicfg[1]);
+               ret = vpdstrtou16(vpd.xaui1cfg_data, vpd.xaui1cfg_len, 16,
+                                 &p->xauicfg[1]);
                if (ret)
                        return ret;
        }
index ec6e849676c146a6462257976b2c016574416a0b..1dac6c6111bf1593f2ac0b7ccb0bccc5f6af8bf0 100644 (file)
@@ -702,6 +702,11 @@ struct doorbell_stats {
        u32 db_full;
 };
 
+struct hash_mac_addr {
+       struct list_head list;
+       u8 addr[ETH_ALEN];
+};
+
 struct adapter {
        void __iomem *regs;
        void __iomem *bar2;
@@ -740,6 +745,7 @@ struct adapter {
        void *uld_handle[CXGB4_ULD_MAX];
        struct list_head list_node;
        struct list_head rcu_node;
+       struct list_head mac_hlist; /* list of MAC addresses in MPS Hash */
 
        struct tid_info tids;
        void **tid_release_head;
@@ -1207,6 +1213,24 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
        return t4_wr_mbox_meat(adap, mbox, cmd, size, rpl, false);
 }
 
+/**
+ *     hash_mac_addr - return the hash value of a MAC address
+ *     @addr: the 48-bit Ethernet MAC address
+ *
+ *     Hashes a MAC address according to the hash function used by HW inexact
+ *     (hash) address matching.
+ */
+static inline int hash_mac_addr(const u8 *addr)
+{
+       u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
+       u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
+
+       a ^= b;
+       a ^= (a >> 12);
+       a ^= (a >> 6);
+       return a & 0x3f;
+}
+
 void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
                       unsigned int data_reg, const u32 *vals,
                       unsigned int nregs, unsigned int start_idx);
@@ -1389,6 +1413,9 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
 int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                      unsigned int viid, bool free, unsigned int naddr,
                      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok);
+int t4_free_mac_filt(struct adapter *adap, unsigned int mbox,
+                    unsigned int viid, unsigned int naddr,
+                    const u8 **addr, bool sleep_ok);
 int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
                  int idx, const u8 *addr, bool persist, bool add_smt);
 int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
index b8a5fb0c32d4ab79ccc711610155ca758bbd2138..adad73f7c8cd96137cc49d8c2c9dad33ec5eed6a 100644 (file)
@@ -338,84 +338,108 @@ void t4_os_portmod_changed(const struct adapter *adap, int port_id)
                netdev_info(dev, "%s module inserted\n", mod_str[pi->mod_type]);
 }
 
+int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
+module_param(dbfifo_int_thresh, int, 0644);
+MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
+
 /*
- * Configure the exact and hash address filters to handle a port's multicast
- * and secondary unicast MAC addresses.
+ * usecs to sleep while draining the dbfifo
  */
-static int set_addr_filters(const struct net_device *dev, bool sleep)
+static int dbfifo_drain_delay = 1000;
+module_param(dbfifo_drain_delay, int, 0644);
+MODULE_PARM_DESC(dbfifo_drain_delay,
+                "usecs to sleep while draining the dbfifo");
+
+static inline int cxgb4_set_addr_hash(struct port_info *pi)
 {
+       struct adapter *adap = pi->adapter;
+       u64 vec = 0;
+       bool ucast = false;
+       struct hash_mac_addr *entry;
+
+       /* Calculate the hash vector for the updated list and program it */
+       list_for_each_entry(entry, &adap->mac_hlist, list) {
+               ucast |= is_unicast_ether_addr(entry->addr);
+               vec |= (1ULL << hash_mac_addr(entry->addr));
+       }
+       return t4_set_addr_hash(adap, adap->mbox, pi->viid, ucast,
+                               vec, false);
+}
+
+static int cxgb4_mac_sync(struct net_device *netdev, const u8 *mac_addr)
+{
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adap = pi->adapter;
+       int ret;
        u64 mhash = 0;
        u64 uhash = 0;
-       bool free = true;
-       u16 filt_idx[7];
-       const u8 *addr[7];
-       int ret, naddr = 0;
-       const struct netdev_hw_addr *ha;
-       int uc_cnt = netdev_uc_count(dev);
-       int mc_cnt = netdev_mc_count(dev);
-       const struct port_info *pi = netdev_priv(dev);
-       unsigned int mb = pi->adapter->pf;
+       bool free = false;
+       bool ucast = is_unicast_ether_addr(mac_addr);
+       const u8 *maclist[1] = {mac_addr};
+       struct hash_mac_addr *new_entry;
 
-       /* first do the secondary unicast addresses */
-       netdev_for_each_uc_addr(ha, dev) {
-               addr[naddr++] = ha->addr;
-               if (--uc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
-                       ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
-                                       naddr, addr, filt_idx, &uhash, sleep);
-                       if (ret < 0)
-                               return ret;
-
-                       free = false;
-                       naddr = 0;
-               }
+       ret = t4_alloc_mac_filt(adap, adap->mbox, pi->viid, free, 1, maclist,
+                               NULL, ucast ? &uhash : &mhash, false);
+       if (ret < 0)
+               goto out;
+       /* if hash != 0, then add the addr to hash addr list
+        * so on the end we will calculate the hash for the
+        * list and program it
+        */
+       if (uhash || mhash) {
+               new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
+               if (!new_entry)
+                       return -ENOMEM;
+               ether_addr_copy(new_entry->addr, mac_addr);
+               list_add_tail(&new_entry->list, &adap->mac_hlist);
+               ret = cxgb4_set_addr_hash(pi);
        }
+out:
+       return ret < 0 ? ret : 0;
+}
 
-       /* next set up the multicast addresses */
-       netdev_for_each_mc_addr(ha, dev) {
-               addr[naddr++] = ha->addr;
-               if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
-                       ret = t4_alloc_mac_filt(pi->adapter, mb, pi->viid, free,
-                                       naddr, addr, filt_idx, &mhash, sleep);
-                       if (ret < 0)
-                               return ret;
+static int cxgb4_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
+{
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adap = pi->adapter;
+       int ret;
+       const u8 *maclist[1] = {mac_addr};
+       struct hash_mac_addr *entry, *tmp;
 
-                       free = false;
-                       naddr = 0;
+       /* If the MAC address to be removed is in the hash addr
+        * list, delete it from the list and update hash vector
+        */
+       list_for_each_entry_safe(entry, tmp, &adap->mac_hlist, list) {
+               if (ether_addr_equal(entry->addr, mac_addr)) {
+                       list_del(&entry->list);
+                       kfree(entry);
+                       return cxgb4_set_addr_hash(pi);
                }
        }
 
-       return t4_set_addr_hash(pi->adapter, mb, pi->viid, uhash != 0,
-                               uhash | mhash, sleep);
+       ret = t4_free_mac_filt(adap, adap->mbox, pi->viid, 1, maclist, false);
+       return ret < 0 ? -EINVAL : 0;
 }
 
-int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
-module_param(dbfifo_int_thresh, int, 0644);
-MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
-
-/*
- * usecs to sleep while draining the dbfifo
- */
-static int dbfifo_drain_delay = 1000;
-module_param(dbfifo_drain_delay, int, 0644);
-MODULE_PARM_DESC(dbfifo_drain_delay,
-                "usecs to sleep while draining the dbfifo");
-
 /*
  * Set Rx properties of a port, such as promiscruity, address filters, and MTU.
  * If @mtu is -1 it is left unchanged.
  */
 static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
 {
-       int ret;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
 
-       ret = set_addr_filters(dev, sleep_ok);
-       if (ret == 0)
-               ret = t4_set_rxmode(pi->adapter, pi->adapter->pf, pi->viid, mtu,
-                                   (dev->flags & IFF_PROMISC) ? 1 : 0,
-                                   (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
-                                   sleep_ok);
-       return ret;
+       if (!(dev->flags & IFF_PROMISC)) {
+               __dev_uc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
+               if (!(dev->flags & IFF_ALLMULTI))
+                       __dev_mc_sync(dev, cxgb4_mac_sync, cxgb4_mac_unsync);
+       }
+
+       return t4_set_rxmode(adapter, adapter->mbox, pi->viid, mtu,
+                            (dev->flags & IFF_PROMISC) ? 1 : 0,
+                            (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
+                            sleep_ok);
 }
 
 /**
@@ -2677,6 +2701,8 @@ static int cxgb_up(struct adapter *adap)
 #if IS_ENABLED(CONFIG_IPV6)
        update_clip(adap);
 #endif
+       /* Initialize hash mac addr list*/
+       INIT_LIST_HEAD(&adap->mac_hlist);
  out:
        return err;
  irq_err:
index b4eb4680a27cc368d90f8716bfde16b85231d03b..deca4a2956cc005fb8adce0b59a1c445699cce8d 100644 (file)
@@ -2226,7 +2226,7 @@ static int process_responses(struct sge_rspq *q, int budget)
                budget_left--;
        }
 
-       if (q->offset >= 0 && rxq->fl.size - rxq->fl.avail >= 16)
+       if (q->offset >= 0 && fl_cap(&rxq->fl) - rxq->fl.avail >= 16)
                __refill_fl(q->adap, &rxq->fl);
        return budget - budget_left;
 }
@@ -2611,8 +2611,18 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
                                htonl(FW_IQ_CMD_FL0CNGCHMAP_V(cong) |
                                      FW_IQ_CMD_FL0CONGCIF_F |
                                      FW_IQ_CMD_FL0CONGEN_F);
+               /* In T6, for egress queue type FL there is internal overhead
+                * of 16B for header going into FLM module.  Hence the maximum
+                * allowed burst size is 448 bytes.  For T4/T5, the hardware
+                * doesn't coalesce fetch requests if more than 64 bytes of
+                * Free List pointers are provided, so we use a 128-byte Fetch
+                * Burst Minimum there (T6 implements coalescing so we can use
+                * the smaller 64-byte value there).
+                */
                c.fl0dcaen_to_fl0cidxfthresh =
-                       htons(FW_IQ_CMD_FL0FBMIN_V(FETCHBURSTMIN_64B_X) |
+                       htons(FW_IQ_CMD_FL0FBMIN_V(chip <= CHELSIO_T5 ?
+                                                  FETCHBURSTMIN_128B_X :
+                                                  FETCHBURSTMIN_64B_X) |
                              FW_IQ_CMD_FL0FBMAX_V((chip <= CHELSIO_T5) ?
                                                   FETCHBURSTMAX_512B_X :
                                                   FETCHBURSTMAX_256B_X));
index 636b4691f252707514e1c099e34e79340ab0a38d..cc1736bece0faabe22f04a828f7d1740bf9462de 100644 (file)
@@ -4432,23 +4432,6 @@ void t4_intr_disable(struct adapter *adapter)
        t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0);
 }
 
-/**
- *     hash_mac_addr - return the hash value of a MAC address
- *     @addr: the 48-bit Ethernet MAC address
- *
- *     Hashes a MAC address according to the hash function used by HW inexact
- *     (hash) address matching.
- */
-static int hash_mac_addr(const u8 *addr)
-{
-       u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
-       u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
-       a ^= b;
-       a ^= (a >> 12);
-       a ^= (a >> 6);
-       return a & 0x3f;
-}
-
 /**
  *     t4_config_rss_range - configure a portion of the RSS mapping table
  *     @adapter: the adapter
@@ -6737,6 +6720,81 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
        return ret;
 }
 
+/**
+ *     t4_free_mac_filt - frees exact-match filters of given MAC addresses
+ *     @adap: the adapter
+ *     @mbox: mailbox to use for the FW command
+ *     @viid: the VI id
+ *     @naddr: the number of MAC addresses to allocate filters for (up to 7)
+ *     @addr: the MAC address(es)
+ *     @sleep_ok: call is allowed to sleep
+ *
+ *     Frees the exact-match filter for each of the supplied addresses
+ *
+ *     Returns a negative error number or the number of filters freed.
+ */
+int t4_free_mac_filt(struct adapter *adap, unsigned int mbox,
+                    unsigned int viid, unsigned int naddr,
+                    const u8 **addr, bool sleep_ok)
+{
+       int offset, ret = 0;
+       struct fw_vi_mac_cmd c;
+       unsigned int nfilters = 0;
+       unsigned int max_naddr = is_t4(adap->params.chip) ?
+                                      NUM_MPS_CLS_SRAM_L_INSTANCES :
+                                      NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+       unsigned int rem = naddr;
+
+       if (naddr > max_naddr)
+               return -EINVAL;
+
+       for (offset = 0; offset < (int)naddr ; /**/) {
+               unsigned int fw_naddr = (rem < ARRAY_SIZE(c.u.exact)
+                                        ? rem
+                                        : ARRAY_SIZE(c.u.exact));
+               size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+                                                    u.exact[fw_naddr]), 16);
+               struct fw_vi_mac_exact *p;
+               int i;
+
+               memset(&c, 0, sizeof(c));
+               c.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
+                                    FW_CMD_EXEC_V(0) |
+                                    FW_VI_MAC_CMD_VIID_V(viid));
+               c.freemacs_to_len16 =
+                               cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) |
+                                           FW_CMD_LEN16_V(len16));
+
+               for (i = 0, p = c.u.exact; i < (int)fw_naddr; i++, p++) {
+                       p->valid_to_idx = cpu_to_be16(
+                               FW_VI_MAC_CMD_VALID_F |
+                               FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
+                       memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
+               }
+
+               ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
+               if (ret)
+                       break;
+
+               for (i = 0, p = c.u.exact; i < fw_naddr; i++, p++) {
+                       u16 index = FW_VI_MAC_CMD_IDX_G(
+                                               be16_to_cpu(p->valid_to_idx));
+
+                       if (index < max_naddr)
+                               nfilters++;
+               }
+
+               offset += fw_naddr;
+               rem -= fw_naddr;
+       }
+
+       if (ret == 0)
+               ret = nfilters;
+       return ret;
+}
+
 /**
  *     t4_change_mac - modifies the exact-match filter for a MAC address
  *     @adap: the adapter
index a8dda635456dc1f8fb0d85799c3f605ea7cda39a..06bc2d2e7a7315ceb0f544aac1fcaec1af51fbc6 100644 (file)
@@ -165,6 +165,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
        CH_PCI_ID_TABLE_FENTRY(0x5098), /* Custom 2x40G QSFP */
        CH_PCI_ID_TABLE_FENTRY(0x5099), /* Custom 2x40G QSFP */
        CH_PCI_ID_TABLE_FENTRY(0x509a), /* Custom T520-CR */
+       CH_PCI_ID_TABLE_FENTRY(0x509b), /* Custom T540-CR LOM */
 
        /* T6 adapters:
         */
index a5231fa771db99a670c257d4c28adadeeea64b75..36cf3073ca37d59c2cf3a129603637fc54619c13 100644 (file)
@@ -65,6 +65,7 @@
 #define TIMERREG_COUNTER0_X            0
 
 #define FETCHBURSTMIN_64B_X            2
+#define FETCHBURSTMIN_128B_X           3
 
 #define FETCHBURSTMAX_256B_X           2
 #define FETCHBURSTMAX_512B_X           3
index 6049f70e110c5701d0a6cb8685b3dbf2a78ab38d..4a707c32d76f523c84b7225cef9b6399b0ceddd3 100644 (file)
@@ -348,6 +348,11 @@ struct sge {
 #define for_each_ethrxq(sge, iter) \
        for (iter = 0; iter < (sge)->ethqsets; iter++)
 
+struct hash_mac_addr {
+       struct list_head list;
+       u8 addr[ETH_ALEN];
+};
+
 /*
  * Per-"adapter" (Virtual Function) information.
  */
@@ -381,6 +386,9 @@ struct adapter {
 
        /* various locks */
        spinlock_t stats_lock;
+
+       /* list of MAC addresses in MPS Hash */
+       struct list_head mac_hlist;
 };
 
 enum { /* adapter flags */
index 0cfa5d72cafd4027a1f06593bfc3f63c0703ba49..1cc8a7a69457dfbb029a5ff0b7469be56ef60ce1 100644 (file)
@@ -741,6 +741,9 @@ static int adapter_up(struct adapter *adapter)
         */
        enable_rx(adapter);
        t4vf_sge_start(adapter);
+
+       /* Initialize hash mac addr list*/
+       INIT_LIST_HEAD(&adapter->mac_hlist);
        return 0;
 }
 
@@ -787,10 +790,6 @@ static int cxgb4vf_open(struct net_device *dev)
        /*
         * Note that this interface is up and start everything up ...
         */
-       netif_set_real_num_tx_queues(dev, pi->nqsets);
-       err = netif_set_real_num_rx_queues(dev, pi->nqsets);
-       if (err)
-               goto err_unwind;
        err = link_start(dev);
        if (err)
                goto err_unwind;
@@ -859,97 +858,74 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
        return ns;
 }
 
-/*
- * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
- * at a specified offset within the list, into an array of addrss pointers and
- * return the number collected.
- */
-static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
-                                                       const u8 **addr,
-                                                       unsigned int offset,
-                                                       unsigned int maxaddrs)
+static inline int cxgb4vf_set_addr_hash(struct port_info *pi)
 {
-       unsigned int index = 0;
-       unsigned int naddr = 0;
-       const struct netdev_hw_addr *ha;
-
-       for_each_dev_addr(dev, ha)
-               if (index++ >= offset) {
-                       addr[naddr++] = ha->addr;
-                       if (naddr >= maxaddrs)
-                               break;
-               }
-       return naddr;
-}
-
-/*
- * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
- * at a specified offset within the list, into an array of addrss pointers and
- * return the number collected.
- */
-static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
-                                                       const u8 **addr,
-                                                       unsigned int offset,
-                                                       unsigned int maxaddrs)
-{
-       unsigned int index = 0;
-       unsigned int naddr = 0;
-       const struct netdev_hw_addr *ha;
+       struct adapter *adapter = pi->adapter;
+       u64 vec = 0;
+       bool ucast = false;
+       struct hash_mac_addr *entry;
 
-       netdev_for_each_mc_addr(ha, dev)
-               if (index++ >= offset) {
-                       addr[naddr++] = ha->addr;
-                       if (naddr >= maxaddrs)
-                               break;
-               }
-       return naddr;
+       /* Calculate the hash vector for the updated list and program it */
+       list_for_each_entry(entry, &adapter->mac_hlist, list) {
+               ucast |= is_unicast_ether_addr(entry->addr);
+               vec |= (1ULL << hash_mac_addr(entry->addr));
+       }
+       return t4vf_set_addr_hash(adapter, pi->viid, ucast, vec, false);
 }
 
-/*
- * Configure the exact and hash address filters to handle a port's multicast
- * and secondary unicast MAC addresses.
- */
-static int set_addr_filters(const struct net_device *dev, bool sleep)
+static int cxgb4vf_mac_sync(struct net_device *netdev, const u8 *mac_addr)
 {
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adapter = pi->adapter;
+       int ret;
        u64 mhash = 0;
        u64 uhash = 0;
-       bool free = true;
-       unsigned int offset, naddr;
-       const u8 *addr[7];
-       int ret;
-       const struct port_info *pi = netdev_priv(dev);
-
-       /* first do the secondary unicast addresses */
-       for (offset = 0; ; offset += naddr) {
-               naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
-                                                    ARRAY_SIZE(addr));
-               if (naddr == 0)
-                       break;
-
-               ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, NULL, &uhash, sleep);
-               if (ret < 0)
-                       return ret;
+       bool free = false;
+       bool ucast = is_unicast_ether_addr(mac_addr);
+       const u8 *maclist[1] = {mac_addr};
+       struct hash_mac_addr *new_entry;
 
-               free = false;
+       ret = t4vf_alloc_mac_filt(adapter, pi->viid, free, 1, maclist,
+                                 NULL, ucast ? &uhash : &mhash, false);
+       if (ret < 0)
+               goto out;
+       /* if hash != 0, then add the addr to hash addr list
+        * so on the end we will calculate the hash for the
+        * list and program it
+        */
+       if (uhash || mhash) {
+               new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
+               if (!new_entry)
+                       return -ENOMEM;
+               ether_addr_copy(new_entry->addr, mac_addr);
+               list_add_tail(&new_entry->list, &adapter->mac_hlist);
+               ret = cxgb4vf_set_addr_hash(pi);
        }
+out:
+       return ret < 0 ? ret : 0;
+}
 
-       /* next set up the multicast addresses */
-       for (offset = 0; ; offset += naddr) {
-               naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
-                                                    ARRAY_SIZE(addr));
-               if (naddr == 0)
-                       break;
+static int cxgb4vf_mac_unsync(struct net_device *netdev, const u8 *mac_addr)
+{
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adapter = pi->adapter;
+       int ret;
+       const u8 *maclist[1] = {mac_addr};
+       struct hash_mac_addr *entry, *tmp;
 
-               ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, NULL, &mhash, sleep);
-               if (ret < 0)
-                       return ret;
-               free = false;
+       /* If the MAC address to be removed is in the hash addr
+        * list, delete it from the list and update hash vector
+        */
+       list_for_each_entry_safe(entry, tmp, &adapter->mac_hlist, list) {
+               if (ether_addr_equal(entry->addr, mac_addr)) {
+                       list_del(&entry->list);
+                       kfree(entry);
+                       return cxgb4vf_set_addr_hash(pi);
+               }
        }
 
-       return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
-                                 uhash | mhash, sleep);
+       ret = t4vf_free_mac_filt(adapter, pi->viid, 1, maclist, false);
+       return ret < 0 ? -EINVAL : 0;
 }
 
 /*
@@ -958,16 +934,18 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
  */
 static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
 {
-       int ret;
        struct port_info *pi = netdev_priv(dev);
 
-       ret = set_addr_filters(dev, sleep_ok);
-       if (ret == 0)
-               ret = t4vf_set_rxmode(pi->adapter, pi->viid, -1,
-                                     (dev->flags & IFF_PROMISC) != 0,
-                                     (dev->flags & IFF_ALLMULTI) != 0,
-                                     1, -1, sleep_ok);
-       return ret;
+       if (!(dev->flags & IFF_PROMISC)) {
+               __dev_uc_sync(dev, cxgb4vf_mac_sync, cxgb4vf_mac_unsync);
+               if (!(dev->flags & IFF_ALLMULTI))
+                       __dev_mc_sync(dev, cxgb4vf_mac_sync,
+                                     cxgb4vf_mac_unsync);
+       }
+       return t4vf_set_rxmode(pi->adapter, pi->viid, -1,
+                              (dev->flags & IFF_PROMISC) != 0,
+                              (dev->flags & IFF_ALLMULTI) != 0,
+                              1, -1, sleep_ok);
 }
 
 /*
@@ -2194,6 +2172,73 @@ static void cleanup_debugfs(struct adapter *adapter)
        /* nothing to do */
 }
 
+/* Figure out how many Ports and Queue Sets we can support.  This depends on
+ * knowing our Virtual Function Resources and may be called a second time if
+ * we fall back from MSI-X to MSI Interrupt Mode.
+ */
+static void size_nports_qsets(struct adapter *adapter)
+{
+       struct vf_resources *vfres = &adapter->params.vfres;
+       unsigned int ethqsets, pmask_nports;
+
+       /* The number of "ports" which we support is equal to the number of
+        * Virtual Interfaces with which we've been provisioned.
+        */
+       adapter->params.nports = vfres->nvi;
+       if (adapter->params.nports > MAX_NPORTS) {
+               dev_warn(adapter->pdev_dev, "only using %d of %d maximum"
+                        " allowed virtual interfaces\n", MAX_NPORTS,
+                        adapter->params.nports);
+               adapter->params.nports = MAX_NPORTS;
+       }
+
+       /* We may have been provisioned with more VIs than the number of
+        * ports we're allowed to access (our Port Access Rights Mask).
+        * This is obviously a configuration conflict but we don't want to
+        * crash the kernel or anything silly just because of that.
+        */
+       pmask_nports = hweight32(adapter->params.vfres.pmask);
+       if (pmask_nports < adapter->params.nports) {
+               dev_warn(adapter->pdev_dev, "only using %d of %d provissioned"
+                        " virtual interfaces; limited by Port Access Rights"
+                        " mask %#x\n", pmask_nports, adapter->params.nports,
+                        adapter->params.vfres.pmask);
+               adapter->params.nports = pmask_nports;
+       }
+
+       /* We need to reserve an Ingress Queue for the Asynchronous Firmware
+        * Event Queue.  And if we're using MSI Interrupts, we'll also need to
+        * reserve an Ingress Queue for a Forwarded Interrupts.
+        *
+        * The rest of the FL/Intr-capable ingress queues will be matched up
+        * one-for-one with Ethernet/Control egress queues in order to form
+        * "Queue Sets" which will be aportioned between the "ports".  For
+        * each Queue Set, we'll need the ability to allocate two Egress
+        * Contexts -- one for the Ingress Queue Free List and one for the TX
+        * Ethernet Queue.
+        *
+        * Note that even if we're currently configured to use MSI-X
+        * Interrupts (module variable msi == MSI_MSIX) we may get downgraded
+        * to MSI Interrupts if we can't get enough MSI-X Interrupts.  If that
+        * happens we'll need to adjust things later.
+        */
+       ethqsets = vfres->niqflint - 1 - (msi == MSI_MSI);
+       if (vfres->nethctrl != ethqsets)
+               ethqsets = min(vfres->nethctrl, ethqsets);
+       if (vfres->neq < ethqsets*2)
+               ethqsets = vfres->neq/2;
+       if (ethqsets > MAX_ETH_QSETS)
+               ethqsets = MAX_ETH_QSETS;
+       adapter->sge.max_ethqsets = ethqsets;
+
+       if (adapter->sge.max_ethqsets < adapter->params.nports) {
+               dev_warn(adapter->pdev_dev, "only using %d of %d available"
+                        " virtual interfaces (too few Queue Sets)\n",
+                        adapter->sge.max_ethqsets, adapter->params.nports);
+               adapter->params.nports = adapter->sge.max_ethqsets;
+       }
+}
+
 /*
  * Perform early "adapter" initialization.  This is where we discover what
  * adapter parameters we're going to be using and initialize basic adapter
@@ -2201,23 +2246,11 @@ static void cleanup_debugfs(struct adapter *adapter)
  */
 static int adap_init0(struct adapter *adapter)
 {
-       struct vf_resources *vfres = &adapter->params.vfres;
        struct sge_params *sge_params = &adapter->params.sge;
        struct sge *s = &adapter->sge;
-       unsigned int ethqsets;
        int err;
        u32 param, val = 0;
 
-       /*
-        * Wait for the device to become ready before proceeding ...
-        */
-       err = t4vf_wait_dev_ready(adapter);
-       if (err) {
-               dev_err(adapter->pdev_dev, "device didn't become ready:"
-                       " err=%d\n", err);
-               return err;
-       }
-
        /*
         * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
         * 2.6.31 and later we can't call pci_reset_function() in order to
@@ -2323,69 +2356,23 @@ static int adap_init0(struct adapter *adapter)
                return err;
        }
 
-       /*
-        * The number of "ports" which we support is equal to the number of
-        * Virtual Interfaces with which we've been provisioned.
-        */
-       adapter->params.nports = vfres->nvi;
-       if (adapter->params.nports > MAX_NPORTS) {
-               dev_warn(adapter->pdev_dev, "only using %d of %d allowed"
-                        " virtual interfaces\n", MAX_NPORTS,
-                        adapter->params.nports);
-               adapter->params.nports = MAX_NPORTS;
-       }
-
-       /*
-        * We need to reserve a number of the ingress queues with Free List
-        * and Interrupt capabilities for special interrupt purposes (like
-        * asynchronous firmware messages, or forwarded interrupts if we're
-        * using MSI).  The rest of the FL/Intr-capable ingress queues will be
-        * matched up one-for-one with Ethernet/Control egress queues in order
-        * to form "Queue Sets" which will be aportioned between the "ports".
-        * For each Queue Set, we'll need the ability to allocate two Egress
-        * Contexts -- one for the Ingress Queue Free List and one for the TX
-        * Ethernet Queue.
-        */
-       ethqsets = vfres->niqflint - INGQ_EXTRAS;
-       if (vfres->nethctrl != ethqsets) {
-               dev_warn(adapter->pdev_dev, "unequal number of [available]"
-                        " ingress/egress queues (%d/%d); using minimum for"
-                        " number of Queue Sets\n", ethqsets, vfres->nethctrl);
-               ethqsets = min(vfres->nethctrl, ethqsets);
-       }
-       if (vfres->neq < ethqsets*2) {
-               dev_warn(adapter->pdev_dev, "Not enough Egress Contexts (%d)"
-                        " to support Queue Sets (%d); reducing allowed Queue"
-                        " Sets\n", vfres->neq, ethqsets);
-               ethqsets = vfres->neq/2;
-       }
-       if (ethqsets > MAX_ETH_QSETS) {
-               dev_warn(adapter->pdev_dev, "only using %d of %d allowed Queue"
-                        " Sets\n", MAX_ETH_QSETS, adapter->sge.max_ethqsets);
-               ethqsets = MAX_ETH_QSETS;
-       }
-       if (vfres->niq != 0 || vfres->neq > ethqsets*2) {
-               dev_warn(adapter->pdev_dev, "unused resources niq/neq (%d/%d)"
-                        " ignored\n", vfres->niq, vfres->neq - ethqsets*2);
-       }
-       adapter->sge.max_ethqsets = ethqsets;
-
-       /*
-        * Check for various parameter sanity issues.  Most checks simply
-        * result in us using fewer resources than our provissioning but we
-        * do need at least  one "port" with which to work ...
-        */
-       if (adapter->sge.max_ethqsets < adapter->params.nports) {
-               dev_warn(adapter->pdev_dev, "only using %d of %d available"
-                        " virtual interfaces (too few Queue Sets)\n",
-                        adapter->sge.max_ethqsets, adapter->params.nports);
-               adapter->params.nports = adapter->sge.max_ethqsets;
+       /* Check for various parameter sanity issues */
+       if (adapter->params.vfres.pmask == 0) {
+               dev_err(adapter->pdev_dev, "no port access configured\n"
+                       "usable!\n");
+               return -EINVAL;
        }
-       if (adapter->params.nports == 0) {
+       if (adapter->params.vfres.nvi == 0) {
                dev_err(adapter->pdev_dev, "no virtual interfaces configured/"
                        "usable!\n");
                return -EINVAL;
        }
+
+       /* Initialize nports and max_ethqsets now that we have our Virtual
+        * Function Resources.
+        */
+       size_nports_qsets(adapter);
+
        return 0;
 }
 
@@ -2799,6 +2786,40 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
                }
        }
 
+       /* See what interrupts we'll be using.  If we've been configured to
+        * use MSI-X interrupts, try to enable them but fall back to using
+        * MSI interrupts if we can't enable MSI-X interrupts.  If we can't
+        * get MSI interrupts we bail with the error.
+        */
+       if (msi == MSI_MSIX && enable_msix(adapter) == 0)
+               adapter->flags |= USING_MSIX;
+       else {
+               if (msi == MSI_MSIX) {
+                       dev_info(adapter->pdev_dev,
+                                "Unable to use MSI-X Interrupts; falling "
+                                "back to MSI Interrupts\n");
+
+                       /* We're going to need a Forwarded Interrupt Queue so
+                        * that may cut into how many Queue Sets we can
+                        * support.
+                        */
+                       msi = MSI_MSI;
+                       size_nports_qsets(adapter);
+               }
+               err = pci_enable_msi(pdev);
+               if (err) {
+                       dev_err(&pdev->dev, "Unable to allocate MSI Interrupts;"
+                               " err=%d\n", err);
+                       goto err_free_dev;
+               }
+               adapter->flags |= USING_MSI;
+       }
+
+       /* Now that we know how many "ports" we have and what interrupt
+        * mechanism we're going to use, we can configure our queue resources.
+        */
+       cfg_queues(adapter);
+
        /*
         * The "card" is now ready to go.  If any errors occur during device
         * registration we do not fail the whole "card" but rather proceed
@@ -2806,10 +2827,14 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
         * must register at least one net device.
         */
        for_each_port(adapter, pidx) {
+               struct port_info *pi = netdev_priv(adapter->port[pidx]);
                netdev = adapter->port[pidx];
                if (netdev == NULL)
                        continue;
 
+               netif_set_real_num_tx_queues(netdev, pi->nqsets);
+               netif_set_real_num_rx_queues(netdev, pi->nqsets);
+
                err = register_netdev(netdev);
                if (err) {
                        dev_warn(&pdev->dev, "cannot register net device %s,"
@@ -2821,7 +2846,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
        }
        if (adapter->registered_device_map == 0) {
                dev_err(&pdev->dev, "could not register any net devices\n");
-               goto err_free_dev;
+               goto err_disable_interrupts;
        }
 
        /*
@@ -2838,32 +2863,6 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
                        setup_debugfs(adapter);
        }
 
-       /*
-        * See what interrupts we'll be using.  If we've been configured to
-        * use MSI-X interrupts, try to enable them but fall back to using
-        * MSI interrupts if we can't enable MSI-X interrupts.  If we can't
-        * get MSI interrupts we bail with the error.
-        */
-       if (msi == MSI_MSIX && enable_msix(adapter) == 0)
-               adapter->flags |= USING_MSIX;
-       else {
-               err = pci_enable_msi(pdev);
-               if (err) {
-                       dev_err(&pdev->dev, "Unable to allocate %s interrupts;"
-                               " err=%d\n",
-                               msi == MSI_MSIX ? "MSI-X or MSI" : "MSI", err);
-                       goto err_free_debugfs;
-               }
-               adapter->flags |= USING_MSI;
-       }
-
-       /*
-        * Now that we know how many "ports" we have and what their types are,
-        * and how many Queue Sets we can support, we can configure our queue
-        * resources.
-        */
-       cfg_queues(adapter);
-
        /*
         * Print a short notice on the existence and configuration of the new
         * VF network device ...
@@ -2884,11 +2883,13 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
         * Error recovery and exit code.  Unwind state that's been created
         * so far and return the error.
         */
-
-err_free_debugfs:
-       if (!IS_ERR_OR_NULL(adapter->debugfs_root)) {
-               cleanup_debugfs(adapter);
-               debugfs_remove_recursive(adapter->debugfs_root);
+err_disable_interrupts:
+       if (adapter->flags & USING_MSIX) {
+               pci_disable_msix(adapter->pdev);
+               adapter->flags &= ~USING_MSIX;
+       } else if (adapter->flags & USING_MSI) {
+               pci_disable_msi(adapter->pdev);
+               adapter->flags &= ~USING_MSI;
        }
 
 err_free_dev:
index 6528231d8a59d0e7d8a2551b6e8312442ffd9d36..1ccd282949a5496ea15122857ba2bc293ed99668 100644 (file)
@@ -1864,7 +1864,7 @@ static int process_responses(struct sge_rspq *rspq, int budget)
         * for new buffer pointers, refill the Free List.
         */
        if (rspq->offset >= 0 &&
-           rxq->fl.size - rxq->fl.avail >= 2*FL_PER_EQ_UNIT)
+           fl_cap(&rxq->fl) - rxq->fl.avail >= 2*FL_PER_EQ_UNIT)
                __refill_fl(rspq->adapter, &rxq->fl);
        return budget - budget_left;
 }
@@ -2300,9 +2300,20 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
                                FW_IQ_CMD_FL0HOSTFCMODE_V(SGE_HOSTFCMODE_NONE) |
                                FW_IQ_CMD_FL0PACKEN_F |
                                FW_IQ_CMD_FL0PADEN_F);
+
+               /* In T6, for egress queue type FL there is internal overhead
+                * of 16B for header going into FLM module.  Hence the maximum
+                * allowed burst size is 448 bytes.  For T4/T5, the hardware
+                * doesn't coalesce fetch requests if more than 64 bytes of
+                * Free List pointers are provided, so we use a 128-byte Fetch
+                * Burst Minimum there (T6 implements coalescing so we can use
+                * the smaller 64-byte value there).
+                */
                cmd.fl0dcaen_to_fl0cidxfthresh =
                        cpu_to_be16(
-                               FW_IQ_CMD_FL0FBMIN_V(SGE_FETCHBURSTMIN_64B) |
+                               FW_IQ_CMD_FL0FBMIN_V(chip <= CHELSIO_T5 ?
+                                                    FETCHBURSTMIN_128B_X :
+                                                    FETCHBURSTMIN_64B_X) |
                                FW_IQ_CMD_FL0FBMAX_V((chip <= CHELSIO_T5) ?
                                                     FETCHBURSTMAX_512B_X :
                                                     FETCHBURSTMAX_256B_X));
@@ -2607,7 +2618,6 @@ int t4vf_sge_init(struct adapter *adapter)
        u32 fl0 = sge_params->sge_fl_buffer_size[0];
        u32 fl1 = sge_params->sge_fl_buffer_size[1];
        struct sge *s = &adapter->sge;
-       unsigned int ingpadboundary, ingpackboundary, ingpad_shift;
 
        /*
         * Start by vetting the basic SGE parameters which have been set up by
@@ -2619,7 +2629,8 @@ int t4vf_sge_init(struct adapter *adapter)
                        fl0, fl1);
                return -EINVAL;
        }
-       if ((sge_params->sge_control & RXPKTCPLMODE_F) == 0) {
+       if ((sge_params->sge_control & RXPKTCPLMODE_F) !=
+           RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) {
                dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n");
                return -EINVAL;
        }
@@ -2632,41 +2643,7 @@ int t4vf_sge_init(struct adapter *adapter)
        s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F)
                        ? 128 : 64);
        s->pktshift = PKTSHIFT_G(sge_params->sge_control);
-
-       /* T4 uses a single control field to specify both the PCIe Padding and
-        * Packing Boundary.  T5 introduced the ability to specify these
-        * separately.  The actual Ingress Packet Data alignment boundary
-        * within Packed Buffer Mode is the maximum of these two
-        * specifications.  (Note that it makes no real practical sense to
-        * have the Pading Boudary be larger than the Packing Boundary but you
-        * could set the chip up that way and, in fact, legacy T4 code would
-        * end doing this because it would initialize the Padding Boundary and
-        * leave the Packing Boundary initialized to 0 (16 bytes).)
-        * Padding Boundary values in T6 starts from 8B,
-        * where as it is 32B for T4 and T5.
-        */
-       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
-               ingpad_shift = INGPADBOUNDARY_SHIFT_X;
-       else
-               ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
-
-       ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_params->sge_control) +
-                              ingpad_shift);
-       if (is_t4(adapter->params.chip)) {
-               s->fl_align = ingpadboundary;
-       } else {
-               /* T5 has a different interpretation of one of the PCIe Packing
-                * Boundary values.
-                */
-               ingpackboundary = INGPACKBOUNDARY_G(sge_params->sge_control2);
-               if (ingpackboundary == INGPACKBOUNDARY_16B_X)
-                       ingpackboundary = 16;
-               else
-                       ingpackboundary = 1 << (ingpackboundary +
-                                               INGPACKBOUNDARY_SHIFT_X);
-
-               s->fl_align = max(ingpadboundary, ingpackboundary);
-       }
+       s->fl_align = t4vf_fl_pkt_align(adapter);
 
        /* A FL with <= fl_starve_thres buffers is starving and a periodic
         * timer will attempt to refill it.  This needs to be larger than the
index 88b8981b47517ecf302667751ee86e8495d118ba..9b40a85cc1e4feae33df1b95ebccb92129b4c84d 100644 (file)
@@ -285,12 +285,31 @@ static inline int is_t4(enum chip_type chip)
        return CHELSIO_CHIP_VERSION(chip) == CHELSIO_T4;
 }
 
+/**
+ *     hash_mac_addr - return the hash value of a MAC address
+ *     @addr: the 48-bit Ethernet MAC address
+ *
+ *     Hashes a MAC address according to the hash function used by hardware
+ *     inexact (hash) address matching.
+ */
+static inline int hash_mac_addr(const u8 *addr)
+{
+       u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
+       u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
+
+       a ^= b;
+       a ^= (a >> 12);
+       a ^= (a >> 6);
+       return a & 0x3f;
+}
+
 int t4vf_wait_dev_ready(struct adapter *);
 int t4vf_port_init(struct adapter *, int);
 
 int t4vf_fw_reset(struct adapter *);
 int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
 
+int t4vf_fl_pkt_align(struct adapter *adapter);
 enum t4_bar2_qtype { T4_BAR2_QTYPE_EGRESS, T4_BAR2_QTYPE_INGRESS };
 int t4vf_bar2_sge_qregs(struct adapter *adapter,
                        unsigned int qid,
@@ -320,6 +339,8 @@ int t4vf_set_rxmode(struct adapter *, unsigned int, int, int, int, int, int,
                    bool);
 int t4vf_alloc_mac_filt(struct adapter *, unsigned int, bool, unsigned int,
                        const u8 **, u16 *, u64 *, bool);
+int t4vf_free_mac_filt(struct adapter *, unsigned int, unsigned int naddr,
+                      const u8 **, bool);
 int t4vf_change_mac(struct adapter *, unsigned int, int, const u8 *, bool);
 int t4vf_set_addr_hash(struct adapter *, unsigned int, bool, u64, bool);
 int t4vf_get_port_stats(struct adapter *, int, struct t4vf_port_stats *);
index b6fa74aafe4771246baf16af218d6a5c7e54670a..fed83d88fc4ef09082078e3aad2f7f45beaece94 100644 (file)
@@ -236,23 +236,6 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
        return -ETIMEDOUT;
 }
 
-/**
- *     hash_mac_addr - return the hash value of a MAC address
- *     @addr: the 48-bit Ethernet MAC address
- *
- *     Hashes a MAC address according to the hash function used by hardware
- *     inexact (hash) address matching.
- */
-static int hash_mac_addr(const u8 *addr)
-{
-       u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
-       u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
-       a ^= b;
-       a ^= (a >> 12);
-       a ^= (a >> 6);
-       return a & 0x3f;
-}
-
 #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
                     FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
                     FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG)
@@ -434,6 +417,61 @@ int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
        return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
 }
 
+/**
+ *     t4vf_fl_pkt_align - return the fl packet alignment
+ *     @adapter: the adapter
+ *
+ *     T4 has a single field to specify the packing and padding boundary.
+ *     T5 onwards has separate fields for this and hence the alignment for
+ *     next packet offset is maximum of these two.  And T6 changes the
+ *     Ingress Padding Boundary Shift, so it's all a mess and it's best
+ *     if we put this in low-level Common Code ...
+ *
+ */
+int t4vf_fl_pkt_align(struct adapter *adapter)
+{
+       u32 sge_control, sge_control2;
+       unsigned int ingpadboundary, ingpackboundary, fl_align, ingpad_shift;
+
+       sge_control = adapter->params.sge.sge_control;
+
+       /* T4 uses a single control field to specify both the PCIe Padding and
+        * Packing Boundary.  T5 introduced the ability to specify these
+        * separately.  The actual Ingress Packet Data alignment boundary
+        * within Packed Buffer Mode is the maximum of these two
+        * specifications.  (Note that it makes no real practical sense to
+        * have the Pading Boudary be larger than the Packing Boundary but you
+        * could set the chip up that way and, in fact, legacy T4 code would
+        * end doing this because it would initialize the Padding Boundary and
+        * leave the Packing Boundary initialized to 0 (16 bytes).)
+        * Padding Boundary values in T6 starts from 8B,
+        * where as it is 32B for T4 and T5.
+        */
+       if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+               ingpad_shift = INGPADBOUNDARY_SHIFT_X;
+       else
+               ingpad_shift = T6_INGPADBOUNDARY_SHIFT_X;
+
+       ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) + ingpad_shift);
+
+       fl_align = ingpadboundary;
+       if (!is_t4(adapter->params.chip)) {
+               /* T5 has a different interpretation of one of the PCIe Packing
+                * Boundary values.
+                */
+               sge_control2 = adapter->params.sge.sge_control2;
+               ingpackboundary = INGPACKBOUNDARY_G(sge_control2);
+               if (ingpackboundary == INGPACKBOUNDARY_16B_X)
+                       ingpackboundary = 16;
+               else
+                       ingpackboundary = 1 << (ingpackboundary +
+                                               INGPACKBOUNDARY_SHIFT_X);
+
+               fl_align = max(ingpadboundary, ingpackboundary);
+       }
+       return fl_align;
+}
+
 /**
  *     t4vf_bar2_sge_qregs - return BAR2 SGE Queue register information
  *     @adapter: the adapter
@@ -1265,6 +1303,77 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
        return ret;
 }
 
+/**
+ *     t4vf_free_mac_filt - frees exact-match filters of given MAC addresses
+ *     @adapter: the adapter
+ *     @viid: the VI id
+ *     @naddr: the number of MAC addresses to allocate filters for (up to 7)
+ *     @addr: the MAC address(es)
+ *     @sleep_ok: call is allowed to sleep
+ *
+ *     Frees the exact-match filter for each of the supplied addresses
+ *
+ *     Returns a negative error number or the number of filters freed.
+ */
+int t4vf_free_mac_filt(struct adapter *adapter, unsigned int viid,
+                      unsigned int naddr, const u8 **addr, bool sleep_ok)
+{
+       int offset, ret = 0;
+       struct fw_vi_mac_cmd cmd;
+       unsigned int nfilters = 0;
+       unsigned int max_naddr = adapter->params.arch.mps_tcam_size;
+       unsigned int rem = naddr;
+
+       if (naddr > max_naddr)
+               return -EINVAL;
+
+       for (offset = 0; offset < (int)naddr ; /**/) {
+               unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) ?
+                                        rem : ARRAY_SIZE(cmd.u.exact));
+               size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+                                                    u.exact[fw_naddr]), 16);
+               struct fw_vi_mac_exact *p;
+               int i;
+
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
+                                    FW_CMD_EXEC_V(0) |
+                                    FW_VI_MAC_CMD_VIID_V(viid));
+               cmd.freemacs_to_len16 =
+                               cpu_to_be32(FW_VI_MAC_CMD_FREEMACS_V(0) |
+                                           FW_CMD_LEN16_V(len16));
+
+               for (i = 0, p = cmd.u.exact; i < (int)fw_naddr; i++, p++) {
+                       p->valid_to_idx = cpu_to_be16(
+                               FW_VI_MAC_CMD_VALID_F |
+                               FW_VI_MAC_CMD_IDX_V(FW_VI_MAC_MAC_BASED_FREE));
+                       memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
+               }
+
+               ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &cmd,
+                                       sleep_ok);
+               if (ret)
+                       break;
+
+               for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
+                       u16 index = FW_VI_MAC_CMD_IDX_G(
+                                               be16_to_cpu(p->valid_to_idx));
+
+                       if (index < max_naddr)
+                               nfilters++;
+               }
+
+               offset += fw_naddr;
+               rem -= fw_naddr;
+       }
+
+       if (ret == 0)
+               ret = nfilters;
+       return ret;
+}
+
 /**
  *     t4vf_change_mac - modifies the exact-match filter for a MAC address
  *     @adapter: the adapter
index 1671fa3332c2d3011db8c308a17ea5a9bf8b3fb2..130f910e47854958e7278c255eee742dd5f46d2b 100644 (file)
@@ -33,7 +33,7 @@
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION            "2.3.0.12"
+#define DRV_VERSION            "2.3.0.20"
 #define DRV_COPYRIGHT          "Copyright 2008-2013 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX          6
@@ -201,16 +201,20 @@ static inline struct net_device *vnic_get_netdev(struct vnic_dev *vdev)
 }
 
 /* wrappers function for kernel log
- * Make sure variable vdev of struct vnic_dev is available in the block where
- * these macros are used
  */
-#define vdev_info(args...)     dev_info(&vdev->pdev->dev, args)
-#define vdev_warn(args...)     dev_warn(&vdev->pdev->dev, args)
-#define vdev_err(args...)      dev_err(&vdev->pdev->dev, args)
-
-#define vdev_netinfo(args...)  netdev_info(vnic_get_netdev(vdev), args)
-#define vdev_netwarn(args...)  netdev_warn(vnic_get_netdev(vdev), args)
-#define vdev_neterr(args...)   netdev_err(vnic_get_netdev(vdev), args)
+#define vdev_err(vdev, fmt, ...)                                       \
+       dev_err(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
+#define vdev_warn(vdev, fmt, ...)                                      \
+       dev_warn(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
+#define vdev_info(vdev, fmt, ...)                                      \
+       dev_info(&(vdev)->pdev->dev, fmt, ##__VA_ARGS__)
+
+#define vdev_neterr(vdev, fmt, ...)                                    \
+       netdev_err(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
+#define vdev_netwarn(vdev, fmt, ...)                                   \
+       netdev_warn(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
+#define vdev_netinfo(vdev, fmt, ...)                                   \
+       netdev_info(vnic_get_netdev(vdev), fmt, ##__VA_ARGS__)
 
 static inline struct device *enic_get_dev(struct enic *enic)
 {
index abeda2a9ea273745f532f0a17732ed8630898bb4..9c682aff38343d1a92b88afc948eca757524dfda 100644 (file)
@@ -43,7 +43,7 @@ int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
 
        cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
        if (!cq->ctrl) {
-               vdev_err("Failed to hook CQ[%d] resource\n", index);
+               vdev_err(vdev, "Failed to hook CQ[%d] resource\n", index);
                return -EINVAL;
        }
 
index 1ffd1050860bb5cde576fd291e0651b351d578ff..8f27df3207bc0799d78c36b8b539caef1ad84ea4 100644 (file)
@@ -53,14 +53,14 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
                return -EINVAL;
 
        if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
-               vdev_err("vNIC BAR0 res hdr length error\n");
+               vdev_err(vdev, "vNIC BAR0 res hdr length error\n");
                return -EINVAL;
        }
 
        rh  = bar->vaddr;
        mrh = bar->vaddr;
        if (!rh) {
-               vdev_err("vNIC BAR0 res hdr not mem-mapped\n");
+               vdev_err(vdev, "vNIC BAR0 res hdr not mem-mapped\n");
                return -EINVAL;
        }
 
@@ -69,7 +69,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
                (ioread32(&rh->version) != VNIC_RES_VERSION)) {
                if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) ||
                        (ioread32(&mrh->version) != MGMTVNIC_VERSION)) {
-                       vdev_err("vNIC BAR0 res magic/version error exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
+                       vdev_err(vdev, "vNIC BAR0 res magic/version error exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
                                 VNIC_RES_MAGIC, VNIC_RES_VERSION,
                                 MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
                                 ioread32(&rh->magic), ioread32(&rh->version));
@@ -106,7 +106,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
                        /* each count is stride bytes long */
                        len = count * VNIC_RES_STRIDE;
                        if (len + bar_offset > bar[bar_num].len) {
-                               vdev_err("vNIC BAR0 resource %d out-of-bounds, offset 0x%x + size 0x%x > bar len 0x%lx\n",
+                               vdev_err(vdev, "vNIC BAR0 resource %d out-of-bounds, offset 0x%x + size 0x%x > bar len 0x%lx\n",
                                         type, bar_offset, len,
                                         bar[bar_num].len);
                                return -EINVAL;
@@ -198,7 +198,7 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
                &ring->base_addr_unaligned);
 
        if (!ring->descs_unaligned) {
-               vdev_err("Failed to allocate ring (size=%d), aborting\n",
+               vdev_err(vdev, "Failed to allocate ring (size=%d), aborting\n",
                         (int)ring->size);
                return -ENOMEM;
        }
@@ -241,7 +241,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
                return -ENODEV;
        }
        if (status & STAT_BUSY) {
-               vdev_neterr("Busy devcmd %d\n", _CMD_N(cmd));
+               vdev_neterr(vdev, "Busy devcmd %d\n", _CMD_N(cmd));
                return -EBUSY;
        }
 
@@ -275,7 +275,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
                                        return -err;
                                if (err != ERR_ECMDUNKNOWN ||
                                    cmd != CMD_CAPABILITY)
-                                       vdev_neterr("Error %d devcmd %d\n",
+                                       vdev_neterr(vdev, "Error %d devcmd %d\n",
                                                    err, _CMD_N(cmd));
                                return -err;
                        }
@@ -290,7 +290,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
                }
        }
 
-       vdev_neterr("Timedout devcmd %d\n", _CMD_N(cmd));
+       vdev_neterr(vdev, "Timedout devcmd %d\n", _CMD_N(cmd));
        return -ETIMEDOUT;
 }
 
@@ -298,7 +298,8 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
                          int wait)
 {
        struct devcmd2_controller *dc2c = vdev->devcmd2;
-       struct devcmd2_result *result = dc2c->result + dc2c->next_result;
+       struct devcmd2_result *result;
+       u8 color;
        unsigned int i;
        int delay, err;
        u32 fetch_index, new_posted;
@@ -312,7 +313,7 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
        new_posted = (posted + 1) % DEVCMD2_RING_SIZE;
 
        if (new_posted == fetch_index) {
-               vdev_neterr("devcmd2 %d: wq is full. fetch index: %u, posted index: %u\n",
+               vdev_neterr(vdev, "devcmd2 %d: wq is full. fetch index: %u, posted index: %u\n",
                            _CMD_N(cmd), fetch_index, posted);
                return -EBUSY;
        }
@@ -336,18 +337,22 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
        if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)
                return 0;
 
+       result = dc2c->result + dc2c->next_result;
+       color = dc2c->color;
+
+       dc2c->next_result++;
+       if (dc2c->next_result == dc2c->result_size) {
+               dc2c->next_result = 0;
+               dc2c->color = dc2c->color ? 0 : 1;
+       }
+
        for (delay = 0; delay < wait; delay++) {
-               if (result->color == dc2c->color) {
-                       dc2c->next_result++;
-                       if (dc2c->next_result == dc2c->result_size) {
-                               dc2c->next_result = 0;
-                               dc2c->color = dc2c->color ? 0 : 1;
-                       }
+               if (result->color == color) {
                        if (result->error) {
                                err = result->error;
                                if (err != ERR_ECMDUNKNOWN ||
                                    cmd != CMD_CAPABILITY)
-                                       vdev_neterr("Error %d devcmd %d\n",
+                                       vdev_neterr(vdev, "Error %d devcmd %d\n",
                                                    err, _CMD_N(cmd));
                                return -err;
                        }
@@ -360,7 +365,7 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
                udelay(100);
        }
 
-       vdev_neterr("devcmd %d timed out\n", _CMD_N(cmd));
+       vdev_neterr(vdev, "devcmd %d timed out\n", _CMD_N(cmd));
 
        return -ETIMEDOUT;
 }
@@ -396,7 +401,7 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
 
        fetch_index = ioread32(&vdev->devcmd2->wq.ctrl->fetch_index);
        if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone  */
-               vdev_err("Fatal error in devcmd2 init - hardware surprise removal");
+               vdev_err(vdev, "Fatal error in devcmd2 init - hardware surprise removal\n");
 
                return -ENODEV;
        }
@@ -469,8 +474,8 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
                err = (int)vdev->args[1];
                if (err != ERR_ECMDUNKNOWN ||
                    cmd != CMD_CAPABILITY)
-                       vdev_neterr("Error %d proxy devcmd %d\n", err,
-                                   _CMD_N(cmd));
+                       vdev_neterr(vdev, "Error %d proxy devcmd %d\n",
+                                   err, _CMD_N(cmd));
                return err;
        }
 
@@ -763,7 +768,7 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
 
        err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
        if (err)
-               vdev_neterr("Can't set packet filter\n");
+               vdev_neterr(vdev, "Can't set packet filter\n");
 
        return err;
 }
@@ -780,7 +785,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, const u8 *addr)
 
        err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
        if (err)
-               vdev_neterr("Can't add addr [%pM], %d\n", addr, err);
+               vdev_neterr(vdev, "Can't add addr [%pM], %d\n", addr, err);
 
        return err;
 }
@@ -797,7 +802,7 @@ int vnic_dev_del_addr(struct vnic_dev *vdev, const u8 *addr)
 
        err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
        if (err)
-               vdev_neterr("Can't del addr [%pM], %d\n", addr, err);
+               vdev_neterr(vdev, "Can't del addr [%pM], %d\n", addr, err);
 
        return err;
 }
@@ -841,7 +846,8 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
        dma_addr_t notify_pa;
 
        if (vdev->notify || vdev->notify_pa) {
-               vdev_neterr("notify block %p still allocated", vdev->notify);
+               vdev_neterr(vdev, "notify block %p still allocated\n",
+                           vdev->notify);
                return -EINVAL;
        }
 
@@ -960,7 +966,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
         */
        if ((err == ERR_ECMDUNKNOWN) ||
                (!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) {
-               vdev_netwarn("Using default conversion factor for interrupt coalesce timer\n");
+               vdev_netwarn(vdev, "Using default conversion factor for interrupt coalesce timer\n");
                vnic_dev_intr_coal_timer_info_default(vdev);
                return 0;
        }
@@ -1098,16 +1104,16 @@ int vnic_devcmd_init(struct vnic_dev *vdev)
        if (res) {
                err = vnic_dev_init_devcmd2(vdev);
                if (err)
-                       vdev_warn("DEVCMD2 init failed: %d, Using DEVCMD1",
+                       vdev_warn(vdev, "DEVCMD2 init failed: %d, Using DEVCMD1\n",
                                  err);
                else
                        return 0;
        } else {
-               vdev_warn("DEVCMD2 resource not found (old firmware?) Using DEVCMD1\n");
+               vdev_warn(vdev, "DEVCMD2 resource not found (old firmware?) Using DEVCMD1\n");
        }
        err = vnic_dev_init_devcmd1(vdev);
        if (err)
-               vdev_err("DEVCMD1 initialization failed: %d", err);
+               vdev_err(vdev, "DEVCMD1 initialization failed: %d\n", err);
 
        return err;
 }
index 942759d9cb3c4f4a932839fb8e9ea028a6f4a459..23604e3d4455eb279c749bad598327de91141f5f 100644 (file)
@@ -40,7 +40,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
 
        intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
        if (!intr->ctrl) {
-               vdev_err("Failed to hook INTR[%d].ctrl resource\n", index);
+               vdev_err(vdev, "Failed to hook INTR[%d].ctrl resource\n",
+                        index);
                return -EINVAL;
        }
 
index cce2777dfc415dc1da33b2e4866127edd095f90c..e572a527b18dd593c54e52e33386481fc9fbe95b 100644 (file)
@@ -92,7 +92,7 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
 
        rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
        if (!rq->ctrl) {
-               vdev_err("Failed to hook RQ[%d] resource\n", index);
+               vdev_err(vdev, "Failed to hook RQ[%d] resource\n", index);
                return -EINVAL;
        }
 
@@ -179,7 +179,7 @@ int vnic_rq_disable(struct vnic_rq *rq)
                udelay(10);
        }
 
-       vdev_neterr("Failed to disable RQ[%d]\n", rq->index);
+       vdev_neterr(vdev, "Failed to disable RQ[%d]\n", rq->index);
 
        return -ETIMEDOUT;
 }
index 05ad16a7e872054b1c6d2e3a4a87235e4ef2c29f..090cc65658a3237beeb0fc16e3501e77a2d69c57 100644 (file)
@@ -95,7 +95,7 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
 
        wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
        if (!wq->ctrl) {
-               vdev_err("Failed to hook WQ[%d] resource\n", index);
+               vdev_err(vdev, "Failed to hook WQ[%d] resource\n", index);
                return -EINVAL;
        }
 
@@ -187,7 +187,7 @@ int vnic_wq_disable(struct vnic_wq *wq)
                udelay(10);
        }
 
-       vdev_neterr("Failed to disable WQ[%d]\n", wq->index);
+       vdev_neterr(vdev, "Failed to disable WQ[%d]\n", wq->index);
 
        return -ETIMEDOUT;
 }
index cf94b72dbacd942b9c56d2bc669854bea7c2ac18..48d91941408d8fe3aa148c632ff33c1ea4201335 100644 (file)
@@ -128,7 +128,6 @@ struct board_info {
        struct resource *data_res;
        struct resource *addr_req;   /* resources requested */
        struct resource *data_req;
-       struct resource *irq_res;
 
        int              irq_wake;
 
@@ -1300,22 +1299,16 @@ static int
 dm9000_open(struct net_device *dev)
 {
        struct board_info *db = netdev_priv(dev);
-       unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
 
        if (netif_msg_ifup(db))
                dev_dbg(db->dev, "enabling %s\n", dev->name);
 
-       /* If there is no IRQ type specified, default to something that
-        * may work, and tell the user that this is a problem */
-
-       if (irqflags == IRQF_TRIGGER_NONE)
-               irqflags = irq_get_trigger_type(dev->irq);
-
-       if (irqflags == IRQF_TRIGGER_NONE)
+       /* If there is no IRQ type specified, tell the user that this is a
+        * problem
+        */
+       if (irq_get_trigger_type(dev->irq) == IRQF_TRIGGER_NONE)
                dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
 
-       irqflags |= IRQF_SHARED;
-
        /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
        iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        mdelay(1); /* delay needs by DM9000B */
@@ -1323,7 +1316,8 @@ dm9000_open(struct net_device *dev)
        /* Initialize DM9000 board */
        dm9000_init_dm9000(dev);
 
-       if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
+       if (request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED,
+                       dev->name, dev))
                return -EAGAIN;
        /* Now that we have an interrupt handler hooked up we can unmask
         * our interrupts
@@ -1500,15 +1494,22 @@ dm9000_probe(struct platform_device *pdev)
 
        db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
-       if (db->addr_res == NULL || db->data_res == NULL ||
-           db->irq_res == NULL) {
-               dev_err(db->dev, "insufficient resources\n");
+       if (!db->addr_res || !db->data_res) {
+               dev_err(db->dev, "insufficient resources addr=%p data=%p\n",
+                       db->addr_res, db->data_res);
                ret = -ENOENT;
                goto out;
        }
 
+       ndev->irq = platform_get_irq(pdev, 0);
+       if (ndev->irq < 0) {
+               dev_err(db->dev, "interrupt resource unavailable: %d\n",
+                       ndev->irq);
+               ret = ndev->irq;
+               goto out;
+       }
+
        db->irq_wake = platform_get_irq(pdev, 1);
        if (db->irq_wake >= 0) {
                dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
@@ -1570,7 +1571,6 @@ dm9000_probe(struct platform_device *pdev)
 
        /* fill in parameters for net-dev structure */
        ndev->base_addr = (unsigned long)db->io_addr;
-       ndev->irq       = db->irq_res->start;
 
        /* ensure at least we have a default set of IO routines */
        dm9000_set_io(db, iosize);
index b553409e04ad33ed50fafe3bdaa8de74d965e6eb..94d0eebef129fa2b5c27622d223e34c3d999c96f 100644 (file)
@@ -505,9 +505,7 @@ media_picked:
        tp->timer.expires = RUN_AT(next_tick);
        add_timer(&tp->timer);
 #ifdef CONFIG_TULIP_NAPI
-       init_timer(&tp->oom_timer);
-        tp->oom_timer.data = (unsigned long)dev;
-        tp->oom_timer.function = oom_timer;
+       setup_timer(&tp->oom_timer, oom_timer, (unsigned long)dev);
 #endif
 }
 
@@ -782,9 +780,8 @@ static void tulip_down (struct net_device *dev)
 
        spin_unlock_irqrestore (&tp->lock, flags);
 
-       init_timer(&tp->timer);
-       tp->timer.data = (unsigned long)dev;
-       tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+       setup_timer(&tp->timer, tulip_tbl[tp->chip_id].media_timer,
+                   (unsigned long)dev);
 
        dev->if_port = tp->saved_if_port;
 
@@ -1475,9 +1472,8 @@ static int tulip_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        tp->csr0 = csr0;
        spin_lock_init(&tp->lock);
        spin_lock_init(&tp->mii_lock);
-       init_timer(&tp->timer);
-       tp->timer.data = (unsigned long)dev;
-       tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+       setup_timer(&tp->timer, tulip_tbl[tp->chip_id].media_timer,
+                   (unsigned long)dev);
 
        INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task);
 
index ab24f84060c64d5eeaffd885c6c368ab6b82a2b2..fe3763df3f130ce98ddfc0868debc193144c4b3d 100644 (file)
@@ -72,6 +72,9 @@
 #define BE_MAX_MTU              (BE_MAX_JUMBO_FRAME_SIZE -     \
                                 (ETH_HLEN + ETH_FCS_LEN))
 
+/* Accommodate for QnQ configurations where VLAN insertion is enabled in HW */
+#define BE_MAX_GSO_SIZE                (65535 - 2 * VLAN_HLEN)
+
 #define BE_NUM_VLANS_SUPPORTED 64
 #define BE_MAX_EQD             128u
 #define        BE_MAX_TX_FRAG_COUNT    30
@@ -124,27 +127,27 @@ struct be_dma_mem {
 };
 
 struct be_queue_info {
+       u32 len;
+       u32 entry_size; /* Size of an element in the queue */
+       u32 tail, head;
+       atomic_t used;  /* Number of valid elements in the queue */
+       u32 id;
        struct be_dma_mem dma_mem;
-       u16 len;
-       u16 entry_size; /* Size of an element in the queue */
-       u16 id;
-       u16 tail, head;
        bool created;
-       atomic_t used;  /* Number of valid elements in the queue */
 };
 
-static inline u32 MODULO(u16 val, u16 limit)
+static inline u32 MODULO(u32 val, u32 limit)
 {
        BUG_ON(limit & (limit - 1));
        return val & (limit - 1);
 }
 
-static inline void index_adv(u16 *index, u16 val, u16 limit)
+static inline void index_adv(u32 *index, u32 val, u32 limit)
 {
        *index = MODULO((*index + val), limit);
 }
 
-static inline void index_inc(u16 *index, u16 limit)
+static inline void index_inc(u32 *index, u32 limit)
 {
        *index = MODULO((*index + 1), limit);
 }
@@ -169,7 +172,7 @@ static inline void queue_head_inc(struct be_queue_info *q)
        index_inc(&q->head, q->len);
 }
 
-static inline void index_dec(u16 *index, u16 limit)
+static inline void index_dec(u32 *index, u32 limit)
 {
        *index = MODULO((*index - 1), limit);
 }
@@ -542,6 +545,7 @@ struct be_adapter {
        struct delayed_work be_err_detection_work;
        u8 recovery_retries;
        u8 err_flags;
+       bool pcicfg_mapped;     /* pcicfg obtained via pci_iomap() */
        u32 flags;
        u32 cmd_privileges;
        /* Ethtool knobs and info */
index 66fa21426fe28080b76b1a31092dd1ee110d44c0..22402db275f282f099fe9f329df0c78ec723b7cf 100644 (file)
@@ -596,7 +596,7 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
        int status;
        struct be_mcc_wrb *wrb;
        struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
-       u16 index = mcc_obj->q.head;
+       u32 index = mcc_obj->q.head;
        struct be_cmd_resp_hdr *resp;
 
        index_dec(&index, mcc_obj->q.len);
index 0b9f741f31af52b1a40404199a78b355b8db725c..d8540ae95e5aeea1dbcee207d6f13374d34852e6 100644 (file)
@@ -666,10 +666,13 @@ enum be_if_flags {
                                         BE_IF_FLAGS_VLAN_PROMISCUOUS |\
                                         BE_IF_FLAGS_MCAST_PROMISCUOUS)
 
-#define BE_IF_EN_FLAGS (BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |\
-                       BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_UNTAGGED)
+#define BE_IF_FILT_FLAGS_BASIC (BE_IF_FLAGS_BROADCAST | \
+                               BE_IF_FLAGS_PASS_L3L4_ERRORS | \
+                               BE_IF_FLAGS_UNTAGGED)
 
-#define BE_IF_ALL_FILT_FLAGS   (BE_IF_EN_FLAGS | BE_IF_FLAGS_ALL_PROMISCUOUS)
+#define BE_IF_ALL_FILT_FLAGS   (BE_IF_FILT_FLAGS_BASIC | \
+                                BE_IF_FLAGS_MULTICAST | \
+                                BE_IF_FLAGS_ALL_PROMISCUOUS)
 
 /* An RX interface is an object with one or more MAC addresses and
  * filtering capabilities. */
index 88f427cb76c391f734a1e3bc12b6ff0be092a6ad..536686476369bfb242ceca0e28a436d150a1ed15 100644 (file)
@@ -125,6 +125,11 @@ static const char * const ue_status_hi_desc[] = {
        "Unknown"
 };
 
+#define BE_VF_IF_EN_FLAGS      (BE_IF_FLAGS_UNTAGGED | \
+                                BE_IF_FLAGS_BROADCAST | \
+                                BE_IF_FLAGS_MULTICAST | \
+                                BE_IF_FLAGS_PASS_L3L4_ERRORS)
+
 static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
 {
        struct be_dma_mem *mem = &q->dma_mem;
@@ -849,9 +854,9 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
 }
 
 /* Grab a WRB header for xmit */
-static u16 be_tx_get_wrb_hdr(struct be_tx_obj *txo)
+static u32 be_tx_get_wrb_hdr(struct be_tx_obj *txo)
 {
-       u16 head = txo->q.head;
+       u32 head = txo->q.head;
 
        queue_head_inc(&txo->q);
        return head;
@@ -895,7 +900,7 @@ static void be_tx_setup_wrb_frag(struct be_tx_obj *txo, dma_addr_t busaddr,
  * WRBs of the current packet are unmapped. Invoked to handle tx setup errors.
  */
 static void be_xmit_restore(struct be_adapter *adapter,
-                           struct be_tx_obj *txo, u16 head, bool map_single,
+                           struct be_tx_obj *txo, u32 head, bool map_single,
                            u32 copied)
 {
        struct device *dev;
@@ -930,7 +935,7 @@ static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
        struct device *dev = &adapter->pdev->dev;
        struct be_queue_info *txq = &txo->q;
        bool map_single = false;
-       u16 head = txq->head;
+       u32 head = txq->head;
        dma_addr_t busaddr;
        int len;
 
@@ -1123,6 +1128,8 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
                                           struct sk_buff *skb,
                                           struct be_wrb_params *wrb_params)
 {
+       int err;
+
        /* Lancer, SH and BE3 in SRIOV mode have a bug wherein
         * packets that are 32b or less may cause a transmit stall
         * on that port. The workaround is to pad such packets
@@ -1139,6 +1146,13 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
                        return NULL;
        }
 
+       /* The stack can send us skbs with length greater than
+        * what the HW can handle. Trim the extra bytes.
+        */
+       WARN_ON_ONCE(skb->len > BE_MAX_GSO_SIZE);
+       err = pskb_trim(skb, BE_MAX_GSO_SIZE);
+       WARN_ON(err);
+
        return skb;
 }
 
@@ -1990,7 +2004,7 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
        struct be_adapter *adapter = rxo->adapter;
        struct be_rx_page_info *rx_page_info;
        struct be_queue_info *rxq = &rxo->q;
-       u16 frag_idx = rxq->tail;
+       u32 frag_idx = rxq->tail;
 
        rx_page_info = &rxo->page_info_tbl[frag_idx];
        BUG_ON(!rx_page_info->page);
@@ -2401,10 +2415,11 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
 {
        struct sk_buff **sent_skbs = txo->sent_skb_list;
        struct be_queue_info *txq = &txo->q;
-       u16 frag_index, num_wrbs = 0;
        struct sk_buff *skb = NULL;
        bool unmap_skb_hdr = false;
        struct be_eth_wrb *wrb;
+       u16 num_wrbs = 0;
+       u32 frag_index;
 
        do {
                if (sent_skbs[txq->tail]) {
@@ -2516,10 +2531,11 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
 
 static void be_tx_compl_clean(struct be_adapter *adapter)
 {
-       u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
        struct device *dev = &adapter->pdev->dev;
+       u16 cmpl = 0, timeo = 0, num_wrbs = 0;
        struct be_tx_compl_info *txcp;
        struct be_queue_info *txq;
+       u32 end_idx, notified_idx;
        struct be_tx_obj *txo;
        int i, pending_txqs;
 
@@ -3547,7 +3563,7 @@ static int be_enable_if_filters(struct be_adapter *adapter)
 {
        int status;
 
-       status = be_cmd_rx_filter(adapter, BE_IF_EN_FLAGS, ON);
+       status = be_cmd_rx_filter(adapter, BE_IF_FILT_FLAGS_BASIC, ON);
        if (status)
                return status;
 
@@ -3864,8 +3880,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)
        int status;
 
        /* If a FW profile exists, then cap_flags are updated */
-       cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                   BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       cap_flags = BE_VF_IF_EN_FLAGS;
 
        for_all_vfs(adapter, vf_cfg, vf) {
                if (!BE3_chip(adapter)) {
@@ -3881,10 +3896,8 @@ static int be_vfs_if_create(struct be_adapter *adapter)
                        }
                }
 
-               en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
-                                       BE_IF_FLAGS_BROADCAST |
-                                       BE_IF_FLAGS_MULTICAST |
-                                       BE_IF_FLAGS_PASS_L3L4_ERRORS);
+               /* PF should enable IF flags during proxy if_create call */
+               en_flags = cap_flags & BE_VF_IF_EN_FLAGS;
                status = be_cmd_if_create(adapter, cap_flags, en_flags,
                                          &vf_cfg->if_handle, vf + 1);
                if (status)
@@ -4848,7 +4861,7 @@ static void be_netdev_init(struct net_device *netdev)
 
        netdev->flags |= IFF_MULTICAST;
 
-       netif_set_gso_max_size(netdev, 65535 - ETH_HLEN);
+       netif_set_gso_max_size(netdev, BE_MAX_GSO_SIZE - ETH_HLEN);
 
        netdev->netdev_ops = &be_netdev_ops;
 
@@ -5029,6 +5042,8 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
                pci_iounmap(adapter->pdev, adapter->csr);
        if (adapter->db)
                pci_iounmap(adapter->pdev, adapter->db);
+       if (adapter->pcicfg && adapter->pcicfg_mapped)
+               pci_iounmap(adapter->pdev, adapter->pcicfg);
 }
 
 static int db_bar(struct be_adapter *adapter)
@@ -5080,8 +5095,10 @@ static int be_map_pci_bars(struct be_adapter *adapter)
                        if (!addr)
                                goto pci_map_err;
                        adapter->pcicfg = addr;
+                       adapter->pcicfg_mapped = true;
                } else {
                        adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
+                       adapter->pcicfg_mapped = false;
                }
        }
 
@@ -5456,6 +5473,8 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
 
        dev_err(&adapter->pdev->dev, "EEH error detected\n");
 
+       be_roce_dev_remove(adapter);
+
        if (!be_check_error(adapter, BE_ERROR_EEH)) {
                be_set_error(adapter, BE_ERROR_EEH);
 
@@ -5520,6 +5539,8 @@ static void be_eeh_resume(struct pci_dev *pdev)
        if (status)
                goto err;
 
+       be_roce_dev_add(adapter);
+
        be_schedule_err_detection(adapter, ERR_DETECTION_DELAY);
        return;
 err:
index 62fa136554ac29a49074e5f176b3fc9ac8d37042..41b01064510098c00a66d86bb49cf2f3fe02f9c3 100644 (file)
@@ -1265,7 +1265,6 @@ static int ethoc_remove(struct platform_device *pdev)
 
                if (priv->mdio) {
                        mdiobus_unregister(priv->mdio);
-                       kfree(priv->mdio->irq);
                        mdiobus_free(priv->mdio);
                }
                if (priv->clk)
index b1026689b78f4075d30b240b4f8dc625d3b9299a..1f23845a0694b5e64eaaa0f71ffca230d54feaf0 100644 (file)
@@ -43,20 +43,21 @@ static void nps_enet_read_rx_fifo(struct net_device *ndev,
        bool dst_is_aligned = IS_ALIGNED((unsigned long)dst, sizeof(u32));
 
        /* In case dst is not aligned we need an intermediate buffer */
-       if (dst_is_aligned)
-               for (i = 0; i < len; i++, reg++)
-                       *reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+       if (dst_is_aligned) {
+               ioread32_rep(priv->regs_base + NPS_ENET_REG_RX_BUF, reg, len);
+               reg += len;
+       }
        else { /* !dst_is_aligned */
                for (i = 0; i < len; i++, reg++) {
                        u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-                       put_unaligned(buf, reg);
+                       put_unaligned_be32(buf, reg);
                }
        }
-
        /* copy last bytes (if any) */
        if (last) {
-               u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-               memcpy((u8*)reg, &buf, last);
+               u32 buf;
+               ioread32_rep(priv->regs_base + NPS_ENET_REG_RX_BUF, &buf, 1);
+               memcpy((u8 *)reg, &buf, last);
        }
 }
 
@@ -66,26 +67,28 @@ static u32 nps_enet_rx_handler(struct net_device *ndev)
        u32 work_done = 0;
        struct nps_enet_priv *priv = netdev_priv(ndev);
        struct sk_buff *skb;
-       struct nps_enet_rx_ctl rx_ctrl;
+       u32 rx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
+       u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT;
+       u32 rx_ctrl_er = (rx_ctrl_value & RX_CTL_ER_MASK) >> RX_CTL_ER_SHIFT;
+       u32 rx_ctrl_crc = (rx_ctrl_value & RX_CTL_CRC_MASK) >> RX_CTL_CRC_SHIFT;
 
-       rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
-       frame_len = rx_ctrl.nr;
+       frame_len = (rx_ctrl_value & RX_CTL_NR_MASK) >> RX_CTL_NR_SHIFT;
 
        /* Check if we got RX */
-       if (!rx_ctrl.cr)
+       if (!rx_ctrl_cr)
                return work_done;
 
        /* If we got here there is a work for us */
        work_done++;
 
        /* Check Rx error */
-       if (rx_ctrl.er) {
+       if (rx_ctrl_er) {
                ndev->stats.rx_errors++;
                err = 1;
        }
 
        /* Check Rx CRC error */
-       if (rx_ctrl.crc) {
+       if (rx_ctrl_crc) {
                ndev->stats.rx_crc_errors++;
                ndev->stats.rx_dropped++;
                err = 1;
@@ -136,23 +139,24 @@ rx_irq_frame_done:
 static void nps_enet_tx_handler(struct net_device *ndev)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_tx_ctl tx_ctrl;
-
-       tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
+       u32 tx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
+       u32 tx_ctrl_ct = (tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT;
+       u32 tx_ctrl_et = (tx_ctrl_value & TX_CTL_ET_MASK) >> TX_CTL_ET_SHIFT;
+       u32 tx_ctrl_nt = (tx_ctrl_value & TX_CTL_NT_MASK) >> TX_CTL_NT_SHIFT;
 
        /* Check if we got TX */
-       if (!priv->tx_packet_sent || tx_ctrl.ct)
+       if (!priv->tx_packet_sent || tx_ctrl_ct)
                return;
 
        /* Ack Tx ctrl register */
        nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, 0);
 
        /* Check Tx transmit error */
-       if (unlikely(tx_ctrl.et)) {
+       if (unlikely(tx_ctrl_et)) {
                ndev->stats.tx_errors++;
        } else {
                ndev->stats.tx_packets++;
-               ndev->stats.tx_bytes += tx_ctrl.nt;
+               ndev->stats.tx_bytes += tx_ctrl_nt;
        }
 
        dev_kfree_skb(priv->tx_skb);
@@ -178,13 +182,16 @@ static int nps_enet_poll(struct napi_struct *napi, int budget)
        nps_enet_tx_handler(ndev);
        work_done = nps_enet_rx_handler(ndev);
        if (work_done < budget) {
-               struct nps_enet_buf_int_enable buf_int_enable;
+               u32 buf_int_enable_value = 0;
 
                napi_complete(napi);
-               buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
-               buf_int_enable.tx_done = NPS_ENET_ENABLE;
+
+               /* set tx_done and rx_rdy bits */
+               buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT;
+               buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT;
+
                nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
-                                buf_int_enable.value);
+                                buf_int_enable_value);
        }
 
        return work_done;
@@ -205,13 +212,12 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
 {
        struct net_device *ndev = dev_instance;
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_rx_ctl rx_ctrl;
-       struct nps_enet_tx_ctl tx_ctrl;
-
-       rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
-       tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
+       u32 rx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL);
+       u32 tx_ctrl_value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL);
+       u32 tx_ctrl_ct = (tx_ctrl_value & TX_CTL_CT_MASK) >> TX_CTL_CT_SHIFT;
+       u32 rx_ctrl_cr = (rx_ctrl_value & RX_CTL_CR_MASK) >> RX_CTL_CR_SHIFT;
 
-       if ((!tx_ctrl.ct && priv->tx_packet_sent) || rx_ctrl.cr)
+       if ((!tx_ctrl_ct && priv->tx_packet_sent) || rx_ctrl_cr)
                if (likely(napi_schedule_prep(&priv->napi))) {
                        nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0);
                        __napi_schedule(&priv->napi);
@@ -223,22 +229,24 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance)
 static void nps_enet_set_hw_mac_address(struct net_device *ndev)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_ge_mac_cfg_1 ge_mac_cfg_1;
-       struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
+       u32 ge_mac_cfg_1_value = 0;
+       u32 *ge_mac_cfg_2_value = &priv->ge_mac_cfg_2_value;
 
        /* set MAC address in HW */
-       ge_mac_cfg_1.octet_0 = ndev->dev_addr[0];
-       ge_mac_cfg_1.octet_1 = ndev->dev_addr[1];
-       ge_mac_cfg_1.octet_2 = ndev->dev_addr[2];
-       ge_mac_cfg_1.octet_3 = ndev->dev_addr[3];
-       ge_mac_cfg_2->octet_4 = ndev->dev_addr[4];
-       ge_mac_cfg_2->octet_5 = ndev->dev_addr[5];
+       ge_mac_cfg_1_value |= ndev->dev_addr[0] << CFG_1_OCTET_0_SHIFT;
+       ge_mac_cfg_1_value |= ndev->dev_addr[1] << CFG_1_OCTET_1_SHIFT;
+       ge_mac_cfg_1_value |= ndev->dev_addr[2] << CFG_1_OCTET_2_SHIFT;
+       ge_mac_cfg_1_value |= ndev->dev_addr[3] << CFG_1_OCTET_3_SHIFT;
+       *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_OCTET_4_MASK)
+                | ndev->dev_addr[4] << CFG_2_OCTET_4_SHIFT;
+       *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_OCTET_5_MASK)
+                | ndev->dev_addr[5] << CFG_2_OCTET_5_SHIFT;
 
        nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_1,
-                        ge_mac_cfg_1.value);
+                        ge_mac_cfg_1_value);
 
        nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
-                        ge_mac_cfg_2->value);
+                        *ge_mac_cfg_2_value);
 }
 
 /**
@@ -254,93 +262,97 @@ static void nps_enet_set_hw_mac_address(struct net_device *ndev)
 static void nps_enet_hw_reset(struct net_device *ndev)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_ge_rst ge_rst;
-       struct nps_enet_phase_fifo_ctl phase_fifo_ctl;
+       u32 ge_rst_value = 0, phase_fifo_ctl_value = 0;
 
-       ge_rst.value = 0;
-       phase_fifo_ctl.value = 0;
        /* Pcs reset sequence*/
-       ge_rst.gmac_0 = NPS_ENET_ENABLE;
-       nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
+       ge_rst_value |= NPS_ENET_ENABLE << RST_GMAC_0_SHIFT;
+       nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value);
        usleep_range(10, 20);
-       ge_rst.value = 0;
-       nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst.value);
+       nps_enet_reg_set(priv, NPS_ENET_REG_GE_RST, ge_rst_value);
 
        /* Tx fifo reset sequence */
-       phase_fifo_ctl.rst = NPS_ENET_ENABLE;
-       phase_fifo_ctl.init = NPS_ENET_ENABLE;
+       phase_fifo_ctl_value |= NPS_ENET_ENABLE << PHASE_FIFO_CTL_RST_SHIFT;
+       phase_fifo_ctl_value |= NPS_ENET_ENABLE << PHASE_FIFO_CTL_INIT_SHIFT;
        nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
-                        phase_fifo_ctl.value);
+                        phase_fifo_ctl_value);
        usleep_range(10, 20);
-       phase_fifo_ctl.value = 0;
+       phase_fifo_ctl_value = 0;
        nps_enet_reg_set(priv, NPS_ENET_REG_PHASE_FIFO_CTL,
-                        phase_fifo_ctl.value);
+                        phase_fifo_ctl_value);
 }
 
 static void nps_enet_hw_enable_control(struct net_device *ndev)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_ge_mac_cfg_0 ge_mac_cfg_0;
-       struct nps_enet_buf_int_enable buf_int_enable;
-       struct nps_enet_ge_mac_cfg_2 *ge_mac_cfg_2 = &priv->ge_mac_cfg_2;
-       struct nps_enet_ge_mac_cfg_3 *ge_mac_cfg_3 = &priv->ge_mac_cfg_3;
+       u32 ge_mac_cfg_0_value = 0, buf_int_enable_value = 0;
+       u32 *ge_mac_cfg_2_value = &priv->ge_mac_cfg_2_value;
+       u32 *ge_mac_cfg_3_value = &priv->ge_mac_cfg_3_value;
        s32 max_frame_length;
 
-       ge_mac_cfg_0.value = 0;
-       buf_int_enable.value = 0;
        /* Enable Rx and Tx statistics */
-       ge_mac_cfg_2->stat_en = NPS_ENET_GE_MAC_CFG_2_STAT_EN;
+       *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_STAT_EN_MASK)
+                | NPS_ENET_GE_MAC_CFG_2_STAT_EN << CFG_2_STAT_EN_SHIFT;
 
        /* Discard packets with different MAC address */
-       ge_mac_cfg_2->disc_da = NPS_ENET_ENABLE;
+       *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK)
+                | NPS_ENET_ENABLE << CFG_2_DISK_DA_SHIFT;
 
        /* Discard multicast packets */
-       ge_mac_cfg_2->disc_mc = NPS_ENET_ENABLE;
+       *ge_mac_cfg_2_value = (*ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK)
+                | NPS_ENET_ENABLE << CFG_2_DISK_MC_SHIFT;
 
        nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2,
-                        ge_mac_cfg_2->value);
+                        *ge_mac_cfg_2_value);
 
        /* Discard Packets bigger than max frame length */
        max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN;
-       if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH)
-               ge_mac_cfg_3->max_len = max_frame_length;
+       if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) {
+               *ge_mac_cfg_3_value =
+                        (*ge_mac_cfg_3_value & ~CFG_3_MAX_LEN_MASK)
+                        | max_frame_length << CFG_3_MAX_LEN_SHIFT;
+       }
 
        /* Enable interrupts */
-       buf_int_enable.rx_rdy = NPS_ENET_ENABLE;
-       buf_int_enable.tx_done = NPS_ENET_ENABLE;
+       buf_int_enable_value |= NPS_ENET_ENABLE << RX_RDY_SHIFT;
+       buf_int_enable_value |= NPS_ENET_ENABLE << TX_DONE_SHIFT;
        nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE,
-                        buf_int_enable.value);
+                        buf_int_enable_value);
 
        /* Write device MAC address to HW */
        nps_enet_set_hw_mac_address(ndev);
 
        /* Rx and Tx HW features */
-       ge_mac_cfg_0.tx_pad_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.tx_crc_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.rx_crc_strip = NPS_ENET_ENABLE;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_PAD_EN_SHIFT;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_CRC_EN_SHIFT;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_CRC_STRIP_SHIFT;
 
        /* IFG configuration */
-       ge_mac_cfg_0.rx_ifg = NPS_ENET_GE_MAC_CFG_0_RX_IFG;
-       ge_mac_cfg_0.tx_ifg = NPS_ENET_GE_MAC_CFG_0_TX_IFG;
+       ge_mac_cfg_0_value |=
+                NPS_ENET_GE_MAC_CFG_0_RX_IFG << CFG_0_RX_IFG_SHIFT;
+       ge_mac_cfg_0_value |=
+                NPS_ENET_GE_MAC_CFG_0_TX_IFG << CFG_0_TX_IFG_SHIFT;
 
        /* preamble configuration */
-       ge_mac_cfg_0.rx_pr_check_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.tx_pr_len = NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_PR_CHECK_EN_SHIFT;
+       ge_mac_cfg_0_value |=
+                NPS_ENET_GE_MAC_CFG_0_TX_PR_LEN << CFG_0_TX_PR_LEN_SHIFT;
 
        /* enable flow control frames */
-       ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR;
-       ge_mac_cfg_3->cf_drop = NPS_ENET_ENABLE;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_FC_EN_SHIFT;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_FC_EN_SHIFT;
+       ge_mac_cfg_0_value |=
+                NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR << CFG_0_TX_FC_RETR_SHIFT;
+       *ge_mac_cfg_3_value = (*ge_mac_cfg_3_value & ~CFG_3_CF_DROP_MASK)
+                | NPS_ENET_ENABLE << CFG_3_CF_DROP_SHIFT;
 
        /* Enable Rx and Tx */
-       ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE;
-       ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_RX_EN_SHIFT;
+       ge_mac_cfg_0_value |= NPS_ENET_ENABLE << CFG_0_TX_EN_SHIFT;
 
        nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3,
-                        ge_mac_cfg_3->value);
+                        *ge_mac_cfg_3_value);
        nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0,
-                        ge_mac_cfg_0.value);
+                        ge_mac_cfg_0_value);
 }
 
 static void nps_enet_hw_disable_control(struct net_device *ndev)
@@ -358,31 +370,28 @@ static void nps_enet_send_frame(struct net_device *ndev,
                                struct sk_buff *skb)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_tx_ctl tx_ctrl;
+       u32 tx_ctrl_value = 0;
        short length = skb->len;
        u32 i, len = DIV_ROUND_UP(length, sizeof(u32));
        u32 *src = (void *)skb->data;
        bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32));
 
-       tx_ctrl.value = 0;
        /* In case src is not aligned we need an intermediate buffer */
        if (src_is_aligned)
-               for (i = 0; i < len; i++, src++)
-                       nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src);
+               iowrite32_rep(priv->regs_base + NPS_ENET_REG_TX_BUF, src, len);
        else /* !src_is_aligned */
                for (i = 0; i < len; i++, src++)
                        nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF,
-                                        get_unaligned(src));
+                                        get_unaligned_be32(src));
 
        /* Write the length of the Frame */
-       tx_ctrl.nt = length;
+       tx_ctrl_value |= length << TX_CTL_NT_SHIFT;
 
        /* Indicate SW is done */
        priv->tx_packet_sent = true;
-       tx_ctrl.ct = NPS_ENET_ENABLE;
-
+       tx_ctrl_value |= NPS_ENET_ENABLE << TX_CTL_CT_SHIFT;
        /* Send Frame */
-       nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl.value);
+       nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, tx_ctrl_value);
 }
 
 /**
@@ -422,19 +431,23 @@ static s32 nps_enet_set_mac_address(struct net_device *ndev, void *p)
 static void nps_enet_set_rx_mode(struct net_device *ndev)
 {
        struct nps_enet_priv *priv = netdev_priv(ndev);
-       struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
-
-       ge_mac_cfg_2.value = priv->ge_mac_cfg_2.value;
+       u32 ge_mac_cfg_2_value = priv->ge_mac_cfg_2_value;
 
        if (ndev->flags & IFF_PROMISC) {
-               ge_mac_cfg_2.disc_da = NPS_ENET_DISABLE;
-               ge_mac_cfg_2.disc_mc = NPS_ENET_DISABLE;
+               ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK)
+                        | NPS_ENET_DISABLE << CFG_2_DISK_DA_SHIFT;
+               ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK)
+                        | NPS_ENET_DISABLE << CFG_2_DISK_MC_SHIFT;
+
        } else {
-               ge_mac_cfg_2.disc_da = NPS_ENET_ENABLE;
-               ge_mac_cfg_2.disc_mc = NPS_ENET_ENABLE;
+               ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_DA_MASK)
+                        | NPS_ENET_ENABLE << CFG_2_DISK_DA_SHIFT;
+               ge_mac_cfg_2_value = (ge_mac_cfg_2_value & ~CFG_2_DISK_MC_MASK)
+                        | NPS_ENET_ENABLE << CFG_2_DISK_MC_SHIFT;
+
        }
 
-       nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2.value);
+       nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_2, ge_mac_cfg_2_value);
 }
 
 /**
@@ -453,12 +466,15 @@ static s32 nps_enet_open(struct net_device *ndev)
 
        /* Reset private variables */
        priv->tx_packet_sent = false;
-       priv->ge_mac_cfg_2.value = 0;
-       priv->ge_mac_cfg_3.value = 0;
+       priv->ge_mac_cfg_2_value = 0;
+       priv->ge_mac_cfg_3_value = 0;
 
        /* ge_mac_cfg_3 default values */
-       priv->ge_mac_cfg_3.rx_ifg_th = NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH;
-       priv->ge_mac_cfg_3.max_len = NPS_ENET_GE_MAC_CFG_3_MAX_LEN;
+       priv->ge_mac_cfg_3_value |=
+                NPS_ENET_GE_MAC_CFG_3_RX_IFG_TH << CFG_3_RX_IFG_TH_SHIFT;
+
+       priv->ge_mac_cfg_3_value |=
+                NPS_ENET_GE_MAC_CFG_3_MAX_LEN << CFG_3_MAX_LEN_SHIFT;
 
        /* Disable HW device */
        nps_enet_hw_disable_control(ndev);
index 6703674d679c964c00cac0ea12e084267df1ee47..d0cab600bce8d94bbfde1fbd30c2fca76fe2cb87 100644 (file)
 #define NPS_ENET_REG_GE_RST            0x1400
 #define NPS_ENET_REG_PHASE_FIFO_CTL    0x1404
 
-/* Tx control register */
-struct nps_enet_tx_ctl {
-       union {
-               /* ct: SW sets to indicate frame ready in Tx buffer for
-                *     transmission. HW resets to when transmission done
-                * et: Transmit error
-                * nt: Length in bytes of Tx frame loaded to Tx buffer
-                */
-               struct {
-                       u32
-                       __reserved_1:16,
-                       ct:1,
-                       et:1,
-                       __reserved_2:3,
-                       nt:11;
-               };
-
-               u32 value;
-       };
-};
-
-/* Rx control register */
-struct nps_enet_rx_ctl {
-       union {
-               /* cr:  HW sets to indicate frame ready in Rx buffer.
-                *      SW resets to indicate host read received frame
-                *      and new frames can be written to Rx buffer
-                * er:  Rx error indication
-                * crc: Rx CRC error indication
-                * nr:  Length in bytes of Rx frame loaded by MAC to Rx buffer
-                */
-               struct {
-                       u32
-                       __reserved_1:16,
-                       cr:1,
-                       er:1,
-                       crc:1,
-                       __reserved_2:2,
-                       nr:11;
-               };
-
-               u32 value;
-       };
-};
-
-/* Interrupt enable for data buffer events register */
-struct nps_enet_buf_int_enable {
-       union {
-               /* tx_done: Interrupt generation in the case when new frame
-                *          is ready in Rx buffer
-                * rx_rdy:  Interrupt generation in the case when current frame
-                *          was read from TX buffer
-                */
-               struct {
-                       u32
-                       __reserved:30,
-                       tx_done:1,
-                       rx_rdy:1;
-               };
-
-               u32 value;
-       };
-};
-
-/* Gbps Eth MAC Configuration 0 register */
-struct nps_enet_ge_mac_cfg_0 {
-       union {
-               /* tx_pr_len:          Transmit preamble length in bytes
-                * tx_ifg_nib:         Tx idle pattern
-                * nib_mode:           Nibble (4-bit) Mode
-                * rx_pr_check_en:     Receive preamble Check Enable
-                * tx_ifg:             Transmit inter-Frame Gap
-                * rx_ifg:             Receive inter-Frame Gap
-                * tx_fc_retr:         Transmit Flow Control Retransmit Mode
-                * rx_length_check_en: Receive Length Check Enable
-                * rx_crc_ignore:      Results of the CRC check are ignored
-                * rx_crc_strip:       MAC strips the CRC from received frames
-                * rx_fc_en:           Receive Flow Control Enable
-                * tx_crc_en:          Transmit CRC Enabled
-                * tx_pad_en:          Transmit Padding Enable
-                * tx_cf_en:           Transmit Flow Control Enable
-                * tx_en:              Transmit Enable
-                * rx_en:              Receive Enable
-                */
-               struct {
-                       u32
-                       tx_pr_len:4,
-                       tx_ifg_nib:4,
-                       nib_mode:1,
-                       rx_pr_check_en:1,
-                       tx_ifg:6,
-                       rx_ifg:4,
-                       tx_fc_retr:3,
-                       rx_length_check_en:1,
-                       rx_crc_ignore:1,
-                       rx_crc_strip:1,
-                       rx_fc_en:1,
-                       tx_crc_en:1,
-                       tx_pad_en:1,
-                       tx_fc_en:1,
-                       tx_en:1,
-                       rx_en:1;
-               };
-
-               u32 value;
-       };
-};
-
-/* Gbps Eth MAC Configuration 1 register */
-struct nps_enet_ge_mac_cfg_1 {
-       union {
-               /* octet_3: MAC address octet 3
-                * octet_2: MAC address octet 2
-                * octet_1: MAC address octet 1
-                * octet_0: MAC address octet 0
-                */
-               struct {
-                       u32
-                       octet_3:8,
-                       octet_2:8,
-                       octet_1:8,
-                       octet_0:8;
-               };
-
-               u32 value;
-       };
-};
-
-/* Gbps Eth MAC Configuration 2 register */
-struct nps_enet_ge_mac_cfg_2 {
-       union {
-               /* transmit_flush_en: MAC flush enable
-                * stat_en:           RMON statistics interface enable
-                * disc_da:           Discard frames with DA different
-                *                    from MAC address
-                * disc_bc:           Discard broadcast frames
-                * disc_mc:           Discard multicast frames
-                * octet_5:           MAC address octet 5
-                * octet_4:           MAC address octet 4
-                */
-               struct {
-                       u32
-                       transmit_flush_en:1,
-                       __reserved_1:5,
-                       stat_en:2,
-                       __reserved_2:1,
-                       disc_da:1,
-                       disc_bc:1,
-                       disc_mc:1,
-                       __reserved_3:4,
-                       octet_5:8,
-                       octet_4:8;
-               };
-
-               u32 value;
-       };
-};
-
-/* Gbps Eth MAC Configuration 3 register */
-struct nps_enet_ge_mac_cfg_3 {
-       union {
-               /* ext_oob_cbfc_sel:  Selects one of the 4 profiles for
-                *                    extended OOB in-flow-control indication
-                * max_len:           Maximum receive frame length in bytes
-                * tx_cbfc_en:        Enable transmission of class-based
-                *                    flow control packets
-                * rx_ifg_th:         Threshold for IFG status reporting via OOB
-                * cf_timeout:        Configurable time to decrement FC counters
-                * cf_drop:           Drop control frames
-                * redirect_cbfc_sel: Selects one of CBFC redirect profiles
-                * rx_cbfc_redir_en:  Enable Rx class-based flow
-                *                    control redirect
-                * rx_cbfc_en:        Enable Rx class-based flow control
-                * tm_hd_mode:        TM header mode
-                */
-               struct {
-                       u32
-                       ext_oob_cbfc_sel:2,
-                       max_len:14,
-                       tx_cbfc_en:1,
-                       rx_ifg_th:5,
-                       cf_timeout:4,
-                       cf_drop:1,
-                       redirect_cbfc_sel:2,
-                       rx_cbfc_redir_en:1,
-                       rx_cbfc_en:1,
-                       tm_hd_mode:1;
-               };
-
-               u32 value;
-       };
-};
-
-/* GE MAC, PCS reset control register */
-struct nps_enet_ge_rst {
-       union {
-               /* gmac_0: GE MAC reset
-                * spcs_0: SGMII PCS reset
-                */
-               struct {
-                       u32
-                       __reserved_1:23,
-                       gmac_0:1,
-                       __reserved_2:7,
-                       spcs_0:1;
-               };
-
-               u32 value;
-       };
-};
-
-/* Tx phase sync FIFO control register */
-struct nps_enet_phase_fifo_ctl {
-       union {
-               /* init: initialize serdes TX phase sync FIFO pointers
-                * rst:  reset serdes TX phase sync FIFO
-                */
-               struct {
-                       u32
-                       __reserved:30,
-                       init:1,
-                       rst:1;
-               };
-
-               u32 value;
-       };
-};
+/* Tx control register masks and shifts */
+#define TX_CTL_NT_MASK 0x7FF
+#define TX_CTL_NT_SHIFT 0
+#define TX_CTL_ET_MASK 0x4000
+#define TX_CTL_ET_SHIFT 14
+#define TX_CTL_CT_MASK 0x8000
+#define TX_CTL_CT_SHIFT 15
+
+/* Rx control register masks and shifts */
+#define RX_CTL_NR_MASK 0x7FF
+#define RX_CTL_NR_SHIFT 0
+#define RX_CTL_CRC_MASK 0x2000
+#define RX_CTL_CRC_SHIFT 13
+#define RX_CTL_ER_MASK 0x4000
+#define RX_CTL_ER_SHIFT 14
+#define RX_CTL_CR_MASK 0x8000
+#define RX_CTL_CR_SHIFT 15
+
+/* Interrupt enable for data buffer events register masks and shifts */
+#define RX_RDY_MASK 0x1
+#define RX_RDY_SHIFT 0
+#define TX_DONE_MASK 0x2
+#define TX_DONE_SHIFT 1
+
+/* Gbps Eth MAC Configuration 0 register masks and shifts */
+#define CFG_0_RX_EN_MASK 0x1
+#define CFG_0_RX_EN_SHIFT 0
+#define CFG_0_TX_EN_MASK 0x2
+#define CFG_0_TX_EN_SHIFT 1
+#define CFG_0_TX_FC_EN_MASK 0x4
+#define CFG_0_TX_FC_EN_SHIFT 2
+#define CFG_0_TX_PAD_EN_MASK 0x8
+#define CFG_0_TX_PAD_EN_SHIFT 3
+#define CFG_0_TX_CRC_EN_MASK 0x10
+#define CFG_0_TX_CRC_EN_SHIFT 4
+#define CFG_0_RX_FC_EN_MASK 0x20
+#define CFG_0_RX_FC_EN_SHIFT 5
+#define CFG_0_RX_CRC_STRIP_MASK 0x40
+#define CFG_0_RX_CRC_STRIP_SHIFT 6
+#define CFG_0_RX_CRC_IGNORE_MASK 0x80
+#define CFG_0_RX_CRC_IGNORE_SHIFT 7
+#define CFG_0_RX_LENGTH_CHECK_EN_MASK 0x100
+#define CFG_0_RX_LENGTH_CHECK_EN_SHIFT 8
+#define CFG_0_TX_FC_RETR_MASK 0xE00
+#define CFG_0_TX_FC_RETR_SHIFT 9
+#define CFG_0_RX_IFG_MASK 0xF000
+#define CFG_0_RX_IFG_SHIFT 12
+#define CFG_0_TX_IFG_MASK 0x3F0000
+#define CFG_0_TX_IFG_SHIFT 16
+#define CFG_0_RX_PR_CHECK_EN_MASK 0x400000
+#define CFG_0_RX_PR_CHECK_EN_SHIFT 22
+#define CFG_0_NIB_MODE_MASK 0x800000
+#define CFG_0_NIB_MODE_SHIFT 23
+#define CFG_0_TX_IFG_NIB_MASK 0xF000000
+#define CFG_0_TX_IFG_NIB_SHIFT 24
+#define CFG_0_TX_PR_LEN_MASK 0xF0000000
+#define CFG_0_TX_PR_LEN_SHIFT 28
+
+/* Gbps Eth MAC Configuration 1 register masks and shifts */
+#define CFG_1_OCTET_0_MASK 0x000000FF
+#define CFG_1_OCTET_0_SHIFT 0
+#define CFG_1_OCTET_1_MASK 0x0000FF00
+#define CFG_1_OCTET_1_SHIFT 8
+#define CFG_1_OCTET_2_MASK 0x00FF0000
+#define CFG_1_OCTET_2_SHIFT 16
+#define CFG_1_OCTET_3_MASK 0xFF000000
+#define CFG_1_OCTET_3_SHIFT 24
+
+/* Gbps Eth MAC Configuration 2 register masks and shifts */
+#define CFG_2_OCTET_4_MASK 0x000000FF
+#define CFG_2_OCTET_4_SHIFT 0
+#define CFG_2_OCTET_5_MASK 0x0000FF00
+#define CFG_2_OCTET_5_SHIFT 8
+#define CFG_2_DISK_MC_MASK 0x00100000
+#define CFG_2_DISK_MC_SHIFT 20
+#define CFG_2_DISK_BC_MASK 0x00200000
+#define CFG_2_DISK_BC_SHIFT 21
+#define CFG_2_DISK_DA_MASK 0x00400000
+#define CFG_2_DISK_DA_SHIFT 22
+#define CFG_2_STAT_EN_MASK 0x3000000
+#define CFG_2_STAT_EN_SHIFT 24
+#define CFG_2_TRANSMIT_FLUSH_EN_MASK 0x80000000
+#define CFG_2_TRANSMIT_FLUSH_EN_SHIFT 31
+
+/* Gbps Eth MAC Configuration 3 register masks and shifts */
+#define CFG_3_TM_HD_MODE_MASK 0x1
+#define CFG_3_TM_HD_MODE_SHIFT 0
+#define CFG_3_RX_CBFC_EN_MASK 0x2
+#define CFG_3_RX_CBFC_EN_SHIFT 1
+#define CFG_3_RX_CBFC_REDIR_EN_MASK 0x4
+#define CFG_3_RX_CBFC_REDIR_EN_SHIFT 2
+#define CFG_3_REDIRECT_CBFC_SEL_MASK 0x18
+#define CFG_3_REDIRECT_CBFC_SEL_SHIFT 3
+#define CFG_3_CF_DROP_MASK 0x20
+#define CFG_3_CF_DROP_SHIFT 5
+#define CFG_3_CF_TIMEOUT_MASK 0x3C0
+#define CFG_3_CF_TIMEOUT_SHIFT 6
+#define CFG_3_RX_IFG_TH_MASK 0x7C00
+#define CFG_3_RX_IFG_TH_SHIFT 10
+#define CFG_3_TX_CBFC_EN_MASK 0x8000
+#define CFG_3_TX_CBFC_EN_SHIFT 15
+#define CFG_3_MAX_LEN_MASK 0x3FFF0000
+#define CFG_3_MAX_LEN_SHIFT 16
+#define CFG_3_EXT_OOB_CBFC_SEL_MASK 0xC0000000
+#define CFG_3_EXT_OOB_CBFC_SEL_SHIFT 30
+
+/* GE MAC, PCS reset control register masks and shifts */
+#define RST_SPCS_MASK 0x1
+#define RST_SPCS_SHIFT 0
+#define RST_GMAC_0_MASK 0x100
+#define RST_GMAC_0_SHIFT 8
+
+/* Tx phase sync FIFO control register masks and shifts */
+#define PHASE_FIFO_CTL_RST_MASK 0x1
+#define PHASE_FIFO_CTL_RST_SHIFT 0
+#define PHASE_FIFO_CTL_INIT_MASK 0x2
+#define PHASE_FIFO_CTL_INIT_SHIFT 1
 
 /**
  * struct nps_enet_priv - Storage of ENET's private information.
@@ -285,8 +175,8 @@ struct nps_enet_priv {
        bool tx_packet_sent;
        struct sk_buff *tx_skb;
        struct napi_struct napi;
-       struct nps_enet_ge_mac_cfg_2 ge_mac_cfg_2;
-       struct nps_enet_ge_mac_cfg_3 ge_mac_cfg_3;
+       u32 ge_mac_cfg_2_value;
+       u32 ge_mac_cfg_3_value;
 };
 
 /**
index ef18ca501f9ea6531c7d55eb212f9dfc553b547a..37c08158308433845f583671dc23d6db411178df 100644 (file)
@@ -3191,6 +3191,7 @@ static int fec_enet_init(struct net_device *ndev)
 static void fec_reset_phy(struct platform_device *pdev)
 {
        int err, phy_reset;
+       bool active_high = false;
        int msec = 1;
        struct device_node *np = pdev->dev.of_node;
 
@@ -3206,14 +3207,17 @@ static void fec_reset_phy(struct platform_device *pdev)
        if (!gpio_is_valid(phy_reset))
                return;
 
+       active_high = of_property_read_bool(np, "phy-reset-active-high");
+
        err = devm_gpio_request_one(&pdev->dev, phy_reset,
-                                   GPIOF_OUT_INIT_LOW, "phy-reset");
+                       active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+                       "phy-reset");
        if (err) {
                dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
                return;
        }
        msleep(msec);
-       gpio_set_value_cansleep(phy_reset, 1);
+       gpio_set_value_cansleep(phy_reset, !active_high);
 }
 #else /* CONFIG_OF */
 static void fec_reset_phy(struct platform_device *pdev)
index 623aa1c8ebc6ba3149fc529e04994496b2e7be18..79a210aaf0bbd69d86ce830a45909ae8ede07f83 100644 (file)
@@ -2791,6 +2791,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
                goto fman_free;
        }
 
+       fman->dev = &of_dev->dev;
+
        return fman;
 
 fman_node_put:
@@ -2845,8 +2847,6 @@ static int fman_probe(struct platform_device *of_dev)
 
        dev_set_drvdata(dev, fman);
 
-       fman->dev = dev;
-
        dev_dbg(dev, "FMan%d probed\n", fman->dts_params.id);
 
        return 0;
index 2aa7b401cc3be29eb24a8fb6d1065bff6caa6e39..08c0415483002e27a2c3a7584fccb412fd5085f7 100644 (file)
@@ -1111,8 +1111,10 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv)
 
        if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))
                priv->errata |= GFAR_ERRATA_12;
+       /* P2020/P1010 Rev 1; MPC8548 Rev 2 */
        if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) ||
-           ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)))
+           ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)) ||
+           ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) < 0x31)))
                priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
 }
 #endif
@@ -2322,6 +2324,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct txfcb *fcb = NULL;
        struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL;
        u32 lstatus;
+       skb_frag_t *frag;
        int i, rq = 0;
        int do_tstamp, do_csum, do_vlan;
        u32 bufaddr;
@@ -2389,52 +2392,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        txbdp = txbdp_start = tx_queue->cur_tx;
        lstatus = be32_to_cpu(txbdp->lstatus);
 
-       /* Time stamp insertion requires one additional TxBD */
-       if (unlikely(do_tstamp))
-               txbdp_tstamp = txbdp = next_txbd(txbdp, base,
-                                                tx_queue->tx_ring_size);
-
-       if (nr_frags == 0) {
-               if (unlikely(do_tstamp)) {
-                       u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus);
-
-                       lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
-                       txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);
-               } else {
-                       lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
-               }
-       } else {
-               /* Place the fragment addresses and lengths into the TxBDs */
-               for (i = 0; i < nr_frags; i++) {
-                       unsigned int frag_len;
-                       /* Point at the next BD, wrapping as needed */
-                       txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
-
-                       frag_len = skb_shinfo(skb)->frags[i].size;
-
-                       lstatus = be32_to_cpu(txbdp->lstatus) | frag_len |
-                                 BD_LFLAG(TXBD_READY);
-
-                       /* Handle the last BD specially */
-                       if (i == nr_frags - 1)
-                               lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
-
-                       bufaddr = skb_frag_dma_map(priv->dev,
-                                                  &skb_shinfo(skb)->frags[i],
-                                                  0,
-                                                  frag_len,
-                                                  DMA_TO_DEVICE);
-                       if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
-                               goto dma_map_err;
-
-                       /* set the TxBD length and buffer pointer */
-                       txbdp->bufPtr = cpu_to_be32(bufaddr);
-                       txbdp->lstatus = cpu_to_be32(lstatus);
-               }
-
-               lstatus = be32_to_cpu(txbdp_start->lstatus);
-       }
-
        /* Add TxPAL between FCB and frame if required */
        if (unlikely(do_tstamp)) {
                skb_push(skb, GMAC_TXPAL_LEN);
@@ -2469,12 +2426,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (do_vlan)
                gfar_tx_vlan(skb, fcb);
 
-       /* Setup tx hardware time stamping if requested */
-       if (unlikely(do_tstamp)) {
-               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-               fcb->ptp = 1;
-       }
-
        bufaddr = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
                                 DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
@@ -2482,6 +2433,46 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        txbdp_start->bufPtr = cpu_to_be32(bufaddr);
 
+       /* Time stamp insertion requires one additional TxBD */
+       if (unlikely(do_tstamp))
+               txbdp_tstamp = txbdp = next_txbd(txbdp, base,
+                                                tx_queue->tx_ring_size);
+
+       if (likely(!nr_frags)) {
+               lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+       } else {
+               u32 lstatus_start = lstatus;
+
+               /* Place the fragment addresses and lengths into the TxBDs */
+               frag = &skb_shinfo(skb)->frags[0];
+               for (i = 0; i < nr_frags; i++, frag++) {
+                       unsigned int size;
+
+                       /* Point at the next BD, wrapping as needed */
+                       txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
+
+                       size = skb_frag_size(frag);
+
+                       lstatus = be32_to_cpu(txbdp->lstatus) | size |
+                                 BD_LFLAG(TXBD_READY);
+
+                       /* Handle the last BD specially */
+                       if (i == nr_frags - 1)
+                               lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+
+                       bufaddr = skb_frag_dma_map(priv->dev, frag, 0,
+                                                  size, DMA_TO_DEVICE);
+                       if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
+                               goto dma_map_err;
+
+                       /* set the TxBD length and buffer pointer */
+                       txbdp->bufPtr = cpu_to_be32(bufaddr);
+                       txbdp->lstatus = cpu_to_be32(lstatus);
+               }
+
+               lstatus = lstatus_start;
+       }
+
        /* If time stamping is requested one additional TxBD must be set up. The
         * first TxBD points to the FCB and must have a data length of
         * GMAC_FCB_LEN. The second TxBD points to the actual frame data with
@@ -2492,12 +2483,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                bufaddr = be32_to_cpu(txbdp_start->bufPtr);
                bufaddr += fcb_len;
+
                lstatus_ts |= BD_LFLAG(TXBD_READY) |
                              (skb_headlen(skb) - fcb_len);
+               if (!nr_frags)
+                       lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
 
                txbdp_tstamp->bufPtr = cpu_to_be32(bufaddr);
                txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
+
+               /* Setup tx hardware time stamping */
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               fcb->ptp = 1;
        } else {
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
        }
@@ -2710,7 +2708,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                                          ~0x7UL);
 
                        memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-                       shhwtstamps.hwtstamp = ns_to_ktime(*ns);
+                       shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
                        skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
                        skb_tstamp_tx(skb, &shhwtstamps);
                        gfar_clear_txbd_status(bdp);
@@ -3039,7 +3037,7 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
                u64 *ns = (u64 *) skb->data;
 
                memset(shhwtstamps, 0, sizeof(*shhwtstamps));
-               shhwtstamps->hwtstamp = ns_to_ktime(*ns);
+               shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
        }
 
        if (priv->padding)
index b40fba929d650d282c23f5d96636806ef4797d48..57798814160dca157d9576448a04e06bfc183255 100644 (file)
@@ -422,19 +422,6 @@ static struct ptp_clock_info ptp_gianfar_caps = {
        .enable         = ptp_gianfar_enable,
 };
 
-/* OF device tree */
-
-static int get_of_u32(struct device_node *node, char *str, u32 *val)
-{
-       int plen;
-       const u32 *prop = of_get_property(node, str, &plen);
-
-       if (!prop || plen != sizeof(*prop))
-               return -1;
-       *val = *prop;
-       return 0;
-}
-
 static int gianfar_ptp_probe(struct platform_device *dev)
 {
        struct device_node *node = dev->dev.of_node;
@@ -452,15 +439,21 @@ static int gianfar_ptp_probe(struct platform_device *dev)
 
        etsects->caps = ptp_gianfar_caps;
 
-       if (get_of_u32(node, "fsl,cksel", &etsects->cksel))
+       if (of_property_read_u32(node, "fsl,cksel", &etsects->cksel))
                etsects->cksel = DEFAULT_CKSEL;
 
-       if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
-           get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
-           get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) ||
-           get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
-           get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
-           get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) {
+       if (of_property_read_u32(node,
+                                "fsl,tclk-period", &etsects->tclk_period) ||
+           of_property_read_u32(node,
+                                "fsl,tmr-prsc", &etsects->tmr_prsc) ||
+           of_property_read_u32(node,
+                                "fsl,tmr-add", &etsects->tmr_add) ||
+           of_property_read_u32(node,
+                                "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
+           of_property_read_u32(node,
+                                "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
+           of_property_read_u32(node,
+                                "fsl,max-adj", &etsects->caps.max_adj)) {
                pr_err("device tree node missing required elements\n");
                goto no_node;
        }
index a7139f588ad205e0a9441ce8e7d62a2513e4d814..678f5018d0be1c410c809fd8031a9f6e6601210e 100644 (file)
@@ -469,8 +469,8 @@ static int fmvj18x_config(struct pcmcia_device *link)
                    goto failed;
            }
            /* Read MACID from CIS */
-           for (i = 5; i < 11; i++)
-                   dev->dev_addr[i] = buf[i];
+           for (i = 0; i < 6; i++)
+                   dev->dev_addr[i] = buf[i + 5];
            kfree(buf);
        } else {
            if (pcmcia_get_mac_from_cis(link, dev))
index 74beb1867230c9cf62a60a2843825316e6d9cdbc..4ccc032633c4e57576b316cca8f0486a3e8b4a98 100644 (file)
@@ -25,6 +25,7 @@ config HIX5HD2_GMAC
 
 config HIP04_ETH
        tristate "HISILICON P04 Ethernet support"
+       depends on HAS_IOMEM    # For MFD_SYSCON
        select MARVELL_PHY
        select MFD_SYSCON
        select HNS_MDIO
index a0070d0e740dae5b3de8f2b2a92a772854b08321..d4f92ed322d6e5c4ac10a3f8d208d94445760e27 100644 (file)
@@ -675,8 +675,12 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,
 {
        int ret;
        struct hnae_vf_cb *vf_cb = hns_ae_get_vf_cb(handle);
+       struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);
 
        switch (loop) {
+       case MAC_INTERNALLOOP_PHY:
+               ret = 0;
+               break;
        case MAC_INTERNALLOOP_SERDES:
                ret = hns_mac_config_sds_loopback(vf_cb->mac_cb, en);
                break;
@@ -686,6 +690,10 @@ static int hns_ae_config_loopback(struct hnae_handle *handle,
        default:
                ret = -EINVAL;
        }
+
+       if (!ret)
+               hns_dsaf_set_inner_lb(mac_cb->dsaf_dev, mac_cb->mac_id, en);
+
        return ret;
 }
 
index 9439f04962e1d96bf480d8aedf6472c912e28813..38fc5be3870cc3258755e79d13ac501ffa0826e4 100644 (file)
@@ -230,6 +230,30 @@ static void hns_dsaf_mix_def_qid_cfg(struct dsaf_device *dsaf_dev)
        }
 }
 
+static void hns_dsaf_inner_qid_cfg(struct dsaf_device *dsaf_dev)
+{
+       u16 max_q_per_vf, max_vfn;
+       u32 q_id, q_num_per_port;
+       u32 mac_id;
+
+       if (AE_IS_VER1(dsaf_dev->dsaf_ver))
+               return;
+
+       hns_rcb_get_queue_mode(dsaf_dev->dsaf_mode,
+                              HNS_DSAF_COMM_SERVICE_NW_IDX,
+                              &max_vfn, &max_q_per_vf);
+       q_num_per_port = max_vfn * max_q_per_vf;
+
+       for (mac_id = 0, q_id = 0; mac_id < DSAF_SERVICE_NW_NUM; mac_id++) {
+               dsaf_set_dev_field(dsaf_dev,
+                                  DSAFV2_SERDES_LBK_0_REG + 4 * mac_id,
+                                  DSAFV2_SERDES_LBK_QID_M,
+                                  DSAFV2_SERDES_LBK_QID_S,
+                                  q_id);
+               q_id += q_num_per_port;
+       }
+}
+
 /**
  * hns_dsaf_sw_port_type_cfg - cfg sw type
  * @dsaf_id: dsa fabric id
@@ -691,6 +715,16 @@ void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en)
        dsaf_set_dev_bit(dsaf_dev, DSAF_CFG_0_REG, DSAF_CFG_MIX_MODE_S, !!en);
 }
 
+void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en)
+{
+       if (AE_IS_VER1(dsaf_dev->dsaf_ver) ||
+           dsaf_dev->mac_cb[mac_id].mac_type == HNAE_PORT_DEBUG)
+               return;
+
+       dsaf_set_dev_bit(dsaf_dev, DSAFV2_SERDES_LBK_0_REG + 4 * mac_id,
+                        DSAFV2_SERDES_LBK_EN_B, !!en);
+}
+
 /**
  * hns_dsaf_tbl_stat_en - tbl
  * @dsaf_id: dsa fabric id
@@ -1022,6 +1056,9 @@ static void hns_dsaf_comm_init(struct dsaf_device *dsaf_dev)
        /* set promisc def queue id */
        hns_dsaf_mix_def_qid_cfg(dsaf_dev);
 
+       /* set inner loopback queue id */
+       hns_dsaf_inner_qid_cfg(dsaf_dev);
+
        /* in non switch mode, set all port to access mode */
        hns_dsaf_sw_port_type_cfg(dsaf_dev, DSAF_SW_PORT_TYPE_NON_VLAN);
 
index 40205b910f80e66a439c14b53e7f2c907b0fbeb1..5fea226efaf330f968b2942a55065c7fc5c01112 100644 (file)
@@ -417,5 +417,6 @@ void hns_dsaf_get_strings(int stringset, u8 *data, int port);
 void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data);
 int hns_dsaf_get_regs_count(void);
 void hns_dsaf_set_promisc_mode(struct dsaf_device *dsaf_dev, u32 en);
+void hns_dsaf_set_inner_lb(struct dsaf_device *dsaf_dev, u32 mac_id, u32 en);
 
 #endif /* __HNS_DSAF_MAIN_H__ */
index f0c4f9b09d5b0477365c862816bc8b8d4dd19b88..60d695daa471eb23d5284778300807f8b235e546 100644 (file)
 #define DSAF_XGE_INT_STS_0_REG         0x1C0
 #define DSAF_PPE_INT_STS_0_REG         0x1E0
 #define DSAF_ROCEE_INT_STS_0_REG       0x200
+#define DSAFV2_SERDES_LBK_0_REG         0x220
 #define DSAF_PPE_QID_CFG_0_REG         0x300
 #define DSAF_SW_PORT_TYPE_0_REG                0x320
 #define DSAF_STP_PORT_TYPE_0_REG       0x340
 #define PPEV2_CFG_RSS_TBL_4N3_S        24
 #define PPEV2_CFG_RSS_TBL_4N3_M        (((1UL << 5) - 1) << PPEV2_CFG_RSS_TBL_4N3_S)
 
+#define DSAFV2_SERDES_LBK_EN_B  8
+#define DSAFV2_SERDES_LBK_QID_S 0
+#define DSAFV2_SERDES_LBK_QID_M        (((1UL << 8) - 1) << DSAFV2_SERDES_LBK_QID_S)
+
 #define PPE_CNT_CLR_CE_B       0
 #define PPE_CNT_CLR_SNAP_EN_B  1
 
index 3df22840fcd15370393e7e6a5c331b72dd87f476..3c4a3bc31a89230c2453c115316306739e28c2a3 100644 (file)
@@ -295,8 +295,10 @@ static int __lb_setup(struct net_device *ndev,
 
        switch (loop) {
        case MAC_INTERNALLOOP_PHY:
-               if ((phy_dev) && (!phy_dev->is_c45))
+               if ((phy_dev) && (!phy_dev->is_c45)) {
                        ret = hns_nic_config_phy_loopback(phy_dev, 0x1);
+                       ret |= h->dev->ops->set_loopback(h, loop, 0x1);
+               }
                break;
        case MAC_INTERNALLOOP_MAC:
                if ((h->dev->ops->set_loopback) &&
@@ -376,6 +378,7 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,
                               struct sk_buff *skb)
 {
        struct net_device *ndev;
+       struct hns_nic_priv *priv;
        struct hnae_ring *ring;
        struct netdev_queue *dev_queue;
        struct sk_buff *new_skb;
@@ -385,8 +388,17 @@ static void __lb_other_process(struct hns_nic_ring_data *ring_data,
        char buff[33]; /* 32B data and the last character '\0' */
 
        if (!ring_data) { /* Just for doing create frame*/
+               ndev = skb->dev;
+               priv = netdev_priv(ndev);
+
                frame_size = skb->len;
                memset(skb->data, 0xFF, frame_size);
+               if ((!AE_IS_VER1(priv->enet_ver)) &&
+                   (priv->ae_handle->port_type == HNAE_PORT_SERVICE)) {
+                       memcpy(skb->data, ndev->dev_addr, 6);
+                       skb->data[5] += 0x1f;
+               }
+
                frame_size &= ~1ul;
                memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
                memset(&skb->data[frame_size / 2 + 10], 0xBE,
@@ -486,6 +498,7 @@ static int __lb_run_test(struct net_device *ndev,
 
        /* place data into test skb */
        (void)skb_put(skb, size);
+       skb->dev = ndev;
        __lb_other_process(NULL, skb);
        skb->queue_mapping = NIC_LB_TEST_RING_ID;
 
index 335417b4756b73d3d2d9f1558b10b2556443bee7..ebe60719e489cd1fbdc12248ee48eed6d0979fd4 100644 (file)
@@ -1166,7 +1166,10 @@ map_failed:
        if (!firmware_has_feature(FW_FEATURE_CMO))
                netdev_err(netdev, "tx: unable to map xmit buffer\n");
        adapter->tx_map_failed++;
-       skb_linearize(skb);
+       if (skb_linearize(skb)) {
+               netdev->stats.tx_dropped++;
+               goto out;
+       }
        force_bounce = 1;
        goto retry_bounce;
 }
index 7d65708437238b48f5c5cdfcb1d901b202e2d547..6e9e16eee5d0eff7d74a2eff4a8a4bb91368afcd 100644 (file)
@@ -1348,44 +1348,44 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
        crq.request_capability.cmd = REQUEST_CAPABILITY;
 
        crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
-       crq.request_capability.number = cpu_to_be32(adapter->req_tx_queues);
+       crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
-       crq.request_capability.number = cpu_to_be32(adapter->req_rx_queues);
+       crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
-       crq.request_capability.number = cpu_to_be32(adapter->req_rx_add_queues);
+       crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
-           cpu_to_be32(adapter->req_tx_entries_per_subcrq);
+           cpu_to_be64(adapter->req_tx_entries_per_subcrq);
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability =
            cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
        crq.request_capability.number =
-           cpu_to_be32(adapter->req_rx_add_entries_per_subcrq);
+           cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
        ibmvnic_send_crq(adapter, &crq);
 
        crq.request_capability.capability = cpu_to_be16(REQ_MTU);
-       crq.request_capability.number = cpu_to_be32(adapter->req_mtu);
+       crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
        ibmvnic_send_crq(adapter, &crq);
 
        if (adapter->netdev->flags & IFF_PROMISC) {
                if (adapter->promisc_supported) {
                        crq.request_capability.capability =
                            cpu_to_be16(PROMISC_REQUESTED);
-                       crq.request_capability.number = cpu_to_be32(1);
+                       crq.request_capability.number = cpu_to_be64(1);
                        ibmvnic_send_crq(adapter, &crq);
                }
        } else {
                crq.request_capability.capability =
                    cpu_to_be16(PROMISC_REQUESTED);
-               crq.request_capability.number = cpu_to_be32(0);
+               crq.request_capability.number = cpu_to_be64(0);
                ibmvnic_send_crq(adapter, &crq);
        }
 
@@ -2312,93 +2312,93 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
        switch (be16_to_cpu(crq->query_capability.capability)) {
        case MIN_TX_QUEUES:
                adapter->min_tx_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_tx_queues = %lld\n",
                           adapter->min_tx_queues);
                break;
        case MIN_RX_QUEUES:
                adapter->min_rx_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_rx_queues = %lld\n",
                           adapter->min_rx_queues);
                break;
        case MIN_RX_ADD_QUEUES:
                adapter->min_rx_add_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_rx_add_queues = %lld\n",
                           adapter->min_rx_add_queues);
                break;
        case MAX_TX_QUEUES:
                adapter->max_tx_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_tx_queues = %lld\n",
                           adapter->max_tx_queues);
                break;
        case MAX_RX_QUEUES:
                adapter->max_rx_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_rx_queues = %lld\n",
                           adapter->max_rx_queues);
                break;
        case MAX_RX_ADD_QUEUES:
                adapter->max_rx_add_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_rx_add_queues = %lld\n",
                           adapter->max_rx_add_queues);
                break;
        case MIN_TX_ENTRIES_PER_SUBCRQ:
                adapter->min_tx_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_tx_entries_per_subcrq = %lld\n",
                           adapter->min_tx_entries_per_subcrq);
                break;
        case MIN_RX_ADD_ENTRIES_PER_SUBCRQ:
                adapter->min_rx_add_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_rx_add_entrs_per_subcrq = %lld\n",
                           adapter->min_rx_add_entries_per_subcrq);
                break;
        case MAX_TX_ENTRIES_PER_SUBCRQ:
                adapter->max_tx_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_tx_entries_per_subcrq = %lld\n",
                           adapter->max_tx_entries_per_subcrq);
                break;
        case MAX_RX_ADD_ENTRIES_PER_SUBCRQ:
                adapter->max_rx_add_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_rx_add_entrs_per_subcrq = %lld\n",
                           adapter->max_rx_add_entries_per_subcrq);
                break;
        case TCP_IP_OFFLOAD:
                adapter->tcp_ip_offload =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "tcp_ip_offload = %lld\n",
                           adapter->tcp_ip_offload);
                break;
        case PROMISC_SUPPORTED:
                adapter->promisc_supported =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "promisc_supported = %lld\n",
                           adapter->promisc_supported);
                break;
        case MIN_MTU:
-               adapter->min_mtu = be32_to_cpu(crq->query_capability.number);
+               adapter->min_mtu = be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);
                break;
        case MAX_MTU:
-               adapter->max_mtu = be32_to_cpu(crq->query_capability.number);
+               adapter->max_mtu = be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);
                break;
        case MAX_MULTICAST_FILTERS:
                adapter->max_multicast_filters =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_multicast_filters = %lld\n",
                           adapter->max_multicast_filters);
                break;
        case VLAN_HEADER_INSERTION:
                adapter->vlan_header_insertion =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                if (adapter->vlan_header_insertion)
                        netdev->features |= NETIF_F_HW_VLAN_STAG_TX;
                netdev_dbg(netdev, "vlan_header_insertion = %lld\n",
@@ -2406,43 +2406,43 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
                break;
        case MAX_TX_SG_ENTRIES:
                adapter->max_tx_sg_entries =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "max_tx_sg_entries = %lld\n",
                           adapter->max_tx_sg_entries);
                break;
        case RX_SG_SUPPORTED:
                adapter->rx_sg_supported =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "rx_sg_supported = %lld\n",
                           adapter->rx_sg_supported);
                break;
        case OPT_TX_COMP_SUB_QUEUES:
                adapter->opt_tx_comp_sub_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "opt_tx_comp_sub_queues = %lld\n",
                           adapter->opt_tx_comp_sub_queues);
                break;
        case OPT_RX_COMP_QUEUES:
                adapter->opt_rx_comp_queues =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "opt_rx_comp_queues = %lld\n",
                           adapter->opt_rx_comp_queues);
                break;
        case OPT_RX_BUFADD_Q_PER_RX_COMP_Q:
                adapter->opt_rx_bufadd_q_per_rx_comp_q =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "opt_rx_bufadd_q_per_rx_comp_q = %lld\n",
                           adapter->opt_rx_bufadd_q_per_rx_comp_q);
                break;
        case OPT_TX_ENTRIES_PER_SUBCRQ:
                adapter->opt_tx_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "opt_tx_entries_per_subcrq = %lld\n",
                           adapter->opt_tx_entries_per_subcrq);
                break;
        case OPT_RXBA_ENTRIES_PER_SUBCRQ:
                adapter->opt_rxba_entries_per_subcrq =
-                   be32_to_cpu(crq->query_capability.number);
+                   be64_to_cpu(crq->query_capability.number);
                netdev_dbg(netdev, "opt_rxba_entries_per_subcrq = %lld\n",
                           adapter->opt_rxba_entries_per_subcrq);
                break;
index 1242925ad34cb6b0336524b1c3c1e569158aee24..1a9993cc79b572f58c172a5f4a071594cf4a93b1 100644 (file)
@@ -319,10 +319,8 @@ struct ibmvnic_capability {
        u8 first;
        u8 cmd;
        __be16 capability; /* one of ibmvnic_capabilities */
+       __be64 number;
        struct ibmvnic_rc rc;
-       __be32 number; /*FIX: should be __be64, but I'm getting the least
-                       * significant word first
-                       */
 } __packed __aligned(8);
 
 struct ibmvnic_login {
index b3949d5bef5c3b7e8f86ca2719f1fdf77353ae95..4e733bf1a38e3d24953ed430946129546e3785ff 100644 (file)
@@ -92,6 +92,10 @@ struct e1000_hw;
 #define E1000_DEV_ID_PCH_SPT_I219_LM2          0x15B7  /* SPT-H PCH */
 #define E1000_DEV_ID_PCH_SPT_I219_V2           0x15B8  /* SPT-H PCH */
 #define E1000_DEV_ID_PCH_LBG_I219_LM3          0x15B9  /* LBG PCH */
+#define E1000_DEV_ID_PCH_SPT_I219_LM4          0x15D7
+#define E1000_DEV_ID_PCH_SPT_I219_V4           0x15D8
+#define E1000_DEV_ID_PCH_SPT_I219_LM5          0x15E3
+#define E1000_DEV_ID_PCH_SPT_I219_V5           0x15D6
 
 #define E1000_REVISION_4       4
 
index a049e30639a13d75cd66185aa225bb3d15847d8e..c0f4887ea44d8c2f157cb9c63555acb5217ff1c9 100644 (file)
@@ -1252,9 +1252,9 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
                        ew32(H2ME, mac_reg);
                }
 
-               /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+               /* Poll up to 300msec for ME to clear ULP_CFG_DONE. */
                while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
-                       if (i++ == 10) {
+                       if (i++ == 30) {
                                ret_val = -E1000_ERR_PHY;
                                goto out;
                        }
@@ -1328,6 +1328,8 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
                     I218_ULP_CONFIG1_RESET_TO_SMBUS |
                     I218_ULP_CONFIG1_WOL_HOST |
                     I218_ULP_CONFIG1_INBAND_EXIT |
+                    I218_ULP_CONFIG1_EN_ULP_LANPHYPC |
+                    I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST |
                     I218_ULP_CONFIG1_DISABLE_SMB_PERST);
        e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
 
@@ -1433,6 +1435,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                        emi_addr = I217_RX_CONFIG;
                ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val);
 
+               if (hw->mac.type == e1000_pch_lpt ||
+                   hw->mac.type == e1000_pch_spt) {
+                       u16 phy_reg;
+
+                       e1e_rphy_locked(hw, I217_PLL_CLOCK_GATE_REG, &phy_reg);
+                       phy_reg &= ~I217_PLL_CLOCK_GATE_MASK;
+                       if (speed == SPEED_100 || speed == SPEED_10)
+                               phy_reg |= 0x3E8;
+                       else
+                               phy_reg |= 0xFA;
+                       e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg);
+               }
                hw->phy.ops.release(hw);
 
                if (ret_val)
@@ -1467,6 +1481,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                                hw->phy.ops.release(hw);
                                if (ret_val)
                                        return ret_val;
+                       } else {
+                               ret_val = hw->phy.ops.acquire(hw);
+                               if (ret_val)
+                                       return ret_val;
+
+                               ret_val = e1e_wphy_locked(hw,
+                                                         PHY_REG(776, 20),
+                                                         0xC023);
+                               hw->phy.ops.release(hw);
+                               if (ret_val)
+                                       return ret_val;
+
                        }
                }
        }
index 34c551e322ebd30a6b3dd4bf994f3df957228db6..2311f6003f58cedcc0d726a31c05b69d0b8b7bcd 100644 (file)
 #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 */
+/* enable ULP even if when phy powered down via lanphypc */
+#define I218_ULP_CONFIG1_EN_ULP_LANPHYPC       0x0400
+/* disable clear of sticky ULP on PERST */
+#define I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST       0x0800
 #define I218_ULP_CONFIG1_DISABLE_SMB_PERST     0x1000  /* Disable on PERST# */
 
 /* SMBus Address Phy Register */
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
 #define HV_PM_CTRL_K1_ENABLE           0x4000
 
+#define I217_PLL_CLOCK_GATE_REG        PHY_REG(772, 28)
+#define I217_PLL_CLOCK_GATE_MASK       0x07FF
+
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
 /* Inband Control */
index c71ba1bfc1ec1dbafacfe5fa829a0464e178d9ef..9b4ec13d9161df41410571b2e1ad771f5774ff4e 100644 (file)
@@ -7452,6 +7452,10 @@ static const struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM2), board_pch_spt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V2), board_pch_spt },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LBG_I219_LM3), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM4), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V4), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_LM5), board_pch_spt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_SPT_I219_V5), board_pch_spt },
 
        { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
 };
index b243c3cbe68faefa9e5857ade0e6a875b4141727..38f558e0bb6298461828f7a5fb3b2c0ba776a666 100644 (file)
@@ -1937,8 +1937,10 @@ static void fm10k_init_reta(struct fm10k_intfc *interface)
        u16 i, rss_i = interface->ring_feature[RING_F_RSS].indices;
        u32 reta, base;
 
-       /* If the netdev is initialized we have to maintain table if possible */
-       if (interface->netdev->reg_state != NETREG_UNINITIALIZED) {
+       /* If the Rx flow indirection table has been configured manually, we
+        * need to maintain it when possible.
+        */
+       if (netif_is_rxfh_configured(interface->netdev)) {
                for (i = FM10K_RETA_SIZE; i--;) {
                        reta = interface->reta[i];
                        if ((((reta << 24) >> 24) < rss_i) &&
@@ -1946,6 +1948,10 @@ static void fm10k_init_reta(struct fm10k_intfc *interface)
                            (((reta <<  8) >> 24) < rss_i) &&
                            (((reta)       >> 24) < rss_i))
                                continue;
+
+                       /* this should never happen */
+                       dev_err(&interface->pdev->dev,
+                               "RSS indirection table assigned flows out of queue bounds. Reconfiguring.\n");
                        goto repopulate_reta;
                }
 
index 662569d5b7c01a0af679fcecb147270a9c8f0c7c..d09a8dd71fc2e4d28eac12be113e84b528dc142d 100644 (file)
@@ -1204,6 +1204,15 @@ err_queueing_scheme:
        return err;
 }
 
+static int __fm10k_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                           struct tc_to_netdev *tc)
+{
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       return fm10k_setup_tc(dev, tc->tc);
+}
+
 static int fm10k_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 {
        switch (cmd) {
@@ -1386,7 +1395,7 @@ static const struct net_device_ops fm10k_netdev_ops = {
        .ndo_vlan_rx_kill_vid   = fm10k_vlan_rx_kill_vid,
        .ndo_set_rx_mode        = fm10k_set_rx_mode,
        .ndo_get_stats64        = fm10k_get_stats64,
-       .ndo_setup_tc           = fm10k_setup_tc,
+       .ndo_setup_tc           = __fm10k_setup_tc,
        .ndo_set_vf_mac         = fm10k_ndo_set_vf_mac,
        .ndo_set_vf_vlan        = fm10k_ndo_set_vf_vlan,
        .ndo_set_vf_rate        = fm10k_ndo_set_vf_bw,
index 53ed3bdd836311be4b0b4e2c383e8a2e04c311fa..2f6210ae8ba0f3cf2621035b314d33ced74e0068 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -64,9 +64,6 @@
 #include "i40e_dcb.h"
 
 /* Useful i40e defaults */
-#define I40E_BASE_PF_SEID     16
-#define I40E_BASE_VSI_SEID    512
-#define I40E_BASE_VEB_SEID    288
 #define I40E_MAX_VEB          16
 
 #define I40E_MAX_NUM_DESCRIPTORS      4096
 #define I40E_PRIV_FLAGS_FD_ATR         BIT(2)
 #define I40E_PRIV_FLAGS_VEB_STATS      BIT(3)
 #define I40E_PRIV_FLAGS_PS             BIT(4)
+#define I40E_PRIV_FLAGS_HW_ATR_EVICT   BIT(5)
 
 #define I40E_NVM_VERSION_LO_SHIFT  0
 #define I40E_NVM_VERSION_LO_MASK   (0xff << I40E_NVM_VERSION_LO_SHIFT)
 #define I40E_OEM_VER_PATCH_MASK    0xff
 #define I40E_OEM_VER_BUILD_SHIFT   8
 #define I40E_OEM_VER_SHIFT         24
+#define I40E_PHY_DEBUG_PORT        BIT(4)
 
 /* The values in here are decimal coded as hex as is the case in the NVM map*/
 #define I40E_CURRENT_NVM_VERSION_HI 0x2
 /* default to trying for four seconds */
 #define I40E_TRY_LINK_TIMEOUT (4 * HZ)
 
+/**
+ * i40e_is_mac_710 - Return true if MAC is X710/XL710
+ * @hw: ptr to the hardware info
+ **/
+static inline bool i40e_is_mac_710(struct i40e_hw *hw)
+{
+       if ((hw->mac.type == I40E_MAC_X710) ||
+           (hw->mac.type == I40E_MAC_XL710))
+               return true;
+
+       return false;
+}
+
 /* driver state flags */
 enum i40e_state_t {
        __I40E_TESTING,
@@ -341,6 +353,10 @@ struct i40e_pf {
 #define I40E_FLAG_NO_PCI_LINK_CHECK            BIT_ULL(42)
 #define I40E_FLAG_100M_SGMII_CAPABLE           BIT_ULL(43)
 #define I40E_FLAG_RESTART_AUTONEG              BIT_ULL(44)
+#define I40E_FLAG_NO_DCB_SUPPORT               BIT_ULL(45)
+#define I40E_FLAG_USE_SET_LLDP_MIB             BIT_ULL(46)
+#define I40E_FLAG_STOP_FW_LLDP                 BIT_ULL(47)
+#define I40E_FLAG_HAVE_10GBASET_PHY            BIT_ULL(48)
 #define I40E_FLAG_PF_MAC                       BIT_ULL(50)
 
        /* tracks features that get auto disabled by errors */
@@ -393,6 +409,7 @@ struct i40e_pf {
        struct i40e_vf *vf;
        int num_alloc_vfs;      /* actual number of VFs allocated */
        u32 vf_aq_requests;
+       u32 arq_overflows;      /* Not fatal, possibly indicative of problems */
 
        /* DCBx/DCBNL capability for PF that indicates
         * whether DCBx is managed by firmware or host
@@ -425,6 +442,7 @@ struct i40e_pf {
 
        u32 ioremap_len;
        u32 fd_inv;
+       u16 phy_led_val;
 };
 
 struct i40e_mac_filter {
@@ -494,6 +512,7 @@ struct i40e_vsi {
        u32 tx_busy;
        u64 tx_linearize;
        u64 tx_force_wb;
+       u64 tx_lost_interrupt;
        u32 rx_buf_failed;
        u32 rx_page_failed;
 
@@ -502,13 +521,6 @@ struct i40e_vsi {
        struct i40e_ring **tx_rings;
 
        u16 work_limit;
-       /* high bit set means dynamic, use accessor routines to read/write.
-        * hardware only supports 2us resolution for the ITR registers.
-        * these values always store the USER setting, and must be converted
-        * before programming to a register.
-        */
-       u16 rx_itr_setting;
-       u16 tx_itr_setting;
        u16 int_rate_limit;  /* value in usecs */
 
        u16 rss_table_size; /* HW RSS table size */
@@ -749,6 +761,9 @@ static inline void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector)
        struct i40e_hw *hw = &pf->hw;
        u32 val;
 
+       /* definitely clear the PBA here, as this function is meant to
+        * clean out all previous interrupts AND enable the interrupt
+        */
        val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
              I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
              (I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
@@ -756,9 +771,8 @@ static inline void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector)
        /* skip the flush */
 }
 
-void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector);
 void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf);
-void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf);
+void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf, bool clearpba);
 #ifdef I40E_FCOE
 struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
                                             struct net_device *netdev,
@@ -788,7 +802,8 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
                                      bool is_vf, bool is_netdev);
 #ifdef I40E_FCOE
 int i40e_close(struct net_device *netdev);
-int i40e_setup_tc(struct net_device *netdev, u8 tc);
+int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+                   struct tc_to_netdev *tc);
 void i40e_netpoll(struct net_device *netdev);
 int i40e_fcoe_enable(struct net_device *netdev);
 int i40e_fcoe_disable(struct net_device *netdev);
index 1fd5ea82a9bc88950a29a305e7c4898c3b6b246c..df8e2fd6a649a34511bc094bf659718f943192d5 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -953,6 +953,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
        u16 flags;
        u16 ntu;
 
+       /* pre-clean the event info */
+       memset(&e->desc, 0, sizeof(e->desc));
+
        /* take the lock before we start messing with the ring */
        mutex_lock(&hw->aq.arq_mutex);
 
@@ -1020,14 +1023,6 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
        hw->aq.arq.next_to_clean = ntc;
        hw->aq.arq.next_to_use = ntu;
 
-clean_arq_element_out:
-       /* Set pending if needed, unlock and return */
-       if (pending != NULL)
-               *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
-
-clean_arq_element_err:
-       mutex_unlock(&hw->aq.arq_mutex);
-
        if (i40e_is_nvm_update_op(&e->desc)) {
                if (hw->aq.nvm_release_on_done) {
                        i40e_release_nvm(hw);
@@ -1048,6 +1043,13 @@ clean_arq_element_err:
                }
        }
 
+clean_arq_element_out:
+       /* Set pending if needed, unlock and return */
+       if (pending)
+               *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
+clean_arq_element_err:
+       mutex_unlock(&hw->aq.arq_mutex);
+
        return ret_code;
 }
 
index 0e608d2a70d5daef38dd1adb4765b472c9edf75b..8d5c65ab6267054feeddaa1b06c5a5ee97077a5e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -34,7 +34,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR      0x0001
-#define I40E_FW_API_VERSION_MINOR      0x0004
+#define I40E_FW_API_VERSION_MINOR      0x0005
 
 struct i40e_aq_desc {
        __le16 flags;
@@ -145,6 +145,9 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_remove_statistics          = 0x0202,
        i40e_aqc_opc_set_port_parameters        = 0x0203,
        i40e_aqc_opc_get_switch_resource_alloc  = 0x0204,
+       i40e_aqc_opc_set_switch_config          = 0x0205,
+       i40e_aqc_opc_rx_ctl_reg_read            = 0x0206,
+       i40e_aqc_opc_rx_ctl_reg_write           = 0x0207,
 
        i40e_aqc_opc_add_vsi                    = 0x0210,
        i40e_aqc_opc_update_vsi_parameters      = 0x0211,
@@ -229,6 +232,7 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_nvm_config_read            = 0x0704,
        i40e_aqc_opc_nvm_config_write           = 0x0705,
        i40e_aqc_opc_oem_post_update            = 0x0720,
+       i40e_aqc_opc_thermal_sensor             = 0x0721,
 
        /* virtualization commands */
        i40e_aqc_opc_send_msg_to_pf             = 0x0801,
@@ -683,6 +687,31 @@ struct i40e_aqc_switch_resource_alloc_element_resp {
 
 I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
 
+/* Set Switch Configuration (direct 0x0205) */
+struct i40e_aqc_set_switch_config {
+       __le16  flags;
+#define I40E_AQ_SET_SWITCH_CFG_PROMISC         0x0001
+#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER       0x0002
+       __le16  valid_flags;
+       u8      reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
+
+/* Read Receive control registers  (direct 0x0206)
+ * Write Receive control registers (direct 0x0207)
+ *     used for accessing Rx control registers that can be
+ *     slow and need special handling when under high Rx load
+ */
+struct i40e_aqc_rx_ctl_reg_read_write {
+       __le32 reserved1;
+       __le32 address;
+       __le32 reserved2;
+       __le32 value;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write);
+
 /* Add VSI (indirect 0x0210)
  *    this indirect command uses struct i40e_aqc_vsi_properties_data
  *    as the indirect buffer (128 bytes)
@@ -909,7 +938,8 @@ struct i40e_aqc_add_veb {
                                        I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT     0x2
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DATA                0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER      0x8
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER      0x8     /* deprecated */
+#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS  0x10
        u8      enable_tcs;
        u8      reserved[9];
 };
@@ -976,6 +1006,7 @@ struct i40e_aqc_add_macvlan_element_data {
 #define I40E_AQC_MACVLAN_ADD_HASH_MATCH                0x0002
 #define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN       0x0004
 #define I40E_AQC_MACVLAN_ADD_TO_QUEUE          0x0008
+#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC    0x0010
        __le16  queue_number;
 #define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT       0
 #define I40E_AQC_MACVLAN_CMD_QUEUE_MASK                (0x7FF << \
@@ -1072,6 +1103,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes {
 #define I40E_AQC_SET_VSI_PROMISC_BROADCAST     0x04
 #define I40E_AQC_SET_VSI_DEFAULT               0x08
 #define I40E_AQC_SET_VSI_PROMISC_VLAN          0x10
+#define I40E_AQC_SET_VSI_PROMISC_TX            0x8000
        __le16  seid;
 #define I40E_AQC_VSI_PROM_CMD_SEID_MASK                0x3FF
        __le16  vlan_tag;
@@ -1264,6 +1296,12 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC         1
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE             2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP                 3
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED           4
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE          5
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC      0x2000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC      0x4000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP       0x8000
 
        __le32  tenant_id;
        u8      reserved[4];
@@ -1932,6 +1970,22 @@ struct i40e_aqc_nvm_oem_post_update_buffer {
 
 I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
 
+/* Thermal Sensor (indirect 0x0721)
+ *     read or set thermal sensor configs and values
+ *     takes a sensor and command specific data buffer, not detailed here
+ */
+struct i40e_aqc_thermal_sensor {
+       u8 sensor_action;
+#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG     0
+#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG      1
+#define I40E_AQ_THERMAL_SENSOR_READ_TEMP       2
+       u8 reserved[7];
+       __le32  addr_high;
+       __le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
+
 /* Send to PF command (indirect 0x0801) id is only used by PF
  * Send to VF command (indirect 0x0802) id is only used by PF
  * Send to Peer PF command (indirect 0x0803)
@@ -2211,6 +2265,7 @@ struct i40e_aqc_add_udp_tunnel {
 #define I40E_AQC_TUNNEL_TYPE_VXLAN     0x00
 #define I40E_AQC_TUNNEL_TYPE_NGE       0x01
 #define I40E_AQC_TUNNEL_TYPE_TEREDO    0x10
+#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE 0x11
        u8      reserved1[10];
 };
 
index 3b03a3165ca71d474f06b0871342add07feb452e..4596294c2ab1cad75db8d1355b05b98b5db47406 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -62,14 +62,6 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
                case I40E_DEV_ID_10G_BASE_T_X722:
                        hw->mac.type = I40E_MAC_X722;
                        break;
-               case I40E_DEV_ID_X722_VF:
-               case I40E_DEV_ID_X722_VF_HV:
-                       hw->mac.type = I40E_MAC_X722_VF;
-                       break;
-               case I40E_DEV_ID_VF:
-               case I40E_DEV_ID_VF_HV:
-                       hw->mac.type = I40E_MAC_VF;
-                       break;
                default:
                        hw->mac.type = I40E_MAC_GENERIC;
                        break;
@@ -1247,7 +1239,13 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
        grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
                    I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
                    I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
-       for (cnt = 0; cnt < grst_del + 10; cnt++) {
+
+       /* It can take upto 15 secs for GRST steady state.
+        * Bump it to 16 secs max to be safe.
+        */
+       grst_del = grst_del * 20;
+
+       for (cnt = 0; cnt < grst_del; cnt++) {
                reg = rd32(hw, I40E_GLGEN_RSTAT);
                if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
                        break;
@@ -1895,6 +1893,32 @@ i40e_status i40e_aq_set_phy_int_mask(struct i40e_hw *hw,
        return status;
 }
 
+/**
+ * i40e_aq_set_phy_debug
+ * @hw: pointer to the hw struct
+ * @cmd_flags: debug command flags
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Reset the external PHY.
+ **/
+enum i40e_status_code i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
+                                       struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_phy_debug *cmd =
+               (struct i40e_aqc_set_phy_debug *)&desc.params.raw;
+       enum i40e_status_code status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_set_phy_debug);
+
+       cmd->command_flags = cmd_flags;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
 /**
  * i40e_aq_add_vsi
  * @hw: pointer to the hw struct
@@ -1960,12 +1984,19 @@ i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
        i40e_fill_default_direct_cmd_desc(&desc,
                                        i40e_aqc_opc_set_vsi_promiscuous_modes);
 
-       if (set)
+       if (set) {
                flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
+               if (((hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver >= 5)) ||
+                   (hw->aq.api_maj_ver > 1))
+                       flags |= I40E_AQC_SET_VSI_PROMISC_TX;
+       }
 
        cmd->promiscuous_flags = cpu_to_le16(flags);
 
        cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
+       if (((hw->aq.api_maj_ver >= 1) && (hw->aq.api_min_ver >= 5)) ||
+           (hw->aq.api_maj_ver > 1))
+               cmd->valid_flags |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_TX);
 
        cmd->seid = cpu_to_le16(seid);
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
@@ -2040,6 +2071,37 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
        return status;
 }
 
+/**
+ * i40e_aq_set_vsi_vlan_promisc - control the VLAN promiscuous setting
+ * @hw: pointer to the hw struct
+ * @seid: vsi number
+ * @enable: set MAC L2 layer unicast promiscuous enable/disable for a given VLAN
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw,
+                                      u16 seid, bool enable,
+                                      struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+               (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
+       i40e_status status;
+       u16 flags = 0;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                       i40e_aqc_opc_set_vsi_promiscuous_modes);
+       if (enable)
+               flags |= I40E_AQC_SET_VSI_PROMISC_VLAN;
+
+       cmd->promiscuous_flags = cpu_to_le16(flags);
+       cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_VLAN);
+       cmd->seid = cpu_to_le16(seid);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
 /**
  * i40e_get_vsi_params - get VSI configuration info
  * @hw: pointer to the hw struct
@@ -2285,8 +2347,8 @@ i40e_status i40e_update_link_info(struct i40e_hw *hw)
  * @downlink_seid: the VSI SEID
  * @enabled_tc: bitmap of TCs to be enabled
  * @default_port: true for default port VSI, false for control port
- * @enable_l2_filtering: true to add L2 filter table rules to regular forwarding rules for cloud support
  * @veb_seid: pointer to where to put the resulting VEB SEID
+ * @enable_stats: true to turn on VEB stats
  * @cmd_details: pointer to command details structure or NULL
  *
  * This asks the FW to add a VEB between the uplink and downlink
@@ -2294,8 +2356,8 @@ i40e_status i40e_update_link_info(struct i40e_hw *hw)
  **/
 i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
                                u16 downlink_seid, u8 enabled_tc,
-                               bool default_port, bool enable_l2_filtering,
-                               u16 *veb_seid,
+                               bool default_port, u16 *veb_seid,
+                               bool enable_stats,
                                struct i40e_asq_cmd_details *cmd_details)
 {
        struct i40e_aq_desc desc;
@@ -2322,8 +2384,9 @@ i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
        else
                veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DATA;
 
-       if (enable_l2_filtering)
-               veb_flags |= I40E_AQC_ADD_VEB_ENABLE_L2_FILTER;
+       /* reverse logic here: set the bitflag to disable the stats */
+       if (!enable_stats)
+               veb_flags |= I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS;
 
        cmd->veb_flags = cpu_to_le16(veb_flags);
 
@@ -2412,6 +2475,7 @@ i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
                (struct i40e_aqc_macvlan *)&desc.params.raw;
        i40e_status status;
        u16 buf_size;
+       int i;
 
        if (count == 0 || !mv_list || !hw)
                return I40E_ERR_PARAM;
@@ -2425,12 +2489,17 @@ i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
        cmd->seid[1] = 0;
        cmd->seid[2] = 0;
 
+       for (i = 0; i < count; i++)
+               if (is_multicast_ether_addr(mv_list[i].mac_addr))
+                       mv_list[i].flags |=
+                              cpu_to_le16(I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC);
+
        desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
        if (buf_size > I40E_AQ_LARGE_BUF)
                desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
 
        status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
-                                   cmd_details);
+                                      cmd_details);
 
        return status;
 }
@@ -2477,6 +2546,137 @@ i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
        return status;
 }
 
+/**
+ * i40e_mirrorrule_op - Internal helper function to add/delete mirror rule
+ * @hw: pointer to the hw struct
+ * @opcode: AQ opcode for add or delete mirror rule
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @id: Destination VSI SEID or Rule ID
+ * @count: length of the list
+ * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_id: Rule ID returned from FW
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Add/Delete a mirror rule to a specific switch. Mirror rules are supported for
+ * VEBs/VEPA elements only
+ **/
+static i40e_status i40e_mirrorrule_op(struct i40e_hw *hw,
+                               u16 opcode, u16 sw_seid, u16 rule_type, u16 id,
+                               u16 count, __le16 *mr_list,
+                               struct i40e_asq_cmd_details *cmd_details,
+                               u16 *rule_id, u16 *rules_used, u16 *rules_free)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_add_delete_mirror_rule *cmd =
+               (struct i40e_aqc_add_delete_mirror_rule *)&desc.params.raw;
+       struct i40e_aqc_add_delete_mirror_rule_completion *resp =
+       (struct i40e_aqc_add_delete_mirror_rule_completion *)&desc.params.raw;
+       i40e_status status;
+       u16 buf_size;
+
+       buf_size = count * sizeof(*mr_list);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(&desc, opcode);
+       cmd->seid = cpu_to_le16(sw_seid);
+       cmd->rule_type = cpu_to_le16(rule_type &
+                                    I40E_AQC_MIRROR_RULE_TYPE_MASK);
+       cmd->num_entries = cpu_to_le16(count);
+       /* Dest VSI for add, rule_id for delete */
+       cmd->destination = cpu_to_le16(id);
+       if (mr_list) {
+               desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF |
+                                               I40E_AQ_FLAG_RD));
+               if (buf_size > I40E_AQ_LARGE_BUF)
+                       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+       }
+
+       status = i40e_asq_send_command(hw, &desc, mr_list, buf_size,
+                                      cmd_details);
+       if (!status ||
+           hw->aq.asq_last_status == I40E_AQ_RC_ENOSPC) {
+               if (rule_id)
+                       *rule_id = le16_to_cpu(resp->rule_id);
+               if (rules_used)
+                       *rules_used = le16_to_cpu(resp->mirror_rules_used);
+               if (rules_free)
+                       *rules_free = le16_to_cpu(resp->mirror_rules_free);
+       }
+       return status;
+}
+
+/**
+ * i40e_aq_add_mirrorrule - add a mirror rule
+ * @hw: pointer to the hw struct
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @dest_vsi: SEID of VSI to which packets will be mirrored
+ * @count: length of the list
+ * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_id: Rule ID returned from FW
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Add mirror rule. Mirror rules are supported for VEBs or VEPA elements only
+ **/
+i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+                       u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
+                       struct i40e_asq_cmd_details *cmd_details,
+                       u16 *rule_id, u16 *rules_used, u16 *rules_free)
+{
+       if (!(rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS ||
+           rule_type == I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS)) {
+               if (count == 0 || !mr_list)
+                       return I40E_ERR_PARAM;
+       }
+
+       return i40e_mirrorrule_op(hw, i40e_aqc_opc_add_mirror_rule, sw_seid,
+                                 rule_type, dest_vsi, count, mr_list,
+                                 cmd_details, rule_id, rules_used, rules_free);
+}
+
+/**
+ * i40e_aq_delete_mirrorrule - delete a mirror rule
+ * @hw: pointer to the hw struct
+ * @sw_seid: Switch SEID (to which rule refers)
+ * @rule_type: Rule Type (ingress/egress/VLAN)
+ * @count: length of the list
+ * @rule_id: Rule ID that is returned in the receive desc as part of
+ *             add_mirrorrule.
+ * @mr_list: list of mirrored VLAN IDs to be removed
+ * @cmd_details: pointer to command details structure or NULL
+ * @rule_used: Number of rules used in internal switch
+ * @rule_free: Number of rules free in internal switch
+ *
+ * Delete a mirror rule. Mirror rules are supported for VEBs/VEPA elements only
+ **/
+i40e_status i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+                       u16 rule_type, u16 rule_id, u16 count, __le16 *mr_list,
+                       struct i40e_asq_cmd_details *cmd_details,
+                       u16 *rules_used, u16 *rules_free)
+{
+       /* Rule ID has to be valid except rule_type: INGRESS VLAN mirroring */
+       if (rule_type != I40E_AQC_MIRROR_RULE_TYPE_VLAN) {
+               if (!rule_id)
+                       return I40E_ERR_PARAM;
+       } else {
+               /* count and mr_list shall be valid for rule_type INGRESS VLAN
+                * mirroring. For other rule_type, count and rule_type should
+                * not matter.
+                */
+               if (count == 0 || !mr_list)
+                       return I40E_ERR_PARAM;
+       }
+
+       return i40e_mirrorrule_op(hw, i40e_aqc_opc_delete_mirror_rule, sw_seid,
+                                 rule_type, rule_id, count, mr_list,
+                                 cmd_details, NULL, rules_used, rules_free);
+}
+
 /**
  * i40e_aq_send_msg_to_vf
  * @hw: pointer to the hardware structure
@@ -3682,7 +3882,7 @@ i40e_status i40e_set_filter_control(struct i40e_hw *hw,
                return ret;
 
        /* Read the PF Queue Filter control register */
-       val = rd32(hw, I40E_PFQF_CTL_0);
+       val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0);
 
        /* Program required PE hash buckets for the PF */
        val &= ~I40E_PFQF_CTL_0_PEHSIZE_MASK;
@@ -3719,7 +3919,7 @@ i40e_status i40e_set_filter_control(struct i40e_hw *hw,
        if (settings->enable_macvlan)
                val |= I40E_PFQF_CTL_0_MACVLAN_ENA_MASK;
 
-       wr32(hw, I40E_PFQF_CTL_0, val);
+       i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, val);
 
        return 0;
 }
@@ -4046,3 +4246,454 @@ i40e_status i40e_aq_configure_partition_bw(struct i40e_hw *hw,
 
        return status;
 }
+
+/**
+ * i40e_read_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Reads specified PHY register value
+ **/
+i40e_status i40e_read_phy_register(struct i40e_hw *hw,
+                                  u8 page, u16 reg, u8 phy_addr,
+                                  u16 *value)
+{
+       i40e_status status = I40E_ERR_TIMEOUT;
+       u32 command = 0;
+       u16 retry = 1000;
+       u8 port_num = hw->func_caps.mdio_port_num;
+
+       command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+                 (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_ADDRESS) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = 0;
+                       break;
+               }
+               usleep_range(10, 20);
+               retry--;
+       } while (retry);
+
+       if (status) {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't write command to external PHY.\n");
+               goto phy_read_end;
+       }
+
+       command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_READ) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       status = I40E_ERR_TIMEOUT;
+       retry = 1000;
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = 0;
+                       break;
+               }
+               usleep_range(10, 20);
+               retry--;
+       } while (retry);
+
+       if (!status) {
+               command = rd32(hw, I40E_GLGEN_MSRWD(port_num));
+               *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >>
+                        I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT;
+       } else {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't read register value from external PHY.\n");
+       }
+
+phy_read_end:
+       return status;
+}
+
+/**
+ * i40e_write_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Writes value to specified PHY register
+ **/
+i40e_status i40e_write_phy_register(struct i40e_hw *hw,
+                                   u8 page, u16 reg, u8 phy_addr,
+                                   u16 value)
+{
+       i40e_status status = I40E_ERR_TIMEOUT;
+       u32 command = 0;
+       u16 retry = 1000;
+       u8 port_num = hw->func_caps.mdio_port_num;
+
+       command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+                 (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_ADDRESS) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = 0;
+                       break;
+               }
+               usleep_range(10, 20);
+               retry--;
+       } while (retry);
+       if (status) {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't write command to external PHY.\n");
+               goto phy_write_end;
+       }
+
+       command = value << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT;
+       wr32(hw, I40E_GLGEN_MSRWD(port_num), command);
+
+       command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_WRITE) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       status = I40E_ERR_TIMEOUT;
+       retry = 1000;
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = 0;
+                       break;
+               }
+               usleep_range(10, 20);
+               retry--;
+       } while (retry);
+
+phy_write_end:
+       return status;
+}
+
+/**
+ * i40e_get_phy_address
+ * @hw: pointer to the HW structure
+ * @dev_num: PHY port num that address we want
+ * @phy_addr: Returned PHY address
+ *
+ * Gets PHY address for current port
+ **/
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num)
+{
+       u8 port_num = hw->func_caps.mdio_port_num;
+       u32 reg_val = rd32(hw, I40E_GLGEN_MDIO_I2C_SEL(port_num));
+
+       return (u8)(reg_val >> ((dev_num + 1) * 5)) & 0x1f;
+}
+
+/**
+ * i40e_blink_phy_led
+ * @hw: pointer to the HW structure
+ * @time: time how long led will blinks in secs
+ * @interval: gap between LED on and off in msecs
+ *
+ * Blinks PHY link LED
+ **/
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                   u32 time, u32 interval)
+{
+       i40e_status status = 0;
+       u32 i;
+       u16 led_ctl;
+       u16 gpio_led_port;
+       u16 led_reg;
+       u16 led_addr = I40E_PHY_LED_PROV_REG_1;
+       u8 phy_addr = 0;
+       u8 port_num;
+
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+            led_addr++) {
+               status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                               led_addr, phy_addr, &led_reg);
+               if (status)
+                       goto phy_blinking_end;
+               led_ctl = led_reg;
+               if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+                       led_reg = 0;
+                       status = i40e_write_phy_register(hw,
+                                                        I40E_PHY_COM_REG_PAGE,
+                                                        led_addr, phy_addr,
+                                                        led_reg);
+                       if (status)
+                               goto phy_blinking_end;
+                       break;
+               }
+       }
+
+       if (time > 0 && interval > 0) {
+               for (i = 0; i < time * 1000; i += interval) {
+                       status = i40e_read_phy_register(hw,
+                                                       I40E_PHY_COM_REG_PAGE,
+                                                       led_addr, phy_addr,
+                                                       &led_reg);
+                       if (status)
+                               goto restore_config;
+                       if (led_reg & I40E_PHY_LED_MANUAL_ON)
+                               led_reg = 0;
+                       else
+                               led_reg = I40E_PHY_LED_MANUAL_ON;
+                       status = i40e_write_phy_register(hw,
+                                                        I40E_PHY_COM_REG_PAGE,
+                                                        led_addr, phy_addr,
+                                                        led_reg);
+                       if (status)
+                               goto restore_config;
+                       msleep(interval);
+               }
+       }
+
+restore_config:
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                        phy_addr, led_ctl);
+
+phy_blinking_end:
+       return status;
+}
+
+/**
+ * i40e_led_get_phy - return current on/off mode
+ * @hw: pointer to the hw struct
+ * @led_addr: address of led register to use
+ * @val: original value of register to use
+ *
+ **/
+i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+                            u16 *val)
+{
+       i40e_status status = 0;
+       u16 gpio_led_port;
+       u8 phy_addr = 0;
+       u16 reg_val;
+       u16 temp_addr;
+       u8 port_num;
+       u32 i;
+
+       temp_addr = I40E_PHY_LED_PROV_REG_1;
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+            temp_addr++) {
+               status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                               temp_addr, phy_addr, &reg_val);
+               if (status)
+                       return status;
+               *val = reg_val;
+               if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
+                       *led_addr = temp_addr;
+                       break;
+               }
+       }
+       return status;
+}
+
+/**
+ * i40e_led_set_phy
+ * @hw: pointer to the HW structure
+ * @on: true or false
+ * @mode: original val plus bit for set or ignore
+ * Set led's on or off when controlled by the PHY
+ *
+ **/
+i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
+                            u16 led_addr, u32 mode)
+{
+       i40e_status status = 0;
+       u16 led_ctl = 0;
+       u16 led_reg = 0;
+       u8 phy_addr = 0;
+       u8 port_num;
+       u32 i;
+
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                       phy_addr, &led_reg);
+       if (status)
+               return status;
+       led_ctl = led_reg;
+       if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+               led_reg = 0;
+               status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                                led_addr, phy_addr, led_reg);
+               if (status)
+                       return status;
+       }
+       status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                       led_addr, phy_addr, &led_reg);
+       if (status)
+               goto restore_config;
+       if (on)
+               led_reg = I40E_PHY_LED_MANUAL_ON;
+       else
+               led_reg = 0;
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                        led_addr, phy_addr, led_reg);
+       if (status)
+               goto restore_config;
+       if (mode & I40E_PHY_LED_MODE_ORIG) {
+               led_ctl = (mode & I40E_PHY_LED_MODE_MASK);
+               status = i40e_write_phy_register(hw,
+                                                I40E_PHY_COM_REG_PAGE,
+                                                led_addr, phy_addr, led_ctl);
+       }
+       return status;
+restore_config:
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                        phy_addr, led_ctl);
+       return status;
+}
+
+/**
+ * i40e_aq_rx_ctl_read_register - use FW to read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: ptr to register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to read the Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 *reg_val,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp =
+               (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+       i40e_status status;
+
+       if (!reg_val)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_rx_ctl_reg_read);
+
+       cmd_resp->address = cpu_to_le32(reg_addr);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       if (status == 0)
+               *reg_val = le32_to_cpu(cmd_resp->value);
+
+       return status;
+}
+
+/**
+ * i40e_read_rx_ctl - read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ **/
+u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
+{
+       i40e_status status = 0;
+       bool use_register;
+       int retry = 5;
+       u32 val = 0;
+
+       use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+       if (!use_register) {
+do_retry:
+               status = i40e_aq_rx_ctl_read_register(hw, reg_addr, &val, NULL);
+               if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+                       usleep_range(1000, 2000);
+                       retry--;
+                       goto do_retry;
+               }
+       }
+
+       /* if the AQ access failed, try the old-fashioned way */
+       if (status || use_register)
+               val = rd32(hw, reg_addr);
+
+       return val;
+}
+
+/**
+ * i40e_aq_rx_ctl_write_register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to write to an Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 reg_val,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_rx_ctl_reg_read_write *cmd =
+               (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_rx_ctl_reg_write);
+
+       cmd->address = cpu_to_le32(reg_addr);
+       cmd->value = cpu_to_le32(reg_val);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_write_rx_ctl - write to an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ **/
+void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
+{
+       i40e_status status = 0;
+       bool use_register;
+       int retry = 5;
+
+       use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+       if (!use_register) {
+do_retry:
+               status = i40e_aq_rx_ctl_write_register(hw, reg_addr,
+                                                      reg_val, NULL);
+               if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+                       usleep_range(1000, 2000);
+                       retry--;
+                       goto do_retry;
+               }
+       }
+
+       /* if the AQ access failed, try the old-fashioned way */
+       if (status || use_register)
+               wr32(hw, reg_addr, reg_val);
+}
index 582daa7ad77621e3dfdcc4941bd3a55adf6961d6..0fab3a9b51d9ae9f1d728870750d140cdf027408 100644 (file)
@@ -380,17 +380,20 @@ static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
 {
        u16 length, typelength, offset = 0;
        struct i40e_cee_app_prio *app;
-       u8 i, up, selector;
+       u8 i;
 
        typelength = ntohs(tlv->hdr.typelen);
        length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
                       I40E_LLDP_TLV_LEN_SHIFT);
 
        dcbcfg->numapps = length / sizeof(*app);
+
        if (!dcbcfg->numapps)
                return;
 
        for (i = 0; i < dcbcfg->numapps; i++) {
+               u8 up, selector;
+
                app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
                for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
                        if (app->prio_map & BIT(up))
@@ -400,13 +403,17 @@ static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
 
                /* Get Selector from lower 2 bits, and convert to IEEE */
                selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
-               if (selector == I40E_CEE_APP_SEL_ETHTYPE)
+               switch (selector) {
+               case I40E_CEE_APP_SEL_ETHTYPE:
                        dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
-               else if (selector == I40E_CEE_APP_SEL_TCPIP)
+                       break;
+               case I40E_CEE_APP_SEL_TCPIP:
                        dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
-               else
+                       break;
+               default:
                        /* Keep selector as it is for unknown types */
                        dcbcfg->app[i].selector = selector;
+               }
 
                dcbcfg->app[i].protocolid = ntohs(app->protocol);
                /* Move to next app */
index 10744a698d6f9daae2748b206b7845772e2c6d70..0c97733d253c45226b6dc702ecbd8357842fbf68 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -61,256 +61,12 @@ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
 {
        int i;
 
-       if ((seid < I40E_BASE_VEB_SEID) ||
-           (seid > (I40E_BASE_VEB_SEID + I40E_MAX_VEB)))
-               dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
-       else
-               for (i = 0; i < I40E_MAX_VEB; i++)
-                       if (pf->veb[i] && pf->veb[i]->seid == seid)
-                               return pf->veb[i];
+       for (i = 0; i < I40E_MAX_VEB; i++)
+               if (pf->veb[i] && pf->veb[i]->seid == seid)
+                       return pf->veb[i];
        return NULL;
 }
 
-/**************************************************************
- * dump
- * The dump entry in debugfs is for getting a data snapshow of
- * the driver's current configuration and runtime details.
- * When the filesystem entry is written, a snapshot is taken.
- * When the entry is read, the most recent snapshot data is dumped.
- **************************************************************/
-static char *i40e_dbg_dump_buf;
-static ssize_t i40e_dbg_dump_data_len;
-static ssize_t i40e_dbg_dump_buffer_len;
-
-/**
- * i40e_dbg_dump_read - read the dump data
- * @filp: the opened file
- * @buffer: where to write the data for the user to read
- * @count: the size of the user's buffer
- * @ppos: file position offset
- **/
-static ssize_t i40e_dbg_dump_read(struct file *filp, char __user *buffer,
-                                 size_t count, loff_t *ppos)
-{
-       int bytes_not_copied;
-       int len;
-
-       /* is *ppos bigger than the available data? */
-       if (*ppos >= i40e_dbg_dump_data_len || !i40e_dbg_dump_buf)
-               return 0;
-
-       /* be sure to not read beyond the end of available data */
-       len = min_t(int, count, (i40e_dbg_dump_data_len - *ppos));
-
-       bytes_not_copied = copy_to_user(buffer, &i40e_dbg_dump_buf[*ppos], len);
-       if (bytes_not_copied)
-               return -EFAULT;
-
-       *ppos += len;
-       return len;
-}
-
-/**
- * i40e_dbg_prep_dump_buf
- * @pf: the PF we're working with
- * @buflen: the desired buffer length
- *
- * Return positive if success, 0 if failed
- **/
-static int i40e_dbg_prep_dump_buf(struct i40e_pf *pf, int buflen)
-{
-       /* if not already big enough, prep for re alloc */
-       if (i40e_dbg_dump_buffer_len && i40e_dbg_dump_buffer_len < buflen) {
-               kfree(i40e_dbg_dump_buf);
-               i40e_dbg_dump_buffer_len = 0;
-               i40e_dbg_dump_buf = NULL;
-       }
-
-       /* get a new buffer if needed */
-       if (!i40e_dbg_dump_buf) {
-               i40e_dbg_dump_buf = kzalloc(buflen, GFP_KERNEL);
-               if (i40e_dbg_dump_buf != NULL)
-                       i40e_dbg_dump_buffer_len = buflen;
-       }
-
-       return i40e_dbg_dump_buffer_len;
-}
-
-/**
- * i40e_dbg_dump_write - trigger a datadump snapshot
- * @filp: the opened file
- * @buffer: where to find the user's data
- * @count: the length of the user's data
- * @ppos: file position offset
- *
- * Any write clears the stats
- **/
-static ssize_t i40e_dbg_dump_write(struct file *filp,
-                                  const char __user *buffer,
-                                  size_t count, loff_t *ppos)
-{
-       struct i40e_pf *pf = filp->private_data;
-       bool seid_found = false;
-       long seid = -1;
-       int buflen = 0;
-       int i, ret;
-       int len;
-       u8 *p;
-
-       /* don't allow partial writes */
-       if (*ppos != 0)
-               return 0;
-
-       /* decode the SEID given to be dumped */
-       ret = kstrtol_from_user(buffer, count, 0, &seid);
-
-       if (ret) {
-               dev_info(&pf->pdev->dev, "bad seid value\n");
-       } else if (seid == 0) {
-               seid_found = true;
-
-               kfree(i40e_dbg_dump_buf);
-               i40e_dbg_dump_buffer_len = 0;
-               i40e_dbg_dump_data_len = 0;
-               i40e_dbg_dump_buf = NULL;
-               dev_info(&pf->pdev->dev, "debug buffer freed\n");
-
-       } else if (seid == pf->pf_seid || seid == 1) {
-               seid_found = true;
-
-               buflen = sizeof(struct i40e_pf);
-               buflen += (sizeof(struct i40e_aq_desc)
-                    * (pf->hw.aq.num_arq_entries + pf->hw.aq.num_asq_entries));
-
-               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-                       p = i40e_dbg_dump_buf;
-
-                       len = sizeof(struct i40e_pf);
-                       memcpy(p, pf, len);
-                       p += len;
-
-                       len = (sizeof(struct i40e_aq_desc)
-                                       * pf->hw.aq.num_asq_entries);
-                       memcpy(p, pf->hw.aq.asq.desc_buf.va, len);
-                       p += len;
-
-                       len = (sizeof(struct i40e_aq_desc)
-                                       * pf->hw.aq.num_arq_entries);
-                       memcpy(p, pf->hw.aq.arq.desc_buf.va, len);
-                       p += len;
-
-                       i40e_dbg_dump_data_len = buflen;
-                       dev_info(&pf->pdev->dev,
-                                "PF seid %ld dumped %d bytes\n",
-                                seid, (int)i40e_dbg_dump_data_len);
-               }
-       } else if (seid >= I40E_BASE_VSI_SEID) {
-               struct i40e_vsi *vsi = NULL;
-               struct i40e_mac_filter *f;
-               int filter_count = 0;
-
-               mutex_lock(&pf->switch_mutex);
-               vsi = i40e_dbg_find_vsi(pf, seid);
-               if (!vsi) {
-                       mutex_unlock(&pf->switch_mutex);
-                       goto write_exit;
-               }
-
-               buflen = sizeof(struct i40e_vsi);
-               buflen += sizeof(struct i40e_q_vector) * vsi->num_q_vectors;
-               buflen += sizeof(struct i40e_ring) * 2 * vsi->num_queue_pairs;
-               buflen += sizeof(struct i40e_tx_buffer) * vsi->num_queue_pairs;
-               buflen += sizeof(struct i40e_rx_buffer) * vsi->num_queue_pairs;
-               list_for_each_entry(f, &vsi->mac_filter_list, list)
-                       filter_count++;
-               buflen += sizeof(struct i40e_mac_filter) * filter_count;
-
-               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-                       p = i40e_dbg_dump_buf;
-                       seid_found = true;
-
-                       len = sizeof(struct i40e_vsi);
-                       memcpy(p, vsi, len);
-                       p += len;
-
-                       if (vsi->num_q_vectors) {
-                               len = (sizeof(struct i40e_q_vector)
-                                       * vsi->num_q_vectors);
-                               memcpy(p, vsi->q_vectors, len);
-                               p += len;
-                       }
-
-                       if (vsi->num_queue_pairs) {
-                               len = (sizeof(struct i40e_ring) *
-                                     vsi->num_queue_pairs);
-                               memcpy(p, vsi->tx_rings, len);
-                               p += len;
-                               memcpy(p, vsi->rx_rings, len);
-                               p += len;
-                       }
-
-                       if (vsi->tx_rings[0]) {
-                               len = sizeof(struct i40e_tx_buffer);
-                               for (i = 0; i < vsi->num_queue_pairs; i++) {
-                                       memcpy(p, vsi->tx_rings[i]->tx_bi, len);
-                                       p += len;
-                               }
-                               len = sizeof(struct i40e_rx_buffer);
-                               for (i = 0; i < vsi->num_queue_pairs; i++) {
-                                       memcpy(p, vsi->rx_rings[i]->rx_bi, len);
-                                       p += len;
-                               }
-                       }
-
-                       /* macvlan filter list */
-                       len = sizeof(struct i40e_mac_filter);
-                       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-                               memcpy(p, f, len);
-                               p += len;
-                       }
-
-                       i40e_dbg_dump_data_len = buflen;
-                       dev_info(&pf->pdev->dev,
-                                "VSI seid %ld dumped %d bytes\n",
-                                seid, (int)i40e_dbg_dump_data_len);
-               }
-               mutex_unlock(&pf->switch_mutex);
-       } else if (seid >= I40E_BASE_VEB_SEID) {
-               struct i40e_veb *veb = NULL;
-
-               mutex_lock(&pf->switch_mutex);
-               veb = i40e_dbg_find_veb(pf, seid);
-               if (!veb) {
-                       mutex_unlock(&pf->switch_mutex);
-                       goto write_exit;
-               }
-
-               buflen = sizeof(struct i40e_veb);
-               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
-                       seid_found = true;
-                       memcpy(i40e_dbg_dump_buf, veb, buflen);
-                       i40e_dbg_dump_data_len = buflen;
-                       dev_info(&pf->pdev->dev,
-                                "VEB seid %ld dumped %d bytes\n",
-                                seid, (int)i40e_dbg_dump_data_len);
-               }
-               mutex_unlock(&pf->switch_mutex);
-       }
-
-write_exit:
-       if (!seid_found)
-               dev_info(&pf->pdev->dev, "unknown seid %ld\n", seid);
-
-       return count;
-}
-
-static const struct file_operations i40e_dbg_dump_fops = {
-       .owner = THIS_MODULE,
-       .open =  simple_open,
-       .read =  i40e_dbg_dump_read,
-       .write = i40e_dbg_dump_write,
-};
-
 /**************************************************************
  * command
  * The command entry in debugfs is for giving the driver commands
@@ -379,19 +135,27 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                return;
        }
        dev_info(&pf->pdev->dev, "vsi seid %d\n", seid);
-       if (vsi->netdev)
-               dev_info(&pf->pdev->dev,
-                        "    netdev: name = %s\n",
-                        vsi->netdev->name);
+       if (vsi->netdev) {
+               struct net_device *nd = vsi->netdev;
+
+               dev_info(&pf->pdev->dev, "    netdev: name = %s, state = %lu, flags = 0x%08x\n",
+                        nd->name, nd->state, nd->flags);
+               dev_info(&pf->pdev->dev, "        features      = 0x%08lx\n",
+                        (unsigned long int)nd->features);
+               dev_info(&pf->pdev->dev, "        hw_features   = 0x%08lx\n",
+                        (unsigned long int)nd->hw_features);
+               dev_info(&pf->pdev->dev, "        vlan_features = 0x%08lx\n",
+                        (unsigned long int)nd->vlan_features);
+       }
        if (vsi->active_vlans)
                dev_info(&pf->pdev->dev,
                         "    vlgrp: & = %p\n", vsi->active_vlans);
        dev_info(&pf->pdev->dev,
-                "    netdev_registered = %i, current_netdev_flags = 0x%04x, state = %li flags = 0x%08lx\n",
-                vsi->netdev_registered,
-                vsi->current_netdev_flags, vsi->state, vsi->flags);
+                "    state = %li flags = 0x%08lx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
+                vsi->state, vsi->flags,
+                vsi->netdev_registered, vsi->current_netdev_flags);
        if (vsi == pf->vsi[pf->lan_vsi])
-               dev_info(&pf->pdev->dev, "MAC address: %pM SAN MAC: %pM Port MAC: %pM\n",
+               dev_info(&pf->pdev->dev, "    MAC address: %pM SAN MAC: %pM Port MAC: %pM\n",
                         pf->hw.mac.addr,
                         pf->hw.mac.san_addr,
                         pf->hw.mac.port_addr);
@@ -511,7 +275,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         rx_ring->dtype);
                dev_info(&pf->pdev->dev,
                         "    rx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
-                        i, rx_ring->hsplit,
+                        i, ring_is_ps_enabled(rx_ring),
                         rx_ring->next_to_use,
                         rx_ring->next_to_clean,
                         rx_ring->ring_active);
@@ -525,6 +289,11 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         i,
                         rx_ring->rx_stats.alloc_page_failed,
                         rx_ring->rx_stats.alloc_buff_failed);
+               dev_info(&pf->pdev->dev,
+                        "    rx_rings[%i]: rx_stats: realloc_count = %lld, page_reuse_count = %lld\n",
+                        i,
+                        rx_ring->rx_stats.realloc_count,
+                        rx_ring->rx_stats.page_reuse_count);
                dev_info(&pf->pdev->dev,
                         "    rx_rings[%i]: size = %i, dma = 0x%08lx\n",
                         i, rx_ring->size,
@@ -533,6 +302,10 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         "    rx_rings[%i]: vsi = %p, q_vector = %p\n",
                         i, rx_ring->vsi,
                         rx_ring->q_vector);
+               dev_info(&pf->pdev->dev,
+                        "    rx_rings[%i]: rx_itr_setting = %d (%s)\n",
+                        i, rx_ring->rx_itr_setting,
+                        ITR_IS_DYNAMIC(rx_ring->rx_itr_setting) ? "dynamic" : "fixed");
        }
        for (i = 0; i < vsi->num_queue_pairs; i++) {
                struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[i]);
@@ -557,8 +330,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         "    tx_rings[%i]: dtype = %d\n",
                         i, tx_ring->dtype);
                dev_info(&pf->pdev->dev,
-                        "    tx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
-                        i, tx_ring->hsplit,
+                        "    tx_rings[%i]: next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
+                        i,
                         tx_ring->next_to_use,
                         tx_ring->next_to_clean,
                         tx_ring->ring_active);
@@ -583,14 +356,15 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                dev_info(&pf->pdev->dev,
                         "    tx_rings[%i]: DCB tc = %d\n",
                         i, tx_ring->dcb_tc);
+               dev_info(&pf->pdev->dev,
+                        "    tx_rings[%i]: tx_itr_setting = %d (%s)\n",
+                        i, tx_ring->tx_itr_setting,
+                        ITR_IS_DYNAMIC(tx_ring->tx_itr_setting) ? "dynamic" : "fixed");
        }
        rcu_read_unlock();
        dev_info(&pf->pdev->dev,
-                "    work_limit = %d, rx_itr_setting = %d (%s), tx_itr_setting = %d (%s)\n",
-                vsi->work_limit, vsi->rx_itr_setting,
-                ITR_IS_DYNAMIC(vsi->rx_itr_setting) ? "dynamic" : "fixed",
-                vsi->tx_itr_setting,
-                ITR_IS_DYNAMIC(vsi->tx_itr_setting) ? "dynamic" : "fixed");
+                "    work_limit = %d\n",
+                vsi->work_limit);
        dev_info(&pf->pdev->dev,
                 "    max_frame = %d, rx_hdr_len = %d, rx_buf_len = %d dtype = %d\n",
                 vsi->max_frame, vsi->rx_hdr_len, vsi->rx_buf_len, vsi->dtype);
@@ -815,20 +589,20 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
                        if (!is_rx_ring) {
                                txd = I40E_TX_DESC(ring, i);
                                dev_info(&pf->pdev->dev,
-                                        "   d[%03i] = 0x%016llx 0x%016llx\n",
+                                        "   d[%03x] = 0x%016llx 0x%016llx\n",
                                         i, txd->buffer_addr,
                                         txd->cmd_type_offset_bsz);
                        } else if (sizeof(union i40e_rx_desc) ==
                                   sizeof(union i40e_16byte_rx_desc)) {
                                rxd = I40E_RX_DESC(ring, i);
                                dev_info(&pf->pdev->dev,
-                                        "   d[%03i] = 0x%016llx 0x%016llx\n",
+                                        "   d[%03x] = 0x%016llx 0x%016llx\n",
                                         i, rxd->read.pkt_addr,
                                         rxd->read.hdr_addr);
                        } else {
                                rxd = I40E_RX_DESC(ring, i);
                                dev_info(&pf->pdev->dev,
-                                        "   d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+                                        "   d[%03x] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
                                         i, rxd->read.pkt_addr,
                                         rxd->read.hdr_addr,
                                         rxd->read.rsvd1, rxd->read.rsvd2);
@@ -843,20 +617,20 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
                if (!is_rx_ring) {
                        txd = I40E_TX_DESC(ring, desc_n);
                        dev_info(&pf->pdev->dev,
-                                "vsi = %02i tx ring = %02i d[%03i] = 0x%016llx 0x%016llx\n",
+                                "vsi = %02i tx ring = %02i d[%03x] = 0x%016llx 0x%016llx\n",
                                 vsi_seid, ring_id, desc_n,
                                 txd->buffer_addr, txd->cmd_type_offset_bsz);
                } else if (sizeof(union i40e_rx_desc) ==
                           sizeof(union i40e_16byte_rx_desc)) {
                        rxd = I40E_RX_DESC(ring, desc_n);
                        dev_info(&pf->pdev->dev,
-                                "vsi = %02i rx ring = %02i d[%03i] = 0x%016llx 0x%016llx\n",
+                                "vsi = %02i rx ring = %02i d[%03x] = 0x%016llx 0x%016llx\n",
                                 vsi_seid, ring_id, desc_n,
                                 rxd->read.pkt_addr, rxd->read.hdr_addr);
                } else {
                        rxd = I40E_RX_DESC(ring, desc_n);
                        dev_info(&pf->pdev->dev,
-                                "vsi = %02i rx ring = %02i d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+                                "vsi = %02i rx ring = %02i d[%03x] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
                                 vsi_seid, ring_id, desc_n,
                                 rxd->read.pkt_addr, rxd->read.hdr_addr,
                                 rxd->read.rsvd1, rxd->read.rsvd2);
@@ -918,12 +692,6 @@ static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid)
 {
        struct i40e_veb *veb;
 
-       if ((seid < I40E_BASE_VEB_SEID) ||
-           (seid >= (I40E_MAX_VEB + I40E_BASE_VEB_SEID))) {
-               dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
-               return;
-       }
-
        veb = i40e_dbg_find_veb(pf, seid);
        if (!veb) {
                dev_info(&pf->pdev->dev, "can't find veb %d\n", seid);
@@ -2202,11 +1970,6 @@ void i40e_dbg_pf_init(struct i40e_pf *pf)
        if (!pfile)
                goto create_failed;
 
-       pfile = debugfs_create_file("dump", 0600, pf->i40e_dbg_pf, pf,
-                                   &i40e_dbg_dump_fops);
-       if (!pfile)
-               goto create_failed;
-
        pfile = debugfs_create_file("netdev_ops", 0600, pf->i40e_dbg_pf, pf,
                                    &i40e_dbg_netdev_ops_fops);
        if (!pfile)
@@ -2227,9 +1990,6 @@ void i40e_dbg_pf_exit(struct i40e_pf *pf)
 {
        debugfs_remove_recursive(pf->i40e_dbg_pf);
        pf->i40e_dbg_pf = NULL;
-
-       kfree(i40e_dbg_dump_buf);
-       i40e_dbg_dump_buf = NULL;
 }
 
 /**
index f7ce5c7c90031a4af7bf26a97ba058c4fa4ffa4d..99257fcd1ef47ca0fb145c4284045ab4ca2ca8c1 100644 (file)
 #define I40E_DEV_ID_20G_KR2            0x1587
 #define I40E_DEV_ID_20G_KR2_A          0x1588
 #define I40E_DEV_ID_10G_BASE_T4                0x1589
-#define I40E_DEV_ID_VF                 0x154C
-#define I40E_DEV_ID_VF_HV              0x1571
 #define I40E_DEV_ID_KX_X722            0x37CE
 #define I40E_DEV_ID_QSFP_X722          0x37CF
 #define I40E_DEV_ID_SFP_X722           0x37D0
 #define I40E_DEV_ID_1G_BASE_T_X722     0x37D1
 #define I40E_DEV_ID_10G_BASE_T_X722    0x37D2
-#define I40E_DEV_ID_X722_VF            0x37CD
-#define I40E_DEV_ID_X722_VF_HV         0x37D9
 
 #define i40e_is_40G_device(d)          ((d) == I40E_DEV_ID_QSFP_A  || \
                                         (d) == I40E_DEV_ID_QSFP_B  || \
index 45495911c5a4f5f221bac91ced1f284371880c4c..784b1659457adbcafae5460d4b91aac2af1f7f63 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -89,6 +89,9 @@ static const struct i40e_stats i40e_gstrings_misc_stats[] = {
        I40E_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol),
        I40E_VSI_STAT("tx_linearize", tx_linearize),
        I40E_VSI_STAT("tx_force_wb", tx_force_wb),
+       I40E_VSI_STAT("tx_lost_interrupt", tx_lost_interrupt),
+       I40E_VSI_STAT("rx_alloc_fail", rx_buf_failed),
+       I40E_VSI_STAT("rx_pg_alloc_fail", rx_page_failed),
 };
 
 /* These PF_STATs might look like duplicates of some NETDEV_STATs,
@@ -143,6 +146,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("rx_oversize", stats.rx_oversize),
        I40E_PF_STAT("rx_jabber", stats.rx_jabber),
        I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
+       I40E_PF_STAT("arq_overflows", arq_overflows),
        I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
        I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
        I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
@@ -232,6 +236,7 @@ static const char i40e_priv_flags_strings[][ETH_GSTRING_LEN] = {
        "flow-director-atr",
        "veb-stats",
        "packet-split",
+       "hw-atr-eviction",
 };
 
 #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_priv_flags_strings)
@@ -1000,16 +1005,19 @@ static int i40e_get_eeprom(struct net_device *netdev,
        /* check for NVMUpdate access method */
        magic = hw->vendor_id | (hw->device_id << 16);
        if (eeprom->magic && eeprom->magic != magic) {
-               struct i40e_nvm_access *cmd;
-               int errno;
+               struct i40e_nvm_access *cmd = (struct i40e_nvm_access *)eeprom;
+               int errno = 0;
 
                /* make sure it is the right magic for NVMUpdate */
                if ((eeprom->magic >> 16) != hw->device_id)
-                       return -EINVAL;
+                       errno = -EINVAL;
+               else if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+                        test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+                       errno = -EBUSY;
+               else
+                       ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
 
-               cmd = (struct i40e_nvm_access *)eeprom;
-               ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-               if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
+               if ((errno || ret_val) && (hw->debug_mask & I40E_DEBUG_NVM))
                        dev_info(&pf->pdev->dev,
                                 "NVMUpdate read failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
                                 ret_val, hw->aq.asq_last_status, errno,
@@ -1093,27 +1101,25 @@ static int i40e_set_eeprom(struct net_device *netdev,
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_hw *hw = &np->vsi->back->hw;
        struct i40e_pf *pf = np->vsi->back;
-       struct i40e_nvm_access *cmd;
+       struct i40e_nvm_access *cmd = (struct i40e_nvm_access *)eeprom;
        int ret_val = 0;
-       int errno;
+       int errno = 0;
        u32 magic;
 
        /* normal ethtool set_eeprom is not supported */
        magic = hw->vendor_id | (hw->device_id << 16);
        if (eeprom->magic == magic)
-               return -EOPNOTSUPP;
-
+               errno = -EOPNOTSUPP;
        /* check for NVMUpdate access method */
-       if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)
-               return -EINVAL;
-
-       if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
-           test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
-               return -EBUSY;
+       else if (!eeprom->magic || (eeprom->magic >> 16) != hw->device_id)
+               errno = -EINVAL;
+       else if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+                test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+               errno = -EBUSY;
+       else
+               ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
 
-       cmd = (struct i40e_nvm_access *)eeprom;
-       ret_val = i40e_nvmupd_command(hw, cmd, bytes, &errno);
-       if (ret_val && (hw->debug_mask & I40E_DEBUG_NVM))
+       if ((errno || ret_val) && (hw->debug_mask & I40E_DEBUG_NVM))
                dev_info(&pf->pdev->dev,
                         "NVMUpdate write failed err=%d status=0x%x errno=%d module=%d offset=0x%x size=%d\n",
                         ret_val, hw->aq.asq_last_status, errno,
@@ -1820,28 +1826,52 @@ static int i40e_set_phys_id(struct net_device *netdev,
                            enum ethtool_phys_id_state state)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
+       i40e_status ret = 0;
        struct i40e_pf *pf = np->vsi->back;
        struct i40e_hw *hw = &pf->hw;
        int blink_freq = 2;
+       u16 temp_status;
 
        switch (state) {
        case ETHTOOL_ID_ACTIVE:
-               pf->led_status = i40e_led_get(hw);
+               if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY)) {
+                       pf->led_status = i40e_led_get(hw);
+               } else {
+                       i40e_aq_set_phy_debug(hw, I40E_PHY_DEBUG_PORT, NULL);
+                       ret = i40e_led_get_phy(hw, &temp_status,
+                                              &pf->phy_led_val);
+                       pf->led_status = temp_status;
+               }
                return blink_freq;
        case ETHTOOL_ID_ON:
-               i40e_led_set(hw, 0xF, false);
+               if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY))
+                       i40e_led_set(hw, 0xf, false);
+               else
+                       ret = i40e_led_set_phy(hw, true, pf->led_status, 0);
                break;
        case ETHTOOL_ID_OFF:
-               i40e_led_set(hw, 0x0, false);
+               if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY))
+                       i40e_led_set(hw, 0x0, false);
+               else
+                       ret = i40e_led_set_phy(hw, false, pf->led_status, 0);
                break;
        case ETHTOOL_ID_INACTIVE:
-               i40e_led_set(hw, pf->led_status, false);
+               if (!(pf->flags & I40E_FLAG_HAVE_10GBASET_PHY)) {
+                       i40e_led_set(hw, false, pf->led_status);
+               } else {
+                       ret = i40e_led_set_phy(hw, false, pf->led_status,
+                                              (pf->phy_led_val |
+                                              I40E_PHY_LED_MODE_ORIG));
+                       i40e_aq_set_phy_debug(hw, 0, NULL);
+               }
                break;
        default:
                break;
        }
-
-       return 0;
+               if (ret)
+                       return -ENOENT;
+               else
+                       return 0;
 }
 
 /* NOTE: i40e hardware uses a conversion factor of 2 for Interrupt
@@ -1849,8 +1879,9 @@ static int i40e_set_phys_id(struct net_device *netdev,
  * 125us (8000 interrupts per second) == ITR(62)
  */
 
-static int i40e_get_coalesce(struct net_device *netdev,
-                            struct ethtool_coalesce *ec)
+static int __i40e_get_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec,
+                              int queue)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
@@ -1858,14 +1889,24 @@ static int i40e_get_coalesce(struct net_device *netdev,
        ec->tx_max_coalesced_frames_irq = vsi->work_limit;
        ec->rx_max_coalesced_frames_irq = vsi->work_limit;
 
-       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
+       /* rx and tx usecs has per queue value. If user doesn't specify the queue,
+        * return queue 0's value to represent.
+        */
+       if (queue < 0) {
+               queue = 0;
+       } else if (queue >= vsi->num_queue_pairs) {
+               return -EINVAL;
+       }
+
+       if (ITR_IS_DYNAMIC(vsi->rx_rings[queue]->rx_itr_setting))
                ec->use_adaptive_rx_coalesce = 1;
 
-       if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
+       if (ITR_IS_DYNAMIC(vsi->tx_rings[queue]->tx_itr_setting))
                ec->use_adaptive_tx_coalesce = 1;
 
-       ec->rx_coalesce_usecs = vsi->rx_itr_setting & ~I40E_ITR_DYNAMIC;
-       ec->tx_coalesce_usecs = vsi->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+       ec->rx_coalesce_usecs = vsi->rx_rings[queue]->rx_itr_setting & ~I40E_ITR_DYNAMIC;
+       ec->tx_coalesce_usecs = vsi->tx_rings[queue]->tx_itr_setting & ~I40E_ITR_DYNAMIC;
+
        /* we use the _usecs_high to store/set the interrupt rate limit
         * that the hardware supports, that almost but not quite
         * fits the original intent of the ethtool variable,
@@ -1878,15 +1919,63 @@ static int i40e_get_coalesce(struct net_device *netdev,
        return 0;
 }
 
-static int i40e_set_coalesce(struct net_device *netdev,
+static int i40e_get_coalesce(struct net_device *netdev,
                             struct ethtool_coalesce *ec)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       return __i40e_get_coalesce(netdev, ec, -1);
+}
+
+static int i40e_get_per_queue_coalesce(struct net_device *netdev, u32 queue,
+                                      struct ethtool_coalesce *ec)
+{
+       return __i40e_get_coalesce(netdev, ec, queue);
+}
+
+static void i40e_set_itr_per_queue(struct i40e_vsi *vsi,
+                                  struct ethtool_coalesce *ec,
+                                  int queue)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
        struct i40e_q_vector *q_vector;
+       u16 vector, intrl;
+
+       intrl = INTRL_USEC_TO_REG(vsi->int_rate_limit);
+
+       vsi->rx_rings[queue]->rx_itr_setting = ec->rx_coalesce_usecs;
+       vsi->tx_rings[queue]->tx_itr_setting = ec->tx_coalesce_usecs;
+
+       if (ec->use_adaptive_rx_coalesce)
+               vsi->rx_rings[queue]->rx_itr_setting |= I40E_ITR_DYNAMIC;
+       else
+               vsi->rx_rings[queue]->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
+
+       if (ec->use_adaptive_tx_coalesce)
+               vsi->tx_rings[queue]->tx_itr_setting |= I40E_ITR_DYNAMIC;
+       else
+               vsi->tx_rings[queue]->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
+
+       q_vector = vsi->rx_rings[queue]->q_vector;
+       q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[queue]->rx_itr_setting);
+       vector = vsi->base_vector + q_vector->v_idx;
+       wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), q_vector->rx.itr);
+
+       q_vector = vsi->tx_rings[queue]->q_vector;
+       q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[queue]->tx_itr_setting);
+       vector = vsi->base_vector + q_vector->v_idx;
+       wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), q_vector->tx.itr);
+
+       wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
+       i40e_flush(hw);
+}
+
+static int __i40e_set_coalesce(struct net_device *netdev,
+                              struct ethtool_coalesce *ec,
+                              int queue)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
-       struct i40e_hw *hw = &pf->hw;
-       u16 vector;
        int i;
 
        if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
@@ -1903,57 +1992,53 @@ static int i40e_set_coalesce(struct net_device *netdev,
                return -EINVAL;
        }
 
-       vector = vsi->base_vector;
-       if ((ec->rx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
-           (ec->rx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
-               vsi->rx_itr_setting = ec->rx_coalesce_usecs;
-       } else if (ec->rx_coalesce_usecs == 0) {
-               vsi->rx_itr_setting = ec->rx_coalesce_usecs;
+       if (ec->rx_coalesce_usecs == 0) {
                if (ec->use_adaptive_rx_coalesce)
                        netif_info(pf, drv, netdev, "rx-usecs=0, need to disable adaptive-rx for a complete disable\n");
-       } else {
-               netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
-               return -EINVAL;
+       } else if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                  (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+                       netif_info(pf, drv, netdev, "Invalid value, rx-usecs range is 0-8160\n");
+                       return -EINVAL;
        }
 
        vsi->int_rate_limit = ec->rx_coalesce_usecs_high;
 
-       if ((ec->tx_coalesce_usecs >= (I40E_MIN_ITR << 1)) &&
-           (ec->tx_coalesce_usecs <= (I40E_MAX_ITR << 1))) {
-               vsi->tx_itr_setting = ec->tx_coalesce_usecs;
-       } else if (ec->tx_coalesce_usecs == 0) {
-               vsi->tx_itr_setting = ec->tx_coalesce_usecs;
+       if (ec->tx_coalesce_usecs == 0) {
                if (ec->use_adaptive_tx_coalesce)
                        netif_info(pf, drv, netdev, "tx-usecs=0, need to disable adaptive-tx for a complete disable\n");
+       } else if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                  (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1))) {
+                       netif_info(pf, drv, netdev, "Invalid value, tx-usecs range is 0-8160\n");
+                       return -EINVAL;
+       }
+
+       /* rx and tx usecs has per queue value. If user doesn't specify the queue,
+        * apply to all queues.
+        */
+       if (queue < 0) {
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       i40e_set_itr_per_queue(vsi, ec, i);
+       } else if (queue < vsi->num_queue_pairs) {
+               i40e_set_itr_per_queue(vsi, ec, queue);
        } else {
-               netif_info(pf, drv, netdev,
-                          "Invalid value, tx-usecs range is 0-8160\n");
+               netif_info(pf, drv, netdev, "Invalid queue value, queue range is 0 - %d\n",
+                          vsi->num_queue_pairs - 1);
                return -EINVAL;
        }
 
-       if (ec->use_adaptive_rx_coalesce)
-               vsi->rx_itr_setting |= I40E_ITR_DYNAMIC;
-       else
-               vsi->rx_itr_setting &= ~I40E_ITR_DYNAMIC;
-
-       if (ec->use_adaptive_tx_coalesce)
-               vsi->tx_itr_setting |= I40E_ITR_DYNAMIC;
-       else
-               vsi->tx_itr_setting &= ~I40E_ITR_DYNAMIC;
-
-       for (i = 0; i < vsi->num_q_vectors; i++, vector++) {
-               u16 intrl = INTRL_USEC_TO_REG(vsi->int_rate_limit);
+       return 0;
+}
 
-               q_vector = vsi->q_vectors[i];
-               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
-               wr32(hw, I40E_PFINT_ITRN(0, vector - 1), q_vector->rx.itr);
-               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
-               wr32(hw, I40E_PFINT_ITRN(1, vector - 1), q_vector->tx.itr);
-               wr32(hw, I40E_PFINT_RATEN(vector - 1), intrl);
-               i40e_flush(hw);
-       }
+static int i40e_set_coalesce(struct net_device *netdev,
+                            struct ethtool_coalesce *ec)
+{
+       return __i40e_set_coalesce(netdev, ec, -1);
+}
 
-       return 0;
+static int i40e_set_per_queue_coalesce(struct net_device *netdev, u32 queue,
+                                      struct ethtool_coalesce *ec)
+{
+       return __i40e_set_coalesce(netdev, ec, queue);
 }
 
 /**
@@ -2151,8 +2236,8 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
 static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
 {
        struct i40e_hw *hw = &pf->hw;
-       u64 hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
-                  ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+       u64 hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
+                  ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
 
        /* RSS does not support anything other than hashing
         * to queues on src and dst IPs and ports
@@ -2261,8 +2346,8 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
                return -EINVAL;
        }
 
-       wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
-       wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
        i40e_flush(hw);
 
        /* Save setting for future output/update */
@@ -2728,6 +2813,8 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
                I40E_PRIV_FLAGS_VEB_STATS : 0;
        ret_flags |= pf->flags & I40E_FLAG_RX_PS_ENABLED ?
                I40E_PRIV_FLAGS_PS : 0;
+       ret_flags |= pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE ?
+               0 : I40E_PRIV_FLAGS_HW_ATR_EVICT;
 
        return ret_flags;
 }
@@ -2779,10 +2866,21 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
                pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
        }
 
-       if (flags & I40E_PRIV_FLAGS_VEB_STATS)
+       if ((flags & I40E_PRIV_FLAGS_VEB_STATS) &&
+           !(pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
                pf->flags |= I40E_FLAG_VEB_STATS_ENABLED;
-       else
+               reset_required = true;
+       } else if (!(flags & I40E_PRIV_FLAGS_VEB_STATS) &&
+                  (pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
                pf->flags &= ~I40E_FLAG_VEB_STATS_ENABLED;
+               reset_required = true;
+       }
+
+       if ((flags & I40E_PRIV_FLAGS_HW_ATR_EVICT) &&
+           (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))
+               pf->auto_disable_flags &= ~I40E_FLAG_HW_ATR_EVICT_CAPABLE;
+       else
+               pf->auto_disable_flags |= I40E_FLAG_HW_ATR_EVICT_CAPABLE;
 
        /* if needed, issue reset to cause things to take effect */
        if (reset_required)
@@ -2828,6 +2926,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
        .get_ts_info            = i40e_get_ts_info,
        .get_priv_flags         = i40e_get_priv_flags,
        .set_priv_flags         = i40e_set_priv_flags,
+       .get_per_queue_coalesce = i40e_get_per_queue_coalesce,
+       .set_per_queue_coalesce = i40e_set_per_queue_coalesce,
 };
 
 void i40e_set_ethtool_ops(struct net_device *netdev)
index 579a46ca82dfa3bce548b7ae81527b064d7b1509..8ad162c16f618c6a87142643301b6dc10e6334cf 100644 (file)
@@ -295,11 +295,11 @@ void i40e_init_pf_fcoe(struct i40e_pf *pf)
        }
 
        /* enable FCoE hash filter */
-       val = rd32(hw, I40E_PFQF_HENA(1));
+       val = i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1));
        val |= BIT(I40E_FILTER_PCTYPE_FCOE_OX - 32);
        val |= BIT(I40E_FILTER_PCTYPE_FCOE_RX - 32);
        val &= I40E_PFQF_HENA_PTYPE_ENA_MASK;
-       wr32(hw, I40E_PFQF_HENA(1), val);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), val);
 
        /* enable flag */
        pf->flags |= I40E_FLAG_FCOE_ENABLED;
@@ -317,11 +317,11 @@ void i40e_init_pf_fcoe(struct i40e_pf *pf)
        pf->filter_settings.fcoe_cntx_num = I40E_DMA_CNTX_SIZE_4K;
 
        /* Setup max frame with FCoE_MTU plus L2 overheads */
-       val = rd32(hw, I40E_GLFCOE_RCTL);
+       val = i40e_read_rx_ctl(hw, I40E_GLFCOE_RCTL);
        val &= ~I40E_GLFCOE_RCTL_MAX_SIZE_MASK;
        val |= ((FCOE_MTU + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
                 << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT);
-       wr32(hw, I40E_GLFCOE_RCTL, val);
+       i40e_write_rx_ctl(hw, I40E_GLFCOE_RCTL, val);
 
        dev_info(&pf->pdev->dev, "FCoE is supported.\n");
 }
@@ -1359,16 +1359,32 @@ static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb,
        struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping];
        struct i40e_tx_buffer *first;
        u32 tx_flags = 0;
+       int fso, count;
        u8 hdr_len = 0;
        u8 sof = 0;
        u8 eof = 0;
-       int fso;
 
        if (i40e_fcoe_set_skb_header(skb))
                goto out_drop;
 
-       if (!i40e_xmit_descriptor_count(skb, tx_ring))
+       count = i40e_xmit_descriptor_count(skb);
+       if (i40e_chk_linearize(skb, count)) {
+               if (__skb_linearize(skb))
+                       goto out_drop;
+               count = TXD_USE_COUNT(skb->len);
+               tx_ring->tx_stats.tx_linearize++;
+       }
+
+       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+        *       + 4 desc gap to avoid the cache line where head is,
+        *       + 1 desc for context descriptor,
+        * otherwise try next time
+        */
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+               tx_ring->tx_stats.tx_busy++;
                return NETDEV_TX_BUSY;
+       }
 
        /* prepare the xmit flags */
        if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -1457,7 +1473,7 @@ static const struct net_device_ops i40e_fcoe_netdev_ops = {
        .ndo_tx_timeout         = i40e_tx_timeout,
        .ndo_vlan_rx_add_vid    = i40e_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = i40e_vlan_rx_kill_vid,
-       .ndo_setup_tc           = i40e_setup_tc,
+       .ndo_setup_tc           = __i40e_setup_tc,
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = i40e_netpoll,
index 320b0491abd95db56a7d71028fba3585acd20134..70d9605a0d9e712f1bb89a38da053c8b07ee9a83 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
 #include <linux/of_net.h>
 #include <linux/pci.h>
 
-#ifdef CONFIG_SPARC
-#include <asm/idprom.h>
-#include <asm/prom.h>
-#endif
-
 /* Local includes */
 #include "i40e.h"
 #include "i40e_diag.h"
@@ -51,7 +46,7 @@ static const char i40e_driver_string[] =
 
 #define DRV_VERSION_MAJOR 1
 #define DRV_VERSION_MINOR 4
-#define DRV_VERSION_BUILD 10
+#define DRV_VERSION_BUILD 25
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -773,7 +768,7 @@ static void i40e_update_fcoe_stats(struct i40e_vsi *vsi)
        if (vsi->type != I40E_VSI_FCOE)
                return;
 
-       idx = (pf->pf_seid - I40E_BASE_PF_SEID) + I40E_FCOE_PF_STAT_OFFSET;
+       idx = hw->pf_id + I40E_FCOE_PF_STAT_OFFSET;
        fs = &vsi->fcoe_stats;
        ofs = &vsi->fcoe_stats_offsets;
 
@@ -824,6 +819,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        struct i40e_eth_stats *oes;
        struct i40e_eth_stats *es;     /* device's eth stats */
        u32 tx_restart, tx_busy;
+       u64 tx_lost_interrupt;
        struct i40e_ring *p;
        u32 rx_page, rx_buf;
        u64 bytes, packets;
@@ -849,6 +845,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        rx_b = rx_p = 0;
        tx_b = tx_p = 0;
        tx_restart = tx_busy = tx_linearize = tx_force_wb = 0;
+       tx_lost_interrupt = 0;
        rx_page = 0;
        rx_buf = 0;
        rcu_read_lock();
@@ -867,6 +864,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
                tx_busy += p->tx_stats.tx_busy;
                tx_linearize += p->tx_stats.tx_linearize;
                tx_force_wb += p->tx_stats.tx_force_wb;
+               tx_lost_interrupt += p->tx_stats.tx_lost_interrupt;
 
                /* Rx queue is part of the same block as Tx queue */
                p = &p[1];
@@ -885,6 +883,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        vsi->tx_busy = tx_busy;
        vsi->tx_linearize = tx_linearize;
        vsi->tx_force_wb = tx_force_wb;
+       vsi->tx_lost_interrupt = tx_lost_interrupt;
        vsi->rx_page_failed = rx_page;
        vsi->rx_buf_failed = rx_buf;
 
@@ -1542,7 +1541,11 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
 
        ether_addr_copy(netdev->dev_addr, addr->sa_data);
 
-       return i40e_sync_vsi_filters(vsi);
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
+       return 0;
 }
 
 /**
@@ -1766,6 +1769,11 @@ bottom_of_search_loop:
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
                vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
        }
+
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
 }
 
 /**
@@ -1937,7 +1945,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                            sizeof(struct i40e_aqc_remove_macvlan_element_data);
                del_list_size = filter_list_len *
                            sizeof(struct i40e_aqc_remove_macvlan_element_data);
-               del_list = kzalloc(del_list_size, GFP_KERNEL);
+               del_list = kzalloc(del_list_size, GFP_ATOMIC);
                if (!del_list) {
                        i40e_cleanup_add_list(&tmp_add_list);
 
@@ -2015,7 +2023,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                               sizeof(struct i40e_aqc_add_macvlan_element_data),
                add_list_size = filter_list_len *
                               sizeof(struct i40e_aqc_add_macvlan_element_data);
-               add_list = kzalloc(add_list_size, GFP_KERNEL);
+               add_list = kzalloc(add_list_size, GFP_ATOMIC);
                if (!add_list) {
                        /* Purge element from temporary lists */
                        i40e_cleanup_add_list(&tmp_add_list);
@@ -2114,7 +2122,9 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
                               test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
                                        &vsi->state));
-               if (vsi->type == I40E_VSI_MAIN && pf->lan_veb != I40E_NO_VEB) {
+               if ((vsi->type == I40E_VSI_MAIN) &&
+                   (pf->lan_veb != I40E_NO_VEB) &&
+                   !(pf->flags & I40E_FLAG_MFP_ENABLED)) {
                        /* set defport ON for Main VSI instead of true promisc
                         * this way we will get all unicast/multicast and VLAN
                         * promisc behavior but will not get VF or VMDq traffic
@@ -2164,6 +2174,10 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                }
        }
 out:
+       /* if something went wrong then set the changed flag so we try again */
+       if (retval)
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+
        clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
        return retval;
 }
@@ -3110,11 +3124,11 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
                struct i40e_q_vector *q_vector = vsi->q_vectors[i];
 
                q_vector->itr_countdown = ITR_COUNTDOWN_START;
-               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+               q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[i]->rx_itr_setting);
                q_vector->rx.latency_range = I40E_LOW_LATENCY;
                wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
                     q_vector->rx.itr);
-               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+               q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[i]->tx_itr_setting);
                q_vector->tx.latency_range = I40E_LOW_LATENCY;
                wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
                     q_vector->tx.itr);
@@ -3206,10 +3220,10 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
 
        /* set the ITR configuration */
        q_vector->itr_countdown = ITR_COUNTDOWN_START;
-       q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+       q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[0]->rx_itr_setting);
        q_vector->rx.latency_range = I40E_LOW_LATENCY;
        wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.itr);
-       q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+       q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[0]->tx_itr_setting);
        q_vector->tx.latency_range = I40E_LOW_LATENCY;
        wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
 
@@ -3249,36 +3263,21 @@ void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf)
 /**
  * i40e_irq_dynamic_enable_icr0 - Enable default interrupt generation for icr0
  * @pf: board private structure
+ * @clearpba: true when all pending interrupt events should be cleared
  **/
-void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf)
+void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf, bool clearpba)
 {
        struct i40e_hw *hw = &pf->hw;
        u32 val;
 
        val = I40E_PFINT_DYN_CTL0_INTENA_MASK   |
-             I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+             (clearpba ? I40E_PFINT_DYN_CTL0_CLEARPBA_MASK : 0) |
              (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
 
        wr32(hw, I40E_PFINT_DYN_CTL0, val);
        i40e_flush(hw);
 }
 
-/**
- * i40e_irq_dynamic_disable - Disable default interrupt generation settings
- * @vsi: pointer to a vsi
- * @vector: disable a particular Hw Interrupt vector
- **/
-void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector)
-{
-       struct i40e_pf *pf = vsi->back;
-       struct i40e_hw *hw = &pf->hw;
-       u32 val;
-
-       val = I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
-       wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val);
-       i40e_flush(hw);
-}
-
 /**
  * i40e_msix_clean_rings - MSIX mode Interrupt Handler
  * @irq: interrupt number
@@ -3404,7 +3403,7 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
                for (i = 0; i < vsi->num_q_vectors; i++)
                        i40e_irq_dynamic_enable(vsi, i);
        } else {
-               i40e_irq_dynamic_enable_icr0(pf);
+               i40e_irq_dynamic_enable_icr0(pf, true);
        }
 
        i40e_flush(&pf->hw);
@@ -3463,16 +3462,12 @@ static irqreturn_t i40e_intr(int irq, void *data)
                struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
                struct i40e_q_vector *q_vector = vsi->q_vectors[0];
 
-               /* temporarily disable queue cause for NAPI processing */
-               u32 qval = rd32(hw, I40E_QINT_RQCTL(0));
-
-               qval &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
-               wr32(hw, I40E_QINT_RQCTL(0), qval);
-
-               qval = rd32(hw, I40E_QINT_TQCTL(0));
-               qval &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
-               wr32(hw, I40E_QINT_TQCTL(0), qval);
-
+               /* We do not have a way to disarm Queue causes while leaving
+                * interrupt enabled for all other causes, ideally
+                * interrupt should be disabled while we are in NAPI but
+                * this is not a performance path and napi_schedule()
+                * can deal with rescheduling.
+                */
                if (!test_bit(__I40E_DOWN, &pf->state))
                        napi_schedule_irqoff(&q_vector->napi);
        }
@@ -3480,6 +3475,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
        if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
                ena_mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
                set_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state);
+               i40e_debug(&pf->hw, I40E_DEBUG_NVM, "AdminQ event\n");
        }
 
        if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
@@ -3550,7 +3546,7 @@ enable_intr:
        wr32(hw, I40E_PFINT_ICR0_ENA, ena_mask);
        if (!test_bit(__I40E_DOWN, &pf->state)) {
                i40e_service_event_schedule(pf);
-               i40e_irq_dynamic_enable_icr0(pf);
+               i40e_irq_dynamic_enable_icr0(pf, false);
        }
 
        return ret;
@@ -3754,7 +3750,7 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename)
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /**
- * i40e_netpoll - A Polling 'interrupt'handler
+ * i40e_netpoll - A Polling 'interrupt' handler
  * @netdev: network interface device structure
  *
  * This is used by netconsole to send skbs without having to re-enable
@@ -3933,6 +3929,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
                else
                        rx_reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
                wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
+               /* No waiting for the Tx queue to disable */
+               if (!enable && test_bit(__I40E_PORT_TX_SUSPENDED, &pf->state))
+                       continue;
 
                /* wait for the change to finish */
                ret = i40e_pf_rxq_wait(pf, pf_q, enable);
@@ -4291,12 +4290,12 @@ static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
 
 #ifdef CONFIG_I40E_DCB
 /**
- * i40e_vsi_wait_txq_disabled - Wait for VSI's queues to be disabled
+ * i40e_vsi_wait_queues_disabled - Wait for VSI's queues to be disabled
  * @vsi: the VSI being configured
  *
- * This function waits for the given VSI's Tx queues to be disabled.
+ * This function waits for the given VSI's queues to be disabled.
  **/
-static int i40e_vsi_wait_txq_disabled(struct i40e_vsi *vsi)
+static int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vsi->back;
        int i, pf_q, ret;
@@ -4313,24 +4312,36 @@ static int i40e_vsi_wait_txq_disabled(struct i40e_vsi *vsi)
                }
        }
 
+       pf_q = vsi->base_queue;
+       for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
+               /* Check and wait for the disable status of the queue */
+               ret = i40e_pf_rxq_wait(pf, pf_q, false);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "VSI seid %d Rx ring %d disable timeout\n",
+                                vsi->seid, pf_q);
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
 /**
- * i40e_pf_wait_txq_disabled - Wait for all queues of PF VSIs to be disabled
+ * i40e_pf_wait_queues_disabled - Wait for all queues of PF VSIs to be disabled
  * @pf: the PF
  *
- * This function waits for the Tx queues to be in disabled state for all the
+ * This function waits for the queues to be in disabled state for all the
  * VSIs that are managed by this PF.
  **/
-static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf)
+static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf)
 {
        int v, ret = 0;
 
        for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
                /* No need to wait for FCoE VSI queues */
                if (pf->vsi[v] && pf->vsi[v]->type != I40E_VSI_FCOE) {
-                       ret = i40e_vsi_wait_txq_disabled(pf->vsi[v]);
+                       ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
                        if (ret)
                                break;
                }
@@ -4356,7 +4367,7 @@ static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi)
 {
        struct i40e_ring *tx_ring = NULL;
        struct i40e_pf  *pf;
-       u32 head, val, tx_pending;
+       u32 head, val, tx_pending_hw;
        int i;
 
        pf = vsi->back;
@@ -4382,16 +4393,9 @@ static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi)
        else
                val = rd32(&pf->hw, I40E_PFINT_DYN_CTL0);
 
-       /* Bail out if interrupts are disabled because napi_poll
-        * execution in-progress or will get scheduled soon.
-        * napi_poll cleans TX and RX queues and updates 'next_to_clean'.
-        */
-       if (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))
-               return;
-
        head = i40e_get_head(tx_ring);
 
-       tx_pending = i40e_get_tx_pending(tx_ring);
+       tx_pending_hw = i40e_get_tx_pending(tx_ring, false);
 
        /* HW is done executing descriptors, updated HEAD write back,
         * but SW hasn't processed those descriptors. If interrupt is
@@ -4399,12 +4403,12 @@ static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi)
         * dev_watchdog detecting timeout on those netdev_queue,
         * hence proactively trigger SW interrupt.
         */
-       if (tx_pending) {
+       if (tx_pending_hw && (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))) {
                /* NAPI Poll didn't run and clear since it was set */
                if (test_and_clear_bit(I40E_Q_VECTOR_HUNG_DETECT,
                                       &tx_ring->q_vector->hung_detected)) {
-                       netdev_info(vsi->netdev, "VSI_seid %d, Hung TX queue %d, tx_pending: %d, NTC:0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x\n",
-                                   vsi->seid, q_idx, tx_pending,
+                       netdev_info(vsi->netdev, "VSI_seid %d, Hung TX queue %d, tx_pending_hw: %d, NTC:0x%x, HWB: 0x%x, NTU: 0x%x, TAIL: 0x%x\n",
+                                   vsi->seid, q_idx, tx_pending_hw,
                                    tx_ring->next_to_clean, head,
                                    tx_ring->next_to_use,
                                    readl(tx_ring->tail));
@@ -4417,6 +4421,17 @@ static void i40e_detect_recover_hung_queue(int q_idx, struct i40e_vsi *vsi)
                                &tx_ring->q_vector->hung_detected);
                }
        }
+
+       /* This is the case where we have interrupts missing,
+        * so the tx_pending in HW will most likely be 0, but we
+        * will have tx_pending in SW since the WB happened but the
+        * interrupt got lost.
+        */
+       if ((!tx_pending_hw) && i40e_get_tx_pending(tx_ring, true) &&
+           (!(val & I40E_PFINT_DYN_CTLN_INTENA_MASK))) {
+               if (napi_reschedule(&tx_ring->q_vector->napi))
+                       tx_ring->tx_stats.tx_lost_interrupt++;
+       }
 }
 
 /**
@@ -5020,8 +5035,7 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
        int err = 0;
 
        /* Do not enable DCB for SW1 and SW2 images even if the FW is capable */
-       if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
-           (pf->hw.aq.fw_maj_ver < 4))
+       if (pf->flags & I40E_FLAG_NO_DCB_SUPPORT)
                goto out;
 
        /* Get the initial DCB configuration */
@@ -5253,11 +5267,7 @@ void i40e_down(struct i40e_vsi *vsi)
  * @netdev: net device to configure
  * @tc: number of traffic classes to enable
  **/
-#ifdef I40E_FCOE
-int i40e_setup_tc(struct net_device *netdev, u8 tc)
-#else
 static int i40e_setup_tc(struct net_device *netdev, u8 tc)
-#endif
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
@@ -5310,6 +5320,19 @@ exit:
        return ret;
 }
 
+#ifdef I40E_FCOE
+int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+                   struct tc_to_netdev *tc)
+#else
+static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
+                          struct tc_to_netdev *tc)
+#endif
+{
+       if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+       return i40e_setup_tc(netdev, tc->tc);
+}
+
 /**
  * i40e_open - Called when a network interface is made active
  * @netdev: network interface device structure
@@ -5352,7 +5375,8 @@ int i40e_open(struct net_device *netdev)
        vxlan_get_rx_port(netdev);
 #endif
 #ifdef CONFIG_I40E_GENEVE
-       geneve_get_rx_port(netdev);
+       if (pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE)
+               geneve_get_rx_port(netdev);
 #endif
 
        return 0;
@@ -5717,8 +5741,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
        if (ret)
                goto exit;
 
-       /* Wait for the PF's Tx queues to be disabled */
-       ret = i40e_pf_wait_txq_disabled(pf);
+       /* Wait for the PF's queues to be disabled */
+       ret = i40e_pf_wait_queues_disabled(pf);
        if (ret) {
                /* Schedule PF reset to recover */
                set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
@@ -6248,6 +6272,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
                if (hw->debug_mask & I40E_DEBUG_AQ)
                        dev_info(&pf->pdev->dev, "ARQ Overflow Error detected\n");
                val &= ~I40E_PF_ARQLEN_ARQOVFL_MASK;
+               pf->arq_overflows++;
        }
        if (val & I40E_PF_ARQLEN_ARQCRIT_MASK) {
                if (hw->debug_mask & I40E_DEBUG_AQ)
@@ -6323,7 +6348,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
                case i40e_aqc_opc_nvm_erase:
                case i40e_aqc_opc_nvm_update:
                case i40e_aqc_opc_oem_post_update:
-                       i40e_debug(&pf->hw, I40E_DEBUG_NVM, "ARQ NVM operation completed\n");
+                       i40e_debug(&pf->hw, I40E_DEBUG_NVM,
+                                  "ARQ NVM operation 0x%04x completed\n",
+                                  opcode);
                        break;
                default:
                        dev_info(&pf->pdev->dev,
@@ -6807,12 +6834,12 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        if (ret)
                goto end_core_reset;
 
-       /* driver is only interested in link up/down and module qualification
-        * reports from firmware
+       /* The driver only wants link up/down and module qualification
+        * reports from firmware.  Note the negative logic.
         */
        ret = i40e_aq_set_phy_int_mask(&pf->hw,
-                                      I40E_AQ_EVENT_LINK_UPDOWN |
-                                      I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+                                      ~(I40E_AQ_EVENT_LINK_UPDOWN |
+                                        I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL);
        if (ret)
                dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n",
                         i40e_stat_str(&pf->hw, ret),
@@ -7082,12 +7109,13 @@ static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
                                ret = i40e_aq_del_udp_tunnel(hw, i, NULL);
 
                        if (ret) {
-                               dev_info(&pf->pdev->dev,
-                                        "%s vxlan port %d, index %d failed, err %s aq_err %s\n",
-                                        port ? "add" : "delete",
-                                        ntohs(port), i,
-                                        i40e_stat_str(&pf->hw, ret),
-                                        i40e_aq_str(&pf->hw,
+                               dev_dbg(&pf->pdev->dev,
+                                       "%s %s port %d, index %d failed, err %s aq_err %s\n",
+                                       pf->udp_ports[i].type ? "vxlan" : "geneve",
+                                       port ? "add" : "delete",
+                                       ntohs(port), i,
+                                       i40e_stat_str(&pf->hw, ret),
+                                       i40e_aq_str(&pf->hw,
                                                    pf->hw.aq.asq_last_status));
                                pf->udp_ports[i].index = 0;
                        }
@@ -7114,6 +7142,7 @@ static void i40e_service_task(struct work_struct *work)
        }
 
        i40e_detect_recover_hung(pf);
+       i40e_sync_filters_subtask(pf);
        i40e_reset_subtask(pf);
        i40e_handle_mdd_event(pf);
        i40e_vc_process_vflr_event(pf);
@@ -7293,8 +7322,6 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
        set_bit(__I40E_DOWN, &vsi->state);
        vsi->flags = 0;
        vsi->idx = vsi_idx;
-       vsi->rx_itr_setting = pf->rx_itr_default;
-       vsi->tx_itr_setting = pf->tx_itr_default;
        vsi->int_rate_limit = 0;
        vsi->rss_table_size = (vsi->type == I40E_VSI_MAIN) ?
                                pf->rss_table_size : 64;
@@ -7461,8 +7488,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                tx_ring->dcb_tc = 0;
                if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE)
                        tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
-               if (vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE)
-                       tx_ring->flags |= I40E_TXR_FLAGS_OUTER_UDP_CSUM;
+               tx_ring->tx_itr_setting = pf->tx_itr_default;
                vsi->tx_rings[i] = tx_ring;
 
                rx_ring = &tx_ring[1];
@@ -7479,6 +7505,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
                        set_ring_16byte_desc_enabled(rx_ring);
                else
                        clear_ring_16byte_desc_enabled(rx_ring);
+               rx_ring->rx_itr_setting = pf->rx_itr_default;
                vsi->rx_rings[i] = rx_ring;
        }
 
@@ -7855,7 +7882,7 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
 
        i40e_flush(hw);
 
-       i40e_irq_dynamic_enable_icr0(pf);
+       i40e_irq_dynamic_enable_icr0(pf, true);
 
        return err;
 }
@@ -8005,7 +8032,7 @@ static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
                u32 *seed_dw = (u32 *)seed;
 
                for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-                       wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+                       i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
        }
 
        if (lut) {
@@ -8042,7 +8069,7 @@ static int i40e_get_rss_reg(struct i40e_vsi *vsi, u8 *seed,
                u32 *seed_dw = (u32 *)seed;
 
                for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-                       seed_dw[i] = rd32(hw, I40E_PFQF_HKEY(i));
+                       seed_dw[i] = i40e_read_rx_ctl(hw, I40E_PFQF_HKEY(i));
        }
        if (lut) {
                u32 *lut_dw = (u32 *)lut;
@@ -8125,19 +8152,19 @@ static int i40e_pf_config_rss(struct i40e_pf *pf)
        int ret;
 
        /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
-       hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
-               ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+       hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) |
+               ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32);
        hena |= i40e_pf_get_default_rss_hena(pf);
 
-       wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
-       wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
 
        /* Determine the RSS table size based on the hardware capabilities */
-       reg_val = rd32(hw, I40E_PFQF_CTL_0);
+       reg_val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0);
        reg_val = (pf->rss_table_size == 512) ?
                        (reg_val | I40E_PFQF_CTL_0_HASHLUTSIZE_512) :
                        (reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512);
-       wr32(hw, I40E_PFQF_CTL_0, reg_val);
+       i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, reg_val);
 
        /* Determine the RSS size of the VSI */
        if (!vsi->rss_size)
@@ -8421,11 +8448,25 @@ static int i40e_sw_init(struct i40e_pf *pf)
                                 pf->hw.func_caps.fd_filters_best_effort;
        }
 
-       if (((pf->hw.mac.type == I40E_MAC_X710) ||
-            (pf->hw.mac.type == I40E_MAC_XL710)) &&
+       if (i40e_is_mac_710(&pf->hw) &&
            (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
-           (pf->hw.aq.fw_maj_ver < 4)))
+           (pf->hw.aq.fw_maj_ver < 4))) {
                pf->flags |= I40E_FLAG_RESTART_AUTONEG;
+               /* No DCB support  for FW < v4.33 */
+               pf->flags |= I40E_FLAG_NO_DCB_SUPPORT;
+       }
+
+       /* Disable FW LLDP if FW < v4.3 */
+       if (i40e_is_mac_710(&pf->hw) &&
+           (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
+           (pf->hw.aq.fw_maj_ver < 4)))
+               pf->flags |= I40E_FLAG_STOP_FW_LLDP;
+
+       /* Use the FW Set LLDP MIB API if FW > v4.40 */
+       if (i40e_is_mac_710(&pf->hw) &&
+           (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) ||
+           (pf->hw.aq.fw_maj_ver >= 5)))
+               pf->flags |= I40E_FLAG_USE_SET_LLDP_MIB;
 
        if (pf->hw.func_caps.vmdq) {
                pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
@@ -8454,8 +8495,18 @@ static int i40e_sw_init(struct i40e_pf *pf)
                             I40E_FLAG_WB_ON_ITR_CAPABLE |
                             I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE |
                             I40E_FLAG_100M_SGMII_CAPABLE |
+                            I40E_FLAG_USE_SET_LLDP_MIB |
                             I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
+       } else if ((pf->hw.aq.api_maj_ver > 1) ||
+                  ((pf->hw.aq.api_maj_ver == 1) &&
+                   (pf->hw.aq.api_min_ver > 4))) {
+               /* Supported in FW API version higher than 1.4 */
+               pf->flags |= I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
+               pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
+       } else {
+               pf->auto_disable_flags = I40E_FLAG_HW_ATR_EVICT_CAPABLE;
        }
+
        pf->eeprom_version = 0xDEAD;
        pf->lan_veb = I40E_NO_VEB;
        pf->lan_vsi = I40E_NO_VSI;
@@ -8591,9 +8642,6 @@ static void i40e_add_vxlan_port(struct net_device *netdev,
        u8 next_idx;
        u8 idx;
 
-       if (sa_family == AF_INET6)
-               return;
-
        idx = i40e_get_udp_port_idx(pf, port);
 
        /* Check if port already exists */
@@ -8633,9 +8681,6 @@ static void i40e_del_vxlan_port(struct net_device *netdev,
        struct i40e_pf *pf = vsi->back;
        u8 idx;
 
-       if (sa_family == AF_INET6)
-               return;
-
        idx = i40e_get_udp_port_idx(pf, port);
 
        /* Check if port already exists */
@@ -8669,7 +8714,7 @@ static void i40e_add_geneve_port(struct net_device *netdev,
        u8 next_idx;
        u8 idx;
 
-       if (sa_family == AF_INET6)
+       if (!(pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE))
                return;
 
        idx = i40e_get_udp_port_idx(pf, port);
@@ -8713,7 +8758,7 @@ static void i40e_del_geneve_port(struct net_device *netdev,
        struct i40e_pf *pf = vsi->back;
        u8 idx;
 
-       if (sa_family == AF_INET6)
+       if (!(pf->flags & I40E_FLAG_GENEVE_OFFLOAD_CAPABLE))
                return;
 
        idx = i40e_get_udp_port_idx(pf, port);
@@ -8951,7 +8996,7 @@ static const struct net_device_ops i40e_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = i40e_netpoll,
 #endif
-       .ndo_setup_tc           = i40e_setup_tc,
+       .ndo_setup_tc           = __i40e_setup_tc,
 #ifdef I40E_FCOE
        .ndo_fcoe_enable        = i40e_fcoe_enable,
        .ndo_fcoe_disable       = i40e_fcoe_disable,
@@ -9003,10 +9048,14 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        np = netdev_priv(netdev);
        np->vsi = vsi;
 
-       netdev->hw_enc_features |= NETIF_F_IP_CSUM        |
-                                  NETIF_F_GSO_UDP_TUNNEL |
-                                  NETIF_F_GSO_GRE        |
-                                  NETIF_F_TSO            |
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM             |
+                                  NETIF_F_IPV6_CSUM           |
+                                  NETIF_F_TSO                 |
+                                  NETIF_F_TSO6                |
+                                  NETIF_F_TSO_ECN             |
+                                  NETIF_F_GSO_GRE             |
+                                  NETIF_F_GSO_UDP_TUNNEL      |
+                                  NETIF_F_GSO_UDP_TUNNEL_CSUM |
                                   0;
 
        netdev->features = NETIF_F_SG                  |
@@ -9028,6 +9077,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
 
        if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
                netdev->features |= NETIF_F_NTUPLE;
+       if (pf->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE)
+               netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
 
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features;
@@ -9532,10 +9583,15 @@ vector_setup_out:
  **/
 static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
 {
-       struct i40e_pf *pf = vsi->back;
+       struct i40e_pf *pf;
        u8 enabled_tc;
        int ret;
 
+       if (!vsi)
+               return NULL;
+
+       pf = vsi->back;
+
        i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
        i40e_vsi_clear_rings(vsi);
 
@@ -10036,13 +10092,13 @@ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = veb->pf;
        bool is_default = veb->pf->cur_promisc;
-       bool is_cloud = false;
+       bool enable_stats = !!(pf->flags & I40E_FLAG_VEB_STATS_ENABLED);
        int ret;
 
        /* get a VEB from the hardware */
        ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid,
                              veb->enabled_tc, is_default,
-                             is_cloud, &veb->seid, NULL);
+                             &veb->seid, enable_stats, NULL);
        if (ret) {
                dev_info(&pf->pdev->dev,
                         "couldn't add VEB, err %s aq_err %s\n",
@@ -10599,21 +10655,9 @@ static void i40e_print_features(struct i40e_pf *pf)
  **/
 static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)
 {
-       struct device_node *dp = pci_device_to_OF_node(pdev);
-       const unsigned char *addr;
-       u8 *mac_addr = pf->hw.mac.addr;
-
        pf->flags &= ~I40E_FLAG_PF_MAC;
-       addr = of_get_mac_address(dp);
-       if (addr) {
-               ether_addr_copy(mac_addr, addr);
+       if (!eth_platform_get_mac_address(&pdev->dev, pf->hw.mac.addr))
                pf->flags |= I40E_FLAG_PF_MAC;
-#ifdef CONFIG_SPARC
-       } else {
-               ether_addr_copy(mac_addr, idprom->id_ethaddr);
-               pf->flags |= I40E_FLAG_PF_MAC;
-#endif /* CONFIG_SPARC */
-       }
 }
 
 /**
@@ -10636,7 +10680,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        u16 wol_nvm_bits;
        u16 link_status;
        int err;
-       u32 len;
        u32 val;
        u32 i;
        u8 set_fc_aq_fail;
@@ -10819,8 +10862,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * Ignore error return codes because if it was already disabled via
         * hardware settings this will fail
         */
-       if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
-           (pf->hw.aq.fw_maj_ver < 4)) {
+       if (pf->flags & I40E_FLAG_STOP_FW_LLDP) {
                dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n");
                i40e_aq_stop_lldp(hw, true, NULL);
        }
@@ -10895,8 +10937,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                pf->num_alloc_vsi = pf->hw.func_caps.num_vsis;
 
        /* Set up the *vsi struct and our local tracking of the MAIN PF vsi. */
-       len = sizeof(struct i40e_vsi *) * pf->num_alloc_vsi;
-       pf->vsi = kzalloc(len, GFP_KERNEL);
+       pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
+                         GFP_KERNEL);
        if (!pf->vsi) {
                err = -ENOMEM;
                goto err_switch_setup;
@@ -10943,12 +10985,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       /* driver is only interested in link up/down and module qualification
-        * reports from firmware
+       /* The driver only wants link up/down and module qualification
+        * reports from firmware.  Note the negative logic.
         */
        err = i40e_aq_set_phy_int_mask(&pf->hw,
-                                      I40E_AQ_EVENT_LINK_UPDOWN |
-                                      I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
+                                      ~(I40E_AQ_EVENT_LINK_UPDOWN |
+                                        I40E_AQ_EVENT_MODULE_QUAL_FAIL), NULL);
        if (err)
                dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n",
                         i40e_stat_str(&pf->hw, err),
@@ -10999,8 +11041,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
            (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
            !test_bit(__I40E_BAD_EEPROM, &pf->state)) {
-               u32 val;
-
                /* disable link interrupts for VFs */
                val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
                val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
@@ -11111,6 +11151,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        i40e_add_filter_to_drop_tx_flow_control_frames(&pf->hw,
                                                       pf->main_vsi_seid);
 
+       if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) ||
+           (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
+               pf->flags |= I40E_FLAG_HAVE_10GBASET_PHY;
+
        /* print a string summarizing features */
        i40e_print_features(pf);
 
@@ -11167,10 +11211,11 @@ static void i40e_remove(struct pci_dev *pdev)
        i40e_ptp_stop(pf);
 
        /* Disable RSS in hw */
-       wr32(hw, I40E_PFQF_HENA(0), 0);
-       wr32(hw, I40E_PFQF_HENA(1), 0);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
 
        /* no more scheduling of any task */
+       set_bit(__I40E_SUSPENDED, &pf->state);
        set_bit(__I40E_DOWN, &pf->state);
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
@@ -11201,8 +11246,8 @@ static void i40e_remove(struct pci_dev *pdev)
                i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
        /* shutdown and destroy the HMC */
-       if (pf->hw.hmc.hmc_obj) {
-               ret_code = i40e_shutdown_lan_hmc(&pf->hw);
+       if (hw->hmc.hmc_obj) {
+               ret_code = i40e_shutdown_lan_hmc(hw);
                if (ret_code)
                        dev_warn(&pdev->dev,
                                 "Failed to destroy the HMC resources: %d\n",
@@ -11210,7 +11255,7 @@ static void i40e_remove(struct pci_dev *pdev)
        }
 
        /* shutdown the adminq */
-       ret_code = i40e_shutdown_adminq(&pf->hw);
+       ret_code = i40e_shutdown_adminq(hw);
        if (ret_code)
                dev_warn(&pdev->dev,
                         "Failed to destroy the Admin Queue resources: %d\n",
@@ -11238,7 +11283,7 @@ static void i40e_remove(struct pci_dev *pdev)
        kfree(pf->qp_pile);
        kfree(pf->vsi);
 
-       iounmap(pf->hw.hw_addr);
+       iounmap(hw->hw_addr);
        kfree(pf);
        pci_release_selected_regions(pdev,
                                     pci_select_bars(pdev, IORESOURCE_MEM));
index 6100cdd9ad13b420f20a640f8dc2572b89afb92d..5730f8091e1bcd9d27df122ee8375f3feeb6117d 100644 (file)
@@ -693,10 +693,11 @@ i40e_status i40e_nvmupd_command(struct i40e_hw *hw,
        /* early check for status command and debug msgs */
        upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 
-       i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d\n",
+       i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n",
                   i40e_nvm_update_state_str[upd_cmd],
                   hw->nvmupd_state,
-                  hw->aq.nvm_release_on_done);
+                  hw->aq.nvm_release_on_done,
+                  cmd->command, cmd->config, cmd->offset, cmd->data_size);
 
        if (upd_cmd == I40E_NVMUPD_INVALID) {
                *perrno = -EFAULT;
index bb9d583e5416fdf469b7853a92ce8c435901bafd..d51eee5bf79acd19d851a7abe3d6b320a5ce14bb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -74,6 +74,12 @@ i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw,
 
 u32 i40e_led_get(struct i40e_hw *hw);
 void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink);
+i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
+                            u16 led_addr, u32 mode);
+i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+                            u16 *val);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                   u32 time, u32 interval);
 
 /* admin send queue commands */
 
@@ -127,6 +133,9 @@ i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
                u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
                u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_vsi_vlan_promisc(struct i40e_hw *hw,
+                               u16 seid, bool enable,
+                               struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
                                struct i40e_vsi_context *vsi_ctx,
                                struct i40e_asq_cmd_details *cmd_details);
@@ -135,8 +144,8 @@ i40e_status i40e_aq_update_vsi_params(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
                                u16 downlink_seid, u8 enabled_tc,
-                               bool default_port, bool enable_l2_filtering,
-                               u16 *pveb_seid,
+                               bool default_port, u16 *pveb_seid,
+                               bool enable_stats,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw,
                                u16 veb_seid, u16 *switch_id, bool *floating,
@@ -149,6 +158,15 @@ i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 vsi_id,
 i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 vsi_id,
                        struct i40e_aqc_remove_macvlan_element_data *mv_list,
                        u16 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+                       u16 rule_type, u16 dest_vsi, u16 count, __le16 *mr_list,
+                       struct i40e_asq_cmd_details *cmd_details,
+                       u16 *rule_id, u16 *rules_used, u16 *rules_free);
+i40e_status i40e_aq_delete_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
+                       u16 rule_type, u16 rule_id, u16 count, __le16 *mr_list,
+                       struct i40e_asq_cmd_details *cmd_details,
+                       u16 *rules_used, u16 *rules_free);
+
 i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
                                u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen,
                                struct i40e_asq_cmd_details *cmd_details);
@@ -324,4 +342,19 @@ i40e_status i40e_aq_debug_dump(struct i40e_hw *hw, u8 cluster_id,
                               struct i40e_asq_cmd_details *cmd_details);
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
                                                    u16 vsi_seid);
+i40e_status i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 *reg_val,
+                               struct i40e_asq_cmd_details *cmd_details);
+u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
+i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 reg_val,
+                               struct i40e_asq_cmd_details *cmd_details);
+void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
+                                  u16 reg, u8 phy_addr, u16 *value);
+i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
+                                   u16 reg, u8 phy_addr, u16 value);
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                   u32 time, u32 interval);
 #endif /* _I40E_PROTOTYPE_H_ */
index dc0402fe3370049e5fd9938f2be23d1649a71e27..86ca27f72f0294bbaa65e85343b29513288e9dab 100644 (file)
 #define I40E_PRTPM_TLPIC 0x001E43C0 /* Reset: GLOBR */
 #define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0
 #define I40E_PRTPM_TLPIC_ETLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_TLPIC_ETLPIC_SHIFT)
+#define I40E_GL_PRS_FVBM(_i) (0x00269760 + ((_i) * 4)) /* _i=0...3 */ /* Reset: CORER */
+#define I40E_GL_PRS_FVBM_MAX_INDEX 3
+#define I40E_GL_PRS_FVBM_FV_BYTE_INDX_SHIFT 0
+#define I40E_GL_PRS_FVBM_FV_BYTE_INDX_MASK I40E_MASK(0x7F, I40E_GL_PRS_FVBM_FV_BYTE_INDX_SHIFT)
+#define I40E_GL_PRS_FVBM_RULE_BUS_INDX_SHIFT 8
+#define I40E_GL_PRS_FVBM_RULE_BUS_INDX_MASK I40E_MASK(0x3F, I40E_GL_PRS_FVBM_RULE_BUS_INDX_SHIFT)
+#define I40E_GL_PRS_FVBM_MSK_ENA_SHIFT 31
+#define I40E_GL_PRS_FVBM_MSK_ENA_MASK I40E_MASK(0x1, I40E_GL_PRS_FVBM_MSK_ENA_SHIFT)
 #define I40E_GLRPB_DPSS 0x000AC828 /* Reset: CORER */
 #define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0
 #define I40E_GLRPB_DPSS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_DPSS_DPS_TCN_SHIFT)
 #define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63
 #define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0
 #define I40E_PRTQF_FD_FLXINSET_INSET_MASK I40E_MASK(0xFF, I40E_PRTQF_FD_FLXINSET_INSET_SHIFT)
+#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
+#define I40E_PRTQF_FD_INSET_MAX_INDEX 63
+#define I40E_PRTQF_FD_INSET_INSET_SHIFT 0
+#define I40E_PRTQF_FD_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTQF_FD_INSET_INSET_SHIFT)
+#define I40E_PRTQF_FD_INSET(_i, _j) (0x00250000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
+#define I40E_PRTQF_FD_INSET_MAX_INDEX 63
+#define I40E_PRTQF_FD_INSET_INSET_SHIFT 0
+#define I40E_PRTQF_FD_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTQF_FD_INSET_INSET_SHIFT)
 #define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */
 #define I40E_PRTQF_FD_MSK_MAX_INDEX 63
 #define I40E_PRTQF_FD_MSK_MASK_SHIFT 0
 #define I40E_GLQF_FD_PCTYPES_MAX_INDEX 63
 #define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT 0
 #define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_MASK I40E_MASK(0x3F, I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT)
+#define I40E_GLQF_FD_MSK(_i, _j) (0x00267200 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_FD_MSK_MAX_INDEX 1
+#define I40E_GLQF_FD_MSK_MASK_SHIFT 0
+#define I40E_GLQF_FD_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_GLQF_FD_MSK_MASK_SHIFT)
+#define I40E_GLQF_FD_MSK_OFFSET_SHIFT 16
+#define I40E_GLQF_FD_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_GLQF_FD_MSK_OFFSET_SHIFT)
+#define I40E_GLQF_HASH_INSET(_i, _j) (0x00267600 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_HASH_INSET_MAX_INDEX 1
+#define I40E_GLQF_HASH_INSET_INSET_SHIFT 0
+#define I40E_GLQF_HASH_INSET_INSET_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_HASH_INSET_INSET_SHIFT)
+#define I40E_GLQF_HASH_MSK(_i, _j) (0x00267A00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_HASH_MSK_MAX_INDEX 1
+#define I40E_GLQF_HASH_MSK_MASK_SHIFT 0
+#define I40E_GLQF_HASH_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_GLQF_HASH_MSK_MASK_SHIFT)
+#define I40E_GLQF_HASH_MSK_OFFSET_SHIFT 16
+#define I40E_GLQF_HASH_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_GLQF_HASH_MSK_OFFSET_SHIFT)
+#define I40E_GLQF_ORT(_i) (0x00268900 + ((_i) * 4)) /* _i=0...63 */ /* Reset: CORER */
+#define I40E_GLQF_ORT_MAX_INDEX 63
+#define I40E_GLQF_ORT_PIT_INDX_SHIFT 0
+#define I40E_GLQF_ORT_PIT_INDX_MASK I40E_MASK(0x1F, I40E_GLQF_ORT_PIT_INDX_SHIFT)
+#define I40E_GLQF_ORT_FIELD_CNT_SHIFT 5
+#define I40E_GLQF_ORT_FIELD_CNT_MASK I40E_MASK(0x3, I40E_GLQF_ORT_FIELD_CNT_SHIFT)
+#define I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT 7
+#define I40E_GLQF_ORT_FLX_PAYLOAD_MASK I40E_MASK(0x1, I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT)
+#define I40E_GLQF_PIT(_i) (0x00268C80 + ((_i) * 4)) /* _i=0...23 */ /* Reset: CORER */
+#define I40E_GLQF_PIT_MAX_INDEX 23
+#define I40E_GLQF_PIT_SOURCE_OFF_SHIFT 0
+#define I40E_GLQF_PIT_SOURCE_OFF_MASK I40E_MASK(0x1F, I40E_GLQF_PIT_SOURCE_OFF_SHIFT)
+#define I40E_GLQF_PIT_FSIZE_SHIFT 5
+#define I40E_GLQF_PIT_FSIZE_MASK I40E_MASK(0x1F, I40E_GLQF_PIT_FSIZE_SHIFT)
+#define I40E_GLQF_PIT_DEST_OFF_SHIFT 10
+#define I40E_GLQF_PIT_DEST_OFF_MASK I40E_MASK(0x3F, I40E_GLQF_PIT_DEST_OFF_SHIFT)
 #define I40E_GLQF_FDEVICTENA(_i) (0x00270384 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
 #define I40E_GLQF_FDEVICTENA_MAX_INDEX 1
 #define I40E_GLQF_FDEVICTENA_GLQF_FDEVICTENA_SHIFT 0
index 47bd8b3145a79a9bf2e299fc303100be4bf8289c..084d0ab316b796b5d5af2ab87b7a5bee193b5a84 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -610,15 +610,19 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
  * @tx_ring: the ring of descriptors
+ * @in_sw: is tx_pending being checked in SW or HW
  *
  * Since there is no access to the ring head register
  * in XL710, we need to use our local copies
  **/
-u32 i40e_get_tx_pending(struct i40e_ring *ring)
+u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw)
 {
        u32 head, tail;
 
-       head = i40e_get_head(ring);
+       if (!in_sw)
+               head = i40e_get_head(ring);
+       else
+               head = ring->next_to_clean;
        tail = readl(ring->tail);
 
        if (head != tail)
@@ -741,7 +745,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                 * them to be written back in case we stay in NAPI.
                 * In this mode on X722 we do not enable Interrupt.
                 */
-               j = i40e_get_tx_pending(tx_ring);
+               j = i40e_get_tx_pending(tx_ring, false);
 
                if (budget &&
                    ((j / (WB_STRIDE + 1)) == 0) && (j != 0) &&
@@ -774,29 +778,48 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
 }
 
 /**
- * i40e_force_wb - Arm hardware to do a wb on noncache aligned descriptors
+ * i40e_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
  * @vsi: the VSI we care about
- * @q_vector: the vector  on which to force writeback
+ * @q_vector: the vector on which to enable writeback
  *
  **/
-void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
+                                 struct i40e_q_vector *q_vector)
 {
        u16 flags = q_vector->tx.ring[0].flags;
+       u32 val;
 
-       if (flags & I40E_TXR_FLAGS_WB_ON_ITR) {
-               u32 val;
+       if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR))
+               return;
 
-               if (q_vector->arm_wb_state)
-                       return;
+       if (q_vector->arm_wb_state)
+               return;
 
-               val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK;
+       if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+               val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK |
+                     I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */
 
                wr32(&vsi->back->hw,
-                    I40E_PFINT_DYN_CTLN(q_vector->v_idx +
-                                        vsi->base_vector - 1),
+                    I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1),
                     val);
-               q_vector->arm_wb_state = true;
-       } else if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+       } else {
+               val = I40E_PFINT_DYN_CTL0_WB_ON_ITR_MASK |
+                     I40E_PFINT_DYN_CTL0_ITR_INDX_MASK; /* set noitr */
+
+               wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0, val);
+       }
+       q_vector->arm_wb_state = true;
+}
+
+/**
+ * i40e_force_wb - Issue SW Interrupt so HW does a wb
+ * @vsi: the VSI we care about
+ * @q_vector: the vector  on which to force writeback
+ *
+ **/
+void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+       if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
                u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
                          I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */
                          I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
@@ -1041,7 +1064,7 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
                        if (rx_bi->page_dma) {
                                dma_unmap_page(dev,
                                               rx_bi->page_dma,
-                                              PAGE_SIZE / 2,
+                                              PAGE_SIZE,
                                               DMA_FROM_DEVICE);
                                rx_bi->page_dma = 0;
                        }
@@ -1176,16 +1199,19 @@ static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
  * i40e_alloc_rx_buffers_ps - Replace used receive buffers; packet split
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40e_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40e_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
        u16 i = rx_ring->next_to_use;
        union i40e_rx_desc *rx_desc;
        struct i40e_rx_buffer *bi;
+       const int current_node = numa_node_id();
 
        /* do nothing if no valid netdev defined */
        if (!rx_ring->netdev || !cleaned_count)
-               return;
+               return false;
 
        while (cleaned_count--) {
                rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -1193,56 +1219,79 @@ void i40e_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 
                if (bi->skb) /* desc is in use */
                        goto no_buffers;
+
+       /* If we've been moved to a different NUMA node, release the
+        * page so we can get a new one on the current node.
+        */
+               if (bi->page &&  page_to_nid(bi->page) != current_node) {
+                       dma_unmap_page(rx_ring->dev,
+                                      bi->page_dma,
+                                      PAGE_SIZE,
+                                      DMA_FROM_DEVICE);
+                       __free_page(bi->page);
+                       bi->page = NULL;
+                       bi->page_dma = 0;
+                       rx_ring->rx_stats.realloc_count++;
+               } else if (bi->page) {
+                       rx_ring->rx_stats.page_reuse_count++;
+               }
+
                if (!bi->page) {
                        bi->page = alloc_page(GFP_ATOMIC);
                        if (!bi->page) {
                                rx_ring->rx_stats.alloc_page_failed++;
                                goto no_buffers;
                        }
-               }
-
-               if (!bi->page_dma) {
-                       /* use a half page if we're re-using */
-                       bi->page_offset ^= PAGE_SIZE / 2;
                        bi->page_dma = dma_map_page(rx_ring->dev,
                                                    bi->page,
-                                                   bi->page_offset,
-                                                   PAGE_SIZE / 2,
+                                                   0,
+                                                   PAGE_SIZE,
                                                    DMA_FROM_DEVICE);
-                       if (dma_mapping_error(rx_ring->dev,
-                                             bi->page_dma)) {
+                       if (dma_mapping_error(rx_ring->dev, bi->page_dma)) {
                                rx_ring->rx_stats.alloc_page_failed++;
+                               __free_page(bi->page);
+                               bi->page = NULL;
                                bi->page_dma = 0;
+                               bi->page_offset = 0;
                                goto no_buffers;
                        }
+                       bi->page_offset = 0;
                }
 
-               dma_sync_single_range_for_device(rx_ring->dev,
-                                                bi->dma,
-                                                0,
-                                                rx_ring->rx_hdr_len,
-                                                DMA_FROM_DEVICE);
                /* Refresh the desc even if buffer_addrs didn't change
                 * because each write-back erases this info.
                 */
-               rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+               rx_desc->read.pkt_addr =
+                               cpu_to_le64(bi->page_dma + bi->page_offset);
                rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
                i++;
                if (i == rx_ring->count)
                        i = 0;
        }
 
+       if (rx_ring->next_to_use != i)
+               i40e_release_rx_desc(rx_ring, i);
+
+       return false;
+
 no_buffers:
        if (rx_ring->next_to_use != i)
                i40e_release_rx_desc(rx_ring, i);
+
+       /* make sure to come back via polling to try again after
+        * allocation failure
+        */
+       return true;
 }
 
 /**
  * i40e_alloc_rx_buffers_1buf - Replace used receive buffers; single buffer
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
        u16 i = rx_ring->next_to_use;
        union i40e_rx_desc *rx_desc;
@@ -1251,7 +1300,7 @@ void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 
        /* do nothing if no valid netdev defined */
        if (!rx_ring->netdev || !cleaned_count)
-               return;
+               return false;
 
        while (cleaned_count--) {
                rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -1259,8 +1308,10 @@ void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                skb = bi->skb;
 
                if (!skb) {
-                       skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-                                                       rx_ring->rx_buf_len);
+                       skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+                                                         rx_ring->rx_buf_len,
+                                                         GFP_ATOMIC |
+                                                         __GFP_NOWARN);
                        if (!skb) {
                                rx_ring->rx_stats.alloc_buff_failed++;
                                goto no_buffers;
@@ -1278,6 +1329,8 @@ void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                        if (dma_mapping_error(rx_ring->dev, bi->dma)) {
                                rx_ring->rx_stats.alloc_buff_failed++;
                                bi->dma = 0;
+                               dev_kfree_skb(bi->skb);
+                               bi->skb = NULL;
                                goto no_buffers;
                        }
                }
@@ -1289,9 +1342,19 @@ void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                        i = 0;
        }
 
+       if (rx_ring->next_to_use != i)
+               i40e_release_rx_desc(rx_ring, i);
+
+       return false;
+
 no_buffers:
        if (rx_ring->next_to_use != i)
                i40e_release_rx_desc(rx_ring, i);
+
+       /* make sure to come back via polling to try again after
+        * allocation failure
+        */
+       return true;
 }
 
 /**
@@ -1326,16 +1389,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
                                    u16 rx_ptype)
 {
        struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
-       bool ipv4 = false, ipv6 = false;
-       bool ipv4_tunnel, ipv6_tunnel;
-       __wsum rx_udp_csum;
-       struct iphdr *iph;
-       __sum16 csum;
-
-       ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
-                    (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
-       ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
-                    (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
+       bool ipv4, ipv6, ipv4_tunnel, ipv6_tunnel;
 
        skb->ip_summed = CHECKSUM_NONE;
 
@@ -1351,12 +1405,10 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        if (!(decoded.known && decoded.outer_ip))
                return;
 
-       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-           decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
-               ipv4 = true;
-       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-                decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
-               ipv6 = true;
+       ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+              (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4);
+       ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+              (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6);
 
        if (ipv4 &&
            (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) |
@@ -1380,37 +1432,17 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
                return;
 
-       /* If VXLAN/GENEVE traffic has an outer UDPv4 checksum we need to check
-        * it in the driver, hardware does not do it for us.
-        * Since L3L4P bit was set we assume a valid IHL value (>=5)
-        * so the total length of IPv4 header is IHL*4 bytes
-        * The UDP_0 bit *may* bet set if the *inner* header is UDP
+       /* The hardware supported by this driver does not validate outer
+        * checksums for tunneled VXLAN or GENEVE frames.  I don't agree
+        * with it but the specification states that you "MAY validate", it
+        * doesn't make it a hard requirement so if we have validated the
+        * inner checksum report CHECKSUM_UNNECESSARY.
         */
-       if (!(vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) &&
-           (ipv4_tunnel)) {
-               skb->transport_header = skb->mac_header +
-                                       sizeof(struct ethhdr) +
-                                       (ip_hdr(skb)->ihl * 4);
-
-               /* Add 4 bytes for VLAN tagged packets */
-               skb->transport_header += (skb->protocol == htons(ETH_P_8021Q) ||
-                                         skb->protocol == htons(ETH_P_8021AD))
-                                         ? VLAN_HLEN : 0;
-
-               if ((ip_hdr(skb)->protocol == IPPROTO_UDP) &&
-                   (udp_hdr(skb)->check != 0)) {
-                       rx_udp_csum = udp_csum(skb);
-                       iph = ip_hdr(skb);
-                       csum = csum_tcpudp_magic(
-                                       iph->saddr, iph->daddr,
-                                       (skb->len - skb_transport_offset(skb)),
-                                       IPPROTO_UDP, rx_udp_csum);
-
-                       if (udp_hdr(skb)->check != csum)
-                               goto checksum_fail;
-
-               } /* else its GRE and so no outer UDP header */
-       }
+
+       ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
+                    (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
+       ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
+                    (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->csum_level = ipv4_tunnel || ipv6_tunnel;
@@ -1475,18 +1507,19 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
  *
  * Returns true if there's any budget left (e.g. the clean is finished)
  **/
-static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, const int budget)
 {
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
        u16 rx_packet_len, rx_header_len, rx_sph, rx_hbo;
        u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
-       const int current_node = numa_mem_id();
        struct i40e_vsi *vsi = rx_ring->vsi;
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       bool failure = false;
        u8 rx_ptype;
        u64 qword;
+       u32 copysize;
 
        if (budget <= 0)
                return 0;
@@ -1497,7 +1530,9 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                u16 vlan_tag;
                /* return some buffers to hardware, one at a time is too slow */
                if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-                       i40e_alloc_rx_buffers_ps(rx_ring, cleaned_count);
+                       failure = failure ||
+                                 i40e_alloc_rx_buffers_ps(rx_ring,
+                                                          cleaned_count);
                        cleaned_count = 0;
                }
 
@@ -1515,6 +1550,12 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                 * DD bit is set.
                 */
                dma_rmb();
+               /* sync header buffer for reading */
+               dma_sync_single_range_for_cpu(rx_ring->dev,
+                                             rx_ring->rx_bi[0].dma,
+                                             i * rx_ring->rx_hdr_len,
+                                             rx_ring->rx_hdr_len,
+                                             DMA_FROM_DEVICE);
                if (i40e_rx_is_programming_status(qword)) {
                        i40e_clean_programming_status(rx_ring, rx_desc);
                        I40E_RX_INCREMENT(rx_ring, i);
@@ -1523,10 +1564,13 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                rx_bi = &rx_ring->rx_bi[i];
                skb = rx_bi->skb;
                if (likely(!skb)) {
-                       skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-                                                       rx_ring->rx_hdr_len);
+                       skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+                                                         rx_ring->rx_hdr_len,
+                                                         GFP_ATOMIC |
+                                                         __GFP_NOWARN);
                        if (!skb) {
                                rx_ring->rx_stats.alloc_buff_failed++;
+                               failure = true;
                                break;
                        }
 
@@ -1534,8 +1578,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        skb_record_rx_queue(skb, rx_ring->queue_index);
                        /* we are reusing so sync this buffer for CPU use */
                        dma_sync_single_range_for_cpu(rx_ring->dev,
-                                                     rx_bi->dma,
-                                                     0,
+                                                     rx_ring->rx_bi[0].dma,
+                                                     i * rx_ring->rx_hdr_len,
                                                      rx_ring->rx_hdr_len,
                                                      DMA_FROM_DEVICE);
                }
@@ -1553,9 +1597,16 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
 
                rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
                           I40E_RXD_QW1_PTYPE_SHIFT;
-               prefetch(rx_bi->page);
+               /* sync half-page for reading */
+               dma_sync_single_range_for_cpu(rx_ring->dev,
+                                             rx_bi->page_dma,
+                                             rx_bi->page_offset,
+                                             PAGE_SIZE / 2,
+                                             DMA_FROM_DEVICE);
+               prefetch(page_address(rx_bi->page) + rx_bi->page_offset);
                rx_bi->skb = NULL;
                cleaned_count++;
+               copysize = 0;
                if (rx_hbo || rx_sph) {
                        int len;
 
@@ -1566,38 +1617,50 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        memcpy(__skb_put(skb, len), rx_bi->hdr_buf, len);
                } else if (skb->len == 0) {
                        int len;
+                       unsigned char *va = page_address(rx_bi->page) +
+                                           rx_bi->page_offset;
 
-                       len = (rx_packet_len > skb_headlen(skb) ?
-                               skb_headlen(skb) : rx_packet_len);
-                       memcpy(__skb_put(skb, len),
-                              rx_bi->page + rx_bi->page_offset,
-                              len);
-                       rx_bi->page_offset += len;
+                       len = min(rx_packet_len, rx_ring->rx_hdr_len);
+                       memcpy(__skb_put(skb, len), va, len);
+                       copysize = len;
                        rx_packet_len -= len;
                }
-
                /* Get the rest of the data if this was a header split */
                if (rx_packet_len) {
-                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-                                          rx_bi->page,
-                                          rx_bi->page_offset,
-                                          rx_packet_len);
-
-                       skb->len += rx_packet_len;
-                       skb->data_len += rx_packet_len;
-                       skb->truesize += rx_packet_len;
-
-                       if ((page_count(rx_bi->page) == 1) &&
-                           (page_to_nid(rx_bi->page) == current_node))
-                               get_page(rx_bi->page);
-                       else
+                       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+                                       rx_bi->page,
+                                       rx_bi->page_offset + copysize,
+                                       rx_packet_len, I40E_RXBUFFER_2048);
+
+                       /* If the page count is more than 2, then both halves
+                        * of the page are used and we need to free it. Do it
+                        * here instead of in the alloc code. Otherwise one
+                        * of the half-pages might be released between now and
+                        * then, and we wouldn't know which one to use.
+                        * Don't call get_page and free_page since those are
+                        * both expensive atomic operations that just change
+                        * the refcount in opposite directions. Just give the
+                        * page to the stack; he can have our refcount.
+                        */
+                       if (page_count(rx_bi->page) > 2) {
+                               dma_unmap_page(rx_ring->dev,
+                                              rx_bi->page_dma,
+                                              PAGE_SIZE,
+                                              DMA_FROM_DEVICE);
                                rx_bi->page = NULL;
+                               rx_bi->page_dma = 0;
+                               rx_ring->rx_stats.realloc_count++;
+                       } else {
+                               get_page(rx_bi->page);
+                               /* switch to the other half-page here; the
+                                * allocation code programs the right addr
+                                * into HW. If we haven't used this half-page,
+                                * the address won't be changed, and HW can
+                                * just use it next time through.
+                                */
+                               rx_bi->page_offset ^= PAGE_SIZE / 2;
+                       }
 
-                       dma_unmap_page(rx_ring->dev,
-                                      rx_bi->page_dma,
-                                      PAGE_SIZE / 2,
-                                      DMA_FROM_DEVICE);
-                       rx_bi->page_dma = 0;
                }
                I40E_RX_INCREMENT(rx_ring, i);
 
@@ -1656,7 +1719,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_packets += total_rx_packets;
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-       return total_rx_packets;
+       return failure ? budget : total_rx_packets;
 }
 
 /**
@@ -1674,6 +1737,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
        u16 rx_packet_len;
+       bool failure = false;
        u8 rx_ptype;
        u64 qword;
        u16 i;
@@ -1684,7 +1748,9 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
                u16 vlan_tag;
                /* return some buffers to hardware, one at a time is too slow */
                if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-                       i40e_alloc_rx_buffers_1buf(rx_ring, cleaned_count);
+                       failure = failure ||
+                                 i40e_alloc_rx_buffers_1buf(rx_ring,
+                                                            cleaned_count);
                        cleaned_count = 0;
                }
 
@@ -1783,7 +1849,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_packets += total_rx_packets;
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-       return total_rx_packets;
+       return failure ? budget : total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
@@ -1791,7 +1857,9 @@ static u32 i40e_buildreg_itr(const int type, const u16 itr)
        u32 val;
 
        val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
-             I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+             /* Don't clear PBA because that can cause lost interrupts that
+              * came in while we were cleaning/polling
+              */
              (type << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
              (itr << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT);
 
@@ -1814,6 +1882,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
        bool rx = false, tx = false;
        u32 rxval, txval;
        int vector;
+       int idx = q_vector->v_idx;
 
        vector = (q_vector->v_idx + vsi->base_vector);
 
@@ -1823,17 +1892,17 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
        rxval = txval = i40e_buildreg_itr(I40E_ITR_NONE, 0);
 
        if (q_vector->itr_countdown > 0 ||
-           (!ITR_IS_DYNAMIC(vsi->rx_itr_setting) &&
-            !ITR_IS_DYNAMIC(vsi->tx_itr_setting))) {
+           (!ITR_IS_DYNAMIC(vsi->rx_rings[idx]->rx_itr_setting) &&
+            !ITR_IS_DYNAMIC(vsi->tx_rings[idx]->tx_itr_setting))) {
                goto enable_int;
        }
 
-       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) {
+       if (ITR_IS_DYNAMIC(vsi->rx_rings[idx]->rx_itr_setting)) {
                rx = i40e_set_new_dynamic_itr(&q_vector->rx);
                rxval = i40e_buildreg_itr(I40E_RX_ITR, q_vector->rx.itr);
        }
 
-       if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) {
+       if (ITR_IS_DYNAMIC(vsi->tx_rings[idx]->tx_itr_setting)) {
                tx = i40e_set_new_dynamic_itr(&q_vector->tx);
                txval = i40e_buildreg_itr(I40E_TX_ITR, q_vector->tx.itr);
        }
@@ -1906,7 +1975,8 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
         * budget and be more aggressive about cleaning up the Tx descriptors.
         */
        i40e_for_each_ring(ring, q_vector->tx) {
-               clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
+               clean_complete = clean_complete &&
+                                i40e_clean_tx_irq(ring, vsi->work_limit);
                arm_wb = arm_wb || ring->arm_wb;
                ring->arm_wb = false;
        }
@@ -1930,7 +2000,7 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
 
                work_done += cleaned;
                /* if we didn't clean as many as budgeted, we must be done */
-               clean_complete &= (budget_per_ring != cleaned);
+               clean_complete = clean_complete && (budget_per_ring > cleaned);
        }
 
        /* If work not completed, return budget and polling will return */
@@ -1938,7 +2008,7 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
 tx_only:
                if (arm_wb) {
                        q_vector->tx.ring[0].tx_stats.tx_force_wb++;
-                       i40e_force_wb(vsi, q_vector);
+                       i40e_enable_wb_on_itr(vsi, q_vector);
                }
                return budget;
        }
@@ -1951,20 +2021,7 @@ tx_only:
        if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
                i40e_update_enable_itr(vsi, q_vector);
        } else { /* Legacy mode */
-               struct i40e_hw *hw = &vsi->back->hw;
-               /* We re-enable the queue 0 cause, but
-                * don't worry about dynamic_enable
-                * because we left it on for the other
-                * possible interrupts during napi
-                */
-               u32 qval = rd32(hw, I40E_QINT_RQCTL(0)) |
-                          I40E_QINT_RQCTL_CAUSE_ENA_MASK;
-
-               wr32(hw, I40E_QINT_RQCTL(0), qval);
-               qval = rd32(hw, I40E_QINT_TQCTL(0)) |
-                      I40E_QINT_TQCTL_CAUSE_ENA_MASK;
-               wr32(hw, I40E_QINT_TQCTL(0), qval);
-               i40e_irq_dynamic_enable_icr0(vsi->back);
+               i40e_irq_dynamic_enable_icr0(vsi->back, false);
        }
        return 0;
 }
@@ -1974,10 +2031,9 @@ tx_only:
  * @tx_ring:  ring to add programming descriptor to
  * @skb:      send buffer
  * @tx_flags: send tx flags
- * @protocol: wire protocol
  **/
 static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
-                    u32 tx_flags, __be16 protocol)
+                    u32 tx_flags)
 {
        struct i40e_filter_program_desc *fdir_desc;
        struct i40e_pf *pf = tx_ring->vsi->back;
@@ -1989,6 +2045,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        struct tcphdr *th;
        unsigned int hlen;
        u32 flex_ptype, dtype_cmd;
+       int l4_proto;
        u16 i;
 
        /* make sure ATR is enabled */
@@ -2002,36 +2059,28 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (!tx_ring->atr_sample_rate)
                return;
 
+       /* Currently only IPv4/IPv6 with TCP is supported */
        if (!(tx_flags & (I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6)))
                return;
 
-       if (!(tx_flags & I40E_TX_FLAGS_UDP_TUNNEL)) {
-               /* snag network header to get L4 type and address */
-               hdr.network = skb_network_header(skb);
+       /* snag network header to get L4 type and address */
+       hdr.network = (tx_flags & I40E_TX_FLAGS_UDP_TUNNEL) ?
+                     skb_inner_network_header(skb) : skb_network_header(skb);
 
-               /* Currently only IPv4/IPv6 with TCP is supported
-                * access ihl as u8 to avoid unaligned access on ia64
-                */
-               if (tx_flags & I40E_TX_FLAGS_IPV4)
-                       hlen = (hdr.network[0] & 0x0F) << 2;
-               else if (protocol == htons(ETH_P_IPV6))
-                       hlen = sizeof(struct ipv6hdr);
-               else
-                       return;
+       /* Note: tx_flags gets modified to reflect inner protocols in
+        * tx_enable_csum function if encap is enabled.
+        */
+       if (tx_flags & I40E_TX_FLAGS_IPV4) {
+               /* access ihl as u8 to avoid unaligned access on ia64 */
+               hlen = (hdr.network[0] & 0x0F) << 2;
+               l4_proto = hdr.ipv4->protocol;
        } else {
-               hdr.network = skb_inner_network_header(skb);
-               hlen = skb_inner_network_header_len(skb);
+               hlen = hdr.network - skb->data;
+               l4_proto = ipv6_find_hdr(skb, &hlen, IPPROTO_TCP, NULL, NULL);
+               hlen -= hdr.network - skb->data;
        }
 
-       /* Currently only IPv4/IPv6 with TCP is supported
-        * Note: tx_flags gets modified to reflect inner protocols in
-        * tx_enable_csum function if encap is enabled.
-        */
-       if ((tx_flags & I40E_TX_FLAGS_IPV4) &&
-           (hdr.ipv4->protocol != IPPROTO_TCP))
-               return;
-       else if ((tx_flags & I40E_TX_FLAGS_IPV6) &&
-                (hdr.ipv6->nexthdr != IPPROTO_TCP))
+       if (l4_proto != IPPROTO_TCP)
                return;
 
        th = (struct tcphdr *)(hdr.network + hlen);
@@ -2039,7 +2088,8 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        /* 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;
-       if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) {
+       if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
+           (!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE))) {
                /* HW ATR eviction will take care of removing filters on FIN
                 * and RST packets.
                 */
@@ -2067,7 +2117,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        flex_ptype = (tx_ring->queue_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
                      I40E_TXD_FLTR_QW0_QINDEX_MASK;
-       flex_ptype |= (protocol == htons(ETH_P_IP)) ?
+       flex_ptype |= (tx_flags & I40E_TX_FLAGS_IPV4) ?
                      (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
                       I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
                      (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
@@ -2101,7 +2151,8 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
                        I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
                        I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
 
-       if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)
+       if ((pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) &&
+           (!(pf->auto_disable_flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE)))
                dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK;
 
        fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
@@ -2206,13 +2257,23 @@ out:
 static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                    u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
-       u32 cd_cmd, cd_tso_len, cd_mss;
-       struct ipv6hdr *ipv6h;
-       struct tcphdr *tcph;
-       struct iphdr *iph;
-       u32 l4len;
+       u64 cd_cmd, cd_tso_len, cd_mss;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
+       union {
+               struct tcphdr *tcp;
+               struct udphdr *udp;
+               unsigned char *hdr;
+       } l4;
+       u32 paylen, l4_offset;
        int err;
 
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
        if (!skb_is_gso(skb))
                return 0;
 
@@ -2220,35 +2281,60 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
-
-       if (iph->version == 4) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-               iph->tot_len = 0;
-               iph->check = 0;
-               tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                0, IPPROTO_TCP, 0);
-       } else if (ipv6h->version == 6) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-               ipv6h->payload_len = 0;
-               tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-                                              0, IPPROTO_TCP, 0);
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
+
+       /* initialize outer IP header fields */
+       if (ip.v4->version == 4) {
+               ip.v4->tot_len = 0;
+               ip.v4->check = 0;
+       } else {
+               ip.v6->payload_len = 0;
        }
 
-       l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-       *hdr_len = (skb->encapsulation
-                   ? (skb_inner_transport_header(skb) - skb->data)
-                   : skb_transport_offset(skb)) + l4len;
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+                                        SKB_GSO_UDP_TUNNEL_CSUM)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+                       /* determine offset of outer transport header */
+                       l4_offset = l4.hdr - skb->data;
+
+                       /* remove payload length from outer checksum */
+                       paylen = (__force u16)l4.udp->check;
+                       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+               }
+
+               /* reset pointers to inner headers */
+               ip.hdr = skb_inner_network_header(skb);
+               l4.hdr = skb_inner_transport_header(skb);
+
+               /* initialize inner IP header fields */
+               if (ip.v4->version == 4) {
+                       ip.v4->tot_len = 0;
+                       ip.v4->check = 0;
+               } else {
+                       ip.v6->payload_len = 0;
+               }
+       }
+
+       /* determine offset of inner transport header */
+       l4_offset = l4.hdr - skb->data;
+
+       /* remove payload length from inner checksum */
+       paylen = (__force u16)l4.tcp->check;
+       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+
+       /* compute length of segmentation header */
+       *hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
        /* find the field values */
        cd_cmd = I40E_TX_CTX_DESC_TSO;
        cd_tso_len = skb->len - *hdr_len;
        cd_mss = skb_shinfo(skb)->gso_size;
-       *cd_type_cmd_tso_mss |= ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
-                               ((u64)cd_tso_len <<
-                                I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
-                               ((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+       *cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
+                               (cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
+                               (cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
        return 1;
 }
 
@@ -2303,129 +2389,154 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
  * @tx_ring: Tx descriptor ring
  * @cd_tunneling: ptr to context desc bits
  **/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
-                               u32 *td_cmd, u32 *td_offset,
-                               struct i40e_ring *tx_ring,
-                               u32 *cd_tunneling)
+static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
+                              u32 *td_cmd, u32 *td_offset,
+                              struct i40e_ring *tx_ring,
+                              u32 *cd_tunneling)
 {
-       struct ipv6hdr *this_ipv6_hdr;
-       unsigned int this_tcp_hdrlen;
-       struct iphdr *this_ip_hdr;
-       u32 network_hdr_len;
-       u8 l4_hdr = 0;
-       struct udphdr *oudph = NULL;
-       struct iphdr *oiph = NULL;
-       u32 l4_tunnel = 0;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
+       union {
+               struct tcphdr *tcp;
+               struct udphdr *udp;
+               unsigned char *hdr;
+       } l4;
+       unsigned char *exthdr;
+       u32 offset, cmd = 0, tunnel = 0;
+       __be16 frag_off;
+       u8 l4_proto = 0;
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
+
+       /* compute outer L2 header size */
+       offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
 
        if (skb->encapsulation) {
-               switch (ip_hdr(skb)->protocol) {
+               /* define outer network header type */
+               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+                       tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+                                 I40E_TX_CTX_EXT_IP_IPV4 :
+                                 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+
+                       l4_proto = ip.v4->protocol;
+               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+                       tunnel |= I40E_TX_CTX_EXT_IP_IPV6;
+
+                       exthdr = ip.hdr + sizeof(*ip.v6);
+                       l4_proto = ip.v6->nexthdr;
+                       if (l4.hdr != exthdr)
+                               ipv6_skip_exthdr(skb, exthdr - skb->data,
+                                                &l4_proto, &frag_off);
+               }
+
+               /* compute outer L3 header size */
+               tunnel |= ((l4.hdr - ip.hdr) / 4) <<
+                         I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
+
+               /* switch IP header pointer from outer to inner header */
+               ip.hdr = skb_inner_network_header(skb);
+
+               /* define outer transport */
+               switch (l4_proto) {
                case IPPROTO_UDP:
-                       oudph = udp_hdr(skb);
-                       oiph = ip_hdr(skb);
-                       l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
+                       tunnel |= I40E_TXD_CTX_UDP_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
                        break;
                case IPPROTO_GRE:
-                       l4_tunnel = I40E_TXD_CTX_GRE_TUNNELING;
+                       tunnel |= I40E_TXD_CTX_GRE_TUNNELING;
+                       *tx_flags |= I40E_TX_FLAGS_UDP_TUNNEL;
                        break;
                default:
-                       return;
-               }
-               network_hdr_len = skb_inner_network_header_len(skb);
-               this_ip_hdr = inner_ip_hdr(skb);
-               this_ipv6_hdr = inner_ipv6_hdr(skb);
-               this_tcp_hdrlen = inner_tcp_hdrlen(skb);
-
-               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-                       if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                               ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
-               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
                        if (*tx_flags & I40E_TX_FLAGS_TSO)
-                               ip_hdr(skb)->check = 0;
+                               return -1;
+
+                       skb_checksum_help(skb);
+                       return 0;
                }
 
-               /* Now set the ctx descriptor fields */
-               *cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
-                                  I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT      |
-                                  l4_tunnel                             |
-                                  ((skb_inner_network_offset(skb) -
-                                       skb_transport_offset(skb)) >> 1) <<
-                                  I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-               if (this_ip_hdr->version == 6) {
-                       *tx_flags &= ~I40E_TX_FLAGS_IPV4;
+               /* compute tunnel header size */
+               tunnel |= ((ip.hdr - l4.hdr) / 2) <<
+                         I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+
+               /* indicate if we need to offload outer UDP header */
+               if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+                   (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+                       tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
+               /* record tunnel offload values */
+               *cd_tunneling |= tunnel;
+
+               /* switch L4 header pointer from outer to inner */
+               l4.hdr = skb_inner_transport_header(skb);
+               l4_proto = 0;
+
+               /* reset type as we transition from outer to inner headers */
+               *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+               if (ip.v4->version == 4)
+                       *tx_flags |= I40E_TX_FLAGS_IPV4;
+               if (ip.v6->version == 6)
                        *tx_flags |= I40E_TX_FLAGS_IPV6;
-               }
-               if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) &&
-                   (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING)        &&
-                   (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) {
-                       oudph->check = ~csum_tcpudp_magic(oiph->saddr,
-                                       oiph->daddr,
-                                       (skb->len - skb_transport_offset(skb)),
-                                       IPPROTO_UDP, 0);
-                       *cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
-               }
-       } else {
-               network_hdr_len = skb_network_header_len(skb);
-               this_ip_hdr = ip_hdr(skb);
-               this_ipv6_hdr = ipv6_hdr(skb);
-               this_tcp_hdrlen = tcp_hdrlen(skb);
        }
 
        /* Enable IP checksum offloads */
        if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-               l4_hdr = this_ip_hdr->protocol;
+               l4_proto = ip.v4->protocol;
                /* the stack computes the IP header already, the only time we
                 * need the hardware to recompute it is in the case of TSO.
                 */
-               if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-                       this_ip_hdr->check = 0;
-               } else {
-                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
-               }
-               /* Now set the td_offset for IP header length */
-               *td_offset = (network_hdr_len >> 2) <<
-                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+               cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+                      I40E_TX_DESC_CMD_IIPT_IPV4_CSUM :
+                      I40E_TX_DESC_CMD_IIPT_IPV4;
        } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-               l4_hdr = this_ipv6_hdr->nexthdr;
-               *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
-               /* Now set the td_offset for IP header length */
-               *td_offset = (network_hdr_len >> 2) <<
-                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+               exthdr = ip.hdr + sizeof(*ip.v6);
+               l4_proto = ip.v6->nexthdr;
+               if (l4.hdr != exthdr)
+                       ipv6_skip_exthdr(skb, exthdr - skb->data,
+                                        &l4_proto, &frag_off);
        }
-       /* words in MACLEN + dwords in IPLEN + dwords in L4Len */
-       *td_offset |= (skb_network_offset(skb) >> 1) <<
-                      I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+
+       /* compute inner L3 header size */
+       offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
 
        /* Enable L4 checksum offloads */
-       switch (l4_hdr) {
+       switch (l4_proto) {
        case IPPROTO_TCP:
                /* enable checksum offloads */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
-               *td_offset |= (this_tcp_hdrlen >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+               offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        case IPPROTO_SCTP:
                /* enable SCTP checksum offload */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
-               *td_offset |= (sizeof(struct sctphdr) >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+               offset |= (sizeof(struct sctphdr) >> 2) <<
+                         I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        case IPPROTO_UDP:
                /* enable UDP checksum offload */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
-               *td_offset |= (sizeof(struct udphdr) >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+               offset |= (sizeof(struct udphdr) >> 2) <<
+                         I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        default:
-               break;
+               if (*tx_flags & I40E_TX_FLAGS_TSO)
+                       return -1;
+               skb_checksum_help(skb);
+               return 0;
        }
+
+       *td_cmd |= cmd;
+       *td_offset |= offset;
+
+       return 1;
 }
 
 /**
@@ -2466,7 +2577,7 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
  *
  * Returns -EBUSY if a stop is needed, else 0
  **/
-static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
 {
        netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
        /* Memory barrier before checking head and tail */
@@ -2483,77 +2594,71 @@ static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
 }
 
 /**
- * i40e_maybe_stop_tx - 1st level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size:    the size buffer we want to assure is available
- *
- * Returns 0 if stop is not needed
- **/
-#ifdef I40E_FCOE
-inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-#else
-static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-#endif
-{
-       if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
-               return 0;
-       return __i40e_maybe_stop_tx(tx_ring, size);
-}
-
-/**
- * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * __i40e_chk_linearize - Check if there are more than 8 fragments per packet
  * @skb:      send buffer
- * @tx_flags: collected send information
  *
  * Note: Our HW can't scatter-gather more than 8 fragments to build
  * a packet on the wire and so we need to figure out the cases where we
  * need to linearize the skb.
  **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
+bool __i40e_chk_linearize(struct sk_buff *skb)
 {
-       struct skb_frag_struct *frag;
-       bool linearize = false;
-       unsigned int size = 0;
-       u16 num_frags;
-       u16 gso_segs;
+       const struct skb_frag_struct *frag, *stale;
+       int gso_size, nr_frags, sum;
 
-       num_frags = skb_shinfo(skb)->nr_frags;
-       gso_segs = skb_shinfo(skb)->gso_segs;
+       /* check to see if TSO is enabled, if so we may get a repreive */
+       gso_size = skb_shinfo(skb)->gso_size;
+       if (unlikely(!gso_size))
+               return true;
 
-       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-               u16 j = 0;
+       /* no need to check if number of frags is less than 8 */
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       if (nr_frags < I40E_MAX_BUFFER_TXD)
+               return false;
 
-               if (num_frags < (I40E_MAX_BUFFER_TXD))
-                       goto linearize_chk_done;
-               /* try the simple math, if we have too many frags per segment */
-               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
-                   I40E_MAX_BUFFER_TXD) {
-                       linearize = true;
-                       goto linearize_chk_done;
-               }
-               frag = &skb_shinfo(skb)->frags[0];
-               /* we might still have more fragments per segment */
-               do {
-                       size += skb_frag_size(frag);
-                       frag++; j++;
-                       if ((size >= skb_shinfo(skb)->gso_size) &&
-                           (j < I40E_MAX_BUFFER_TXD)) {
-                               size = (size % skb_shinfo(skb)->gso_size);
-                               j = (size) ? 1 : 0;
-                       }
-                       if (j == I40E_MAX_BUFFER_TXD) {
-                               linearize = true;
-                               break;
-                       }
-                       num_frags--;
-               } while (num_frags);
-       } else {
-               if (num_frags >= I40E_MAX_BUFFER_TXD)
-                       linearize = true;
+       /* We need to walk through the list and validate that each group
+        * of 6 fragments totals at least gso_size.  However we don't need
+        * to perform such validation on the first or last 6 since the first
+        * 6 cannot inherit any data from a descriptor before them, and the
+        * last 6 cannot inherit any data from a descriptor after them.
+        */
+       nr_frags -= I40E_MAX_BUFFER_TXD - 1;
+       frag = &skb_shinfo(skb)->frags[0];
+
+       /* Initialize size to the negative value of gso_size minus 1.  We
+        * use this as the worst case scenerio in which the frag ahead
+        * of us only provides one byte which is why we are limited to 6
+        * descriptors for a single transmit as the header and previous
+        * fragment are already consuming 2 descriptors.
+        */
+       sum = 1 - gso_size;
+
+       /* Add size of frags 1 through 5 to create our initial sum */
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+
+       /* Walk through fragments adding latest fragment, testing it, and
+        * then removing stale fragments from the sum.
+        */
+       stale = &skb_shinfo(skb)->frags[0];
+       for (;;) {
+               sum += skb_frag_size(++frag);
+
+               /* if sum is negative we failed to make sufficient progress */
+               if (sum < 0)
+                       return true;
+
+               /* use pre-decrement to avoid processing last fragment */
+               if (!--nr_frags)
+                       break;
+
+               sum -= skb_frag_size(++stale);
        }
 
-linearize_chk_done:
-       return linearize;
+       return false;
 }
 
 /**
@@ -2759,43 +2864,6 @@ dma_error:
        tx_ring->next_to_use = i;
 }
 
-/**
- * i40e_xmit_descriptor_count - calculate number of tx descriptors needed
- * @skb:     send buffer
- * @tx_ring: ring to send buffer on
- *
- * Returns number of data descriptors needed for this skb. Returns 0 to indicate
- * there is not enough descriptors available in this ring since we need at least
- * one descriptor.
- **/
-#ifdef I40E_FCOE
-inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
-                                     struct i40e_ring *tx_ring)
-#else
-static inline int i40e_xmit_descriptor_count(struct sk_buff *skb,
-                                            struct i40e_ring *tx_ring)
-#endif
-{
-       unsigned int f;
-       int count = 0;
-
-       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
-        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 4 desc gap to avoid the cache line where head is,
-        *       + 1 desc for context descriptor,
-        * otherwise try next time
-        */
-       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
-               count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
-
-       count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
-               tx_ring->tx_stats.tx_busy++;
-               return 0;
-       }
-       return count;
-}
-
 /**
  * i40e_xmit_frame_ring - Sends buffer on Tx ring
  * @skb:     send buffer
@@ -2814,14 +2882,30 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        __be16 protocol;
        u32 td_cmd = 0;
        u8 hdr_len = 0;
+       int tso, count;
        int tsyn;
-       int tso;
 
        /* prefetch the data, we'll need it later */
        prefetch(skb->data);
 
-       if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
+       count = i40e_xmit_descriptor_count(skb);
+       if (i40e_chk_linearize(skb, count)) {
+               if (__skb_linearize(skb))
+                       goto out_drop;
+               count = TXD_USE_COUNT(skb->len);
+               tx_ring->tx_stats.tx_linearize++;
+       }
+
+       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+        *       + 4 desc gap to avoid the cache line where head is,
+        *       + 1 desc for context descriptor,
+        * otherwise try next time
+        */
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+               tx_ring->tx_stats.tx_busy++;
                return NETDEV_TX_BUSY;
+       }
 
        /* prepare the xmit flags */
        if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -2846,29 +2930,22 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
+       /* Always offload the checksum, since it's in the data descriptor */
+       tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
+                                 tx_ring, &cd_tunneling);
+       if (tso < 0)
+               goto out_drop;
+
        tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss);
 
        if (tsyn)
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
-       if (i40e_chk_linearize(skb, tx_flags)) {
-               if (skb_linearize(skb))
-                       goto out_drop;
-               tx_ring->tx_stats.tx_linearize++;
-       }
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
        td_cmd |= I40E_TX_DESC_CMD_ICRC;
 
-       /* Always offload the checksum, since it's in the data descriptor */
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               tx_flags |= I40E_TX_FLAGS_CSUM;
-
-               i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
-                                   tx_ring, &cd_tunneling);
-       }
-
        i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
                           cd_tunneling, cd_l2tag2);
 
@@ -2876,7 +2953,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
         *
         * NOTE: this must always be directly before the data descriptor.
         */
-       i40e_atr(tx_ring, skb, tx_flags, protocol);
+       i40e_atr(tx_ring, skb, tx_flags);
 
        i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
                    td_cmd, td_offset);
index 3f081e25e097aa34cca027e60c9bb720e310e9d6..cdd5dc00aec519972dd3af6166666a0d3c65766f 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -153,7 +153,6 @@ enum i40e_dyn_idx_t {
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 #define I40E_MIN_DESC_PENDING  4
 
-#define I40E_TX_FLAGS_CSUM             BIT(0)
 #define I40E_TX_FLAGS_HW_VLAN          BIT(1)
 #define I40E_TX_FLAGS_SW_VLAN          BIT(2)
 #define I40E_TX_FLAGS_TSO              BIT(3)
@@ -203,12 +202,15 @@ struct i40e_tx_queue_stats {
        u64 tx_done_old;
        u64 tx_linearize;
        u64 tx_force_wb;
+       u64 tx_lost_interrupt;
 };
 
 struct i40e_rx_queue_stats {
        u64 non_eop_descs;
        u64 alloc_page_failed;
        u64 alloc_buff_failed;
+       u64 page_reuse_count;
+       u64 realloc_count;
 };
 
 enum i40e_ring_state_t {
@@ -246,6 +248,14 @@ struct i40e_ring {
        u8 dcb_tc;                      /* Traffic class of ring */
        u8 __iomem *tail;
 
+       /* high bit set means dynamic, use accessor routines to read/write.
+        * hardware only supports 2us resolution for the ITR registers.
+        * these values always store the USER setting, and must be converted
+        * before programming to a register.
+        */
+       u16 rx_itr_setting;
+       u16 tx_itr_setting;
+
        u16 count;                      /* Number of descriptors */
        u16 reg_idx;                    /* HW register index of the ring */
        u16 rx_hdr_len;
@@ -254,7 +264,6 @@ struct i40e_ring {
 #define I40E_RX_DTYPE_NO_SPLIT      0
 #define I40E_RX_DTYPE_HEADER_SPLIT  1
 #define I40E_RX_DTYPE_SPLIT_ALWAYS  2
-       u8  hsplit;
 #define I40E_RX_SPLIT_L2      0x1
 #define I40E_RX_SPLIT_IP      0x2
 #define I40E_RX_SPLIT_TCP_UDP 0x4
@@ -275,7 +284,6 @@ struct i40e_ring {
 
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR       BIT(0)
-#define I40E_TXR_FLAGS_OUTER_UDP_CSUM  BIT(1)
 #define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
        /* stats structs */
@@ -316,8 +324,8 @@ struct i40e_ring_container {
 #define i40e_for_each_ring(pos, head) \
        for (pos = (head).ring; pos != NULL; pos = pos->next)
 
-void i40e_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
-void i40e_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40e_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40e_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
 void i40e_alloc_rx_headers(struct i40e_ring *rxr);
 netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
@@ -331,13 +339,13 @@ int i40e_napi_poll(struct napi_struct *napi, int budget);
 void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                 struct i40e_tx_buffer *first, u32 tx_flags,
                 const u8 hdr_len, u32 td_cmd, u32 td_offset);
-int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
-int i40e_xmit_descriptor_count(struct sk_buff *skb, struct i40e_ring *tx_ring);
 int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
                               struct i40e_ring *tx_ring, u32 *flags);
 #endif
 void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
-u32 i40e_get_tx_pending(struct i40e_ring *ring);
+u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
+int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
+bool __i40e_chk_linearize(struct sk_buff *skb);
 
 /**
  * i40e_get_head - Retrieve head from head writeback
@@ -352,4 +360,63 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
 
        return le32_to_cpu(*(volatile __le32 *)head);
 }
+
+/**
+ * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns number of data descriptors needed for this skb. Returns 0 to indicate
+ * there is not enough descriptors available in this ring since we need at least
+ * one descriptor.
+ **/
+static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
+{
+       const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+       unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+       int count = 0, size = skb_headlen(skb);
+
+       for (;;) {
+               count += TXD_USE_COUNT(size);
+
+               if (!nr_frags--)
+                       break;
+
+               size = skb_frag_size(frag++);
+       }
+
+       return count;
+}
+
+/**
+ * i40e_maybe_stop_tx - 1st level check for Tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+       if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __i40e_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @count:    number of buffers used
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
+{
+       /* we can only support up to 8 data buffers for a single send */
+       if (likely(count <= I40E_MAX_BUFFER_TXD))
+               return false;
+
+       return __i40e_chk_linearize(skb);
+}
 #endif /* _I40E_TXRX_H_ */
index dd2da356d9a1bb6628fcd0825f400350fc037e6f..0a0baf71041b050d3cda5ee902f94a8e33b81548 100644 (file)
@@ -90,6 +90,22 @@ enum i40e_debug_mask {
        I40E_DEBUG_ALL                  = 0xFFFFFFFF
 };
 
+#define I40E_MDIO_STCODE                0
+#define I40E_MDIO_OPCODE_ADDRESS        0
+#define I40E_MDIO_OPCODE_WRITE          I40E_MASK(1, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ_INC_ADDR  I40E_MASK(2, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ           I40E_MASK(3, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+
+#define I40E_PHY_COM_REG_PAGE                   0x1E
+#define I40E_PHY_LED_LINK_MODE_MASK             0xF0
+#define I40E_PHY_LED_MANUAL_ON                  0x100
+#define I40E_PHY_LED_PROV_REG_1                 0xC430
+#define I40E_PHY_LED_MODE_MASK                  0xFFFF
+#define I40E_PHY_LED_MODE_ORIG                  0x80000000
+
 /* These are structs for managing the hardware information and the operations.
  * The structures of function pointers are filled out at init time when we
  * know for sure exactly which hardware we're working with.  This gives us the
@@ -1098,6 +1114,10 @@ enum i40e_filter_program_desc_pcmd {
                                         I40E_TXD_FLTR_QW1_CMD_SHIFT)
 #define I40E_TXD_FLTR_QW1_ATR_MASK     BIT_ULL(I40E_TXD_FLTR_QW1_ATR_SHIFT)
 
+#define I40E_TXD_FLTR_QW1_ATR_SHIFT    (0xEULL + \
+                                        I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_ATR_MASK     BIT_ULL(I40E_TXD_FLTR_QW1_ATR_SHIFT)
+
 #define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20
 #define I40E_TXD_FLTR_QW1_CNTINDEX_MASK        (0x1FFUL << \
                                         I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT)
index 659d78270fdbaffe5e99f766d673f01cef98ab6a..acd2693a4e97d9747ea446d4c499dd44f00918cf 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -461,7 +461,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id,
                rx_ctx.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
 
                /* set splitalways mode 10b */
-               rx_ctx.dtype = 0x2;
+               rx_ctx.dtype = I40E_RX_DTYPE_HEADER_SPLIT;
        }
 
        /* databuffer length validation */
@@ -602,8 +602,8 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
         * that VF queues be mapped using this method, even when they are
         * contiguous in real life
         */
-       wr32(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
-            I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
+       i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
+                         I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
 
        /* enable VF vplan_qtable mappings */
        reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
@@ -630,7 +630,8 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
                                                      (j * 2) + 1);
                        reg |= qid << 16;
                }
-               wr32(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id), reg);
+               i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id),
+                                 reg);
        }
 
        i40e_flush(hw);
@@ -980,7 +981,7 @@ err_alloc:
                i40e_free_vfs(pf);
 err_iov:
        /* Re-enable interrupt 0. */
-       i40e_irq_dynamic_enable_icr0(pf);
+       i40e_irq_dynamic_enable_icr0(pf, false);
        return ret;
 }
 
@@ -2037,7 +2038,11 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
        if (!test_bit(__I40E_VFLR_EVENT_PENDING, &pf->state))
                return 0;
 
-       /* re-enable vflr interrupt cause */
+       /* Re-enable the VFLR interrupt cause here, before looking for which
+        * VF got reset. Otherwise, if another VF gets a reset while the
+        * first one is being processed, that interrupt will be lost, and
+        * that VF will be stuck in reset forever.
+        */
        reg = rd32(hw, I40E_PFINT_ICR0_ENA);
        reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
        wr32(hw, I40E_PFINT_ICR0_ENA, reg);
@@ -2198,6 +2203,8 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
                 * and then reloading the VF driver.
                 */
                i40e_vc_disable_vf(pf, vf);
+               /* During reset the VF got a new VSI, so refresh the pointer. */
+               vsi = pf->vsi[vf->lan_vsi_idx];
        }
 
        /* Check for condition where there was already a port VLAN ID
@@ -2306,6 +2313,9 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
        case I40E_LINK_SPEED_40GB:
                speed = 40000;
                break;
+       case I40E_LINK_SPEED_20GB:
+               speed = 20000;
+               break;
        case I40E_LINK_SPEED_10GB:
                speed = 10000;
                break;
index da44995def42f3b034a1b08780a0c901335e02c7..e74642a0c42ef0dd0889f269ab358ccd4c082914 100644 (file)
@@ -91,8 +91,8 @@ struct i40e_vf {
         * When assigned, these will be non-zero, because VSI 0 is always
         * the main LAN VSI for the PF.
         */
-       u8 lan_vsi_idx;         /* index into PF struct */
-       u8 lan_vsi_id;          /* ID as used by firmware */
+       u16 lan_vsi_idx;        /* index into PF struct */
+       u16 lan_vsi_id;         /* ID as used by firmware */
 
        u8 num_queue_pairs;     /* num of qps assigned to VF vsis */
        u64 num_mdd_events;     /* num of mdd events detected */
index 3f65e39b3fe43b9231ab28bfe32b8728aba95ce1..44f7ed7583dd15d1f11b49ef871628d22d23c144 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -887,6 +887,9 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
        u16 flags;
        u16 ntu;
 
+       /* pre-clean the event info */
+       memset(&e->desc, 0, sizeof(e->desc));
+
        /* take the lock before we start messing with the ring */
        mutex_lock(&hw->aq.arq_mutex);
 
index 578b1780fb08deaeaff6bfdb0e6fa50e5a93311a..aad8d62771102e090fcdf22fae68722306c4f2d7 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -34,7 +34,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR      0x0001
-#define I40E_FW_API_VERSION_MINOR      0x0004
+#define I40E_FW_API_VERSION_MINOR      0x0005
 
 struct i40e_aq_desc {
        __le16 flags;
@@ -145,6 +145,9 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_remove_statistics          = 0x0202,
        i40e_aqc_opc_set_port_parameters        = 0x0203,
        i40e_aqc_opc_get_switch_resource_alloc  = 0x0204,
+       i40e_aqc_opc_set_switch_config          = 0x0205,
+       i40e_aqc_opc_rx_ctl_reg_read            = 0x0206,
+       i40e_aqc_opc_rx_ctl_reg_write           = 0x0207,
 
        i40e_aqc_opc_add_vsi                    = 0x0210,
        i40e_aqc_opc_update_vsi_parameters      = 0x0211,
@@ -229,6 +232,7 @@ enum i40e_admin_queue_opc {
        i40e_aqc_opc_nvm_config_read            = 0x0704,
        i40e_aqc_opc_nvm_config_write           = 0x0705,
        i40e_aqc_opc_oem_post_update            = 0x0720,
+       i40e_aqc_opc_thermal_sensor             = 0x0721,
 
        /* virtualization commands */
        i40e_aqc_opc_send_msg_to_pf             = 0x0801,
@@ -680,6 +684,31 @@ struct i40e_aqc_switch_resource_alloc_element_resp {
 
 I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
 
+/* Set Switch Configuration (direct 0x0205) */
+struct i40e_aqc_set_switch_config {
+       __le16  flags;
+#define I40E_AQ_SET_SWITCH_CFG_PROMISC         0x0001
+#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER       0x0002
+       __le16  valid_flags;
+       u8      reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
+
+/* Read Receive control registers  (direct 0x0206)
+ * Write Receive control registers (direct 0x0207)
+ *     used for accessing Rx control registers that can be
+ *     slow and need special handling when under high Rx load
+ */
+struct i40e_aqc_rx_ctl_reg_read_write {
+       __le32 reserved1;
+       __le32 address;
+       __le32 reserved2;
+       __le32 value;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_rx_ctl_reg_read_write);
+
 /* Add VSI (indirect 0x0210)
  *    this indirect command uses struct i40e_aqc_vsi_properties_data
  *    as the indirect buffer (128 bytes)
@@ -906,7 +935,8 @@ struct i40e_aqc_add_veb {
                                        I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT     0x2
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DATA                0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER      0x8
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER      0x8     /* deprecated */
+#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS  0x10
        u8      enable_tcs;
        u8      reserved[9];
 };
@@ -973,6 +1003,7 @@ struct i40e_aqc_add_macvlan_element_data {
 #define I40E_AQC_MACVLAN_ADD_HASH_MATCH                0x0002
 #define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN       0x0004
 #define I40E_AQC_MACVLAN_ADD_TO_QUEUE          0x0008
+#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC    0x0010
        __le16  queue_number;
 #define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT       0
 #define I40E_AQC_MACVLAN_CMD_QUEUE_MASK                (0x7FF << \
@@ -1069,6 +1100,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes {
 #define I40E_AQC_SET_VSI_PROMISC_BROADCAST     0x04
 #define I40E_AQC_SET_VSI_DEFAULT               0x08
 #define I40E_AQC_SET_VSI_PROMISC_VLAN          0x10
+#define I40E_AQC_SET_VSI_PROMISC_TX            0x8000
        __le16  seid;
 #define I40E_AQC_VSI_PROM_CMD_SEID_MASK                0x3FF
        __le16  vlan_tag;
@@ -1261,6 +1293,12 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC         1
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE             2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP                 3
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED           4
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE          5
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC      0x2000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC      0x4000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP       0x8000
 
        __le32  tenant_id;
        u8      reserved[4];
@@ -1929,6 +1967,22 @@ struct i40e_aqc_nvm_oem_post_update_buffer {
 
 I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
 
+/* Thermal Sensor (indirect 0x0721)
+ *     read or set thermal sensor configs and values
+ *     takes a sensor and command specific data buffer, not detailed here
+ */
+struct i40e_aqc_thermal_sensor {
+       u8 sensor_action;
+#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG     0
+#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG      1
+#define I40E_AQ_THERMAL_SENSOR_READ_TEMP       2
+       u8 reserved[7];
+       __le32  addr_high;
+       __le32  addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
+
 /* Send to PF command (indirect 0x0801) id is only used by PF
  * Send to VF command (indirect 0x0802) id is only used by PF
  * Send to Peer PF command (indirect 0x0803)
@@ -2103,6 +2157,7 @@ struct i40e_aqc_add_udp_tunnel {
 #define I40E_AQC_TUNNEL_TYPE_VXLAN     0x00
 #define I40E_AQC_TUNNEL_TYPE_NGE       0x01
 #define I40E_AQC_TUNNEL_TYPE_TEREDO    0x10
+#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE 0x11
        u8      reserved1[10];
 };
 
index 938783e0baac81451e156d138e22e2b5e521f1ef..771ac6ad8cdad91023ed6aaa836e7e38b560dfe8 100644 (file)
@@ -903,6 +903,131 @@ struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = {
        I40E_PTT_UNUSED_ENTRY(255)
 };
 
+/**
+ * i40evf_aq_rx_ctl_read_register - use FW to read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: ptr to register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to read the Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 *reg_val,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_rx_ctl_reg_read_write *cmd_resp =
+               (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+       i40e_status status;
+
+       if (!reg_val)
+               return I40E_ERR_PARAM;
+
+       i40evf_fill_default_direct_cmd_desc(&desc,
+                                           i40e_aqc_opc_rx_ctl_reg_read);
+
+       cmd_resp->address = cpu_to_le32(reg_addr);
+
+       status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       if (status == 0)
+               *reg_val = le32_to_cpu(cmd_resp->value);
+
+       return status;
+}
+
+/**
+ * i40evf_read_rx_ctl - read from an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ **/
+u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
+{
+       i40e_status status = 0;
+       bool use_register;
+       int retry = 5;
+       u32 val = 0;
+
+       use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+       if (!use_register) {
+do_retry:
+               status = i40evf_aq_rx_ctl_read_register(hw, reg_addr,
+                                                       &val, NULL);
+               if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+                       usleep_range(1000, 2000);
+                       retry--;
+                       goto do_retry;
+               }
+       }
+
+       /* if the AQ access failed, try the old-fashioned way */
+       if (status || use_register)
+               val = rd32(hw, reg_addr);
+
+       return val;
+}
+
+/**
+ * i40evf_aq_rx_ctl_write_register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Use the firmware to write to an Rx control register,
+ * especially useful if the Rx unit is under heavy pressure
+ **/
+i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 reg_val,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_rx_ctl_reg_read_write *cmd =
+               (struct i40e_aqc_rx_ctl_reg_read_write *)&desc.params.raw;
+       i40e_status status;
+
+       i40evf_fill_default_direct_cmd_desc(&desc,
+                                           i40e_aqc_opc_rx_ctl_reg_write);
+
+       cmd->address = cpu_to_le32(reg_addr);
+       cmd->value = cpu_to_le32(reg_val);
+
+       status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40evf_write_rx_ctl - write to an Rx control register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ **/
+void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
+{
+       i40e_status status = 0;
+       bool use_register;
+       int retry = 5;
+
+       use_register = (hw->aq.api_maj_ver == 1) && (hw->aq.api_min_ver < 5);
+       if (!use_register) {
+do_retry:
+               status = i40evf_aq_rx_ctl_write_register(hw, reg_addr,
+                                                        reg_val, NULL);
+               if (hw->aq.asq_last_status == I40E_AQ_RC_EAGAIN && retry) {
+                       usleep_range(1000, 2000);
+                       retry--;
+                       goto do_retry;
+               }
+       }
+
+       /* if the AQ access failed, try the old-fashioned way */
+       if (status || use_register)
+               wr32(hw, reg_addr, reg_val);
+}
+
 /**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
index cbd9a1b078abf6caaa959218e0b4a4920c414d02..d89d52109efa543bb840999d734421c19cb4aa71 100644 (file)
@@ -103,4 +103,19 @@ i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
                                                    u16 vsi_seid);
+i40e_status i40evf_aq_rx_ctl_read_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 *reg_val,
+                               struct i40e_asq_cmd_details *cmd_details);
+u32 i40evf_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr);
+i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
+                               u32 reg_addr, u32 reg_val,
+                               struct i40e_asq_cmd_details *cmd_details);
+void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
+                                  u16 reg, u8 phy_addr, u16 *value);
+i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
+                                   u16 reg, u8 phy_addr, u16 value);
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
+i40e_status i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                   u32 time, u32 interval);
 #endif /* _I40E_PROTOTYPE_H_ */
index 7d663fb6192756e7168c22e20ba101fea02cf478..ebcc25c05796d7d42372395ba9f8d3bf838d547a 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -129,15 +129,19 @@ void i40evf_free_tx_resources(struct i40e_ring *tx_ring)
 /**
  * i40evf_get_tx_pending - how many Tx descriptors not processed
  * @tx_ring: the ring of descriptors
+ * @in_sw: is tx_pending being checked in SW or HW
  *
  * Since there is no access to the ring head register
  * in XL710, we need to use our local copies
  **/
-u32 i40evf_get_tx_pending(struct i40e_ring *ring)
+u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw)
 {
        u32 head, tail;
 
-       head = i40e_get_head(ring);
+       if (!in_sw)
+               head = i40e_get_head(ring);
+       else
+               head = ring->next_to_clean;
        tail = readl(ring->tail);
 
        if (head != tail)
@@ -259,7 +263,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                 * them to be written back in case we stay in NAPI.
                 * In this mode on X722 we do not enable Interrupt.
                 */
-               j = i40evf_get_tx_pending(tx_ring);
+               j = i40evf_get_tx_pending(tx_ring, false);
 
                if (budget &&
                    ((j / (WB_STRIDE + 1)) == 0) && (j > 0) &&
@@ -292,39 +296,49 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
 }
 
 /**
- * i40evf_force_wb -Arm hardware to do a wb on noncache aligned descriptors
+ * i40evf_enable_wb_on_itr - Arm hardware to do a wb, interrupts are not enabled
  * @vsi: the VSI we care about
- * @q_vector: the vector  on which to force writeback
+ * @q_vector: the vector on which to enable writeback
  *
  **/
-static void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
+                                 struct i40e_q_vector *q_vector)
 {
        u16 flags = q_vector->tx.ring[0].flags;
+       u32 val;
 
-       if (flags & I40E_TXR_FLAGS_WB_ON_ITR) {
-               u32 val;
+       if (!(flags & I40E_TXR_FLAGS_WB_ON_ITR))
+               return;
 
-               if (q_vector->arm_wb_state)
-                       return;
+       if (q_vector->arm_wb_state)
+               return;
 
-               val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK;
+       val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK |
+             I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */
 
-               wr32(&vsi->back->hw,
-                    I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
-                                         vsi->base_vector - 1),
-                    val);
-               q_vector->arm_wb_state = true;
-       } else {
-               u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
-                         I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
-                         I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
-                         I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK;
-                         /* allow 00 to be written to the index */
-
-               wr32(&vsi->back->hw,
-                    I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
-                                         vsi->base_vector - 1), val);
-       }
+       wr32(&vsi->back->hw,
+            I40E_VFINT_DYN_CTLN1(q_vector->v_idx +
+                                 vsi->base_vector - 1), val);
+       q_vector->arm_wb_state = true;
+}
+
+/**
+ * i40evf_force_wb - Issue SW Interrupt so HW does a wb
+ * @vsi: the VSI we care about
+ * @q_vector: the vector  on which to force writeback
+ *
+ **/
+void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+       u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+                 I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */
+                 I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK |
+                 I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK
+                 /* allow 00 to be written to the index */;
+
+       wr32(&vsi->back->hw,
+            I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1),
+            val);
 }
 
 /**
@@ -522,7 +536,7 @@ void i40evf_clean_rx_ring(struct i40e_ring *rx_ring)
                        if (rx_bi->page_dma) {
                                dma_unmap_page(dev,
                                               rx_bi->page_dma,
-                                              PAGE_SIZE / 2,
+                                              PAGE_SIZE,
                                               DMA_FROM_DEVICE);
                                rx_bi->page_dma = 0;
                        }
@@ -657,16 +671,19 @@ static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
  * i40evf_alloc_rx_buffers_ps - Replace used receive buffers; packet split
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40evf_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40evf_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
        u16 i = rx_ring->next_to_use;
        union i40e_rx_desc *rx_desc;
        struct i40e_rx_buffer *bi;
+       const int current_node = numa_node_id();
 
        /* do nothing if no valid netdev defined */
        if (!rx_ring->netdev || !cleaned_count)
-               return;
+               return false;
 
        while (cleaned_count--) {
                rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -674,56 +691,79 @@ void i40evf_alloc_rx_buffers_ps(struct i40e_ring *rx_ring, u16 cleaned_count)
 
                if (bi->skb) /* desc is in use */
                        goto no_buffers;
+
+       /* If we've been moved to a different NUMA node, release the
+        * page so we can get a new one on the current node.
+        */
+               if (bi->page &&  page_to_nid(bi->page) != current_node) {
+                       dma_unmap_page(rx_ring->dev,
+                                      bi->page_dma,
+                                      PAGE_SIZE,
+                                      DMA_FROM_DEVICE);
+                       __free_page(bi->page);
+                       bi->page = NULL;
+                       bi->page_dma = 0;
+                       rx_ring->rx_stats.realloc_count++;
+               } else if (bi->page) {
+                       rx_ring->rx_stats.page_reuse_count++;
+               }
+
                if (!bi->page) {
                        bi->page = alloc_page(GFP_ATOMIC);
                        if (!bi->page) {
                                rx_ring->rx_stats.alloc_page_failed++;
                                goto no_buffers;
                        }
-               }
-
-               if (!bi->page_dma) {
-                       /* use a half page if we're re-using */
-                       bi->page_offset ^= PAGE_SIZE / 2;
                        bi->page_dma = dma_map_page(rx_ring->dev,
                                                    bi->page,
-                                                   bi->page_offset,
-                                                   PAGE_SIZE / 2,
+                                                   0,
+                                                   PAGE_SIZE,
                                                    DMA_FROM_DEVICE);
-                       if (dma_mapping_error(rx_ring->dev,
-                                             bi->page_dma)) {
+                       if (dma_mapping_error(rx_ring->dev, bi->page_dma)) {
                                rx_ring->rx_stats.alloc_page_failed++;
+                               __free_page(bi->page);
+                               bi->page = NULL;
                                bi->page_dma = 0;
+                               bi->page_offset = 0;
                                goto no_buffers;
                        }
+                       bi->page_offset = 0;
                }
 
-               dma_sync_single_range_for_device(rx_ring->dev,
-                                                bi->dma,
-                                                0,
-                                                rx_ring->rx_hdr_len,
-                                                DMA_FROM_DEVICE);
                /* Refresh the desc even if buffer_addrs didn't change
                 * because each write-back erases this info.
                 */
-               rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+               rx_desc->read.pkt_addr =
+                               cpu_to_le64(bi->page_dma + bi->page_offset);
                rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
                i++;
                if (i == rx_ring->count)
                        i = 0;
        }
 
+       if (rx_ring->next_to_use != i)
+               i40e_release_rx_desc(rx_ring, i);
+
+       return false;
+
 no_buffers:
        if (rx_ring->next_to_use != i)
                i40e_release_rx_desc(rx_ring, i);
+
+       /* make sure to come back via polling to try again after
+        * allocation failure
+        */
+       return true;
 }
 
 /**
  * i40evf_alloc_rx_buffers_1buf - Replace used receive buffers; single buffer
  * @rx_ring: ring to place buffers on
  * @cleaned_count: number of buffers to replace
+ *
+ * Returns true if any errors on allocation
  **/
-void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
+bool i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 {
        u16 i = rx_ring->next_to_use;
        union i40e_rx_desc *rx_desc;
@@ -732,7 +772,7 @@ void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
 
        /* do nothing if no valid netdev defined */
        if (!rx_ring->netdev || !cleaned_count)
-               return;
+               return false;
 
        while (cleaned_count--) {
                rx_desc = I40E_RX_DESC(rx_ring, i);
@@ -740,8 +780,10 @@ void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                skb = bi->skb;
 
                if (!skb) {
-                       skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-                                                       rx_ring->rx_buf_len);
+                       skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+                                                         rx_ring->rx_buf_len,
+                                                         GFP_ATOMIC |
+                                                         __GFP_NOWARN);
                        if (!skb) {
                                rx_ring->rx_stats.alloc_buff_failed++;
                                goto no_buffers;
@@ -759,6 +801,8 @@ void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                        if (dma_mapping_error(rx_ring->dev, bi->dma)) {
                                rx_ring->rx_stats.alloc_buff_failed++;
                                bi->dma = 0;
+                               dev_kfree_skb(bi->skb);
+                               bi->skb = NULL;
                                goto no_buffers;
                        }
                }
@@ -770,9 +814,19 @@ void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rx_ring, u16 cleaned_count)
                        i = 0;
        }
 
+       if (rx_ring->next_to_use != i)
+               i40e_release_rx_desc(rx_ring, i);
+
+       return false;
+
 no_buffers:
        if (rx_ring->next_to_use != i)
                i40e_release_rx_desc(rx_ring, i);
+
+       /* make sure to come back via polling to try again after
+        * allocation failure
+        */
+       return true;
 }
 
 /**
@@ -807,16 +861,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
                                    u16 rx_ptype)
 {
        struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(rx_ptype);
-       bool ipv4 = false, ipv6 = false;
-       bool ipv4_tunnel, ipv6_tunnel;
-       __wsum rx_udp_csum;
-       struct iphdr *iph;
-       __sum16 csum;
-
-       ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
-                    (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
-       ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
-                    (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
+       bool ipv4, ipv6, ipv4_tunnel, ipv6_tunnel;
 
        skb->ip_summed = CHECKSUM_NONE;
 
@@ -832,12 +877,10 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        if (!(decoded.known && decoded.outer_ip))
                return;
 
-       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-           decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4)
-               ipv4 = true;
-       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
-                decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6)
-               ipv6 = true;
+       ipv4 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+              (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV4);
+       ipv6 = (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP) &&
+              (decoded.outer_ip_ver == I40E_RX_PTYPE_OUTER_IPV6);
 
        if (ipv4 &&
            (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) |
@@ -861,36 +904,17 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT))
                return;
 
-       /* If VXLAN traffic has an outer UDPv4 checksum we need to check
-        * it in the driver, hardware does not do it for us.
-        * Since L3L4P bit was set we assume a valid IHL value (>=5)
-        * so the total length of IPv4 header is IHL*4 bytes
-        * The UDP_0 bit *may* bet set if the *inner* header is UDP
+       /* The hardware supported by this driver does not validate outer
+        * checksums for tunneled VXLAN or GENEVE frames.  I don't agree
+        * with it but the specification states that you "MAY validate", it
+        * doesn't make it a hard requirement so if we have validated the
+        * inner checksum report CHECKSUM_UNNECESSARY.
         */
-       if (ipv4_tunnel) {
-               skb->transport_header = skb->mac_header +
-                                       sizeof(struct ethhdr) +
-                                       (ip_hdr(skb)->ihl * 4);
-
-               /* Add 4 bytes for VLAN tagged packets */
-               skb->transport_header += (skb->protocol == htons(ETH_P_8021Q) ||
-                                         skb->protocol == htons(ETH_P_8021AD))
-                                         ? VLAN_HLEN : 0;
-
-               if ((ip_hdr(skb)->protocol == IPPROTO_UDP) &&
-                   (udp_hdr(skb)->check != 0)) {
-                       rx_udp_csum = udp_csum(skb);
-                       iph = ip_hdr(skb);
-                       csum = csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                (skb->len -
-                                                 skb_transport_offset(skb)),
-                                                IPPROTO_UDP, rx_udp_csum);
-
-                       if (udp_hdr(skb)->check != csum)
-                               goto checksum_fail;
-
-               } /* else its GRE and so no outer UDP header */
-       }
+
+       ipv4_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT4_MAC_PAY3) &&
+                    (rx_ptype <= I40E_RX_PTYPE_GRENAT4_MACVLAN_IPV6_ICMP_PAY4);
+       ipv6_tunnel = (rx_ptype >= I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
+                    (rx_ptype <= I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->csum_level = ipv4_tunnel || ipv6_tunnel;
@@ -955,18 +979,19 @@ static inline void i40e_rx_hash(struct i40e_ring *ring,
  *
  * Returns true if there's any budget left (e.g. the clean is finished)
  **/
-static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
+static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, const int budget)
 {
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
        u16 rx_packet_len, rx_header_len, rx_sph, rx_hbo;
        u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
-       const int current_node = numa_mem_id();
        struct i40e_vsi *vsi = rx_ring->vsi;
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       bool failure = false;
        u8 rx_ptype;
        u64 qword;
+       u32 copysize;
 
        do {
                struct i40e_rx_buffer *rx_bi;
@@ -974,7 +999,9 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                u16 vlan_tag;
                /* return some buffers to hardware, one at a time is too slow */
                if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-                       i40evf_alloc_rx_buffers_ps(rx_ring, cleaned_count);
+                       failure = failure ||
+                                 i40evf_alloc_rx_buffers_ps(rx_ring,
+                                                            cleaned_count);
                        cleaned_count = 0;
                }
 
@@ -992,13 +1019,22 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                 * DD bit is set.
                 */
                dma_rmb();
+               /* sync header buffer for reading */
+               dma_sync_single_range_for_cpu(rx_ring->dev,
+                                             rx_ring->rx_bi[0].dma,
+                                             i * rx_ring->rx_hdr_len,
+                                             rx_ring->rx_hdr_len,
+                                             DMA_FROM_DEVICE);
                rx_bi = &rx_ring->rx_bi[i];
                skb = rx_bi->skb;
                if (likely(!skb)) {
-                       skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
-                                                       rx_ring->rx_hdr_len);
+                       skb = __netdev_alloc_skb_ip_align(rx_ring->netdev,
+                                                         rx_ring->rx_hdr_len,
+                                                         GFP_ATOMIC |
+                                                         __GFP_NOWARN);
                        if (!skb) {
                                rx_ring->rx_stats.alloc_buff_failed++;
+                               failure = true;
                                break;
                        }
 
@@ -1006,8 +1042,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        skb_record_rx_queue(skb, rx_ring->queue_index);
                        /* we are reusing so sync this buffer for CPU use */
                        dma_sync_single_range_for_cpu(rx_ring->dev,
-                                                     rx_bi->dma,
-                                                     0,
+                                                     rx_ring->rx_bi[0].dma,
+                                                     i * rx_ring->rx_hdr_len,
                                                      rx_ring->rx_hdr_len,
                                                      DMA_FROM_DEVICE);
                }
@@ -1025,9 +1061,16 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
 
                rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
                           I40E_RXD_QW1_PTYPE_SHIFT;
-               prefetch(rx_bi->page);
+               /* sync half-page for reading */
+               dma_sync_single_range_for_cpu(rx_ring->dev,
+                                             rx_bi->page_dma,
+                                             rx_bi->page_offset,
+                                             PAGE_SIZE / 2,
+                                             DMA_FROM_DEVICE);
+               prefetch(page_address(rx_bi->page) + rx_bi->page_offset);
                rx_bi->skb = NULL;
                cleaned_count++;
+               copysize = 0;
                if (rx_hbo || rx_sph) {
                        int len;
 
@@ -1038,38 +1081,50 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
                        memcpy(__skb_put(skb, len), rx_bi->hdr_buf, len);
                } else if (skb->len == 0) {
                        int len;
+                       unsigned char *va = page_address(rx_bi->page) +
+                                           rx_bi->page_offset;
 
-                       len = (rx_packet_len > skb_headlen(skb) ?
-                               skb_headlen(skb) : rx_packet_len);
-                       memcpy(__skb_put(skb, len),
-                              rx_bi->page + rx_bi->page_offset,
-                              len);
-                       rx_bi->page_offset += len;
+                       len = min(rx_packet_len, rx_ring->rx_hdr_len);
+                       memcpy(__skb_put(skb, len), va, len);
+                       copysize = len;
                        rx_packet_len -= len;
                }
-
                /* Get the rest of the data if this was a header split */
                if (rx_packet_len) {
-                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
-                                          rx_bi->page,
-                                          rx_bi->page_offset,
-                                          rx_packet_len);
-
-                       skb->len += rx_packet_len;
-                       skb->data_len += rx_packet_len;
-                       skb->truesize += rx_packet_len;
-
-                       if ((page_count(rx_bi->page) == 1) &&
-                           (page_to_nid(rx_bi->page) == current_node))
-                               get_page(rx_bi->page);
-                       else
+                       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
+                                       rx_bi->page,
+                                       rx_bi->page_offset + copysize,
+                                       rx_packet_len, I40E_RXBUFFER_2048);
+
+                       /* If the page count is more than 2, then both halves
+                        * of the page are used and we need to free it. Do it
+                        * here instead of in the alloc code. Otherwise one
+                        * of the half-pages might be released between now and
+                        * then, and we wouldn't know which one to use.
+                        * Don't call get_page and free_page since those are
+                        * both expensive atomic operations that just change
+                        * the refcount in opposite directions. Just give the
+                        * page to the stack; he can have our refcount.
+                        */
+                       if (page_count(rx_bi->page) > 2) {
+                               dma_unmap_page(rx_ring->dev,
+                                              rx_bi->page_dma,
+                                              PAGE_SIZE,
+                                              DMA_FROM_DEVICE);
                                rx_bi->page = NULL;
+                               rx_bi->page_dma = 0;
+                               rx_ring->rx_stats.realloc_count++;
+                       } else {
+                               get_page(rx_bi->page);
+                               /* switch to the other half-page here; the
+                                * allocation code programs the right addr
+                                * into HW. If we haven't used this half-page,
+                                * the address won't be changed, and HW can
+                                * just use it next time through.
+                                */
+                               rx_bi->page_offset ^= PAGE_SIZE / 2;
+                       }
 
-                       dma_unmap_page(rx_ring->dev,
-                                      rx_bi->page_dma,
-                                      PAGE_SIZE / 2,
-                                      DMA_FROM_DEVICE);
-                       rx_bi->page_dma = 0;
                }
                I40E_RX_INCREMENT(rx_ring, i);
 
@@ -1121,7 +1176,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_packets += total_rx_packets;
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-       return total_rx_packets;
+       return failure ? budget : total_rx_packets;
 }
 
 /**
@@ -1139,6 +1194,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
        u16 rx_packet_len;
+       bool failure = false;
        u8 rx_ptype;
        u64 qword;
        u16 i;
@@ -1149,7 +1205,9 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
                u16 vlan_tag;
                /* return some buffers to hardware, one at a time is too slow */
                if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
-                       i40evf_alloc_rx_buffers_1buf(rx_ring, cleaned_count);
+                       failure = failure ||
+                                 i40evf_alloc_rx_buffers_1buf(rx_ring,
+                                                              cleaned_count);
                        cleaned_count = 0;
                }
 
@@ -1230,7 +1288,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget)
        rx_ring->q_vector->rx.total_packets += total_rx_packets;
        rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
 
-       return total_rx_packets;
+       return failure ? budget : total_rx_packets;
 }
 
 static u32 i40e_buildreg_itr(const int type, const u16 itr)
@@ -1238,7 +1296,9 @@ static u32 i40e_buildreg_itr(const int type, const u16 itr)
        u32 val;
 
        val = I40E_VFINT_DYN_CTLN1_INTENA_MASK |
-             I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK |
+             /* Don't clear PBA because that can cause lost interrupts that
+              * came in while we were cleaning/polling
+              */
              (type << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) |
              (itr << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT);
 
@@ -1351,7 +1411,8 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
         * budget and be more aggressive about cleaning up the Tx descriptors.
         */
        i40e_for_each_ring(ring, q_vector->tx) {
-               clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
+               clean_complete = clean_complete &&
+                                i40e_clean_tx_irq(ring, vsi->work_limit);
                arm_wb = arm_wb || ring->arm_wb;
                ring->arm_wb = false;
        }
@@ -1375,7 +1436,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
 
                work_done += cleaned;
                /* if we didn't clean as many as budgeted, we must be done */
-               clean_complete &= (budget_per_ring != cleaned);
+               clean_complete = clean_complete && (budget_per_ring > cleaned);
        }
 
        /* If work not completed, return budget and polling will return */
@@ -1383,7 +1444,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
 tx_only:
                if (arm_wb) {
                        q_vector->tx.ring[0].tx_stats.tx_force_wb++;
-                       i40evf_force_wb(vsi, q_vector);
+                       i40e_enable_wb_on_itr(vsi, q_vector);
                }
                return budget;
        }
@@ -1463,13 +1524,23 @@ out:
 static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
                    u8 *hdr_len, u64 *cd_type_cmd_tso_mss)
 {
-       u32 cd_cmd, cd_tso_len, cd_mss;
-       struct ipv6hdr *ipv6h;
-       struct tcphdr *tcph;
-       struct iphdr *iph;
-       u32 l4len;
+       u64 cd_cmd, cd_tso_len, cd_mss;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
+       union {
+               struct tcphdr *tcp;
+               struct udphdr *udp;
+               unsigned char *hdr;
+       } l4;
+       u32 paylen, l4_offset;
        int err;
 
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
        if (!skb_is_gso(skb))
                return 0;
 
@@ -1477,35 +1548,60 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
-       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
-
-       if (iph->version == 4) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-               iph->tot_len = 0;
-               iph->check = 0;
-               tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                0, IPPROTO_TCP, 0);
-       } else if (ipv6h->version == 6) {
-               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
-               ipv6h->payload_len = 0;
-               tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
-                                              0, IPPROTO_TCP, 0);
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
+
+       /* initialize outer IP header fields */
+       if (ip.v4->version == 4) {
+               ip.v4->tot_len = 0;
+               ip.v4->check = 0;
+       } else {
+               ip.v6->payload_len = 0;
+       }
+
+       if (skb_shinfo(skb)->gso_type & (SKB_GSO_UDP_TUNNEL | SKB_GSO_GRE |
+                                        SKB_GSO_UDP_TUNNEL_CSUM)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM) {
+                       /* determine offset of outer transport header */
+                       l4_offset = l4.hdr - skb->data;
+
+                       /* remove payload length from outer checksum */
+                       paylen = (__force u16)l4.udp->check;
+                       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+                       l4.udp->check = ~csum_fold((__force __wsum)paylen);
+               }
+
+               /* reset pointers to inner headers */
+               ip.hdr = skb_inner_network_header(skb);
+               l4.hdr = skb_inner_transport_header(skb);
+
+               /* initialize inner IP header fields */
+               if (ip.v4->version == 4) {
+                       ip.v4->tot_len = 0;
+                       ip.v4->check = 0;
+               } else {
+                       ip.v6->payload_len = 0;
+               }
        }
 
-       l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
-       *hdr_len = (skb->encapsulation
-                   ? (skb_inner_transport_header(skb) - skb->data)
-                   : skb_transport_offset(skb)) + l4len;
+       /* determine offset of inner transport header */
+       l4_offset = l4.hdr - skb->data;
+
+       /* remove payload length from inner checksum */
+       paylen = (__force u16)l4.tcp->check;
+       paylen += ntohs(1) * (u16)~(skb->len - l4_offset);
+       l4.tcp->check = ~csum_fold((__force __wsum)paylen);
+
+       /* compute length of segmentation header */
+       *hdr_len = (l4.tcp->doff * 4) + l4_offset;
 
        /* find the field values */
        cd_cmd = I40E_TX_CTX_DESC_TSO;
        cd_tso_len = skb->len - *hdr_len;
        cd_mss = skb_shinfo(skb)->gso_size;
-       *cd_type_cmd_tso_mss |= ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
-                               ((u64)cd_tso_len <<
-                                I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
-                               ((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+       *cd_type_cmd_tso_mss |= (cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) |
+                               (cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) |
+                               (cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
        return 1;
 }
 
@@ -1515,129 +1611,157 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
  * @tx_flags: pointer to Tx flags currently set
  * @td_cmd: Tx descriptor command bits to set
  * @td_offset: Tx descriptor header offsets to set
+ * @tx_ring: Tx descriptor ring
  * @cd_tunneling: ptr to context desc bits
  **/
-static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
-                               u32 *td_cmd, u32 *td_offset,
-                               struct i40e_ring *tx_ring,
-                               u32 *cd_tunneling)
+static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags,
+                              u32 *td_cmd, u32 *td_offset,
+                              struct i40e_ring *tx_ring,
+                              u32 *cd_tunneling)
 {
-       struct ipv6hdr *this_ipv6_hdr;
-       unsigned int this_tcp_hdrlen;
-       struct iphdr *this_ip_hdr;
-       u32 network_hdr_len;
-       u8 l4_hdr = 0;
-       struct udphdr *oudph;
-       struct iphdr *oiph;
-       u32 l4_tunnel = 0;
+       union {
+               struct iphdr *v4;
+               struct ipv6hdr *v6;
+               unsigned char *hdr;
+       } ip;
+       union {
+               struct tcphdr *tcp;
+               struct udphdr *udp;
+               unsigned char *hdr;
+       } l4;
+       unsigned char *exthdr;
+       u32 offset, cmd = 0, tunnel = 0;
+       __be16 frag_off;
+       u8 l4_proto = 0;
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
+       ip.hdr = skb_network_header(skb);
+       l4.hdr = skb_transport_header(skb);
+
+       /* compute outer L2 header size */
+       offset = ((ip.hdr - skb->data) / 2) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
 
        if (skb->encapsulation) {
-               switch (ip_hdr(skb)->protocol) {
+               /* define outer network header type */
+               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
+                       tunnel |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+                                 I40E_TX_CTX_EXT_IP_IPV4 :
+                                 I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+
+                       l4_proto = ip.v4->protocol;
+               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
+                       tunnel |= I40E_TX_CTX_EXT_IP_IPV6;
+
+                       exthdr = ip.hdr + sizeof(*ip.v6);
+                       l4_proto = ip.v6->nexthdr;
+                       if (l4.hdr != exthdr)
+                               ipv6_skip_exthdr(skb, exthdr - skb->data,
+                                                &l4_proto, &frag_off);
+               }
+
+               /* compute outer L3 header size */
+               tunnel |= ((l4.hdr - ip.hdr) / 4) <<
+                         I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT;
+
+               /* switch IP header pointer from outer to inner header */
+               ip.hdr = skb_inner_network_header(skb);
+
+               /* define outer transport */
+               switch (l4_proto) {
                case IPPROTO_UDP:
-                       oudph = udp_hdr(skb);
-                       oiph = ip_hdr(skb);
-                       l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING;
+                       tunnel |= I40E_TXD_CTX_UDP_TUNNELING;
+                       *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
+                       break;
+               case IPPROTO_GRE:
+                       tunnel |= I40E_TXD_CTX_GRE_TUNNELING;
                        *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL;
                        break;
                default:
-                       return;
-               }
-               network_hdr_len = skb_inner_network_header_len(skb);
-               this_ip_hdr = inner_ip_hdr(skb);
-               this_ipv6_hdr = inner_ipv6_hdr(skb);
-               this_tcp_hdrlen = inner_tcp_hdrlen(skb);
-
-               if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-                       if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
-                               ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
-               } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
                        if (*tx_flags & I40E_TX_FLAGS_TSO)
-                               ip_hdr(skb)->check = 0;
-               }
+                               return -1;
 
-               /* Now set the ctx descriptor fields */
-               *cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
-                                  I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT      |
-                                  l4_tunnel                             |
-                                  ((skb_inner_network_offset(skb) -
-                                       skb_transport_offset(skb)) >> 1) <<
-                                  I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-               if (this_ip_hdr->version == 6) {
-                       *tx_flags &= ~I40E_TX_FLAGS_IPV4;
-                       *tx_flags |= I40E_TX_FLAGS_IPV6;
+                       skb_checksum_help(skb);
+                       return 0;
                }
 
-               if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) &&
-                   (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING)        &&
-                   (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) {
-                       oudph->check = ~csum_tcpudp_magic(oiph->saddr,
-                                       oiph->daddr,
-                                       (skb->len - skb_transport_offset(skb)),
-                                       IPPROTO_UDP, 0);
-                       *cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
-               }
-       } else {
-               network_hdr_len = skb_network_header_len(skb);
-               this_ip_hdr = ip_hdr(skb);
-               this_ipv6_hdr = ipv6_hdr(skb);
-               this_tcp_hdrlen = tcp_hdrlen(skb);
+               /* compute tunnel header size */
+               tunnel |= ((ip.hdr - l4.hdr) / 2) <<
+                         I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+
+               /* indicate if we need to offload outer UDP header */
+               if ((*tx_flags & I40E_TX_FLAGS_TSO) &&
+                   (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM))
+                       tunnel |= I40E_TXD_CTX_QW0_L4T_CS_MASK;
+
+               /* record tunnel offload values */
+               *cd_tunneling |= tunnel;
+
+               /* switch L4 header pointer from outer to inner */
+               l4.hdr = skb_inner_transport_header(skb);
+               l4_proto = 0;
+
+               /* reset type as we transition from outer to inner headers */
+               *tx_flags &= ~(I40E_TX_FLAGS_IPV4 | I40E_TX_FLAGS_IPV6);
+               if (ip.v4->version == 4)
+                       *tx_flags |= I40E_TX_FLAGS_IPV4;
+               if (ip.v6->version == 6)
+                       *tx_flags |= I40E_TX_FLAGS_IPV6;
        }
 
        /* Enable IP checksum offloads */
        if (*tx_flags & I40E_TX_FLAGS_IPV4) {
-               l4_hdr = this_ip_hdr->protocol;
+               l4_proto = ip.v4->protocol;
                /* the stack computes the IP header already, the only time we
                 * need the hardware to recompute it is in the case of TSO.
                 */
-               if (*tx_flags & I40E_TX_FLAGS_TSO) {
-                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
-                       this_ip_hdr->check = 0;
-               } else {
-                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
-               }
-               /* Now set the td_offset for IP header length */
-               *td_offset = (network_hdr_len >> 2) <<
-                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+               cmd |= (*tx_flags & I40E_TX_FLAGS_TSO) ?
+                      I40E_TX_DESC_CMD_IIPT_IPV4_CSUM :
+                      I40E_TX_DESC_CMD_IIPT_IPV4;
        } else if (*tx_flags & I40E_TX_FLAGS_IPV6) {
-               l4_hdr = this_ipv6_hdr->nexthdr;
-               *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
-               /* Now set the td_offset for IP header length */
-               *td_offset = (network_hdr_len >> 2) <<
-                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+
+               exthdr = ip.hdr + sizeof(*ip.v6);
+               l4_proto = ip.v6->nexthdr;
+               if (l4.hdr != exthdr)
+                       ipv6_skip_exthdr(skb, exthdr - skb->data,
+                                        &l4_proto, &frag_off);
        }
-       /* words in MACLEN + dwords in IPLEN + dwords in L4Len */
-       *td_offset |= (skb_network_offset(skb) >> 1) <<
-                      I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+
+       /* compute inner L3 header size */
+       offset |= ((l4.hdr - ip.hdr) / 4) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
 
        /* Enable L4 checksum offloads */
-       switch (l4_hdr) {
+       switch (l4_proto) {
        case IPPROTO_TCP:
                /* enable checksum offloads */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
-               *td_offset |= (this_tcp_hdrlen >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+               offset |= l4.tcp->doff << I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        case IPPROTO_SCTP:
                /* enable SCTP checksum offload */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
-               *td_offset |= (sizeof(struct sctphdr) >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+               offset |= (sizeof(struct sctphdr) >> 2) <<
+                         I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        case IPPROTO_UDP:
                /* enable UDP checksum offload */
-               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
-               *td_offset |= (sizeof(struct udphdr) >> 2) <<
-                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+               offset |= (sizeof(struct udphdr) >> 2) <<
+                         I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
                break;
        default:
-               break;
+               if (*tx_flags & I40E_TX_FLAGS_TSO)
+                       return -1;
+               skb_checksum_help(skb);
+               return 0;
        }
+
+       *td_cmd |= cmd;
+       *td_offset |= offset;
+
+       return 1;
 }
 
 /**
@@ -1672,59 +1796,71 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
 }
 
 /**
- * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * __i40evf_chk_linearize - Check if there are more than 8 fragments per packet
  * @skb:      send buffer
- * @tx_flags: collected send information
  *
  * Note: Our HW can't scatter-gather more than 8 fragments to build
  * a packet on the wire and so we need to figure out the cases where we
  * need to linearize the skb.
  **/
-static bool i40e_chk_linearize(struct sk_buff *skb, u32 tx_flags)
+bool __i40evf_chk_linearize(struct sk_buff *skb)
 {
-       struct skb_frag_struct *frag;
-       bool linearize = false;
-       unsigned int size = 0;
-       u16 num_frags;
-       u16 gso_segs;
+       const struct skb_frag_struct *frag, *stale;
+       int gso_size, nr_frags, sum;
 
-       num_frags = skb_shinfo(skb)->nr_frags;
-       gso_segs = skb_shinfo(skb)->gso_segs;
+       /* check to see if TSO is enabled, if so we may get a repreive */
+       gso_size = skb_shinfo(skb)->gso_size;
+       if (unlikely(!gso_size))
+               return true;
 
-       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO)) {
-               u16 j = 0;
+       /* no need to check if number of frags is less than 8 */
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       if (nr_frags < I40E_MAX_BUFFER_TXD)
+               return false;
 
-               if (num_frags < (I40E_MAX_BUFFER_TXD))
-                       goto linearize_chk_done;
-               /* try the simple math, if we have too many frags per segment */
-               if (DIV_ROUND_UP((num_frags + gso_segs), gso_segs) >
-                   I40E_MAX_BUFFER_TXD) {
-                       linearize = true;
-                       goto linearize_chk_done;
-               }
-               frag = &skb_shinfo(skb)->frags[0];
-               /* we might still have more fragments per segment */
-               do {
-                       size += skb_frag_size(frag);
-                       frag++; j++;
-                       if ((size >= skb_shinfo(skb)->gso_size) &&
-                           (j < I40E_MAX_BUFFER_TXD)) {
-                               size = (size % skb_shinfo(skb)->gso_size);
-                               j = (size) ? 1 : 0;
-                       }
-                       if (j == I40E_MAX_BUFFER_TXD) {
-                               linearize = true;
-                               break;
-                       }
-                       num_frags--;
-               } while (num_frags);
-       } else {
-               if (num_frags >= I40E_MAX_BUFFER_TXD)
-                       linearize = true;
+       /* We need to walk through the list and validate that each group
+        * of 6 fragments totals at least gso_size.  However we don't need
+        * to perform such validation on the first or last 6 since the first
+        * 6 cannot inherit any data from a descriptor before them, and the
+        * last 6 cannot inherit any data from a descriptor after them.
+        */
+       nr_frags -= I40E_MAX_BUFFER_TXD - 1;
+       frag = &skb_shinfo(skb)->frags[0];
+
+       /* Initialize size to the negative value of gso_size minus 1.  We
+        * use this as the worst case scenerio in which the frag ahead
+        * of us only provides one byte which is why we are limited to 6
+        * descriptors for a single transmit as the header and previous
+        * fragment are already consuming 2 descriptors.
+        */
+       sum = 1 - gso_size;
+
+       /* Add size of frags 1 through 5 to create our initial sum */
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+       sum += skb_frag_size(++frag);
+
+       /* Walk through fragments adding latest fragment, testing it, and
+        * then removing stale fragments from the sum.
+        */
+       stale = &skb_shinfo(skb)->frags[0];
+       for (;;) {
+               sum += skb_frag_size(++frag);
+
+               /* if sum is negative we failed to make sufficient progress */
+               if (sum < 0)
+                       return true;
+
+               /* use pre-decrement to avoid processing last fragment */
+               if (!--nr_frags)
+                       break;
+
+               sum -= skb_frag_size(++stale);
        }
 
-linearize_chk_done:
-       return linearize;
+       return false;
 }
 
 /**
@@ -1734,7 +1870,7 @@ linearize_chk_done:
  *
  * Returns -EBUSY if a stop is needed, else 0
  **/
-static inline int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
 {
        netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
        /* Memory barrier before checking head and tail */
@@ -1750,20 +1886,6 @@ static inline int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
        return 0;
 }
 
-/**
- * i40evf_maybe_stop_tx - 1st level check for tx stop conditions
- * @tx_ring: the ring to be checked
- * @size:    the size buffer we want to assure is available
- *
- * Returns 0 if stop is not needed
- **/
-static inline int i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
-{
-       if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
-               return 0;
-       return __i40evf_maybe_stop_tx(tx_ring, size);
-}
-
 /**
  * i40evf_tx_map - Build the Tx descriptor
  * @tx_ring:  ring to send buffer on
@@ -1879,7 +2001,7 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
                                                 tx_ring->queue_index),
                                                 first->bytecount);
-       i40evf_maybe_stop_tx(tx_ring, DESC_NEEDED);
+       i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
        /* Algorithm to optimize tail and RS bit setting:
         * if xmit_more is supported
@@ -1961,38 +2083,6 @@ dma_error:
        tx_ring->next_to_use = i;
 }
 
-/**
- * i40evf_xmit_descriptor_count - calculate number of tx descriptors needed
- * @skb:     send buffer
- * @tx_ring: ring to send buffer on
- *
- * Returns number of data descriptors needed for this skb. Returns 0 to indicate
- * there is not enough descriptors available in this ring since we need at least
- * one descriptor.
- **/
-static inline int i40evf_xmit_descriptor_count(struct sk_buff *skb,
-                                              struct i40e_ring *tx_ring)
-{
-       unsigned int f;
-       int count = 0;
-
-       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
-        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 4 desc gap to avoid the cache line where head is,
-        *       + 1 desc for context descriptor,
-        * otherwise try next time
-        */
-       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
-               count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
-
-       count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40evf_maybe_stop_tx(tx_ring, count + 4 + 1)) {
-               tx_ring->tx_stats.tx_busy++;
-               return 0;
-       }
-       return count;
-}
-
 /**
  * i40e_xmit_frame_ring - Sends buffer on Tx ring
  * @skb:     send buffer
@@ -2011,13 +2101,29 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        __be16 protocol;
        u32 td_cmd = 0;
        u8 hdr_len = 0;
-       int tso;
+       int tso, count;
 
        /* prefetch the data, we'll need it later */
        prefetch(skb->data);
 
-       if (0 == i40evf_xmit_descriptor_count(skb, tx_ring))
+       count = i40e_xmit_descriptor_count(skb);
+       if (i40e_chk_linearize(skb, count)) {
+               if (__skb_linearize(skb))
+                       goto out_drop;
+               count = TXD_USE_COUNT(skb->len);
+               tx_ring->tx_stats.tx_linearize++;
+       }
+
+       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+        *       + 4 desc gap to avoid the cache line where head is,
+        *       + 1 desc for context descriptor,
+        * otherwise try next time
+        */
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
+               tx_ring->tx_stats.tx_busy++;
                return NETDEV_TX_BUSY;
+       }
 
        /* prepare the xmit flags */
        if (i40evf_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
@@ -2042,24 +2148,17 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        else if (tso)
                tx_flags |= I40E_TX_FLAGS_TSO;
 
-       if (i40e_chk_linearize(skb, tx_flags)) {
-               if (skb_linearize(skb))
-                       goto out_drop;
-               tx_ring->tx_stats.tx_linearize++;
-       }
+       /* Always offload the checksum, since it's in the data descriptor */
+       tso = i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
+                                 tx_ring, &cd_tunneling);
+       if (tso < 0)
+               goto out_drop;
+
        skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
        td_cmd |= I40E_TX_DESC_CMD_ICRC;
 
-       /* Always offload the checksum, since it's in the data descriptor */
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               tx_flags |= I40E_TX_FLAGS_CSUM;
-
-               i40e_tx_enable_csum(skb, &tx_flags, &td_cmd, &td_offset,
-                                   tx_ring, &cd_tunneling);
-       }
-
        i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
                           cd_tunneling, cd_l2tag2);
 
index e29bb3e86cfdc86378c5e924e6ed531f68979250..c1dd8c5c966697bc79ae47babbab8a598d20ef18 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -153,7 +153,6 @@ enum i40e_dyn_idx_t {
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
 #define I40E_MIN_DESC_PENDING  4
 
-#define I40E_TX_FLAGS_CSUM             BIT(0)
 #define I40E_TX_FLAGS_HW_VLAN          BIT(1)
 #define I40E_TX_FLAGS_SW_VLAN          BIT(2)
 #define I40E_TX_FLAGS_TSO              BIT(3)
@@ -202,12 +201,15 @@ struct i40e_tx_queue_stats {
        u64 tx_done_old;
        u64 tx_linearize;
        u64 tx_force_wb;
+       u64 tx_lost_interrupt;
 };
 
 struct i40e_rx_queue_stats {
        u64 non_eop_descs;
        u64 alloc_page_failed;
        u64 alloc_buff_failed;
+       u64 page_reuse_count;
+       u64 realloc_count;
 };
 
 enum i40e_ring_state_t {
@@ -253,7 +255,6 @@ struct i40e_ring {
 #define I40E_RX_DTYPE_NO_SPLIT      0
 #define I40E_RX_DTYPE_HEADER_SPLIT  1
 #define I40E_RX_DTYPE_SPLIT_ALWAYS  2
-       u8  hsplit;
 #define I40E_RX_SPLIT_L2      0x1
 #define I40E_RX_SPLIT_IP      0x2
 #define I40E_RX_SPLIT_TCP_UDP 0x4
@@ -273,7 +274,6 @@ struct i40e_ring {
 
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR       BIT(0)
-#define I40E_TXR_FLAGS_OUTER_UDP_CSUM  BIT(1)
 
        /* stats structs */
        struct i40e_queue_stats stats;
@@ -313,8 +313,8 @@ struct i40e_ring_container {
 #define i40e_for_each_ring(pos, head) \
        for (pos = (head).ring; pos != NULL; pos = pos->next)
 
-void i40evf_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
-void i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40evf_alloc_rx_buffers_ps(struct i40e_ring *rxr, u16 cleaned_count);
+bool i40evf_alloc_rx_buffers_1buf(struct i40e_ring *rxr, u16 cleaned_count);
 void i40evf_alloc_rx_headers(struct i40e_ring *rxr);
 netdev_tx_t i40evf_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
 void i40evf_clean_tx_ring(struct i40e_ring *tx_ring);
@@ -324,7 +324,10 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring);
 void i40evf_free_tx_resources(struct i40e_ring *tx_ring);
 void i40evf_free_rx_resources(struct i40e_ring *rx_ring);
 int i40evf_napi_poll(struct napi_struct *napi, int budget);
-u32 i40evf_get_tx_pending(struct i40e_ring *ring);
+void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector);
+u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw);
+int __i40evf_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
+bool __i40evf_chk_linearize(struct sk_buff *skb);
 
 /**
  * i40e_get_head - Retrieve head from head writeback
@@ -339,4 +342,63 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
 
        return le32_to_cpu(*(volatile __le32 *)head);
 }
+
+/**
+ * i40e_xmit_descriptor_count - calculate number of Tx descriptors needed
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns number of data descriptors needed for this skb. Returns 0 to indicate
+ * there is not enough descriptors available in this ring since we need at least
+ * one descriptor.
+ **/
+static inline int i40e_xmit_descriptor_count(struct sk_buff *skb)
+{
+       const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+       unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+       int count = 0, size = skb_headlen(skb);
+
+       for (;;) {
+               count += TXD_USE_COUNT(size);
+
+               if (!nr_frags--)
+                       break;
+
+               size = skb_frag_size(frag++);
+       }
+
+       return count;
+}
+
+/**
+ * i40e_maybe_stop_tx - 1st level check for Tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static inline int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+       if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __i40evf_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40e_chk_linearize - Check if there are more than 8 fragments per packet
+ * @skb:      send buffer
+ * @count:    number of buffers used
+ *
+ * Note: Our HW can't scatter-gather more than 8 fragments to build
+ * a packet on the wire and so we need to figure out the cases where we
+ * need to linearize the skb.
+ **/
+static inline bool i40e_chk_linearize(struct sk_buff *skb, int count)
+{
+       /* we can only support up to 8 data buffers for a single send */
+       if (likely(count <= I40E_MAX_BUFFER_TXD))
+               return false;
+
+       return __i40evf_chk_linearize(skb);
+}
 #endif /* _I40E_TXRX_H_ */
index 9e15f68d9dddec10bab585b10cce367cbdef551d..e657eccd232c6ef54f86a73056857257e549101f 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2014 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -274,6 +274,9 @@ struct i40evf_adapter {
 };
 
 
+/* Ethtool Private Flags */
+#define I40EVF_PRIV_FLAGS_PS           BIT(0)
+
 /* needed by i40evf_ethtool.c */
 extern char i40evf_driver_name[];
 extern const char i40evf_driver_version[];
@@ -281,6 +284,7 @@ extern const char i40evf_driver_version[];
 int i40evf_up(struct i40evf_adapter *adapter);
 void i40evf_down(struct i40evf_adapter *adapter);
 int i40evf_process_config(struct i40evf_adapter *adapter);
+void i40evf_schedule_reset(struct i40evf_adapter *adapter);
 void i40evf_reset(struct i40evf_adapter *adapter);
 void i40evf_set_ethtool_ops(struct net_device *netdev);
 void i40evf_update_stats(struct i40evf_adapter *adapter);
index bd1c2728bc5c603887bc6d0a8090706c19ea3143..dd4430aae7fa4aa5f09b03c5bb86d96395c7ebf9 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -63,6 +63,12 @@ static const struct i40evf_stats i40evf_gstrings_stats[] = {
 #define I40EVF_STATS_LEN(_dev) \
        (I40EVF_GLOBAL_STATS_LEN + I40EVF_QUEUE_STATS_LEN(_dev))
 
+static const char i40evf_priv_flags_strings[][ETH_GSTRING_LEN] = {
+       "packet-split",
+};
+
+#define I40EVF_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40evf_priv_flags_strings)
+
 /**
  * i40evf_get_settings - Get Link Speed and Duplex settings
  * @netdev: network interface device structure
@@ -97,6 +103,8 @@ static int i40evf_get_sset_count(struct net_device *netdev, int sset)
 {
        if (sset == ETH_SS_STATS)
                return I40EVF_STATS_LEN(netdev);
+       else if (sset == ETH_SS_PRIV_FLAGS)
+               return I40EVF_PRIV_FLAGS_STR_LEN;
        else
                return -EINVAL;
 }
@@ -162,6 +170,12 @@ static void i40evf_get_strings(struct net_device *netdev, u32 sset, u8 *data)
                        snprintf(p, ETH_GSTRING_LEN, "rx-%u.bytes", i);
                        p += ETH_GSTRING_LEN;
                }
+       } else if (sset == ETH_SS_PRIV_FLAGS) {
+               for (i = 0; i < I40EVF_PRIV_FLAGS_STR_LEN; i++) {
+                       memcpy(data, i40evf_priv_flags_strings[i],
+                              ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
        }
 }
 
@@ -211,6 +225,7 @@ static void i40evf_get_drvinfo(struct net_device *netdev,
        strlcpy(drvinfo->version, i40evf_driver_version, 32);
        strlcpy(drvinfo->fw_version, "N/A", 4);
        strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       drvinfo->n_priv_flags = I40EVF_PRIV_FLAGS_STR_LEN;
 }
 
 /**
@@ -710,6 +725,54 @@ static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir,
                                 I40EVF_HLUT_ARRAY_SIZE);
 }
 
+/**
+ * i40evf_get_priv_flags - report device private flags
+ * @dev: network interface device structure
+ *
+ * The get string set count and the string set should be matched for each
+ * flag returned.  Add new strings for each flag to the i40e_priv_flags_strings
+ * array.
+ *
+ * Returns a u32 bitmap of flags.
+ **/
+static u32 i40evf_get_priv_flags(struct net_device *dev)
+{
+       struct i40evf_adapter *adapter = netdev_priv(dev);
+       u32 ret_flags = 0;
+
+       ret_flags |= adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ?
+               I40EVF_PRIV_FLAGS_PS : 0;
+
+       return ret_flags;
+}
+
+/**
+ * i40evf_set_priv_flags - set private flags
+ * @dev: network interface device structure
+ * @flags: bit flags to be set
+ **/
+static int i40evf_set_priv_flags(struct net_device *dev, u32 flags)
+{
+       struct i40evf_adapter *adapter = netdev_priv(dev);
+       bool reset_required = false;
+
+       if ((flags & I40EVF_PRIV_FLAGS_PS) &&
+           !(adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
+               adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
+               reset_required = true;
+       } else if (!(flags & I40EVF_PRIV_FLAGS_PS) &&
+                  (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED)) {
+               adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
+               reset_required = true;
+       }
+
+       /* if needed, issue reset to cause things to take effect */
+       if (reset_required)
+               i40evf_schedule_reset(adapter);
+
+       return 0;
+}
+
 static const struct ethtool_ops i40evf_ethtool_ops = {
        .get_settings           = i40evf_get_settings,
        .get_drvinfo            = i40evf_get_drvinfo,
@@ -719,6 +782,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = {
        .get_strings            = i40evf_get_strings,
        .get_ethtool_stats      = i40evf_get_ethtool_stats,
        .get_sset_count         = i40evf_get_sset_count,
+       .get_priv_flags         = i40evf_get_priv_flags,
+       .set_priv_flags         = i40evf_set_priv_flags,
        .get_msglevel           = i40evf_get_msglevel,
        .set_msglevel           = i40evf_set_msglevel,
        .get_coalesce           = i40evf_get_coalesce,
index 66964eb6b7de3d0222b4b19e00c7be5c7ea0871b..4b70aae2fa8406ed408036f2ba0d81c8e29a07be 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 - 2015 Intel Corporation.
+ * Copyright(c) 2013 - 2016 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,
@@ -32,13 +32,13 @@ static int i40evf_close(struct net_device *netdev);
 
 char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
-       "Intel(R) XL710/X710 Virtual Function Network Driver";
+       "Intel(R) 40-10 Gigabit Virtual Function Network Driver";
 
 #define DRV_KERN "-k"
 
 #define DRV_VERSION_MAJOR 1
 #define DRV_VERSION_MINOR 4
-#define DRV_VERSION_BUILD 4
+#define DRV_VERSION_BUILD 15
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD) \
@@ -172,6 +172,19 @@ void i40evf_debug_d(void *hw, u32 mask, char *fmt_str, ...)
        pr_info("%s", buf);
 }
 
+/**
+ * i40evf_schedule_reset - Set the flags and schedule a reset event
+ * @adapter: board private structure
+ **/
+void i40evf_schedule_reset(struct i40evf_adapter *adapter)
+{
+       if (!(adapter->flags &
+             (I40EVF_FLAG_RESET_PENDING | I40EVF_FLAG_RESET_NEEDED))) {
+               adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+               schedule_work(&adapter->reset_task);
+       }
+}
+
 /**
  * i40evf_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
@@ -181,11 +194,7 @@ static void i40evf_tx_timeout(struct net_device *netdev)
        struct i40evf_adapter *adapter = netdev_priv(netdev);
 
        adapter->tx_timeout_count++;
-       if (!(adapter->flags & (I40EVF_FLAG_RESET_PENDING |
-                               I40EVF_FLAG_RESET_NEEDED))) {
-               adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
-               queue_work(i40evf_wq, &adapter->reset_task);
-       }
+       i40evf_schedule_reset(adapter);
 }
 
 /**
@@ -638,35 +647,22 @@ static void i40evf_configure_rx(struct i40evf_adapter *adapter)
        int rx_buf_len;
 
 
-       adapter->flags &= ~I40EVF_FLAG_RX_PS_CAPABLE;
-       adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;
-
-       /* Decide whether to use packet split mode or not */
-       if (netdev->mtu > ETH_DATA_LEN) {
-               if (adapter->flags & I40EVF_FLAG_RX_PS_CAPABLE)
-                       adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
-               else
-                       adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
-       } else {
-               if (adapter->flags & I40EVF_FLAG_RX_1BUF_CAPABLE)
-                       adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
-               else
-                       adapter->flags |= I40EVF_FLAG_RX_PS_ENABLED;
-       }
-
        /* Set the RX buffer length according to the mode */
-       if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
-               rx_buf_len = I40E_RX_HDR_SIZE;
-       } else {
-               if (netdev->mtu <= ETH_DATA_LEN)
-                       rx_buf_len = I40EVF_RXBUFFER_2048;
-               else
-                       rx_buf_len = ALIGN(max_frame, 1024);
-       }
+       if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED ||
+           netdev->mtu <= ETH_DATA_LEN)
+               rx_buf_len = I40EVF_RXBUFFER_2048;
+       else
+               rx_buf_len = ALIGN(max_frame, 1024);
 
        for (i = 0; i < adapter->num_active_queues; i++) {
                adapter->rx_rings[i].tail = hw->hw_addr + I40E_QRX_TAIL1(i);
                adapter->rx_rings[i].rx_buf_len = rx_buf_len;
+               if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+                       set_ring_ps_enabled(&adapter->rx_rings[i]);
+                       adapter->rx_rings[i].rx_hdr_len = I40E_RX_HDR_SIZE;
+               } else {
+                       clear_ring_ps_enabled(&adapter->rx_rings[i]);
+               }
        }
 }
 
@@ -1003,7 +999,12 @@ static void i40evf_configure(struct i40evf_adapter *adapter)
        for (i = 0; i < adapter->num_active_queues; i++) {
                struct i40e_ring *ring = &adapter->rx_rings[i];
 
+       if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+               i40evf_alloc_rx_headers(ring);
+               i40evf_alloc_rx_buffers_ps(ring, ring->count);
+       } else {
                i40evf_alloc_rx_buffers_1buf(ring, ring->count);
+       }
                ring->next_to_use = ring->count - 1;
                writel(ring->next_to_use, ring->tail);
        }
@@ -1837,6 +1838,7 @@ static void i40evf_reset_task(struct work_struct *work)
                        break;
                msleep(I40EVF_RESET_WAIT_MS);
        }
+       pci_set_master(adapter->pdev);
        /* extra wait to make sure minimum wait is met */
        msleep(I40EVF_RESET_WAIT_MS);
        if (i == I40EVF_RESET_WAIT_COUNT) {
@@ -1881,6 +1883,7 @@ static void i40evf_reset_task(struct work_struct *work)
                adapter->netdev->flags &= ~IFF_UP;
                clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
                adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+               adapter->state = __I40EVF_DOWN;
                dev_info(&adapter->pdev->dev, "Reset task did not complete, VF disabled\n");
                return; /* Do not attempt to reinit. It's dead, Jim. */
        }
@@ -2334,9 +2337,24 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
                            NETIF_F_IPV6_CSUM |
                            NETIF_F_TSO |
                            NETIF_F_TSO6 |
+                           NETIF_F_TSO_ECN |
+                           NETIF_F_GSO_GRE            |
+                           NETIF_F_GSO_UDP_TUNNEL |
                            NETIF_F_RXCSUM |
                            NETIF_F_GRO;
 
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM             |
+                                  NETIF_F_IPV6_CSUM           |
+                                  NETIF_F_TSO                 |
+                                  NETIF_F_TSO6                |
+                                  NETIF_F_TSO_ECN             |
+                                  NETIF_F_GSO_GRE             |
+                                  NETIF_F_GSO_UDP_TUNNEL      |
+                                  NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
+       if (adapter->flags & I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE)
+               netdev->features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
+
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features;
        netdev->hw_features &= ~NETIF_F_RXCSUM;
@@ -2475,11 +2493,20 @@ static void i40evf_init_task(struct work_struct *work)
        default:
                goto err_alloc;
        }
+
+       if (hw->mac.type == I40E_MAC_X722_VF)
+               adapter->flags |= I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE;
+
        if (i40evf_process_config(adapter))
                goto err_alloc;
        adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
 
        adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
+       adapter->flags |= I40EVF_FLAG_RX_1BUF_CAPABLE;
+       adapter->flags |= I40EVF_FLAG_RX_PS_CAPABLE;
+
+       /* Default to single buffer rx, can be changed through ethtool. */
+       adapter->flags &= ~I40EVF_FLAG_RX_PS_ENABLED;
 
        netdev->netdev_ops = &i40evf_netdev_ops;
        i40evf_set_ethtool_ops(netdev);
@@ -2510,10 +2537,6 @@ static void i40evf_init_task(struct work_struct *work)
        if (err)
                goto err_sw_init;
        i40evf_map_rings_to_vectors(adapter);
-       if (adapter->vf_res->vf_offload_flags &
-                   I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
-               adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE;
-
        if (adapter->vf_res->vf_offload_flags &
            I40E_VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
                adapter->flags |= I40EVF_FLAG_WB_ON_ITR_CAPABLE;
index d3739cc5b608488d6b1e91405c7e267d85327db3..488e738f76c6dfdc0e75a2780e38ae307cb105c0 100644 (file)
@@ -270,6 +270,10 @@ void i40evf_configure_queues(struct i40evf_adapter *adapter)
                vqpi->rxq.max_pkt_size = adapter->netdev->mtu
                                        + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
                vqpi->rxq.databuffer_size = adapter->rx_rings[i].rx_buf_len;
+               if (adapter->flags & I40EVF_FLAG_RX_PS_ENABLED) {
+                       vqpi->rxq.splithdr_enabled = true;
+                       vqpi->rxq.hdr_size = I40E_RX_HDR_SIZE;
+               }
                vqpi++;
        }
 
index adb33e2a0137600e841cd2b289f7f3bb4f28362a..a23aa6704394b46fd3d7530f6ea8fadd48dd431b 100644 (file)
@@ -34,6 +34,7 @@
 #include "e1000_mac.h"
 #include "e1000_82575.h"
 #include "e1000_i210.h"
+#include "igb.h"
 
 static s32  igb_get_invariants_82575(struct e1000_hw *);
 static s32  igb_acquire_phy_82575(struct e1000_hw *);
@@ -71,6 +72,32 @@ 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 };
 
+/* Due to a hw errata, if the host tries to  configure the VFTA register
+ * while performing queries from the BMC or DMA, then the VFTA in some
+ * cases won't be written.
+ */
+
+/**
+ *  igb_write_vfta_i350 - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
+{
+       struct igb_adapter *adapter = hw->back;
+       int i;
+
+       for (i = 10; i--;)
+               array_wr32(E1000_VFTA, offset, value);
+
+       wrfl();
+       adapter->shadow_vfta[offset] = value;
+}
+
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
  *  @hw: pointer to the HW structure
@@ -398,6 +425,8 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
 
        /* Set mta register count */
        mac->mta_reg_count = 128;
+       /* Set uta register count */
+       mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
        /* Set rar entry count */
        switch (mac->type) {
        case e1000_82576:
@@ -429,6 +458,11 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
                mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
        }
 
+       if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
+               mac->ops.write_vfta = igb_write_vfta_i350;
+       else
+               mac->ops.write_vfta = igb_write_vfta;
+
        /* Set if part includes ASF firmware */
        mac->asf_firmware_present = true;
        /* Set if manageability features are enabled. */
@@ -1517,10 +1551,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
 
        /* Disabling VLAN filtering */
        hw_dbg("Initializing the IEEE VLAN\n");
-       if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
-               igb_clear_vfta_i350(hw);
-       else
-               igb_clear_vfta(hw);
+       igb_clear_vfta(hw);
 
        /* Setup the receive address */
        igb_init_rx_addrs(hw, rar_count);
@@ -2889,7 +2920,7 @@ static struct e1000_mac_operations e1000_mac_ops_82575 = {
 #endif
 };
 
-static struct e1000_phy_operations e1000_phy_ops_82575 = {
+static const struct e1000_phy_operations e1000_phy_ops_82575 = {
        .acquire              = igb_acquire_phy_82575,
        .get_cfg_done         = igb_get_cfg_done_82575,
        .release              = igb_release_phy_82575,
index 2154aea7aa7e70c9d5083bc3631a37f885d48bd4..de8805a2a2feff757c21099ccc52223b98c0c83b 100644 (file)
@@ -56,10 +56,10 @@ s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset, u8 dev_addr,
 #define E1000_SRRCTL_TIMESTAMP                          0x40000000
 
 
-#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#define E1000_MRQC_ENABLE_RSS_MQ            0x00000002
 #define E1000_MRQC_ENABLE_VMDQ              0x00000003
 #define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
-#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005
+#define E1000_MRQC_ENABLE_VMDQ_RSS_MQ       0x00000005
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
 
index c3c598c347a951455d9e2626e023159b81f68136..e9f23ee8f15efa76950fd21a3fdd52950a139663 100644 (file)
 /* Ethertype field values */
 #define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
 
-#define MAX_JUMBO_FRAME_SIZE    0x3F00
+/* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */
+#define MAX_JUMBO_FRAME_SIZE   0x2600
 
 /* PBA constants */
 #define E1000_PBA_34K 0x0022
index 4034207eb5ccb434a9ae4af124b10223f9c71395..2fb2213cd562e84df0bcd42f55618e76133fe922 100644 (file)
@@ -325,7 +325,7 @@ struct e1000_mac_operations {
        s32 (*get_thermal_sensor_data)(struct e1000_hw *);
        s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
 #endif
-
+       void (*write_vfta)(struct e1000_hw *, u32, u32);
 };
 
 struct e1000_phy_operations {
@@ -372,7 +372,7 @@ struct e1000_thermal_sensor_data {
 struct e1000_info {
        s32 (*get_invariants)(struct e1000_hw *);
        struct e1000_mac_operations *mac_ops;
-       struct e1000_phy_operations *phy_ops;
+       const struct e1000_phy_operations *phy_ops;
        struct e1000_nvm_operations *nvm_ops;
 };
 
index 2a88595f956cf4e3089d20a986f0adb9db48681e..07cf4fe5833815b4cac586656551782b4649a27c 100644 (file)
@@ -92,10 +92,8 @@ void igb_clear_vfta(struct e1000_hw *hw)
 {
        u32 offset;
 
-       for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-               array_wr32(E1000_VFTA, offset, 0);
-               wrfl();
-       }
+       for (offset = E1000_VLAN_FILTER_TBL_SIZE; offset--;)
+               hw->mac.ops.write_vfta(hw, offset, 0);
 }
 
 /**
@@ -107,54 +105,14 @@ void igb_clear_vfta(struct e1000_hw *hw)
  *  Writes value at the given offset in the register array which stores
  *  the VLAN filter table.
  **/
-static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
 {
+       struct igb_adapter *adapter = hw->back;
+
        array_wr32(E1000_VFTA, offset, value);
        wrfl();
-}
-
-/* Due to a hw errata, if the host tries to  configure the VFTA register
- * while performing queries from the BMC or DMA, then the VFTA in some
- * cases won't be written.
- */
 
-/**
- *  igb_clear_vfta_i350 - Clear VLAN filter table
- *  @hw: pointer to the HW structure
- *
- *  Clears the register array which contains the VLAN filter table by
- *  setting all the values to 0.
- **/
-void igb_clear_vfta_i350(struct e1000_hw *hw)
-{
-       u32 offset;
-       int i;
-
-       for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-               for (i = 0; i < 10; i++)
-                       array_wr32(E1000_VFTA, offset, 0);
-
-               wrfl();
-       }
-}
-
-/**
- *  igb_write_vfta_i350 - Write value to VLAN filter table
- *  @hw: pointer to the HW structure
- *  @offset: register offset in VLAN filter table
- *  @value: register value written to VLAN filter table
- *
- *  Writes value at the given offset in the register array which stores
- *  the VLAN filter table.
- **/
-static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
-{
-       int i;
-
-       for (i = 0; i < 10; i++)
-               array_wr32(E1000_VFTA, offset, value);
-
-       wrfl();
+       adapter->shadow_vfta[offset] = value;
 }
 
 /**
@@ -182,41 +140,156 @@ void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
                hw->mac.ops.rar_set(hw, mac_addr, i);
 }
 
+/**
+ *  igb_find_vlvf_slot - find the VLAN id or the first empty slot
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vlvf_bypass: skip VLVF if no match is found
+ *
+ *  return the VLVF index where this VLAN id should be placed
+ *
+ **/
+static s32 igb_find_vlvf_slot(struct e1000_hw *hw, u32 vlan, bool vlvf_bypass)
+{
+       s32 regindex, first_empty_slot;
+       u32 bits;
+
+       /* short cut the special case */
+       if (vlan == 0)
+               return 0;
+
+       /* if vlvf_bypass is set we don't want to use an empty slot, we
+        * will simply bypass the VLVF if there are no entries present in the
+        * VLVF that contain our VLAN
+        */
+       first_empty_slot = vlvf_bypass ? -E1000_ERR_NO_SPACE : 0;
+
+       /* Search for the VLAN id in the VLVF entries. Save off the first empty
+        * slot found along the way.
+        *
+        * pre-decrement loop covering (IXGBE_VLVF_ENTRIES - 1) .. 1
+        */
+       for (regindex = E1000_VLVF_ARRAY_SIZE; --regindex > 0;) {
+               bits = rd32(E1000_VLVF(regindex)) & E1000_VLVF_VLANID_MASK;
+               if (bits == vlan)
+                       return regindex;
+               if (!first_empty_slot && !bits)
+                       first_empty_slot = regindex;
+       }
+
+       return first_empty_slot ? : -E1000_ERR_NO_SPACE;
+}
+
 /**
  *  igb_vfta_set - enable or disable vlan in VLAN filter table
  *  @hw: pointer to the HW structure
- *  @vid: VLAN id to add or remove
- *  @add: if true add filter, if false remove
+ *  @vlan: VLAN id to add or remove
+ *  @vind: VMDq output index that maps queue to VLAN id
+ *  @vlan_on: if true add filter, if false remove
  *
  *  Sets or clears a bit in the VLAN filter table array based on VLAN id
  *  and if we are adding or removing the filter
  **/
-s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
+s32 igb_vfta_set(struct e1000_hw *hw, u32 vlan, u32 vind,
+                bool vlan_on, bool vlvf_bypass)
 {
-       u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
-       u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
-       u32 vfta;
        struct igb_adapter *adapter = hw->back;
-       s32 ret_val = 0;
+       u32 regidx, vfta_delta, vfta, bits;
+       s32 vlvf_index;
 
-       vfta = adapter->shadow_vfta[index];
+       if ((vlan > 4095) || (vind > 7))
+               return -E1000_ERR_PARAM;
 
-       /* bit was set/cleared before we started */
-       if ((!!(vfta & mask)) == add) {
-               ret_val = -E1000_ERR_CONFIG;
-       } else {
-               if (add)
-                       vfta |= mask;
-               else
-                       vfta &= ~mask;
+       /* this is a 2 part operation - first the VFTA, then the
+        * VLVF and VLVFB if VT Mode is set
+        * We don't write the VFTA until we know the VLVF part succeeded.
+        */
+
+       /* Part 1
+        * The VFTA is a bitstring made up of 128 32-bit registers
+        * that enable the particular VLAN id, much like the MTA:
+        *    bits[11-5]: which register
+        *    bits[4-0]:  which bit in the register
+        */
+       regidx = vlan / 32;
+       vfta_delta = 1 << (vlan % 32);
+       vfta = adapter->shadow_vfta[regidx];
+
+       /* vfta_delta represents the difference between the current value
+        * of vfta and the value we want in the register.  Since the diff
+        * is an XOR mask we can just update vfta using an XOR.
+        */
+       vfta_delta &= vlan_on ? ~vfta : vfta;
+       vfta ^= vfta_delta;
+
+       /* Part 2
+        * If VT Mode is set
+        *   Either vlan_on
+        *     make sure the VLAN is in VLVF
+        *     set the vind bit in the matching VLVFB
+        *   Or !vlan_on
+        *     clear the pool bit and possibly the vind
+        */
+       if (!adapter->vfs_allocated_count)
+               goto vfta_update;
+
+       vlvf_index = igb_find_vlvf_slot(hw, vlan, vlvf_bypass);
+       if (vlvf_index < 0) {
+               if (vlvf_bypass)
+                       goto vfta_update;
+               return vlvf_index;
        }
-       if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
-               igb_write_vfta_i350(hw, index, vfta);
-       else
-               igb_write_vfta(hw, index, vfta);
-       adapter->shadow_vfta[index] = vfta;
 
-       return ret_val;
+       bits = rd32(E1000_VLVF(vlvf_index));
+
+       /* set the pool bit */
+       bits |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vind);
+       if (vlan_on)
+               goto vlvf_update;
+
+       /* clear the pool bit */
+       bits ^= 1 << (E1000_VLVF_POOLSEL_SHIFT + vind);
+
+       if (!(bits & E1000_VLVF_POOLSEL_MASK)) {
+               /* Clear VFTA first, then disable VLVF.  Otherwise
+                * we run the risk of stray packets leaking into
+                * the PF via the default pool
+                */
+               if (vfta_delta)
+                       hw->mac.ops.write_vfta(hw, regidx, vfta);
+
+               /* disable VLVF and clear remaining bit from pool */
+               wr32(E1000_VLVF(vlvf_index), 0);
+
+               return 0;
+       }
+
+       /* If there are still bits set in the VLVFB registers
+        * for the VLAN ID indicated we need to see if the
+        * caller is requesting that we clear the VFTA entry bit.
+        * If the caller has requested that we clear the VFTA
+        * entry bit but there are still pools/VFs using this VLAN
+        * ID entry then ignore the request.  We're not worried
+        * about the case where we're turning the VFTA VLAN ID
+        * entry bit on, only when requested to turn it off as
+        * there may be multiple pools and/or VFs using the
+        * VLAN ID entry.  In that case we cannot clear the
+        * VFTA bit until all pools/VFs using that VLAN ID have also
+        * been cleared.  This will be indicated by "bits" being
+        * zero.
+        */
+       vfta_delta = 0;
+
+vlvf_update:
+       /* record pool change and enable VLAN ID if not already enabled */
+       wr32(E1000_VLVF(vlvf_index), bits | vlan | E1000_VLVF_VLANID_ENABLE);
+
+vfta_update:
+       /* bit was set/cleared before we started */
+       if (vfta_delta)
+               hw->mac.ops.write_vfta(hw, regidx, vfta);
+
+       return 0;
 }
 
 /**
index ea24961b0d705e557a6b9bd57772d984ab0927ae..90c8893c3eeda728f1f18979088d2ecd7f5431d6 100644 (file)
@@ -56,8 +56,9 @@ s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
 
 void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
 void igb_clear_vfta(struct e1000_hw *hw);
-void igb_clear_vfta_i350(struct e1000_hw *hw);
-s32  igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+s32  igb_vfta_set(struct e1000_hw *hw, u32 vid, u32 vind,
+                 bool vlan_on, bool vlvf_bypass);
 void igb_config_collision_dist(struct e1000_hw *hw);
 void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
 void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
index 162cc49345d09babbd7fab30ec0917215e1a9b64..10f5c9e016a965096b7d02250d340238edd68f48 100644 (file)
@@ -322,14 +322,20 @@ static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
 {
        s32 ret_val = -E1000_ERR_MBX;
        u32 p2v_mailbox;
+       int count = 10;
 
-       /* Take ownership of the buffer */
-       wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
+       do {
+               /* Take ownership of the buffer */
+               wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
 
-       /* reserve mailbox for vf use */
-       p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
-       if (p2v_mailbox & E1000_P2VMAILBOX_PFU)
-               ret_val = 0;
+               /* reserve mailbox for vf use */
+               p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+               if (p2v_mailbox & E1000_P2VMAILBOX_PFU) {
+                       ret_val = 0;
+                       break;
+               }
+               udelay(1000);
+       } while (count-- > 0);
 
        return ret_val;
 }
index e3cb93bdb21aed5341a758694735283058f8b71f..9413fa61392f0afc596969f1e9e9003b4245831c 100644 (file)
@@ -95,7 +95,6 @@ struct vf_data_storage {
        unsigned char vf_mac_addresses[ETH_ALEN];
        u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
        u16 num_vf_mc_hashes;
-       u16 vlans_enabled;
        u32 flags;
        unsigned long last_nack;
        u16 pf_vlan; /* When set, guest VLAN config not allowed. */
@@ -482,6 +481,7 @@ struct igb_adapter {
 #define IGB_FLAG_MAS_ENABLE            (1 << 12)
 #define IGB_FLAG_HAS_MSIX              (1 << 13)
 #define IGB_FLAG_EEE                   (1 << 14)
+#define IGB_FLAG_VLAN_PROMISC          BIT(15)
 
 /* Media Auto Sense */
 #define IGB_MAS_ENABLE_0               0X0001
@@ -510,6 +510,8 @@ enum igb_boards {
 extern char igb_driver_name[];
 extern char igb_driver_version[];
 
+int igb_open(struct net_device *netdev);
+int igb_close(struct net_device *netdev);
 int igb_up(struct igb_adapter *);
 void igb_down(struct igb_adapter *);
 void igb_reinit_locked(struct igb_adapter *);
index 1d329f1d047be8604f0e11f33bb09a04d49cfd9d..7982243d1f9bedfef02d1b34559833777cb2fe00 100644 (file)
@@ -2017,7 +2017,7 @@ static void igb_diag_test(struct net_device *netdev,
 
                if (if_running)
                        /* indicate we're in test mode */
-                       dev_close(netdev);
+                       igb_close(netdev);
                else
                        igb_reset(adapter);
 
@@ -2050,7 +2050,7 @@ static void igb_diag_test(struct net_device *netdev,
 
                clear_bit(__IGB_TESTING, &adapter->state);
                if (if_running)
-                       dev_open(netdev);
+                       igb_open(netdev);
        } else {
                dev_info(&adapter->pdev->dev, "online testing starting\n");
 
index 31e5f39428393818257853b44b0b4915f4817eac..834b1b6a9277b461f0969044b318f2d1046c9291 100644 (file)
@@ -122,8 +122,8 @@ static void igb_setup_mrqc(struct igb_adapter *);
 static int igb_probe(struct pci_dev *, const struct pci_device_id *);
 static void igb_remove(struct pci_dev *pdev);
 static int igb_sw_init(struct igb_adapter *);
-static int igb_open(struct net_device *);
-static int igb_close(struct net_device *);
+int igb_open(struct net_device *);
+int igb_close(struct net_device *);
 static void igb_configure(struct igb_adapter *);
 static void igb_configure_tx(struct igb_adapter *);
 static void igb_configure_rx(struct igb_adapter *);
@@ -140,7 +140,7 @@ static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev,
                                          struct rtnl_link_stats64 *stats);
 static int igb_change_mtu(struct net_device *, int);
 static int igb_set_mac(struct net_device *, void *);
-static void igb_set_uta(struct igb_adapter *adapter);
+static void igb_set_uta(struct igb_adapter *adapter, bool set);
 static irqreturn_t igb_intr(int irq, void *);
 static irqreturn_t igb_intr_msi(int irq, void *);
 static irqreturn_t igb_msix_other(int irq, void *);
@@ -1534,12 +1534,13 @@ static void igb_irq_enable(struct igb_adapter *adapter)
 static void igb_update_mng_vlan(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
+       u16 pf_id = adapter->vfs_allocated_count;
        u16 vid = adapter->hw.mng_cookie.vlan_id;
        u16 old_vid = adapter->mng_vlan_id;
 
        if (hw->mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
                /* add VID to filter table */
-               igb_vfta_set(hw, vid, true);
+               igb_vfta_set(hw, vid, pf_id, true, true);
                adapter->mng_vlan_id = vid;
        } else {
                adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
@@ -1549,7 +1550,7 @@ static void igb_update_mng_vlan(struct igb_adapter *adapter)
            (vid != old_vid) &&
            !test_bit(old_vid, adapter->active_vlans)) {
                /* remove VID from filter table */
-               igb_vfta_set(hw, old_vid, false);
+               igb_vfta_set(hw, vid, pf_id, false, true);
        }
 }
 
@@ -1818,6 +1819,10 @@ void igb_down(struct igb_adapter *adapter)
 
        if (!pci_channel_offline(adapter->pdev))
                igb_reset(adapter);
+
+       /* clear VLAN promisc flag so VFTA will be updated if necessary */
+       adapter->flags &= ~IGB_FLAG_VLAN_PROMISC;
+
        igb_clean_all_tx_rings(adapter);
        igb_clean_all_rx_rings(adapter);
 #ifdef CONFIG_IGB_DCA
@@ -1862,7 +1867,7 @@ void igb_reset(struct igb_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_mac_info *mac = &hw->mac;
        struct e1000_fc_info *fc = &hw->fc;
-       u32 pba = 0, tx_space, min_tx_space, min_rx_space, hwm;
+       u32 pba, hwm;
 
        /* Repartition Pba for greater than 9k mtu
         * To take effect CTRL.RST is required.
@@ -1886,9 +1891,10 @@ void igb_reset(struct igb_adapter *adapter)
                break;
        }
 
-       if ((adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) &&
-           (mac->type < e1000_82576)) {
-               /* adjust PBA for jumbo frames */
+       if (mac->type == e1000_82575) {
+               u32 min_rx_space, min_tx_space, needed_tx_space;
+
+               /* write Rx PBA so that hardware can report correct Tx PBA */
                wr32(E1000_PBA, pba);
 
                /* To maintain wire speed transmits, the Tx FIFO should be
@@ -1898,31 +1904,26 @@ void igb_reset(struct igb_adapter *adapter)
                 * one full receive packet and is similarly rounded up and
                 * expressed in KB.
                 */
-               pba = rd32(E1000_PBA);
-               /* upper 16 bits has Tx packet buffer allocation size in KB */
-               tx_space = pba >> 16;
-               /* lower 16 bits has Rx packet buffer allocation size in KB */
-               pba &= 0xffff;
-               /* the Tx fifo also stores 16 bytes of information about the Tx
-                * but don't include ethernet FCS because hardware appends it
+               min_rx_space = DIV_ROUND_UP(MAX_JUMBO_FRAME_SIZE, 1024);
+
+               /* The Tx FIFO also stores 16 bytes of information about the Tx
+                * but don't include Ethernet FCS because hardware appends it.
+                * We only need to round down to the nearest 512 byte block
+                * count since the value we care about is 2 frames, not 1.
                 */
-               min_tx_space = (adapter->max_frame_size +
-                               sizeof(union e1000_adv_tx_desc) -
-                               ETH_FCS_LEN) * 2;
-               min_tx_space = ALIGN(min_tx_space, 1024);
-               min_tx_space >>= 10;
-               /* software strips receive CRC, so leave room for it */
-               min_rx_space = adapter->max_frame_size;
-               min_rx_space = ALIGN(min_rx_space, 1024);
-               min_rx_space >>= 10;
+               min_tx_space = adapter->max_frame_size;
+               min_tx_space += sizeof(union e1000_adv_tx_desc) - ETH_FCS_LEN;
+               min_tx_space = DIV_ROUND_UP(min_tx_space, 512);
+
+               /* upper 16 bits has Tx packet buffer allocation size in KB */
+               needed_tx_space = min_tx_space - (rd32(E1000_PBA) >> 16);
 
                /* If current Tx allocation is less than the min Tx FIFO size,
                 * and the min Tx FIFO size is less than the current Rx FIFO
-                * allocation, take space away from current Rx allocation
+                * allocation, take space away from current Rx allocation.
                 */
-               if (tx_space < min_tx_space &&
-                   ((min_tx_space - tx_space) < pba)) {
-                       pba = pba - (min_tx_space - tx_space);
+               if (needed_tx_space < pba) {
+                       pba -= needed_tx_space;
 
                        /* if short on Rx space, Rx wins and must trump Tx
                         * adjustment
@@ -1930,18 +1931,20 @@ void igb_reset(struct igb_adapter *adapter)
                        if (pba < min_rx_space)
                                pba = min_rx_space;
                }
+
+               /* adjust PBA for jumbo frames */
                wr32(E1000_PBA, pba);
        }
 
-       /* flow control settings */
-       /* The high water mark must be low enough to fit one full frame
-        * (or the size used for early receive) above it in the Rx FIFO.
-        * Set it to the lower of:
-        * - 90% of the Rx FIFO size, or
-        * - the full Rx FIFO size minus one full frame
+       /* flow control settings
+        * The high water mark must be low enough to fit one full frame
+        * after transmitting the pause frame.  As such we must have enough
+        * space to allow for us to complete our current transmit and then
+        * receive the frame that is in progress from the link partner.
+        * Set it to:
+        * - the full Rx FIFO size minus one full Tx plus one full Rx frame
         */
-       hwm = min(((pba << 10) * 9 / 10),
-                       ((pba << 10) - 2 * adapter->max_frame_size));
+       hwm = (pba << 10) - (adapter->max_frame_size + MAX_JUMBO_FRAME_SIZE);
 
        fc->high_water = hwm & 0xFFFFFFF0;      /* 16-byte granularity */
        fc->low_water = fc->high_water - 16;
@@ -2051,7 +2054,7 @@ static int igb_set_features(struct net_device *netdev,
        if (changed & NETIF_F_HW_VLAN_CTAG_RX)
                igb_vlan_mode(netdev, features);
 
-       if (!(changed & NETIF_F_RXALL))
+       if (!(changed & (NETIF_F_RXALL | NETIF_F_NTUPLE)))
                return 0;
 
        netdev->features = features;
@@ -2064,6 +2067,25 @@ static int igb_set_features(struct net_device *netdev,
        return 0;
 }
 
+static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
+                          struct net_device *dev,
+                          const unsigned char *addr, u16 vid,
+                          u16 flags)
+{
+       /* guarantee we can provide a unique filter for the unicast address */
+       if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
+               struct igb_adapter *adapter = netdev_priv(dev);
+               struct e1000_hw *hw = &adapter->hw;
+               int vfn = adapter->vfs_allocated_count;
+               int rar_entries = hw->mac.rar_entry_count - (vfn + 1);
+
+               if (netdev_uc_count(dev) >= rar_entries)
+                       return -ENOMEM;
+       }
+
+       return ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, flags);
+}
+
 static const struct net_device_ops igb_netdev_ops = {
        .ndo_open               = igb_open,
        .ndo_stop               = igb_close,
@@ -2087,6 +2109,7 @@ static const struct net_device_ops igb_netdev_ops = {
 #endif
        .ndo_fix_features       = igb_fix_features,
        .ndo_set_features       = igb_set_features,
+       .ndo_fdb_add            = igb_ndo_fdb_add,
        .ndo_features_check     = passthru_features_check,
 };
 
@@ -2349,27 +2372,35 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * assignment.
         */
        netdev->features |= NETIF_F_SG |
-                           NETIF_F_IP_CSUM |
-                           NETIF_F_IPV6_CSUM |
                            NETIF_F_TSO |
                            NETIF_F_TSO6 |
                            NETIF_F_RXHASH |
                            NETIF_F_RXCSUM |
+                           NETIF_F_HW_CSUM |
                            NETIF_F_HW_VLAN_CTAG_RX |
                            NETIF_F_HW_VLAN_CTAG_TX;
 
+       if (hw->mac.type >= e1000_82576)
+               netdev->features |= NETIF_F_SCTP_CRC;
+
        /* copy netdev features into list of user selectable features */
        netdev->hw_features |= netdev->features;
        netdev->hw_features |= NETIF_F_RXALL;
 
+       if (hw->mac.type >= e1000_i350)
+               netdev->hw_features |= NETIF_F_NTUPLE;
+
        /* set this bit last since it cannot be part of hw_features */
        netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
-       netdev->vlan_features |= NETIF_F_TSO |
+       netdev->vlan_features |= NETIF_F_SG |
+                                NETIF_F_TSO |
                                 NETIF_F_TSO6 |
-                                NETIF_F_IP_CSUM |
-                                NETIF_F_IPV6_CSUM |
-                                NETIF_F_SG;
+                                NETIF_F_HW_CSUM |
+                                NETIF_F_SCTP_CRC;
+
+       netdev->mpls_features |= NETIF_F_HW_CSUM;
+       netdev->hw_enc_features |= NETIF_F_HW_CSUM;
 
        netdev->priv_flags |= IFF_SUPP_NOFCS;
 
@@ -2378,11 +2409,6 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
 
-       if (hw->mac.type >= e1000_82576) {
-               netdev->hw_features |= NETIF_F_SCTP_CRC;
-               netdev->features |= NETIF_F_SCTP_CRC;
-       }
-
        netdev->priv_flags |= IFF_UNICAST_FLT;
 
        adapter->en_mng_pt = igb_enable_mng_pass_thru(hw);
@@ -2515,6 +2541,26 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                adapter->wol = 0;
        }
 
+       /* Some vendors want the ability to Use the EEPROM setting as
+        * enable/disable only, and not for capability
+        */
+       if (((hw->mac.type == e1000_i350) ||
+            (hw->mac.type == e1000_i354)) &&
+           (pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)) {
+               adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+               adapter->wol = 0;
+       }
+       if (hw->mac.type == e1000_i350) {
+               if (((pdev->subsystem_device == 0x5001) ||
+                    (pdev->subsystem_device == 0x5002)) &&
+                               (hw->bus.func == 0)) {
+                       adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+                       adapter->wol = 0;
+               }
+               if (pdev->subsystem_device == 0x1F52)
+                       adapter->flags |= IGB_FLAG_WOL_SUPPORTED;
+       }
+
        device_set_wakeup_enable(&adapter->pdev->dev,
                                 adapter->flags & IGB_FLAG_WOL_SUPPORTED);
 
@@ -2921,14 +2967,6 @@ void igb_set_flag_queue_pairs(struct igb_adapter *adapter,
                /* Device supports enough interrupts without queue pairing. */
                break;
        case e1000_82576:
-               /* If VFs are going to be allocated with RSS queues then we
-                * should pair the queues in order to conserve interrupts due
-                * to limited supply.
-                */
-               if ((adapter->rss_queues > 1) &&
-                   (adapter->vfs_allocated_count > 6))
-                       adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
-               /* fall through */
        case e1000_82580:
        case e1000_i350:
        case e1000_i354:
@@ -2939,6 +2977,8 @@ void igb_set_flag_queue_pairs(struct igb_adapter *adapter,
                 */
                if (adapter->rss_queues > (max_rss_queues / 2))
                        adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
+               else
+                       adapter->flags &= ~IGB_FLAG_QUEUE_PAIRS;
                break;
        }
 }
@@ -3132,7 +3172,7 @@ err_setup_tx:
        return err;
 }
 
-static int igb_open(struct net_device *netdev)
+int igb_open(struct net_device *netdev)
 {
        return __igb_open(netdev, false);
 }
@@ -3169,7 +3209,7 @@ static int __igb_close(struct net_device *netdev, bool suspending)
        return 0;
 }
 
-static int igb_close(struct net_device *netdev)
+int igb_close(struct net_device *netdev)
 {
        return __igb_close(netdev, false);
 }
@@ -3460,12 +3500,12 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
                        wr32(E1000_VT_CTL, vtctl);
                }
                if (adapter->rss_queues > 1)
-                       mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
+                       mrqc |= E1000_MRQC_ENABLE_VMDQ_RSS_MQ;
                else
                        mrqc |= E1000_MRQC_ENABLE_VMDQ;
        } else {
                if (hw->mac.type != e1000_i211)
-                       mrqc |= E1000_MRQC_ENABLE_RSS_4Q;
+                       mrqc |= E1000_MRQC_ENABLE_RSS_MQ;
        }
        igb_vmm_control(adapter);
 
@@ -3498,7 +3538,7 @@ void igb_setup_rctl(struct igb_adapter *adapter)
        /* disable store bad packets and clear size bits. */
        rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_SZ_256);
 
-       /* enable LPE to prevent packets larger than max_frame_size */
+       /* enable LPE to allow for reception of jumbo frames */
        rctl |= E1000_RCTL_LPE;
 
        /* disable queue 0 to prevent tail write w/o re-config */
@@ -3522,8 +3562,7 @@ void igb_setup_rctl(struct igb_adapter *adapter)
                         E1000_RCTL_BAM | /* RX All Bcast Pkts */
                         E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
 
-               rctl &= ~(E1000_RCTL_VFE | /* Disable VLAN filter */
-                         E1000_RCTL_DPF | /* Allow filtered pause */
+               rctl &= ~(E1000_RCTL_DPF | /* Allow filtered pause */
                          E1000_RCTL_CFIEN); /* Dis VLAN CFIEN Filter */
                /* Do not mess with E1000_CTRL_VME, it affects transmit as well,
                 * and that breaks VLANs.
@@ -3539,12 +3578,8 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
        struct e1000_hw *hw = &adapter->hw;
        u32 vmolr;
 
-       /* if it isn't the PF check to see if VFs are enabled and
-        * increase the size to support vlan tags
-        */
-       if (vfn < adapter->vfs_allocated_count &&
-           adapter->vf_data[vfn].vlans_enabled)
-               size += VLAN_TAG_SIZE;
+       if (size > MAX_JUMBO_FRAME_SIZE)
+               size = MAX_JUMBO_FRAME_SIZE;
 
        vmolr = rd32(E1000_VMOLR(vfn));
        vmolr &= ~E1000_VMOLR_RLPML_MASK;
@@ -3554,30 +3589,26 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
        return 0;
 }
 
-/**
- *  igb_rlpml_set - set maximum receive packet size
- *  @adapter: board private structure
- *
- *  Configure maximum receivable packet size.
- **/
-static void igb_rlpml_set(struct igb_adapter *adapter)
+static inline void igb_set_vf_vlan_strip(struct igb_adapter *adapter,
+                                        int vfn, bool enable)
 {
-       u32 max_frame_size = adapter->max_frame_size;
        struct e1000_hw *hw = &adapter->hw;
-       u16 pf_id = adapter->vfs_allocated_count;
+       u32 val, reg;
 
-       if (pf_id) {
-               igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
-               /* If we're in VMDQ or SR-IOV mode, then set global RLPML
-                * to our max jumbo frame size, in case we need to enable
-                * jumbo frames on one of the rings later.
-                * This will not pass over-length frames into the default
-                * queue because it's gated by the VMOLR.RLPML.
-                */
-               max_frame_size = MAX_JUMBO_FRAME_SIZE;
-       }
+       if (hw->mac.type < e1000_82576)
+               return;
 
-       wr32(E1000_RLPML, max_frame_size);
+       if (hw->mac.type == e1000_i350)
+               reg = E1000_DVMOLR(vfn);
+       else
+               reg = E1000_VMOLR(vfn);
+
+       val = rd32(reg);
+       if (enable)
+               val |= E1000_VMOLR_STRVLAN;
+       else
+               val &= ~(E1000_VMOLR_STRVLAN);
+       wr32(reg, val);
 }
 
 static inline void igb_set_vmolr(struct igb_adapter *adapter,
@@ -3593,14 +3624,6 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
                return;
 
        vmolr = rd32(E1000_VMOLR(vfn));
-       vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
-       if (hw->mac.type == e1000_i350) {
-               u32 dvmolr;
-
-               dvmolr = rd32(E1000_DVMOLR(vfn));
-               dvmolr |= E1000_DVMOLR_STRVLAN;
-               wr32(E1000_DVMOLR(vfn), dvmolr);
-       }
        if (aupe)
                vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
        else
@@ -3684,9 +3707,6 @@ static void igb_configure_rx(struct igb_adapter *adapter)
 {
        int i;
 
-       /* set UTA to appropriate mode */
-       igb_set_uta(adapter);
-
        /* set the correct pool for the PF default MAC address in entry 0 */
        igb_rar_set_qsel(adapter, adapter->hw.mac.addr, 0,
                         adapter->vfs_allocated_count);
@@ -4004,6 +4024,130 @@ static int igb_write_uc_addr_list(struct net_device *netdev)
        return count;
 }
 
+static int igb_vlan_promisc_enable(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 i, pf_id;
+
+       switch (hw->mac.type) {
+       case e1000_i210:
+       case e1000_i211:
+       case e1000_i350:
+               /* VLAN filtering needed for VLAN prio filter */
+               if (adapter->netdev->features & NETIF_F_NTUPLE)
+                       break;
+               /* fall through */
+       case e1000_82576:
+       case e1000_82580:
+       case e1000_i354:
+               /* VLAN filtering needed for pool filtering */
+               if (adapter->vfs_allocated_count)
+                       break;
+               /* fall through */
+       default:
+               return 1;
+       }
+
+       /* We are already in VLAN promisc, nothing to do */
+       if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+               return 0;
+
+       if (!adapter->vfs_allocated_count)
+               goto set_vfta;
+
+       /* Add PF to all active pools */
+       pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+
+       for (i = E1000_VLVF_ARRAY_SIZE; --i;) {
+               u32 vlvf = rd32(E1000_VLVF(i));
+
+               vlvf |= 1 << pf_id;
+               wr32(E1000_VLVF(i), vlvf);
+       }
+
+set_vfta:
+       /* Set all bits in the VLAN filter table array */
+       for (i = E1000_VLAN_FILTER_TBL_SIZE; i--;)
+               hw->mac.ops.write_vfta(hw, i, ~0U);
+
+       /* Set flag so we don't redo unnecessary work */
+       adapter->flags |= IGB_FLAG_VLAN_PROMISC;
+
+       return 0;
+}
+
+#define VFTA_BLOCK_SIZE 8
+static void igb_scrub_vfta(struct igb_adapter *adapter, u32 vfta_offset)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vfta[VFTA_BLOCK_SIZE] = { 0 };
+       u32 vid_start = vfta_offset * 32;
+       u32 vid_end = vid_start + (VFTA_BLOCK_SIZE * 32);
+       u32 i, vid, word, bits, pf_id;
+
+       /* guarantee that we don't scrub out management VLAN */
+       vid = adapter->mng_vlan_id;
+       if (vid >= vid_start && vid < vid_end)
+               vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
+
+       if (!adapter->vfs_allocated_count)
+               goto set_vfta;
+
+       pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+
+       for (i = E1000_VLVF_ARRAY_SIZE; --i;) {
+               u32 vlvf = rd32(E1000_VLVF(i));
+
+               /* pull VLAN ID from VLVF */
+               vid = vlvf & VLAN_VID_MASK;
+
+               /* only concern ourselves with a certain range */
+               if (vid < vid_start || vid >= vid_end)
+                       continue;
+
+               if (vlvf & E1000_VLVF_VLANID_ENABLE) {
+                       /* record VLAN ID in VFTA */
+                       vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
+
+                       /* if PF is part of this then continue */
+                       if (test_bit(vid, adapter->active_vlans))
+                               continue;
+               }
+
+               /* remove PF from the pool */
+               bits = ~(1 << pf_id);
+               bits &= rd32(E1000_VLVF(i));
+               wr32(E1000_VLVF(i), bits);
+       }
+
+set_vfta:
+       /* extract values from active_vlans and write back to VFTA */
+       for (i = VFTA_BLOCK_SIZE; i--;) {
+               vid = (vfta_offset + i) * 32;
+               word = vid / BITS_PER_LONG;
+               bits = vid % BITS_PER_LONG;
+
+               vfta[i] |= adapter->active_vlans[word] >> bits;
+
+               hw->mac.ops.write_vfta(hw, vfta_offset + i, vfta[i]);
+       }
+}
+
+static void igb_vlan_promisc_disable(struct igb_adapter *adapter)
+{
+       u32 i;
+
+       /* We are not in VLAN promisc, nothing to do */
+       if (!(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+               return;
+
+       /* Set flag so we don't redo unnecessary work */
+       adapter->flags &= ~IGB_FLAG_VLAN_PROMISC;
+
+       for (i = 0; i < E1000_VLAN_FILTER_TBL_SIZE; i += VFTA_BLOCK_SIZE)
+               igb_scrub_vfta(adapter, i);
+}
+
 /**
  *  igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
  *  @netdev: network interface device structure
@@ -4018,21 +4162,17 @@ static void igb_set_rx_mode(struct net_device *netdev)
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        unsigned int vfn = adapter->vfs_allocated_count;
-       u32 rctl, vmolr = 0;
+       u32 rctl = 0, vmolr = 0;
        int count;
 
        /* Check for Promiscuous and All Multicast modes */
-       rctl = rd32(E1000_RCTL);
-
-       /* clear the effected bits */
-       rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
-
        if (netdev->flags & IFF_PROMISC) {
-               /* retain VLAN HW filtering if in VT mode */
-               if (adapter->vfs_allocated_count)
-                       rctl |= E1000_RCTL_VFE;
-               rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-               vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
+               rctl |= E1000_RCTL_UPE | E1000_RCTL_MPE;
+               vmolr |= E1000_VMOLR_MPME;
+
+               /* enable use of UTA filter to force packets to default pool */
+               if (hw->mac.type == e1000_82576)
+                       vmolr |= E1000_VMOLR_ROPE;
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
                        rctl |= E1000_RCTL_MPE;
@@ -4050,17 +4190,34 @@ static void igb_set_rx_mode(struct net_device *netdev)
                                vmolr |= E1000_VMOLR_ROMPE;
                        }
                }
-               /* Write addresses to available RAR registers, if there is not
-                * sufficient space to store all the addresses then enable
-                * unicast promiscuous mode
-                */
-               count = igb_write_uc_addr_list(netdev);
-               if (count < 0) {
-                       rctl |= E1000_RCTL_UPE;
-                       vmolr |= E1000_VMOLR_ROPE;
-               }
-               rctl |= E1000_RCTL_VFE;
        }
+
+       /* Write addresses to available RAR registers, if there is not
+        * sufficient space to store all the addresses then enable
+        * unicast promiscuous mode
+        */
+       count = igb_write_uc_addr_list(netdev);
+       if (count < 0) {
+               rctl |= E1000_RCTL_UPE;
+               vmolr |= E1000_VMOLR_ROPE;
+       }
+
+       /* enable VLAN filtering by default */
+       rctl |= E1000_RCTL_VFE;
+
+       /* disable VLAN filtering for modes that require it */
+       if ((netdev->flags & IFF_PROMISC) ||
+           (netdev->features & NETIF_F_RXALL)) {
+               /* if we fail to set all rules then just clear VFE */
+               if (igb_vlan_promisc_enable(adapter))
+                       rctl &= ~E1000_RCTL_VFE;
+       } else {
+               igb_vlan_promisc_disable(adapter);
+       }
+
+       /* update state of unicast, multicast, and VLAN filtering modes */
+       rctl |= rd32(E1000_RCTL) & ~(E1000_RCTL_UPE | E1000_RCTL_MPE |
+                                    E1000_RCTL_VFE);
        wr32(E1000_RCTL, rctl);
 
        /* In order to support SR-IOV and eventually VMDq it is necessary to set
@@ -4071,9 +4228,19 @@ static void igb_set_rx_mode(struct net_device *netdev)
        if ((hw->mac.type < e1000_82576) || (hw->mac.type > e1000_i350))
                return;
 
+       /* set UTA to appropriate mode */
+       igb_set_uta(adapter, !!(vmolr & E1000_VMOLR_ROPE));
+
        vmolr |= rd32(E1000_VMOLR(vfn)) &
                 ~(E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_ROMPE);
+
+       /* enable Rx jumbo frames, no need for restriction */
+       vmolr &= ~E1000_VMOLR_RLPML_MASK;
+       vmolr |= MAX_JUMBO_FRAME_SIZE | E1000_VMOLR_LPE;
+
        wr32(E1000_VMOLR(vfn), vmolr);
+       wr32(E1000_RLPML, MAX_JUMBO_FRAME_SIZE);
+
        igb_restore_vf_multicasts(adapter);
 }
 
@@ -4227,6 +4394,7 @@ static void igb_watchdog_task(struct work_struct *work)
        u32 link;
        int i;
        u32 connsw;
+       u16 phy_data, retry_count = 20;
 
        link = igb_has_link(adapter);
 
@@ -4305,6 +4473,25 @@ static void igb_watchdog_task(struct work_struct *work)
                                break;
                        }
 
+                       if (adapter->link_speed != SPEED_1000)
+                               goto no_wait;
+
+                       /* wait for Remote receiver status OK */
+retry_read_status:
+                       if (!igb_read_phy_reg(hw, PHY_1000T_STATUS,
+                                             &phy_data)) {
+                               if (!(phy_data & SR_1000T_REMOTE_RX_STATUS) &&
+                                   retry_count) {
+                                       msleep(100);
+                                       retry_count--;
+                                       goto retry_read_status;
+                               } else if (!retry_count) {
+                                       dev_err(&adapter->pdev->dev, "exceed max 2 second\n");
+                               }
+                       } else {
+                               dev_err(&adapter->pdev->dev, "read 1000Base-T Status Reg\n");
+                       }
+no_wait:
                        netif_carrier_on(netdev);
 
                        igb_ping_all_vfs(adapter);
@@ -4713,70 +4900,57 @@ static int igb_tso(struct igb_ring *tx_ring,
        return 1;
 }
 
+static inline bool igb_ipv6_csum_is_sctp(struct sk_buff *skb)
+{
+       unsigned int offset = 0;
+
+       ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
+
+       return offset == skb_checksum_start_offset(skb);
+}
+
 static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
 {
        struct sk_buff *skb = first->skb;
        u32 vlan_macip_lens = 0;
-       u32 mss_l4len_idx = 0;
        u32 type_tucmd = 0;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
                if (!(first->tx_flags & IGB_TX_FLAGS_VLAN))
                        return;
-       } else {
-               u8 l4_hdr = 0;
-
-               switch (first->protocol) {
-               case htons(ETH_P_IP):
-                       vlan_macip_lens |= skb_network_header_len(skb);
-                       type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
-                       l4_hdr = ip_hdr(skb)->protocol;
-                       break;
-               case htons(ETH_P_IPV6):
-                       vlan_macip_lens |= skb_network_header_len(skb);
-                       l4_hdr = ipv6_hdr(skb)->nexthdr;
-                       break;
-               default:
-                       if (unlikely(net_ratelimit())) {
-                               dev_warn(tx_ring->dev,
-                                        "partial checksum but proto=%x!\n",
-                                        first->protocol);
-                       }
-                       break;
-               }
+               goto no_csum;
+       }
 
-               switch (l4_hdr) {
-               case IPPROTO_TCP:
-                       type_tucmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                       mss_l4len_idx = tcp_hdrlen(skb) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               case IPPROTO_SCTP:
-                       type_tucmd |= E1000_ADVTXD_TUCMD_L4T_SCTP;
-                       mss_l4len_idx = sizeof(struct sctphdr) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               case IPPROTO_UDP:
-                       mss_l4len_idx = sizeof(struct udphdr) <<
-                                       E1000_ADVTXD_L4LEN_SHIFT;
-                       break;
-               default:
-                       if (unlikely(net_ratelimit())) {
-                               dev_warn(tx_ring->dev,
-                                        "partial checksum but l4 proto=%x!\n",
-                                        l4_hdr);
-                       }
+       switch (skb->csum_offset) {
+       case offsetof(struct tcphdr, check):
+               type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+               /* fall through */
+       case offsetof(struct udphdr, check):
+               break;
+       case offsetof(struct sctphdr, checksum):
+               /* validate that this is actually an SCTP request */
+               if (((first->protocol == htons(ETH_P_IP)) &&
+                    (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+                   ((first->protocol == htons(ETH_P_IPV6)) &&
+                    igb_ipv6_csum_is_sctp(skb))) {
+                       type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
                        break;
                }
-
-               /* update TX checksum flag */
-               first->tx_flags |= IGB_TX_FLAGS_CSUM;
+       default:
+               skb_checksum_help(skb);
+               goto csum_failed;
        }
 
+       /* update TX checksum flag */
+       first->tx_flags |= IGB_TX_FLAGS_CSUM;
+       vlan_macip_lens = skb_checksum_start_offset(skb) -
+                         skb_network_offset(skb);
+no_csum:
        vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
        vlan_macip_lens |= first->tx_flags & IGB_TX_FLAGS_VLAN_MASK;
 
-       igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, mss_l4len_idx);
+       igb_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
 }
 
 #define IGB_SET_FLAG(_input, _flag, _result) \
@@ -5088,16 +5262,6 @@ static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
 
-       if (test_bit(__IGB_DOWN, &adapter->state)) {
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
-       }
-
-       if (skb->len <= 0) {
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
-       }
-
        /* The minimum packet size with TCTL.PSP set is 17 so pad the skb
         * in order to meet this minimum size requirement.
         */
@@ -5792,125 +5956,132 @@ static void igb_restore_vf_multicasts(struct igb_adapter *adapter)
 static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 pool_mask, reg, vid;
-       int i;
+       u32 pool_mask, vlvf_mask, i;
 
-       pool_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+       /* create mask for VF and other pools */
+       pool_mask = E1000_VLVF_POOLSEL_MASK;
+       vlvf_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+
+       /* drop PF from pool bits */
+       pool_mask &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT +
+                            adapter->vfs_allocated_count));
 
        /* Find the vlan filter for this id */
-       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-               reg = rd32(E1000_VLVF(i));
+       for (i = E1000_VLVF_ARRAY_SIZE; i--;) {
+               u32 vlvf = rd32(E1000_VLVF(i));
+               u32 vfta_mask, vid, vfta;
 
                /* remove the vf from the pool */
-               reg &= ~pool_mask;
-
-               /* if pool is empty then remove entry from vfta */
-               if (!(reg & E1000_VLVF_POOLSEL_MASK) &&
-                   (reg & E1000_VLVF_VLANID_ENABLE)) {
-                       reg = 0;
-                       vid = reg & E1000_VLVF_VLANID_MASK;
-                       igb_vfta_set(hw, vid, false);
-               }
+               if (!(vlvf & vlvf_mask))
+                       continue;
+
+               /* clear out bit from VLVF */
+               vlvf ^= vlvf_mask;
+
+               /* if other pools are present, just remove ourselves */
+               if (vlvf & pool_mask)
+                       goto update_vlvfb;
 
-               wr32(E1000_VLVF(i), reg);
+               /* if PF is present, leave VFTA */
+               if (vlvf & E1000_VLVF_POOLSEL_MASK)
+                       goto update_vlvf;
+
+               vid = vlvf & E1000_VLVF_VLANID_MASK;
+               vfta_mask = 1 << (vid % 32);
+
+               /* clear bit from VFTA */
+               vfta = adapter->shadow_vfta[vid / 32];
+               if (vfta & vfta_mask)
+                       hw->mac.ops.write_vfta(hw, vid / 32, vfta ^ vfta_mask);
+update_vlvf:
+               /* clear pool selection enable */
+               if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+                       vlvf &= E1000_VLVF_POOLSEL_MASK;
+               else
+                       vlvf = 0;
+update_vlvfb:
+               /* clear pool bits */
+               wr32(E1000_VLVF(i), vlvf);
        }
+}
 
-       adapter->vf_data[vf].vlans_enabled = 0;
+static int igb_find_vlvf_entry(struct e1000_hw *hw, u32 vlan)
+{
+       u32 vlvf;
+       int idx;
+
+       /* short cut the special case */
+       if (vlan == 0)
+               return 0;
+
+       /* Search for the VLAN id in the VLVF entries */
+       for (idx = E1000_VLVF_ARRAY_SIZE; --idx;) {
+               vlvf = rd32(E1000_VLVF(idx));
+               if ((vlvf & VLAN_VID_MASK) == vlan)
+                       break;
+       }
+
+       return idx;
 }
 
-static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
+void igb_update_pf_vlvf(struct igb_adapter *adapter, u32 vid)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 reg, i;
-
-       /* The vlvf table only exists on 82576 hardware and newer */
-       if (hw->mac.type < e1000_82576)
-               return -1;
+       u32 bits, pf_id;
+       int idx;
 
-       /* we only need to do this if VMDq is enabled */
-       if (!adapter->vfs_allocated_count)
-               return -1;
+       idx = igb_find_vlvf_entry(hw, vid);
+       if (!idx)
+               return;
 
-       /* Find the vlan filter for this id */
-       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-               reg = rd32(E1000_VLVF(i));
-               if ((reg & E1000_VLVF_VLANID_ENABLE) &&
-                   vid == (reg & E1000_VLVF_VLANID_MASK))
-                       break;
+       /* See if any other pools are set for this VLAN filter
+        * entry other than the PF.
+        */
+       pf_id = adapter->vfs_allocated_count + E1000_VLVF_POOLSEL_SHIFT;
+       bits = ~(1 << pf_id) & E1000_VLVF_POOLSEL_MASK;
+       bits &= rd32(E1000_VLVF(idx));
+
+       /* Disable the filter so this falls into the default pool. */
+       if (!bits) {
+               if (adapter->flags & IGB_FLAG_VLAN_PROMISC)
+                       wr32(E1000_VLVF(idx), 1 << pf_id);
+               else
+                       wr32(E1000_VLVF(idx), 0);
        }
+}
 
-       if (add) {
-               if (i == E1000_VLVF_ARRAY_SIZE) {
-                       /* Did not find a matching VLAN ID entry that was
-                        * enabled.  Search for a free filter entry, i.e.
-                        * one without the enable bit set
-                        */
-                       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-                               reg = rd32(E1000_VLVF(i));
-                               if (!(reg & E1000_VLVF_VLANID_ENABLE))
-                                       break;
-                       }
-               }
-               if (i < E1000_VLVF_ARRAY_SIZE) {
-                       /* Found an enabled/available entry */
-                       reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
-
-                       /* if !enabled we need to set this up in vfta */
-                       if (!(reg & E1000_VLVF_VLANID_ENABLE)) {
-                               /* add VID to filter table */
-                               igb_vfta_set(hw, vid, true);
-                               reg |= E1000_VLVF_VLANID_ENABLE;
-                       }
-                       reg &= ~E1000_VLVF_VLANID_MASK;
-                       reg |= vid;
-                       wr32(E1000_VLVF(i), reg);
-
-                       /* do not modify RLPML for PF devices */
-                       if (vf >= adapter->vfs_allocated_count)
-                               return 0;
-
-                       if (!adapter->vf_data[vf].vlans_enabled) {
-                               u32 size;
-
-                               reg = rd32(E1000_VMOLR(vf));
-                               size = reg & E1000_VMOLR_RLPML_MASK;
-                               size += 4;
-                               reg &= ~E1000_VMOLR_RLPML_MASK;
-                               reg |= size;
-                               wr32(E1000_VMOLR(vf), reg);
-                       }
+static s32 igb_set_vf_vlan(struct igb_adapter *adapter, u32 vid,
+                          bool add, u32 vf)
+{
+       int pf_id = adapter->vfs_allocated_count;
+       struct e1000_hw *hw = &adapter->hw;
+       int err;
 
-                       adapter->vf_data[vf].vlans_enabled++;
-               }
-       } else {
-               if (i < E1000_VLVF_ARRAY_SIZE) {
-                       /* remove vf from the pool */
-                       reg &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT + vf));
-                       /* if pool is empty then remove entry from vfta */
-                       if (!(reg & E1000_VLVF_POOLSEL_MASK)) {
-                               reg = 0;
-                               igb_vfta_set(hw, vid, false);
-                       }
-                       wr32(E1000_VLVF(i), reg);
-
-                       /* do not modify RLPML for PF devices */
-                       if (vf >= adapter->vfs_allocated_count)
-                               return 0;
-
-                       adapter->vf_data[vf].vlans_enabled--;
-                       if (!adapter->vf_data[vf].vlans_enabled) {
-                               u32 size;
-
-                               reg = rd32(E1000_VMOLR(vf));
-                               size = reg & E1000_VMOLR_RLPML_MASK;
-                               size -= 4;
-                               reg &= ~E1000_VMOLR_RLPML_MASK;
-                               reg |= size;
-                               wr32(E1000_VMOLR(vf), reg);
-                       }
-               }
+       /* If VLAN overlaps with one the PF is currently monitoring make
+        * sure that we are able to allocate a VLVF entry.  This may be
+        * redundant but it guarantees PF will maintain visibility to
+        * the VLAN.
+        */
+       if (add && test_bit(vid, adapter->active_vlans)) {
+               err = igb_vfta_set(hw, vid, pf_id, true, false);
+               if (err)
+                       return err;
        }
-       return 0;
+
+       err = igb_vfta_set(hw, vid, vf, add, false);
+
+       if (add && !err)
+               return err;
+
+       /* If we failed to add the VF VLAN or we are removing the VF VLAN
+        * we may need to drop the PF pool bit in order to allow us to free
+        * up the VLVF resources.
+        */
+       if (test_bit(vid, adapter->active_vlans) ||
+           (adapter->flags & IGB_FLAG_VLAN_PROMISC))
+               igb_update_pf_vlvf(adapter, vid);
+
+       return err;
 }
 
 static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
@@ -5923,130 +6094,104 @@ static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
                wr32(E1000_VMVIR(vf), 0);
 }
 
-static int igb_ndo_set_vf_vlan(struct net_device *netdev,
-                              int vf, u16 vlan, u8 qos)
+static int igb_enable_port_vlan(struct igb_adapter *adapter, int vf,
+                               u16 vlan, u8 qos)
 {
-       int err = 0;
-       struct igb_adapter *adapter = netdev_priv(netdev);
+       int err;
 
-       if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
-               return -EINVAL;
-       if (vlan || qos) {
-               err = igb_vlvf_set(adapter, vlan, !!vlan, vf);
-               if (err)
-                       goto out;
-               igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
-               igb_set_vmolr(adapter, vf, !vlan);
-               adapter->vf_data[vf].pf_vlan = vlan;
-               adapter->vf_data[vf].pf_qos = qos;
-               dev_info(&adapter->pdev->dev,
-                        "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
-               if (test_bit(__IGB_DOWN, &adapter->state)) {
-                       dev_warn(&adapter->pdev->dev,
-                                "The VF VLAN has been set, but the PF device is not up.\n");
-                       dev_warn(&adapter->pdev->dev,
-                                "Bring the PF device up before attempting to use the VF device.\n");
-               }
-       } else {
-               igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
-                            false, vf);
-               igb_set_vmvir(adapter, vlan, vf);
-               igb_set_vmolr(adapter, vf, true);
-               adapter->vf_data[vf].pf_vlan = 0;
-               adapter->vf_data[vf].pf_qos = 0;
+       err = igb_set_vf_vlan(adapter, vlan, true, vf);
+       if (err)
+               return err;
+
+       igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+       igb_set_vmolr(adapter, vf, !vlan);
+
+       /* revoke access to previous VLAN */
+       if (vlan != adapter->vf_data[vf].pf_vlan)
+               igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
+                               false, vf);
+
+       adapter->vf_data[vf].pf_vlan = vlan;
+       adapter->vf_data[vf].pf_qos = qos;
+       igb_set_vf_vlan_strip(adapter, vf, true);
+       dev_info(&adapter->pdev->dev,
+                "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+       if (test_bit(__IGB_DOWN, &adapter->state)) {
+               dev_warn(&adapter->pdev->dev,
+                        "The VF VLAN has been set, but the PF device is not up.\n");
+               dev_warn(&adapter->pdev->dev,
+                        "Bring the PF device up before attempting to use the VF device.\n");
        }
-out:
+
        return err;
 }
 
-static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
+static int igb_disable_port_vlan(struct igb_adapter *adapter, int vf)
 {
-       struct e1000_hw *hw = &adapter->hw;
-       int i;
-       u32 reg;
+       /* Restore tagless access via VLAN 0 */
+       igb_set_vf_vlan(adapter, 0, true, vf);
 
-       /* Find the vlan filter for this id */
-       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
-               reg = rd32(E1000_VLVF(i));
-               if ((reg & E1000_VLVF_VLANID_ENABLE) &&
-                   vid == (reg & E1000_VLVF_VLANID_MASK))
-                       break;
-       }
+       igb_set_vmvir(adapter, 0, vf);
+       igb_set_vmolr(adapter, vf, true);
+
+       /* Remove any PF assigned VLAN */
+       if (adapter->vf_data[vf].pf_vlan)
+               igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
+                               false, vf);
 
-       if (i >= E1000_VLVF_ARRAY_SIZE)
-               i = -1;
+       adapter->vf_data[vf].pf_vlan = 0;
+       adapter->vf_data[vf].pf_qos = 0;
+       igb_set_vf_vlan_strip(adapter, vf, false);
 
-       return i;
+       return 0;
 }
 
-static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
+static int igb_ndo_set_vf_vlan(struct net_device *netdev,
+                              int vf, u16 vlan, u8 qos)
 {
-       struct e1000_hw *hw = &adapter->hw;
-       int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
-       int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
-       int err = 0;
+       struct igb_adapter *adapter = netdev_priv(netdev);
 
-       /* If in promiscuous mode we need to make sure the PF also has
-        * the VLAN filter set.
-        */
-       if (add && (adapter->netdev->flags & IFF_PROMISC))
-               err = igb_vlvf_set(adapter, vid, add,
-                                  adapter->vfs_allocated_count);
-       if (err)
-               goto out;
+       if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
+               return -EINVAL;
 
-       err = igb_vlvf_set(adapter, vid, add, vf);
+       return (vlan || qos) ? igb_enable_port_vlan(adapter, vf, vlan, qos) :
+                              igb_disable_port_vlan(adapter, vf);
+}
 
-       if (err)
-               goto out;
+static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
+{
+       int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+       int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
+       int ret;
 
-       /* Go through all the checks to see if the VLAN filter should
-        * be wiped completely.
-        */
-       if (!add && (adapter->netdev->flags & IFF_PROMISC)) {
-               u32 vlvf, bits;
-               int regndx = igb_find_vlvf_entry(adapter, vid);
-
-               if (regndx < 0)
-                       goto out;
-               /* See if any other pools are set for this VLAN filter
-                * entry other than the PF.
-                */
-               vlvf = bits = rd32(E1000_VLVF(regndx));
-               bits &= 1 << (E1000_VLVF_POOLSEL_SHIFT +
-                             adapter->vfs_allocated_count);
-               /* If the filter was removed then ensure PF pool bit
-                * is cleared if the PF only added itself to the pool
-                * because the PF is in promiscuous mode.
-                */
-               if ((vlvf & VLAN_VID_MASK) == vid &&
-                   !test_bit(vid, adapter->active_vlans) &&
-                   !bits)
-                       igb_vlvf_set(adapter, vid, add,
-                                    adapter->vfs_allocated_count);
-       }
+       if (adapter->vf_data[vf].pf_vlan)
+               return -1;
 
-out:
-       return err;
+       /* VLAN 0 is a special case, don't allow it to be removed */
+       if (!vid && !add)
+               return 0;
+
+       ret = igb_set_vf_vlan(adapter, vid, !!add, vf);
+       if (!ret)
+               igb_set_vf_vlan_strip(adapter, vf, !!vid);
+       return ret;
 }
 
 static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
 {
-       /* clear flags - except flag that indicates PF has set the MAC */
-       adapter->vf_data[vf].flags &= IGB_VF_FLAG_PF_SET_MAC;
-       adapter->vf_data[vf].last_nack = jiffies;
+       struct vf_data_storage *vf_data = &adapter->vf_data[vf];
 
-       /* reset offloads to defaults */
-       igb_set_vmolr(adapter, vf, true);
+       /* clear flags - except flag that indicates PF has set the MAC */
+       vf_data->flags &= IGB_VF_FLAG_PF_SET_MAC;
+       vf_data->last_nack = jiffies;
 
        /* reset vlans for device */
        igb_clear_vf_vfta(adapter, vf);
-       if (adapter->vf_data[vf].pf_vlan)
-               igb_ndo_set_vf_vlan(adapter->netdev, vf,
-                                   adapter->vf_data[vf].pf_vlan,
-                                   adapter->vf_data[vf].pf_qos);
-       else
-               igb_clear_vf_vfta(adapter, vf);
+       igb_set_vf_vlan(adapter, vf_data->pf_vlan, true, vf);
+       igb_set_vmvir(adapter, vf_data->pf_vlan |
+                              (vf_data->pf_qos << VLAN_PRIO_SHIFT), vf);
+       igb_set_vmolr(adapter, vf, !vf_data->pf_vlan);
+       igb_set_vf_vlan_strip(adapter, vf, !!(vf_data->pf_vlan));
 
        /* reset multicast table array for vf */
        adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -6191,7 +6336,7 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
                                 "VF %d attempted to override administratively set VLAN tag\nReload the VF driver to resume operations\n",
                                 vf);
                else
-                       retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+                       retval = igb_set_vf_vlan_msg(adapter, msgbuf, vf);
                break;
        default:
                dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
@@ -6233,6 +6378,7 @@ static void igb_msg_task(struct igb_adapter *adapter)
 /**
  *  igb_set_uta - Set unicast filter table address
  *  @adapter: board private structure
+ *  @set: boolean indicating if we are setting or clearing bits
  *
  *  The unicast table address is a register array of 32-bit registers.
  *  The table is meant to be used in a way similar to how the MTA is used
@@ -6240,21 +6386,18 @@ static void igb_msg_task(struct igb_adapter *adapter)
  *  set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous
  *  enable bit to allow vlan tag stripping when promiscuous mode is enabled
  **/
-static void igb_set_uta(struct igb_adapter *adapter)
+static void igb_set_uta(struct igb_adapter *adapter, bool set)
 {
        struct e1000_hw *hw = &adapter->hw;
+       u32 uta = set ? ~0 : 0;
        int i;
 
-       /* The UTA table only exists on 82576 hardware and newer */
-       if (hw->mac.type < e1000_82576)
-               return;
-
        /* we only need to do this if VMDq is enabled */
        if (!adapter->vfs_allocated_count)
                return;
 
-       for (i = 0; i < hw->mac.uta_reg_count; i++)
-               array_wr32(E1000_UTA, i, ~0);
+       for (i = hw->mac.uta_reg_count; i--;)
+               array_wr32(E1000_UTA, i, uta);
 }
 
 /**
@@ -7202,7 +7345,7 @@ static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
                wr32(E1000_CTRL, ctrl);
        }
 
-       igb_rlpml_set(adapter);
+       igb_set_vf_vlan_strip(adapter, adapter->vfs_allocated_count, enable);
 }
 
 static int igb_vlan_rx_add_vid(struct net_device *netdev,
@@ -7212,11 +7355,9 @@ static int igb_vlan_rx_add_vid(struct net_device *netdev,
        struct e1000_hw *hw = &adapter->hw;
        int pf_id = adapter->vfs_allocated_count;
 
-       /* attempt to add filter to vlvf array */
-       igb_vlvf_set(adapter, vid, true, pf_id);
-
        /* add the filter since PF can receive vlans w/o entry in vlvf */
-       igb_vfta_set(hw, vid, true);
+       if (!vid || !(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+               igb_vfta_set(hw, vid, pf_id, true, !!vid);
 
        set_bit(vid, adapter->active_vlans);
 
@@ -7227,16 +7368,12 @@ static int igb_vlan_rx_kill_vid(struct net_device *netdev,
                                __be16 proto, u16 vid)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
-       struct e1000_hw *hw = &adapter->hw;
        int pf_id = adapter->vfs_allocated_count;
-       s32 err;
-
-       /* remove vlan from VLVF table array */
-       err = igb_vlvf_set(adapter, vid, false, pf_id);
+       struct e1000_hw *hw = &adapter->hw;
 
-       /* if vid was not present in VLVF just remove it from table */
-       if (err)
-               igb_vfta_set(hw, vid, false);
+       /* remove VID from filter table */
+       if (vid && !(adapter->flags & IGB_FLAG_VLAN_PROMISC))
+               igb_vfta_set(hw, vid, pf_id, false, true);
 
        clear_bit(vid, adapter->active_vlans);
 
@@ -7245,11 +7382,12 @@ static int igb_vlan_rx_kill_vid(struct net_device *netdev,
 
 static void igb_restore_vlan(struct igb_adapter *adapter)
 {
-       u16 vid;
+       u16 vid = 1;
 
        igb_vlan_mode(adapter->netdev, adapter->netdev->features);
+       igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), 0);
 
-       for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
+       for_each_set_bit_from(vid, adapter->active_vlans, VLAN_N_VID)
                igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
 }
 
@@ -7704,15 +7842,14 @@ static void igb_io_resume(struct pci_dev *pdev)
 static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
                             u8 qsel)
 {
-       u32 rar_low, rar_high;
        struct e1000_hw *hw = &adapter->hw;
+       u32 rar_low, rar_high;
 
        /* HW expects these in little endian so we reverse the byte order
-        * from network order (big endian) to little endian
+        * from network order (big endian) to CPU endian
         */
-       rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
-                  ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
-       rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+       rar_low = le32_to_cpup((__be32 *)(addr));
+       rar_high = le16_to_cpup((__be16 *)(addr + 4));
 
        /* Indicate to hardware the Address is Valid. */
        rar_high |= E1000_RAH_AV;
@@ -7959,9 +8096,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
                         * than the Rx threshold. Set hwm to PBA - max frame
                         * size in 16B units, capping it at PBA - 6KB.
                         */
-                       hwm = 64 * pba - adapter->max_frame_size / 16;
-                       if (hwm < 64 * (pba - 6))
-                               hwm = 64 * (pba - 6);
+                       hwm = 64 * (pba - 6);
                        reg = rd32(E1000_FCRTC);
                        reg &= ~E1000_FCRTC_RTH_COAL_MASK;
                        reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
@@ -7971,9 +8106,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
                        /* Set the DMA Coalescing Rx threshold to PBA - 2 * max
                         * frame size, capping it at PBA - 10KB.
                         */
-                       dmac_thr = pba - adapter->max_frame_size / 512;
-                       if (dmac_thr < pba - 10)
-                               dmac_thr = pba - 10;
+                       dmac_thr = pba - 10;
                        reg = rd32(E1000_DMACR);
                        reg &= ~E1000_DMACR_DMACTHR_MASK;
                        reg |= ((dmac_thr << E1000_DMACR_DMACTHR_SHIFT)
index c44df87c38de233578c531e13ea7cb9ef211ceb7..22a8a29895b45d324da4311dcfd93650ccd20bbb 100644 (file)
@@ -525,7 +525,8 @@ static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
                ts.tv_nsec = rq->perout.period.nsec;
                ns = timespec64_to_ns(&ts);
                ns = ns >> 1;
-               if (on && ns <= 70000000LL) {
+               if (on && ((ns <= 70000000LL) || (ns == 125000000LL) ||
+                          (ns == 250000000LL) || (ns == 500000000LL))) {
                        if (ns < 8LL)
                                return -EINVAL;
                        use_freq = 1;
index 7b6cb4c3764caff0432a543080d9d05d766bf475..01752f44ace2a0515a1c6ef35b900a32c719f07c 100644 (file)
@@ -234,13 +234,19 @@ static s32 e1000_check_for_rst_vf(struct e1000_hw *hw)
 static s32 e1000_obtain_mbx_lock_vf(struct e1000_hw *hw)
 {
        s32 ret_val = -E1000_ERR_MBX;
-
-       /* Take ownership of the buffer */
-       ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
-
-       /* reserve mailbox for VF use */
-       if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU)
-               ret_val = E1000_SUCCESS;
+       int count = 10;
+
+       do {
+               /* Take ownership of the buffer */
+               ew32(V2PMAILBOX(0), E1000_V2PMAILBOX_VFU);
+
+               /* reserve mailbox for VF use */
+               if (e1000_read_v2p_mailbox(hw) & E1000_V2PMAILBOX_VFU) {
+                       ret_val = 0;
+                       break;
+               }
+               udelay(1000);
+       } while (count-- > 0);
 
        return ret_val;
 }
index 297af801f0519136eb1fe0f69a50a746e84c06b8..c12442252adbd0bdf76c1a1aa5394a796b37d0de 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/prefetch.h>
+#include <linux/sctp.h>
 
 #include "igbvf.h"
 
@@ -876,7 +877,6 @@ static irqreturn_t igbvf_msix_other(int irq, void *data)
 
        adapter->int_counter1++;
 
-       netif_carrier_off(netdev);
        hw->mac.get_link_status = 1;
        if (!test_bit(__IGBVF_DOWN, &adapter->state))
                mod_timer(&adapter->watchdog_timer, jiffies + 1);
@@ -1908,6 +1908,31 @@ static void igbvf_watchdog_task(struct work_struct *work)
 #define IGBVF_TX_FLAGS_VLAN_MASK       0xffff0000
 #define IGBVF_TX_FLAGS_VLAN_SHIFT      16
 
+static void igbvf_tx_ctxtdesc(struct igbvf_ring *tx_ring, u32 vlan_macip_lens,
+                             u32 type_tucmd, u32 mss_l4len_idx)
+{
+       struct e1000_adv_tx_context_desc *context_desc;
+       struct igbvf_buffer *buffer_info;
+       u16 i = tx_ring->next_to_use;
+
+       context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+       buffer_info = &tx_ring->buffer_info[i];
+
+       i++;
+       tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
+
+       /* set bits to identify this as an advanced context descriptor */
+       type_tucmd |= E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT;
+
+       context_desc->vlan_macip_lens   = cpu_to_le32(vlan_macip_lens);
+       context_desc->seqnum_seed       = 0;
+       context_desc->type_tucmd_mlhl   = cpu_to_le32(type_tucmd);
+       context_desc->mss_l4len_idx     = cpu_to_le32(mss_l4len_idx);
+
+       buffer_info->time_stamp = jiffies;
+       buffer_info->dma = 0;
+}
+
 static int igbvf_tso(struct igbvf_adapter *adapter,
                     struct igbvf_ring *tx_ring,
                     struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
@@ -1987,65 +2012,56 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
        return true;
 }
 
-static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
-                                struct igbvf_ring *tx_ring,
-                                struct sk_buff *skb, u32 tx_flags,
-                                __be16 protocol)
+static inline bool igbvf_ipv6_csum_is_sctp(struct sk_buff *skb)
 {
-       struct e1000_adv_tx_context_desc *context_desc;
-       unsigned int i;
-       struct igbvf_buffer *buffer_info;
-       u32 info = 0, tu_cmd = 0;
-
-       if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
-           (tx_flags & IGBVF_TX_FLAGS_VLAN)) {
-               i = tx_ring->next_to_use;
-               buffer_info = &tx_ring->buffer_info[i];
-               context_desc = IGBVF_TX_CTXTDESC_ADV(*tx_ring, i);
+       unsigned int offset = 0;
 
-               if (tx_flags & IGBVF_TX_FLAGS_VLAN)
-                       info |= (tx_flags & IGBVF_TX_FLAGS_VLAN_MASK);
+       ipv6_find_hdr(skb, &offset, IPPROTO_SCTP, NULL, NULL);
 
-               info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
-               if (skb->ip_summed == CHECKSUM_PARTIAL)
-                       info |= (skb_transport_header(skb) -
-                                skb_network_header(skb));
+       return offset == skb_checksum_start_offset(skb);
+}
 
-               context_desc->vlan_macip_lens = cpu_to_le32(info);
+static bool igbvf_tx_csum(struct igbvf_ring *tx_ring, struct sk_buff *skb,
+                         u32 tx_flags, __be16 protocol)
+{
+       u32 vlan_macip_lens = 0;
+       u32 type_tucmd = 0;
 
-               tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+       if (skb->ip_summed != CHECKSUM_PARTIAL) {
+csum_failed:
+               if (!(tx_flags & IGBVF_TX_FLAGS_VLAN))
+                       return false;
+               goto no_csum;
+       }
 
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       switch (protocol) {
-                       case htons(ETH_P_IP):
-                               tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
-                               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
-                                       tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                               break;
-                       case htons(ETH_P_IPV6):
-                               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
-                                       tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
-                               break;
-                       default:
-                               break;
-                       }
+       switch (skb->csum_offset) {
+       case offsetof(struct tcphdr, check):
+               type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
+               /* fall through */
+       case offsetof(struct udphdr, check):
+               break;
+       case offsetof(struct sctphdr, checksum):
+               /* validate that this is actually an SCTP request */
+               if (((protocol == htons(ETH_P_IP)) &&
+                    (ip_hdr(skb)->protocol == IPPROTO_SCTP)) ||
+                   ((protocol == htons(ETH_P_IPV6)) &&
+                    igbvf_ipv6_csum_is_sctp(skb))) {
+                       type_tucmd = E1000_ADVTXD_TUCMD_L4T_SCTP;
+                       break;
                }
-
-               context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
-               context_desc->seqnum_seed = 0;
-               context_desc->mss_l4len_idx = 0;
-
-               buffer_info->time_stamp = jiffies;
-               buffer_info->dma = 0;
-               i++;
-               if (i == tx_ring->count)
-                       i = 0;
-               tx_ring->next_to_use = i;
-
-               return true;
+       default:
+               skb_checksum_help(skb);
+               goto csum_failed;
        }
 
-       return false;
+       vlan_macip_lens = skb_checksum_start_offset(skb) -
+                         skb_network_offset(skb);
+no_csum:
+       vlan_macip_lens |= skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT;
+       vlan_macip_lens |= tx_flags & IGBVF_TX_FLAGS_VLAN_MASK;
+
+       igbvf_tx_ctxtdesc(tx_ring, vlan_macip_lens, type_tucmd, 0);
+       return true;
 }
 
 static int igbvf_maybe_stop_tx(struct net_device *netdev, int size)
@@ -2264,7 +2280,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
 
        if (tso)
                tx_flags |= IGBVF_TX_FLAGS_TSO;
-       else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) &&
+       else if (igbvf_tx_csum(tx_ring, skb, tx_flags, protocol) &&
                 (skb->ip_summed == CHECKSUM_PARTIAL))
                tx_flags |= IGBVF_TX_FLAGS_CSUM;
 
@@ -2717,11 +2733,11 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->bd_number = cards_found++;
 
        netdev->hw_features = NETIF_F_SG |
-                          NETIF_F_IP_CSUM |
-                          NETIF_F_IPV6_CSUM |
-                          NETIF_F_TSO |
-                          NETIF_F_TSO6 |
-                          NETIF_F_RXCSUM;
+                             NETIF_F_TSO |
+                             NETIF_F_TSO6 |
+                             NETIF_F_RXCSUM |
+                             NETIF_F_HW_CSUM |
+                             NETIF_F_SCTP_CRC;
 
        netdev->features = netdev->hw_features |
                           NETIF_F_HW_VLAN_CTAG_TX |
@@ -2731,11 +2747,14 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
-       netdev->vlan_features |= NETIF_F_TSO;
-       netdev->vlan_features |= NETIF_F_TSO6;
-       netdev->vlan_features |= NETIF_F_IP_CSUM;
-       netdev->vlan_features |= NETIF_F_IPV6_CSUM;
-       netdev->vlan_features |= NETIF_F_SG;
+       netdev->vlan_features |= NETIF_F_SG |
+                                NETIF_F_TSO |
+                                NETIF_F_TSO6 |
+                                NETIF_F_HW_CSUM |
+                                NETIF_F_SCTP_CRC;
+
+       netdev->mpls_features |= NETIF_F_HW_CSUM;
+       netdev->hw_enc_features |= NETIF_F_HW_CSUM;
 
        /*reset the controller to put the device in a known good state */
        err = hw->mac.ops.reset_hw(hw);
index 0f1eca639f680caadff0a13b53622e6672fee20d..f00a41d9a1ca6528364e839e4240234b833cfdad 100644 (file)
@@ -126,6 +126,7 @@ struct e1000_adv_tx_context_desc {
 #define E1000_ADVTXD_MACLEN_SHIFT      9  /* Adv ctxt desc mac len shift */
 #define E1000_ADVTXD_TUCMD_IPV4                0x00000400 /* IP Packet Type: 1=IPv4 */
 #define E1000_ADVTXD_TUCMD_L4T_TCP     0x00000800 /* L4 Packet TYPE of TCP */
+#define E1000_ADVTXD_TUCMD_L4T_SCTP    0x00001000 /* L4 packet TYPE of SCTP */
 #define E1000_ADVTXD_L4LEN_SHIFT       8  /* Adv ctxt L4LEN shift */
 #define E1000_ADVTXD_MSS_SHIFT         16 /* Adv ctxt MSS shift */
 
index 4b9156cd8b93c542828e84fcd6dda0fb6d882e99..84fa28ceb200c968ad8422ca5194cf8dfb3dc13c 100644 (file)
@@ -796,6 +796,10 @@ struct ixgbe_adapter {
        u8 default_up;
        unsigned long fwd_bitmask; /* Bitmask indicating in use pools */
 
+#define IXGBE_MAX_LINK_HANDLE 10
+       struct ixgbe_mat_field *jump_tables[IXGBE_MAX_LINK_HANDLE];
+       unsigned long tables;
+
 /* maximum number of RETA entries among all devices supported by ixgbe
  * driver: currently it's x550 device in non-SRIOV mode
  */
@@ -925,6 +929,9 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw,
                                          u16 soft_id);
 void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
                                          union ixgbe_atr_input *mask);
+int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
+                                   struct ixgbe_fdir_filter *input,
+                                   u16 sw_idx);
 void ixgbe_set_rx_mode(struct net_device *netdev);
 #ifdef CONFIG_IXGBE_DCB
 void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
index bea96b3bc90c4c8889beed9536e53f8cca3a760a..726e0eeee63bb35ddaef4247d8705287759ea6f7 100644 (file)
@@ -2520,9 +2520,9 @@ static int ixgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
        return ret;
 }
 
-static int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
-                                          struct ixgbe_fdir_filter *input,
-                                          u16 sw_idx)
+int ixgbe_update_ethtool_fdir_entry(struct ixgbe_adapter *adapter,
+                                   struct ixgbe_fdir_filter *input,
+                                   u16 sw_idx)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        struct hlist_node *node2;
index 0c701b8438b6e5ff4f2eddbebc76df0fe855846c..4d6223da4a19b7ad337714760552bf226b00f23f 100644 (file)
@@ -51,6 +51,8 @@
 #include <linux/prefetch.h>
 #include <scsi/fc/fc_fcoe.h>
 #include <net/vxlan.h>
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_gact.h>
 
 #ifdef CONFIG_OF
 #include <linux/of_net.h>
@@ -65,6 +67,7 @@
 #include "ixgbe_common.h"
 #include "ixgbe_dcb_82599.h"
 #include "ixgbe_sriov.h"
+#include "ixgbe_model.h"
 
 char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
@@ -5545,6 +5548,9 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter)
 #endif /* CONFIG_IXGBE_DCB */
 #endif /* IXGBE_FCOE */
 
+       /* initialize static ixgbe jump table entries */
+       adapter->jump_tables[0] = ixgbe_ipv4_fields;
+
        adapter->mac_table = kzalloc(sizeof(struct ixgbe_mac_addr) *
                                     hw->mac.num_rar_entries,
                                     GFP_ATOMIC);
@@ -8200,6 +8206,225 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
        return 0;
 }
 
+static int ixgbe_delete_clsu32(struct ixgbe_adapter *adapter,
+                              struct tc_cls_u32_offload *cls)
+{
+       int err;
+
+       spin_lock(&adapter->fdir_perfect_lock);
+       err = ixgbe_update_ethtool_fdir_entry(adapter, NULL, cls->knode.handle);
+       spin_unlock(&adapter->fdir_perfect_lock);
+       return err;
+}
+
+static int ixgbe_configure_clsu32_add_hnode(struct ixgbe_adapter *adapter,
+                                           __be16 protocol,
+                                           struct tc_cls_u32_offload *cls)
+{
+       /* This ixgbe devices do not support hash tables at the moment
+        * so abort when given hash tables.
+        */
+       if (cls->hnode.divisor > 0)
+               return -EINVAL;
+
+       set_bit(TC_U32_USERHTID(cls->hnode.handle), &adapter->tables);
+       return 0;
+}
+
+static int ixgbe_configure_clsu32_del_hnode(struct ixgbe_adapter *adapter,
+                                           struct tc_cls_u32_offload *cls)
+{
+       clear_bit(TC_U32_USERHTID(cls->hnode.handle), &adapter->tables);
+       return 0;
+}
+
+static int ixgbe_configure_clsu32(struct ixgbe_adapter *adapter,
+                                 __be16 protocol,
+                                 struct tc_cls_u32_offload *cls)
+{
+       u32 loc = cls->knode.handle & 0xfffff;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_mat_field *field_ptr;
+       struct ixgbe_fdir_filter *input;
+       union ixgbe_atr_input mask;
+#ifdef CONFIG_NET_CLS_ACT
+       const struct tc_action *a;
+#endif
+       int i, err = 0;
+       u8 queue;
+       u32 handle;
+
+       memset(&mask, 0, sizeof(union ixgbe_atr_input));
+       handle = cls->knode.handle;
+
+       /* At the moment cls_u32 jumps to transport layer and skips past
+        * L2 headers. The canonical method to match L2 frames is to use
+        * negative values. However this is error prone at best but really
+        * just broken because there is no way to "know" what sort of hdr
+        * is in front of the transport layer. Fix cls_u32 to support L2
+        * headers when needed.
+        */
+       if (protocol != htons(ETH_P_IP))
+               return -EINVAL;
+
+       if (cls->knode.link_handle ||
+           cls->knode.link_handle >= IXGBE_MAX_LINK_HANDLE) {
+               struct ixgbe_nexthdr *nexthdr = ixgbe_ipv4_jumps;
+               u32 uhtid = TC_U32_USERHTID(cls->knode.link_handle);
+
+               if (!test_bit(uhtid, &adapter->tables))
+                       return -EINVAL;
+
+               for (i = 0; nexthdr[i].jump; i++) {
+                       if (nexthdr->o != cls->knode.sel->offoff ||
+                           nexthdr->s != cls->knode.sel->offshift ||
+                           nexthdr->m != cls->knode.sel->offmask ||
+                           /* do not support multiple key jumps its just mad */
+                           cls->knode.sel->nkeys > 1)
+                               return -EINVAL;
+
+                       if (nexthdr->off != cls->knode.sel->keys[0].off ||
+                           nexthdr->val != cls->knode.sel->keys[0].val ||
+                           nexthdr->mask != cls->knode.sel->keys[0].mask)
+                               return -EINVAL;
+
+                       if (uhtid >= IXGBE_MAX_LINK_HANDLE)
+                               return -EINVAL;
+
+                       adapter->jump_tables[uhtid] = nexthdr->jump;
+               }
+               return 0;
+       }
+
+       if (loc >= ((1024 << adapter->fdir_pballoc) - 2)) {
+               e_err(drv, "Location out of range\n");
+               return -EINVAL;
+       }
+
+       /* cls u32 is a graph starting at root node 0x800. The driver tracks
+        * links and also the fields used to advance the parser across each
+        * link (e.g. nexthdr/eat parameters from 'tc'). This way we can map
+        * the u32 graph onto the hardware parse graph denoted in ixgbe_model.h
+        * To add support for new nodes update ixgbe_model.h parse structures
+        * this function _should_ be generic try not to hardcode values here.
+        */
+       if (TC_U32_USERHTID(handle) == 0x800) {
+               field_ptr = adapter->jump_tables[0];
+       } else {
+               if (TC_U32_USERHTID(handle) >= ARRAY_SIZE(adapter->jump_tables))
+                       return -EINVAL;
+
+               field_ptr = adapter->jump_tables[TC_U32_USERHTID(handle)];
+       }
+
+       if (!field_ptr)
+               return -EINVAL;
+
+       input = kzalloc(sizeof(*input), GFP_KERNEL);
+       if (!input)
+               return -ENOMEM;
+
+       for (i = 0; i < cls->knode.sel->nkeys; i++) {
+               int off = cls->knode.sel->keys[i].off;
+               __be32 val = cls->knode.sel->keys[i].val;
+               __be32 m = cls->knode.sel->keys[i].mask;
+               bool found_entry = false;
+               int j;
+
+               for (j = 0; field_ptr[j].val; j++) {
+                       if (field_ptr[j].off == off &&
+                           field_ptr[j].mask == m) {
+                               field_ptr[j].val(input, &mask, val, m);
+                               input->filter.formatted.flow_type |=
+                                       field_ptr[j].type;
+                               found_entry = true;
+                               break;
+                       }
+               }
+
+               if (!found_entry)
+                       goto err_out;
+       }
+
+       mask.formatted.flow_type = IXGBE_ATR_L4TYPE_IPV6_MASK |
+                                  IXGBE_ATR_L4TYPE_MASK;
+
+       if (input->filter.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4)
+               mask.formatted.flow_type &= IXGBE_ATR_L4TYPE_IPV6_MASK;
+
+#ifdef CONFIG_NET_CLS_ACT
+       if (list_empty(&cls->knode.exts->actions))
+               goto err_out;
+
+       list_for_each_entry(a, &cls->knode.exts->actions, list) {
+               if (!is_tcf_gact_shot(a))
+                       goto err_out;
+       }
+#endif
+
+       input->action = IXGBE_FDIR_DROP_QUEUE;
+       queue = IXGBE_FDIR_DROP_QUEUE;
+       input->sw_idx = loc;
+
+       spin_lock(&adapter->fdir_perfect_lock);
+
+       if (hlist_empty(&adapter->fdir_filter_list)) {
+               memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
+               err = ixgbe_fdir_set_input_mask_82599(hw, &mask);
+               if (err)
+                       goto err_out_w_lock;
+       } else if (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
+               err = -EINVAL;
+               goto err_out_w_lock;
+       }
+
+       ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);
+       err = ixgbe_fdir_write_perfect_filter_82599(hw, &input->filter,
+                                                   input->sw_idx, queue);
+       if (!err)
+               ixgbe_update_ethtool_fdir_entry(adapter, input, input->sw_idx);
+       spin_unlock(&adapter->fdir_perfect_lock);
+
+       return err;
+err_out_w_lock:
+       spin_unlock(&adapter->fdir_perfect_lock);
+err_out:
+       kfree(input);
+       return -EINVAL;
+}
+
+int __ixgbe_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                    struct tc_to_netdev *tc)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+
+       if (TC_H_MAJ(handle) == TC_H_MAJ(TC_H_INGRESS) &&
+           tc->type == TC_SETUP_CLSU32) {
+               switch (tc->cls_u32->command) {
+               case TC_CLSU32_NEW_KNODE:
+               case TC_CLSU32_REPLACE_KNODE:
+                       return ixgbe_configure_clsu32(adapter,
+                                                     proto, tc->cls_u32);
+               case TC_CLSU32_DELETE_KNODE:
+                       return ixgbe_delete_clsu32(adapter, tc->cls_u32);
+               case TC_CLSU32_NEW_HNODE:
+               case TC_CLSU32_REPLACE_HNODE:
+                       return ixgbe_configure_clsu32_add_hnode(adapter, proto,
+                                                               tc->cls_u32);
+               case TC_CLSU32_DELETE_HNODE:
+                       return ixgbe_configure_clsu32_del_hnode(adapter,
+                                                               tc->cls_u32);
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       return ixgbe_setup_tc(dev, tc->tc);
+}
+
 #ifdef CONFIG_PCI_IOV
 void ixgbe_sriov_reinit(struct ixgbe_adapter *adapter)
 {
@@ -8262,19 +8487,17 @@ static int ixgbe_set_features(struct net_device *netdev,
        }
 
        /*
-        * Check if Flow Director n-tuple support was enabled or disabled.  If
-        * the state changed, we need to reset.
+        * Check if Flow Director n-tuple support or hw_tc support was
+        * enabled or disabled.  If the state changed, we need to reset.
         */
-       switch (features & NETIF_F_NTUPLE) {
-       case NETIF_F_NTUPLE:
+       if ((features & NETIF_F_NTUPLE) || (features & NETIF_F_HW_TC)) {
                /* turn off ATR, enable perfect filters and reset */
                if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
                        need_reset = true;
 
                adapter->flags &= ~IXGBE_FLAG_FDIR_HASH_CAPABLE;
                adapter->flags |= IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
-               break;
-       default:
+       } else {
                /* turn off perfect filters, enable ATR and reset */
                if (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                        need_reset = true;
@@ -8282,23 +8505,16 @@ static int ixgbe_set_features(struct net_device *netdev,
                adapter->flags &= ~IXGBE_FLAG_FDIR_PERFECT_CAPABLE;
 
                /* We cannot enable ATR if SR-IOV is enabled */
-               if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
-                       break;
-
-               /* We cannot enable ATR if we have 2 or more traffic classes */
-               if (netdev_get_num_tc(netdev) > 1)
-                       break;
-
-               /* We cannot enable ATR if RSS is disabled */
-               if (adapter->ring_feature[RING_F_RSS].limit <= 1)
-                       break;
-
-               /* A sample rate of 0 indicates ATR disabled */
-               if (!adapter->atr_sample_rate)
-                       break;
-
-               adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
-               break;
+               if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED ||
+                   /* We cannot enable ATR if we have 2 or more tcs */
+                   (netdev_get_num_tc(netdev) > 1) ||
+                   /* We cannot enable ATR if RSS is disabled */
+                   (adapter->ring_feature[RING_F_RSS].limit <= 1) ||
+                   /* A sample rate of 0 indicates ATR disabled */
+                   (!adapter->atr_sample_rate))
+                       ; /* do nothing not supported */
+               else /* otherwise supported and set the flag */
+                       adapter->flags |= IXGBE_FLAG_FDIR_HASH_CAPABLE;
        }
 
        if (features & NETIF_F_HW_VLAN_CTAG_RX)
@@ -8657,9 +8873,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_set_vf_trust       = ixgbe_ndo_set_vf_trust,
        .ndo_get_vf_config      = ixgbe_ndo_get_vf_config,
        .ndo_get_stats64        = ixgbe_get_stats64,
-#ifdef CONFIG_IXGBE_DCB
-       .ndo_setup_tc           = ixgbe_setup_tc,
-#endif
+       .ndo_setup_tc           = __ixgbe_setup_tc,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
@@ -9030,7 +9244,8 @@ skip_sriov:
        case ixgbe_mac_X550EM_x:
                netdev->features |= NETIF_F_SCTP_CRC;
                netdev->hw_features |= NETIF_F_SCTP_CRC |
-                                      NETIF_F_NTUPLE;
+                                      NETIF_F_NTUPLE |
+                                      NETIF_F_HW_TC;
                break;
        default:
                break;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_model.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_model.h
new file mode 100644 (file)
index 0000000..ce48872
--- /dev/null
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ *
+ * Intel 10 Gigabit PCI Express Linux drive
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _IXGBE_MODEL_H_
+#define _IXGBE_MODEL_H_
+
+#include "ixgbe.h"
+#include "ixgbe_type.h"
+
+struct ixgbe_mat_field {
+       unsigned int off;
+       unsigned int mask;
+       int (*val)(struct ixgbe_fdir_filter *input,
+                  union ixgbe_atr_input *mask,
+                  u32 val, u32 m);
+       unsigned int type;
+};
+
+static inline int ixgbe_mat_prgm_sip(struct ixgbe_fdir_filter *input,
+                                    union ixgbe_atr_input *mask,
+                                    u32 val, u32 m)
+{
+       input->filter.formatted.src_ip[0] = val;
+       mask->formatted.src_ip[0] = m;
+       return 0;
+}
+
+static inline int ixgbe_mat_prgm_dip(struct ixgbe_fdir_filter *input,
+                                    union ixgbe_atr_input *mask,
+                                    u32 val, u32 m)
+{
+       input->filter.formatted.dst_ip[0] = val;
+       mask->formatted.dst_ip[0] = m;
+       return 0;
+}
+
+static struct ixgbe_mat_field ixgbe_ipv4_fields[] = {
+       { .off = 12, .mask = -1, .val = ixgbe_mat_prgm_sip,
+         .type = IXGBE_ATR_FLOW_TYPE_IPV4},
+       { .off = 16, .mask = -1, .val = ixgbe_mat_prgm_dip,
+         .type = IXGBE_ATR_FLOW_TYPE_IPV4},
+       { .val = NULL } /* terminal node */
+};
+
+static inline int ixgbe_mat_prgm_sport(struct ixgbe_fdir_filter *input,
+                                      union ixgbe_atr_input *mask,
+                                      u32 val, u32 m)
+{
+       input->filter.formatted.src_port = val & 0xffff;
+       mask->formatted.src_port = m & 0xffff;
+       return 0;
+};
+
+static inline int ixgbe_mat_prgm_dport(struct ixgbe_fdir_filter *input,
+                                      union ixgbe_atr_input *mask,
+                                      u32 val, u32 m)
+{
+       input->filter.formatted.dst_port = val & 0xffff;
+       mask->formatted.dst_port = m & 0xffff;
+       return 0;
+};
+
+static struct ixgbe_mat_field ixgbe_tcp_fields[] = {
+       {.off = 0, .mask = 0xffff, .val = ixgbe_mat_prgm_sport,
+        .type = IXGBE_ATR_FLOW_TYPE_TCPV4},
+       {.off = 2, .mask = 0xffff, .val = ixgbe_mat_prgm_dport,
+        .type = IXGBE_ATR_FLOW_TYPE_TCPV4},
+       { .val = NULL } /* terminal node */
+};
+
+struct ixgbe_nexthdr {
+       /* offset, shift, and mask of position to next header */
+       unsigned int o;
+       u32 s;
+       u32 m;
+       /* match criteria to make this jump*/
+       unsigned int off;
+       u32 val;
+       u32 mask;
+       /* location of jump to make */
+       struct ixgbe_mat_field *jump;
+};
+
+static struct ixgbe_nexthdr ixgbe_ipv4_jumps[] = {
+       { .o = 0, .s = 6, .m = 0xf,
+         .off = 8, .val = 0x600, .mask = 0xff00, .jump = ixgbe_tcp_fields},
+       { .jump = NULL } /* terminal node */
+};
+#endif /* _IXGBE_MODEL_H_ */
index b1de7afd41166cc9ef67ed7e43191aaff897ec4e..3ddf657bc10bcc51d5a217595ba8e98ed909e0cd 100644 (file)
@@ -270,11 +270,17 @@ jme_reset_mac_processor(struct jme_adapter *jme)
 }
 
 static inline void
-jme_clear_pm(struct jme_adapter *jme)
+jme_clear_pm_enable_wol(struct jme_adapter *jme)
 {
        jwrite32(jme, JME_PMCS, PMCS_STMASK | jme->reg_pmcs);
 }
 
+static inline void
+jme_clear_pm_disable_wol(struct jme_adapter *jme)
+{
+       jwrite32(jme, JME_PMCS, PMCS_STMASK);
+}
+
 static int
 jme_reload_eeprom(struct jme_adapter *jme)
 {
@@ -1853,7 +1859,7 @@ jme_open(struct net_device *netdev)
        struct jme_adapter *jme = netdev_priv(netdev);
        int rc;
 
-       jme_clear_pm(jme);
+       jme_clear_pm_disable_wol(jme);
        JME_NAPI_ENABLE(jme);
 
        tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
@@ -1925,11 +1931,11 @@ jme_wait_link(struct jme_adapter *jme)
 static void
 jme_powersave_phy(struct jme_adapter *jme)
 {
-       if (jme->reg_pmcs) {
+       if (jme->reg_pmcs && device_may_wakeup(&jme->pdev->dev)) {
                jme_set_100m_half(jme);
                if (jme->reg_pmcs & (PMCS_LFEN | PMCS_LREN))
                        jme_wait_link(jme);
-               jme_clear_pm(jme);
+               jme_clear_pm_enable_wol(jme);
        } else {
                jme_phy_off(jme);
        }
@@ -2646,9 +2652,6 @@ jme_set_wol(struct net_device *netdev,
        if (wol->wolopts & WAKE_MAGIC)
                jme->reg_pmcs |= PMCS_MFEN;
 
-       jwrite32(jme, JME_PMCS, jme->reg_pmcs);
-       device_set_wakeup_enable(&jme->pdev->dev, !!(jme->reg_pmcs));
-
        return 0;
 }
 
@@ -3172,8 +3175,8 @@ jme_init_one(struct pci_dev *pdev,
        jme->mii_if.mdio_read = jme_mdio_read;
        jme->mii_if.mdio_write = jme_mdio_write;
 
-       jme_clear_pm(jme);
-       device_set_wakeup_enable(&pdev->dev, true);
+       jme_clear_pm_disable_wol(jme);
+       device_init_wakeup(&pdev->dev, true);
 
        jme_set_phyfifo_5level(jme);
        jme->pcirev = pdev->revision;
@@ -3304,7 +3307,7 @@ jme_resume(struct device *dev)
        if (!netif_running(netdev))
                return 0;
 
-       jme_clear_pm(jme);
+       jme_clear_pm_disable_wol(jme);
        jme_phy_on(jme);
        if (test_bit(JME_FLAG_SSET, &jme->flags))
                jme_set_settings(netdev, &jme->old_ecmd);
@@ -3312,13 +3315,14 @@ jme_resume(struct device *dev)
                jme_reset_phy_processor(jme);
        jme_phy_calibration(jme);
        jme_phy_setEA(jme);
-       jme_start_irq(jme);
        netif_device_attach(netdev);
 
        atomic_inc(&jme->link_changing);
 
        jme_reset_link(jme);
 
+       jme_start_irq(jme);
+
        return 0;
 }
 
index 662c2ee268c7c7512c7d5f1290e1cb02fa3883dc..b0ae69f8449369585dfa82de3243f401f8a1022a 100644 (file)
@@ -370,6 +370,11 @@ struct mvneta_port {
        struct net_device *dev;
        struct notifier_block cpu_notifier;
        int rxq_def;
+       /* Protect the access to the percpu interrupt registers,
+        * ensuring that the configuration remains coherent.
+        */
+       spinlock_t lock;
+       bool is_stopped;
 
        /* Core clock */
        struct clk *clk;
@@ -1038,6 +1043,43 @@ static void mvneta_set_autoneg(struct mvneta_port *pp, int enable)
        }
 }
 
+static void mvneta_percpu_unmask_interrupt(void *arg)
+{
+       struct mvneta_port *pp = arg;
+
+       /* All the queue are unmasked, but actually only the ones
+        * mapped to this CPU will be unmasked
+        */
+       mvreg_write(pp, MVNETA_INTR_NEW_MASK,
+                   MVNETA_RX_INTR_MASK_ALL |
+                   MVNETA_TX_INTR_MASK_ALL |
+                   MVNETA_MISCINTR_INTR_MASK);
+}
+
+static void mvneta_percpu_mask_interrupt(void *arg)
+{
+       struct mvneta_port *pp = arg;
+
+       /* All the queue are masked, but actually only the ones
+        * mapped to this CPU will be masked
+        */
+       mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
+       mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
+       mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+}
+
+static void mvneta_percpu_clear_intr_cause(void *arg)
+{
+       struct mvneta_port *pp = arg;
+
+       /* All the queue are cleared, but actually only the ones
+        * mapped to this CPU will be cleared
+        */
+       mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
+       mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+       mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
+}
+
 /* This method sets defaults to the NETA port:
  *     Clears interrupt Cause and Mask registers.
  *     Clears all MAC tables.
@@ -1055,14 +1097,10 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
        int max_cpu = num_present_cpus();
 
        /* Clear all Cause registers */
-       mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
-       mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
-       mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+       on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
 
        /* Mask all interrupts */
-       mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+       on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
        mvreg_write(pp, MVNETA_INTR_ENABLE, 0);
 
        /* Enable MBUS Retry bit16 */
@@ -2528,34 +2566,9 @@ static int mvneta_setup_txqs(struct mvneta_port *pp)
        return 0;
 }
 
-static void mvneta_percpu_unmask_interrupt(void *arg)
-{
-       struct mvneta_port *pp = arg;
-
-       /* All the queue are unmasked, but actually only the ones
-        * maped to this CPU will be unmasked
-        */
-       mvreg_write(pp, MVNETA_INTR_NEW_MASK,
-                   MVNETA_RX_INTR_MASK_ALL |
-                   MVNETA_TX_INTR_MASK_ALL |
-                   MVNETA_MISCINTR_INTR_MASK);
-}
-
-static void mvneta_percpu_mask_interrupt(void *arg)
-{
-       struct mvneta_port *pp = arg;
-
-       /* All the queue are masked, but actually only the ones
-        * maped to this CPU will be masked
-        */
-       mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
-}
-
 static void mvneta_start_dev(struct mvneta_port *pp)
 {
-       unsigned int cpu;
+       int cpu;
 
        mvneta_max_rx_size_set(pp, pp->pkt_size);
        mvneta_txq_max_tx_size_set(pp, pp->pkt_size);
@@ -2564,16 +2577,15 @@ static void mvneta_start_dev(struct mvneta_port *pp)
        mvneta_port_enable(pp);
 
        /* Enable polling on the port */
-       for_each_present_cpu(cpu) {
+       for_each_online_cpu(cpu) {
                struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
                napi_enable(&port->napi);
        }
 
        /* Unmask interrupts. It has to be done from each CPU */
-       for_each_online_cpu(cpu)
-               smp_call_function_single(cpu, mvneta_percpu_unmask_interrupt,
-                                        pp, true);
+       on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
+
        mvreg_write(pp, MVNETA_INTR_MISC_MASK,
                    MVNETA_CAUSE_PHY_STATUS_CHANGE |
                    MVNETA_CAUSE_LINK_CHANGE |
@@ -2589,7 +2601,7 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
 
        phy_stop(pp->phy_dev);
 
-       for_each_present_cpu(cpu) {
+       for_each_online_cpu(cpu) {
                struct mvneta_pcpu_port *port = per_cpu_ptr(pp->ports, cpu);
 
                napi_disable(&port->napi);
@@ -2604,13 +2616,10 @@ static void mvneta_stop_dev(struct mvneta_port *pp)
        mvneta_port_disable(pp);
 
        /* Clear all ethernet port interrupts */
-       mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
-       mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
+       on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
 
        /* Mask all ethernet port interrupts */
-       mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
-       mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+       on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 
        mvneta_tx_reset(pp);
        mvneta_rx_reset(pp);
@@ -2847,11 +2856,20 @@ static void mvneta_percpu_disable(void *arg)
        disable_percpu_irq(pp->dev->irq);
 }
 
+/* Electing a CPU must be done in an atomic way: it should be done
+ * after or before the removal/insertion of a CPU and this function is
+ * not reentrant.
+ */
 static void mvneta_percpu_elect(struct mvneta_port *pp)
 {
-       int online_cpu_idx, max_cpu, cpu, i = 0;
+       int elected_cpu = 0, max_cpu, cpu, i = 0;
+
+       /* Use the cpu associated to the rxq when it is online, in all
+        * the other cases, use the cpu 0 which can't be offline.
+        */
+       if (cpu_online(pp->rxq_def))
+               elected_cpu = pp->rxq_def;
 
-       online_cpu_idx = pp->rxq_def % num_online_cpus();
        max_cpu = num_present_cpus();
 
        for_each_online_cpu(cpu) {
@@ -2862,7 +2880,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)
                        if ((rxq % max_cpu) == cpu)
                                rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
 
-               if (i == online_cpu_idx)
+               if (cpu == elected_cpu)
                        /* Map the default receive queue queue to the
                         * elected CPU
                         */
@@ -2873,7 +2891,7 @@ static void mvneta_percpu_elect(struct mvneta_port *pp)
                 * the CPU bound to the default RX queue
                 */
                if (txq_number == 1)
-                       txq_map = (i == online_cpu_idx) ?
+                       txq_map = (cpu == elected_cpu) ?
                                MVNETA_CPU_TXQ_ACCESS(1) : 0;
                else
                        txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
@@ -2902,6 +2920,14 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
+               spin_lock(&pp->lock);
+               /* Configuring the driver for a new CPU while the
+                * driver is stopping is racy, so just avoid it.
+                */
+               if (pp->is_stopped) {
+                       spin_unlock(&pp->lock);
+                       break;
+               }
                netif_tx_stop_all_queues(pp->dev);
 
                /* We have to synchronise on tha napi of each CPU
@@ -2917,9 +2943,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
                }
 
                /* Mask all ethernet port interrupts */
-               mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
-               mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
-               mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+               on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
                napi_enable(&port->napi);
 
 
@@ -2934,27 +2958,25 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
                 */
                mvneta_percpu_elect(pp);
 
-               /* Unmask all ethernet port interrupts, as this
-                * notifier is called for each CPU then the CPU to
-                * Queue mapping is applied
-                */
-               mvreg_write(pp, MVNETA_INTR_NEW_MASK,
-                       MVNETA_RX_INTR_MASK(rxq_number) |
-                       MVNETA_TX_INTR_MASK(txq_number) |
-                       MVNETA_MISCINTR_INTR_MASK);
+               /* Unmask all ethernet port interrupts */
+               on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
                mvreg_write(pp, MVNETA_INTR_MISC_MASK,
                        MVNETA_CAUSE_PHY_STATUS_CHANGE |
                        MVNETA_CAUSE_LINK_CHANGE |
                        MVNETA_CAUSE_PSC_SYNC_CHANGE);
                netif_tx_start_all_queues(pp->dev);
+               spin_unlock(&pp->lock);
                break;
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
                netif_tx_stop_all_queues(pp->dev);
+               /* Thanks to this lock we are sure that any pending
+                * cpu election is done
+                */
+               spin_lock(&pp->lock);
                /* Mask all ethernet port interrupts */
-               mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
-               mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
-               mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
+               on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
+               spin_unlock(&pp->lock);
 
                napi_synchronize(&port->napi);
                napi_disable(&port->napi);
@@ -2968,12 +2990,11 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                /* Check if a new CPU must be elected now this on is down */
+               spin_lock(&pp->lock);
                mvneta_percpu_elect(pp);
+               spin_unlock(&pp->lock);
                /* Unmask all ethernet port interrupts */
-               mvreg_write(pp, MVNETA_INTR_NEW_MASK,
-                       MVNETA_RX_INTR_MASK(rxq_number) |
-                       MVNETA_TX_INTR_MASK(txq_number) |
-                       MVNETA_MISCINTR_INTR_MASK);
+               on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
                mvreg_write(pp, MVNETA_INTR_MISC_MASK,
                        MVNETA_CAUSE_PHY_STATUS_CHANGE |
                        MVNETA_CAUSE_LINK_CHANGE |
@@ -2988,7 +3009,7 @@ static int mvneta_percpu_notifier(struct notifier_block *nfb,
 static int mvneta_open(struct net_device *dev)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       int ret, cpu;
+       int ret;
 
        pp->pkt_size = MVNETA_RX_PKT_SIZE(pp->dev->mtu);
        pp->frag_size = SKB_DATA_ALIGN(MVNETA_RX_BUF_SIZE(pp->pkt_size)) +
@@ -3010,22 +3031,12 @@ static int mvneta_open(struct net_device *dev)
                goto err_cleanup_txqs;
        }
 
-       /* Even though the documentation says that request_percpu_irq
-        * doesn't enable the interrupts automatically, it actually
-        * does so on the local CPU.
-        *
-        * Make sure it's disabled.
-        */
-       mvneta_percpu_disable(pp);
-
        /* Enable per-CPU interrupt on all the CPU to handle our RX
         * queue interrupts
         */
-       for_each_online_cpu(cpu)
-               smp_call_function_single(cpu, mvneta_percpu_enable,
-                                        pp, true);
-
+       on_each_cpu(mvneta_percpu_enable, pp, true);
 
+       pp->is_stopped = false;
        /* Register a CPU notifier to handle the case where our CPU
         * might be taken offline.
         */
@@ -3057,13 +3068,20 @@ err_cleanup_rxqs:
 static int mvneta_stop(struct net_device *dev)
 {
        struct mvneta_port *pp = netdev_priv(dev);
-       int cpu;
 
+       /* Inform that we are stopping so we don't want to setup the
+        * driver for new CPUs in the notifiers
+        */
+       spin_lock(&pp->lock);
+       pp->is_stopped = true;
        mvneta_stop_dev(pp);
        mvneta_mdio_remove(pp);
        unregister_cpu_notifier(&pp->cpu_notifier);
-       for_each_present_cpu(cpu)
-               smp_call_function_single(cpu, mvneta_percpu_disable, pp, true);
+       /* Now that the notifier are unregistered, we can release le
+        * lock
+        */
+       spin_unlock(&pp->lock);
+       on_each_cpu(mvneta_percpu_disable, pp, true);
        free_percpu_irq(dev->irq, pp->ports);
        mvneta_cleanup_rxqs(pp);
        mvneta_cleanup_txqs(pp);
@@ -3312,9 +3330,7 @@ static int  mvneta_config_rss(struct mvneta_port *pp)
 
        netif_tx_stop_all_queues(pp->dev);
 
-       for_each_online_cpu(cpu)
-               smp_call_function_single(cpu, mvneta_percpu_mask_interrupt,
-                                        pp, true);
+       on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
 
        /* We have to synchronise on the napi of each CPU */
        for_each_online_cpu(cpu) {
@@ -3335,7 +3351,9 @@ static int  mvneta_config_rss(struct mvneta_port *pp)
        mvreg_write(pp, MVNETA_PORT_CONFIG, val);
 
        /* Update the elected CPU matching the new rxq_def */
+       spin_lock(&pp->lock);
        mvneta_percpu_elect(pp);
+       spin_unlock(&pp->lock);
 
        /* We have to synchronise on the napi of each CPU */
        for_each_online_cpu(cpu) {
index a4beccf1fd46e26483dc796829d444a15f77723f..c797971aefabbd89ddd31e8defd7ff9f93508f0c 100644 (file)
@@ -3061,7 +3061,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,
 
                pe = kzalloc(sizeof(*pe), GFP_KERNEL);
                if (!pe)
-                       return -1;
+                       return -ENOMEM;
                mvpp2_prs_tcam_lu_set(pe, MVPP2_PRS_LU_MAC);
                pe->index = tid;
 
@@ -3077,7 +3077,7 @@ static int mvpp2_prs_mac_da_accept(struct mvpp2 *priv, int port,
        if (pmap == 0) {
                if (add) {
                        kfree(pe);
-                       return -1;
+                       return -EINVAL;
                }
                mvpp2_prs_hw_inv(priv, pe->index);
                priv->prs_shadow[pe->index].valid = false;
diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
new file mode 100644 (file)
index 0000000..698bb89
--- /dev/null
@@ -0,0 +1,17 @@
+config NET_VENDOR_MEDIATEK
+       bool "MediaTek ethernet driver"
+       depends on ARCH_MEDIATEK
+       ---help---
+         If you have a Mediatek SoC with ethernet, say Y.
+
+if NET_VENDOR_MEDIATEK
+
+config NET_MEDIATEK_SOC
+       tristate "MediaTek MT7623 Gigabit ethernet support"
+       depends on NET_VENDOR_MEDIATEK && (MACH_MT7623 || MACH_MT2701)
+       select PHYLIB
+       ---help---
+         This driver supports the gigabit ethernet MACs in the
+         MediaTek MT2701/MT7623 chipset family.
+
+endif #NET_VENDOR_MEDIATEK
diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
new file mode 100644 (file)
index 0000000..aa3f1c8
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the Mediatek SoCs built-in ethernet macs
+#
+
+obj-$(CONFIG_NET_MEDIATEK_SOC)                 += mtk_eth_soc.o
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
new file mode 100644 (file)
index 0000000..ba3afa5
--- /dev/null
@@ -0,0 +1,1807 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   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.
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/if_vlan.h>
+#include <linux/reset.h>
+#include <linux/tcp.h>
+
+#include "mtk_eth_soc.h"
+
+static int mtk_msg_level = -1;
+module_param_named(msg_level, mtk_msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+
+#define MTK_ETHTOOL_STAT(x) { #x, \
+                             offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
+
+/* strings used by ethtool */
+static const struct mtk_ethtool_stats {
+       char str[ETH_GSTRING_LEN];
+       u32 offset;
+} mtk_ethtool_stats[] = {
+       MTK_ETHTOOL_STAT(tx_bytes),
+       MTK_ETHTOOL_STAT(tx_packets),
+       MTK_ETHTOOL_STAT(tx_skip),
+       MTK_ETHTOOL_STAT(tx_collisions),
+       MTK_ETHTOOL_STAT(rx_bytes),
+       MTK_ETHTOOL_STAT(rx_packets),
+       MTK_ETHTOOL_STAT(rx_overflow),
+       MTK_ETHTOOL_STAT(rx_fcs_errors),
+       MTK_ETHTOOL_STAT(rx_short_errors),
+       MTK_ETHTOOL_STAT(rx_long_errors),
+       MTK_ETHTOOL_STAT(rx_checksum_errors),
+       MTK_ETHTOOL_STAT(rx_flow_control_packets),
+};
+
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+{
+       __raw_writel(val, eth->base + reg);
+}
+
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg)
+{
+       return __raw_readl(eth->base + reg);
+}
+
+static int mtk_mdio_busy_wait(struct mtk_eth *eth)
+{
+       unsigned long t_start = jiffies;
+
+       while (1) {
+               if (!(mtk_r32(eth, MTK_PHY_IAC) & PHY_IAC_ACCESS))
+                       return 0;
+               if (time_after(jiffies, t_start + PHY_IAC_TIMEOUT))
+                       break;
+               usleep_range(10, 20);
+       }
+
+       dev_err(eth->dev, "mdio: MDIO timeout\n");
+       return -1;
+}
+
+u32 _mtk_mdio_write(struct mtk_eth *eth, u32 phy_addr,
+                   u32 phy_register, u32 write_data)
+{
+       if (mtk_mdio_busy_wait(eth))
+               return -1;
+
+       write_data &= 0xffff;
+
+       mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_WRITE |
+               (phy_register << PHY_IAC_REG_SHIFT) |
+               (phy_addr << PHY_IAC_ADDR_SHIFT) | write_data,
+               MTK_PHY_IAC);
+
+       if (mtk_mdio_busy_wait(eth))
+               return -1;
+
+       return 0;
+}
+
+u32 _mtk_mdio_read(struct mtk_eth *eth, int phy_addr, int phy_reg)
+{
+       u32 d;
+
+       if (mtk_mdio_busy_wait(eth))
+               return 0xffff;
+
+       mtk_w32(eth, PHY_IAC_ACCESS | PHY_IAC_START | PHY_IAC_READ |
+               (phy_reg << PHY_IAC_REG_SHIFT) |
+               (phy_addr << PHY_IAC_ADDR_SHIFT),
+               MTK_PHY_IAC);
+
+       if (mtk_mdio_busy_wait(eth))
+               return 0xffff;
+
+       d = mtk_r32(eth, MTK_PHY_IAC) & 0xffff;
+
+       return d;
+}
+
+static int mtk_mdio_write(struct mii_bus *bus, int phy_addr,
+                         int phy_reg, u16 val)
+{
+       struct mtk_eth *eth = bus->priv;
+
+       return _mtk_mdio_write(eth, phy_addr, phy_reg, val);
+}
+
+static int mtk_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+       struct mtk_eth *eth = bus->priv;
+
+       return _mtk_mdio_read(eth, phy_addr, phy_reg);
+}
+
+static void mtk_phy_link_adjust(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       u32 mcr = MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG |
+                 MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN |
+                 MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN |
+                 MAC_MCR_BACKPR_EN;
+
+       switch (mac->phy_dev->speed) {
+       case SPEED_1000:
+               mcr |= MAC_MCR_SPEED_1000;
+               break;
+       case SPEED_100:
+               mcr |= MAC_MCR_SPEED_100;
+               break;
+       };
+
+       if (mac->phy_dev->link)
+               mcr |= MAC_MCR_FORCE_LINK;
+
+       if (mac->phy_dev->duplex)
+               mcr |= MAC_MCR_FORCE_DPX;
+
+       if (mac->phy_dev->pause)
+               mcr |= MAC_MCR_FORCE_RX_FC | MAC_MCR_FORCE_TX_FC;
+
+       mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
+
+       if (mac->phy_dev->link)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
+}
+
+static int mtk_phy_connect_node(struct mtk_eth *eth, struct mtk_mac *mac,
+                               struct device_node *phy_node)
+{
+       const __be32 *_addr = NULL;
+       struct phy_device *phydev;
+       int phy_mode, addr;
+
+       _addr = of_get_property(phy_node, "reg", NULL);
+
+       if (!_addr || (be32_to_cpu(*_addr) >= 0x20)) {
+               pr_err("%s: invalid phy address\n", phy_node->name);
+               return -EINVAL;
+       }
+       addr = be32_to_cpu(*_addr);
+       phy_mode = of_get_phy_mode(phy_node);
+       if (phy_mode < 0) {
+               dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode);
+               return -EINVAL;
+       }
+
+       phydev = of_phy_connect(eth->netdev[mac->id], phy_node,
+                               mtk_phy_link_adjust, 0, phy_mode);
+       if (IS_ERR(phydev)) {
+               dev_err(eth->dev, "could not connect to PHY\n");
+               return PTR_ERR(phydev);
+       }
+
+       dev_info(eth->dev,
+                "connected mac %d to PHY at %s [uid=%08x, driver=%s]\n",
+                mac->id, phydev_name(phydev), phydev->phy_id,
+                phydev->drv->name);
+
+       mac->phy_dev = phydev;
+
+       return 0;
+}
+
+static int mtk_phy_connect(struct mtk_mac *mac)
+{
+       struct mtk_eth *eth = mac->hw;
+       struct device_node *np;
+       u32 val, ge_mode;
+
+       np = of_parse_phandle(mac->of_node, "phy-handle", 0);
+       if (!np)
+               return -ENODEV;
+
+       switch (of_get_phy_mode(np)) {
+       case PHY_INTERFACE_MODE_RGMII:
+               ge_mode = 0;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+               ge_mode = 1;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               ge_mode = 2;
+               break;
+       default:
+               dev_err(eth->dev, "invalid phy_mode\n");
+               return -1;
+       }
+
+       /* put the gmac into the right mode */
+       regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
+       val &= ~SYSCFG0_GE_MODE(SYSCFG0_GE_MASK, mac->id);
+       val |= SYSCFG0_GE_MODE(ge_mode, mac->id);
+       regmap_write(eth->ethsys, ETHSYS_SYSCFG0, val);
+
+       mtk_phy_connect_node(eth, mac, np);
+       mac->phy_dev->autoneg = AUTONEG_ENABLE;
+       mac->phy_dev->speed = 0;
+       mac->phy_dev->duplex = 0;
+       mac->phy_dev->supported &= PHY_BASIC_FEATURES;
+       mac->phy_dev->advertising = mac->phy_dev->supported |
+                                   ADVERTISED_Autoneg;
+       phy_start_aneg(mac->phy_dev);
+
+       return 0;
+}
+
+static int mtk_mdio_init(struct mtk_eth *eth)
+{
+       struct device_node *mii_np;
+       int err;
+
+       mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus");
+       if (!mii_np) {
+               dev_err(eth->dev, "no %s child node found", "mdio-bus");
+               return -ENODEV;
+       }
+
+       if (!of_device_is_available(mii_np)) {
+               err = 0;
+               goto err_put_node;
+       }
+
+       eth->mii_bus = mdiobus_alloc();
+       if (!eth->mii_bus) {
+               err = -ENOMEM;
+               goto err_put_node;
+       }
+
+       eth->mii_bus->name = "mdio";
+       eth->mii_bus->read = mtk_mdio_read;
+       eth->mii_bus->write = mtk_mdio_write;
+       eth->mii_bus->priv = eth;
+       eth->mii_bus->parent = eth->dev;
+
+       snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name);
+       err = of_mdiobus_register(eth->mii_bus, mii_np);
+       if (err)
+               goto err_free_bus;
+
+       return 0;
+
+err_free_bus:
+       kfree(eth->mii_bus);
+
+err_put_node:
+       of_node_put(mii_np);
+       eth->mii_bus = NULL;
+       return err;
+}
+
+static void mtk_mdio_cleanup(struct mtk_eth *eth)
+{
+       if (!eth->mii_bus)
+               return;
+
+       mdiobus_unregister(eth->mii_bus);
+       of_node_put(eth->mii_bus->dev.of_node);
+       kfree(eth->mii_bus);
+}
+
+static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask)
+{
+       u32 val;
+
+       val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+       mtk_w32(eth, val & ~mask, MTK_QDMA_INT_MASK);
+       /* flush write */
+       mtk_r32(eth, MTK_QDMA_INT_MASK);
+}
+
+static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask)
+{
+       u32 val;
+
+       val = mtk_r32(eth, MTK_QDMA_INT_MASK);
+       mtk_w32(eth, val | mask, MTK_QDMA_INT_MASK);
+       /* flush write */
+       mtk_r32(eth, MTK_QDMA_INT_MASK);
+}
+
+static int mtk_set_mac_address(struct net_device *dev, void *p)
+{
+       int ret = eth_mac_addr(dev, p);
+       struct mtk_mac *mac = netdev_priv(dev);
+       const char *macaddr = dev->dev_addr;
+       unsigned long flags;
+
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&mac->hw->page_lock, flags);
+       mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1],
+               MTK_GDMA_MAC_ADRH(mac->id));
+       mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) |
+               (macaddr[4] << 8) | macaddr[5],
+               MTK_GDMA_MAC_ADRL(mac->id));
+       spin_unlock_irqrestore(&mac->hw->page_lock, flags);
+
+       return 0;
+}
+
+void mtk_stats_update_mac(struct mtk_mac *mac)
+{
+       struct mtk_hw_stats *hw_stats = mac->hw_stats;
+       unsigned int base = MTK_GDM1_TX_GBCNT;
+       u64 stats;
+
+       base += hw_stats->reg_offset;
+
+       u64_stats_update_begin(&hw_stats->syncp);
+
+       hw_stats->rx_bytes += mtk_r32(mac->hw, base);
+       stats =  mtk_r32(mac->hw, base + 0x04);
+       if (stats)
+               hw_stats->rx_bytes += (stats << 32);
+       hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08);
+       hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10);
+       hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14);
+       hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18);
+       hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c);
+       hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20);
+       hw_stats->rx_flow_control_packets +=
+                                       mtk_r32(mac->hw, base + 0x24);
+       hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28);
+       hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c);
+       hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30);
+       stats =  mtk_r32(mac->hw, base + 0x34);
+       if (stats)
+               hw_stats->tx_bytes += (stats << 32);
+       hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38);
+       u64_stats_update_end(&hw_stats->syncp);
+}
+
+static void mtk_stats_update(struct mtk_eth *eth)
+{
+       int i;
+
+       for (i = 0; i < MTK_MAC_COUNT; i++) {
+               if (!eth->mac[i] || !eth->mac[i]->hw_stats)
+                       continue;
+               if (spin_trylock(&eth->mac[i]->hw_stats->stats_lock)) {
+                       mtk_stats_update_mac(eth->mac[i]);
+                       spin_unlock(&eth->mac[i]->hw_stats->stats_lock);
+               }
+       }
+}
+
+static struct rtnl_link_stats64 *mtk_get_stats64(struct net_device *dev,
+                                       struct rtnl_link_stats64 *storage)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_hw_stats *hw_stats = mac->hw_stats;
+       unsigned int start;
+
+       if (netif_running(dev) && netif_device_present(dev)) {
+               if (spin_trylock(&hw_stats->stats_lock)) {
+                       mtk_stats_update_mac(mac);
+                       spin_unlock(&hw_stats->stats_lock);
+               }
+       }
+
+       do {
+               start = u64_stats_fetch_begin_irq(&hw_stats->syncp);
+               storage->rx_packets = hw_stats->rx_packets;
+               storage->tx_packets = hw_stats->tx_packets;
+               storage->rx_bytes = hw_stats->rx_bytes;
+               storage->tx_bytes = hw_stats->tx_bytes;
+               storage->collisions = hw_stats->tx_collisions;
+               storage->rx_length_errors = hw_stats->rx_short_errors +
+                       hw_stats->rx_long_errors;
+               storage->rx_over_errors = hw_stats->rx_overflow;
+               storage->rx_crc_errors = hw_stats->rx_fcs_errors;
+               storage->rx_errors = hw_stats->rx_checksum_errors;
+               storage->tx_aborted_errors = hw_stats->tx_skip;
+       } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start));
+
+       storage->tx_errors = dev->stats.tx_errors;
+       storage->rx_dropped = dev->stats.rx_dropped;
+       storage->tx_dropped = dev->stats.tx_dropped;
+
+       return storage;
+}
+
+static inline int mtk_max_frag_size(int mtu)
+{
+       /* make sure buf_size will be at least MTK_MAX_RX_LENGTH */
+       if (mtu + MTK_RX_ETH_HLEN < MTK_MAX_RX_LENGTH)
+               mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
+
+       return SKB_DATA_ALIGN(MTK_RX_HLEN + mtu) +
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
+static inline int mtk_max_buf_size(int frag_size)
+{
+       int buf_size = frag_size - NET_SKB_PAD - NET_IP_ALIGN -
+                      SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       WARN_ON(buf_size < MTK_MAX_RX_LENGTH);
+
+       return buf_size;
+}
+
+static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd,
+                                  struct mtk_rx_dma *dma_rxd)
+{
+       rxd->rxd1 = READ_ONCE(dma_rxd->rxd1);
+       rxd->rxd2 = READ_ONCE(dma_rxd->rxd2);
+       rxd->rxd3 = READ_ONCE(dma_rxd->rxd3);
+       rxd->rxd4 = READ_ONCE(dma_rxd->rxd4);
+}
+
+/* the qdma core needs scratch memory to be setup */
+static int mtk_init_fq_dma(struct mtk_eth *eth)
+{
+       unsigned int phy_ring_head, phy_ring_tail;
+       int cnt = MTK_DMA_SIZE;
+       dma_addr_t dma_addr;
+       int i;
+
+       eth->scratch_ring = dma_alloc_coherent(eth->dev,
+                                              cnt * sizeof(struct mtk_tx_dma),
+                                              &phy_ring_head,
+                                              GFP_ATOMIC | __GFP_ZERO);
+       if (unlikely(!eth->scratch_ring))
+               return -ENOMEM;
+
+       eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE,
+                                   GFP_KERNEL);
+       dma_addr = dma_map_single(eth->dev,
+                                 eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
+                                 DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+               return -ENOMEM;
+
+       memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt);
+       phy_ring_tail = phy_ring_head +
+                       (sizeof(struct mtk_tx_dma) * (cnt - 1));
+
+       for (i = 0; i < cnt; i++) {
+               eth->scratch_ring[i].txd1 =
+                                       (dma_addr + (i * MTK_QDMA_PAGE_SIZE));
+               if (i < cnt - 1)
+                       eth->scratch_ring[i].txd2 = (phy_ring_head +
+                               ((i + 1) * sizeof(struct mtk_tx_dma)));
+               eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE);
+       }
+
+       mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD);
+       mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL);
+       mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT);
+       mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN);
+
+       return 0;
+}
+
+static inline void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc)
+{
+       void *ret = ring->dma;
+
+       return ret + (desc - ring->phys);
+}
+
+static inline struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring,
+                                                   struct mtk_tx_dma *txd)
+{
+       int idx = txd - ring->dma;
+
+       return &ring->buf[idx];
+}
+
+static void mtk_tx_unmap(struct device *dev, struct mtk_tx_buf *tx_buf)
+{
+       if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
+               dma_unmap_single(dev,
+                                dma_unmap_addr(tx_buf, dma_addr0),
+                                dma_unmap_len(tx_buf, dma_len0),
+                                DMA_TO_DEVICE);
+       } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
+               dma_unmap_page(dev,
+                              dma_unmap_addr(tx_buf, dma_addr0),
+                              dma_unmap_len(tx_buf, dma_len0),
+                              DMA_TO_DEVICE);
+       }
+       tx_buf->flags = 0;
+       if (tx_buf->skb &&
+           (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC))
+               dev_kfree_skb_any(tx_buf->skb);
+       tx_buf->skb = NULL;
+}
+
+static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev,
+                     int tx_num, struct mtk_tx_ring *ring, bool gso)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+       struct mtk_tx_dma *itxd, *txd;
+       struct mtk_tx_buf *tx_buf;
+       unsigned long flags;
+       dma_addr_t mapped_addr;
+       unsigned int nr_frags;
+       int i, n_desc = 1;
+       u32 txd4 = 0;
+
+       itxd = ring->next_free;
+       if (itxd == ring->last_free)
+               return -ENOMEM;
+
+       /* set the forward port */
+       txd4 |= (mac->id + 1) << TX_DMA_FPORT_SHIFT;
+
+       tx_buf = mtk_desc_to_tx_buf(ring, itxd);
+       memset(tx_buf, 0, sizeof(*tx_buf));
+
+       if (gso)
+               txd4 |= TX_DMA_TSO;
+
+       /* TX Checksum offload */
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               txd4 |= TX_DMA_CHKSUM;
+
+       /* VLAN header offload */
+       if (skb_vlan_tag_present(skb))
+               txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
+
+       mapped_addr = dma_map_single(&dev->dev, skb->data,
+                                    skb_headlen(skb), DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+               return -ENOMEM;
+
+       /* normally we can rely on the stack not calling this more than once,
+        * however we have 2 queues running ont he same ring so we need to lock
+        * the ring access
+        */
+       spin_lock_irqsave(&eth->page_lock, flags);
+       WRITE_ONCE(itxd->txd1, mapped_addr);
+       tx_buf->flags |= MTK_TX_FLAGS_SINGLE0;
+       dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+       dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb));
+
+       /* TX SG offload */
+       txd = itxd;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       for (i = 0; i < nr_frags; i++) {
+               struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+               unsigned int offset = 0;
+               int frag_size = skb_frag_size(frag);
+
+               while (frag_size) {
+                       bool last_frag = false;
+                       unsigned int frag_map_size;
+
+                       txd = mtk_qdma_phys_to_virt(ring, txd->txd2);
+                       if (txd == ring->last_free)
+                               goto err_dma;
+
+                       n_desc++;
+                       frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN);
+                       mapped_addr = skb_frag_dma_map(&dev->dev, frag, offset,
+                                                      frag_map_size,
+                                                      DMA_TO_DEVICE);
+                       if (unlikely(dma_mapping_error(&dev->dev, mapped_addr)))
+                               goto err_dma;
+
+                       if (i == nr_frags - 1 &&
+                           (frag_size - frag_map_size) == 0)
+                               last_frag = true;
+
+                       WRITE_ONCE(txd->txd1, mapped_addr);
+                       WRITE_ONCE(txd->txd3, (TX_DMA_SWC |
+                                              TX_DMA_PLEN0(frag_map_size) |
+                                              last_frag * TX_DMA_LS0) |
+                                              mac->id);
+                       WRITE_ONCE(txd->txd4, 0);
+
+                       tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC;
+                       tx_buf = mtk_desc_to_tx_buf(ring, txd);
+                       memset(tx_buf, 0, sizeof(*tx_buf));
+
+                       tx_buf->flags |= MTK_TX_FLAGS_PAGE0;
+                       dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr);
+                       dma_unmap_len_set(tx_buf, dma_len0, frag_map_size);
+                       frag_size -= frag_map_size;
+                       offset += frag_map_size;
+               }
+       }
+
+       /* store skb to cleanup */
+       tx_buf->skb = skb;
+
+       WRITE_ONCE(itxd->txd4, txd4);
+       WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) |
+                               (!nr_frags * TX_DMA_LS0)));
+
+       spin_unlock_irqrestore(&eth->page_lock, flags);
+
+       netdev_sent_queue(dev, skb->len);
+       skb_tx_timestamp(skb);
+
+       ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
+       atomic_sub(n_desc, &ring->free_count);
+
+       /* make sure that all changes to the dma ring are flushed before we
+        * continue
+        */
+       wmb();
+
+       if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more)
+               mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR);
+
+       return 0;
+
+err_dma:
+       do {
+               tx_buf = mtk_desc_to_tx_buf(ring, txd);
+
+               /* unmap dma */
+               mtk_tx_unmap(&dev->dev, tx_buf);
+
+               itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
+               itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2);
+       } while (itxd != txd);
+
+       return -ENOMEM;
+}
+
+static inline int mtk_cal_txd_req(struct sk_buff *skb)
+{
+       int i, nfrags;
+       struct skb_frag_struct *frag;
+
+       nfrags = 1;
+       if (skb_is_gso(skb)) {
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       frag = &skb_shinfo(skb)->frags[i];
+                       nfrags += DIV_ROUND_UP(frag->size, MTK_TX_DMA_BUF_LEN);
+               }
+       } else {
+               nfrags += skb_shinfo(skb)->nr_frags;
+       }
+
+       return DIV_ROUND_UP(nfrags, 2);
+}
+
+static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+       struct mtk_tx_ring *ring = &eth->tx_ring;
+       struct net_device_stats *stats = &dev->stats;
+       bool gso = false;
+       int tx_num;
+
+       tx_num = mtk_cal_txd_req(skb);
+       if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
+               netif_stop_queue(dev);
+               netif_err(eth, tx_queued, dev,
+                         "Tx Ring full when queue awake!\n");
+               return NETDEV_TX_BUSY;
+       }
+
+       /* TSO: fill MSS info in tcp checksum field */
+       if (skb_is_gso(skb)) {
+               if (skb_cow_head(skb, 0)) {
+                       netif_warn(eth, tx_err, dev,
+                                  "GSO expand head fail.\n");
+                       goto drop;
+               }
+
+               if (skb_shinfo(skb)->gso_type &
+                               (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+                       gso = true;
+                       tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size);
+               }
+       }
+
+       if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
+               goto drop;
+
+       if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) {
+               netif_stop_queue(dev);
+               if (unlikely(atomic_read(&ring->free_count) >
+                            ring->thresh))
+                       netif_wake_queue(dev);
+       }
+
+       return NETDEV_TX_OK;
+
+drop:
+       stats->tx_dropped++;
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static int mtk_poll_rx(struct napi_struct *napi, int budget,
+                      struct mtk_eth *eth, u32 rx_intr)
+{
+       struct mtk_rx_ring *ring = &eth->rx_ring;
+       int idx = ring->calc_idx;
+       struct sk_buff *skb;
+       u8 *data, *new_data;
+       struct mtk_rx_dma *rxd, trxd;
+       int done = 0;
+
+       while (done < budget) {
+               struct net_device *netdev;
+               unsigned int pktlen;
+               dma_addr_t dma_addr;
+               int mac = 0;
+
+               idx = NEXT_RX_DESP_IDX(idx);
+               rxd = &ring->dma[idx];
+               data = ring->data[idx];
+
+               mtk_rx_get_desc(&trxd, rxd);
+               if (!(trxd.rxd2 & RX_DMA_DONE))
+                       break;
+
+               /* find out which mac the packet come from. values start at 1 */
+               mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) &
+                     RX_DMA_FPORT_MASK;
+               mac--;
+
+               netdev = eth->netdev[mac];
+
+               /* alloc new buffer */
+               new_data = napi_alloc_frag(ring->frag_size);
+               if (unlikely(!new_data)) {
+                       netdev->stats.rx_dropped++;
+                       goto release_desc;
+               }
+               dma_addr = dma_map_single(&eth->netdev[mac]->dev,
+                                         new_data + NET_SKB_PAD,
+                                         ring->buf_size,
+                                         DMA_FROM_DEVICE);
+               if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) {
+                       skb_free_frag(new_data);
+                       goto release_desc;
+               }
+
+               /* receive data */
+               skb = build_skb(data, ring->frag_size);
+               if (unlikely(!skb)) {
+                       put_page(virt_to_head_page(new_data));
+                       goto release_desc;
+               }
+               skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+               dma_unmap_single(&netdev->dev, trxd.rxd1,
+                                ring->buf_size, DMA_FROM_DEVICE);
+               pktlen = RX_DMA_GET_PLEN0(trxd.rxd2);
+               skb->dev = netdev;
+               skb_put(skb, pktlen);
+               if (trxd.rxd4 & RX_DMA_L4_VALID)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb_checksum_none_assert(skb);
+               skb->protocol = eth_type_trans(skb, netdev);
+
+               if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
+                   RX_DMA_VID(trxd.rxd3))
+                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                              RX_DMA_VID(trxd.rxd3));
+               napi_gro_receive(napi, skb);
+
+               ring->data[idx] = new_data;
+               rxd->rxd1 = (unsigned int)dma_addr;
+
+release_desc:
+               rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size);
+
+               ring->calc_idx = idx;
+               /* make sure that all changes to the dma ring are flushed before
+                * we continue
+                */
+               wmb();
+               mtk_w32(eth, ring->calc_idx, MTK_QRX_CRX_IDX0);
+               done++;
+       }
+
+       if (done < budget)
+               mtk_w32(eth, rx_intr, MTK_QMTK_INT_STATUS);
+
+       return done;
+}
+
+static int mtk_poll_tx(struct mtk_eth *eth, int budget, bool *tx_again)
+{
+       struct mtk_tx_ring *ring = &eth->tx_ring;
+       struct mtk_tx_dma *desc;
+       struct sk_buff *skb;
+       struct mtk_tx_buf *tx_buf;
+       int total = 0, done[MTK_MAX_DEVS];
+       unsigned int bytes[MTK_MAX_DEVS];
+       u32 cpu, dma;
+       static int condition;
+       int i;
+
+       memset(done, 0, sizeof(done));
+       memset(bytes, 0, sizeof(bytes));
+
+       cpu = mtk_r32(eth, MTK_QTX_CRX_PTR);
+       dma = mtk_r32(eth, MTK_QTX_DRX_PTR);
+
+       desc = mtk_qdma_phys_to_virt(ring, cpu);
+
+       while ((cpu != dma) && budget) {
+               u32 next_cpu = desc->txd2;
+               int mac;
+
+               desc = mtk_qdma_phys_to_virt(ring, desc->txd2);
+               if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0)
+                       break;
+
+               mac = (desc->txd4 >> TX_DMA_FPORT_SHIFT) &
+                      TX_DMA_FPORT_MASK;
+               mac--;
+
+               tx_buf = mtk_desc_to_tx_buf(ring, desc);
+               skb = tx_buf->skb;
+               if (!skb) {
+                       condition = 1;
+                       break;
+               }
+
+               if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) {
+                       bytes[mac] += skb->len;
+                       done[mac]++;
+                       budget--;
+               }
+               mtk_tx_unmap(eth->dev, tx_buf);
+
+               ring->last_free->txd2 = next_cpu;
+               ring->last_free = desc;
+               atomic_inc(&ring->free_count);
+
+               cpu = next_cpu;
+       }
+
+       mtk_w32(eth, cpu, MTK_QTX_CRX_PTR);
+
+       for (i = 0; i < MTK_MAC_COUNT; i++) {
+               if (!eth->netdev[i] || !done[i])
+                       continue;
+               netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
+               total += done[i];
+       }
+
+       /* read hw index again make sure no new tx packet */
+       if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR))
+               *tx_again = true;
+       else
+               mtk_w32(eth, MTK_TX_DONE_INT, MTK_QMTK_INT_STATUS);
+
+       if (!total)
+               return 0;
+
+       for (i = 0; i < MTK_MAC_COUNT; i++) {
+               if (!eth->netdev[i] ||
+                   unlikely(!netif_queue_stopped(eth->netdev[i])))
+                       continue;
+               if (atomic_read(&ring->free_count) > ring->thresh)
+                       netif_wake_queue(eth->netdev[i]);
+       }
+
+       return total;
+}
+
+static int mtk_poll(struct napi_struct *napi, int budget)
+{
+       struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi);
+       u32 status, status2, mask, tx_intr, rx_intr, status_intr;
+       int tx_done, rx_done;
+       bool tx_again = false;
+
+       status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+       status2 = mtk_r32(eth, MTK_INT_STATUS2);
+       tx_intr = MTK_TX_DONE_INT;
+       rx_intr = MTK_RX_DONE_INT;
+       status_intr = (MTK_GDM1_AF | MTK_GDM2_AF);
+       tx_done = 0;
+       rx_done = 0;
+       tx_again = 0;
+
+       if (status & tx_intr)
+               tx_done = mtk_poll_tx(eth, budget, &tx_again);
+
+       if (status & rx_intr)
+               rx_done = mtk_poll_rx(napi, budget, eth, rx_intr);
+
+       if (unlikely(status2 & status_intr)) {
+               mtk_stats_update(eth);
+               mtk_w32(eth, status_intr, MTK_INT_STATUS2);
+       }
+
+       if (unlikely(netif_msg_intr(eth))) {
+               mask = mtk_r32(eth, MTK_QDMA_INT_MASK);
+               netdev_info(eth->netdev[0],
+                           "done tx %d, rx %d, intr 0x%08x/0x%x\n",
+                           tx_done, rx_done, status, mask);
+       }
+
+       if (tx_again || rx_done == budget)
+               return budget;
+
+       status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+       if (status & (tx_intr | rx_intr))
+               return budget;
+
+       napi_complete(napi);
+       mtk_irq_enable(eth, tx_intr | rx_intr);
+
+       return rx_done;
+}
+
+static int mtk_tx_alloc(struct mtk_eth *eth)
+{
+       struct mtk_tx_ring *ring = &eth->tx_ring;
+       int i, sz = sizeof(*ring->dma);
+
+       ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf),
+                              GFP_KERNEL);
+       if (!ring->buf)
+               goto no_tx_mem;
+
+       ring->dma = dma_alloc_coherent(eth->dev,
+                                         MTK_DMA_SIZE * sz,
+                                         &ring->phys,
+                                         GFP_ATOMIC | __GFP_ZERO);
+       if (!ring->dma)
+               goto no_tx_mem;
+
+       memset(ring->dma, 0, MTK_DMA_SIZE * sz);
+       for (i = 0; i < MTK_DMA_SIZE; i++) {
+               int next = (i + 1) % MTK_DMA_SIZE;
+               u32 next_ptr = ring->phys + next * sz;
+
+               ring->dma[i].txd2 = next_ptr;
+               ring->dma[i].txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU;
+       }
+
+       atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
+       ring->next_free = &ring->dma[0];
+       ring->last_free = &ring->dma[MTK_DMA_SIZE - 2];
+       ring->thresh = max((unsigned long)MTK_DMA_SIZE >> 2,
+                             MAX_SKB_FRAGS);
+
+       /* make sure that all changes to the dma ring are flushed before we
+        * continue
+        */
+       wmb();
+
+       mtk_w32(eth, ring->phys, MTK_QTX_CTX_PTR);
+       mtk_w32(eth, ring->phys, MTK_QTX_DTX_PTR);
+       mtk_w32(eth,
+               ring->phys + ((MTK_DMA_SIZE - 1) * sz),
+               MTK_QTX_CRX_PTR);
+       mtk_w32(eth,
+               ring->phys + ((MTK_DMA_SIZE - 1) * sz),
+               MTK_QTX_DRX_PTR);
+
+       return 0;
+
+no_tx_mem:
+       return -ENOMEM;
+}
+
+static void mtk_tx_clean(struct mtk_eth *eth)
+{
+       struct mtk_tx_ring *ring = &eth->tx_ring;
+       int i;
+
+       if (ring->buf) {
+               for (i = 0; i < MTK_DMA_SIZE; i++)
+                       mtk_tx_unmap(eth->dev, &ring->buf[i]);
+               kfree(ring->buf);
+               ring->buf = NULL;
+       }
+
+       if (ring->dma) {
+               dma_free_coherent(eth->dev,
+                                 MTK_DMA_SIZE * sizeof(*ring->dma),
+                                 ring->dma,
+                                 ring->phys);
+               ring->dma = NULL;
+       }
+}
+
+static int mtk_rx_alloc(struct mtk_eth *eth)
+{
+       struct mtk_rx_ring *ring = &eth->rx_ring;
+       int i;
+
+       ring->frag_size = mtk_max_frag_size(ETH_DATA_LEN);
+       ring->buf_size = mtk_max_buf_size(ring->frag_size);
+       ring->data = kcalloc(MTK_DMA_SIZE, sizeof(*ring->data),
+                            GFP_KERNEL);
+       if (!ring->data)
+               return -ENOMEM;
+
+       for (i = 0; i < MTK_DMA_SIZE; i++) {
+               ring->data[i] = netdev_alloc_frag(ring->frag_size);
+               if (!ring->data[i])
+                       return -ENOMEM;
+       }
+
+       ring->dma = dma_alloc_coherent(eth->dev,
+                                      MTK_DMA_SIZE * sizeof(*ring->dma),
+                                      &ring->phys,
+                                      GFP_ATOMIC | __GFP_ZERO);
+       if (!ring->dma)
+               return -ENOMEM;
+
+       for (i = 0; i < MTK_DMA_SIZE; i++) {
+               dma_addr_t dma_addr = dma_map_single(eth->dev,
+                               ring->data[i] + NET_SKB_PAD,
+                               ring->buf_size,
+                               DMA_FROM_DEVICE);
+               if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
+                       return -ENOMEM;
+               ring->dma[i].rxd1 = (unsigned int)dma_addr;
+
+               ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size);
+       }
+       ring->calc_idx = MTK_DMA_SIZE - 1;
+       /* make sure that all changes to the dma ring are flushed before we
+        * continue
+        */
+       wmb();
+
+       mtk_w32(eth, eth->rx_ring.phys, MTK_QRX_BASE_PTR0);
+       mtk_w32(eth, MTK_DMA_SIZE, MTK_QRX_MAX_CNT0);
+       mtk_w32(eth, eth->rx_ring.calc_idx, MTK_QRX_CRX_IDX0);
+       mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX);
+       mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0));
+
+       return 0;
+}
+
+static void mtk_rx_clean(struct mtk_eth *eth)
+{
+       struct mtk_rx_ring *ring = &eth->rx_ring;
+       int i;
+
+       if (ring->data && ring->dma) {
+               for (i = 0; i < MTK_DMA_SIZE; i++) {
+                       if (!ring->data[i])
+                               continue;
+                       if (!ring->dma[i].rxd1)
+                               continue;
+                       dma_unmap_single(eth->dev,
+                                        ring->dma[i].rxd1,
+                                        ring->buf_size,
+                                        DMA_FROM_DEVICE);
+                       skb_free_frag(ring->data[i]);
+               }
+               kfree(ring->data);
+               ring->data = NULL;
+       }
+
+       if (ring->dma) {
+               dma_free_coherent(eth->dev,
+                                 MTK_DMA_SIZE * sizeof(*ring->dma),
+                                 ring->dma,
+                                 ring->phys);
+               ring->dma = NULL;
+       }
+}
+
+/* wait for DMA to finish whatever it is doing before we start using it again */
+static int mtk_dma_busy_wait(struct mtk_eth *eth)
+{
+       unsigned long t_start = jiffies;
+
+       while (1) {
+               if (!(mtk_r32(eth, MTK_QDMA_GLO_CFG) &
+                     (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)))
+                       return 0;
+               if (time_after(jiffies, t_start + MTK_DMA_BUSY_TIMEOUT))
+                       break;
+       }
+
+       dev_err(eth->dev, "DMA init timeout\n");
+       return -1;
+}
+
+static int mtk_dma_init(struct mtk_eth *eth)
+{
+       int err;
+
+       if (mtk_dma_busy_wait(eth))
+               return -EBUSY;
+
+       /* QDMA needs scratch memory for internal reordering of the
+        * descriptors
+        */
+       err = mtk_init_fq_dma(eth);
+       if (err)
+               return err;
+
+       err = mtk_tx_alloc(eth);
+       if (err)
+               return err;
+
+       err = mtk_rx_alloc(eth);
+       if (err)
+               return err;
+
+       /* Enable random early drop and set drop threshold automatically */
+       mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | FC_THRES_MIN,
+               MTK_QDMA_FC_THRES);
+       mtk_w32(eth, 0x0, MTK_QDMA_HRED2);
+
+       return 0;
+}
+
+static void mtk_dma_free(struct mtk_eth *eth)
+{
+       int i;
+
+       for (i = 0; i < MTK_MAC_COUNT; i++)
+               if (eth->netdev[i])
+                       netdev_reset_queue(eth->netdev[i]);
+       mtk_tx_clean(eth);
+       mtk_rx_clean(eth);
+       kfree(eth->scratch_head);
+}
+
+static void mtk_tx_timeout(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+
+       eth->netdev[mac->id]->stats.tx_errors++;
+       netif_err(eth, tx_err, dev,
+                 "transmit timed out\n");
+       schedule_work(&mac->pending_work);
+}
+
+static irqreturn_t mtk_handle_irq(int irq, void *_eth)
+{
+       struct mtk_eth *eth = _eth;
+       u32 status;
+
+       status = mtk_r32(eth, MTK_QMTK_INT_STATUS);
+       if (unlikely(!status))
+               return IRQ_NONE;
+
+       if (likely(status & (MTK_RX_DONE_INT | MTK_TX_DONE_INT))) {
+               if (likely(napi_schedule_prep(&eth->rx_napi)))
+                       __napi_schedule(&eth->rx_napi);
+       } else {
+               mtk_w32(eth, status, MTK_QMTK_INT_STATUS);
+       }
+       mtk_irq_disable(eth, (MTK_RX_DONE_INT | MTK_TX_DONE_INT));
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void mtk_poll_controller(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+       u32 int_mask = MTK_TX_DONE_INT | MTK_RX_DONE_INT;
+
+       mtk_irq_disable(eth, int_mask);
+       mtk_handle_irq(dev->irq, dev);
+       mtk_irq_enable(eth, int_mask);
+}
+#endif
+
+static int mtk_start_dma(struct mtk_eth *eth)
+{
+       int err;
+
+       err = mtk_dma_init(eth);
+       if (err) {
+               mtk_dma_free(eth);
+               return err;
+       }
+
+       mtk_w32(eth,
+               MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN |
+               MTK_RX_2B_OFFSET | MTK_DMA_SIZE_16DWORDS |
+               MTK_RX_BT_32DWORDS,
+               MTK_QDMA_GLO_CFG);
+
+       return 0;
+}
+
+static int mtk_open(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+
+       /* we run 2 netdevs on the same dma ring so we only bring it up once */
+       if (!atomic_read(&eth->dma_refcnt)) {
+               int err = mtk_start_dma(eth);
+
+               if (err)
+                       return err;
+
+               napi_enable(&eth->rx_napi);
+               mtk_irq_enable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+       }
+       atomic_inc(&eth->dma_refcnt);
+
+       phy_start(mac->phy_dev);
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg)
+{
+       unsigned long flags;
+       u32 val;
+       int i;
+
+       /* stop the dma engine */
+       spin_lock_irqsave(&eth->page_lock, flags);
+       val = mtk_r32(eth, glo_cfg);
+       mtk_w32(eth, val & ~(MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN),
+               glo_cfg);
+       spin_unlock_irqrestore(&eth->page_lock, flags);
+
+       /* wait for dma stop */
+       for (i = 0; i < 10; i++) {
+               val = mtk_r32(eth, glo_cfg);
+               if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) {
+                       msleep(20);
+                       continue;
+               }
+               break;
+       }
+}
+
+static int mtk_stop(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+
+       netif_tx_disable(dev);
+       phy_stop(mac->phy_dev);
+
+       /* only shutdown DMA if this is the last user */
+       if (!atomic_dec_and_test(&eth->dma_refcnt))
+               return 0;
+
+       mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+       napi_disable(&eth->rx_napi);
+
+       mtk_stop_dma(eth, MTK_QDMA_GLO_CFG);
+
+       mtk_dma_free(eth);
+
+       return 0;
+}
+
+static int __init mtk_hw_init(struct mtk_eth *eth)
+{
+       int err, i;
+
+       /* reset the frame engine */
+       reset_control_assert(eth->rstc);
+       usleep_range(10, 20);
+       reset_control_deassert(eth->rstc);
+       usleep_range(10, 20);
+
+       /* Set GE2 driving and slew rate */
+       regmap_write(eth->pctl, GPIO_DRV_SEL10, 0xa00);
+
+       /* set GE2 TDSEL */
+       regmap_write(eth->pctl, GPIO_OD33_CTRL8, 0x5);
+
+       /* set GE2 TUNE */
+       regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0);
+
+       /* GE1, Force 1000M/FD, FC ON */
+       mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0));
+
+       /* GE2, Force 1000M/FD, FC ON */
+       mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1));
+
+       /* Enable RX VLan Offloading */
+       mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
+
+       err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0,
+                              dev_name(eth->dev), eth);
+       if (err)
+               return err;
+
+       err = mtk_mdio_init(eth);
+       if (err)
+               return err;
+
+       /* disable delay and normal interrupt */
+       mtk_w32(eth, 0, MTK_QDMA_DELAY_INT);
+       mtk_irq_disable(eth, MTK_TX_DONE_INT | MTK_RX_DONE_INT);
+       mtk_w32(eth, RST_GL_PSE, MTK_RST_GL);
+       mtk_w32(eth, 0, MTK_RST_GL);
+
+       /* FE int grouping */
+       mtk_w32(eth, 0, MTK_FE_INT_GRP);
+
+       for (i = 0; i < 2; i++) {
+               u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i));
+
+               /* setup the forward port to send frame to QDMA */
+               val &= ~0xffff;
+               val |= 0x5555;
+
+               /* Enable RX checksum */
+               val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN;
+
+               /* setup the mac dma */
+               mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i));
+       }
+
+       return 0;
+}
+
+static int __init mtk_init(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+       const char *mac_addr;
+
+       mac_addr = of_get_mac_address(mac->of_node);
+       if (mac_addr)
+               ether_addr_copy(dev->dev_addr, mac_addr);
+
+       /* If the mac address is invalid, use random mac address  */
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               random_ether_addr(dev->dev_addr);
+               dev_err(eth->dev, "generated random MAC address %pM\n",
+                       dev->dev_addr);
+               dev->addr_assign_type = NET_ADDR_RANDOM;
+       }
+
+       return mtk_phy_connect(mac);
+}
+
+static void mtk_uninit(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_eth *eth = mac->hw;
+
+       phy_disconnect(mac->phy_dev);
+       mtk_mdio_cleanup(eth);
+       mtk_irq_disable(eth, ~0);
+       free_irq(dev->irq, dev);
+}
+
+static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               return phy_mii_ioctl(mac->phy_dev, ifr, cmd);
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static void mtk_pending_work(struct work_struct *work)
+{
+       struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work);
+       struct mtk_eth *eth = mac->hw;
+       struct net_device *dev = eth->netdev[mac->id];
+       int err;
+
+       rtnl_lock();
+       mtk_stop(dev);
+
+       err = mtk_open(dev);
+       if (err) {
+               netif_alert(eth, ifup, dev,
+                           "Driver up/down cycle failed, closing device.\n");
+               dev_close(dev);
+       }
+       rtnl_unlock();
+}
+
+static int mtk_cleanup(struct mtk_eth *eth)
+{
+       int i;
+
+       for (i = 0; i < MTK_MAC_COUNT; i++) {
+               struct mtk_mac *mac = netdev_priv(eth->netdev[i]);
+
+               if (!eth->netdev[i])
+                       continue;
+
+               unregister_netdev(eth->netdev[i]);
+               free_netdev(eth->netdev[i]);
+               cancel_work_sync(&mac->pending_work);
+       }
+
+       return 0;
+}
+
+static int mtk_get_settings(struct net_device *dev,
+                           struct ethtool_cmd *cmd)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       int err;
+
+       err = phy_read_status(mac->phy_dev);
+       if (err)
+               return -ENODEV;
+
+       return phy_ethtool_gset(mac->phy_dev, cmd);
+}
+
+static int mtk_set_settings(struct net_device *dev,
+                           struct ethtool_cmd *cmd)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       if (cmd->phy_address != mac->phy_dev->mdio.addr) {
+               mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
+                                              cmd->phy_address);
+               if (!mac->phy_dev)
+                       return -ENODEV;
+       }
+
+       return phy_ethtool_sset(mac->phy_dev, cmd);
+}
+
+static void mtk_get_drvinfo(struct net_device *dev,
+                           struct ethtool_drvinfo *info)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
+       strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
+       info->n_stats = ARRAY_SIZE(mtk_ethtool_stats);
+}
+
+static u32 mtk_get_msglevel(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       return mac->hw->msg_enable;
+}
+
+static void mtk_set_msglevel(struct net_device *dev, u32 value)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       mac->hw->msg_enable = value;
+}
+
+static int mtk_nway_reset(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+
+       return genphy_restart_aneg(mac->phy_dev);
+}
+
+static u32 mtk_get_link(struct net_device *dev)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       int err;
+
+       err = genphy_update_link(mac->phy_dev);
+       if (err)
+               return ethtool_op_get_link(dev);
+
+       return mac->phy_dev->link;
+}
+
+static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) {
+                       memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static int mtk_get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(mtk_ethtool_stats);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void mtk_get_ethtool_stats(struct net_device *dev,
+                                 struct ethtool_stats *stats, u64 *data)
+{
+       struct mtk_mac *mac = netdev_priv(dev);
+       struct mtk_hw_stats *hwstats = mac->hw_stats;
+       u64 *data_src, *data_dst;
+       unsigned int start;
+       int i;
+
+       if (netif_running(dev) && netif_device_present(dev)) {
+               if (spin_trylock(&hwstats->stats_lock)) {
+                       mtk_stats_update_mac(mac);
+                       spin_unlock(&hwstats->stats_lock);
+               }
+       }
+
+       do {
+               data_src = (u64*)hwstats;
+               data_dst = data;
+               start = u64_stats_fetch_begin_irq(&hwstats->syncp);
+
+               for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++)
+                       *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset);
+       } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
+}
+
+static struct ethtool_ops mtk_ethtool_ops = {
+       .get_settings           = mtk_get_settings,
+       .set_settings           = mtk_set_settings,
+       .get_drvinfo            = mtk_get_drvinfo,
+       .get_msglevel           = mtk_get_msglevel,
+       .set_msglevel           = mtk_set_msglevel,
+       .nway_reset             = mtk_nway_reset,
+       .get_link               = mtk_get_link,
+       .get_strings            = mtk_get_strings,
+       .get_sset_count         = mtk_get_sset_count,
+       .get_ethtool_stats      = mtk_get_ethtool_stats,
+};
+
+static const struct net_device_ops mtk_netdev_ops = {
+       .ndo_init               = mtk_init,
+       .ndo_uninit             = mtk_uninit,
+       .ndo_open               = mtk_open,
+       .ndo_stop               = mtk_stop,
+       .ndo_start_xmit         = mtk_start_xmit,
+       .ndo_set_mac_address    = mtk_set_mac_address,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = mtk_do_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_tx_timeout         = mtk_tx_timeout,
+       .ndo_get_stats64        = mtk_get_stats64,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = mtk_poll_controller,
+#endif
+};
+
+static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
+{
+       struct mtk_mac *mac;
+       const __be32 *_id = of_get_property(np, "reg", NULL);
+       int id, err;
+
+       if (!_id) {
+               dev_err(eth->dev, "missing mac id\n");
+               return -EINVAL;
+       }
+
+       id = be32_to_cpup(_id);
+       if (id >= MTK_MAC_COUNT) {
+               dev_err(eth->dev, "%d is not a valid mac id\n", id);
+               return -EINVAL;
+       }
+
+       if (eth->netdev[id]) {
+               dev_err(eth->dev, "duplicate mac id found: %d\n", id);
+               return -EINVAL;
+       }
+
+       eth->netdev[id] = alloc_etherdev(sizeof(*mac));
+       if (!eth->netdev[id]) {
+               dev_err(eth->dev, "alloc_etherdev failed\n");
+               return -ENOMEM;
+       }
+       mac = netdev_priv(eth->netdev[id]);
+       eth->mac[id] = mac;
+       mac->id = id;
+       mac->hw = eth;
+       mac->of_node = np;
+       INIT_WORK(&mac->pending_work, mtk_pending_work);
+
+       mac->hw_stats = devm_kzalloc(eth->dev,
+                                    sizeof(*mac->hw_stats),
+                                    GFP_KERNEL);
+       if (!mac->hw_stats) {
+               dev_err(eth->dev, "failed to allocate counter memory\n");
+               err = -ENOMEM;
+               goto free_netdev;
+       }
+       spin_lock_init(&mac->hw_stats->stats_lock);
+       mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET;
+
+       SET_NETDEV_DEV(eth->netdev[id], eth->dev);
+       eth->netdev[id]->netdev_ops = &mtk_netdev_ops;
+       eth->netdev[id]->base_addr = (unsigned long)eth->base;
+       eth->netdev[id]->vlan_features = MTK_HW_FEATURES &
+               ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
+       eth->netdev[id]->features |= MTK_HW_FEATURES;
+       eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
+
+       err = register_netdev(eth->netdev[id]);
+       if (err) {
+               dev_err(eth->dev, "error bringing up device\n");
+               goto free_netdev;
+       }
+       eth->netdev[id]->irq = eth->irq;
+       netif_info(eth, probe, eth->netdev[id],
+                  "mediatek frame engine at 0x%08lx, irq %d\n",
+                  eth->netdev[id]->base_addr, eth->netdev[id]->irq);
+
+       return 0;
+
+free_netdev:
+       free_netdev(eth->netdev[id]);
+       return err;
+}
+
+static int mtk_probe(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct device_node *mac_np;
+       const struct of_device_id *match;
+       struct mtk_soc_data *soc;
+       struct mtk_eth *eth;
+       int err;
+
+       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+       pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+       device_reset(&pdev->dev);
+
+       match = of_match_device(of_mtk_match, &pdev->dev);
+       soc = (struct mtk_soc_data *)match->data;
+
+       eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL);
+       if (!eth)
+               return -ENOMEM;
+
+       eth->base = devm_ioremap_resource(&pdev->dev, res);
+       if (!eth->base)
+               return -EADDRNOTAVAIL;
+
+       spin_lock_init(&eth->page_lock);
+
+       eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                     "mediatek,ethsys");
+       if (IS_ERR(eth->ethsys)) {
+               dev_err(&pdev->dev, "no ethsys regmap found\n");
+               return PTR_ERR(eth->ethsys);
+       }
+
+       eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                   "mediatek,pctl");
+       if (IS_ERR(eth->pctl)) {
+               dev_err(&pdev->dev, "no pctl regmap found\n");
+               return PTR_ERR(eth->pctl);
+       }
+
+       eth->rstc = devm_reset_control_get(&pdev->dev, "eth");
+       if (IS_ERR(eth->rstc)) {
+               dev_err(&pdev->dev, "no eth reset found\n");
+               return PTR_ERR(eth->rstc);
+       }
+
+       eth->irq = platform_get_irq(pdev, 0);
+       if (eth->irq < 0) {
+               dev_err(&pdev->dev, "no IRQ resource found\n");
+               return -ENXIO;
+       }
+
+       eth->clk_ethif = devm_clk_get(&pdev->dev, "ethif");
+       eth->clk_esw = devm_clk_get(&pdev->dev, "esw");
+       eth->clk_gp1 = devm_clk_get(&pdev->dev, "gp1");
+       eth->clk_gp2 = devm_clk_get(&pdev->dev, "gp2");
+       if (IS_ERR(eth->clk_esw) || IS_ERR(eth->clk_gp1) ||
+           IS_ERR(eth->clk_gp2) || IS_ERR(eth->clk_ethif))
+               return -ENODEV;
+
+       clk_prepare_enable(eth->clk_ethif);
+       clk_prepare_enable(eth->clk_esw);
+       clk_prepare_enable(eth->clk_gp1);
+       clk_prepare_enable(eth->clk_gp2);
+
+       eth->dev = &pdev->dev;
+       eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE);
+
+       err = mtk_hw_init(eth);
+       if (err)
+               return err;
+
+       for_each_child_of_node(pdev->dev.of_node, mac_np) {
+               if (!of_device_is_compatible(mac_np,
+                                            "mediatek,eth-mac"))
+                       continue;
+
+               if (!of_device_is_available(mac_np))
+                       continue;
+
+               err = mtk_add_mac(eth, mac_np);
+               if (err)
+                       goto err_free_dev;
+       }
+
+       /* we run 2 devices on the same DMA ring so we need a dummy device
+        * for NAPI to work
+        */
+       init_dummy_netdev(&eth->dummy_dev);
+       netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_poll,
+                      MTK_NAPI_WEIGHT);
+
+       platform_set_drvdata(pdev, eth);
+
+       return 0;
+
+err_free_dev:
+       mtk_cleanup(eth);
+       return err;
+}
+
+static int mtk_remove(struct platform_device *pdev)
+{
+       struct mtk_eth *eth = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(eth->clk_ethif);
+       clk_disable_unprepare(eth->clk_esw);
+       clk_disable_unprepare(eth->clk_gp1);
+       clk_disable_unprepare(eth->clk_gp2);
+
+       netif_napi_del(&eth->rx_napi);
+       mtk_cleanup(eth);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+const struct of_device_id of_mtk_match[] = {
+       { .compatible = "mediatek,mt7623-eth" },
+       {},
+};
+
+static struct platform_driver mtk_driver = {
+       .probe = mtk_probe,
+       .remove = mtk_remove,
+       .driver = {
+               .name = "mtk_soc_eth",
+               .owner = THIS_MODULE,
+               .of_match_table = of_mtk_match,
+       },
+};
+
+module_platform_driver(mtk_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC");
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
new file mode 100644 (file)
index 0000000..48a5292
--- /dev/null
@@ -0,0 +1,421 @@
+/*   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; version 2 of the License
+ *
+ *   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.
+ *
+ *   Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org>
+ *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
+ *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
+ */
+
+#ifndef MTK_ETH_H
+#define MTK_ETH_H
+
+#define MTK_QDMA_PAGE_SIZE     2048
+#define        MTK_MAX_RX_LENGTH       1536
+#define MTK_TX_DMA_BUF_LEN     0x3fff
+#define MTK_DMA_SIZE           256
+#define MTK_NAPI_WEIGHT                64
+#define MTK_MAC_COUNT          2
+#define MTK_RX_ETH_HLEN                (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)
+#define MTK_RX_HLEN            (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
+#define MTK_DMA_DUMMY_DESC     0xffffffff
+#define MTK_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \
+                                NETIF_MSG_PROBE | \
+                                NETIF_MSG_LINK | \
+                                NETIF_MSG_TIMER | \
+                                NETIF_MSG_IFDOWN | \
+                                NETIF_MSG_IFUP | \
+                                NETIF_MSG_RX_ERR | \
+                                NETIF_MSG_TX_ERR)
+#define MTK_HW_FEATURES                (NETIF_F_IP_CSUM | \
+                                NETIF_F_RXCSUM | \
+                                NETIF_F_HW_VLAN_CTAG_TX | \
+                                NETIF_F_HW_VLAN_CTAG_RX | \
+                                NETIF_F_SG | NETIF_F_TSO | \
+                                NETIF_F_TSO6 | \
+                                NETIF_F_IPV6_CSUM)
+#define NEXT_RX_DESP_IDX(X)    (((X) + 1) & (MTK_DMA_SIZE - 1))
+
+/* Frame Engine Global Reset Register */
+#define MTK_RST_GL             0x04
+#define RST_GL_PSE             BIT(0)
+
+/* Frame Engine Interrupt Status Register */
+#define MTK_INT_STATUS2                0x08
+#define MTK_GDM1_AF            BIT(28)
+#define MTK_GDM2_AF            BIT(29)
+
+/* Frame Engine Interrupt Grouping Register */
+#define MTK_FE_INT_GRP         0x20
+
+/* CDMP Exgress Control Register */
+#define MTK_CDMP_EG_CTRL       0x404
+
+/* GDM Exgress Control Register */
+#define MTK_GDMA_FWD_CFG(x)    (0x500 + (x * 0x1000))
+#define MTK_GDMA_ICS_EN                BIT(22)
+#define MTK_GDMA_TCS_EN                BIT(21)
+#define MTK_GDMA_UCS_EN                BIT(20)
+
+/* Unicast Filter MAC Address Register - Low */
+#define MTK_GDMA_MAC_ADRL(x)   (0x508 + (x * 0x1000))
+
+/* Unicast Filter MAC Address Register - High */
+#define MTK_GDMA_MAC_ADRH(x)   (0x50C + (x * 0x1000))
+
+/* QDMA TX Queue Configuration Registers */
+#define MTK_QTX_CFG(x)         (0x1800 + (x * 0x10))
+#define QDMA_RES_THRES         4
+
+/* QDMA TX Queue Scheduler Registers */
+#define MTK_QTX_SCH(x)         (0x1804 + (x * 0x10))
+
+/* QDMA RX Base Pointer Register */
+#define MTK_QRX_BASE_PTR0      0x1900
+
+/* QDMA RX Maximum Count Register */
+#define MTK_QRX_MAX_CNT0       0x1904
+
+/* QDMA RX CPU Pointer Register */
+#define MTK_QRX_CRX_IDX0       0x1908
+
+/* QDMA RX DMA Pointer Register */
+#define MTK_QRX_DRX_IDX0       0x190C
+
+/* QDMA Global Configuration Register */
+#define MTK_QDMA_GLO_CFG       0x1A04
+#define MTK_RX_2B_OFFSET       BIT(31)
+#define MTK_RX_BT_32DWORDS     (3 << 11)
+#define MTK_TX_WB_DDONE                BIT(6)
+#define MTK_DMA_SIZE_16DWORDS  (2 << 4)
+#define MTK_RX_DMA_BUSY                BIT(3)
+#define MTK_TX_DMA_BUSY                BIT(1)
+#define MTK_RX_DMA_EN          BIT(2)
+#define MTK_TX_DMA_EN          BIT(0)
+#define MTK_DMA_BUSY_TIMEOUT   HZ
+
+/* QDMA Reset Index Register */
+#define MTK_QDMA_RST_IDX       0x1A08
+#define MTK_PST_DRX_IDX0       BIT(16)
+
+/* QDMA Delay Interrupt Register */
+#define MTK_QDMA_DELAY_INT     0x1A0C
+
+/* QDMA Flow Control Register */
+#define MTK_QDMA_FC_THRES      0x1A10
+#define FC_THRES_DROP_MODE     BIT(20)
+#define FC_THRES_DROP_EN       (7 << 16)
+#define FC_THRES_MIN           0x4444
+
+/* QDMA Interrupt Status Register */
+#define MTK_QMTK_INT_STATUS    0x1A18
+#define MTK_RX_DONE_INT1       BIT(17)
+#define MTK_RX_DONE_INT0       BIT(16)
+#define MTK_TX_DONE_INT3       BIT(3)
+#define MTK_TX_DONE_INT2       BIT(2)
+#define MTK_TX_DONE_INT1       BIT(1)
+#define MTK_TX_DONE_INT0       BIT(0)
+#define MTK_RX_DONE_INT                (MTK_RX_DONE_INT0 | MTK_RX_DONE_INT1)
+#define MTK_TX_DONE_INT                (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \
+                                MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3)
+
+/* QDMA Interrupt Status Register */
+#define MTK_QDMA_INT_MASK      0x1A1C
+
+/* QDMA Interrupt Mask Register */
+#define MTK_QDMA_HRED2         0x1A44
+
+/* QDMA TX Forward CPU Pointer Register */
+#define MTK_QTX_CTX_PTR                0x1B00
+
+/* QDMA TX Forward DMA Pointer Register */
+#define MTK_QTX_DTX_PTR                0x1B04
+
+/* QDMA TX Release CPU Pointer Register */
+#define MTK_QTX_CRX_PTR                0x1B10
+
+/* QDMA TX Release DMA Pointer Register */
+#define MTK_QTX_DRX_PTR                0x1B14
+
+/* QDMA FQ Head Pointer Register */
+#define MTK_QDMA_FQ_HEAD       0x1B20
+
+/* QDMA FQ Head Pointer Register */
+#define MTK_QDMA_FQ_TAIL       0x1B24
+
+/* QDMA FQ Free Page Counter Register */
+#define MTK_QDMA_FQ_CNT                0x1B28
+
+/* QDMA FQ Free Page Buffer Length Register */
+#define MTK_QDMA_FQ_BLEN       0x1B2C
+
+/* GMA1 Received Good Byte Count Register */
+#define MTK_GDM1_TX_GBCNT      0x2400
+#define MTK_STAT_OFFSET                0x40
+
+/* QDMA descriptor txd4 */
+#define TX_DMA_CHKSUM          (0x7 << 29)
+#define TX_DMA_TSO             BIT(28)
+#define TX_DMA_FPORT_SHIFT     25
+#define TX_DMA_FPORT_MASK      0x7
+#define TX_DMA_INS_VLAN                BIT(16)
+
+/* QDMA descriptor txd3 */
+#define TX_DMA_OWNER_CPU       BIT(31)
+#define TX_DMA_LS0             BIT(30)
+#define TX_DMA_PLEN0(_x)       (((_x) & MTK_TX_DMA_BUF_LEN) << 16)
+#define TX_DMA_SWC             BIT(14)
+#define TX_DMA_SDL(_x)         (((_x) & 0x3fff) << 16)
+
+/* QDMA descriptor rxd2 */
+#define RX_DMA_DONE            BIT(31)
+#define RX_DMA_PLEN0(_x)       (((_x) & 0x3fff) << 16)
+#define RX_DMA_GET_PLEN0(_x)   (((_x) >> 16) & 0x3fff)
+
+/* QDMA descriptor rxd3 */
+#define RX_DMA_VID(_x)         ((_x) & 0xfff)
+
+/* QDMA descriptor rxd4 */
+#define RX_DMA_L4_VALID                BIT(24)
+#define RX_DMA_FPORT_SHIFT     19
+#define RX_DMA_FPORT_MASK      0x7
+
+/* PHY Indirect Access Control registers */
+#define MTK_PHY_IAC            0x10004
+#define PHY_IAC_ACCESS         BIT(31)
+#define PHY_IAC_READ           BIT(19)
+#define PHY_IAC_WRITE          BIT(18)
+#define PHY_IAC_START          BIT(16)
+#define PHY_IAC_ADDR_SHIFT     20
+#define PHY_IAC_REG_SHIFT      25
+#define PHY_IAC_TIMEOUT                HZ
+
+/* Mac control registers */
+#define MTK_MAC_MCR(x)         (0x10100 + (x * 0x100))
+#define MAC_MCR_MAX_RX_1536    BIT(24)
+#define MAC_MCR_IPG_CFG                (BIT(18) | BIT(16))
+#define MAC_MCR_FORCE_MODE     BIT(15)
+#define MAC_MCR_TX_EN          BIT(14)
+#define MAC_MCR_RX_EN          BIT(13)
+#define MAC_MCR_BACKOFF_EN     BIT(9)
+#define MAC_MCR_BACKPR_EN      BIT(8)
+#define MAC_MCR_FORCE_RX_FC    BIT(5)
+#define MAC_MCR_FORCE_TX_FC    BIT(4)
+#define MAC_MCR_SPEED_1000     BIT(3)
+#define MAC_MCR_SPEED_100      BIT(2)
+#define MAC_MCR_FORCE_DPX      BIT(1)
+#define MAC_MCR_FORCE_LINK     BIT(0)
+#define MAC_MCR_FIXED_LINK     (MAC_MCR_MAX_RX_1536 | MAC_MCR_IPG_CFG | \
+                                MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | \
+                                MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | \
+                                MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_RX_FC | \
+                                MAC_MCR_FORCE_TX_FC | MAC_MCR_SPEED_1000 | \
+                                MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK)
+
+/* GPIO port control registers for GMAC 2*/
+#define GPIO_OD33_CTRL8                0x4c0
+#define GPIO_BIAS_CTRL         0xed0
+#define GPIO_DRV_SEL10         0xf00
+
+/* ethernet subsystem config register */
+#define ETHSYS_SYSCFG0         0x14
+#define SYSCFG0_GE_MASK                0x3
+#define SYSCFG0_GE_MODE(x, y)  (x << (12 + (y * 2)))
+
+struct mtk_rx_dma {
+       unsigned int rxd1;
+       unsigned int rxd2;
+       unsigned int rxd3;
+       unsigned int rxd4;
+} __packed __aligned(4);
+
+struct mtk_tx_dma {
+       unsigned int txd1;
+       unsigned int txd2;
+       unsigned int txd3;
+       unsigned int txd4;
+} __packed __aligned(4);
+
+struct mtk_eth;
+struct mtk_mac;
+
+/* struct mtk_hw_stats - the structure that holds the traffic statistics.
+ * @stats_lock:                make sure that stats operations are atomic
+ * @reg_offset:                the status register offset of the SoC
+ * @syncp:             the refcount
+ *
+ * All of the supported SoCs have hardware counters for traffic statistics.
+ * Whenever the status IRQ triggers we can read the latest stats from these
+ * counters and store them in this struct.
+ */
+struct mtk_hw_stats {
+       u64 tx_bytes;
+       u64 tx_packets;
+       u64 tx_skip;
+       u64 tx_collisions;
+       u64 rx_bytes;
+       u64 rx_packets;
+       u64 rx_overflow;
+       u64 rx_fcs_errors;
+       u64 rx_short_errors;
+       u64 rx_long_errors;
+       u64 rx_checksum_errors;
+       u64 rx_flow_control_packets;
+
+       spinlock_t              stats_lock;
+       u32                     reg_offset;
+       struct u64_stats_sync   syncp;
+};
+
+/* PDMA descriptor can point at 1-2 segments. This enum allows us to track how
+ * memory was allocated so that it can be freed properly
+ */
+enum mtk_tx_flags {
+       MTK_TX_FLAGS_SINGLE0    = 0x01,
+       MTK_TX_FLAGS_PAGE0      = 0x02,
+};
+
+/* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at
+ *                     by the TX descriptor    s
+ * @skb:               The SKB pointer of the packet being sent
+ * @dma_addr0:         The base addr of the first segment
+ * @dma_len0:          The length of the first segment
+ * @dma_addr1:         The base addr of the second segment
+ * @dma_len1:          The length of the second segment
+ */
+struct mtk_tx_buf {
+       struct sk_buff *skb;
+       u32 flags;
+       DEFINE_DMA_UNMAP_ADDR(dma_addr0);
+       DEFINE_DMA_UNMAP_LEN(dma_len0);
+       DEFINE_DMA_UNMAP_ADDR(dma_addr1);
+       DEFINE_DMA_UNMAP_LEN(dma_len1);
+};
+
+/* struct mtk_tx_ring -        This struct holds info describing a TX ring
+ * @dma:               The descriptor ring
+ * @buf:               The memory pointed at by the ring
+ * @phys:              The physical addr of tx_buf
+ * @next_free:         Pointer to the next free descriptor
+ * @last_free:         Pointer to the last free descriptor
+ * @thresh:            The threshold of minimum amount of free descriptors
+ * @free_count:                QDMA uses a linked list. Track how many free descriptors
+ *                     are present
+ */
+struct mtk_tx_ring {
+       struct mtk_tx_dma *dma;
+       struct mtk_tx_buf *buf;
+       dma_addr_t phys;
+       struct mtk_tx_dma *next_free;
+       struct mtk_tx_dma *last_free;
+       u16 thresh;
+       atomic_t free_count;
+};
+
+/* struct mtk_rx_ring -        This struct holds info describing a RX ring
+ * @dma:               The descriptor ring
+ * @data:              The memory pointed at by the ring
+ * @phys:              The physical addr of rx_buf
+ * @frag_size:         How big can each fragment be
+ * @buf_size:          The size of each packet buffer
+ * @calc_idx:          The current head of ring
+ */
+struct mtk_rx_ring {
+       struct mtk_rx_dma *dma;
+       u8 **data;
+       dma_addr_t phys;
+       u16 frag_size;
+       u16 buf_size;
+       u16 calc_idx;
+};
+
+/* currently no SoC has more than 2 macs */
+#define MTK_MAX_DEVS                   2
+
+/* struct mtk_eth -    This is the main datasructure for holding the state
+ *                     of the driver
+ * @dev:               The device pointer
+ * @base:              The mapped register i/o base
+ * @page_lock:         Make sure that register operations are atomic
+ * @dummy_dev:         we run 2 netdevs on 1 physical DMA ring and need a
+ *                     dummy for NAPI to work
+ * @netdev:            The netdev instances
+ * @mac:               Each netdev is linked to a physical MAC
+ * @irq:               The IRQ that we are using
+ * @msg_enable:                Ethtool msg level
+ * @ethsys:            The register map pointing at the range used to setup
+ *                     MII modes
+ * @pctl:              The register map pointing at the range used to setup
+ *                     GMAC port drive/slew values
+ * @dma_refcnt:                track how many netdevs are using the DMA engine
+ * @tx_ring:           Pointer to the memore holding info about the TX ring
+ * @rx_ring:           Pointer to the memore holding info about the RX ring
+ * @rx_napi:           The NAPI struct
+ * @scratch_ring:      Newer SoCs need memory for a second HW managed TX ring
+ * @scratch_head:      The scratch memory that scratch_ring points to.
+ * @clk_ethif:         The ethif clock
+ * @clk_esw:           The switch clock
+ * @clk_gp1:           The gmac1 clock
+ * @clk_gp2:           The gmac2 clock
+ * @mii_bus:           If there is a bus we need to create an instance for it
+ */
+
+struct mtk_eth {
+       struct device                   *dev;
+       void __iomem                    *base;
+       struct reset_control            *rstc;
+       spinlock_t                      page_lock;
+       struct net_device               dummy_dev;
+       struct net_device               *netdev[MTK_MAX_DEVS];
+       struct mtk_mac                  *mac[MTK_MAX_DEVS];
+       int                             irq;
+       u32                             msg_enable;
+       unsigned long                   sysclk;
+       struct regmap                   *ethsys;
+       struct regmap                   *pctl;
+       atomic_t                        dma_refcnt;
+       struct mtk_tx_ring              tx_ring;
+       struct mtk_rx_ring              rx_ring;
+       struct napi_struct              rx_napi;
+       struct mtk_tx_dma               *scratch_ring;
+       void                            *scratch_head;
+       struct clk                      *clk_ethif;
+       struct clk                      *clk_esw;
+       struct clk                      *clk_gp1;
+       struct clk                      *clk_gp2;
+       struct mii_bus                  *mii_bus;
+};
+
+/* struct mtk_mac -    the structure that holds the info about the MACs of the
+ *                     SoC
+ * @id:                        The number of the MAC
+ * @of_node:           Our devicetree node
+ * @hw:                        Backpointer to our main datastruture
+ * @hw_stats:          Packet statistics counter
+ * @phy_dev:           The attached PHY if available
+ * @pending_work:      The workqueue used to reset the dma ring
+ */
+struct mtk_mac {
+       int                             id;
+       struct device_node              *of_node;
+       struct mtk_eth                  *hw;
+       struct mtk_hw_stats             *hw_stats;
+       struct phy_device               *phy_dev;
+       struct work_struct              pending_work;
+};
+
+/* the struct describing the SoC. these are declared in the soc_xyz.c files */
+extern const struct of_device_id of_mtk_match[];
+
+/* read the hardware status register */
+void mtk_stats_update_mac(struct mtk_mac *mac);
+
+void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg);
+u32 mtk_r32(struct mtk_eth *eth, unsigned reg);
+
+#endif /* MTK_ETH_H */
index 1486ce902a561e498a10bcccf208d869559a7ed1..9ca3734ebb6b84fdb5e58c0def6c461ed924ba5b 100644 (file)
@@ -4,6 +4,7 @@
 
 config MLX4_EN
        tristate "Mellanox Technologies 1/10/40Gbit Ethernet support"
+       depends on MAY_USE_DEVLINK
        depends on PCI
        select MLX4_CORE
        select PTP_1588_CLOCK
index 715de8affcc950e0ea18fd706bc8f04542d34a6f..c7e939945259dc876b66cfedd0d85f9d7e90a914 100644 (file)
@@ -182,10 +182,17 @@ void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
                err = mlx4_reset_slave(dev);
        else
                err = mlx4_reset_master(dev);
-       BUG_ON(err != 0);
 
+       if (!err) {
+               mlx4_err(dev, "device was reset successfully\n");
+       } else {
+               /* EEH could have disabled the PCI channel during reset. That's
+                * recoverable and the PCI error flow will handle it.
+                */
+               if (!pci_channel_offline(dev->persist->pdev))
+                       BUG_ON(1);
+       }
        dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR;
-       mlx4_err(dev, "device was reset successfully\n");
        mutex_unlock(&persist->device_state_mutex);
 
        /* At that step HW was already reset, now notify clients */
index d48d5793407d9ec729fe8548a049a2506d02a934..e94ca1c3fc7c6a83a190a29d4116086dcc9de8ca 100644 (file)
@@ -2429,7 +2429,7 @@ err_thread:
        flush_workqueue(priv->mfunc.master.comm_wq);
        destroy_workqueue(priv->mfunc.master.comm_wq);
 err_slaves:
-       while (--i) {
+       while (i--) {
                for (port = 1; port <= MLX4_MAX_PORTS; port++)
                        kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
        }
index 3348e646db705f41ff1cb3923d4d1533aea80e2d..a849da92f857e5c22cd1ec93158cecbff9c75d90 100644 (file)
@@ -318,7 +318,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
        if (timestamp_en)
                cq_context->flags  |= cpu_to_be32(1 << 19);
 
-       cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
+       cq_context->logsize_usrpage =
+               cpu_to_be32((ilog2(nent) << 24) |
+                           mlx4_to_hw_uar_index(dev, uar->index));
        cq_context->comp_eqn        = priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(vector)].eqn;
        cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
 
index 038f9ce391e626f02d3fe2f51a19fbd4b08a2711..1494997c4f7e3bef36141ea439d812ca9bb1a335 100644 (file)
@@ -236,6 +236,24 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
        .enable         = mlx4_en_phc_enable,
 };
 
+#define MLX4_EN_WRAP_AROUND_SEC        10ULL
+
+/* This function calculates the max shift that enables the user range
+ * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register.
+ */
+static u32 freq_to_shift(u16 freq)
+{
+       u32 freq_khz = freq * 1000;
+       u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
+       u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ?
+               max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1;
+       /* calculate max possible multiplier in order to fit in 64bit */
+       u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded);
+
+       /* This comes from the reverse of clocksource_khz2mult */
+       return ilog2(div_u64(max_mul * freq_khz, 1000000));
+}
+
 void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
 {
        struct mlx4_dev *dev = mdev->dev;
@@ -254,12 +272,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
        memset(&mdev->cycles, 0, sizeof(mdev->cycles));
        mdev->cycles.read = mlx4_en_read_clock;
        mdev->cycles.mask = CLOCKSOURCE_MASK(48);
-       /* Using shift to make calculation more accurate. Since current HW
-        * clock frequency is 427 MHz, and cycles are given using a 48 bits
-        * register, the biggest shift when calculating using u64, is 14
-        * (max_cycles * multiplier < 2^64)
-        */
-       mdev->cycles.shift = 14;
+       mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);
        mdev->cycles.mult =
                clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
        mdev->nominal_c_mult = mdev->cycles.mult;
index dd84cabb2a51a994ad86b228aaae8d12351f5e38..f69584a9b47fbef008a1ec138feba9f10504d997 100644 (file)
@@ -501,34 +501,30 @@ static u32 mlx4_en_autoneg_get(struct net_device *dev)
        return autoneg;
 }
 
-static u32 ptys_get_supported_port(struct mlx4_ptys_reg *ptys_reg)
+static void ptys2ethtool_update_supported_port(unsigned long *mask,
+                                              struct mlx4_ptys_reg *ptys_reg)
 {
        u32 eth_proto = be32_to_cpu(ptys_reg->eth_proto_cap);
 
        if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_T)
                         | MLX4_PROT_MASK(MLX4_1000BASE_T)
                         | MLX4_PROT_MASK(MLX4_100BASE_TX))) {
-                       return SUPPORTED_TP;
-       }
-
-       if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR)
+               __set_bit(ETHTOOL_LINK_MODE_TP_BIT, mask);
+       } else if (eth_proto & (MLX4_PROT_MASK(MLX4_10GBASE_CR)
                         | MLX4_PROT_MASK(MLX4_10GBASE_SR)
                         | MLX4_PROT_MASK(MLX4_56GBASE_SR4)
                         | MLX4_PROT_MASK(MLX4_40GBASE_CR4)
                         | MLX4_PROT_MASK(MLX4_40GBASE_SR4)
                         | MLX4_PROT_MASK(MLX4_1000BASE_CX_SGMII))) {
-                       return SUPPORTED_FIBRE;
-       }
-
-       if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4)
+               __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mask);
+       } else if (eth_proto & (MLX4_PROT_MASK(MLX4_56GBASE_KR4)
                         | MLX4_PROT_MASK(MLX4_40GBASE_KR4)
                         | MLX4_PROT_MASK(MLX4_20GBASE_KR2)
                         | MLX4_PROT_MASK(MLX4_10GBASE_KR)
                         | MLX4_PROT_MASK(MLX4_10GBASE_KX4)
                         | MLX4_PROT_MASK(MLX4_1000BASE_KX))) {
-                       return SUPPORTED_Backplane;
+               __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, mask);
        }
-       return 0;
 }
 
 static u32 ptys_get_active_port(struct mlx4_ptys_reg *ptys_reg)
@@ -574,122 +570,111 @@ static u32 ptys_get_active_port(struct mlx4_ptys_reg *ptys_reg)
 enum ethtool_report {
        SUPPORTED = 0,
        ADVERTISED = 1,
-       SPEED = 2
 };
 
+struct ptys2ethtool_config {
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised);
+       u32 speed;
+};
+
+static unsigned long *ptys2ethtool_link_mode(struct ptys2ethtool_config *cfg,
+                                            enum ethtool_report report)
+{
+       switch (report) {
+       case SUPPORTED:
+               return cfg->supported;
+       case ADVERTISED:
+               return cfg->advertised;
+       }
+       return NULL;
+}
+
+#define MLX4_BUILD_PTYS2ETHTOOL_CONFIG(reg_, speed_, ...)              \
+       ({                                                              \
+               struct ptys2ethtool_config *cfg;                        \
+               const unsigned int modes[] = { __VA_ARGS__ };           \
+               unsigned int i;                                         \
+               cfg = &ptys2ethtool_map[reg_];                          \
+               cfg->speed = speed_;                                    \
+               bitmap_zero(cfg->supported,                             \
+                           __ETHTOOL_LINK_MODE_MASK_NBITS);            \
+               bitmap_zero(cfg->advertised,                            \
+                           __ETHTOOL_LINK_MODE_MASK_NBITS);            \
+               for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) {             \
+                       __set_bit(modes[i], cfg->supported);            \
+                       __set_bit(modes[i], cfg->advertised);           \
+               }                                                       \
+       })
+
 /* Translates mlx4 link mode to equivalent ethtool Link modes/speed */
-static u32 ptys2ethtool_map[MLX4_LINK_MODES_SZ][3] = {
-       [MLX4_100BASE_TX] = {
-               SUPPORTED_100baseT_Full,
-               ADVERTISED_100baseT_Full,
-               SPEED_100
-               },
-
-       [MLX4_1000BASE_T] = {
-               SUPPORTED_1000baseT_Full,
-               ADVERTISED_1000baseT_Full,
-               SPEED_1000
-               },
-       [MLX4_1000BASE_CX_SGMII] = {
-               SUPPORTED_1000baseKX_Full,
-               ADVERTISED_1000baseKX_Full,
-               SPEED_1000
-               },
-       [MLX4_1000BASE_KX] = {
-               SUPPORTED_1000baseKX_Full,
-               ADVERTISED_1000baseKX_Full,
-               SPEED_1000
-               },
-
-       [MLX4_10GBASE_T] = {
-               SUPPORTED_10000baseT_Full,
-               ADVERTISED_10000baseT_Full,
-               SPEED_10000
-               },
-       [MLX4_10GBASE_CX4] = {
-               SUPPORTED_10000baseKX4_Full,
-               ADVERTISED_10000baseKX4_Full,
-               SPEED_10000
-               },
-       [MLX4_10GBASE_KX4] = {
-               SUPPORTED_10000baseKX4_Full,
-               ADVERTISED_10000baseKX4_Full,
-               SPEED_10000
-               },
-       [MLX4_10GBASE_KR] = {
-               SUPPORTED_10000baseKR_Full,
-               ADVERTISED_10000baseKR_Full,
-               SPEED_10000
-               },
-       [MLX4_10GBASE_CR] = {
-               SUPPORTED_10000baseKR_Full,
-               ADVERTISED_10000baseKR_Full,
-               SPEED_10000
-               },
-       [MLX4_10GBASE_SR] = {
-               SUPPORTED_10000baseKR_Full,
-               ADVERTISED_10000baseKR_Full,
-               SPEED_10000
-               },
-
-       [MLX4_20GBASE_KR2] = {
-               SUPPORTED_20000baseMLD2_Full | SUPPORTED_20000baseKR2_Full,
-               ADVERTISED_20000baseMLD2_Full | ADVERTISED_20000baseKR2_Full,
-               SPEED_20000
-               },
-
-       [MLX4_40GBASE_CR4] = {
-               SUPPORTED_40000baseCR4_Full,
-               ADVERTISED_40000baseCR4_Full,
-               SPEED_40000
-               },
-       [MLX4_40GBASE_KR4] = {
-               SUPPORTED_40000baseKR4_Full,
-               ADVERTISED_40000baseKR4_Full,
-               SPEED_40000
-               },
-       [MLX4_40GBASE_SR4] = {
-               SUPPORTED_40000baseSR4_Full,
-               ADVERTISED_40000baseSR4_Full,
-               SPEED_40000
-               },
-
-       [MLX4_56GBASE_KR4] = {
-               SUPPORTED_56000baseKR4_Full,
-               ADVERTISED_56000baseKR4_Full,
-               SPEED_56000
-               },
-       [MLX4_56GBASE_CR4] = {
-               SUPPORTED_56000baseCR4_Full,
-               ADVERTISED_56000baseCR4_Full,
-               SPEED_56000
-               },
-       [MLX4_56GBASE_SR4] = {
-               SUPPORTED_56000baseSR4_Full,
-               ADVERTISED_56000baseSR4_Full,
-               SPEED_56000
-               },
+static struct ptys2ethtool_config ptys2ethtool_map[MLX4_LINK_MODES_SZ];
+
+void __init mlx4_en_init_ptys2ethtool_map(void)
+{
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_100BASE_TX, SPEED_100,
+                                      ETHTOOL_LINK_MODE_100baseT_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_T, SPEED_1000,
+                                      ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_CX_SGMII, SPEED_1000,
+                                      ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_1000BASE_KX, SPEED_1000,
+                                      ETHTOOL_LINK_MODE_1000baseKX_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_T, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseT_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_CX4, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_KX4, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_KR, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_CR, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_10GBASE_SR, SPEED_10000,
+                                      ETHTOOL_LINK_MODE_10000baseKR_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_20GBASE_KR2, SPEED_20000,
+                                      ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
+                                      ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_CR4, SPEED_40000,
+                                      ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_KR4, SPEED_40000,
+                                      ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_40GBASE_SR4, SPEED_40000,
+                                      ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_KR4, SPEED_56000,
+                                      ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_CR4, SPEED_56000,
+                                      ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT);
+       MLX4_BUILD_PTYS2ETHTOOL_CONFIG(MLX4_56GBASE_SR4, SPEED_56000,
+                                      ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT);
 };
 
-static u32 ptys2ethtool_link_modes(u32 eth_proto, enum ethtool_report report)
+static void ptys2ethtool_update_link_modes(unsigned long *link_modes,
+                                          u32 eth_proto,
+                                          enum ethtool_report report)
 {
        int i;
-       u32 link_modes = 0;
-
        for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
                if (eth_proto & MLX4_PROT_MASK(i))
-                       link_modes |= ptys2ethtool_map[i][report];
+                       bitmap_or(link_modes, link_modes,
+                                 ptys2ethtool_link_mode(&ptys2ethtool_map[i],
+                                                        report),
+                                 __ETHTOOL_LINK_MODE_MASK_NBITS);
        }
-       return link_modes;
 }
 
-static u32 ethtool2ptys_link_modes(u32 link_modes, enum ethtool_report report)
+static u32 ethtool2ptys_link_modes(const unsigned long *link_modes,
+                                  enum ethtool_report report)
 {
        int i;
        u32 ptys_modes = 0;
 
        for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
-               if (ptys2ethtool_map[i][report] & link_modes)
+               if (bitmap_intersects(
+                           ptys2ethtool_link_mode(&ptys2ethtool_map[i],
+                                                  report),
+                           link_modes,
+                           __ETHTOOL_LINK_MODE_MASK_NBITS))
                        ptys_modes |= 1 << i;
        }
        return ptys_modes;
@@ -702,14 +687,15 @@ static u32 speed2ptys_link_modes(u32 speed)
        u32 ptys_modes = 0;
 
        for (i = 0; i < MLX4_LINK_MODES_SZ; i++) {
-               if (ptys2ethtool_map[i][SPEED] == speed)
+               if (ptys2ethtool_map[i].speed == speed)
                        ptys_modes |= 1 << i;
        }
        return ptys_modes;
 }
 
-static int ethtool_get_ptys_settings(struct net_device *dev,
-                                    struct ethtool_cmd *cmd)
+static int
+ethtool_get_ptys_link_ksettings(struct net_device *dev,
+                               struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_ptys_reg ptys_reg;
@@ -737,79 +723,102 @@ static int ethtool_get_ptys_settings(struct net_device *dev,
        en_dbg(DRV, priv, "ptys_reg.eth_proto_lp_adv %x\n",
               be32_to_cpu(ptys_reg.eth_proto_lp_adv));
 
-       cmd->supported = 0;
-       cmd->advertising = 0;
+       /* reset supported/advertising masks */
+       ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
+       ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
 
-       cmd->supported |= ptys_get_supported_port(&ptys_reg);
+       ptys2ethtool_update_supported_port(link_ksettings->link_modes.supported,
+                                          &ptys_reg);
 
        eth_proto = be32_to_cpu(ptys_reg.eth_proto_cap);
-       cmd->supported |= ptys2ethtool_link_modes(eth_proto, SUPPORTED);
+       ptys2ethtool_update_link_modes(link_ksettings->link_modes.supported,
+                                      eth_proto, SUPPORTED);
 
        eth_proto = be32_to_cpu(ptys_reg.eth_proto_admin);
-       cmd->advertising |= ptys2ethtool_link_modes(eth_proto, ADVERTISED);
+       ptys2ethtool_update_link_modes(link_ksettings->link_modes.advertising,
+                                      eth_proto, ADVERTISED);
 
-       cmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
-       cmd->advertising |= (priv->prof->tx_pause) ? ADVERTISED_Pause : 0;
+       ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+                                            Pause);
+       ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+                                            Asym_Pause);
 
-       cmd->advertising |= (priv->prof->tx_pause ^ priv->prof->rx_pause) ?
-               ADVERTISED_Asym_Pause : 0;
+       if (priv->prof->tx_pause)
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, Pause);
+       if (priv->prof->tx_pause ^ priv->prof->rx_pause)
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, Asym_Pause);
 
-       cmd->port = ptys_get_active_port(&ptys_reg);
-       cmd->transceiver = (SUPPORTED_TP & cmd->supported) ?
-               XCVR_EXTERNAL : XCVR_INTERNAL;
+       link_ksettings->base.port = ptys_get_active_port(&ptys_reg);
 
        if (mlx4_en_autoneg_get(dev)) {
-               cmd->supported |= SUPPORTED_Autoneg;
-               cmd->advertising |= ADVERTISED_Autoneg;
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    supported, Autoneg);
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, Autoneg);
        }
 
-       cmd->autoneg = (priv->port_state.flags & MLX4_EN_PORT_ANC) ?
+       link_ksettings->base.autoneg
+               = (priv->port_state.flags & MLX4_EN_PORT_ANC) ?
                AUTONEG_ENABLE : AUTONEG_DISABLE;
 
        eth_proto = be32_to_cpu(ptys_reg.eth_proto_lp_adv);
-       cmd->lp_advertising = ptys2ethtool_link_modes(eth_proto, ADVERTISED);
 
-       cmd->lp_advertising |= (priv->port_state.flags & MLX4_EN_PORT_ANC) ?
-                       ADVERTISED_Autoneg : 0;
+       ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
+       ptys2ethtool_update_link_modes(
+               link_ksettings->link_modes.lp_advertising,
+               eth_proto, ADVERTISED);
+       if (priv->port_state.flags & MLX4_EN_PORT_ANC)
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    lp_advertising, Autoneg);
 
-       cmd->phy_address = 0;
-       cmd->mdio_support = 0;
-       cmd->maxtxpkt = 0;
-       cmd->maxrxpkt = 0;
-       cmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
-       cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
+       link_ksettings->base.phy_address = 0;
+       link_ksettings->base.mdio_support = 0;
+       link_ksettings->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
+       link_ksettings->base.eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
 
        return ret;
 }
 
-static void ethtool_get_default_settings(struct net_device *dev,
-                                        struct ethtool_cmd *cmd)
+static void
+ethtool_get_default_link_ksettings(
+       struct net_device *dev, struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        int trans_type;
 
-       cmd->autoneg = AUTONEG_DISABLE;
-       cmd->supported = SUPPORTED_10000baseT_Full;
-       cmd->advertising = ADVERTISED_10000baseT_Full;
-       trans_type = priv->port_state.transceiver;
+       link_ksettings->base.autoneg = AUTONEG_DISABLE;
+
+       ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
+       ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+                                            10000baseT_Full);
 
+       ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
+       ethtool_link_ksettings_add_link_mode(link_ksettings, advertising,
+                                            10000baseT_Full);
+
+       trans_type = priv->port_state.transceiver;
        if (trans_type > 0 && trans_type <= 0xC) {
-               cmd->port = PORT_FIBRE;
-               cmd->transceiver = XCVR_EXTERNAL;
-               cmd->supported |= SUPPORTED_FIBRE;
-               cmd->advertising |= ADVERTISED_FIBRE;
+               link_ksettings->base.port = PORT_FIBRE;
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    supported, FIBRE);
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, FIBRE);
        } else if (trans_type == 0x80 || trans_type == 0) {
-               cmd->port = PORT_TP;
-               cmd->transceiver = XCVR_INTERNAL;
-               cmd->supported |= SUPPORTED_TP;
-               cmd->advertising |= ADVERTISED_TP;
+               link_ksettings->base.port = PORT_TP;
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    supported, TP);
+               ethtool_link_ksettings_add_link_mode(link_ksettings,
+                                                    advertising, TP);
        } else  {
-               cmd->port = -1;
-               cmd->transceiver = -1;
+               link_ksettings->base.port = -1;
        }
 }
 
-static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mlx4_en_get_link_ksettings(struct net_device *dev,
+                          struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        int ret = -EINVAL;
@@ -822,16 +831,16 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
               priv->port_state.flags & MLX4_EN_PORT_ANE);
 
        if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL)
-               ret = ethtool_get_ptys_settings(dev, cmd);
+               ret = ethtool_get_ptys_link_ksettings(dev, link_ksettings);
        if (ret) /* ETH PROT CRTL is not supported or PTYS CMD failed */
-               ethtool_get_default_settings(dev, cmd);
+               ethtool_get_default_link_ksettings(dev, link_ksettings);
 
        if (netif_carrier_ok(dev)) {
-               ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
-               cmd->duplex = DUPLEX_FULL;
+               link_ksettings->base.speed = priv->port_state.link_speed;
+               link_ksettings->base.duplex = DUPLEX_FULL;
        } else {
-               ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
-               cmd->duplex = DUPLEX_UNKNOWN;
+               link_ksettings->base.speed = SPEED_UNKNOWN;
+               link_ksettings->base.duplex = DUPLEX_UNKNOWN;
        }
        return 0;
 }
@@ -855,21 +864,29 @@ static __be32 speed_set_ptys_admin(struct mlx4_en_priv *priv, u32 speed,
        return proto_admin;
 }
 
-static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int
+mlx4_en_set_link_ksettings(struct net_device *dev,
+                          const struct ethtool_link_ksettings *link_ksettings)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_ptys_reg ptys_reg;
        __be32 proto_admin;
        int ret;
 
-       u32 ptys_adv = ethtool2ptys_link_modes(cmd->advertising, ADVERTISED);
-       int speed = ethtool_cmd_speed(cmd);
+       u32 ptys_adv = ethtool2ptys_link_modes(
+               link_ksettings->link_modes.advertising, ADVERTISED);
+       const int speed = link_ksettings->base.speed;
 
-       en_dbg(DRV, priv, "Set Speed=%d adv=0x%x autoneg=%d duplex=%d\n",
-              speed, cmd->advertising, cmd->autoneg, cmd->duplex);
+       en_dbg(DRV, priv,
+              "Set Speed=%d adv={%*pbl} autoneg=%d duplex=%d\n",
+              speed, __ETHTOOL_LINK_MODE_MASK_NBITS,
+              link_ksettings->link_modes.advertising,
+              link_ksettings->base.autoneg,
+              link_ksettings->base.duplex);
 
-       if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL) ||
-           (cmd->duplex == DUPLEX_HALF))
+       if (!(priv->mdev->dev->caps.flags2 &
+             MLX4_DEV_CAP_FLAG2_ETH_PROT_CTRL) ||
+           (link_ksettings->base.duplex == DUPLEX_HALF))
                return -EINVAL;
 
        memset(&ptys_reg, 0, sizeof(ptys_reg));
@@ -883,7 +900,7 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                return 0;
        }
 
-       proto_admin = cmd->autoneg == AUTONEG_ENABLE ?
+       proto_admin = link_ksettings->base.autoneg == AUTONEG_ENABLE ?
                cpu_to_be32(ptys_adv) :
                speed_set_ptys_admin(priv, speed,
                                     ptys_reg.eth_proto_cap);
@@ -1982,8 +1999,8 @@ static int mlx4_en_set_phys_id(struct net_device *dev,
 
 const struct ethtool_ops mlx4_en_ethtool_ops = {
        .get_drvinfo = mlx4_en_get_drvinfo,
-       .get_settings = mlx4_en_get_settings,
-       .set_settings = mlx4_en_set_settings,
+       .get_link_ksettings = mlx4_en_get_link_ksettings,
+       .set_link_ksettings = mlx4_en_set_link_ksettings,
        .get_link = ethtool_op_get_link,
        .get_strings = mlx4_en_get_strings,
        .get_sset_count = mlx4_en_get_sset_count,
index e0ec280a7fa13a55fd239f84c6f6c24db2c2e5e5..bf7628db098acd24f9a510ca07862736f0475cfe 100644 (file)
@@ -382,6 +382,7 @@ static void mlx4_en_verify_params(void)
 static int __init mlx4_en_init(void)
 {
        mlx4_en_verify_params();
+       mlx4_en_init_ptys2ethtool_map();
 
        return mlx4_register_interface(&mlx4_en_interface);
 }
index 0c7e3f69a73bb6f787b8387efd3d34624a188568..b4b258c8ca47d47f804fc85adb665e9d08fa48df 100644 (file)
@@ -40,6 +40,7 @@
 #include <net/ip.h>
 #include <net/busy_poll.h>
 #include <net/vxlan.h>
+#include <net/devlink.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/device.h>
@@ -69,6 +70,15 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
        return 0;
 }
 
+static int __mlx4_en_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                             struct tc_to_netdev *tc)
+{
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       return mlx4_en_setup_tc(dev, tc->tc);
+}
+
 #ifdef CONFIG_RFS_ACCEL
 
 struct mlx4_en_filter {
@@ -2024,8 +2034,11 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
        en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port);
 
        /* Unregister device - this will close the port if it was up */
-       if (priv->registered)
+       if (priv->registered) {
+               devlink_port_type_clear(mlx4_get_devlink_port(mdev->dev,
+                                                             priv->port));
                unregister_netdev(dev);
+       }
 
        if (priv->allocated)
                mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
@@ -2245,7 +2258,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
        struct mlx4_en_dev *mdev = en_priv->mdev;
        u64 mac_u64 = mlx4_mac_to_u64(mac);
 
-       if (!is_valid_ether_addr(mac))
+       if (is_multicast_ether_addr(mac))
                return -EINVAL;
 
        return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
@@ -2344,8 +2357,6 @@ out:
        /* set offloads */
        priv->dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
                                      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL;
-       priv->dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
-       priv->dev->features    |= NETIF_F_GSO_UDP_TUNNEL;
 }
 
 static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
@@ -2356,8 +2367,6 @@ static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
        /* unset offloads */
        priv->dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
                                      NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL);
-       priv->dev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
-       priv->dev->features    &= ~NETIF_F_GSO_UDP_TUNNEL;
 
        ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
                                  VXLAN_STEER_BY_OUTER_MAC, 0);
@@ -2466,7 +2475,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #endif
        .ndo_set_features       = mlx4_en_set_features,
        .ndo_fix_features       = mlx4_en_fix_features,
-       .ndo_setup_tc           = mlx4_en_setup_tc,
+       .ndo_setup_tc           = __mlx4_en_setup_tc,
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
@@ -2504,7 +2513,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
 #endif
        .ndo_set_features       = mlx4_en_set_features,
        .ndo_fix_features       = mlx4_en_fix_features,
-       .ndo_setup_tc           = mlx4_en_setup_tc,
+       .ndo_setup_tc           = __mlx4_en_setup_tc,
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
@@ -2980,6 +2989,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                priv->rss_hash_fn = ETH_RSS_HASH_TOP;
        }
 
+       if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
+               dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+               dev->features    |= NETIF_F_GSO_UDP_TUNNEL;
+       }
+
        mdev->pndev[port] = dev;
        mdev->upper[port] = NULL;
 
@@ -3041,6 +3055,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        }
 
        priv->registered = 1;
+       devlink_port_type_eth_set(mlx4_get_devlink_port(mdev->dev, priv->port),
+                                 dev);
 
        return 0;
 
index ee99e67187f5b1cc68fc224b91d5b2bf2d133b05..3904b5fc0b7c904548763ffbb2d31fbcccfe5b6c 100644 (file)
@@ -238,11 +238,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
        stats->collisions = 0;
        stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP);
        stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength);
-       stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+       stats->rx_over_errors = 0;
        stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC);
        stats->rx_frame_errors = 0;
        stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
-       stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw);
+       stats->rx_missed_errors = 0;
        stats->tx_aborted_errors = 0;
        stats->tx_carrier_errors = 0;
        stats->tx_fifo_errors = 0;
index 12aab5a659d33e4c098a6b8bedf2d4014798e14c..02e925d6f7348d774fe70c4a91b5038d5a27ba35 100644 (file)
@@ -58,7 +58,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
        } else {
                context->sq_size_stride = ilog2(TXBB_SIZE) - 4;
        }
-       context->usr_page = cpu_to_be32(mdev->priv_uar.index);
+       context->usr_page = cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+                                       mdev->priv_uar.index));
        context->local_qpn = cpu_to_be32(qpn);
        context->pri_path.ackto = 1 & 0x07;
        context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
index 4421bf5463f67159618c3a4c572b4e9ebc04dd7b..c0d7b729623636e241f76213596c664b1e70c047 100644 (file)
@@ -213,7 +213,9 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
        mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn,
                                ring->cqn, user_prio, &ring->context);
        if (ring->bf_alloced)
-               ring->context.usr_page = cpu_to_be32(ring->bf.uar->index);
+               ring->context.usr_page =
+                       cpu_to_be32(mlx4_to_hw_uar_index(mdev->dev,
+                                                        ring->bf.uar->index));
 
        err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context,
                               &ring->qp, &ring->qp_state);
@@ -274,7 +276,8 @@ static void mlx4_en_stamp_wqe(struct mlx4_en_priv *priv,
 
 static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                                struct mlx4_en_tx_ring *ring,
-                               int index, u8 owner, u64 timestamp)
+                               int index, u8 owner, u64 timestamp,
+                               int napi_mode)
 {
        struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
        struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
@@ -345,7 +348,8 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_consume_skb_any(skb);
+       napi_consume_skb(skb, napi_mode);
+
        return tx_info->nr_txbb;
 }
 
@@ -369,7 +373,8 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
        while (ring->cons != ring->prod) {
                ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
                                                ring->cons & ring->size_mask,
-                                               !!(ring->cons & ring->size), 0);
+                                               !!(ring->cons & ring->size), 0,
+                                               0 /* Non-NAPI caller */);
                ring->cons += ring->last_nr_txbb;
                cnt++;
        }
@@ -383,7 +388,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
 }
 
 static bool mlx4_en_process_tx_cq(struct net_device *dev,
-                                struct mlx4_en_cq *cq)
+                                 struct mlx4_en_cq *cq, int napi_budget)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_cq *mcq = &cq->mcq;
@@ -449,7 +454,7 @@ static bool mlx4_en_process_tx_cq(struct net_device *dev,
                        last_nr_txbb = mlx4_en_free_tx_desc(
                                        priv, ring, ring_index,
                                        !!((ring_cons + txbbs_skipped) &
-                                       ring->size), timestamp);
+                                       ring->size), timestamp, napi_budget);
 
                        mlx4_en_stamp_wqe(priv, ring, stamp_index,
                                          !!((ring_cons + txbbs_stamp) &
@@ -509,7 +514,7 @@ int mlx4_en_poll_tx_cq(struct napi_struct *napi, int budget)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        int clean_complete;
 
-       clean_complete = mlx4_en_process_tx_cq(dev, cq);
+       clean_complete = mlx4_en_process_tx_cq(dev, cq, budget);
        if (!clean_complete)
                return budget;
 
index 4696053165f8ca192d5e8ccb21971d175d267ca7..f613977455e08340995baeb65763086e408479f3 100644 (file)
@@ -940,9 +940,10 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
 
        if (!priv->eq_table.uar_map[index]) {
                priv->eq_table.uar_map[index] =
-                       ioremap(pci_resource_start(dev->persist->pdev, 2) +
-                               ((eq->eqn / 4) << PAGE_SHIFT),
-                               PAGE_SIZE);
+                       ioremap(
+                               pci_resource_start(dev->persist->pdev, 2) +
+                               ((eq->eqn / 4) << (dev->uar_page_shift)),
+                               (1 << (dev->uar_page_shift)));
                if (!priv->eq_table.uar_map[index]) {
                        mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n",
                                 eq->eqn);
index 0472941af82033852106e5ab3dfc2399ca82cdaa..dec77d6f0ac998be9ef4a44281e18872efbbdc20 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/errno.h>
+#include <net/devlink.h>
 
 #include "mlx4.h"
 
@@ -249,3 +250,11 @@ void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int
        return result;
 }
 EXPORT_SYMBOL_GPL(mlx4_get_protocol_dev);
+
+struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port)
+{
+       struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
+
+       return &info->devlink_port;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_devlink_port);
index f1b6d219e445431c0dfe4f255b8abe9d3ec5f9b4..503ec23e84cce68e6e47613ea9dc495dae9942cd 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/io-mapping.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
+#include <net/devlink.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/doorbell.h>
@@ -168,6 +169,20 @@ struct mlx4_port_config {
 
 static atomic_t pf_loading = ATOMIC_INIT(0);
 
+static inline void mlx4_set_num_reserved_uars(struct mlx4_dev *dev,
+                                             struct mlx4_dev_cap *dev_cap)
+{
+       /* The reserved_uars is calculated by system page size unit.
+        * Therefore, adjustment is added when the uar page size is less
+        * than the system page size
+        */
+       dev->caps.reserved_uars =
+               max_t(int,
+                     mlx4_get_num_reserved_uar(dev),
+                     dev_cap->reserved_uars /
+                       (1 << (PAGE_SHIFT - dev->uar_page_shift)));
+}
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
 {
@@ -386,8 +401,6 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.reserved_mtts      = dev_cap->reserved_mtts;
        dev->caps.reserved_mrws      = dev_cap->reserved_mrws;
 
-       /* The first 128 UARs are used for EQ doorbells */
-       dev->caps.reserved_uars      = max_t(int, 128, dev_cap->reserved_uars);
        dev->caps.reserved_pds       = dev_cap->reserved_pds;
        dev->caps.reserved_xrcds     = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ?
                                        dev_cap->reserved_xrcds : 0;
@@ -405,6 +418,15 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
        dev->caps.max_rss_tbl_sz     = dev_cap->max_rss_tbl_sz;
 
+       /* Save uar page shift */
+       if (!mlx4_is_slave(dev)) {
+               /* Virtual PCI function needs to determine UAR page size from
+                * firmware. Only master PCI function can set the uar page size
+                */
+               dev->uar_page_shift = DEFAULT_UAR_PAGE_SHIFT;
+               mlx4_set_num_reserved_uars(dev, dev_cap);
+       }
+
        if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) {
                struct mlx4_init_hca_param hca_param;
 
@@ -815,16 +837,25 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
                return -ENODEV;
        }
 
-       /* slave gets uar page size from QUERY_HCA fw command */
-       dev->caps.uar_page_size = 1 << (hca_param.uar_page_sz + 12);
+       /* Set uar_page_shift for VF */
+       dev->uar_page_shift = hca_param.uar_page_sz + 12;
 
-       /* TODO: relax this assumption */
-       if (dev->caps.uar_page_size != PAGE_SIZE) {
-               mlx4_err(dev, "UAR size:%d != kernel PAGE_SIZE of %ld\n",
-                        dev->caps.uar_page_size, PAGE_SIZE);
-               return -ENODEV;
+       /* Make sure the master uar page size is valid */
+       if (dev->uar_page_shift > PAGE_SHIFT) {
+               mlx4_err(dev,
+                        "Invalid configuration: uar page size is larger than system page size\n");
+               return  -ENODEV;
        }
 
+       /* Set reserved_uars based on the uar_page_shift */
+       mlx4_set_num_reserved_uars(dev, &dev_cap);
+
+       /* Although uar page size in FW differs from system page size,
+        * upper software layers (mlx4_ib, mlx4_en and part of mlx4_core)
+        * still works with assumption that uar page size == system page size
+        */
+       dev->caps.uar_page_size = PAGE_SIZE;
+
        memset(&func_cap, 0, sizeof(func_cap));
        err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap);
        if (err) {
@@ -1051,36 +1082,20 @@ static ssize_t show_port_type(struct device *dev,
        return strlen(buf);
 }
 
-static ssize_t set_port_type(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
+static int __set_port_type(struct mlx4_port_info *info,
+                          enum mlx4_port_type port_type)
 {
-       struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
-                                                  port_attr);
        struct mlx4_dev *mdev = info->dev;
        struct mlx4_priv *priv = mlx4_priv(mdev);
        enum mlx4_port_type types[MLX4_MAX_PORTS];
        enum mlx4_port_type new_types[MLX4_MAX_PORTS];
-       static DEFINE_MUTEX(set_port_type_mutex);
        int i;
        int err = 0;
 
-       mutex_lock(&set_port_type_mutex);
-
-       if (!strcmp(buf, "ib\n"))
-               info->tmp_type = MLX4_PORT_TYPE_IB;
-       else if (!strcmp(buf, "eth\n"))
-               info->tmp_type = MLX4_PORT_TYPE_ETH;
-       else if (!strcmp(buf, "auto\n"))
-               info->tmp_type = MLX4_PORT_TYPE_AUTO;
-       else {
-               mlx4_err(mdev, "%s is not supported port type\n", buf);
-               err = -EINVAL;
-               goto err_out;
-       }
-
        mlx4_stop_sense(mdev);
        mutex_lock(&priv->port_mutex);
+       info->tmp_type = port_type;
+
        /* Possible type is always the one that was delivered */
        mdev->caps.possible_type[info->port] = info->tmp_type;
 
@@ -1122,6 +1137,37 @@ static ssize_t set_port_type(struct device *dev,
 out:
        mlx4_start_sense(mdev);
        mutex_unlock(&priv->port_mutex);
+
+       return err;
+}
+
+static ssize_t set_port_type(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
+                                                  port_attr);
+       struct mlx4_dev *mdev = info->dev;
+       enum mlx4_port_type port_type;
+       static DEFINE_MUTEX(set_port_type_mutex);
+       int err;
+
+       mutex_lock(&set_port_type_mutex);
+
+       if (!strcmp(buf, "ib\n")) {
+               port_type = MLX4_PORT_TYPE_IB;
+       } else if (!strcmp(buf, "eth\n")) {
+               port_type = MLX4_PORT_TYPE_ETH;
+       } else if (!strcmp(buf, "auto\n")) {
+               port_type = MLX4_PORT_TYPE_AUTO;
+       } else {
+               mlx4_err(mdev, "%s is not supported port type\n", buf);
+               err = -EINVAL;
+               goto err_out;
+       }
+
+       err = __set_port_type(info, port_type);
+
 err_out:
        mutex_unlock(&set_port_type_mutex);
 
@@ -1226,6 +1272,7 @@ err_set_port:
 static int mlx4_mf_bond(struct mlx4_dev *dev)
 {
        int err = 0;
+       int nvfs;
        struct mlx4_slaves_pport slaves_port1;
        struct mlx4_slaves_pport slaves_port2;
        DECLARE_BITMAP(slaves_port_1_2, MLX4_MFUNC_MAX);
@@ -1242,11 +1289,18 @@ static int mlx4_mf_bond(struct mlx4_dev *dev)
                return -EINVAL;
        }
 
+       /* number of virtual functions is number of total functions minus one
+        * physical function for each port.
+        */
+       nvfs = bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) +
+               bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1) - 2;
+
        /* limit on maximum allowed VFs */
-       if ((bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) +
-           bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1)) >
-           MAX_MF_BOND_ALLOWED_SLAVES)
+       if (nvfs > MAX_MF_BOND_ALLOWED_SLAVES) {
+               mlx4_warn(dev, "HA mode is not supported for %d VFs (max %d are allowed)\n",
+                         nvfs, MAX_MF_BOND_ALLOWED_SLAVES);
                return -EINVAL;
+       }
 
        if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
                mlx4_warn(dev, "HA mode unsupported for NON DMFS steering\n");
@@ -2179,8 +2233,12 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 
                dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
 
-               init_hca.log_uar_sz = ilog2(dev->caps.num_uars);
-               init_hca.uar_page_sz = PAGE_SHIFT - 12;
+               /* Always set UAR page size 4KB, set log_uar_sz accordingly */
+               init_hca.log_uar_sz = ilog2(dev->caps.num_uars) +
+                                     PAGE_SHIFT -
+                                     DEFAULT_UAR_PAGE_SHIFT;
+               init_hca.uar_page_sz = DEFAULT_UAR_PAGE_SHIFT - 12;
+
                init_hca.mw_enabled = 0;
                if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||
                    dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN)
@@ -2847,8 +2905,13 @@ no_msi:
 
 static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
 {
+       struct devlink *devlink = priv_to_devlink(mlx4_priv(dev));
        struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
-       int err = 0;
+       int err;
+
+       err = devlink_port_register(devlink, &info->devlink_port, port);
+       if (err)
+               return err;
 
        info->dev = dev;
        info->port = port;
@@ -2873,6 +2936,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
        err = device_create_file(&dev->persist->pdev->dev, &info->port_attr);
        if (err) {
                mlx4_err(dev, "Failed to create file for port %d\n", port);
+               devlink_port_unregister(&info->devlink_port);
                info->port = -1;
        }
 
@@ -3644,23 +3708,54 @@ err_disable_pdev:
        return err;
 }
 
+static int mlx4_devlink_port_type_set(struct devlink_port *devlink_port,
+                                     enum devlink_port_type port_type)
+{
+       struct mlx4_port_info *info = container_of(devlink_port,
+                                                  struct mlx4_port_info,
+                                                  devlink_port);
+       enum mlx4_port_type mlx4_port_type;
+
+       switch (port_type) {
+       case DEVLINK_PORT_TYPE_AUTO:
+               mlx4_port_type = MLX4_PORT_TYPE_AUTO;
+               break;
+       case DEVLINK_PORT_TYPE_ETH:
+               mlx4_port_type = MLX4_PORT_TYPE_ETH;
+               break;
+       case DEVLINK_PORT_TYPE_IB:
+               mlx4_port_type = MLX4_PORT_TYPE_IB;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return __set_port_type(info, mlx4_port_type);
+}
+
+static const struct devlink_ops mlx4_devlink_ops = {
+       .port_type_set  = mlx4_devlink_port_type_set,
+};
+
 static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       struct devlink *devlink;
        struct mlx4_priv *priv;
        struct mlx4_dev *dev;
        int ret;
 
        printk_once(KERN_INFO "%s", mlx4_version);
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
+       devlink = devlink_alloc(&mlx4_devlink_ops, sizeof(*priv));
+       if (!devlink)
                return -ENOMEM;
+       priv = devlink_priv(devlink);
 
        dev       = &priv->dev;
        dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL);
        if (!dev->persist) {
-               kfree(priv);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_devlink_free;
        }
        dev->persist->pdev = pdev;
        dev->persist->dev = dev;
@@ -3669,14 +3764,23 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
        mutex_init(&dev->persist->device_state_mutex);
        mutex_init(&dev->persist->interface_state_mutex);
 
+       ret = devlink_register(devlink, &pdev->dev);
+       if (ret)
+               goto err_persist_free;
+
        ret =  __mlx4_init_one(pdev, id->driver_data, priv);
-       if (ret) {
-               kfree(dev->persist);
-               kfree(priv);
-       } else {
-               pci_save_state(pdev);
-       }
+       if (ret)
+               goto err_devlink_unregister;
 
+       pci_save_state(pdev);
+       return 0;
+
+err_devlink_unregister:
+       devlink_unregister(devlink);
+err_persist_free:
+       kfree(dev->persist);
+err_devlink_free:
+       devlink_free(devlink);
        return ret;
 }
 
@@ -3777,6 +3881,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
        struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
        struct mlx4_dev  *dev  = persist->dev;
        struct mlx4_priv *priv = mlx4_priv(dev);
+       struct devlink *devlink = priv_to_devlink(priv);
        int active_vfs = 0;
 
        mutex_lock(&persist->interface_state_mutex);
@@ -3807,8 +3912,9 @@ static void mlx4_remove_one(struct pci_dev *pdev)
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
+       devlink_unregister(devlink);
        kfree(dev->persist);
-       kfree(priv);
+       devlink_free(devlink);
        pci_set_drvdata(pdev, NULL);
 }
 
index 7baef52db6b7586cf41df128c8ddecc581bc1568..ef9683101eada7081163b7f6bf1473c18bd63da2 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <net/devlink.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/driver.h>
@@ -828,6 +829,7 @@ struct mlx4_port_info {
        struct mlx4_roce_gid_table gid_table;
        int                     base_qpn;
        struct cpu_rmap         *rmap;
+       struct devlink_port     devlink_port;
 };
 
 struct mlx4_sense {
index 35de7d2e6b34939f6db687d2275035fab74957ab..d12ab6a733446c52ba2afb037768bb2dd43f3515 100644 (file)
@@ -607,6 +607,7 @@ static inline struct mlx4_cqe *mlx4_en_get_cqe(void *buf, int idx, int cqe_sz)
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
+void mlx4_en_init_ptys2ethtool_map(void);
 void mlx4_en_update_loopback_state(struct net_device *dev,
                                   netdev_features_t features);
 
index 609c59dc854e987a073e32cb4ff2c08736998edb..b3cc3ab63799462709a569cff08f6e4c5de59f43 100644 (file)
@@ -269,9 +269,15 @@ EXPORT_SYMBOL_GPL(mlx4_bf_free);
 
 int mlx4_init_uar_table(struct mlx4_dev *dev)
 {
-       if (dev->caps.num_uars <= 128) {
-               mlx4_err(dev, "Only %d UAR pages (need more than 128)\n",
-                        dev->caps.num_uars);
+       int num_reserved_uar = mlx4_get_num_reserved_uar(dev);
+
+       mlx4_dbg(dev, "uar_page_shift = %d", dev->uar_page_shift);
+       mlx4_dbg(dev, "Effective reserved_uars=%d", dev->caps.reserved_uars);
+
+       if (dev->caps.num_uars <= num_reserved_uar) {
+               mlx4_err(
+                       dev, "Only %d UAR pages (need more than %d)\n",
+                       dev->caps.num_uars, num_reserved_uar);
                mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n");
                return -ENODEV;
        }
index 787b7bb54d52acd094570283bf6793f1bfb0dab0..211c65087997dd5a92cc53a13f9fd3869927d09d 100644 (file)
@@ -193,10 +193,10 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
        if (need_mf_bond) {
                if (port == 1) {
                        mutex_lock(&table->mutex);
-                       mutex_lock(&dup_table->mutex);
+                       mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
                } else {
                        mutex_lock(&dup_table->mutex);
-                       mutex_lock(&table->mutex);
+                       mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
                }
        } else {
                mutex_lock(&table->mutex);
@@ -389,10 +389,10 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
        if (dup) {
                if (port == 1) {
                        mutex_lock(&table->mutex);
-                       mutex_lock(&dup_table->mutex);
+                       mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
                } else {
                        mutex_lock(&dup_table->mutex);
-                       mutex_lock(&table->mutex);
+                       mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
                }
        } else {
                mutex_lock(&table->mutex);
@@ -479,10 +479,10 @@ int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
        if (dup) {
                if (port == 1) {
                        mutex_lock(&table->mutex);
-                       mutex_lock(&dup_table->mutex);
+                       mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
                } else {
                        mutex_lock(&dup_table->mutex);
-                       mutex_lock(&table->mutex);
+                       mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
                }
        } else {
                mutex_lock(&table->mutex);
@@ -588,10 +588,10 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
        if (need_mf_bond) {
                if (port == 1) {
                        mutex_lock(&table->mutex);
-                       mutex_lock(&dup_table->mutex);
+                       mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
                } else {
                        mutex_lock(&dup_table->mutex);
-                       mutex_lock(&table->mutex);
+                       mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
                }
        } else {
                mutex_lock(&table->mutex);
@@ -764,10 +764,10 @@ void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
        if (dup) {
                if (port == 1) {
                        mutex_lock(&table->mutex);
-                       mutex_lock(&dup_table->mutex);
+                       mutex_lock_nested(&dup_table->mutex, SINGLE_DEPTH_NESTING);
                } else {
                        mutex_lock(&dup_table->mutex);
-                       mutex_lock(&table->mutex);
+                       mutex_lock_nested(&table->mutex, SINGLE_DEPTH_NESTING);
                }
        } else {
                mutex_lock(&table->mutex);
index b46dbe29ef6c8ec72db19c6e8fd841f5cb806a1b..25ce1b030a00f28cb3ea96833d368d7380aaff44 100644 (file)
@@ -915,11 +915,13 @@ static int handle_existing_counter(struct mlx4_dev *dev, u8 slave, int port,
 
        spin_lock_irq(mlx4_tlock(dev));
        r = find_res(dev, counter_index, RES_COUNTER);
-       if (!r || r->owner != slave)
+       if (!r || r->owner != slave) {
                ret = -EINVAL;
-       counter = container_of(r, struct res_counter, com);
-       if (!counter->port)
-               counter->port = port;
+       } else {
+               counter = container_of(r, struct res_counter, com);
+               if (!counter->port)
+                       counter->port = port;
+       }
 
        spin_unlock_irq(mlx4_tlock(dev));
        return ret;
index c503ea05e7427e866d8f26364ccf75f885a81823..1cf722eba607d82e8e34ff498e1b154f8fc8cc5d 100644 (file)
@@ -19,3 +19,15 @@ config MLX5_CORE_EN
          Ethernet support in Mellanox Technologies ConnectX-4 NIC.
          Ethernet and Infiniband support in ConnectX-4 are currently mutually
          exclusive.
+
+config MLX5_CORE_EN_DCB
+       bool "Data Center Bridging (DCB) Support"
+       default y
+       depends on MLX5_CORE_EN && DCB
+       ---help---
+         Say Y here if you want to use Data Center Bridging (DCB) in the
+         driver.
+         If set to N, will not be able to configure QoS and ratelimit attributes.
+         This flag is depended on the kernel's DCB support.
+
+         If unsure, set to Y
index 01c0256effb8f3e70b55920232095ddf4380252f..4fc45ee0c5d165c1b723002cf83472024d1ca393 100644 (file)
@@ -3,6 +3,9 @@ obj-$(CONFIG_MLX5_CORE)         += mlx5_core.o
 mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
                health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o   \
                mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o
+
 mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o \
                en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \
-               en_txrx.o en_clock.o
+               en_txrx.o en_clock.o vxlan.o en_tc.o
+
+mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) +=  en_dcbnl.o
index 037fc4cdf5af675e811f5f50950816d8dfeaff51..97f5114fc11394b1583ed5e6009064bfbfb0daa5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2013-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -560,6 +560,18 @@ const char *mlx5_command_str(int command)
        case MLX5_CMD_OP_ACCESS_REG:
                return "MLX5_CMD_OP_ACCESS_REG";
 
+       case MLX5_CMD_OP_SET_WOL_ROL:
+               return "SET_WOL_ROL";
+
+       case MLX5_CMD_OP_QUERY_WOL_ROL:
+               return "QUERY_WOL_ROL";
+
+       case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
+               return "ADD_VXLAN_UDP_DPORT";
+
+       case MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT:
+               return "DELETE_VXLAN_UDP_DPORT";
+
        default: return "unknown command opcode";
        }
 }
index aac071a7e830b5fd777da7a5e4d014d802ad70d0..0cb4a093958b5c7434b212f4c7b484c888671c32 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -29,6 +29,8 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#ifndef __MLX5_EN_H__
+#define __MLX5_EN_H__
 
 #include <linux/if_vlan.h>
 #include <linux/etherdevice.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/qp.h>
 #include <linux/mlx5/cq.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/vport.h>
 #include <linux/mlx5/transobj.h>
+#include <linux/rhashtable.h>
 #include "wq.h"
 #include "mlx5_core.h"
 
 
 #define MLX5E_NUM_MAIN_GROUPS 9
 
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+#define MLX5E_MAX_BW_ALLOC 100 /* Max percentage of BW allocation */
+#define MLX5E_MIN_BW_ALLOC 1   /* Min percentage of BW allocation */
+#endif
+
 static const char vport_strings[][ETH_GSTRING_LEN] = {
        /* vport statistics */
        "rx_packets",
@@ -95,12 +104,15 @@ static const char vport_strings[][ETH_GSTRING_LEN] = {
        /* SW counters */
        "tso_packets",
        "tso_bytes",
+       "tso_inner_packets",
+       "tso_inner_bytes",
        "lro_packets",
        "lro_bytes",
        "rx_csum_good",
        "rx_csum_none",
        "rx_csum_sw",
        "tx_csum_offload",
+       "tx_csum_inner",
        "tx_queue_stopped",
        "tx_queue_wake",
        "tx_queue_dropped",
@@ -133,18 +145,21 @@ struct mlx5e_vport_stats {
        /* SW counters */
        u64 tso_packets;
        u64 tso_bytes;
+       u64 tso_inner_packets;
+       u64 tso_inner_bytes;
        u64 lro_packets;
        u64 lro_bytes;
        u64 rx_csum_good;
        u64 rx_csum_none;
        u64 rx_csum_sw;
        u64 tx_csum_offload;
+       u64 tx_csum_inner;
        u64 tx_queue_stopped;
        u64 tx_queue_wake;
        u64 tx_queue_dropped;
        u64 rx_wqe_err;
 
-#define NUM_VPORT_COUNTERS     32
+#define NUM_VPORT_COUNTERS     35
 };
 
 static const char pport_strings[][ETH_GSTRING_LEN] = {
@@ -223,6 +238,7 @@ struct mlx5e_pport_stats {
 
 static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
        "packets",
+       "bytes",
        "csum_none",
        "csum_sw",
        "lro_packets",
@@ -232,35 +248,46 @@ static const char rq_stats_strings[][ETH_GSTRING_LEN] = {
 
 struct mlx5e_rq_stats {
        u64 packets;
+       u64 bytes;
        u64 csum_none;
        u64 csum_sw;
        u64 lro_packets;
        u64 lro_bytes;
        u64 wqe_err;
-#define NUM_RQ_STATS 6
+#define NUM_RQ_STATS 7
 };
 
 static const char sq_stats_strings[][ETH_GSTRING_LEN] = {
        "packets",
+       "bytes",
        "tso_packets",
        "tso_bytes",
+       "tso_inner_packets",
+       "tso_inner_bytes",
+       "csum_offload_inner",
+       "nop",
        "csum_offload_none",
        "stopped",
        "wake",
        "dropped",
-       "nop"
 };
 
 struct mlx5e_sq_stats {
+       /* commonly accessed in data path */
        u64 packets;
+       u64 bytes;
        u64 tso_packets;
        u64 tso_bytes;
+       u64 tso_inner_packets;
+       u64 tso_inner_bytes;
+       u64 csum_offload_inner;
+       u64 nop;
+       /* less likely accessed in data path */
        u64 csum_offload_none;
        u64 stopped;
        u64 wake;
        u64 dropped;
-       u64 nop;
-#define NUM_SQ_STATS 8
+#define NUM_SQ_STATS 12
 };
 
 struct mlx5e_stats {
@@ -272,7 +299,6 @@ struct mlx5e_params {
        u8  log_sq_size;
        u8  log_rq_size;
        u16 num_channels;
-       u8  default_vlan_prio;
        u8  num_tc;
        u16 rx_cq_moderation_usec;
        u16 rx_cq_moderation_pkts;
@@ -285,6 +311,9 @@ struct mlx5e_params {
        u8  rss_hfunc;
        u8  toeplitz_hash_key[40];
        u32 indirection_rqt[MLX5E_INDIR_RQT_SIZE];
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       struct ieee_ets ets;
+#endif
 };
 
 struct mlx5e_tstamp {
@@ -304,14 +333,9 @@ enum {
        MLX5E_RQ_STATE_POST_WQES_ENABLE,
 };
 
-enum cq_flags {
-       MLX5E_CQ_HAS_CQES = 1,
-};
-
 struct mlx5e_cq {
        /* data path - accessed per cqe */
        struct mlx5_cqwq           wq;
-       unsigned long              flags;
 
        /* data path - accessed per napi poll */
        struct napi_struct        *napi;
@@ -364,6 +388,7 @@ struct mlx5e_sq_dma {
 
 enum {
        MLX5E_SQ_STATE_WAKE_TXQ_ENABLE,
+       MLX5E_SQ_STATE_BF_ENABLE,
 };
 
 struct mlx5e_sq {
@@ -392,7 +417,6 @@ struct mlx5e_sq {
        struct mlx5_wq_cyc         wq;
        u32                        dma_fifo_mask;
        void __iomem              *uar_map;
-       void __iomem              *uar_bf_map;
        struct netdev_queue       *txq;
        u32                        sqn;
        u16                        bf_buf_size;
@@ -452,6 +476,8 @@ enum mlx5e_traffic_types {
        MLX5E_NUM_TT,
 };
 
+#define IS_HASHING_TT(tt) (tt != MLX5E_TT_ANY)
+
 enum mlx5e_rqt_ix {
        MLX5E_INDIRECTION_RQT,
        MLX5E_SINGLE_RQ_RQT,
@@ -491,21 +517,33 @@ struct mlx5e_vlan_db {
        bool          filter_disabled;
 };
 
+struct mlx5e_vxlan_db {
+       spinlock_t                      lock; /* protect vxlan table */
+       struct radix_tree_root          tree;
+};
+
 struct mlx5e_flow_table {
        int num_groups;
        struct mlx5_flow_table          *t;
        struct mlx5_flow_group          **g;
 };
 
+struct mlx5e_tc_flow_table {
+       struct mlx5_flow_table          *t;
+
+       struct rhashtable_params        ht_params;
+       struct rhashtable               ht;
+};
+
 struct mlx5e_flow_tables {
        struct mlx5_flow_namespace      *ns;
+       struct mlx5e_tc_flow_table      tc;
        struct mlx5e_flow_table         vlan;
        struct mlx5e_flow_table         main;
 };
 
 struct mlx5e_priv {
        /* priv data path fields - start */
-       int                        default_vlan_prio;
        struct mlx5e_sq            **txq_to_sq_map;
        int channeltc_to_txq_map[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC];
        /* priv data path fields - end */
@@ -526,9 +564,9 @@ struct mlx5e_priv {
        struct mlx5e_flow_tables   fts;
        struct mlx5e_eth_addr_db   eth_addr;
        struct mlx5e_vlan_db       vlan;
+       struct mlx5e_vxlan_db      vxlan;
 
        struct mlx5e_params        params;
-       spinlock_t                 async_events_spinlock; /* sync hw events */
        struct work_struct         update_carrier_work;
        struct work_struct         set_rx_mode_work;
        struct delayed_work        update_stats_work;
@@ -591,7 +629,7 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev);
 void mlx5e_completion_event(struct mlx5_core_cq *mcq);
 void mlx5e_cq_error_event(struct mlx5_core_cq *mcq, enum mlx5_event event);
 int mlx5e_napi_poll(struct napi_struct *napi, int budget);
-bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq);
+bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget);
 int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget);
 bool mlx5e_post_rx_wqes(struct mlx5e_rq *rq);
 struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq);
@@ -618,9 +656,12 @@ void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
 void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
 
 int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix);
+void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
 
 int mlx5e_open_locked(struct net_device *netdev);
 int mlx5e_close_locked(struct net_device *netdev);
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+                                  int num_channels);
 
 static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
                                      struct mlx5e_tx_wqe *wqe, int bf_sz)
@@ -636,16 +677,12 @@ static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq,
         * doorbell
         */
        wmb();
-
-       if (bf_sz) {
-               __iowrite64_copy(sq->uar_bf_map + ofst, &wqe->ctrl, bf_sz);
-
-               /* flush the write-combining mapped buffer */
-               wmb();
-
-       } else {
+       if (bf_sz)
+               __iowrite64_copy(sq->uar_map + ofst, &wqe->ctrl, bf_sz);
+       else
                mlx5_write64((__be32 *)&wqe->ctrl, sq->uar_map + ofst, NULL);
-       }
+       /* flush the write-combining mapped buffer */
+       wmb();
 
        sq->bf_offset ^= sq->bf_buf_size;
 }
@@ -665,4 +702,11 @@ static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 }
 
 extern const struct ethtool_ops mlx5e_ethtool_ops;
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+extern const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops;
+int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets);
+#endif
+
 u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev);
+
+#endif /* __MLX5_EN_H__ */
index be6543570b2be18d476773f6b530dfeab6057800..2018eebe1531563e036c41c19372331f8a576b14 100644 (file)
@@ -62,10 +62,11 @@ static void mlx5e_timestamp_overflow(struct work_struct *work)
        struct delayed_work *dwork = to_delayed_work(work);
        struct mlx5e_tstamp *tstamp = container_of(dwork, struct mlx5e_tstamp,
                                                   overflow_work);
+       unsigned long flags;
 
-       write_lock(&tstamp->lock);
+       write_lock_irqsave(&tstamp->lock, flags);
        timecounter_read(&tstamp->clock);
-       write_unlock(&tstamp->lock);
+       write_unlock_irqrestore(&tstamp->lock, flags);
        schedule_delayed_work(&tstamp->overflow_work, tstamp->overflow_period);
 }
 
@@ -136,10 +137,11 @@ static int mlx5e_ptp_settime(struct ptp_clock_info *ptp,
        struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
                                                   ptp_info);
        u64 ns = timespec64_to_ns(ts);
+       unsigned long flags;
 
-       write_lock(&tstamp->lock);
+       write_lock_irqsave(&tstamp->lock, flags);
        timecounter_init(&tstamp->clock, &tstamp->cycles, ns);
-       write_unlock(&tstamp->lock);
+       write_unlock_irqrestore(&tstamp->lock, flags);
 
        return 0;
 }
@@ -150,10 +152,11 @@ static int mlx5e_ptp_gettime(struct ptp_clock_info *ptp,
        struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
                                                   ptp_info);
        u64 ns;
+       unsigned long flags;
 
-       write_lock(&tstamp->lock);
+       write_lock_irqsave(&tstamp->lock, flags);
        ns = timecounter_read(&tstamp->clock);
-       write_unlock(&tstamp->lock);
+       write_unlock_irqrestore(&tstamp->lock, flags);
 
        *ts = ns_to_timespec64(ns);
 
@@ -164,10 +167,11 @@ static int mlx5e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 {
        struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
                                                   ptp_info);
+       unsigned long flags;
 
-       write_lock(&tstamp->lock);
+       write_lock_irqsave(&tstamp->lock, flags);
        timecounter_adjtime(&tstamp->clock, delta);
-       write_unlock(&tstamp->lock);
+       write_unlock_irqrestore(&tstamp->lock, flags);
 
        return 0;
 }
@@ -176,6 +180,7 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
 {
        u64 adj;
        u32 diff;
+       unsigned long flags;
        int neg_adj = 0;
        struct mlx5e_tstamp *tstamp = container_of(ptp, struct mlx5e_tstamp,
                                                  ptp_info);
@@ -189,11 +194,11 @@ static int mlx5e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 delta)
        adj *= delta;
        diff = div_u64(adj, 1000000000ULL);
 
-       write_lock(&tstamp->lock);
+       write_lock_irqsave(&tstamp->lock, flags);
        timecounter_read(&tstamp->clock);
        tstamp->cycles.mult = neg_adj ? tstamp->nominal_c_mult - diff :
                                        tstamp->nominal_c_mult + diff;
-       write_unlock(&tstamp->lock);
+       write_unlock_irqrestore(&tstamp->lock, flags);
 
        return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
new file mode 100644 (file)
index 0000000..3036f27
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include "en.h"
+
+#define MLX5E_MAX_PRIORITY 8
+
+#define MLX5E_100MB (100000)
+#define MLX5E_1GB   (1000000)
+
+static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
+                                  struct ieee_ets *ets)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (!MLX5_CAP_GEN(priv->mdev, ets))
+               return -ENOTSUPP;
+
+       memcpy(ets, &priv->params.ets, sizeof(*ets));
+       return 0;
+}
+
+enum {
+       MLX5E_VENDOR_TC_GROUP_NUM = 7,
+       MLX5E_ETS_TC_GROUP_NUM    = 0,
+};
+
+static void mlx5e_build_tc_group(struct ieee_ets *ets, u8 *tc_group, int max_tc)
+{
+       bool any_tc_mapped_to_ets = false;
+       int strict_group;
+       int i;
+
+       for (i = 0; i <= max_tc; i++)
+               if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS)
+                       any_tc_mapped_to_ets = true;
+
+       strict_group = any_tc_mapped_to_ets ? 1 : 0;
+
+       for (i = 0; i <= max_tc; i++) {
+               switch (ets->tc_tsa[i]) {
+               case IEEE_8021QAZ_TSA_VENDOR:
+                       tc_group[i] = MLX5E_VENDOR_TC_GROUP_NUM;
+                       break;
+               case IEEE_8021QAZ_TSA_STRICT:
+                       tc_group[i] = strict_group++;
+                       break;
+               case IEEE_8021QAZ_TSA_ETS:
+                       tc_group[i] = MLX5E_ETS_TC_GROUP_NUM;
+                       break;
+               }
+       }
+}
+
+static void mlx5e_build_tc_tx_bw(struct ieee_ets *ets, u8 *tc_tx_bw,
+                                u8 *tc_group, int max_tc)
+{
+       int i;
+
+       for (i = 0; i <= max_tc; i++) {
+               switch (ets->tc_tsa[i]) {
+               case IEEE_8021QAZ_TSA_VENDOR:
+                       tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
+                       break;
+               case IEEE_8021QAZ_TSA_STRICT:
+                       tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
+                       break;
+               case IEEE_8021QAZ_TSA_ETS:
+                       tc_tx_bw[i] = ets->tc_tx_bw[i] ?: MLX5E_MIN_BW_ALLOC;
+                       break;
+               }
+       }
+}
+
+int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets *ets)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS];
+       u8 tc_group[IEEE_8021QAZ_MAX_TCS];
+       int max_tc = mlx5_max_tc(mdev);
+       int err;
+
+       if (!MLX5_CAP_GEN(mdev, ets))
+               return -ENOTSUPP;
+
+       mlx5e_build_tc_group(ets, tc_group, max_tc);
+       mlx5e_build_tc_tx_bw(ets, tc_tx_bw, tc_group, max_tc);
+
+       err = mlx5_set_port_prio_tc(mdev, ets->prio_tc);
+       if (err)
+               return err;
+
+       err = mlx5_set_port_tc_group(mdev, tc_group);
+       if (err)
+               return err;
+
+       return mlx5_set_port_tc_bw_alloc(mdev, tc_tx_bw);
+}
+
+static int mlx5e_dbcnl_validate_ets(struct ieee_ets *ets)
+{
+       int bw_sum = 0;
+       int i;
+
+       /* Validate Priority */
+       for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+               if (ets->prio_tc[i] >= MLX5E_MAX_PRIORITY)
+                       return -EINVAL;
+       }
+
+       /* Validate Bandwidth Sum */
+       for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+               if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS)
+                       bw_sum += ets->tc_tx_bw[i];
+       }
+
+       if (bw_sum != 0 && bw_sum != 100)
+               return -EINVAL;
+       return 0;
+}
+
+static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev,
+                                  struct ieee_ets *ets)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int err;
+
+       err = mlx5e_dbcnl_validate_ets(ets);
+       if (err)
+               return err;
+
+       err = mlx5e_dcbnl_ieee_setets_core(priv, ets);
+       if (err)
+               return err;
+
+       memcpy(&priv->params.ets, ets, sizeof(*ets));
+       priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
+
+       return 0;
+}
+
+static int mlx5e_dcbnl_ieee_getpfc(struct net_device *dev,
+                                  struct ieee_pfc *pfc)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+
+       pfc->pfc_cap = mlx5_max_tc(mdev) + 1;
+
+       return mlx5_query_port_pfc(mdev, &pfc->pfc_en, NULL);
+}
+
+static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev,
+                                  struct ieee_pfc *pfc)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       enum mlx5_port_status ps;
+       u8 curr_pfc_en;
+       int ret;
+
+       mlx5_query_port_pfc(mdev, &curr_pfc_en, NULL);
+
+       if (pfc->pfc_en == curr_pfc_en)
+               return 0;
+
+       mlx5_query_port_admin_status(mdev, &ps);
+       if (ps == MLX5_PORT_UP)
+               mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN);
+
+       ret = mlx5_set_port_pfc(mdev, pfc->pfc_en, pfc->pfc_en);
+
+       if (ps == MLX5_PORT_UP)
+               mlx5_set_port_admin_status(mdev, MLX5_PORT_UP);
+
+       return ret;
+}
+
+static u8 mlx5e_dcbnl_getdcbx(struct net_device *dev)
+{
+       return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
+}
+
+static u8 mlx5e_dcbnl_setdcbx(struct net_device *dev, u8 mode)
+{
+       if ((mode & DCB_CAP_DCBX_LLD_MANAGED) ||
+           (mode & DCB_CAP_DCBX_VER_CEE) ||
+           !(mode & DCB_CAP_DCBX_VER_IEEE) ||
+           !(mode & DCB_CAP_DCBX_HOST))
+               return 1;
+
+       return 0;
+}
+
+static int mlx5e_dcbnl_ieee_getmaxrate(struct net_device *netdev,
+                                      struct ieee_maxrate *maxrate)
+{
+       struct mlx5e_priv *priv    = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
+       u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
+       int err;
+       int i;
+
+       err = mlx5_query_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit);
+       if (err)
+               return err;
+
+       memset(maxrate->tc_maxrate, 0, sizeof(maxrate->tc_maxrate));
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               switch (max_bw_unit[i]) {
+               case MLX5_100_MBPS_UNIT:
+                       maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_100MB;
+                       break;
+               case MLX5_GBPS_UNIT:
+                       maxrate->tc_maxrate[i] = max_bw_value[i] * MLX5E_1GB;
+                       break;
+               case MLX5_BW_NO_LIMIT:
+                       break;
+               default:
+                       WARN(true, "non-supported BW unit");
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev,
+                                      struct ieee_maxrate *maxrate)
+{
+       struct mlx5e_priv *priv    = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
+       u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
+       __u64 upper_limit_mbps = roundup(255 * MLX5E_100MB, MLX5E_1GB);
+       int i;
+
+       memset(max_bw_value, 0, sizeof(max_bw_value));
+       memset(max_bw_unit, 0, sizeof(max_bw_unit));
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               if (!maxrate->tc_maxrate[i]) {
+                       max_bw_unit[i]  = MLX5_BW_NO_LIMIT;
+                       continue;
+               }
+               if (maxrate->tc_maxrate[i] < upper_limit_mbps) {
+                       max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
+                                                 MLX5E_100MB);
+                       max_bw_value[i] = max_bw_value[i] ? max_bw_value[i] : 1;
+                       max_bw_unit[i]  = MLX5_100_MBPS_UNIT;
+               } else {
+                       max_bw_value[i] = div_u64(maxrate->tc_maxrate[i],
+                                                 MLX5E_1GB);
+                       max_bw_unit[i]  = MLX5_GBPS_UNIT;
+               }
+       }
+
+       return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit);
+}
+
+const struct dcbnl_rtnl_ops mlx5e_dcbnl_ops = {
+       .ieee_getets    = mlx5e_dcbnl_ieee_getets,
+       .ieee_setets    = mlx5e_dcbnl_ieee_setets,
+       .ieee_getmaxrate = mlx5e_dcbnl_ieee_getmaxrate,
+       .ieee_setmaxrate = mlx5e_dcbnl_ieee_setmaxrate,
+       .ieee_getpfc    = mlx5e_dcbnl_ieee_getpfc,
+       .ieee_setpfc    = mlx5e_dcbnl_ieee_setpfc,
+       .getdcbx        = mlx5e_dcbnl_getdcbx,
+       .setdcbx        = mlx5e_dcbnl_setdcbx,
+};
index 65624ac65b4c347ac5dedf55f3b209de799e7e5f..68834b715f6c114c89d6df339cb9cc81a72b8f75 100644 (file)
@@ -211,13 +211,14 @@ static void mlx5e_get_strings(struct net_device *dev,
                                sprintf(data + (idx++) * ETH_GSTRING_LEN,
                                        "rx%d_%s", i, rq_stats_strings[j]);
 
-               for (i = 0; i < priv->params.num_channels; i++)
-                       for (tc = 0; tc < priv->params.num_tc; tc++)
+               for (tc = 0; tc < priv->params.num_tc; tc++)
+                       for (i = 0; i < priv->params.num_channels; i++)
                                for (j = 0; j < NUM_SQ_STATS; j++)
                                        sprintf(data +
-                                               (idx++) * ETH_GSTRING_LEN,
-                                               "tx%d_%d_%s", i, tc,
-                                               sq_stats_strings[j]);
+                                             (idx++) * ETH_GSTRING_LEN,
+                                             "tx%d_%s",
+                                             priv->channeltc_to_txq_map[i][tc],
+                                             sq_stats_strings[j]);
                break;
        }
 }
@@ -249,8 +250,8 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev,
                                                &priv->state) ? 0 :
                                       ((u64 *)&priv->channel[i]->rq.stats)[j];
 
-       for (i = 0; i < priv->params.num_channels; i++)
-               for (tc = 0; tc < priv->params.num_tc; tc++)
+       for (tc = 0; tc < priv->params.num_tc; tc++)
+               for (i = 0; i < priv->params.num_channels; i++)
                        for (j = 0; j < NUM_SQ_STATS; j++)
                                data[idx++] = !test_bit(MLX5E_STATE_OPENED,
                                                        &priv->state) ? 0 :
@@ -385,6 +386,8 @@ static int mlx5e_set_channels(struct net_device *dev,
                mlx5e_close_locked(dev);
 
        priv->params.num_channels = count;
+       mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+                                     MLX5E_INDIR_RQT_SIZE, count);
 
        if (was_opened)
                err = mlx5e_open_locked(dev);
@@ -399,6 +402,9 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
+               return -ENOTSUPP;
+
        coal->rx_coalesce_usecs       = priv->params.rx_cq_moderation_usec;
        coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts;
        coal->tx_coalesce_usecs       = priv->params.tx_cq_moderation_usec;
@@ -416,11 +422,18 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
        int tc;
        int i;
 
+       if (!MLX5_CAP_GEN(mdev, cq_moderation))
+               return -ENOTSUPP;
+
+       mutex_lock(&priv->state_lock);
        priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs;
        priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames;
        priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs;
        priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames;
 
+       if (!test_bit(MLX5E_STATE_OPENED, &priv->state))
+               goto out;
+
        for (i = 0; i < priv->params.num_channels; ++i) {
                c = priv->channel[i];
 
@@ -436,6 +449,8 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
                                               coal->rx_max_coalesced_frames);
        }
 
+out:
+       mutex_unlock(&priv->state_lock);
        return 0;
 }
 
@@ -703,18 +718,36 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
        return 0;
 }
 
+static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
+       int i;
+
+       MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
+       mlx5e_build_tir_ctx_hash(tirc, priv);
+
+       for (i = 0; i < MLX5E_NUM_TT; i++)
+               if (IS_HASHING_TT(i))
+                       mlx5_core_modify_tir(mdev, priv->tirn[i], in, inlen);
+}
+
 static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
                          const u8 *key, const u8 hfunc)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
-       bool close_open;
-       int err = 0;
+       int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+       void *in;
 
        if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&
            (hfunc != ETH_RSS_HASH_XOR) &&
            (hfunc != ETH_RSS_HASH_TOP))
                return -EINVAL;
 
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
        mutex_lock(&priv->state_lock);
 
        if (indir) {
@@ -723,11 +756,6 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
                mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT);
        }
 
-       close_open = (key || (hfunc != ETH_RSS_HASH_NO_CHANGE)) &&
-                    test_bit(MLX5E_STATE_OPENED, &priv->state);
-       if (close_open)
-               mlx5e_close_locked(dev);
-
        if (key)
                memcpy(priv->params.toeplitz_hash_key, key,
                       sizeof(priv->params.toeplitz_hash_key));
@@ -735,12 +763,13 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
        if (hfunc != ETH_RSS_HASH_NO_CHANGE)
                priv->params.rss_hfunc = hfunc;
 
-       if (close_open)
-               err = mlx5e_open_locked(priv->netdev);
+       mlx5e_modify_tirs_hash(priv, in, inlen);
 
        mutex_unlock(&priv->state_lock);
 
-       return err;
+       kvfree(in);
+
+       return 0;
 }
 
 static int mlx5e_get_rxnfc(struct net_device *netdev,
@@ -884,6 +913,129 @@ static int mlx5e_get_ts_info(struct net_device *dev,
        return 0;
 }
 
+static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev)
+{
+       __u32 ret = 0;
+
+       if (MLX5_CAP_GEN(mdev, wol_g))
+               ret |= WAKE_MAGIC;
+
+       if (MLX5_CAP_GEN(mdev, wol_s))
+               ret |= WAKE_MAGICSECURE;
+
+       if (MLX5_CAP_GEN(mdev, wol_a))
+               ret |= WAKE_ARP;
+
+       if (MLX5_CAP_GEN(mdev, wol_b))
+               ret |= WAKE_BCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_m))
+               ret |= WAKE_MCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_u))
+               ret |= WAKE_UCAST;
+
+       if (MLX5_CAP_GEN(mdev, wol_p))
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode)
+{
+       __u32 ret = 0;
+
+       if (mode & MLX5_WOL_MAGIC)
+               ret |= WAKE_MAGIC;
+
+       if (mode & MLX5_WOL_SECURED_MAGIC)
+               ret |= WAKE_MAGICSECURE;
+
+       if (mode & MLX5_WOL_ARP)
+               ret |= WAKE_ARP;
+
+       if (mode & MLX5_WOL_BROADCAST)
+               ret |= WAKE_BCAST;
+
+       if (mode & MLX5_WOL_MULTICAST)
+               ret |= WAKE_MCAST;
+
+       if (mode & MLX5_WOL_UNICAST)
+               ret |= WAKE_UCAST;
+
+       if (mode & MLX5_WOL_PHY_ACTIVITY)
+               ret |= WAKE_PHY;
+
+       return ret;
+}
+
+static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode)
+{
+       u8 ret = 0;
+
+       if (mode & WAKE_MAGIC)
+               ret |= MLX5_WOL_MAGIC;
+
+       if (mode & WAKE_MAGICSECURE)
+               ret |= MLX5_WOL_SECURED_MAGIC;
+
+       if (mode & WAKE_ARP)
+               ret |= MLX5_WOL_ARP;
+
+       if (mode & WAKE_BCAST)
+               ret |= MLX5_WOL_BROADCAST;
+
+       if (mode & WAKE_MCAST)
+               ret |= MLX5_WOL_MULTICAST;
+
+       if (mode & WAKE_UCAST)
+               ret |= MLX5_WOL_UNICAST;
+
+       if (mode & WAKE_PHY)
+               ret |= MLX5_WOL_PHY_ACTIVITY;
+
+       return ret;
+}
+
+static void mlx5e_get_wol(struct net_device *netdev,
+                         struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 mlx5_wol_mode;
+       int err;
+
+       memset(wol, 0, sizeof(*wol));
+
+       wol->supported = mlx5e_get_wol_supported(mdev);
+       if (!wol->supported)
+               return;
+
+       err = mlx5_query_port_wol(mdev, &mlx5_wol_mode);
+       if (err)
+               return;
+
+       wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode);
+}
+
+static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       __u32 wol_supported = mlx5e_get_wol_supported(mdev);
+       u32 mlx5_wol_mode;
+
+       if (!wol_supported)
+               return -ENOTSUPP;
+
+       if (wol->wolopts & ~wol_supported)
+               return -EINVAL;
+
+       mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts);
+
+       return mlx5_set_port_wol(mdev, mlx5_wol_mode);
+}
+
 const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
@@ -908,4 +1060,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .get_pauseparam    = mlx5e_get_pauseparam,
        .set_pauseparam    = mlx5e_set_pauseparam,
        .get_ts_info       = mlx5e_get_ts_info,
+       .get_wol           = mlx5e_get_wol,
+       .set_wol           = mlx5e_set_wol,
 };
index 80d81abc4820d301d0cfd6bbc3764d6d34b4a274..d00a2420341010e8c759b6e2bc44debbf498a7b0 100644 (file)
@@ -1041,7 +1041,7 @@ static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv)
        int err;
 
        ft->num_groups = 0;
-       ft->t = mlx5_create_flow_table(priv->fts.ns, 0, MLX5E_MAIN_TABLE_SIZE);
+       ft->t = mlx5_create_flow_table(priv->fts.ns, 1, MLX5E_MAIN_TABLE_SIZE);
 
        if (IS_ERR(ft->t)) {
                err = PTR_ERR(ft->t);
@@ -1150,7 +1150,7 @@ static int mlx5e_create_vlan_flow_table(struct mlx5e_priv *priv)
        int err;
 
        ft->num_groups = 0;
-       ft->t = mlx5_create_flow_table(priv->fts.ns, 0, MLX5E_VLAN_TABLE_SIZE);
+       ft->t = mlx5_create_flow_table(priv->fts.ns, 1, MLX5E_VLAN_TABLE_SIZE);
 
        if (IS_ERR(ft->t)) {
                err = PTR_ERR(ft->t);
index 6a3e430f10624e637fb8b3dcfaade968d2a83c53..ac5807803c8471d7b7015fb3c992e737e3b83f98 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
  * SOFTWARE.
  */
 
+#include <net/tc_act/tc_gact.h>
+#include <net/pkt_cls.h>
 #include <linux/mlx5/fs.h>
+#include <net/vxlan.h>
 #include "en.h"
+#include "en_tc.h"
 #include "eswitch.h"
+#include "vxlan.h"
 
 struct mlx5e_rq_param {
        u32                        rqc[MLX5_ST_SZ_DW(rqc)];
@@ -141,11 +146,18 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
                return;
 
        /* Collect firts the SW counters and then HW for consistency */
+       s->rx_packets           = 0;
+       s->rx_bytes             = 0;
+       s->tx_packets           = 0;
+       s->tx_bytes             = 0;
        s->tso_packets          = 0;
        s->tso_bytes            = 0;
+       s->tso_inner_packets    = 0;
+       s->tso_inner_bytes      = 0;
        s->tx_queue_stopped     = 0;
        s->tx_queue_wake        = 0;
        s->tx_queue_dropped     = 0;
+       s->tx_csum_inner        = 0;
        tx_offload_none         = 0;
        s->lro_packets          = 0;
        s->lro_bytes            = 0;
@@ -155,6 +167,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
        for (i = 0; i < priv->params.num_channels; i++) {
                rq_stats = &priv->channel[i]->rq.stats;
 
+               s->rx_packets   += rq_stats->packets;
+               s->rx_bytes     += rq_stats->bytes;
                s->lro_packets  += rq_stats->lro_packets;
                s->lro_bytes    += rq_stats->lro_bytes;
                s->rx_csum_none += rq_stats->csum_none;
@@ -164,11 +178,16 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
                for (j = 0; j < priv->params.num_tc; j++) {
                        sq_stats = &priv->channel[i]->sq[j].stats;
 
+                       s->tx_packets           += sq_stats->packets;
+                       s->tx_bytes             += sq_stats->bytes;
                        s->tso_packets          += sq_stats->tso_packets;
                        s->tso_bytes            += sq_stats->tso_bytes;
+                       s->tso_inner_packets    += sq_stats->tso_inner_packets;
+                       s->tso_inner_bytes      += sq_stats->tso_inner_bytes;
                        s->tx_queue_stopped     += sq_stats->stopped;
                        s->tx_queue_wake        += sq_stats->wake;
                        s->tx_queue_dropped     += sq_stats->dropped;
+                       s->tx_csum_inner        += sq_stats->csum_offload_inner;
                        tx_offload_none         += sq_stats->csum_offload_none;
                }
        }
@@ -225,25 +244,8 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
        s->tx_broadcast_bytes   =
                MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
 
-       s->rx_packets =
-               s->rx_unicast_packets +
-               s->rx_multicast_packets +
-               s->rx_broadcast_packets;
-       s->rx_bytes =
-               s->rx_unicast_bytes +
-               s->rx_multicast_bytes +
-               s->rx_broadcast_bytes;
-       s->tx_packets =
-               s->tx_unicast_packets +
-               s->tx_multicast_packets +
-               s->tx_broadcast_packets;
-       s->tx_bytes =
-               s->tx_unicast_bytes +
-               s->tx_multicast_bytes +
-               s->tx_broadcast_bytes;
-
        /* Update calculated offload counters */
-       s->tx_csum_offload = s->tx_packets - tx_offload_none;
+       s->tx_csum_offload = s->tx_packets - tx_offload_none - s->tx_csum_inner;
        s->rx_csum_good    = s->rx_packets - s->rx_csum_none -
                               s->rx_csum_sw;
 
@@ -267,9 +269,14 @@ static void mlx5e_update_stats_work(struct work_struct *work)
        mutex_unlock(&priv->state_lock);
 }
 
-static void __mlx5e_async_event(struct mlx5e_priv *priv,
-                               enum mlx5_dev_event event)
+static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
+                             enum mlx5_dev_event event, unsigned long param)
 {
+       struct mlx5e_priv *priv = vpriv;
+
+       if (!test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state))
+               return;
+
        switch (event) {
        case MLX5_DEV_EVENT_PORT_UP:
        case MLX5_DEV_EVENT_PORT_DOWN:
@@ -281,17 +288,6 @@ static void __mlx5e_async_event(struct mlx5e_priv *priv,
        }
 }
 
-static void mlx5e_async_event(struct mlx5_core_dev *mdev, void *vpriv,
-                             enum mlx5_dev_event event, unsigned long param)
-{
-       struct mlx5e_priv *priv = vpriv;
-
-       spin_lock(&priv->async_events_spinlock);
-       if (test_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state))
-               __mlx5e_async_event(priv, event);
-       spin_unlock(&priv->async_events_spinlock);
-}
-
 static void mlx5e_enable_async_events(struct mlx5e_priv *priv)
 {
        set_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
@@ -299,9 +295,8 @@ static void mlx5e_enable_async_events(struct mlx5e_priv *priv)
 
 static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
 {
-       spin_lock_irq(&priv->async_events_spinlock);
        clear_bit(MLX5E_STATE_ASYNC_EVENTS_ENABLE, &priv->state);
-       spin_unlock_irq(&priv->async_events_spinlock);
+       synchronize_irq(mlx5_get_msix_vec(priv->mdev, MLX5_EQ_VEC_ASYNC));
 }
 
 #define MLX5E_HW2SW_MTU(hwmtu) (hwmtu - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN))
@@ -547,7 +542,7 @@ static int mlx5e_create_sq(struct mlx5e_channel *c,
        int txq_ix;
        int err;
 
-       err = mlx5_alloc_map_uar(mdev, &sq->uar);
+       err = mlx5_alloc_map_uar(mdev, &sq->uar, true);
        if (err)
                return err;
 
@@ -559,8 +554,12 @@ static int mlx5e_create_sq(struct mlx5e_channel *c,
                goto err_unmap_free_uar;
 
        sq->wq.db       = &sq->wq.db[MLX5_SND_DBR];
-       sq->uar_map     = sq->uar.map;
-       sq->uar_bf_map  = sq->uar.bf_map;
+       if (sq->uar.bf_map) {
+               set_bit(MLX5E_SQ_STATE_BF_ENABLE, &sq->state);
+               sq->uar_map = sq->uar.bf_map;
+       } else {
+               sq->uar_map = sq->uar.map;
+       }
        sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2;
        sq->max_inline  = param->max_inline;
 
@@ -869,12 +868,10 @@ static int mlx5e_open_cq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_cq;
 
-       err = mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
-                                            moderation_usecs,
-                                            moderation_frames);
-       if (err)
-               goto err_destroy_cq;
-
+       if (MLX5_CAP_GEN(mdev, cq_moderation))
+               mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
+                                              moderation_usecs,
+                                              moderation_frames);
        return 0;
 
 err_destroy_cq:
@@ -1063,6 +1060,15 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
        param->wq.linear = 1;
 }
 
+static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param)
+{
+       void *rqc = param->rqc;
+       void *wq = MLX5_ADDR_OF(rqc, rqc, wq);
+
+       MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST);
+       MLX5_SET(wq, wq, log_wq_stride,    ilog2(sizeof(struct mlx5e_rx_wqe)));
+}
+
 static void mlx5e_build_sq_param(struct mlx5e_priv *priv,
                                 struct mlx5e_sq_param *param)
 {
@@ -1199,7 +1205,6 @@ static void mlx5e_fill_indir_rqt_rqns(struct mlx5e_priv *priv, void *rqtc)
                        ix = mlx5e_bits_invert(i, MLX5E_LOG_INDIR_RQT_SIZE);
 
                ix = priv->params.indirection_rqt[ix];
-               ix = ix % priv->params.num_channels;
                MLX5_SET(rqtc, rqtc, rq_num[i],
                         test_bit(MLX5E_STATE_OPENED, &priv->state) ?
                         priv->channel[ix]->rq.rqn :
@@ -1317,7 +1322,22 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)
                              lro_timer_supported_periods[2]));
 }
 
-static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
+void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
+{
+       MLX5_SET(tirc, tirc, rx_hash_fn,
+                mlx5e_rx_hash_fn(priv->params.rss_hfunc));
+       if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
+               void *rss_key = MLX5_ADDR_OF(tirc, tirc,
+                                            rx_hash_toeplitz_key);
+               size_t len = MLX5_FLD_SZ_BYTES(tirc,
+                                              rx_hash_toeplitz_key);
+
+               MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
+               memcpy(rss_key, priv->params.toeplitz_hash_key, len);
+       }
+}
+
+static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
 
@@ -1325,6 +1345,7 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
        void *tirc;
        int inlen;
        int err;
+       int tt;
 
        inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
        in = mlx5_vzalloc(inlen);
@@ -1336,7 +1357,11 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
 
        mlx5e_build_tir_ctx_lro(tirc, priv);
 
-       err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+       for (tt = 0; tt < MLX5E_NUM_TT; tt++) {
+               err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen);
+               if (err)
+                       break;
+       }
 
        kvfree(in);
 
@@ -1400,6 +1425,24 @@ static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
        return 0;
 }
 
+static void mlx5e_netdev_set_tcs(struct net_device *netdev)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int nch = priv->params.num_channels;
+       int ntc = priv->params.num_tc;
+       int tc;
+
+       netdev_reset_tc(netdev);
+
+       if (ntc == 1)
+               return;
+
+       netdev_set_num_tc(netdev, ntc);
+
+       for (tc = 0; tc < ntc; tc++)
+               netdev_set_tc_queue(netdev, tc, nch, tc * nch);
+}
+
 int mlx5e_open_locked(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1408,6 +1451,8 @@ int mlx5e_open_locked(struct net_device *netdev)
 
        set_bit(MLX5E_STATE_OPENED, &priv->state);
 
+       mlx5e_netdev_set_tcs(netdev);
+
        num_txqs = priv->params.num_channels * priv->params.num_tc;
        netif_set_real_num_tx_queues(netdev, num_txqs);
        netif_set_real_num_rx_queues(netdev, priv->params.num_channels);
@@ -1430,8 +1475,8 @@ int mlx5e_open_locked(struct net_device *netdev)
                goto err_close_channels;
        }
 
-       mlx5e_update_carrier(priv);
        mlx5e_redirect_rqts(priv);
+       mlx5e_update_carrier(priv);
        mlx5e_timestamp_init(priv);
 
        schedule_delayed_work(&priv->update_stats_work, 0);
@@ -1470,8 +1515,8 @@ int mlx5e_close_locked(struct net_device *netdev)
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
 
        mlx5e_timestamp_cleanup(priv);
-       mlx5e_redirect_rqts(priv);
        netif_carrier_off(priv->netdev);
+       mlx5e_redirect_rqts(priv);
        mlx5e_close_channels(priv);
 
        return 0;
@@ -1553,8 +1598,7 @@ static int mlx5e_open_drop_rq(struct mlx5e_priv *priv)
 
        memset(&cq_param, 0, sizeof(cq_param));
        memset(&rq_param, 0, sizeof(rq_param));
-       mlx5e_build_rx_cq_param(priv, &cq_param);
-       mlx5e_build_rq_param(priv, &rq_param);
+       mlx5e_build_drop_rq_param(&rq_param);
 
        err = mlx5e_create_drop_cq(priv, cq, &cq_param);
        if (err)
@@ -1602,7 +1646,7 @@ static int mlx5e_create_tis(struct mlx5e_priv *priv, int tc)
 
        memset(in, 0, sizeof(in));
 
-       MLX5_SET(tisc, tisc, prio,  tc);
+       MLX5_SET(tisc, tisc, prio, tc << 1);
        MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
 
        return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]);
@@ -1618,7 +1662,7 @@ static int mlx5e_create_tises(struct mlx5e_priv *priv)
        int err;
        int tc;
 
-       for (tc = 0; tc < priv->params.num_tc; tc++) {
+       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++) {
                err = mlx5e_create_tis(priv, tc);
                if (err)
                        goto err_close_tises;
@@ -1637,7 +1681,7 @@ static void mlx5e_destroy_tises(struct mlx5e_priv *priv)
 {
        int tc;
 
-       for (tc = 0; tc < priv->params.num_tc; tc++)
+       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++)
                mlx5e_destroy_tis(priv, tc);
 }
 
@@ -1672,17 +1716,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt)
        default:
                MLX5_SET(tirc, tirc, indirect_table,
                         priv->rqtn[MLX5E_INDIRECTION_RQT]);
-               MLX5_SET(tirc, tirc, rx_hash_fn,
-                        mlx5e_rx_hash_fn(priv->params.rss_hfunc));
-               if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
-                       void *rss_key = MLX5_ADDR_OF(tirc, tirc,
-                                                    rx_hash_toeplitz_key);
-                       size_t len = MLX5_FLD_SZ_BYTES(tirc,
-                                                      rx_hash_toeplitz_key);
-
-                       MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
-                       memcpy(rss_key, priv->params.toeplitz_hash_key, len);
-               }
+               mlx5e_build_tir_ctx_hash(tirc, priv);
                break;
        }
 
@@ -1824,6 +1858,58 @@ static void mlx5e_destroy_tirs(struct mlx5e_priv *priv)
                mlx5e_destroy_tir(priv, i);
 }
 
+static int mlx5e_setup_tc(struct net_device *netdev, u8 tc)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       bool was_opened;
+       int err = 0;
+
+       if (tc && tc != MLX5E_MAX_NUM_TC)
+               return -EINVAL;
+
+       mutex_lock(&priv->state_lock);
+
+       was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
+       if (was_opened)
+               mlx5e_close_locked(priv->netdev);
+
+       priv->params.num_tc = tc ? tc : 1;
+
+       if (was_opened)
+               err = mlx5e_open_locked(priv->netdev);
+
+       mutex_unlock(&priv->state_lock);
+
+       return err;
+}
+
+static int mlx5e_ndo_setup_tc(struct net_device *dev, u32 handle,
+                             __be16 proto, struct tc_to_netdev *tc)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+
+       if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
+               goto mqprio;
+
+       switch (tc->type) {
+       case TC_SETUP_CLSFLOWER:
+               switch (tc->cls_flower->command) {
+               case TC_CLSFLOWER_REPLACE:
+                       return mlx5e_configure_flower(priv, proto, tc->cls_flower);
+               case TC_CLSFLOWER_DESTROY:
+                       return mlx5e_delete_flower(priv, tc->cls_flower);
+               }
+       default:
+               return -EOPNOTSUPP;
+       }
+
+mqprio:
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       return mlx5e_setup_tc(dev, tc->tc);
+}
+
 static struct rtnl_link_stats64 *
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
@@ -1885,8 +1971,10 @@ static int mlx5e_set_features(struct net_device *netdev,
                        mlx5e_close_locked(priv->netdev);
 
                priv->params.lro_en = !!(features & NETIF_F_LRO);
-               mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV4_TCP);
-               mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV6_TCP);
+               err = mlx5e_modify_tirs_lro(priv);
+               if (err)
+                       mlx5_core_warn(priv->mdev, "lro modify failed, %d\n",
+                                      err);
 
                if (was_opened)
                        err = mlx5e_open_locked(priv->netdev);
@@ -1901,6 +1989,13 @@ static int mlx5e_set_features(struct net_device *netdev,
                        mlx5e_disable_vlan_filter(priv);
        }
 
+       if ((changes & NETIF_F_HW_TC) && !(features & NETIF_F_HW_TC) &&
+           mlx5e_tc_num_filters(priv)) {
+               netdev_err(netdev,
+                          "Active offloaded tc filters, can't turn hw_tc_offload off\n");
+               return -EINVAL;
+       }
+
        return err;
 }
 
@@ -2024,18 +2119,116 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
                                            vf_stats);
 }
 
-static struct net_device_ops mlx5e_netdev_ops = {
+static void mlx5e_add_vxlan_port(struct net_device *netdev,
+                                sa_family_t sa_family, __be16 port)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (!mlx5e_vxlan_allowed(priv->mdev))
+               return;
+
+       mlx5e_vxlan_add_port(priv, be16_to_cpu(port));
+}
+
+static void mlx5e_del_vxlan_port(struct net_device *netdev,
+                                sa_family_t sa_family, __be16 port)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       if (!mlx5e_vxlan_allowed(priv->mdev))
+               return;
+
+       mlx5e_vxlan_del_port(priv, be16_to_cpu(port));
+}
+
+static netdev_features_t mlx5e_vxlan_features_check(struct mlx5e_priv *priv,
+                                                   struct sk_buff *skb,
+                                                   netdev_features_t features)
+{
+       struct udphdr *udph;
+       u16 proto;
+       u16 port = 0;
+
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IP):
+               proto = ip_hdr(skb)->protocol;
+               break;
+       case htons(ETH_P_IPV6):
+               proto = ipv6_hdr(skb)->nexthdr;
+               break;
+       default:
+               goto out;
+       }
+
+       if (proto == IPPROTO_UDP) {
+               udph = udp_hdr(skb);
+               port = be16_to_cpu(udph->dest);
+       }
+
+       /* Verify if UDP port is being offloaded by HW */
+       if (port && mlx5e_vxlan_lookup_port(priv, port))
+               return features;
+
+out:
+       /* Disable CSUM and GSO if the udp dport is not offloaded by HW */
+       return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+}
+
+static netdev_features_t mlx5e_features_check(struct sk_buff *skb,
+                                             struct net_device *netdev,
+                                             netdev_features_t features)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       features = vlan_features_check(skb, features);
+       features = vxlan_features_check(skb, features);
+
+       /* Validate if the tunneled packet is being offloaded by HW */
+       if (skb->encapsulation &&
+           (features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK))
+               return mlx5e_vxlan_features_check(priv, skb, features);
+
+       return features;
+}
+
+static const struct net_device_ops mlx5e_netdev_ops_basic = {
        .ndo_open                = mlx5e_open,
        .ndo_stop                = mlx5e_close,
        .ndo_start_xmit          = mlx5e_xmit,
+       .ndo_setup_tc            = mlx5e_ndo_setup_tc,
+       .ndo_select_queue        = mlx5e_select_queue,
        .ndo_get_stats64         = mlx5e_get_stats,
        .ndo_set_rx_mode         = mlx5e_set_rx_mode,
        .ndo_set_mac_address     = mlx5e_set_mac,
-       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
-       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
+       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
        .ndo_set_features        = mlx5e_set_features,
-       .ndo_change_mtu          = mlx5e_change_mtu,
-       .ndo_do_ioctl            = mlx5e_ioctl,
+       .ndo_change_mtu          = mlx5e_change_mtu,
+       .ndo_do_ioctl            = mlx5e_ioctl,
+};
+
+static const struct net_device_ops mlx5e_netdev_ops_sriov = {
+       .ndo_open                = mlx5e_open,
+       .ndo_stop                = mlx5e_close,
+       .ndo_start_xmit          = mlx5e_xmit,
+       .ndo_setup_tc            = mlx5e_ndo_setup_tc,
+       .ndo_select_queue        = mlx5e_select_queue,
+       .ndo_get_stats64         = mlx5e_get_stats,
+       .ndo_set_rx_mode         = mlx5e_set_rx_mode,
+       .ndo_set_mac_address     = mlx5e_set_mac,
+       .ndo_vlan_rx_add_vid     = mlx5e_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid    = mlx5e_vlan_rx_kill_vid,
+       .ndo_set_features        = mlx5e_set_features,
+       .ndo_change_mtu          = mlx5e_change_mtu,
+       .ndo_do_ioctl            = mlx5e_ioctl,
+       .ndo_add_vxlan_port      = mlx5e_add_vxlan_port,
+       .ndo_del_vxlan_port      = mlx5e_del_vxlan_port,
+       .ndo_features_check      = mlx5e_features_check,
+       .ndo_set_vf_mac          = mlx5e_set_vf_mac,
+       .ndo_set_vf_vlan         = mlx5e_set_vf_vlan,
+       .ndo_get_vf_config       = mlx5e_get_vf_config,
+       .ndo_set_vf_link_state   = mlx5e_set_vf_link_state,
+       .ndo_get_vf_stats        = mlx5e_get_vf_stats,
 };
 
 static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
@@ -2057,6 +2250,8 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
        }
        if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
                mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+       if (!MLX5_CAP_GEN(mdev, cq_moderation))
+               mlx5_core_warn(mdev, "CQ modiration is not supported\n");
 
        return 0;
 }
@@ -2070,12 +2265,38 @@ u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev)
               2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/;
 }
 
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+static void mlx5e_ets_init(struct mlx5e_priv *priv)
+{
+       int i;
+
+       priv->params.ets.ets_cap = mlx5_max_tc(priv->mdev) + 1;
+       for (i = 0; i < priv->params.ets.ets_cap; i++) {
+               priv->params.ets.tc_tx_bw[i] = MLX5E_MAX_BW_ALLOC;
+               priv->params.ets.tc_tsa[i] = IEEE_8021QAZ_TSA_VENDOR;
+               priv->params.ets.prio_tc[i] = i;
+       }
+
+       /* tclass[prio=0]=1, tclass[prio=1]=0, tclass[prio=i]=i (for i>1) */
+       priv->params.ets.prio_tc[0] = 1;
+       priv->params.ets.prio_tc[1] = 0;
+}
+#endif
+
+void mlx5e_build_default_indir_rqt(u32 *indirection_rqt, int len,
+                                  int num_channels)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               indirection_rqt[i] = i % num_channels;
+}
+
 static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
                                    struct net_device *netdev,
                                    int num_channels)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
-       int i;
 
        priv->params.log_sq_size           =
                MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
@@ -2093,14 +2314,13 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
        priv->params.min_rx_wqes           =
                MLX5E_PARAMS_DEFAULT_MIN_RX_WQES;
        priv->params.num_tc                = 1;
-       priv->params.default_vlan_prio     = 0;
        priv->params.rss_hfunc             = ETH_RSS_HASH_XOR;
 
        netdev_rss_key_fill(priv->params.toeplitz_hash_key,
                            sizeof(priv->params.toeplitz_hash_key));
 
-       for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
-               priv->params.indirection_rqt[i] = i % num_channels;
+       mlx5e_build_default_indir_rqt(priv->params.indirection_rqt,
+                                     MLX5E_INDIR_RQT_SIZE, num_channels);
 
        priv->params.lro_wqe_sz            =
                MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
@@ -2108,9 +2328,11 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
        priv->mdev                         = mdev;
        priv->netdev                       = netdev;
        priv->params.num_channels          = num_channels;
-       priv->default_vlan_prio            = priv->params.default_vlan_prio;
 
-       spin_lock_init(&priv->async_events_spinlock);
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       mlx5e_ets_init(priv);
+#endif
+
        mutex_init(&priv->state_lock);
 
        INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
@@ -2137,18 +2359,15 @@ static void mlx5e_build_netdev(struct net_device *netdev)
 
        SET_NETDEV_DEV(netdev, &mdev->pdev->dev);
 
-       if (priv->params.num_tc > 1)
-               mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue;
-
        if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
-               mlx5e_netdev_ops.ndo_set_vf_mac = mlx5e_set_vf_mac;
-               mlx5e_netdev_ops.ndo_set_vf_vlan = mlx5e_set_vf_vlan;
-               mlx5e_netdev_ops.ndo_get_vf_config = mlx5e_get_vf_config;
-               mlx5e_netdev_ops.ndo_set_vf_link_state = mlx5e_set_vf_link_state;
-               mlx5e_netdev_ops.ndo_get_vf_stats = mlx5e_get_vf_stats;
+               netdev->netdev_ops = &mlx5e_netdev_ops_sriov;
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+               netdev->dcbnl_ops = &mlx5e_dcbnl_ops;
+#endif
+       } else {
+               netdev->netdev_ops = &mlx5e_netdev_ops_basic;
        }
 
-       netdev->netdev_ops        = &mlx5e_netdev_ops;
        netdev->watchdog_timeo    = 15 * HZ;
 
        netdev->ethtool_ops       = &mlx5e_ethtool_ops;
@@ -2170,10 +2389,27 @@ static void mlx5e_build_netdev(struct net_device *netdev)
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_RX;
        netdev->hw_features      |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
+       if (mlx5e_vxlan_allowed(mdev)) {
+               netdev->hw_features     |= NETIF_F_GSO_UDP_TUNNEL;
+               netdev->hw_enc_features |= NETIF_F_IP_CSUM;
+               netdev->hw_enc_features |= NETIF_F_RXCSUM;
+               netdev->hw_enc_features |= NETIF_F_TSO;
+               netdev->hw_enc_features |= NETIF_F_TSO6;
+               netdev->hw_enc_features |= NETIF_F_RXHASH;
+               netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
+       }
+
        netdev->features          = netdev->hw_features;
        if (!priv->params.lro_en)
                netdev->features  &= ~NETIF_F_LRO;
 
+#define FT_CAP(f) MLX5_CAP_FLOWTABLE(mdev, flow_table_properties_nic_receive.f)
+       if (FT_CAP(flow_modify_en) &&
+           FT_CAP(modify_root) &&
+           FT_CAP(identified_miss_table_mode) &&
+           FT_CAP(flow_table_modify))
+               priv->netdev->hw_features      |= NETIF_F_HW_TC;
+
        netdev->features         |= NETIF_F_HIGHDMA;
 
        netdev->priv_flags       |= IFF_UNICAST_FLT;
@@ -2216,7 +2452,9 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
        if (mlx5e_check_required_hca_cap(mdev))
                return NULL;
 
-       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv), nch, nch);
+       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
+                                   nch * MLX5E_MAX_NUM_TC,
+                                   nch);
        if (!netdev) {
                mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
                return NULL;
@@ -2229,7 +2467,7 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
 
        priv = netdev_priv(netdev);
 
-       err = mlx5_alloc_map_uar(mdev, &priv->cq_uar);
+       err = mlx5_alloc_map_uar(mdev, &priv->cq_uar, false);
        if (err) {
                mlx5_core_err(mdev, "alloc_map uar failed, %d\n", err);
                goto err_free_netdev;
@@ -2291,17 +2529,33 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
 
        mlx5e_init_eth_addr(priv);
 
+       mlx5e_vxlan_init(priv);
+
+       err = mlx5e_tc_init(priv);
+       if (err)
+               goto err_destroy_flow_tables;
+
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
+#endif
+
        err = register_netdev(netdev);
        if (err) {
                mlx5_core_err(mdev, "register_netdev failed, %d\n", err);
-               goto err_destroy_flow_tables;
+               goto err_tc_cleanup;
        }
 
+       if (mlx5e_vxlan_allowed(mdev))
+               vxlan_get_rx_port(netdev);
+
        mlx5e_enable_async_events(priv);
        schedule_work(&priv->set_rx_mode_work);
 
        return priv;
 
+err_tc_cleanup:
+       mlx5e_tc_cleanup(priv);
+
 err_destroy_flow_tables:
        mlx5e_destroy_flow_tables(priv);
 
@@ -2349,6 +2603,8 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
        mlx5e_disable_async_events(priv);
        flush_scheduled_work();
        unregister_netdev(netdev);
+       mlx5e_tc_cleanup(priv);
+       mlx5e_vxlan_cleanup(priv);
        mlx5e_destroy_flow_tables(priv);
        mlx5e_destroy_tirs(priv);
        mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT);
index dd959d929aadd561ab78c252fe2127e1beb24fad..58d4e2f962c3591f3dea1bbf0fccf4c5a62d0810 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/tcp.h>
 #include <net/busy_poll.h>
 #include "en.h"
+#include "en_tc.h"
 
 static inline bool mlx5e_rx_hw_stamp(struct mlx5e_tstamp *tstamp)
 {
@@ -167,14 +168,15 @@ static inline bool is_first_ethertype_ip(struct sk_buff *skb)
 static inline void mlx5e_handle_csum(struct net_device *netdev,
                                     struct mlx5_cqe64 *cqe,
                                     struct mlx5e_rq *rq,
-                                    struct sk_buff *skb)
+                                    struct sk_buff *skb,
+                                    bool   lro)
 {
        if (unlikely(!(netdev->features & NETIF_F_RXCSUM)))
                goto csum_none;
 
-       if (likely(cqe->hds_ip_ext & CQE_L4_OK)) {
+       if (lro) {
                skb->ip_summed = CHECKSUM_UNNECESSARY;
-       } else if (is_first_ethertype_ip(skb)) {
+       } else if (likely(is_first_ethertype_ip(skb))) {
                skb->ip_summed = CHECKSUM_COMPLETE;
                skb->csum = csum_unfold((__force __sum16)cqe->check_sum);
                rq->stats.csum_sw++;
@@ -211,7 +213,7 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
        if (unlikely(mlx5e_rx_hw_stamp(tstamp)))
                mlx5e_fill_hwstamp(tstamp, get_cqe_ts(cqe), skb_hwtstamps(skb));
 
-       mlx5e_handle_csum(netdev, cqe, rq, skb);
+       mlx5e_handle_csum(netdev, cqe, rq, skb, !!lro_num_seg);
 
        skb->protocol = eth_type_trans(skb, netdev);
 
@@ -223,6 +225,8 @@ static inline void mlx5e_build_rx_skb(struct mlx5_cqe64 *cqe,
        if (cqe_has_vlan(cqe))
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                       be16_to_cpu(cqe->vlan_info));
+
+       skb->mark = be32_to_cpu(cqe->sop_drop_qpn) & MLX5E_TC_FLOW_ID_MASK;
 }
 
 int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
@@ -230,10 +234,6 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
        struct mlx5e_rq *rq = container_of(cq, struct mlx5e_rq, cq);
        int work_done;
 
-       /* avoid accessing cq (dma coherent memory) if not needed */
-       if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
-               return 0;
-
        for (work_done = 0; work_done < budget; work_done++) {
                struct mlx5e_rx_wqe *wqe;
                struct mlx5_cqe64 *cqe;
@@ -267,6 +267,7 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
 
                mlx5e_build_rx_skb(cqe, rq, skb);
                rq->stats.packets++;
+               rq->stats.bytes += be32_to_cpu(cqe->byte_cnt);
                napi_gro_receive(cq->napi, skb);
 
 wq_ll_pop:
@@ -279,8 +280,5 @@ wq_ll_pop:
        /* ensure cq space is freed before enabling more cqes */
        wmb();
 
-       if (work_done == budget)
-               set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
-
        return work_done;
 }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
new file mode 100644 (file)
index 0000000..b3de09f
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <net/flow_dissector.h>
+#include <net/pkt_cls.h>
+#include <net/tc_act/tc_gact.h>
+#include <net/tc_act/tc_skbedit.h>
+#include <linux/mlx5/fs.h>
+#include <linux/mlx5/device.h>
+#include <linux/rhashtable.h>
+#include "en.h"
+#include "en_tc.h"
+
+struct mlx5e_tc_flow {
+       struct rhash_head       node;
+       u64                     cookie;
+       struct mlx5_flow_rule   *rule;
+};
+
+#define MLX5E_TC_FLOW_TABLE_NUM_ENTRIES 1024
+#define MLX5E_TC_FLOW_TABLE_NUM_GROUPS 4
+
+static struct mlx5_flow_rule *mlx5e_tc_add_flow(struct mlx5e_priv *priv,
+                                               u32 *match_c, u32 *match_v,
+                                               u32 action, u32 flow_tag)
+{
+       struct mlx5_flow_destination dest = {
+               .type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE,
+               {.ft = priv->fts.vlan.t},
+       };
+       struct mlx5_flow_rule *rule;
+       bool table_created = false;
+
+       if (IS_ERR_OR_NULL(priv->fts.tc.t)) {
+               priv->fts.tc.t =
+                       mlx5_create_auto_grouped_flow_table(priv->fts.ns, 0,
+                                                           MLX5E_TC_FLOW_TABLE_NUM_ENTRIES,
+                                                           MLX5E_TC_FLOW_TABLE_NUM_GROUPS);
+               if (IS_ERR(priv->fts.tc.t)) {
+                       netdev_err(priv->netdev,
+                                  "Failed to create tc offload table\n");
+                       return ERR_CAST(priv->fts.tc.t);
+               }
+
+               table_created = true;
+       }
+
+       rule = mlx5_add_flow_rule(priv->fts.tc.t, MLX5_MATCH_OUTER_HEADERS,
+                                 match_c, match_v,
+                                 action, flow_tag,
+                                 action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST ? &dest : NULL);
+
+       if (IS_ERR(rule) && table_created) {
+               mlx5_destroy_flow_table(priv->fts.tc.t);
+               priv->fts.tc.t = NULL;
+       }
+
+       return rule;
+}
+
+static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
+                             struct mlx5_flow_rule *rule)
+{
+       mlx5_del_flow_rule(rule);
+
+       if (!mlx5e_tc_num_filters(priv)) {
+               mlx5_destroy_flow_table(priv->fts.tc.t);
+               priv->fts.tc.t = NULL;
+       }
+}
+
+static int parse_cls_flower(struct mlx5e_priv *priv,
+                           u32 *match_c, u32 *match_v,
+                           struct tc_cls_flower_offload *f)
+{
+       void *headers_c = MLX5_ADDR_OF(fte_match_param, match_c, outer_headers);
+       void *headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers);
+       u16 addr_type = 0;
+       u8 ip_proto = 0;
+
+       if (f->dissector->used_keys &
+           ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+             BIT(FLOW_DISSECTOR_KEY_BASIC) |
+             BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_PORTS))) {
+               netdev_warn(priv->netdev, "Unsupported key used: 0x%x\n",
+                           f->dissector->used_keys);
+               return -EOPNOTSUPP;
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
+               struct flow_dissector_key_control *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_BASIC,
+                                                 f->key);
+               addr_type = key->addr_type;
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
+               struct flow_dissector_key_basic *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_BASIC,
+                                                 f->key);
+               struct flow_dissector_key_basic *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_BASIC,
+                                                 f->mask);
+               ip_proto = key->ip_proto;
+
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype,
+                        ntohs(mask->n_proto));
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
+                        ntohs(key->n_proto));
+
+               MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol,
+                        mask->ip_proto);
+               MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
+                        key->ip_proto);
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+               struct flow_dissector_key_eth_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ETH_ADDRS,
+                                                 f->key);
+               struct flow_dissector_key_eth_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ETH_ADDRS,
+                                                 f->mask);
+
+               ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                            dmac_47_16),
+                               mask->dst);
+               ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                            dmac_47_16),
+                               key->dst);
+
+               ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                            smac_47_16),
+                               mask->src);
+               ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                            smac_47_16),
+                               key->src);
+       }
+
+       if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+               struct flow_dissector_key_ipv4_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                 f->key);
+               struct flow_dissector_key_ipv4_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                 f->mask);
+
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                   src_ipv4_src_ipv6.ipv4_layout.ipv4),
+                      &mask->src, sizeof(mask->src));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                   src_ipv4_src_ipv6.ipv4_layout.ipv4),
+                      &key->src, sizeof(key->src));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                   dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
+                      &mask->dst, sizeof(mask->dst));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                   dst_ipv4_dst_ipv6.ipv4_layout.ipv4),
+                      &key->dst, sizeof(key->dst));
+       }
+
+       if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+               struct flow_dissector_key_ipv6_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                 f->key);
+               struct flow_dissector_key_ipv6_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                 f->mask);
+
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                      &mask->src, sizeof(mask->src));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                   src_ipv4_src_ipv6.ipv6_layout.ipv6),
+                      &key->src, sizeof(key->src));
+
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c,
+                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                      &mask->dst, sizeof(mask->dst));
+               memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
+                                   dst_ipv4_dst_ipv6.ipv6_layout.ipv6),
+                      &key->dst, sizeof(key->dst));
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
+               struct flow_dissector_key_ports *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_PORTS,
+                                                 f->key);
+               struct flow_dissector_key_ports *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_PORTS,
+                                                 f->mask);
+               switch (ip_proto) {
+               case IPPROTO_TCP:
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                tcp_sport, ntohs(mask->src));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                tcp_sport, ntohs(key->src));
+
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                tcp_dport, ntohs(mask->dst));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                tcp_dport, ntohs(key->dst));
+                       break;
+
+               case IPPROTO_UDP:
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                udp_sport, ntohs(mask->src));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                udp_sport, ntohs(key->src));
+
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+                                udp_dport, ntohs(mask->dst));
+                       MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+                                udp_dport, ntohs(key->dst));
+                       break;
+               default:
+                       netdev_err(priv->netdev,
+                                  "Only UDP and TCP transport are supported\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int parse_tc_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
+                           u32 *action, u32 *flow_tag)
+{
+       const struct tc_action *a;
+
+       if (tc_no_actions(exts))
+               return -EINVAL;
+
+       *flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
+       *action = 0;
+
+       tc_for_each_action(a, exts) {
+               /* Only support a single action per rule */
+               if (*action)
+                       return -EINVAL;
+
+               if (is_tcf_gact_shot(a)) {
+                       *action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
+                       continue;
+               }
+
+               if (is_tcf_skbedit_mark(a)) {
+                       u32 mark = tcf_skbedit_mark(a);
+
+                       if (mark & ~MLX5E_TC_FLOW_ID_MASK) {
+                               netdev_warn(priv->netdev, "Bad flow mark - only 16 bit is supported: 0x%x\n",
+                                           mark);
+                               return -EINVAL;
+                       }
+
+                       *flow_tag = mark;
+                       *action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+                       continue;
+               }
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
+                          struct tc_cls_flower_offload *f)
+{
+       struct mlx5e_tc_flow_table *tc = &priv->fts.tc;
+       u32 *match_c;
+       u32 *match_v;
+       int err = 0;
+       u32 flow_tag;
+       u32 action;
+       struct mlx5e_tc_flow *flow;
+       struct mlx5_flow_rule *old = NULL;
+
+       flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
+                                     tc->ht_params);
+       if (flow)
+               old = flow->rule;
+       else
+               flow = kzalloc(sizeof(*flow), GFP_KERNEL);
+
+       match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+       match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
+       if (!match_c || !match_v || !flow) {
+               err = -ENOMEM;
+               goto err_free;
+       }
+
+       flow->cookie = f->cookie;
+
+       err = parse_cls_flower(priv, match_c, match_v, f);
+       if (err < 0)
+               goto err_free;
+
+       err = parse_tc_actions(priv, f->exts, &action, &flow_tag);
+       if (err < 0)
+               goto err_free;
+
+       err = rhashtable_insert_fast(&tc->ht, &flow->node,
+                                    tc->ht_params);
+       if (err)
+               goto err_free;
+
+       flow->rule = mlx5e_tc_add_flow(priv, match_c, match_v, action,
+                                      flow_tag);
+       if (IS_ERR(flow->rule)) {
+               err = PTR_ERR(flow->rule);
+               goto err_hash_del;
+       }
+
+       if (old)
+               mlx5e_tc_del_flow(priv, old);
+
+       goto out;
+
+err_hash_del:
+       rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
+
+err_free:
+       if (!old)
+               kfree(flow);
+out:
+       kfree(match_c);
+       kfree(match_v);
+       return err;
+}
+
+int mlx5e_delete_flower(struct mlx5e_priv *priv,
+                       struct tc_cls_flower_offload *f)
+{
+       struct mlx5e_tc_flow *flow;
+       struct mlx5e_tc_flow_table *tc = &priv->fts.tc;
+
+       flow = rhashtable_lookup_fast(&tc->ht, &f->cookie,
+                                     tc->ht_params);
+       if (!flow)
+               return -EINVAL;
+
+       rhashtable_remove_fast(&tc->ht, &flow->node, tc->ht_params);
+
+       mlx5e_tc_del_flow(priv, flow->rule);
+
+       kfree(flow);
+
+       return 0;
+}
+
+static const struct rhashtable_params mlx5e_tc_flow_ht_params = {
+       .head_offset = offsetof(struct mlx5e_tc_flow, node),
+       .key_offset = offsetof(struct mlx5e_tc_flow, cookie),
+       .key_len = sizeof(((struct mlx5e_tc_flow *)0)->cookie),
+       .automatic_shrinking = true,
+};
+
+int mlx5e_tc_init(struct mlx5e_priv *priv)
+{
+       struct mlx5e_tc_flow_table *tc = &priv->fts.tc;
+
+       tc->ht_params = mlx5e_tc_flow_ht_params;
+       return rhashtable_init(&tc->ht, &tc->ht_params);
+}
+
+static void _mlx5e_tc_del_flow(void *ptr, void *arg)
+{
+       struct mlx5e_tc_flow *flow = ptr;
+       struct mlx5e_priv *priv = arg;
+
+       mlx5e_tc_del_flow(priv, flow->rule);
+       kfree(flow);
+}
+
+void mlx5e_tc_cleanup(struct mlx5e_priv *priv)
+{
+       struct mlx5e_tc_flow_table *tc = &priv->fts.tc;
+
+       rhashtable_free_and_destroy(&tc->ht, _mlx5e_tc_del_flow, priv);
+
+       if (!IS_ERR_OR_NULL(priv->fts.tc.t)) {
+               mlx5_destroy_flow_table(priv->fts.tc.t);
+               priv->fts.tc.t = NULL;
+       }
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
new file mode 100644 (file)
index 0000000..d677428
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_EN_TC_H__
+#define __MLX5_EN_TC_H__
+
+#define MLX5E_TC_FLOW_ID_MASK 0x0000ffff
+
+int mlx5e_tc_init(struct mlx5e_priv *priv);
+void mlx5e_tc_cleanup(struct mlx5e_priv *priv);
+
+int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol,
+                          struct tc_cls_flower_offload *f);
+int mlx5e_delete_flower(struct mlx5e_priv *priv,
+                       struct tc_cls_flower_offload *f);
+
+static inline int mlx5e_tc_num_filters(struct mlx5e_priv *priv)
+{
+       return atomic_read(&priv->fts.tc.ht.nelems);
+}
+
+#endif /* __MLX5_EN_TC_H__ */
index 2c3fba0fff546179f68a53ab23fcdf7620ba188e..1ffc7cb6f78c4ab7de755ac751e5cf24f0b8a426 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -109,12 +109,10 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
        int channel_ix = fallback(dev, skb);
-       int up = skb_vlan_tag_present(skb)        ?
-                skb->vlan_tci >> VLAN_PRIO_SHIFT :
-                priv->default_vlan_prio;
-       int tc = netdev_get_prio_tc_map(dev, up);
+       int up = (netdev_get_num_tc(dev) && skb_vlan_tag_present(skb)) ?
+                skb->vlan_tci >> VLAN_PRIO_SHIFT : 0;
 
-       return priv->channeltc_to_txq_map[channel_ix][tc];
+       return priv->channeltc_to_txq_map[channel_ix][up];
 }
 
 static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq,
@@ -179,6 +177,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
        unsigned int skb_len = skb->len;
        u8  opcode = MLX5_OPCODE_SEND;
        dma_addr_t dma_addr = 0;
+       unsigned int num_bytes;
        bool bf = false;
        u16 headlen;
        u16 ds_cnt;
@@ -187,9 +186,16 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
 
        memset(wqe, 0, sizeof(*wqe));
 
-       if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
-               eseg->cs_flags  = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
-       else
+       if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+               eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM;
+               if (skb->encapsulation) {
+                       eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM |
+                                         MLX5_ETH_WQE_L4_INNER_CSUM;
+                       sq->stats.csum_offload_inner++;
+               } else {
+                       eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM;
+               }
+       } else
                sq->stats.csum_offload_none++;
 
        if (sq->cc != sq->prev_cc) {
@@ -198,24 +204,30 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
        }
 
        if (skb_is_gso(skb)) {
-               u32 payload_len;
-
                eseg->mss    = cpu_to_be16(skb_shinfo(skb)->gso_size);
                opcode       = MLX5_OPCODE_LSO;
-               ihs          = skb_transport_offset(skb) + tcp_hdrlen(skb);
-               payload_len  = skb->len - ihs;
-               wi->num_bytes = skb->len +
-                               (skb_shinfo(skb)->gso_segs - 1) * ihs;
-               sq->stats.tso_packets++;
-               sq->stats.tso_bytes += payload_len;
+
+               if (skb->encapsulation) {
+                       ihs = skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
+                       sq->stats.tso_inner_packets++;
+                       sq->stats.tso_inner_bytes += skb->len - ihs;
+               } else {
+                       ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
+                       sq->stats.tso_packets++;
+                       sq->stats.tso_bytes += skb->len - ihs;
+               }
+
+               num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs;
        } else {
                bf = sq->bf_budget &&
                     !skb->xmit_more &&
                     !skb_shinfo(skb)->nr_frags;
                ihs = mlx5e_get_inline_hdr_size(sq, skb, bf);
-               wi->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
+               num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN);
        }
 
+       wi->num_bytes = num_bytes;
+
        if (skb_vlan_tag_present(skb)) {
                mlx5e_insert_vlan(eseg->inline_hdr_start, skb, ihs, &skb_data,
                                  &skb_len);
@@ -293,7 +305,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
        if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) {
                int bf_sz = 0;
 
-               if (bf && sq->uar_bf_map)
+               if (bf && test_bit(MLX5E_SQ_STATE_BF_ENABLE, &sq->state))
                        bf_sz = wi->num_wqebbs << 3;
 
                cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
@@ -307,6 +319,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
        sq->bf_budget = bf ? sq->bf_budget - 1 : 0;
 
        sq->stats.packets++;
+       sq->stats.bytes += num_bytes;
        return NETDEV_TX_OK;
 
 dma_unmap_wqe_err:
@@ -326,7 +339,7 @@ netdev_tx_t mlx5e_xmit(struct sk_buff *skb, struct net_device *dev)
        return mlx5e_sq_xmit(sq, skb);
 }
 
-bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
+bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
 {
        struct mlx5e_sq *sq;
        u32 dma_fifo_cc;
@@ -335,10 +348,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
        u16 sqcc;
        int i;
 
-       /* avoid accessing cq (dma coherent memory) if not needed */
-       if (!test_and_clear_bit(MLX5E_CQ_HAS_CQES, &cq->flags))
-               return false;
-
        sq = container_of(cq, struct mlx5e_sq, cq);
 
        npkts = 0;
@@ -402,7 +411,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
                        npkts++;
                        nbytes += wi->num_bytes;
                        sqcc += wi->num_wqebbs;
-                       dev_kfree_skb(skb);
+                       napi_consume_skb(skb, napi_budget);
                } while (!last_wqe);
        }
 
@@ -422,10 +431,6 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
                                netif_tx_wake_queue(sq->txq);
                                sq->stats.wake++;
        }
-       if (i == MLX5E_TX_CQ_POLL_BUDGET) {
-               set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
-               return true;
-       }
 
-       return false;
+       return (i == MLX5E_TX_CQ_POLL_BUDGET);
 }
index 4ac8d716dbddfd9650d50c9c2af15efe7089a7d6..9bb4395aceeb495156550821d34d6ea976a812d2 100644 (file)
@@ -60,7 +60,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget)
        clear_bit(MLX5E_CHANNEL_NAPI_SCHED, &c->flags);
 
        for (i = 0; i < c->num_tc; i++)
-               busy |= mlx5e_poll_tx_cq(&c->sq[i].cq);
+               busy |= mlx5e_poll_tx_cq(&c->sq[i].cq, budget);
 
        work_done = mlx5e_poll_rx_cq(&c->rq.cq, budget);
        busy |= work_done == budget;
@@ -88,7 +88,6 @@ void mlx5e_completion_event(struct mlx5_core_cq *mcq)
 {
        struct mlx5e_cq *cq = container_of(mcq, struct mlx5e_cq, mcq);
 
-       set_bit(MLX5E_CQ_HAS_CQES, &cq->flags);
        set_bit(MLX5E_CHANNEL_NAPI_SCHED, &cq->channel->flags);
        barrier();
        napi_schedule(cq->napi);
index 647a3ca2c2a925c1d6157febb59fa51ea39872da..18fccec72c5da210ec04be452837c1a5fddf7762 100644 (file)
@@ -442,6 +442,11 @@ int mlx5_destroy_unmap_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
 }
 EXPORT_SYMBOL_GPL(mlx5_destroy_unmap_eq);
 
+u32 mlx5_get_msix_vec(struct mlx5_core_dev *dev, int vecidx)
+{
+       return dev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector;
+}
+
 int mlx5_eq_init(struct mlx5_core_dev *dev)
 {
        int err;
index a9894d2e8e26b01b6e77dc83c5b8df8d5ebd3a7c..f46f1db0fc00df8d6edbb4a8c1443950d3c91eb9 100644 (file)
@@ -218,19 +218,22 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
                                      match_value);
        memcpy(in_match_value, &fte->val, MLX5_ST_SZ_BYTES(fte_match_param));
 
-       in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
-       list_for_each_entry(dst, &fte->node.children, node.list) {
-               unsigned int id;
-
-               MLX5_SET(dest_format_struct, in_dests, destination_type,
-                        dst->dest_attr.type);
-               if (dst->dest_attr.type ==
-                   MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE)
-                       id = dst->dest_attr.ft->id;
-               else
-                       id = dst->dest_attr.tir_num;
-               MLX5_SET(dest_format_struct, in_dests, destination_id, id);
-               in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
+       if (fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
+               in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
+               list_for_each_entry(dst, &fte->node.children, node.list) {
+                       unsigned int id;
+
+                       MLX5_SET(dest_format_struct, in_dests, destination_type,
+                                dst->dest_attr.type);
+                       if (dst->dest_attr.type ==
+                           MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) {
+                               id = dst->dest_attr.ft->id;
+                       } else {
+                               id = dst->dest_attr.tir_num;
+                       }
+                       MLX5_SET(dest_format_struct, in_dests, destination_id, id);
+                       in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
+               }
        }
        memset(out, 0, sizeof(out));
        err = mlx5_cmd_exec_check_status(dev, in, inlen, out,
index 6f68dba8d7edcfb212e23461d20b8bd24a3d6723..e848d708d2b733caf9edc9a0f0f0f1cdd60ad688 100644 (file)
@@ -73,8 +73,8 @@
 #define BY_PASS_MIN_LEVEL (KENREL_MIN_LEVEL + MLX5_BY_PASS_NUM_PRIOS +\
                           LEFTOVERS_MAX_FT)
 
-#define KERNEL_MAX_FT 2
-#define KERNEL_NUM_PRIOS 1
+#define KERNEL_MAX_FT 3
+#define KERNEL_NUM_PRIOS 2
 #define KENREL_MIN_LEVEL 2
 
 struct node_caps {
@@ -360,8 +360,8 @@ static void del_rule(struct fs_node *node)
        memcpy(match_value, fte->val, sizeof(fte->val));
        fs_get_obj(ft, fg->node.parent);
        list_del(&rule->node.list);
-       fte->dests_size--;
-       if (fte->dests_size) {
+       if ((fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) &&
+           --fte->dests_size) {
                err = mlx5_cmd_update_fte(dev, ft,
                                          fg->id, fte);
                if (err)
@@ -763,7 +763,8 @@ static struct mlx5_flow_rule *alloc_rule(struct mlx5_flow_destination *dest)
                return NULL;
 
        rule->node.type = FS_TYPE_FLOW_DEST;
-       memcpy(&rule->dest_attr, dest, sizeof(*dest));
+       if (dest)
+               memcpy(&rule->dest_attr, dest, sizeof(*dest));
 
        return rule;
 }
@@ -785,8 +786,9 @@ static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,
        /* Add dest to dests list- added as first element after the head */
        tree_init_node(&rule->node, 1, del_rule);
        list_add_tail(&rule->node.list, &fte->node.children);
-       fte->dests_size++;
-       if (fte->dests_size == 1)
+       if (dest)
+               fte->dests_size++;
+       if (fte->dests_size == 1 || !dest)
                err = mlx5_cmd_create_fte(get_dev(&ft->node),
                                          ft, fg->id, fte);
        else
@@ -802,7 +804,8 @@ static struct mlx5_flow_rule *add_rule_fte(struct fs_fte *fte,
 free_rule:
        list_del(&rule->node.list);
        kfree(rule);
-       fte->dests_size--;
+       if (dest)
+               fte->dests_size--;
        return ERR_PTR(err);
 }
 
@@ -996,6 +999,9 @@ mlx5_add_flow_rule(struct mlx5_flow_table *ft,
        struct mlx5_flow_group *g;
        struct mlx5_flow_rule *rule;
 
+       if ((action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) && !dest)
+               return ERR_PTR(-EINVAL);
+
        nested_lock_ref_node(&ft->node, FS_MUTEX_GRANDPARENT);
        fs_for_each_fg(g, ft)
                if (compare_match_criteria(g->mask.match_criteria_enable,
index 1545a944c309bf3205ad49fc1de90bd21c3eaacd..8b7133de498eedfa7cf5c46638bfd6b02a980309 100644 (file)
@@ -767,22 +767,6 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev)
        return -ENOTSUPP;
 }
 
-static int map_bf_area(struct mlx5_core_dev *dev)
-{
-       resource_size_t bf_start = pci_resource_start(dev->pdev, 0);
-       resource_size_t bf_len = pci_resource_len(dev->pdev, 0);
-
-       dev->priv.bf_mapping = io_mapping_create_wc(bf_start, bf_len);
-
-       return dev->priv.bf_mapping ? 0 : -ENOMEM;
-}
-
-static void unmap_bf_area(struct mlx5_core_dev *dev)
-{
-       if (dev->priv.bf_mapping)
-               io_mapping_free(dev->priv.bf_mapping);
-}
-
 static void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv)
 {
        struct mlx5_device_context *dev_ctx;
@@ -1103,14 +1087,9 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
                goto err_stop_eqs;
        }
 
-       if (map_bf_area(dev))
-               dev_err(&pdev->dev, "Failed to map blue flame area\n");
-
        err = mlx5_irq_set_affinity_hints(dev);
-       if (err) {
+       if (err)
                dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n");
-               goto err_unmap_bf_area;
-       }
 
        MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock);
 
@@ -1169,10 +1148,6 @@ err_fs:
        mlx5_cleanup_qp_table(dev);
        mlx5_cleanup_cq_table(dev);
        mlx5_irq_clear_affinity_hints(dev);
-
-err_unmap_bf_area:
-       unmap_bf_area(dev);
-
        free_comp_eqs(dev);
 
 err_stop_eqs:
@@ -1242,7 +1217,6 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv)
        mlx5_cleanup_qp_table(dev);
        mlx5_cleanup_cq_table(dev);
        mlx5_irq_clear_affinity_hints(dev);
-       unmap_bf_area(dev);
        free_comp_eqs(dev);
        mlx5_stop_eqs(dev);
        mlx5_free_uuars(dev, &priv->uuari);
index 0336847ec9a163feb9f3da8d87d811b04671d404..0b0b226c789e1f6ef2a43881f2c9172997639661 100644 (file)
@@ -99,6 +99,7 @@ int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
 int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
 int mlx5_wait_for_vf_pages(struct mlx5_core_dev *dev);
 cycle_t mlx5_read_internal_timer(struct mlx5_core_dev *dev);
+u32 mlx5_get_msix_vec(struct mlx5_core_dev *dev, int vecidx);
 
 void mlx5e_init(void);
 void mlx5e_cleanup(void);
index a87e773e93f3439dbd4cf93bc08a9a7563f4977b..e1f2e1059cfd7948f83afdf6d9fa4d28e9d5c8c1 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/module.h>
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/port.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
 
@@ -363,3 +364,223 @@ int mlx5_query_port_pause(struct mlx5_core_dev *dev,
        return 0;
 }
 EXPORT_SYMBOL_GPL(mlx5_query_port_pause);
+
+int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx)
+{
+       u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
+       u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
+
+       memset(in, 0, sizeof(in));
+       MLX5_SET(pfcc_reg, in, local_port, 1);
+       MLX5_SET(pfcc_reg, in, pfctx, pfc_en_tx);
+       MLX5_SET(pfcc_reg, in, pfcrx, pfc_en_rx);
+       MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_tx);
+       MLX5_SET_TO_ONES(pfcc_reg, in, prio_mask_rx);
+
+       return mlx5_core_access_reg(dev, in, sizeof(in), out,
+                                   sizeof(out), MLX5_REG_PFCC, 0, 1);
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_pfc);
+
+int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx, u8 *pfc_en_rx)
+{
+       u32 in[MLX5_ST_SZ_DW(pfcc_reg)];
+       u32 out[MLX5_ST_SZ_DW(pfcc_reg)];
+       int err;
+
+       memset(in, 0, sizeof(in));
+       MLX5_SET(pfcc_reg, in, local_port, 1);
+
+       err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+                                  sizeof(out), MLX5_REG_PFCC, 0, 0);
+       if (err)
+               return err;
+
+       if (pfc_en_tx)
+               *pfc_en_tx = MLX5_GET(pfcc_reg, out, pfctx);
+
+       if (pfc_en_rx)
+               *pfc_en_rx = MLX5_GET(pfcc_reg, out, pfcrx);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_pfc);
+
+int mlx5_max_tc(struct mlx5_core_dev *mdev)
+{
+       u8 num_tc = MLX5_CAP_GEN(mdev, max_tc) ? : 8;
+
+       return num_tc - 1;
+}
+
+int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc)
+{
+       u32 in[MLX5_ST_SZ_DW(qtct_reg)];
+       u32 out[MLX5_ST_SZ_DW(qtct_reg)];
+       int err;
+       int i;
+
+       memset(in, 0, sizeof(in));
+       for (i = 0; i < 8; i++) {
+               if (prio_tc[i] > mlx5_max_tc(mdev))
+                       return -EINVAL;
+
+               MLX5_SET(qtct_reg, in, prio, i);
+               MLX5_SET(qtct_reg, in, tclass, prio_tc[i]);
+
+               err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
+                                          sizeof(out), MLX5_REG_QTCT, 0, 1);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_prio_tc);
+
+static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
+                                  int inlen)
+{
+       u32 out[MLX5_ST_SZ_DW(qtct_reg)];
+
+       if (!MLX5_CAP_GEN(mdev, ets))
+               return -ENOTSUPP;
+
+       return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
+                                   MLX5_REG_QETCR, 0, 1);
+}
+
+static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
+                                    int outlen)
+{
+       u32 in[MLX5_ST_SZ_DW(qtct_reg)];
+
+       if (!MLX5_CAP_GEN(mdev, ets))
+               return -ENOTSUPP;
+
+       memset(in, 0, sizeof(in));
+       return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
+                                   MLX5_REG_QETCR, 0, 0);
+}
+
+int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group)
+{
+       u32 in[MLX5_ST_SZ_DW(qetc_reg)];
+       int i;
+
+       memset(in, 0, sizeof(in));
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               MLX5_SET(qetc_reg, in, tc_configuration[i].g, 1);
+               MLX5_SET(qetc_reg, in, tc_configuration[i].group, tc_group[i]);
+       }
+
+       return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_tc_group);
+
+int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw)
+{
+       u32 in[MLX5_ST_SZ_DW(qetc_reg)];
+       int i;
+
+       memset(in, 0, sizeof(in));
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               MLX5_SET(qetc_reg, in, tc_configuration[i].b, 1);
+               MLX5_SET(qetc_reg, in, tc_configuration[i].bw_allocation, tc_bw[i]);
+       }
+
+       return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_tc_bw_alloc);
+
+int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
+                                   u8 *max_bw_value,
+                                   u8 *max_bw_units)
+{
+       u32 in[MLX5_ST_SZ_DW(qetc_reg)];
+       void *ets_tcn_conf;
+       int i;
+
+       memset(in, 0, sizeof(in));
+
+       MLX5_SET(qetc_reg, in, port_number, 1);
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, in, tc_configuration[i]);
+
+               MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, r, 1);
+               MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_units,
+                        max_bw_units[i]);
+               MLX5_SET(ets_tcn_config_reg, ets_tcn_conf, max_bw_value,
+                        max_bw_value[i]);
+       }
+
+       return mlx5_set_port_qetcr_reg(mdev, in, sizeof(in));
+}
+EXPORT_SYMBOL_GPL(mlx5_modify_port_ets_rate_limit);
+
+int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
+                                  u8 *max_bw_value,
+                                  u8 *max_bw_units)
+{
+       u32 out[MLX5_ST_SZ_DW(qetc_reg)];
+       void *ets_tcn_conf;
+       int err;
+       int i;
+
+       err = mlx5_query_port_qetcr_reg(mdev, out, sizeof(out));
+       if (err)
+               return err;
+
+       for (i = 0; i <= mlx5_max_tc(mdev); i++) {
+               ets_tcn_conf = MLX5_ADDR_OF(qetc_reg, out, tc_configuration[i]);
+
+               max_bw_value[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
+                                          max_bw_value);
+               max_bw_units[i] = MLX5_GET(ets_tcn_config_reg, ets_tcn_conf,
+                                          max_bw_units);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_ets_rate_limit);
+
+int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode)
+{
+       u32 in[MLX5_ST_SZ_DW(set_wol_rol_in)];
+       u32 out[MLX5_ST_SZ_DW(set_wol_rol_out)];
+
+       memset(in, 0, sizeof(in));
+       memset(out, 0, sizeof(out));
+
+       MLX5_SET(set_wol_rol_in, in, opcode, MLX5_CMD_OP_SET_WOL_ROL);
+       MLX5_SET(set_wol_rol_in, in, wol_mode_valid, 1);
+       MLX5_SET(set_wol_rol_in, in, wol_mode, wol_mode);
+
+       return mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
+                                         out, sizeof(out));
+}
+EXPORT_SYMBOL_GPL(mlx5_set_port_wol);
+
+int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode)
+{
+       u32 in[MLX5_ST_SZ_DW(query_wol_rol_in)];
+       u32 out[MLX5_ST_SZ_DW(query_wol_rol_out)];
+       int err;
+
+       memset(in, 0, sizeof(in));
+       memset(out, 0, sizeof(out));
+
+       MLX5_SET(query_wol_rol_in, in, opcode, MLX5_CMD_OP_QUERY_WOL_ROL);
+
+       err = mlx5_cmd_exec_check_status(mdev, in, sizeof(in),
+                                        out, sizeof(out));
+
+       if (!err)
+               *wol_mode = MLX5_GET(query_wol_rol_out, out, wol_mode);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(mlx5_query_port_wol);
index eb05c845ece9247e7e54fee5880ad27be7be7253..8ba080e441a1863e63d4188820afbd2f1c39bd6e 100644 (file)
@@ -226,7 +226,8 @@ int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
        return 0;
 }
 
-int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
+int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar,
+                      bool map_wc)
 {
        phys_addr_t pfn;
        phys_addr_t uar_bar_start;
@@ -240,20 +241,26 @@ int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
 
        uar_bar_start = pci_resource_start(mdev->pdev, 0);
        pfn           = (uar_bar_start >> PAGE_SHIFT) + uar->index;
-       uar->map      = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
-       if (!uar->map) {
-               mlx5_core_warn(mdev, "ioremap() failed, %d\n", err);
-               err = -ENOMEM;
-               goto err_free_uar;
-       }
 
-       if (mdev->priv.bf_mapping)
-               uar->bf_map = io_mapping_map_wc(mdev->priv.bf_mapping,
-                                               uar->index << PAGE_SHIFT);
+       if (map_wc) {
+               uar->bf_map = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE);
+               if (!uar->bf_map) {
+                       mlx5_core_warn(mdev, "ioremap_wc() failed\n");
+                       uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+                       if (!uar->map)
+                               goto err_free_uar;
+               }
+       } else {
+               uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+               if (!uar->map)
+                       goto err_free_uar;
+       }
 
        return 0;
 
 err_free_uar:
+       mlx5_core_warn(mdev, "ioremap() failed\n");
+       err = -ENOMEM;
        mlx5_cmd_free_uar(mdev, uar->index);
 
        return err;
@@ -262,8 +269,8 @@ EXPORT_SYMBOL(mlx5_alloc_map_uar);
 
 void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
 {
-       io_mapping_unmap(uar->bf_map);
        iounmap(uar->map);
+       iounmap(uar->bf_map);
        mlx5_cmd_free_uar(mdev, uar->index);
 }
 EXPORT_SYMBOL(mlx5_unmap_free_uar);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.c
new file mode 100644 (file)
index 0000000..9f10df2
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mlx5/driver.h>
+#include "mlx5_core.h"
+#include "vxlan.h"
+
+void mlx5e_vxlan_init(struct mlx5e_priv *priv)
+{
+       struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
+
+       spin_lock_init(&vxlan_db->lock);
+       INIT_RADIX_TREE(&vxlan_db->tree, GFP_ATOMIC);
+}
+
+static int mlx5e_vxlan_core_add_port_cmd(struct mlx5_core_dev *mdev, u16 port)
+{
+       struct mlx5_outbox_hdr *hdr;
+       int err;
+
+       u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)];
+       u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)];
+
+       memset(in, 0, sizeof(in));
+       memset(out, 0, sizeof(out));
+
+       MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
+                MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
+       MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
+
+       err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+       if (err)
+               return err;
+
+       hdr = (struct mlx5_outbox_hdr *)out;
+       return hdr->status ? -ENOMEM : 0;
+}
+
+static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port)
+{
+       u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)];
+       u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)];
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+
+       MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
+                MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
+       MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
+
+       return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
+                                         sizeof(out));
+}
+
+struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port)
+{
+       struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
+       struct mlx5e_vxlan *vxlan;
+
+       spin_lock(&vxlan_db->lock);
+       vxlan = radix_tree_lookup(&vxlan_db->tree, port);
+       spin_unlock(&vxlan_db->lock);
+
+       return vxlan;
+}
+
+int mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port)
+{
+       struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
+       struct mlx5e_vxlan *vxlan;
+       int err;
+
+       err = mlx5e_vxlan_core_add_port_cmd(priv->mdev, port);
+       if (err)
+               return err;
+
+       vxlan = kzalloc(sizeof(*vxlan), GFP_KERNEL);
+       if (!vxlan) {
+               err = -ENOMEM;
+               goto err_delete_port;
+       }
+
+       vxlan->udp_port = port;
+
+       spin_lock_irq(&vxlan_db->lock);
+       err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan);
+       spin_unlock_irq(&vxlan_db->lock);
+       if (err)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       kfree(vxlan);
+err_delete_port:
+       mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
+       return err;
+}
+
+static void __mlx5e_vxlan_core_del_port(struct mlx5e_priv *priv, u16 port)
+{
+       struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
+       struct mlx5e_vxlan *vxlan;
+
+       spin_lock_irq(&vxlan_db->lock);
+       vxlan = radix_tree_delete(&vxlan_db->tree, port);
+       spin_unlock_irq(&vxlan_db->lock);
+
+       if (!vxlan)
+               return;
+
+       mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port);
+
+       kfree(vxlan);
+}
+
+void mlx5e_vxlan_del_port(struct mlx5e_priv *priv, u16 port)
+{
+       if (!mlx5e_vxlan_lookup_port(priv, port))
+               return;
+
+       __mlx5e_vxlan_core_del_port(priv, port);
+}
+
+void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv)
+{
+       struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
+       struct mlx5e_vxlan *vxlan;
+       unsigned int port = 0;
+
+       spin_lock_irq(&vxlan_db->lock);
+       while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) {
+               port = vxlan->udp_port;
+               spin_unlock_irq(&vxlan_db->lock);
+               __mlx5e_vxlan_core_del_port(priv, (u16)port);
+               spin_lock_irq(&vxlan_db->lock);
+       }
+       spin_unlock_irq(&vxlan_db->lock);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h b/drivers/net/ethernet/mellanox/mlx5/core/vxlan.h
new file mode 100644 (file)
index 0000000..a016850
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __MLX5_VXLAN_H__
+#define __MLX5_VXLAN_H__
+
+#include <linux/mlx5/driver.h>
+#include "en.h"
+
+struct mlx5e_vxlan {
+       u16 udp_port;
+};
+
+static inline bool mlx5e_vxlan_allowed(struct mlx5_core_dev *mdev)
+{
+       return (MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan) &&
+               mlx5_core_is_pf(mdev));
+}
+
+void mlx5e_vxlan_init(struct mlx5e_priv *priv);
+int  mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port);
+void mlx5e_vxlan_del_port(struct mlx5e_priv *priv, u16 port);
+struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port);
+void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv);
+
+#endif /* __MLX5_VXLAN_H__ */
index ce26adcb4988171fc5e1c81712fb5c6055fe689c..2ad7f67854d5ceda3e4234244d809314f8b71932 100644 (file)
@@ -4,6 +4,7 @@
 
 config MLXSW_CORE
        tristate "Mellanox Technologies Switch ASICs support"
+       depends on MAY_USE_DEVLINK
        ---help---
          This driver supports Mellanox Technologies Switch ASICs family.
 
index 22379eb8e92458612b7a5a8e74cc1decd8dc0629..f69f6280519f4854addfb8768497a269066d36c5 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/rcupdate.h>
 #include <linux/slab.h>
 #include <asm/byteorder.h>
+#include <net/devlink.h>
 
 #include "core.h"
 #include "item.h"
@@ -784,6 +785,38 @@ static void mlxsw_core_debugfs_fini(struct mlxsw_core *mlxsw_core)
        debugfs_remove_recursive(mlxsw_core->dbg_dir);
 }
 
+static int mlxsw_devlink_port_split(struct devlink *devlink,
+                                   unsigned int port_index,
+                                   unsigned int count)
+{
+       struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
+
+       if (port_index >= MLXSW_PORT_MAX_PORTS)
+               return -EINVAL;
+       if (!mlxsw_core->driver->port_split)
+               return -EOPNOTSUPP;
+       return mlxsw_core->driver->port_split(mlxsw_core->driver_priv,
+                                             port_index, count);
+}
+
+static int mlxsw_devlink_port_unsplit(struct devlink *devlink,
+                                     unsigned int port_index)
+{
+       struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
+
+       if (port_index >= MLXSW_PORT_MAX_PORTS)
+               return -EINVAL;
+       if (!mlxsw_core->driver->port_unsplit)
+               return -EOPNOTSUPP;
+       return mlxsw_core->driver->port_unsplit(mlxsw_core->driver_priv,
+                                               port_index);
+}
+
+static const struct devlink_ops mlxsw_devlink_ops = {
+       .port_split     = mlxsw_devlink_port_split,
+       .port_unsplit   = mlxsw_devlink_port_unsplit,
+};
+
 int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
                                   const struct mlxsw_bus *mlxsw_bus,
                                   void *bus_priv)
@@ -791,6 +824,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
        const char *device_kind = mlxsw_bus_info->device_kind;
        struct mlxsw_core *mlxsw_core;
        struct mlxsw_driver *mlxsw_driver;
+       struct devlink *devlink;
        size_t alloc_size;
        int err;
 
@@ -798,12 +832,13 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
        if (!mlxsw_driver)
                return -EINVAL;
        alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
-       mlxsw_core = kzalloc(alloc_size, GFP_KERNEL);
-       if (!mlxsw_core) {
+       devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
+       if (!devlink) {
                err = -ENOMEM;
-               goto err_core_alloc;
+               goto err_devlink_alloc;
        }
 
+       mlxsw_core = devlink_priv(devlink);
        INIT_LIST_HEAD(&mlxsw_core->rx_listener_list);
        INIT_LIST_HEAD(&mlxsw_core->event_listener_list);
        mlxsw_core->driver = mlxsw_driver;
@@ -841,6 +876,10 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
        if (err)
                goto err_hwmon_init;
 
+       err = devlink_register(devlink, mlxsw_bus_info->dev);
+       if (err)
+               goto err_devlink_register;
+
        err = mlxsw_driver->init(mlxsw_core->driver_priv, mlxsw_core,
                                 mlxsw_bus_info);
        if (err)
@@ -855,6 +894,8 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
 err_debugfs_init:
        mlxsw_core->driver->fini(mlxsw_core->driver_priv);
 err_driver_init:
+       devlink_unregister(devlink);
+err_devlink_register:
 err_hwmon_init:
        mlxsw_emad_fini(mlxsw_core);
 err_emad_init:
@@ -864,8 +905,8 @@ err_bus_init:
 err_alloc_lag_mapping:
        free_percpu(mlxsw_core->pcpu_stats);
 err_alloc_stats:
-       kfree(mlxsw_core);
-err_core_alloc:
+       devlink_free(devlink);
+err_devlink_alloc:
        mlxsw_core_driver_put(device_kind);
        return err;
 }
@@ -874,14 +915,16 @@ EXPORT_SYMBOL(mlxsw_core_bus_device_register);
 void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core)
 {
        const char *device_kind = mlxsw_core->bus_info->device_kind;
+       struct devlink *devlink = priv_to_devlink(mlxsw_core);
 
        mlxsw_core_debugfs_fini(mlxsw_core);
        mlxsw_core->driver->fini(mlxsw_core->driver_priv);
+       devlink_unregister(devlink);
        mlxsw_emad_fini(mlxsw_core);
        mlxsw_core->bus->fini(mlxsw_core->bus_priv);
        kfree(mlxsw_core->lag.mapping);
        free_percpu(mlxsw_core->pcpu_stats);
-       kfree(mlxsw_core);
+       devlink_free(devlink);
        mlxsw_core_driver_put(device_kind);
 }
 EXPORT_SYMBOL(mlxsw_core_bus_device_unregister);
index a01723600f0ae801139099e872a4fa2585a36e2f..c73d1c0792a6431b9c724c06273e5305d0dfaef9 100644 (file)
@@ -186,6 +186,8 @@ struct mlxsw_driver {
        int (*init)(void *driver_priv, struct mlxsw_core *mlxsw_core,
                    const struct mlxsw_bus_info *mlxsw_bus_info);
        void (*fini)(void *driver_priv);
+       int (*port_split)(void *driver_priv, u8 local_port, unsigned int count);
+       int (*port_unsplit)(void *driver_priv, u8 local_port);
        void (*txhdr_construct)(struct sk_buff *skb,
                                const struct mlxsw_tx_info *tx_info);
        u8 txhdr_len;
index c071077aafbdb53ad959538b290b203f2256335e..7f4173c8eda36c979b0d0e5b14f5bacc81a23a3e 100644 (file)
@@ -215,7 +215,7 @@ mlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q)
 {
        int index = q->producer_counter & (q->count - 1);
 
-       if ((q->producer_counter - q->consumer_counter) == q->count)
+       if ((u16) (q->producer_counter - q->consumer_counter) == q->count)
                return NULL;
        return mlxsw_pci_queue_elem_info_get(q, index);
 }
@@ -1681,11 +1681,18 @@ static const struct mlxsw_bus mlxsw_pci_bus = {
 
 static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci)
 {
+       unsigned long end;
+
        mlxsw_pci_write32(mlxsw_pci, SW_RESET, MLXSW_PCI_SW_RESET_RST_BIT);
-       /* Current firware does not let us know when the reset is done.
-        * So we just wait here for constant time and hope for the best.
-        */
-       msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
+       wmb(); /* reset needs to be written before we read control register */
+       end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
+       do {
+               u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
+
+               if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC)
+                       break;
+               cond_resched();
+       } while (time_before(jiffies, end));
        return 0;
 }
 
index 912106054ff2701d29a805b8e31cb41dc939b5d4..d942a3e6fa4151cbc10f4207b25c95ea8aa734c6 100644 (file)
@@ -61,6 +61,9 @@
 #define MLXSW_PCI_SW_RESET                     0xF0010
 #define MLXSW_PCI_SW_RESET_RST_BIT             BIT(0)
 #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS       5000
+#define MLXSW_PCI_FW_READY                     0xA1844
+#define MLXSW_PCI_FW_READY_MASK                        0xFF
+#define MLXSW_PCI_FW_READY_MAGIC               0x5E
 
 #define MLXSW_PCI_DOORBELL_SDQ_OFFSET          0x000
 #define MLXSW_PCI_DOORBELL_RDQ_OFFSET          0x200
index 726f5435b32f15ec3a39c7710a998c469fdd3837..f33b997f2b61c514a7f7d7017843fbbbe766472c 100644 (file)
@@ -49,7 +49,7 @@
 #define MLXSW_PORT_MID                 0xd000
 
 #define MLXSW_PORT_MAX_PHY_PORTS       0x40
-#define MLXSW_PORT_MAX_PORTS           MLXSW_PORT_MAX_PHY_PORTS
+#define MLXSW_PORT_MAX_PORTS           (MLXSW_PORT_MAX_PHY_PORTS + 1)
 
 #define MLXSW_PORT_DEVID_BITS_OFFSET   10
 #define MLXSW_PORT_PHY_BITS_OFFSET     4
@@ -59,6 +59,8 @@
 
 #define MLXSW_PORT_DONT_CARE           (MLXSW_PORT_MAX_PORTS)
 
+#define MLXSW_PORT_MODULE_MAX_WIDTH    4
+
 enum mlxsw_port_admin_status {
        MLXSW_PORT_ADMIN_STATUS_UP = 1,
        MLXSW_PORT_ADMIN_STATUS_DOWN = 2,
index bb77e2207804d9c3431b091f8d219297c8f92300..ffe4c030573332cf43bb8b3d66a0eb922031da5c 100644 (file)
@@ -873,6 +873,62 @@ static inline void mlxsw_reg_spvm_pack(char *payload, u8 local_port,
        }
 }
 
+/* SPAFT - Switch Port Acceptable Frame Types
+ * ------------------------------------------
+ * The Switch Port Acceptable Frame Types register configures the frame
+ * admittance of the port.
+ */
+#define MLXSW_REG_SPAFT_ID 0x2010
+#define MLXSW_REG_SPAFT_LEN 0x08
+
+static const struct mlxsw_reg_info mlxsw_reg_spaft = {
+       .id = MLXSW_REG_SPAFT_ID,
+       .len = MLXSW_REG_SPAFT_LEN,
+};
+
+/* reg_spaft_local_port
+ * Local port number.
+ * Access: Index
+ *
+ * Note: CPU port is not supported (all tag types are allowed).
+ */
+MLXSW_ITEM32(reg, spaft, local_port, 0x00, 16, 8);
+
+/* reg_spaft_sub_port
+ * Virtual port within the physical port.
+ * Should be set to 0 when virtual ports are not enabled on the port.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, sub_port, 0x00, 8, 8);
+
+/* reg_spaft_allow_untagged
+ * When set, untagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_untagged, 0x04, 31, 1);
+
+/* reg_spaft_allow_prio_tagged
+ * When set, priority tagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_prio_tagged, 0x04, 30, 1);
+
+/* reg_spaft_allow_tagged
+ * When set, tagged frames on the ingress are allowed (default).
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, spaft, allow_tagged, 0x04, 29, 1);
+
+static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port,
+                                       bool allow_untagged)
+{
+       MLXSW_REG_ZERO(spaft, payload);
+       mlxsw_reg_spaft_local_port_set(payload, local_port);
+       mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged);
+       mlxsw_reg_spaft_allow_prio_tagged_set(payload, true);
+       mlxsw_reg_spaft_allow_tagged_set(payload, true);
+}
+
 /* SFGC - Switch Flooding Group Configuration
  * ------------------------------------------
  * The following register controls the association of flooding tables and MIDs
@@ -3203,6 +3259,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
                return "SPVID";
        case MLXSW_REG_SPVM_ID:
                return "SPVM";
+       case MLXSW_REG_SPAFT_ID:
+               return "SPAFT";
        case MLXSW_REG_SFGC_ID:
                return "SFGC";
        case MLXSW_REG_SFTR_ID:
index 217856bdd400474d400d1e4e3dd275a096f50db5..4afbc3e9e381bffff2bdabad30bee6653ef21eae 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/jiffies.h>
 #include <linux/bitops.h>
 #include <linux/list.h>
+#include <net/devlink.h>
 #include <net/switchdev.h>
 #include <generated/utsrelease.h>
 
@@ -304,21 +305,47 @@ mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port)
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl);
 }
 
-static int mlxsw_sp_port_module_check(struct mlxsw_sp_port *mlxsw_sp_port,
-                                     bool *p_usable)
+static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp,
+                                        u8 local_port, u8 *p_module,
+                                        u8 *p_width)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        char pmlp_pl[MLXSW_REG_PMLP_LEN];
        int err;
 
-       mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port);
+       mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
        err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
        if (err)
                return err;
-       *p_usable = mlxsw_reg_pmlp_width_get(pmlp_pl) ? true : false;
+       *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
+       *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
        return 0;
 }
 
+static int mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
+                                   u8 module, u8 width, u8 lane)
+{
+       char pmlp_pl[MLXSW_REG_PMLP_LEN];
+       int i;
+
+       mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
+       mlxsw_reg_pmlp_width_set(pmlp_pl, width);
+       for (i = 0; i < width; i++) {
+               mlxsw_reg_pmlp_module_set(pmlp_pl, i, module);
+               mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, lane + i);  /* Rx & Tx */
+       }
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
+}
+
+static int mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port)
+{
+       char pmlp_pl[MLXSW_REG_PMLP_LEN];
+
+       mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
+       mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
+}
+
 static int mlxsw_sp_port_open(struct net_device *dev)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
@@ -1273,6 +1300,18 @@ static u32 mlxsw_sp_to_ptys_speed(u32 speed)
        return ptys_proto;
 }
 
+static u32 mlxsw_sp_to_ptys_upper_speed(u32 upper_speed)
+{
+       u32 ptys_proto = 0;
+       int i;
+
+       for (i = 0; i < MLXSW_SP_PORT_LINK_MODE_LEN; i++) {
+               if (mlxsw_sp_port_link_mode[i].speed <= upper_speed)
+                       ptys_proto |= mlxsw_sp_port_link_mode[i].mask;
+       }
+       return ptys_proto;
+}
+
 static int mlxsw_sp_port_set_settings(struct net_device *dev,
                                      struct ethtool_cmd *cmd)
 {
@@ -1349,11 +1388,27 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
        .set_settings           = mlxsw_sp_port_set_settings,
 };
 
-static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
+static int
+mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 width)
 {
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       u32 upper_speed = MLXSW_SP_PORT_BASE_SPEED * width;
+       char ptys_pl[MLXSW_REG_PTYS_LEN];
+       u32 eth_proto_admin;
+
+       eth_proto_admin = mlxsw_sp_to_ptys_upper_speed(upper_speed);
+       mlxsw_reg_ptys_pack(ptys_pl, mlxsw_sp_port->local_port,
+                           eth_proto_admin);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptys), ptys_pl);
+}
+
+static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
+                                 bool split, u8 module, u8 width)
+{
+       struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
        struct mlxsw_sp_port *mlxsw_sp_port;
+       struct devlink_port *devlink_port;
        struct net_device *dev;
-       bool usable;
        size_t bytes;
        int err;
 
@@ -1364,6 +1419,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
        mlxsw_sp_port->dev = dev;
        mlxsw_sp_port->mlxsw_sp = mlxsw_sp;
        mlxsw_sp_port->local_port = local_port;
+       mlxsw_sp_port->split = split;
        bytes = DIV_ROUND_UP(VLAN_N_VID, BITS_PER_BYTE);
        mlxsw_sp_port->active_vlans = kzalloc(bytes, GFP_KERNEL);
        if (!mlxsw_sp_port->active_vlans) {
@@ -1404,17 +1460,14 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
         */
        dev->hard_header_len += MLXSW_TXHDR_LEN;
 
-       err = mlxsw_sp_port_module_check(mlxsw_sp_port, &usable);
+       devlink_port = &mlxsw_sp_port->devlink_port;
+       if (mlxsw_sp_port->split)
+               devlink_port_split_set(devlink_port, module);
+       err = devlink_port_register(devlink, devlink_port, local_port);
        if (err) {
-               dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to check module\n",
-                       mlxsw_sp_port->local_port);
-               goto err_port_module_check;
-       }
-
-       if (!usable) {
-               dev_dbg(mlxsw_sp->bus_info->dev, "Port %d: Not usable, skipping initialization\n",
+               dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to register devlink port\n",
                        mlxsw_sp_port->local_port);
-               goto port_not_usable;
+               goto err_devlink_port_register;
        }
 
        err = mlxsw_sp_port_system_port_mapping_set(mlxsw_sp_port);
@@ -1431,6 +1484,13 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
                goto err_port_swid_set;
        }
 
+       err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port, width);
+       if (err) {
+               dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n",
+                       mlxsw_sp_port->local_port);
+               goto err_port_speed_by_width_set;
+       }
+
        err = mlxsw_sp_port_mtu_set(mlxsw_sp_port, ETH_DATA_LEN);
        if (err) {
                dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set MTU\n",
@@ -1457,6 +1517,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port)
                goto err_register_netdev;
        }
 
+       devlink_port_type_eth_set(devlink_port, dev);
+
        err = mlxsw_sp_port_vlan_init(mlxsw_sp_port);
        if (err)
                goto err_port_vlan_init;
@@ -1470,10 +1532,11 @@ err_register_netdev:
 err_port_buffers_init:
 err_port_admin_status_set:
 err_port_mtu_set:
+err_port_speed_by_width_set:
 err_port_swid_set:
 err_port_system_port_mapping_set:
-port_not_usable:
-err_port_module_check:
+       devlink_port_unregister(&mlxsw_sp_port->devlink_port);
+err_devlink_port_register:
 err_dev_addr_init:
        free_percpu(mlxsw_sp_port->pcpu_stats);
 err_alloc_stats:
@@ -1485,6 +1548,28 @@ err_port_active_vlans_alloc:
        return err;
 }
 
+static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port,
+                               bool split, u8 module, u8 width, u8 lane)
+{
+       int err;
+
+       err = mlxsw_sp_port_module_map(mlxsw_sp, local_port, module, width,
+                                      lane);
+       if (err)
+               return err;
+
+       err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split, module,
+                                    width);
+       if (err)
+               goto err_port_create;
+
+       return 0;
+
+err_port_create:
+       mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
+       return err;
+}
+
 static void mlxsw_sp_port_vports_fini(struct mlxsw_sp_port *mlxsw_sp_port)
 {
        struct net_device *dev = mlxsw_sp_port->dev;
@@ -1505,12 +1590,19 @@ static void mlxsw_sp_port_vports_fini(struct mlxsw_sp_port *mlxsw_sp_port)
 static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
+       struct devlink_port *devlink_port;
 
        if (!mlxsw_sp_port)
                return;
+       mlxsw_sp->ports[local_port] = NULL;
+       devlink_port = &mlxsw_sp_port->devlink_port;
+       devlink_port_type_clear(devlink_port);
        unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
+       devlink_port_unregister(devlink_port);
        mlxsw_sp_port_vports_fini(mlxsw_sp_port);
        mlxsw_sp_port_switchdev_fini(mlxsw_sp_port);
+       mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
+       mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
        free_percpu(mlxsw_sp_port->pcpu_stats);
        kfree(mlxsw_sp_port->untagged_vlans);
        kfree(mlxsw_sp_port->active_vlans);
@@ -1529,6 +1621,7 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp)
 static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
 {
        size_t alloc_size;
+       u8 module, width;
        int i;
        int err;
 
@@ -1538,19 +1631,158 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp)
                return -ENOMEM;
 
        for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++) {
-               err = mlxsw_sp_port_create(mlxsw_sp, i);
+               err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &module,
+                                                   &width);
+               if (err)
+                       goto err_port_module_info_get;
+               if (!width)
+                       continue;
+               mlxsw_sp->port_to_module[i] = module;
+               err = __mlxsw_sp_port_create(mlxsw_sp, i, false, module, width);
                if (err)
                        goto err_port_create;
        }
        return 0;
 
 err_port_create:
+err_port_module_info_get:
        for (i--; i >= 1; i--)
                mlxsw_sp_port_remove(mlxsw_sp, i);
        kfree(mlxsw_sp->ports);
        return err;
 }
 
+static u8 mlxsw_sp_cluster_base_port_get(u8 local_port)
+{
+       u8 offset = (local_port - 1) % MLXSW_SP_PORTS_PER_CLUSTER_MAX;
+
+       return local_port - offset;
+}
+
+static int mlxsw_sp_port_split(void *priv, u8 local_port, unsigned int count)
+{
+       struct mlxsw_sp *mlxsw_sp = priv;
+       struct mlxsw_sp_port *mlxsw_sp_port;
+       u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count;
+       u8 module, cur_width, base_port;
+       int i;
+       int err;
+
+       mlxsw_sp_port = mlxsw_sp->ports[local_port];
+       if (!mlxsw_sp_port) {
+               dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
+                       local_port);
+               return -EINVAL;
+       }
+
+       if (count != 2 && count != 4) {
+               netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n");
+               return -EINVAL;
+       }
+
+       err = mlxsw_sp_port_module_info_get(mlxsw_sp, local_port, &module,
+                                           &cur_width);
+       if (err) {
+               netdev_err(mlxsw_sp_port->dev, "Failed to get port's width\n");
+               return err;
+       }
+
+       if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) {
+               netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n");
+               return -EINVAL;
+       }
+
+       /* Make sure we have enough slave (even) ports for the split. */
+       if (count == 2) {
+               base_port = local_port;
+               if (mlxsw_sp->ports[base_port + 1]) {
+                       netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
+                       return -EINVAL;
+               }
+       } else {
+               base_port = mlxsw_sp_cluster_base_port_get(local_port);
+               if (mlxsw_sp->ports[base_port + 1] ||
+                   mlxsw_sp->ports[base_port + 3]) {
+                       netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n");
+                       return -EINVAL;
+               }
+       }
+
+       for (i = 0; i < count; i++)
+               mlxsw_sp_port_remove(mlxsw_sp, base_port + i);
+
+       for (i = 0; i < count; i++) {
+               err = mlxsw_sp_port_create(mlxsw_sp, base_port + i, true,
+                                          module, width, i * width);
+               if (err) {
+                       dev_err(mlxsw_sp->bus_info->dev, "Failed to create split port\n");
+                       goto err_port_create;
+               }
+       }
+
+       return 0;
+
+err_port_create:
+       for (i--; i >= 0; i--)
+               mlxsw_sp_port_remove(mlxsw_sp, base_port + i);
+       for (i = 0; i < count / 2; i++) {
+               module = mlxsw_sp->port_to_module[base_port + i * 2];
+               mlxsw_sp_port_create(mlxsw_sp, base_port + i * 2, false,
+                                    module, MLXSW_PORT_MODULE_MAX_WIDTH, 0);
+       }
+       return err;
+}
+
+static int mlxsw_sp_port_unsplit(void *priv, u8 local_port)
+{
+       struct mlxsw_sp *mlxsw_sp = priv;
+       struct mlxsw_sp_port *mlxsw_sp_port;
+       u8 module, cur_width, base_port;
+       unsigned int count;
+       int i;
+       int err;
+
+       mlxsw_sp_port = mlxsw_sp->ports[local_port];
+       if (!mlxsw_sp_port) {
+               dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n",
+                       local_port);
+               return -EINVAL;
+       }
+
+       if (!mlxsw_sp_port->split) {
+               netdev_err(mlxsw_sp_port->dev, "Port wasn't split\n");
+               return -EINVAL;
+       }
+
+       err = mlxsw_sp_port_module_info_get(mlxsw_sp, local_port, &module,
+                                           &cur_width);
+       if (err) {
+               netdev_err(mlxsw_sp_port->dev, "Failed to get port's width\n");
+               return err;
+       }
+       count = cur_width == 1 ? 4 : 2;
+
+       base_port = mlxsw_sp_cluster_base_port_get(local_port);
+
+       /* Determine which ports to remove. */
+       if (count == 2 && local_port >= base_port + 2)
+               base_port = base_port + 2;
+
+       for (i = 0; i < count; i++)
+               mlxsw_sp_port_remove(mlxsw_sp, base_port + i);
+
+       for (i = 0; i < count / 2; i++) {
+               module = mlxsw_sp->port_to_module[base_port + i * 2];
+               err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * 2, false,
+                                          module, MLXSW_PORT_MODULE_MAX_WIDTH,
+                                          0);
+               if (err)
+                       dev_err(mlxsw_sp->bus_info->dev, "Failed to reinstantiate port\n");
+       }
+
+       return 0;
+}
+
 static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg,
                                     char *pude_pl, void *priv)
 {
@@ -1974,6 +2206,8 @@ static struct mlxsw_driver mlxsw_sp_driver = {
        .priv_size              = sizeof(struct mlxsw_sp),
        .init                   = mlxsw_sp_init,
        .fini                   = mlxsw_sp_fini,
+       .port_split             = mlxsw_sp_port_split,
+       .port_unsplit           = mlxsw_sp_port_unsplit,
        .txhdr_construct        = mlxsw_sp_txhdr_construct,
        .txhdr_len              = MLXSW_TXHDR_LEN,
        .profile                = &mlxsw_sp_config_profile,
@@ -2123,6 +2357,8 @@ static int mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port,
        if (flush_fdb && mlxsw_sp_port_fdb_flush(mlxsw_sp_port))
                netdev_err(mlxsw_sp_port->dev, "Failed to flush FDB\n");
 
+       mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
+
        mlxsw_sp_port->learning = 0;
        mlxsw_sp_port->learning_sync = 0;
        mlxsw_sp_port->uc_flood = 0;
@@ -2356,9 +2592,7 @@ static int mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
        if (mlxsw_sp_port->bridged) {
                mlxsw_sp_port_active_vlans_del(mlxsw_sp_port);
                mlxsw_sp_port_bridge_leave(mlxsw_sp_port, false);
-
-               if (lag->ref_count == 1)
-                       mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL);
+               mlxsw_sp_master_bridge_dec(mlxsw_sp, NULL);
        }
 
        if (lag->ref_count == 1) {
@@ -2746,6 +2980,13 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
                goto err_vport_flood_set;
        }
 
+       err = mlxsw_sp_port_stp_state_set(mlxsw_sp_vport, vid,
+                                         MLXSW_REG_SPMS_STATE_FORWARDING);
+       if (err) {
+               netdev_err(dev, "Failed to set STP state\n");
+               goto err_port_stp_state_set;
+       }
+
        if (flush_fdb && mlxsw_sp_vport_fdb_flush(mlxsw_sp_vport))
                netdev_err(dev, "Failed to flush FDB\n");
 
@@ -2763,6 +3004,7 @@ static int mlxsw_sp_vport_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_vport,
 
        return 0;
 
+err_port_stp_state_set:
 err_vport_flood_set:
 err_port_vid_learning_set:
 err_port_vid_to_fid_validate:
index 7f42eb1c320e1c02ff12892c94261800e29eed64..4b8abaf063210cf6386b9957b0c8653898693893 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/if_vlan.h>
 #include <linux/list.h>
 #include <net/switchdev.h>
+#include <net/devlink.h>
 
 #include "port.h"
 #include "core.h"
 
 #define MLXSW_SP_MID_MAX 7000
 
+#define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4
+
+#define MLXSW_SP_PORT_BASE_SPEED 25000 /* Mb/s */
+
 struct mlxsw_sp_port;
 
 struct mlxsw_sp_upper {
@@ -118,10 +123,13 @@ struct mlxsw_sp {
 #define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
                unsigned int interval; /* ms */
        } fdb_notify;
+#define MLXSW_SP_MIN_AGEING_TIME 10
+#define MLXSW_SP_MAX_AGEING_TIME 1000000
 #define MLXSW_SP_DEFAULT_AGEING_TIME 300
        u32 ageing_time;
        struct mlxsw_sp_upper master_bridge;
        struct mlxsw_sp_upper lags[MLXSW_SP_LAG_MAX];
+       u8 port_to_module[MLXSW_PORT_MAX_PORTS];
 };
 
 static inline struct mlxsw_sp_upper *
@@ -149,7 +157,8 @@ struct mlxsw_sp_port {
           learning_sync:1,
           uc_flood:1,
           bridged:1,
-          lagged:1;
+          lagged:1,
+          split:1;
        u16 pvid;
        u16 lag_id;
        struct {
@@ -162,6 +171,7 @@ struct mlxsw_sp_port {
        unsigned long *untagged_vlans;
        /* VLAN interfaces */
        struct list_head vports_list;
+       struct devlink_port devlink_port;
 };
 
 static inline struct mlxsw_sp_port *
@@ -254,5 +264,6 @@ int mlxsw_sp_port_kill_vid(struct net_device *dev,
 int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
                             bool set, bool only_uc);
 void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
+int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
 
 #endif
index e492ca2cdecd9953d5f0ec4124f7077e839803dc..e1c74efff51ae16e585188d7d3fdbacbe071bee5 100644 (file)
@@ -311,8 +311,13 @@ static int mlxsw_sp_port_attr_br_ageing_set(struct mlxsw_sp_port *mlxsw_sp_port,
        unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t);
        u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000;
 
-       if (switchdev_trans_ph_prepare(trans))
-               return 0;
+       if (switchdev_trans_ph_prepare(trans)) {
+               if (ageing_time < MLXSW_SP_MIN_AGEING_TIME ||
+                   ageing_time > MLXSW_SP_MAX_AGEING_TIME)
+                       return -ERANGE;
+               else
+                       return 0;
+       }
 
        return mlxsw_sp_ageing_set(mlxsw_sp, ageing_time);
 }
@@ -370,7 +375,8 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
        return err;
 }
 
-static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                   u16 vid)
 {
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        char spvid_pl[MLXSW_REG_SPVID_LEN];
@@ -379,6 +385,53 @@ static int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl);
 }
 
+static int mlxsw_sp_port_allow_untagged_set(struct mlxsw_sp_port *mlxsw_sp_port,
+                                           bool allow)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       char spaft_pl[MLXSW_REG_SPAFT_LEN];
+
+       mlxsw_reg_spaft_pack(spaft_pl, mlxsw_sp_port->local_port, allow);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spaft), spaft_pl);
+}
+
+int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+       struct net_device *dev = mlxsw_sp_port->dev;
+       int err;
+
+       if (!vid) {
+               err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port, false);
+               if (err) {
+                       netdev_err(dev, "Failed to disallow untagged traffic\n");
+                       return err;
+               }
+       } else {
+               err = __mlxsw_sp_port_pvid_set(mlxsw_sp_port, vid);
+               if (err) {
+                       netdev_err(dev, "Failed to set PVID\n");
+                       return err;
+               }
+
+               /* Only allow if not already allowed. */
+               if (!mlxsw_sp_port->pvid) {
+                       err = mlxsw_sp_port_allow_untagged_set(mlxsw_sp_port,
+                                                              true);
+                       if (err) {
+                               netdev_err(dev, "Failed to allow untagged traffic\n");
+                               goto err_port_allow_untagged_set;
+                       }
+               }
+       }
+
+       mlxsw_sp_port->pvid = vid;
+       return 0;
+
+err_port_allow_untagged_set:
+       __mlxsw_sp_port_pvid_set(mlxsw_sp_port, mlxsw_sp_port->pvid);
+       return err;
+}
+
 static int mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
 {
        char sfmr_pl[MLXSW_REG_SFMR_LEN];
@@ -540,7 +593,12 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
                        netdev_err(dev, "Unable to add PVID %d\n", vid_begin);
                        goto err_port_pvid_set;
                }
-               mlxsw_sp_port->pvid = vid_begin;
+       } else if (!flag_pvid && old_pvid >= vid_begin && old_pvid <= vid_end) {
+               err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
+               if (err) {
+                       netdev_err(dev, "Unable to del PVID\n");
+                       goto err_port_pvid_set;
+               }
        }
 
        /* Changing activity bits only if HW operation succeded */
@@ -892,20 +950,18 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
                return err;
        }
 
+       if (init)
+               goto out;
+
        pvid = mlxsw_sp_port->pvid;
-       if (pvid >= vid_begin && pvid <= vid_end && pvid != 1) {
-               /* Default VLAN is always 1 */
-               err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1);
+       if (pvid >= vid_begin && pvid <= vid_end) {
+               err = mlxsw_sp_port_pvid_set(mlxsw_sp_port, 0);
                if (err) {
                        netdev_err(dev, "Unable to del PVID %d\n", pvid);
                        return err;
                }
-               mlxsw_sp_port->pvid = 1;
        }
 
-       if (init)
-               goto out;
-
        err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,
                                        false, false);
        if (err) {
index d85960cfb69438cf349517e4c15f97ede6eb1683..7a60a26759b64c0d322e14d8a1443992e12aeb1f 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/device.h>
 #include <linux/skbuff.h>
 #include <linux/if_vlan.h>
+#include <net/devlink.h>
 #include <net/switchdev.h>
 #include <generated/utsrelease.h>
 
@@ -78,6 +79,7 @@ struct mlxsw_sx_port {
        struct mlxsw_sx_port_pcpu_stats __percpu *pcpu_stats;
        struct mlxsw_sx *mlxsw_sx;
        u8 local_port;
+       struct devlink_port devlink_port;
 };
 
 /* tx_hdr_version
@@ -953,7 +955,9 @@ mlxsw_sx_port_mac_learning_mode_set(struct mlxsw_sx_port *mlxsw_sx_port,
 
 static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port)
 {
+       struct devlink *devlink = priv_to_devlink(mlxsw_sx->core);
        struct mlxsw_sx_port *mlxsw_sx_port;
+       struct devlink_port *devlink_port;
        struct net_device *dev;
        bool usable;
        int err;
@@ -1007,6 +1011,14 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port)
                goto port_not_usable;
        }
 
+       devlink_port = &mlxsw_sx_port->devlink_port;
+       err = devlink_port_register(devlink, devlink_port, local_port);
+       if (err) {
+               dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to register devlink port\n",
+                       mlxsw_sx_port->local_port);
+               goto err_devlink_port_register;
+       }
+
        err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
        if (err) {
                dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
@@ -1064,6 +1076,8 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port)
                goto err_register_netdev;
        }
 
+       devlink_port_type_eth_set(devlink_port, dev);
+
        mlxsw_sx->ports[local_port] = mlxsw_sx_port;
        return 0;
 
@@ -1075,6 +1089,8 @@ err_port_mtu_set:
 err_port_speed_set:
 err_port_swid_set:
 err_port_system_port_mapping_set:
+       devlink_port_unregister(&mlxsw_sx_port->devlink_port);
+err_devlink_port_register:
 port_not_usable:
 err_port_module_check:
 err_dev_addr_get:
@@ -1087,11 +1103,15 @@ err_alloc_stats:
 static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
 {
        struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port];
+       struct devlink_port *devlink_port;
 
        if (!mlxsw_sx_port)
                return;
+       devlink_port = &mlxsw_sx_port->devlink_port;
+       devlink_port_type_clear(devlink_port);
        unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */
        mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
+       devlink_port_unregister(devlink_port);
        free_percpu(mlxsw_sx_port->pcpu_stats);
        free_netdev(mlxsw_sx_port->dev);
 }
index 00cfd95ca59d53fe040ef5b002e7d30604d35e96..3e67f451f2ab918c95d7a6c3429d45b359e18978 100644 (file)
@@ -474,9 +474,9 @@ static int moxart_mac_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ndev->base_addr = res->start;
        priv->base = devm_ioremap_resource(p_dev, res);
-       ret = IS_ERR(priv->base);
-       if (ret) {
+       if (IS_ERR(priv->base)) {
                dev_err(p_dev, "devm_ioremap_resource failed\n");
+               ret = PTR_ERR(priv->base);
                goto init_fail;
        }
 
index 75e88f4c15315c84c20106022f38edc1dccf75e7..9b0d7f463ff3a052713d648a2b3eba0a8078a2be 100644 (file)
@@ -5629,12 +5629,8 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
        u64_stats_init(&np->swstats_rx_syncp);
        u64_stats_init(&np->swstats_tx_syncp);
 
-       init_timer(&np->oom_kick);
-       np->oom_kick.data = (unsigned long) dev;
-       np->oom_kick.function = nv_do_rx_refill;        /* timer handler */
-       init_timer(&np->nic_poll);
-       np->nic_poll.data = (unsigned long) dev;
-       np->nic_poll.function = nv_do_nic_poll; /* timer handler */
+       setup_timer(&np->oom_kick, nv_do_rx_refill, (unsigned long)dev);
+       setup_timer(&np->nic_poll, nv_do_nic_poll, (unsigned long)dev);
        init_timer_deferrable(&np->stats_poll);
        np->stats_poll.data = (unsigned long) dev;
        np->stats_poll.function = nv_do_stats_poll;     /* timer handler */
index db19c6f49859d38e594acb81607197a3f8cbc9d7..7c92e8306c1948264622e3de35e7d334de5d2639 100644 (file)
@@ -5,7 +5,7 @@
 config NET_VENDOR_PASEMI
        bool "PA Semi devices"
        default y
-       depends on PPC_PASEMI && PCI && INET
+       depends on PPC_PASEMI && PCI
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -18,9 +18,8 @@ if NET_VENDOR_PASEMI
 
 config PASEMI_MAC
        tristate "PA Semi 1/10Gbit MAC"
-       depends on PPC_PASEMI && PCI && INET
+       depends on PPC_PASEMI && PCI
        select PHYLIB
-       select INET_LRO
        ---help---
          This driver supports the on-chip 1/10Gbit Ethernet controller on
          PA Semi's PWRficient line of chips.
index 57a6e6cd74fc3c9c99708530b431cd0e5b768f8c..af54df52aa6b7927671f7ec199524f80d15421fc 100644 (file)
@@ -30,9 +30,7 @@
 #include <linux/skbuff.h>
 
 #include <linux/ip.h>
-#include <linux/tcp.h>
 #include <net/checksum.h>
-#include <linux/inet_lro.h>
 #include <linux/prefetch.h>
 
 #include <asm/irq.h>
  *
  * - Multicast support
  * - Large MTU support
- * - SW LRO
  * - Multiqueue RX/TX
  */
 
-#define LRO_MAX_AGGR 64
-
 #define PE_MIN_MTU     64
 #define PE_MAX_MTU     9000
 #define PE_DEF_MTU     ETH_DATA_LEN
@@ -257,37 +252,6 @@ static int pasemi_mac_set_mac_addr(struct net_device *dev, void *p)
        return 0;
 }
 
-static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
-                      void **tcph, u64 *hdr_flags, void *data)
-{
-       u64 macrx = (u64) data;
-       unsigned int ip_len;
-       struct iphdr *iph;
-
-       /* IPv4 header checksum failed */
-       if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK)
-               return -1;
-
-       /* non tcp packet */
-       skb_reset_network_header(skb);
-       iph = ip_hdr(skb);
-       if (iph->protocol != IPPROTO_TCP)
-               return -1;
-
-       ip_len = ip_hdrlen(skb);
-       skb_set_transport_header(skb, ip_len);
-       *tcph = tcp_hdr(skb);
-
-       /* check if ip header and tcp header are complete */
-       if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
-               return -1;
-
-       *hdr_flags = LRO_IPV4 | LRO_TCP;
-       *iphdr = iph;
-
-       return 0;
-}
-
 static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
                                    const int nfrags,
                                    struct sk_buff *skb,
@@ -817,7 +781,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
                skb_put(skb, len-4);
 
                skb->protocol = eth_type_trans(skb, mac->netdev);
-               lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx);
+               napi_gro_receive(&mac->napi, skb);
 
 next:
                RX_DESC(rx, n) = 0;
@@ -839,8 +803,6 @@ next:
 
        rx_ring(mac)->next_to_clean = n;
 
-       lro_flush_all(&mac->lro_mgr);
-
        /* Increase is in number of 16-byte entries, and since each descriptor
         * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
         * count*2.
@@ -1754,16 +1716,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
                        NETIF_F_HIGHDMA | NETIF_F_GSO;
 
-       mac->lro_mgr.max_aggr = LRO_MAX_AGGR;
-       mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
-       mac->lro_mgr.lro_arr = mac->lro_desc;
-       mac->lro_mgr.get_skb_header = get_skb_hdr;
-       mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
-       mac->lro_mgr.dev = mac->netdev;
-       mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
-       mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-
-
        mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
        if (!mac->dma_pdev) {
                dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
index a5807703ab9650f176c268f828415c81a5598a5e..161c99a98403c5aa3eeadb0dedf71dbbf141f8c3 100644 (file)
@@ -31,7 +31,6 @@
 #define CS_RING_SIZE (TX_RING_SIZE*2)
 
 
-#define MAX_LRO_DESCRIPTORS 8
 #define MAX_CS 2
 
 struct pasemi_mac_txring {
@@ -84,10 +83,7 @@ struct pasemi_mac {
 
        u8              mac_addr[ETH_ALEN];
 
-       struct net_lro_mgr      lro_mgr;
-       struct net_lro_desc     lro_desc[MAX_LRO_DESCRIPTORS];
        struct timer_list       rxtimer;
-       unsigned int            lro_max_aggr;
 
        struct pasemi_mac_txring *tx;
        struct pasemi_mac_rxring *rx;
index 25fae568261f6d2b51ea1011c4610b2019b88de7..f046bfc18e7db064bb280c7ec41618bc4b8df6a1 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
-#include <linux/inet_lro.h>
 
 #include <asm/pasemi_dma.h>
 #include "pasemi_mac.h"
index 6409a06bbdf633b0ce440bf817aabfe69311dd1e..fd362b6923f48b9fff5c55fdcf7fd241d94ef9aa 100644 (file)
@@ -2891,7 +2891,7 @@ netxen_sysfs_read_crb(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
        u64 qmdata;
@@ -2919,7 +2919,7 @@ netxen_sysfs_write_crb(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
        u64 qmdata;
@@ -2960,7 +2960,7 @@ netxen_sysfs_read_mem(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u64 data;
        int ret;
@@ -2981,7 +2981,7 @@ static ssize_t netxen_sysfs_write_mem(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t offset, size_t size)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u64 data;
        int ret;
@@ -3018,7 +3018,7 @@ netxen_sysfs_read_dimm(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t offset, size_t size)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        struct net_device *netdev = adapter->netdev;
        struct netxen_dimm_cfg dimm;
index 1292c360390cd79d532ca155158858bd630648d5..fcb8e9ba51d9b6ad85ecf6bd2361e71896c6b592 100644 (file)
@@ -26,7 +26,7 @@
 #include "qed_hsi.h"
 
 extern const struct qed_common_ops qed_common_ops_pass;
-#define DRV_MODULE_VERSION "8.4.0.0"
+#define DRV_MODULE_VERSION "8.7.0.0"
 
 #define MAX_HWFNS_PER_DEVICE    (4)
 #define NAME_SIZE 16
@@ -70,8 +70,8 @@ struct qed_sb_sp_info;
 struct qed_mcp_info;
 
 struct qed_rt_data {
-       u32 init_val;
-       bool b_valid;
+       u32     *init_val;
+       bool    *b_valid;
 };
 
 /* The PCI personality is not quite synonymous to protocol ID:
@@ -120,6 +120,10 @@ enum QED_PORT_MODE {
        QED_PORT_MODE_DE_1X25G
 };
 
+enum qed_dev_cap {
+       QED_DEV_CAP_ETH,
+};
+
 struct qed_hw_info {
        /* PCI personality */
        enum qed_pci_personality        personality;
@@ -142,15 +146,13 @@ struct qed_hw_info {
        u16                             ovlan;
        u32                             part_num[4];
 
-       u32                             vendor_id;
-       u32                             device_id;
-
        unsigned char                   hw_mac_addr[ETH_ALEN];
 
        struct qed_igu_info             *p_igu_info;
 
        u32                             port_mode;
        u32                             hw_mode;
+       unsigned long           device_capabilities;
 };
 
 struct qed_hw_cid_data {
@@ -267,7 +269,7 @@ struct qed_hwfn {
        struct qed_hw_info              hw_info;
 
        /* rt_array (for init-tool) */
-       struct qed_rt_data              *rt_data;
+       struct qed_rt_data              rt_data;
 
        /* SPQ */
        struct qed_spq                  *p_spq;
@@ -301,6 +303,9 @@ struct qed_hwfn {
        bool                            b_int_enabled;
        bool                            b_int_requested;
 
+       /* True if the driver requests for the link */
+       bool                            b_drv_link_init;
+
        struct qed_mcp_info             *mcp_info;
 
        struct qed_hw_cid_data          *p_tx_cids;
@@ -350,9 +355,20 @@ struct qed_dev {
        char    name[NAME_SIZE];
 
        u8      type;
-#define QED_DEV_TYPE_BB_A0      (0 << 0)
-#define QED_DEV_TYPE_MASK       (0x3)
-#define QED_DEV_TYPE_SHIFT      (0)
+#define QED_DEV_TYPE_BB (0 << 0)
+#define QED_DEV_TYPE_AH BIT(0)
+/* Translate type/revision combo into the proper conditions */
+#define QED_IS_BB(dev)  ((dev)->type == QED_DEV_TYPE_BB)
+#define QED_IS_BB_A0(dev)       (QED_IS_BB(dev) && \
+                                CHIP_REV_IS_A0(dev))
+#define QED_IS_BB_B0(dev)       (QED_IS_BB(dev) && \
+                                CHIP_REV_IS_B0(dev))
+
+#define QED_GET_TYPE(dev)       (QED_IS_BB_A0(dev) ? CHIP_BB_A0 : \
+                                QED_IS_BB_B0(dev) ? CHIP_BB_B0 : CHIP_K2)
+
+       u16     vendor_id;
+       u16     device_id;
 
        u16     chip_num;
 #define CHIP_NUM_MASK                   0xffff
@@ -361,6 +377,8 @@ struct qed_dev {
        u16     chip_rev;
 #define CHIP_REV_MASK                   0xf
 #define CHIP_REV_SHIFT                  12
+#define CHIP_REV_IS_A0(_cdev)   (!(_cdev)->chip_rev)
+#define CHIP_REV_IS_B0(_cdev)   ((_cdev)->chip_rev == 1)
 
        u16                             chip_metal;
 #define CHIP_METAL_MASK                 0xff
@@ -375,10 +393,10 @@ struct qed_dev {
        u8                              num_funcs_in_port;
 
        u8                              path_id;
-       enum mf_mode                    mf_mode;
-#define IS_MF(_p_hwfn)          (((_p_hwfn)->cdev)->mf_mode != SF)
-#define IS_MF_SI(_p_hwfn)       (((_p_hwfn)->cdev)->mf_mode == MF_NPAR)
-#define IS_MF_SD(_p_hwfn)       (((_p_hwfn)->cdev)->mf_mode == MF_OVLAN)
+       enum qed_mf_mode                mf_mode;
+#define IS_MF_DEFAULT(_p_hwfn)  (((_p_hwfn)->cdev)->mf_mode == QED_MF_DEFAULT)
+#define IS_MF_SI(_p_hwfn)       (((_p_hwfn)->cdev)->mf_mode == QED_MF_NPAR)
+#define IS_MF_SD(_p_hwfn)       (((_p_hwfn)->cdev)->mf_mode == QED_MF_OVLAN)
 
        int                             pcie_width;
        int                             pcie_speed;
@@ -441,11 +459,6 @@ struct qed_dev {
        const struct firmware           *firmware;
 };
 
-#define QED_GET_TYPE(dev)       (((dev)->type & QED_DEV_TYPE_MASK) >> \
-                                QED_DEV_TYPE_SHIFT)
-#define QED_IS_BB_A0(dev)       (QED_GET_TYPE(dev) == QED_DEV_TYPE_BB_A0)
-#define QED_IS_BB(dev)  (QED_IS_BB_A0(dev))
-
 #define NUM_OF_SBS(dev)         MAX_SB_PER_PATH_BB
 #define NUM_OF_ENG_PFS(dev)     MAX_NUM_PFS_BB
 
index 7ccdb46c67645e9522dcd58eb5ed278e1acfc549..fc767c07a2644bf11b12e50b005c55b6d5bae828 100644 (file)
@@ -448,7 +448,7 @@ int qed_cxt_mngr_alloc(struct qed_hwfn *p_hwfn)
        struct qed_cxt_mngr *p_mngr;
        u32 i;
 
-       p_mngr = kzalloc(sizeof(*p_mngr), GFP_ATOMIC);
+       p_mngr = kzalloc(sizeof(*p_mngr), GFP_KERNEL);
        if (!p_mngr) {
                DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_cxt_mngr'\n");
                return -ENOMEM;
@@ -581,7 +581,8 @@ void qed_qm_init_pf(struct qed_hwfn *p_hwfn)
        params.num_pf_cids = iids.cids;
        params.start_pq = qm_info->start_pq;
        params.num_pf_pqs = qm_info->num_pqs;
-       params.start_vport = qm_info->num_vports;
+       params.start_vport = qm_info->start_vport;
+       params.num_vports = qm_info->num_vports;
        params.pf_wfq = qm_info->pf_wfq;
        params.pf_rl = qm_info->pf_rl;
        params.pq_params = qm_info->qm_pq_params;
index 817bbd5476ffb5956fca105686fc9029d06339ff..b7d100f6bd6fac64d90977b920a7a29150cd5427 100644 (file)
 #include "qed_sp.h"
 
 /* API common to all protocols */
+enum BAR_ID {
+       BAR_ID_0,       /* used for GRC */
+       BAR_ID_1        /* Used for doorbells */
+};
+
+static u32 qed_hw_bar_size(struct qed_hwfn     *p_hwfn,
+                          enum BAR_ID          bar_id)
+{
+       u32     bar_reg = (bar_id == BAR_ID_0 ?
+                          PGLUE_B_REG_PF_BAR0_SIZE : PGLUE_B_REG_PF_BAR1_SIZE);
+       u32     val = qed_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg);
+
+       if (val)
+               return 1 << (val + 15);
+
+       /* Old MFW initialized above registered only conditionally */
+       if (p_hwfn->cdev->num_hwfns > 1) {
+               DP_INFO(p_hwfn,
+                       "BAR size not configured. Assuming BAR size of 256kB for GRC and 512kB for DB\n");
+                       return BAR_ID_0 ? 256 * 1024 : 512 * 1024;
+       } else {
+               DP_INFO(p_hwfn,
+                       "BAR size not configured. Assuming BAR size of 512kB for GRC and 512kB for DB\n");
+                       return 512 * 1024;
+       }
+}
+
 void qed_init_dp(struct qed_dev *cdev,
                 u32 dp_module, u8 dp_level)
 {
@@ -134,17 +161,17 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn)
        /* PQs will be arranged as follows: First per-TC PQ then pure-LB quete.
         */
        qm_info->qm_pq_params = kzalloc(sizeof(*qm_info->qm_pq_params) *
-                                       num_pqs, GFP_ATOMIC);
+                                       num_pqs, GFP_KERNEL);
        if (!qm_info->qm_pq_params)
                goto alloc_err;
 
        qm_info->qm_vport_params = kzalloc(sizeof(*qm_info->qm_vport_params) *
-                                          num_vports, GFP_ATOMIC);
+                                          num_vports, GFP_KERNEL);
        if (!qm_info->qm_vport_params)
                goto alloc_err;
 
        qm_info->qm_port_params = kzalloc(sizeof(*qm_info->qm_port_params) *
-                                         MAX_NUM_PORTS, GFP_ATOMIC);
+                                         MAX_NUM_PORTS, GFP_KERNEL);
        if (!qm_info->qm_port_params)
                goto alloc_err;
 
@@ -341,11 +368,6 @@ void qed_resc_setup(struct qed_dev *cdev)
        }
 }
 
-#define FINAL_CLEANUP_CMD_OFFSET        (0)
-#define FINAL_CLEANUP_CMD (0x1)
-#define FINAL_CLEANUP_VALID_OFFSET      (6)
-#define FINAL_CLEANUP_VFPF_ID_SHIFT     (7)
-#define FINAL_CLEANUP_COMP (0x2)
 #define FINAL_CLEANUP_POLL_CNT          (100)
 #define FINAL_CLEANUP_POLL_TIME         (10)
 int qed_final_cleanup(struct qed_hwfn *p_hwfn,
@@ -355,12 +377,14 @@ int qed_final_cleanup(struct qed_hwfn *p_hwfn,
        u32 command = 0, addr, count = FINAL_CLEANUP_POLL_CNT;
        int rc = -EBUSY;
 
-       addr = GTT_BAR0_MAP_REG_USDM_RAM + USTORM_FLR_FINAL_ACK_OFFSET;
+       addr = GTT_BAR0_MAP_REG_USDM_RAM +
+               USTORM_FLR_FINAL_ACK_OFFSET(p_hwfn->rel_pf_id);
 
-       command |= FINAL_CLEANUP_CMD << FINAL_CLEANUP_CMD_OFFSET;
-       command |= 1 << FINAL_CLEANUP_VALID_OFFSET;
-       command |= id << FINAL_CLEANUP_VFPF_ID_SHIFT;
-       command |= FINAL_CLEANUP_COMP << SDM_OP_GEN_COMP_TYPE_SHIFT;
+       command |= X_FINAL_CLEANUP_AGG_INT <<
+               SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT;
+       command |= 1 << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT;
+       command |= id << SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT;
+       command |= SDM_COMP_TYPE_AGG_INT << SDM_OP_GEN_COMP_TYPE_SHIFT;
 
        /* Make sure notification is not set before initiating final cleanup */
        if (REG_RD(p_hwfn, addr)) {
@@ -396,7 +420,7 @@ static void qed_calc_hw_mode(struct qed_hwfn *p_hwfn)
 {
        int hw_mode = 0;
 
-       hw_mode = (1 << MODE_BB_A0);
+       hw_mode = (1 << MODE_BB_B0);
 
        switch (p_hwfn->cdev->num_ports_in_engines) {
        case 1:
@@ -415,18 +439,16 @@ static void qed_calc_hw_mode(struct qed_hwfn *p_hwfn)
        }
 
        switch (p_hwfn->cdev->mf_mode) {
-       case SF:
-               hw_mode |= 1 << MODE_SF;
+       case QED_MF_DEFAULT:
+       case QED_MF_NPAR:
+               hw_mode |= 1 << MODE_MF_SI;
                break;
-       case MF_OVLAN:
+       case QED_MF_OVLAN:
                hw_mode |= 1 << MODE_MF_SD;
                break;
-       case MF_NPAR:
-               hw_mode |= 1 << MODE_MF_SI;
-               break;
        default:
-               DP_NOTICE(p_hwfn, "Unsupported MF mode, init as SF\n");
-               hw_mode |= 1 << MODE_SF;
+               DP_NOTICE(p_hwfn, "Unsupported MF mode, init as DEFAULT\n");
+               hw_mode |= 1 << MODE_MF_SI;
        }
 
        hw_mode |= 1 << MODE_ASIC;
@@ -655,10 +677,8 @@ int qed_hw_init(struct qed_dev *cdev,
                bool allow_npar_tx_switch,
                const u8 *bin_fw_data)
 {
-       struct qed_storm_stats *p_stat;
-       u32 load_code, param, *p_address;
+       u32 load_code, param;
        int rc, mfw_rc, i;
-       u8 fw_vport = 0;
 
        rc = qed_init_fw_data(cdev, bin_fw_data);
        if (rc != 0)
@@ -667,10 +687,6 @@ int qed_hw_init(struct qed_dev *cdev,
        for_each_hwfn(cdev, i) {
                struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
 
-               rc = qed_fw_vport(p_hwfn, 0, &fw_vport);
-               if (rc != 0)
-                       return rc;
-
                /* Enable DMAE in PXP */
                rc = qed_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true);
 
@@ -734,35 +750,60 @@ int qed_hw_init(struct qed_dev *cdev,
                }
 
                p_hwfn->hw_init_done = true;
+       }
+
+       return 0;
+}
 
-               /* init PF stats */
-               p_stat = &p_hwfn->storm_stats;
-               p_stat->mstats.address = BAR0_MAP_REG_MSDM_RAM +
-                                        MSTORM_QUEUE_STAT_OFFSET(fw_vport);
-               p_stat->mstats.len = sizeof(struct eth_mstorm_per_queue_stat);
+#define QED_HW_STOP_RETRY_LIMIT (10)
+static inline void qed_hw_timers_stop(struct qed_dev *cdev,
+                                     struct qed_hwfn *p_hwfn,
+                                     struct qed_ptt *p_ptt)
+{
+       int i;
 
-               p_stat->ustats.address = BAR0_MAP_REG_USDM_RAM +
-                                        USTORM_QUEUE_STAT_OFFSET(fw_vport);
-               p_stat->ustats.len = sizeof(struct eth_ustorm_per_queue_stat);
+       /* close timers */
+       qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
+       qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
 
-               p_stat->pstats.address = BAR0_MAP_REG_PSDM_RAM +
-                                        PSTORM_QUEUE_STAT_OFFSET(fw_vport);
-               p_stat->pstats.len = sizeof(struct eth_pstorm_per_queue_stat);
+       for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
+               if ((!qed_rd(p_hwfn, p_ptt,
+                            TM_REG_PF_SCAN_ACTIVE_CONN)) &&
+                   (!qed_rd(p_hwfn, p_ptt,
+                            TM_REG_PF_SCAN_ACTIVE_TASK)))
+                       break;
 
-               p_address = &p_stat->tstats.address;
-               *p_address = BAR0_MAP_REG_TSDM_RAM +
-                            TSTORM_PORT_STAT_OFFSET(MFW_PORT(p_hwfn));
-               p_stat->tstats.len = sizeof(struct tstorm_per_port_stat);
+               /* Dependent on number of connection/tasks, possibly
+                * 1ms sleep is required between polls
+                */
+               usleep_range(1000, 2000);
        }
 
-       return 0;
+       if (i < QED_HW_STOP_RETRY_LIMIT)
+               return;
+
+       DP_NOTICE(p_hwfn,
+                 "Timers linear scans are not over [Connection %02x Tasks %02x]\n",
+                 (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_CONN),
+                 (u8)qed_rd(p_hwfn, p_ptt, TM_REG_PF_SCAN_ACTIVE_TASK));
+}
+
+void qed_hw_timers_stop_all(struct qed_dev *cdev)
+{
+       int j;
+
+       for_each_hwfn(cdev, j) {
+               struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
+               struct qed_ptt *p_ptt = p_hwfn->p_main_ptt;
+
+               qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
+       }
 }
 
-#define QED_HW_STOP_RETRY_LIMIT (10)
 int qed_hw_stop(struct qed_dev *cdev)
 {
        int rc = 0, t_rc;
-       int i, j;
+       int j;
 
        for_each_hwfn(cdev, j) {
                struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
@@ -775,7 +816,8 @@ int qed_hw_stop(struct qed_dev *cdev)
 
                rc = qed_sp_pf_stop(p_hwfn);
                if (rc)
-                       return rc;
+                       DP_NOTICE(p_hwfn,
+                                 "Failed to close PF against FW. Continue to stop HW to prevent illegal host access by the device\n");
 
                qed_wr(p_hwfn, p_ptt,
                       NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF, 0x1);
@@ -786,24 +828,7 @@ int qed_hw_stop(struct qed_dev *cdev)
                qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
                qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
 
-               qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
-               qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
-               for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
-                       if ((!qed_rd(p_hwfn, p_ptt,
-                                    TM_REG_PF_SCAN_ACTIVE_CONN)) &&
-                           (!qed_rd(p_hwfn, p_ptt,
-                                    TM_REG_PF_SCAN_ACTIVE_TASK)))
-                               break;
-
-                       usleep_range(1000, 2000);
-               }
-               if (i == QED_HW_STOP_RETRY_LIMIT)
-                       DP_NOTICE(p_hwfn,
-                                 "Timers linear scans are not over [Connection %02x Tasks %02x]\n",
-                                 (u8)qed_rd(p_hwfn, p_ptt,
-                                            TM_REG_PF_SCAN_ACTIVE_CONN),
-                                 (u8)qed_rd(p_hwfn, p_ptt,
-                                            TM_REG_PF_SCAN_ACTIVE_TASK));
+               qed_hw_timers_stop(cdev, p_hwfn, p_ptt);
 
                /* Disable Attention Generation */
                qed_int_igu_disable_int(p_hwfn, p_ptt);
@@ -832,7 +857,7 @@ int qed_hw_stop(struct qed_dev *cdev)
 
 void qed_hw_stop_fastpath(struct qed_dev *cdev)
 {
-       int i, j;
+       int j;
 
        for_each_hwfn(cdev, j) {
                struct qed_hwfn *p_hwfn = &cdev->hwfns[j];
@@ -851,25 +876,6 @@ void qed_hw_stop_fastpath(struct qed_dev *cdev)
                qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_ROCE, 0x0);
                qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_OPENFLOW, 0x0);
 
-               qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_CONN, 0x0);
-               qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, 0x0);
-               for (i = 0; i < QED_HW_STOP_RETRY_LIMIT; i++) {
-                       if ((!qed_rd(p_hwfn, p_ptt,
-                                    TM_REG_PF_SCAN_ACTIVE_CONN)) &&
-                           (!qed_rd(p_hwfn, p_ptt,
-                                    TM_REG_PF_SCAN_ACTIVE_TASK)))
-                               break;
-
-                       usleep_range(1000, 2000);
-               }
-               if (i == QED_HW_STOP_RETRY_LIMIT)
-                       DP_NOTICE(p_hwfn,
-                                 "Timers linear scans are not over [Connection %02x Tasks %02x]\n",
-                                 (u8)qed_rd(p_hwfn, p_ptt,
-                                            TM_REG_PF_SCAN_ACTIVE_CONN),
-                                 (u8)qed_rd(p_hwfn, p_ptt,
-                                            TM_REG_PF_SCAN_ACTIVE_TASK));
-
                qed_int_igu_init_pure_rt(p_hwfn, p_ptt, false, false);
 
                /* Need to wait 1ms to guarantee SBs are cleared */
@@ -954,18 +960,8 @@ static void qed_hw_hwfn_free(struct qed_hwfn *p_hwfn)
 }
 
 /* Setup bar access */
-static int qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
+static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
 {
-       int rc;
-
-       /* Allocate PTT pool */
-       rc = qed_ptt_pool_alloc(p_hwfn);
-       if (rc)
-               return rc;
-
-       /* Allocate the main PTT */
-       p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN);
-
        /* clear indirect access */
        qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_88_F0, 0);
        qed_wr(p_hwfn, p_hwfn->p_main_ptt, PGLUE_B_REG_PGL_ADDR_8C_F0, 0);
@@ -980,8 +976,6 @@ static int qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
        /* enable internal target-read */
        qed_wr(p_hwfn, p_hwfn->p_main_ptt,
               PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
-
-       return 0;
 }
 
 static void get_function_id(struct qed_hwfn *p_hwfn)
@@ -1016,14 +1010,17 @@ static void qed_hw_get_resc(struct qed_hwfn *p_hwfn)
 {
        u32 *resc_start = p_hwfn->hw_info.resc_start;
        u32 *resc_num = p_hwfn->hw_info.resc_num;
+       struct qed_sb_cnt_info sb_cnt_info;
        int num_funcs, i;
 
-       num_funcs = IS_MF(p_hwfn) ? MAX_NUM_PFS_BB
-                                 : p_hwfn->cdev->num_ports_in_engines;
+       num_funcs = MAX_NUM_PFS_BB;
+
+       memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
+       qed_int_get_num_sbs(p_hwfn, &sb_cnt_info);
 
        resc_num[QED_SB] = min_t(u32,
                                 (MAX_SB_PER_PATH_BB / num_funcs),
-                                qed_int_get_num_sbs(p_hwfn, NULL));
+                                sb_cnt_info.sb_cnt);
        resc_num[QED_L2_QUEUE] = MAX_NUM_L2_QUEUES_BB / num_funcs;
        resc_num[QED_VPORT] = MAX_NUM_VPORTS_BB / num_funcs;
        resc_num[QED_RSS_ENG] = ETH_RSS_ENGINE_NUM_BB / num_funcs;
@@ -1071,7 +1068,7 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
                               struct qed_ptt *p_ptt)
 {
        u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
-       u32 port_cfg_addr, link_temp, val, nvm_cfg_addr;
+       u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
        struct qed_mcp_link_params *link;
 
        /* Read global nvm_cfg address */
@@ -1086,13 +1083,6 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
        /* Read nvm_cfg1  (Notice this is just offset, and not offsize (TBD) */
        nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4);
 
-       /* Read Vendor Id / Device Id */
-       addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
-              offsetof(struct nvm_cfg1, glob) +
-              offsetof(struct nvm_cfg1_glob, pci_id);
-       p_hwfn->hw_info.vendor_id = qed_rd(p_hwfn, p_ptt, addr) &
-                                   NVM_CFG1_GLOB_VENDOR_ID_MASK;
-
        addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
               offsetof(struct nvm_cfg1, glob) +
               offsetof(struct nvm_cfg1_glob, core_cfg);
@@ -1134,21 +1124,6 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
                break;
        }
 
-       addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
-              offsetof(struct nvm_cfg1, func[MCP_PF_ID(p_hwfn)]) +
-              offsetof(struct nvm_cfg1_func, device_id);
-       val = qed_rd(p_hwfn, p_ptt, addr);
-
-       if (IS_MF(p_hwfn)) {
-               p_hwfn->hw_info.device_id =
-                       (val & NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_MASK) >>
-                       NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_OFFSET;
-       } else {
-               p_hwfn->hw_info.device_id =
-                       (val & NVM_CFG1_FUNC_VENDOR_DEVICE_ID_MASK) >>
-                       NVM_CFG1_FUNC_VENDOR_DEVICE_ID_OFFSET;
-       }
-
        /* Read default link configuration */
        link = &p_hwfn->mcp_info->link_input;
        port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
@@ -1220,18 +1195,28 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn,
 
        switch (mf_mode) {
        case NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED:
-               p_hwfn->cdev->mf_mode = MF_OVLAN;
+               p_hwfn->cdev->mf_mode = QED_MF_OVLAN;
                break;
        case NVM_CFG1_GLOB_MF_MODE_NPAR1_0:
-               p_hwfn->cdev->mf_mode = MF_NPAR;
+               p_hwfn->cdev->mf_mode = QED_MF_NPAR;
                break;
-       case NVM_CFG1_GLOB_MF_MODE_FORCED_SF:
-               p_hwfn->cdev->mf_mode = SF;
+       case NVM_CFG1_GLOB_MF_MODE_DEFAULT:
+               p_hwfn->cdev->mf_mode = QED_MF_DEFAULT;
                break;
        }
        DP_INFO(p_hwfn, "Multi function mode is %08x\n",
                p_hwfn->cdev->mf_mode);
 
+       /* Read Multi-function information from shmem */
+       addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
+               offsetof(struct nvm_cfg1, glob) +
+               offsetof(struct nvm_cfg1_glob, device_capabilities);
+
+       device_capabilities = qed_rd(p_hwfn, p_ptt, addr);
+       if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET)
+               __set_bit(QED_DEV_CAP_ETH,
+                         &p_hwfn->hw_info.device_capabilities);
+
        return qed_mcp_fill_shmem_func_info(p_hwfn, p_ptt);
 }
 
@@ -1291,31 +1276,38 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn,
        return rc;
 }
 
-static void qed_get_dev_info(struct qed_dev *cdev)
+static int qed_get_dev_info(struct qed_dev *cdev)
 {
+       struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
        u32 tmp;
 
-       cdev->chip_num = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt,
+       /* Read Vendor Id / Device Id */
+       pci_read_config_word(cdev->pdev, PCI_VENDOR_ID,
+                            &cdev->vendor_id);
+       pci_read_config_word(cdev->pdev, PCI_DEVICE_ID,
+                            &cdev->device_id);
+       cdev->chip_num = (u16)qed_rd(p_hwfn, p_hwfn->p_main_ptt,
                                     MISCS_REG_CHIP_NUM);
-       cdev->chip_rev = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt,
+       cdev->chip_rev = (u16)qed_rd(p_hwfn, p_hwfn->p_main_ptt,
                                     MISCS_REG_CHIP_REV);
        MASK_FIELD(CHIP_REV, cdev->chip_rev);
 
+       cdev->type = QED_DEV_TYPE_BB;
        /* Learn number of HW-functions */
-       tmp = qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt,
+       tmp = qed_rd(p_hwfn, p_hwfn->p_main_ptt,
                     MISCS_REG_CMT_ENABLED_FOR_PAIR);
 
-       if (tmp & (1 << cdev->hwfns[0].rel_pf_id)) {
+       if (tmp & (1 << p_hwfn->rel_pf_id)) {
                DP_NOTICE(cdev->hwfns, "device in CMT mode\n");
                cdev->num_hwfns = 2;
        } else {
                cdev->num_hwfns = 1;
        }
 
-       cdev->chip_bond_id = qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt,
+       cdev->chip_bond_id = qed_rd(p_hwfn, p_hwfn->p_main_ptt,
                                    MISCS_REG_CHIP_TEST_REG) >> 4;
        MASK_FIELD(CHIP_BOND_ID, cdev->chip_bond_id);
-       cdev->chip_metal = (u16)qed_rd(cdev->hwfns, cdev->hwfns[0].p_main_ptt,
+       cdev->chip_metal = (u16)qed_rd(p_hwfn, p_hwfn->p_main_ptt,
                                       MISCS_REG_CHIP_METAL);
        MASK_FIELD(CHIP_METAL, cdev->chip_metal);
 
@@ -1323,6 +1315,14 @@ static void qed_get_dev_info(struct qed_dev *cdev)
                "Chip details - Num: %04x Rev: %04x Bond id: %04x Metal: %04x\n",
                cdev->chip_num, cdev->chip_rev,
                cdev->chip_bond_id, cdev->chip_metal);
+
+       if (QED_IS_BB(cdev) && CHIP_REV_IS_A0(cdev)) {
+               DP_NOTICE(cdev->hwfns,
+                         "The chip type/rev (BB A0) is not supported!\n");
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
@@ -1345,15 +1345,24 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
 
        get_function_id(p_hwfn);
 
-       rc = qed_hw_hwfn_prepare(p_hwfn);
+       /* Allocate PTT pool */
+       rc = qed_ptt_pool_alloc(p_hwfn);
        if (rc) {
                DP_NOTICE(p_hwfn, "Failed to prepare hwfn's hw\n");
                goto err0;
        }
 
+       /* Allocate the main PTT */
+       p_hwfn->p_main_ptt = qed_get_reserved_ptt(p_hwfn, RESERVED_PTT_MAIN);
+
        /* First hwfn learns basic information, e.g., number of hwfns */
-       if (!p_hwfn->my_id)
-               qed_get_dev_info(p_hwfn->cdev);
+       if (!p_hwfn->my_id) {
+               rc = qed_get_dev_info(p_hwfn->cdev);
+               if (rc != 0)
+                       goto err1;
+       }
+
+       qed_hw_hwfn_prepare(p_hwfn);
 
        /* Initialize MCP structure */
        rc = qed_mcp_cmd_init(p_hwfn, p_hwfn->p_main_ptt);
@@ -1385,17 +1394,6 @@ err0:
        return rc;
 }
 
-static u32 qed_hw_bar_size(struct qed_hwfn     *p_hwfn,
-                          u8                   bar_id)
-{
-       u32 bar_reg = (bar_id == 0 ? PGLUE_B_REG_PF_BAR0_SIZE
-                      : PGLUE_B_REG_PF_BAR1_SIZE);
-       u32 val = qed_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg);
-
-       /* Get the BAR size(in KB) from hardware given val */
-       return 1 << (val + 15);
-}
-
 int qed_hw_prepare(struct qed_dev *cdev,
                   int personality)
 {
@@ -1420,11 +1418,11 @@ int qed_hw_prepare(struct qed_dev *cdev,
                u8 __iomem *addr;
 
                /* adjust bar offset for second engine */
-               addr = cdev->regview + qed_hw_bar_size(p_hwfn, 0) / 2;
+               addr = cdev->regview + qed_hw_bar_size(p_hwfn, BAR_ID_0) / 2;
                p_regview = addr;
 
                /* adjust doorbell bar offset for second engine */
-               addr = cdev->doorbells + qed_hw_bar_size(p_hwfn, 1) / 2;
+               addr = cdev->doorbells + qed_hw_bar_size(p_hwfn, BAR_ID_1) / 2;
                p_doorbell = addr;
 
                /* prepare second hw function */
@@ -1536,223 +1534,6 @@ void qed_chain_free(struct qed_dev *cdev,
                          p_chain->p_phys_addr);
 }
 
-static void __qed_get_vport_stats(struct qed_dev *cdev,
-                                 struct qed_eth_stats  *stats)
-{
-       int i, j;
-
-       memset(stats, 0, sizeof(*stats));
-
-       for_each_hwfn(cdev, i) {
-               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
-               struct eth_mstorm_per_queue_stat mstats;
-               struct eth_ustorm_per_queue_stat ustats;
-               struct eth_pstorm_per_queue_stat pstats;
-               struct tstorm_per_port_stat tstats;
-               struct port_stats port_stats;
-               struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
-
-               if (!p_ptt) {
-                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
-                       continue;
-               }
-
-               memset(&mstats, 0, sizeof(mstats));
-               qed_memcpy_from(p_hwfn, p_ptt, &mstats,
-                               p_hwfn->storm_stats.mstats.address,
-                               p_hwfn->storm_stats.mstats.len);
-
-               memset(&ustats, 0, sizeof(ustats));
-               qed_memcpy_from(p_hwfn, p_ptt, &ustats,
-                               p_hwfn->storm_stats.ustats.address,
-                               p_hwfn->storm_stats.ustats.len);
-
-               memset(&pstats, 0, sizeof(pstats));
-               qed_memcpy_from(p_hwfn, p_ptt, &pstats,
-                               p_hwfn->storm_stats.pstats.address,
-                               p_hwfn->storm_stats.pstats.len);
-
-               memset(&tstats, 0, sizeof(tstats));
-               qed_memcpy_from(p_hwfn, p_ptt, &tstats,
-                               p_hwfn->storm_stats.tstats.address,
-                               p_hwfn->storm_stats.tstats.len);
-
-               memset(&port_stats, 0, sizeof(port_stats));
-
-               if (p_hwfn->mcp_info)
-                       qed_memcpy_from(p_hwfn, p_ptt, &port_stats,
-                                       p_hwfn->mcp_info->port_addr +
-                                       offsetof(struct public_port, stats),
-                                       sizeof(port_stats));
-               qed_ptt_release(p_hwfn, p_ptt);
-
-               stats->no_buff_discards +=
-                       HILO_64_REGPAIR(mstats.no_buff_discard);
-               stats->packet_too_big_discard +=
-                       HILO_64_REGPAIR(mstats.packet_too_big_discard);
-               stats->ttl0_discard +=
-                       HILO_64_REGPAIR(mstats.ttl0_discard);
-               stats->tpa_coalesced_pkts +=
-                       HILO_64_REGPAIR(mstats.tpa_coalesced_pkts);
-               stats->tpa_coalesced_events +=
-                       HILO_64_REGPAIR(mstats.tpa_coalesced_events);
-               stats->tpa_aborts_num +=
-                       HILO_64_REGPAIR(mstats.tpa_aborts_num);
-               stats->tpa_coalesced_bytes +=
-                       HILO_64_REGPAIR(mstats.tpa_coalesced_bytes);
-
-               stats->rx_ucast_bytes +=
-                       HILO_64_REGPAIR(ustats.rcv_ucast_bytes);
-               stats->rx_mcast_bytes +=
-                       HILO_64_REGPAIR(ustats.rcv_mcast_bytes);
-               stats->rx_bcast_bytes +=
-                       HILO_64_REGPAIR(ustats.rcv_bcast_bytes);
-               stats->rx_ucast_pkts +=
-                       HILO_64_REGPAIR(ustats.rcv_ucast_pkts);
-               stats->rx_mcast_pkts +=
-                       HILO_64_REGPAIR(ustats.rcv_mcast_pkts);
-               stats->rx_bcast_pkts +=
-                       HILO_64_REGPAIR(ustats.rcv_bcast_pkts);
-
-               stats->mftag_filter_discards +=
-                       HILO_64_REGPAIR(tstats.mftag_filter_discard);
-               stats->mac_filter_discards +=
-                       HILO_64_REGPAIR(tstats.eth_mac_filter_discard);
-
-               stats->tx_ucast_bytes +=
-                       HILO_64_REGPAIR(pstats.sent_ucast_bytes);
-               stats->tx_mcast_bytes +=
-                       HILO_64_REGPAIR(pstats.sent_mcast_bytes);
-               stats->tx_bcast_bytes +=
-                       HILO_64_REGPAIR(pstats.sent_bcast_bytes);
-               stats->tx_ucast_pkts +=
-                       HILO_64_REGPAIR(pstats.sent_ucast_pkts);
-               stats->tx_mcast_pkts +=
-                       HILO_64_REGPAIR(pstats.sent_mcast_pkts);
-               stats->tx_bcast_pkts +=
-                       HILO_64_REGPAIR(pstats.sent_bcast_pkts);
-               stats->tx_err_drop_pkts +=
-                       HILO_64_REGPAIR(pstats.error_drop_pkts);
-               stats->rx_64_byte_packets       += port_stats.pmm.r64;
-               stats->rx_127_byte_packets      += port_stats.pmm.r127;
-               stats->rx_255_byte_packets      += port_stats.pmm.r255;
-               stats->rx_511_byte_packets      += port_stats.pmm.r511;
-               stats->rx_1023_byte_packets     += port_stats.pmm.r1023;
-               stats->rx_1518_byte_packets     += port_stats.pmm.r1518;
-               stats->rx_1522_byte_packets     += port_stats.pmm.r1522;
-               stats->rx_2047_byte_packets     += port_stats.pmm.r2047;
-               stats->rx_4095_byte_packets     += port_stats.pmm.r4095;
-               stats->rx_9216_byte_packets     += port_stats.pmm.r9216;
-               stats->rx_16383_byte_packets    += port_stats.pmm.r16383;
-               stats->rx_crc_errors        += port_stats.pmm.rfcs;
-               stats->rx_mac_crtl_frames       += port_stats.pmm.rxcf;
-               stats->rx_pause_frames    += port_stats.pmm.rxpf;
-               stats->rx_pfc_frames        += port_stats.pmm.rxpp;
-               stats->rx_align_errors    += port_stats.pmm.raln;
-               stats->rx_carrier_errors        += port_stats.pmm.rfcr;
-               stats->rx_oversize_packets      += port_stats.pmm.rovr;
-               stats->rx_jabbers              += port_stats.pmm.rjbr;
-               stats->rx_undersize_packets     += port_stats.pmm.rund;
-               stats->rx_fragments          += port_stats.pmm.rfrg;
-               stats->tx_64_byte_packets       += port_stats.pmm.t64;
-               stats->tx_65_to_127_byte_packets += port_stats.pmm.t127;
-               stats->tx_128_to_255_byte_packets += port_stats.pmm.t255;
-               stats->tx_256_to_511_byte_packets  += port_stats.pmm.t511;
-               stats->tx_512_to_1023_byte_packets += port_stats.pmm.t1023;
-               stats->tx_1024_to_1518_byte_packets += port_stats.pmm.t1518;
-               stats->tx_1519_to_2047_byte_packets += port_stats.pmm.t2047;
-               stats->tx_2048_to_4095_byte_packets += port_stats.pmm.t4095;
-               stats->tx_4096_to_9216_byte_packets += port_stats.pmm.t9216;
-               stats->tx_9217_to_16383_byte_packets += port_stats.pmm.t16383;
-               stats->tx_pause_frames    += port_stats.pmm.txpf;
-               stats->tx_pfc_frames        += port_stats.pmm.txpp;
-               stats->tx_lpi_entry_count       += port_stats.pmm.tlpiec;
-               stats->tx_total_collisions      += port_stats.pmm.tncl;
-               stats->rx_mac_bytes          += port_stats.pmm.rbyte;
-               stats->rx_mac_uc_packets        += port_stats.pmm.rxuca;
-               stats->rx_mac_mc_packets        += port_stats.pmm.rxmca;
-               stats->rx_mac_bc_packets        += port_stats.pmm.rxbca;
-               stats->rx_mac_frames_ok  += port_stats.pmm.rxpok;
-               stats->tx_mac_bytes          += port_stats.pmm.tbyte;
-               stats->tx_mac_uc_packets        += port_stats.pmm.txuca;
-               stats->tx_mac_mc_packets        += port_stats.pmm.txmca;
-               stats->tx_mac_bc_packets        += port_stats.pmm.txbca;
-               stats->tx_mac_ctrl_frames       += port_stats.pmm.txcf;
-
-               for (j = 0; j < 8; j++) {
-                       stats->brb_truncates += port_stats.brb.brb_truncate[j];
-                       stats->brb_discards += port_stats.brb.brb_discard[j];
-               }
-       }
-}
-
-void qed_get_vport_stats(struct qed_dev *cdev,
-                        struct qed_eth_stats *stats)
-{
-       u32 i;
-
-       if (!cdev) {
-               memset(stats, 0, sizeof(*stats));
-               return;
-       }
-
-       __qed_get_vport_stats(cdev, stats);
-
-       if (!cdev->reset_stats)
-               return;
-
-       /* Reduce the statistics baseline */
-       for (i = 0; i < sizeof(struct qed_eth_stats) / sizeof(u64); i++)
-               ((u64 *)stats)[i] -= ((u64 *)cdev->reset_stats)[i];
-}
-
-/* zeroes V-PORT specific portion of stats (Port stats remains untouched) */
-void qed_reset_vport_stats(struct qed_dev *cdev)
-{
-       int i;
-
-       for_each_hwfn(cdev, i) {
-               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
-               struct eth_mstorm_per_queue_stat mstats;
-               struct eth_ustorm_per_queue_stat ustats;
-               struct eth_pstorm_per_queue_stat pstats;
-               struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
-
-               if (!p_ptt) {
-                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
-                       continue;
-               }
-
-               memset(&mstats, 0, sizeof(mstats));
-               qed_memcpy_to(p_hwfn, p_ptt,
-                             p_hwfn->storm_stats.mstats.address,
-                             &mstats,
-                             p_hwfn->storm_stats.mstats.len);
-
-               memset(&ustats, 0, sizeof(ustats));
-               qed_memcpy_to(p_hwfn, p_ptt,
-                             p_hwfn->storm_stats.ustats.address,
-                             &ustats,
-                             p_hwfn->storm_stats.ustats.len);
-
-               memset(&pstats, 0, sizeof(pstats));
-               qed_memcpy_to(p_hwfn, p_ptt,
-                             p_hwfn->storm_stats.pstats.address,
-                             &pstats,
-                             p_hwfn->storm_stats.pstats.len);
-
-               qed_ptt_release(p_hwfn, p_ptt);
-       }
-
-       /* PORT statistics are not necessarily reset, so we need to
-        * read and create a baseline for future statistics.
-        */
-       if (!cdev->reset_stats)
-               DP_INFO(cdev, "Reset stats not allocated\n");
-       else
-               __qed_get_vport_stats(cdev, cdev->reset_stats);
-}
-
 int qed_fw_l2_queue(struct qed_hwfn *p_hwfn,
                    u16 src_id, u16 *dst_id)
 {
index e29a3ba6c8b034039a13014113187fee15e22a96..d6c7ddf4f4d4b54bd23563ba43b125bd9cd64af7 100644 (file)
@@ -77,6 +77,15 @@ int qed_hw_init(struct qed_dev *cdev,
                bool allow_npar_tx_switch,
                const u8 *bin_fw_data);
 
+/**
+ * @brief qed_hw_timers_stop_all - stop the timers HW block
+ *
+ * @param cdev
+ *
+ * @return void
+ */
+void qed_hw_timers_stop_all(struct qed_dev *cdev);
+
 /**
  * @brief qed_hw_stop -
  *
@@ -156,8 +165,6 @@ struct qed_ptt *qed_ptt_acquire(struct qed_hwfn *p_hwfn);
  */
 void qed_ptt_release(struct qed_hwfn *p_hwfn,
                     struct qed_ptt *p_ptt);
-void qed_get_vport_stats(struct qed_dev *cdev,
-                        struct qed_eth_stats   *stats);
 void qed_reset_vport_stats(struct qed_dev *cdev);
 
 enum qed_dmae_address_type_t {
index 264e954675d1f390f1991b031e83779f6d7424b3..a368f5e71d958bd1979236e9022dae07843479e0 100644 (file)
@@ -34,6 +34,8 @@ enum common_event_opcode {
        COMMON_EVENT_RESERVED3,
        COMMON_EVENT_RESERVED4,
        COMMON_EVENT_RESERVED5,
+       COMMON_EVENT_RESERVED6,
+       COMMON_EVENT_EMPTY,
        MAX_COMMON_EVENT_OPCODE
 };
 
@@ -45,6 +47,7 @@ enum common_ramrod_cmd_id {
        COMMON_RAMROD_RESERVED,
        COMMON_RAMROD_RESERVED2,
        COMMON_RAMROD_RESERVED3,
+       COMMON_RAMROD_EMPTY,
        MAX_COMMON_RAMROD_CMD_ID
 };
 
@@ -331,6 +334,179 @@ struct xstorm_core_conn_ag_ctx {
        __le16  word15 /* word15 */;
 };
 
+struct tstorm_core_conn_ag_ctx {
+       u8      byte0 /* cdu_validation */;
+       u8      byte1 /* state */;
+       u8      flags0;
+#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
+#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
+#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK     0x1       /* bit2 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT    2
+#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK     0x1       /* bit3 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT    3
+#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK     0x1       /* bit4 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT    4
+#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK     0x1       /* bit5 */
+#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT    5
+#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* timer0cf */
+#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT     6
+       u8 flags1;
+#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* timer1cf */
+#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT     0
+#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* timer2cf */
+#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT     2
+#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK      0x3       /* timer_stop_all */
+#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT     4
+#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK      0x3       /* cf4 */
+#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT     6
+       u8 flags2;
+#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK      0x3       /* cf5 */
+#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT     0
+#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK      0x3       /* cf6 */
+#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT     2
+#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK      0x3       /* cf7 */
+#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT     4
+#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK      0x3       /* cf8 */
+#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT     6
+       u8 flags3;
+#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK      0x3       /* cf9 */
+#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT     0
+#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK     0x3       /* cf10 */
+#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT    2
+#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
+#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   4
+#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
+#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   5
+#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
+#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   6
+#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK    0x1       /* cf3en */
+#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT   7
+       u8 flags4;
+#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK    0x1       /* cf4en */
+#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT   0
+#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK    0x1       /* cf5en */
+#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT   1
+#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK    0x1       /* cf6en */
+#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT   2
+#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK    0x1       /* cf7en */
+#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT   3
+#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK    0x1       /* cf8en */
+#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT   4
+#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK    0x1       /* cf9en */
+#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT   5
+#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK   0x1       /* cf10en */
+#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT  6
+#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7
+       u8 flags5;
+#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0
+#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1
+#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2
+#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3
+#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK  0x1       /* rule5en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4
+#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK  0x1       /* rule6en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5
+#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK  0x1       /* rule7en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6
+#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK  0x1       /* rule8en */
+#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7
+       __le32  reg0 /* reg0 */;
+       __le32  reg1 /* reg1 */;
+       __le32  reg2 /* reg2 */;
+       __le32  reg3 /* reg3 */;
+       __le32  reg4 /* reg4 */;
+       __le32  reg5 /* reg5 */;
+       __le32  reg6 /* reg6 */;
+       __le32  reg7 /* reg7 */;
+       __le32  reg8 /* reg8 */;
+       u8      byte2 /* byte2 */;
+       u8      byte3 /* byte3 */;
+       __le16  word0 /* word0 */;
+       u8      byte4 /* byte4 */;
+       u8      byte5 /* byte5 */;
+       __le16  word1 /* word1 */;
+       __le16  word2 /* conn_dpi */;
+       __le16  word3 /* word3 */;
+       __le32  reg9 /* reg9 */;
+       __le32  reg10 /* reg10 */;
+};
+
+struct ustorm_core_conn_ag_ctx {
+       u8      reserved /* cdu_validation */;
+       u8      byte1 /* state */;
+       u8      flags0;
+#define USTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
+#define USTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
+#define USTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
+#define USTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
+#define USTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* timer0cf */
+#define USTORM_CORE_CONN_AG_CTX_CF0_SHIFT     2
+#define USTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* timer1cf */
+#define USTORM_CORE_CONN_AG_CTX_CF1_SHIFT     4
+#define USTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* timer2cf */
+#define USTORM_CORE_CONN_AG_CTX_CF2_SHIFT     6
+       u8 flags1;
+#define USTORM_CORE_CONN_AG_CTX_CF3_MASK      0x3       /* timer_stop_all */
+#define USTORM_CORE_CONN_AG_CTX_CF3_SHIFT     0
+#define USTORM_CORE_CONN_AG_CTX_CF4_MASK      0x3       /* cf4 */
+#define USTORM_CORE_CONN_AG_CTX_CF4_SHIFT     2
+#define USTORM_CORE_CONN_AG_CTX_CF5_MASK      0x3       /* cf5 */
+#define USTORM_CORE_CONN_AG_CTX_CF5_SHIFT     4
+#define USTORM_CORE_CONN_AG_CTX_CF6_MASK      0x3       /* cf6 */
+#define USTORM_CORE_CONN_AG_CTX_CF6_SHIFT     6
+       u8 flags2;
+#define USTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
+#define USTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   0
+#define USTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
+#define USTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   1
+#define USTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
+#define USTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   2
+#define USTORM_CORE_CONN_AG_CTX_CF3EN_MASK    0x1       /* cf3en */
+#define USTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT   3
+#define USTORM_CORE_CONN_AG_CTX_CF4EN_MASK    0x1       /* cf4en */
+#define USTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT   4
+#define USTORM_CORE_CONN_AG_CTX_CF5EN_MASK    0x1       /* cf5en */
+#define USTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT   5
+#define USTORM_CORE_CONN_AG_CTX_CF6EN_MASK    0x1       /* cf6en */
+#define USTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT   6
+#define USTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
+#define USTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7
+       u8 flags3;
+#define USTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
+#define USTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0
+#define USTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
+#define USTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1
+#define USTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
+#define USTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2
+#define USTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
+#define USTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3
+#define USTORM_CORE_CONN_AG_CTX_RULE5EN_MASK  0x1       /* rule5en */
+#define USTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4
+#define USTORM_CORE_CONN_AG_CTX_RULE6EN_MASK  0x1       /* rule6en */
+#define USTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5
+#define USTORM_CORE_CONN_AG_CTX_RULE7EN_MASK  0x1       /* rule7en */
+#define USTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6
+#define USTORM_CORE_CONN_AG_CTX_RULE8EN_MASK  0x1       /* rule8en */
+#define USTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7
+       u8      byte2 /* byte2 */;
+       u8      byte3 /* byte3 */;
+       __le16  word0 /* conn_dpi */;
+       __le16  word1 /* word1 */;
+       __le32  rx_producers /* reg0 */;
+       __le32  reg1 /* reg1 */;
+       __le32  reg2 /* reg2 */;
+       __le32  reg3 /* reg3 */;
+       __le16  word2 /* word2 */;
+       __le16  word3 /* word3 */;
+};
+
 /* The core storm context for the Mstorm */
 struct mstorm_core_conn_st_ctx {
        __le32 reserved[24];
@@ -349,8 +525,9 @@ struct core_conn_context {
        struct regpair                  pstorm_st_padding[2];
        struct xstorm_core_conn_st_ctx  xstorm_st_context;
        struct xstorm_core_conn_ag_ctx  xstorm_ag_context;
+       struct tstorm_core_conn_ag_ctx  tstorm_ag_context;
+       struct ustorm_core_conn_ag_ctx  ustorm_ag_context;
        struct mstorm_core_conn_st_ctx  mstorm_st_context;
-       struct regpair                  mstorm_st_padding[2];
        struct ustorm_core_conn_st_ctx  ustorm_st_context;
        struct regpair                  ustorm_st_padding[2] /* padding */;
 };
@@ -397,10 +574,12 @@ union event_ring_element {
 };
 
 enum personality_type {
+       BAD_PERSONALITY_TYP,
        PERSONALITY_RESERVED,
        PERSONALITY_RESERVED2,
        PERSONALITY_RDMA_AND_ETH /* Roce or Iwarp */,
        PERSONALITY_RESERVED3,
+       PERSONALITY_CORE,
        PERSONALITY_ETH /* Ethernet */,
        PERSONALITY_RESERVED4,
        MAX_PERSONALITY_TYPE
@@ -570,7 +749,7 @@ enum block_addr {
        GRCBASE_NWM             = 0x800000,
        GRCBASE_NWS             = 0x700000,
        GRCBASE_MS              = 0x6a0000,
-       GRCBASE_PHY_PCIE        = 0x618000,
+       GRCBASE_PHY_PCIE        = 0x620000,
        GRCBASE_MISC_AEU        = 0x8000,
        GRCBASE_BAR0_MAP        = 0x1c00000,
        MAX_BLOCK_ADDR
@@ -789,19 +968,19 @@ struct igu_msix_vector {
 
 enum init_modes {
        MODE_BB_A0,
-       MODE_RESERVED,
+       MODE_BB_B0,
        MODE_RESERVED2,
        MODE_ASIC,
        MODE_RESERVED3,
        MODE_RESERVED4,
        MODE_RESERVED5,
+       MODE_RESERVED6,
        MODE_SF,
        MODE_MF_SD,
        MODE_MF_SI,
        MODE_PORTS_PER_ENG_1,
        MODE_PORTS_PER_ENG_2,
        MODE_PORTS_PER_ENG_4,
-       MODE_40G,
        MODE_100G,
        MODE_EAGLE_ENG1_WORKAROUND,
        MAX_INIT_MODES
@@ -816,43 +995,6 @@ enum init_phases {
        MAX_INIT_PHASES
 };
 
-struct mstorm_core_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define MSTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
-#define MSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
-#define MSTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
-#define MSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
-#define MSTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* cf0 */
-#define MSTORM_CORE_CONN_AG_CTX_CF0_SHIFT     2
-#define MSTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* cf1 */
-#define MSTORM_CORE_CONN_AG_CTX_CF1_SHIFT     4
-#define MSTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* cf2 */
-#define MSTORM_CORE_CONN_AG_CTX_CF2_SHIFT     6
-       u8 flags1;
-#define MSTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
-#define MSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   0
-#define MSTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
-#define MSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   1
-#define MSTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
-#define MSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   2
-#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
-#define MSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3
-#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
-#define MSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4
-#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
-#define MSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5
-#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
-#define MSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6
-#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
-#define MSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7
-       __le16  word0 /* word0 */;
-       __le16  word1 /* word1 */;
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-};
-
 /* per encapsulation type enabling flags */
 struct prs_reg_encapsulation_type_en {
        u8 flags;
@@ -928,249 +1070,43 @@ struct qm_rf_opportunistic_mask {
 
 /* QM hardware structure of QM map memory */
 struct qm_rf_pq_map {
-       u32 reg;
-#define QM_RF_PQ_MAP_PQ_VALID_MASK          0x1         /* PQ active */
-#define QM_RF_PQ_MAP_PQ_VALID_SHIFT         0
-#define QM_RF_PQ_MAP_RL_ID_MASK             0xFF        /* RL ID */
-#define QM_RF_PQ_MAP_RL_ID_SHIFT            1
-#define QM_RF_PQ_MAP_VP_PQ_ID_MASK          0x1FF
-#define QM_RF_PQ_MAP_VP_PQ_ID_SHIFT         9
-#define QM_RF_PQ_MAP_VOQ_MASK               0x1F        /* VOQ */
-#define QM_RF_PQ_MAP_VOQ_SHIFT              18
-#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_MASK  0x3         /* WRR weight */
-#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_SHIFT 23
-#define QM_RF_PQ_MAP_RL_VALID_MASK          0x1         /* RL active */
-#define QM_RF_PQ_MAP_RL_VALID_SHIFT         25
-#define QM_RF_PQ_MAP_RESERVED_MASK          0x3F
-#define QM_RF_PQ_MAP_RESERVED_SHIFT         26
-};
-
-/* SDM operation gen command (generate aggregative interrupt) */
-struct sdm_op_gen {
-       __le32 command;
-#define SDM_OP_GEN_COMP_PARAM_MASK  0xFFFF      /* completion parameters 0-15 */
-#define SDM_OP_GEN_COMP_PARAM_SHIFT 0
-#define SDM_OP_GEN_COMP_TYPE_MASK   0xF         /* completion type 16-19 */
-#define SDM_OP_GEN_COMP_TYPE_SHIFT  16
-#define SDM_OP_GEN_RESERVED_MASK    0xFFF       /* reserved 20-31 */
-#define SDM_OP_GEN_RESERVED_SHIFT   20
-};
-
-struct tstorm_core_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define TSTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
-#define TSTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
-#define TSTORM_CORE_CONN_AG_CTX_BIT2_MASK     0x1       /* bit2 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT2_SHIFT    2
-#define TSTORM_CORE_CONN_AG_CTX_BIT3_MASK     0x1       /* bit3 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT3_SHIFT    3
-#define TSTORM_CORE_CONN_AG_CTX_BIT4_MASK     0x1       /* bit4 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT4_SHIFT    4
-#define TSTORM_CORE_CONN_AG_CTX_BIT5_MASK     0x1       /* bit5 */
-#define TSTORM_CORE_CONN_AG_CTX_BIT5_SHIFT    5
-#define TSTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* timer0cf */
-#define TSTORM_CORE_CONN_AG_CTX_CF0_SHIFT     6
-       u8 flags1;
-#define TSTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* timer1cf */
-#define TSTORM_CORE_CONN_AG_CTX_CF1_SHIFT     0
-#define TSTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* timer2cf */
-#define TSTORM_CORE_CONN_AG_CTX_CF2_SHIFT     2
-#define TSTORM_CORE_CONN_AG_CTX_CF3_MASK      0x3       /* timer_stop_all */
-#define TSTORM_CORE_CONN_AG_CTX_CF3_SHIFT     4
-#define TSTORM_CORE_CONN_AG_CTX_CF4_MASK      0x3       /* cf4 */
-#define TSTORM_CORE_CONN_AG_CTX_CF4_SHIFT     6
-       u8 flags2;
-#define TSTORM_CORE_CONN_AG_CTX_CF5_MASK      0x3       /* cf5 */
-#define TSTORM_CORE_CONN_AG_CTX_CF5_SHIFT     0
-#define TSTORM_CORE_CONN_AG_CTX_CF6_MASK      0x3       /* cf6 */
-#define TSTORM_CORE_CONN_AG_CTX_CF6_SHIFT     2
-#define TSTORM_CORE_CONN_AG_CTX_CF7_MASK      0x3       /* cf7 */
-#define TSTORM_CORE_CONN_AG_CTX_CF7_SHIFT     4
-#define TSTORM_CORE_CONN_AG_CTX_CF8_MASK      0x3       /* cf8 */
-#define TSTORM_CORE_CONN_AG_CTX_CF8_SHIFT     6
-       u8 flags3;
-#define TSTORM_CORE_CONN_AG_CTX_CF9_MASK      0x3       /* cf9 */
-#define TSTORM_CORE_CONN_AG_CTX_CF9_SHIFT     0
-#define TSTORM_CORE_CONN_AG_CTX_CF10_MASK     0x3       /* cf10 */
-#define TSTORM_CORE_CONN_AG_CTX_CF10_SHIFT    2
-#define TSTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
-#define TSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   4
-#define TSTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
-#define TSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   5
-#define TSTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
-#define TSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   6
-#define TSTORM_CORE_CONN_AG_CTX_CF3EN_MASK    0x1       /* cf3en */
-#define TSTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT   7
-       u8 flags4;
-#define TSTORM_CORE_CONN_AG_CTX_CF4EN_MASK    0x1       /* cf4en */
-#define TSTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT   0
-#define TSTORM_CORE_CONN_AG_CTX_CF5EN_MASK    0x1       /* cf5en */
-#define TSTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT   1
-#define TSTORM_CORE_CONN_AG_CTX_CF6EN_MASK    0x1       /* cf6en */
-#define TSTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT   2
-#define TSTORM_CORE_CONN_AG_CTX_CF7EN_MASK    0x1       /* cf7en */
-#define TSTORM_CORE_CONN_AG_CTX_CF7EN_SHIFT   3
-#define TSTORM_CORE_CONN_AG_CTX_CF8EN_MASK    0x1       /* cf8en */
-#define TSTORM_CORE_CONN_AG_CTX_CF8EN_SHIFT   4
-#define TSTORM_CORE_CONN_AG_CTX_CF9EN_MASK    0x1       /* cf9en */
-#define TSTORM_CORE_CONN_AG_CTX_CF9EN_SHIFT   5
-#define TSTORM_CORE_CONN_AG_CTX_CF10EN_MASK   0x1       /* cf10en */
-#define TSTORM_CORE_CONN_AG_CTX_CF10EN_SHIFT  6
-#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7
-       u8 flags5;
-#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0
-#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1
-#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2
-#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3
-#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_MASK  0x1       /* rule5en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4
-#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_MASK  0x1       /* rule6en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5
-#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_MASK  0x1       /* rule7en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6
-#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_MASK  0x1       /* rule8en */
-#define TSTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-       __le32  reg2 /* reg2 */;
-       __le32  reg3 /* reg3 */;
-       __le32  reg4 /* reg4 */;
-       __le32  reg5 /* reg5 */;
-       __le32  reg6 /* reg6 */;
-       __le32  reg7 /* reg7 */;
-       __le32  reg8 /* reg8 */;
-       u8      byte2 /* byte2 */;
-       u8      byte3 /* byte3 */;
-       __le16  word0 /* word0 */;
-       u8      byte4 /* byte4 */;
-       u8      byte5 /* byte5 */;
-       __le16  word1 /* word1 */;
-       __le16  word2 /* conn_dpi */;
-       __le16  word3 /* word3 */;
-       __le32  reg9 /* reg9 */;
-       __le32  reg10 /* reg10 */;
+       u32 reg;
+#define QM_RF_PQ_MAP_PQ_VALID_MASK          0x1         /* PQ active */
+#define QM_RF_PQ_MAP_PQ_VALID_SHIFT         0
+#define QM_RF_PQ_MAP_RL_ID_MASK             0xFF        /* RL ID */
+#define QM_RF_PQ_MAP_RL_ID_SHIFT            1
+#define QM_RF_PQ_MAP_VP_PQ_ID_MASK          0x1FF
+#define QM_RF_PQ_MAP_VP_PQ_ID_SHIFT         9
+#define QM_RF_PQ_MAP_VOQ_MASK               0x1F        /* VOQ */
+#define QM_RF_PQ_MAP_VOQ_SHIFT              18
+#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_MASK  0x3         /* WRR weight */
+#define QM_RF_PQ_MAP_WRR_WEIGHT_GROUP_SHIFT 23
+#define QM_RF_PQ_MAP_RL_VALID_MASK          0x1         /* RL active */
+#define QM_RF_PQ_MAP_RL_VALID_SHIFT         25
+#define QM_RF_PQ_MAP_RESERVED_MASK          0x3F
+#define QM_RF_PQ_MAP_RESERVED_SHIFT         26
 };
 
-struct ustorm_core_conn_ag_ctx {
-       u8      reserved /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define USTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
-#define USTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
-#define USTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
-#define USTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
-#define USTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* timer0cf */
-#define USTORM_CORE_CONN_AG_CTX_CF0_SHIFT     2
-#define USTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* timer1cf */
-#define USTORM_CORE_CONN_AG_CTX_CF1_SHIFT     4
-#define USTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* timer2cf */
-#define USTORM_CORE_CONN_AG_CTX_CF2_SHIFT     6
-       u8 flags1;
-#define USTORM_CORE_CONN_AG_CTX_CF3_MASK      0x3       /* timer_stop_all */
-#define USTORM_CORE_CONN_AG_CTX_CF3_SHIFT     0
-#define USTORM_CORE_CONN_AG_CTX_CF4_MASK      0x3       /* cf4 */
-#define USTORM_CORE_CONN_AG_CTX_CF4_SHIFT     2
-#define USTORM_CORE_CONN_AG_CTX_CF5_MASK      0x3       /* cf5 */
-#define USTORM_CORE_CONN_AG_CTX_CF5_SHIFT     4
-#define USTORM_CORE_CONN_AG_CTX_CF6_MASK      0x3       /* cf6 */
-#define USTORM_CORE_CONN_AG_CTX_CF6_SHIFT     6
-       u8 flags2;
-#define USTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
-#define USTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   0
-#define USTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
-#define USTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   1
-#define USTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
-#define USTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   2
-#define USTORM_CORE_CONN_AG_CTX_CF3EN_MASK    0x1       /* cf3en */
-#define USTORM_CORE_CONN_AG_CTX_CF3EN_SHIFT   3
-#define USTORM_CORE_CONN_AG_CTX_CF4EN_MASK    0x1       /* cf4en */
-#define USTORM_CORE_CONN_AG_CTX_CF4EN_SHIFT   4
-#define USTORM_CORE_CONN_AG_CTX_CF5EN_MASK    0x1       /* cf5en */
-#define USTORM_CORE_CONN_AG_CTX_CF5EN_SHIFT   5
-#define USTORM_CORE_CONN_AG_CTX_CF6EN_MASK    0x1       /* cf6en */
-#define USTORM_CORE_CONN_AG_CTX_CF6EN_SHIFT   6
-#define USTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
-#define USTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 7
-       u8 flags3;
-#define USTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
-#define USTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 0
-#define USTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
-#define USTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 1
-#define USTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
-#define USTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 2
-#define USTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
-#define USTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 3
-#define USTORM_CORE_CONN_AG_CTX_RULE5EN_MASK  0x1       /* rule5en */
-#define USTORM_CORE_CONN_AG_CTX_RULE5EN_SHIFT 4
-#define USTORM_CORE_CONN_AG_CTX_RULE6EN_MASK  0x1       /* rule6en */
-#define USTORM_CORE_CONN_AG_CTX_RULE6EN_SHIFT 5
-#define USTORM_CORE_CONN_AG_CTX_RULE7EN_MASK  0x1       /* rule7en */
-#define USTORM_CORE_CONN_AG_CTX_RULE7EN_SHIFT 6
-#define USTORM_CORE_CONN_AG_CTX_RULE8EN_MASK  0x1       /* rule8en */
-#define USTORM_CORE_CONN_AG_CTX_RULE8EN_SHIFT 7
-       u8      byte2 /* byte2 */;
-       u8      byte3 /* byte3 */;
-       __le16  word0 /* conn_dpi */;
-       __le16  word1 /* word1 */;
-       __le32  rx_producers /* reg0 */;
-       __le32  reg1 /* reg1 */;
-       __le32  reg2 /* reg2 */;
-       __le32  reg3 /* reg3 */;
-       __le16  word2 /* word2 */;
-       __le16  word3 /* word3 */;
+/* Completion params for aggregated interrupt completion */
+struct sdm_agg_int_comp_params {
+       __le16 params;
+#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_MASK      0x3F
+#define SDM_AGG_INT_COMP_PARAMS_AGG_INT_INDEX_SHIFT     0
+#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_MASK  0x1
+#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_ENABLE_SHIFT 6
+#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_MASK     0x1FF
+#define SDM_AGG_INT_COMP_PARAMS_AGG_VECTOR_BIT_SHIFT    7
 };
 
-struct ystorm_core_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define YSTORM_CORE_CONN_AG_CTX_BIT0_MASK     0x1       /* exist_in_qm0 */
-#define YSTORM_CORE_CONN_AG_CTX_BIT0_SHIFT    0
-#define YSTORM_CORE_CONN_AG_CTX_BIT1_MASK     0x1       /* exist_in_qm1 */
-#define YSTORM_CORE_CONN_AG_CTX_BIT1_SHIFT    1
-#define YSTORM_CORE_CONN_AG_CTX_CF0_MASK      0x3       /* cf0 */
-#define YSTORM_CORE_CONN_AG_CTX_CF0_SHIFT     2
-#define YSTORM_CORE_CONN_AG_CTX_CF1_MASK      0x3       /* cf1 */
-#define YSTORM_CORE_CONN_AG_CTX_CF1_SHIFT     4
-#define YSTORM_CORE_CONN_AG_CTX_CF2_MASK      0x3       /* cf2 */
-#define YSTORM_CORE_CONN_AG_CTX_CF2_SHIFT     6
-       u8 flags1;
-#define YSTORM_CORE_CONN_AG_CTX_CF0EN_MASK    0x1       /* cf0en */
-#define YSTORM_CORE_CONN_AG_CTX_CF0EN_SHIFT   0
-#define YSTORM_CORE_CONN_AG_CTX_CF1EN_MASK    0x1       /* cf1en */
-#define YSTORM_CORE_CONN_AG_CTX_CF1EN_SHIFT   1
-#define YSTORM_CORE_CONN_AG_CTX_CF2EN_MASK    0x1       /* cf2en */
-#define YSTORM_CORE_CONN_AG_CTX_CF2EN_SHIFT   2
-#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_MASK  0x1       /* rule0en */
-#define YSTORM_CORE_CONN_AG_CTX_RULE0EN_SHIFT 3
-#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_MASK  0x1       /* rule1en */
-#define YSTORM_CORE_CONN_AG_CTX_RULE1EN_SHIFT 4
-#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_MASK  0x1       /* rule2en */
-#define YSTORM_CORE_CONN_AG_CTX_RULE2EN_SHIFT 5
-#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_MASK  0x1       /* rule3en */
-#define YSTORM_CORE_CONN_AG_CTX_RULE3EN_SHIFT 6
-#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_MASK  0x1       /* rule4en */
-#define YSTORM_CORE_CONN_AG_CTX_RULE4EN_SHIFT 7
-       u8      byte2 /* byte2 */;
-       u8      byte3 /* byte3 */;
-       __le16  word0 /* word0 */;
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-       __le16  word1 /* word1 */;
-       __le16  word2 /* word2 */;
-       __le16  word3 /* word3 */;
-       __le16  word4 /* word4 */;
-       __le32  reg2 /* reg2 */;
-       __le32  reg3 /* reg3 */;
+/* SDM operation gen command (generate aggregative interrupt) */
+struct sdm_op_gen {
+       __le32 command;
+#define SDM_OP_GEN_COMP_PARAM_MASK  0xFFFF      /* completion parameters 0-15 */
+#define SDM_OP_GEN_COMP_PARAM_SHIFT 0
+#define SDM_OP_GEN_COMP_TYPE_MASK   0xF         /* completion type 16-19 */
+#define SDM_OP_GEN_COMP_TYPE_SHIFT  16
+#define SDM_OP_GEN_RESERVED_MASK    0xFFF       /* reserved 20-31 */
+#define SDM_OP_GEN_RESERVED_SHIFT   20
 };
 
 /*********************************** Init ************************************/
@@ -1274,13 +1210,6 @@ enum chip_ids {
        MAX_CHIP_IDS
 };
 
-enum idle_chk_severity_types {
-       IDLE_CHK_SEVERITY_ERROR /* idle check failure should cause an error */,
-       IDLE_CHK_SEVERITY_ERROR_NO_TRAFFIC,
-       IDLE_CHK_SEVERITY_WARNING,
-       MAX_IDLE_CHK_SEVERITY_TYPES
-};
-
 struct init_array_raw_hdr {
        __le32 data;
 #define INIT_ARRAY_RAW_HDR_TYPE_MASK    0xF
@@ -1340,14 +1269,6 @@ struct init_callback_op {
        __le16  block_id /* Blocks ID */;
 };
 
-/* init comparison types */
-enum init_comparison_types {
-       INIT_COMPARISON_EQ /* init value is included in the init command */,
-       INIT_COMPARISON_OR /* init value is all zeros */,
-       INIT_COMPARISON_AND /* init value is an array of values */,
-       MAX_INIT_COMPARISON_TYPES
-};
-
 /* init operation: delay */
 struct init_delay_op {
        __le32  op_data;
@@ -1444,12 +1365,10 @@ struct init_read_op {
        __le32 op_data;
 #define INIT_READ_OP_OP_MASK         0xF
 #define INIT_READ_OP_OP_SHIFT        0
-#define INIT_READ_OP_POLL_COMP_MASK  0x7
-#define INIT_READ_OP_POLL_COMP_SHIFT 4
+#define INIT_READ_OP_POLL_TYPE_MASK  0xF
+#define INIT_READ_OP_POLL_TYPE_SHIFT 4
 #define INIT_READ_OP_RESERVED_MASK   0x1
-#define INIT_READ_OP_RESERVED_SHIFT  7
-#define INIT_READ_OP_POLL_MASK       0x1
-#define INIT_READ_OP_POLL_SHIFT      8
+#define INIT_READ_OP_RESERVED_SHIFT  8
 #define INIT_READ_OP_ADDRESS_MASK    0x7FFFFF
 #define INIT_READ_OP_ADDRESS_SHIFT   9
        __le32 expected_val;
@@ -1477,6 +1396,14 @@ enum init_op_types {
        MAX_INIT_OP_TYPES
 };
 
+enum init_poll_types {
+       INIT_POLL_NONE /* No polling */,
+       INIT_POLL_EQ /* init value is included in the init command */,
+       INIT_POLL_OR /* init value is all zeros */,
+       INIT_POLL_AND /* init value is an array of values */,
+       MAX_INIT_POLL_TYPES
+};
+
 /* init source types */
 enum init_source_types {
        INIT_SRC_INLINE /* init value is included in the init command */,
@@ -1677,175 +1604,213 @@ bool qed_send_qm_stop_cmd(struct qed_hwfn     *p_hwfn,
                          u16                   num_pqs);
 
 /* Ystorm flow control mode. Use enum fw_flow_ctrl_mode */
-#define YSTORM_FLOW_CONTROL_MODE_OFFSET                        (IRO[0].base)
-#define YSTORM_FLOW_CONTROL_MODE_SIZE                  (IRO[0].size)
+#define YSTORM_FLOW_CONTROL_MODE_OFFSET  (IRO[0].base)
+#define YSTORM_FLOW_CONTROL_MODE_SIZE    (IRO[0].size)
 /* Tstorm port statistics */
-#define TSTORM_PORT_STAT_OFFSET(port_id)               (IRO[1].base + \
-                                                        ((port_id) * \
-                                                         IRO[1].m1))
-#define TSTORM_PORT_STAT_SIZE                          (IRO[1].size)
+#define TSTORM_PORT_STAT_OFFSET(port_id) (IRO[1].base + ((port_id) * IRO[1].m1))
+#define TSTORM_PORT_STAT_SIZE            (IRO[1].size)
+/* Tstorm ll2 port statistics */
+#define TSTORM_LL2_PORT_STAT_OFFSET(port_id) \
+                               (IRO[2].base + ((port_id) * IRO[2].m1))
+#define TSTORM_LL2_PORT_STAT_SIZE            (IRO[2].size)
 /* Ustorm VF-PF Channel ready flag */
-#define USTORM_VF_PF_CHANNEL_READY_OFFSET(vf_id)       (IRO[2].base +  \
-                                                        ((vf_id) *     \
-                                                         IRO[2].m1))
-#define USTORM_VF_PF_CHANNEL_READY_SIZE                        (IRO[2].size)
+#define USTORM_VF_PF_CHANNEL_READY_OFFSET(vf_id) \
+                               (IRO[3].base +  ((vf_id) * IRO[3].m1))
+#define USTORM_VF_PF_CHANNEL_READY_SIZE          (IRO[3].size)
 /* Ustorm Final flr cleanup ack */
-#define USTORM_FLR_FINAL_ACK_OFFSET                    (IRO[3].base)
-#define USTORM_FLR_FINAL_ACK_SIZE                      (IRO[3].size)
+#define USTORM_FLR_FINAL_ACK_OFFSET(pf_id) (IRO[4].base + ((pf_id) * IRO[4].m1))
+#define USTORM_FLR_FINAL_ACK_SIZE          (IRO[4].size)
 /* Ustorm Event ring consumer */
-#define USTORM_EQE_CONS_OFFSET(pf_id)                  (IRO[4].base +  \
-                                                        ((pf_id) *     \
-                                                         IRO[4].m1))
-#define USTORM_EQE_CONS_SIZE                           (IRO[4].size)
-/* Ustorm Completion ring consumer */
-#define USTORM_CQ_CONS_OFFSET(global_queue_id)         (IRO[5].base +  \
-                                                        ((global_queue_id) * \
-                                                         IRO[5].m1))
-#define USTORM_CQ_CONS_SIZE                            (IRO[5].size)
+#define USTORM_EQE_CONS_OFFSET(pf_id)    (IRO[5].base +        ((pf_id) * IRO[5].m1))
+#define USTORM_EQE_CONS_SIZE             (IRO[5].size)
+/* Ustorm Common Queue ring consumer */
+#define USTORM_COMMON_QUEUE_CONS_OFFSET(global_queue_id) \
+                       (IRO[6].base + ((global_queue_id) * IRO[6].m1))
+#define USTORM_COMMON_QUEUE_CONS_SIZE    (IRO[6].size)
 /* Xstorm Integration Test Data */
-#define XSTORM_INTEG_TEST_DATA_OFFSET                  (IRO[6].base)
-#define XSTORM_INTEG_TEST_DATA_SIZE                    (IRO[6].size)
+#define XSTORM_INTEG_TEST_DATA_OFFSET    (IRO[7].base)
+#define XSTORM_INTEG_TEST_DATA_SIZE      (IRO[7].size)
 /* Ystorm Integration Test Data */
-#define YSTORM_INTEG_TEST_DATA_OFFSET                  (IRO[7].base)
-#define YSTORM_INTEG_TEST_DATA_SIZE                    (IRO[7].size)
+#define YSTORM_INTEG_TEST_DATA_OFFSET    (IRO[8].base)
+#define YSTORM_INTEG_TEST_DATA_SIZE      (IRO[8].size)
 /* Pstorm Integration Test Data */
-#define PSTORM_INTEG_TEST_DATA_OFFSET                  (IRO[8].base)
-#define PSTORM_INTEG_TEST_DATA_SIZE                    (IRO[8].size)
+#define PSTORM_INTEG_TEST_DATA_OFFSET    (IRO[9].base)
+#define PSTORM_INTEG_TEST_DATA_SIZE      (IRO[9].size)
 /* Tstorm Integration Test Data */
-#define TSTORM_INTEG_TEST_DATA_OFFSET                  (IRO[9].base)
-#define TSTORM_INTEG_TEST_DATA_SIZE                    (IRO[9].size)
+#define TSTORM_INTEG_TEST_DATA_OFFSET    (IRO[10].base)
+#define TSTORM_INTEG_TEST_DATA_SIZE      (IRO[10].size)
 /* Mstorm Integration Test Data */
-#define MSTORM_INTEG_TEST_DATA_OFFSET                  (IRO[10].base)
-#define MSTORM_INTEG_TEST_DATA_SIZE                    (IRO[10].size)
+#define MSTORM_INTEG_TEST_DATA_OFFSET    (IRO[11].base)
+#define MSTORM_INTEG_TEST_DATA_SIZE      (IRO[11].size)
 /* Ustorm Integration Test Data */
-#define USTORM_INTEG_TEST_DATA_OFFSET                  (IRO[11].base)
-#define USTORM_INTEG_TEST_DATA_SIZE                    (IRO[11].size)
+#define USTORM_INTEG_TEST_DATA_OFFSET    (IRO[12].base)
+#define USTORM_INTEG_TEST_DATA_SIZE      (IRO[12].size)
 /* Tstorm producers */
-#define TSTORM_LL2_RX_PRODS_OFFSET(core_rx_queue_id)   (IRO[12].base + \
-                                                        ((core_rx_queue_id) * \
-                                                         IRO[12].m1))
-#define TSTORM_LL2_RX_PRODS_SIZE                       (IRO[12].size)
-/* Tstorm LiteL2 queue statistics */
-#define CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(core_rx_q_id) (IRO[13].base + \
-                                                            ((core_rx_q_id) * \
-                                                             IRO[13].m1))
-#define CORE_LL2_TSTORM_PER_QUEUE_STAT_SIZE            (IRO[13].size)
+#define TSTORM_LL2_RX_PRODS_OFFSET(core_rx_queue_id) \
+                       (IRO[13].base + ((core_rx_queue_id) * IRO[13].m1))
+#define TSTORM_LL2_RX_PRODS_SIZE         (IRO[13].size)
+/* Tstorm LightL2 queue statistics */
+#define CORE_LL2_TSTORM_PER_QUEUE_STAT_OFFSET(core_rx_queue_id) \
+                       (IRO[14].base + ((core_rx_queue_id) * IRO[14].m1))
+#define CORE_LL2_TSTORM_PER_QUEUE_STAT_SIZE    (IRO[14].size)
 /* Ustorm LiteL2 queue statistics */
-#define CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(core_rx_q_id) (IRO[14].base + \
-                                                            ((core_rx_q_id) * \
-                                                             IRO[14].m1))
-#define CORE_LL2_USTORM_PER_QUEUE_STAT_SIZE            (IRO[14].size)
+#define CORE_LL2_USTORM_PER_QUEUE_STAT_OFFSET(core_rx_queue_id) \
+                       (IRO[15].base + ((core_rx_queue_id) * IRO[15].m1))
+#define CORE_LL2_USTORM_PER_QUEUE_STAT_SIZE    (IRO[15].size)
 /* Pstorm LiteL2 queue statistics */
-#define CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(core_txst_id) (IRO[15].base + \
-                                                            ((core_txst_id) * \
-                                                             IRO[15].m1))
-#define CORE_LL2_PSTORM_PER_QUEUE_STAT_SIZE            (IRO[15].size)
+#define CORE_LL2_PSTORM_PER_QUEUE_STAT_OFFSET(core_tx_stats_id) \
+                       (IRO[16].base + ((core_tx_stats_id) * IRO[16].m1))
+#define CORE_LL2_PSTORM_PER_QUEUE_STAT_SIZE    (IRO[16].size)
 /* Mstorm queue statistics */
-#define MSTORM_QUEUE_STAT_OFFSET(stat_counter_id) (IRO[16].base + \
-                                                  ((stat_counter_id) * \
-                                                   IRO[16].m1))
-#define MSTORM_QUEUE_STAT_SIZE                         (IRO[16].size)
+#define MSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \
+                       (IRO[17].base + ((stat_counter_id) * IRO[17].m1))
+#define MSTORM_QUEUE_STAT_SIZE                 (IRO[17].size)
 /* Mstorm producers */
-#define MSTORM_PRODS_OFFSET(queue_id)                  (IRO[17].base + \
-                                                        ((queue_id) *  \
-                                                         IRO[17].m1))
-#define MSTORM_PRODS_SIZE                              (IRO[17].size)
+#define MSTORM_PRODS_OFFSET(queue_id) (IRO[18].base + ((queue_id) * IRO[18].m1))
+#define MSTORM_PRODS_SIZE             (IRO[18].size)
 /* TPA agregation timeout in us resolution (on ASIC) */
-#define MSTORM_TPA_TIMEOUT_US_OFFSET                   (IRO[18].base)
-#define MSTORM_TPA_TIMEOUT_US_SIZE                     (IRO[18].size)
+#define MSTORM_TPA_TIMEOUT_US_OFFSET  (IRO[19].base)
+#define MSTORM_TPA_TIMEOUT_US_SIZE    (IRO[19].size)
 /* Ustorm queue statistics */
-#define USTORM_QUEUE_STAT_OFFSET(stat_counter_id)      (IRO[19].base + \
-                                                       ((stat_counter_id) * \
-                                                        IRO[19].m1))
-#define USTORM_QUEUE_STAT_SIZE                         (IRO[19].size)
+#define USTORM_QUEUE_STAT_OFFSET(stat_counter_id) \
+                       (IRO[20].base + ((stat_counter_id) * IRO[20].m1))
+#define USTORM_QUEUE_STAT_SIZE        (IRO[20].size)
 /* Ustorm queue zone */
-#define USTORM_ETH_QUEUE_ZONE_OFFSET(queue_id)         (IRO[20].base + \
-                                                        ((queue_id) *  \
-                                                         IRO[20].m1))
-#define USTORM_ETH_QUEUE_ZONE_SIZE                     (IRO[20].size)
+#define USTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \
+                       (IRO[21].base + ((queue_id) * IRO[21].m1))
+#define USTORM_ETH_QUEUE_ZONE_SIZE    (IRO[21].size)
 /* Pstorm queue statistics */
-#define PSTORM_QUEUE_STAT_OFFSET(stat_counter_id)      (IRO[21].base + \
-                                                        ((stat_counter_id) * \
-                                                         IRO[21].m1))
-#define PSTORM_QUEUE_STAT_SIZE                         (IRO[21].size)
+#define PSTORM_QUEUE_STAT_OFFSET(stat_counter_id) \
+               (IRO[22].base + ((stat_counter_id) * IRO[22].m1))
+#define PSTORM_QUEUE_STAT_SIZE        (IRO[22].size)
 /* Tstorm last parser message */
-#define TSTORM_ETH_PRS_INPUT_OFFSET(pf_id)             (IRO[22].base + \
-                                                        ((pf_id) *     \
-                                                         IRO[22].m1))
-#define TSTORM_ETH_PRS_INPUT_SIZE                      (IRO[22].size)
+#define TSTORM_ETH_PRS_INPUT_OFFSET  (IRO[23].base)
+#define TSTORM_ETH_PRS_INPUT_SIZE    (IRO[23].size)
+/* Tstorm Eth limit Rx rate */
+#define ETH_RX_RATE_LIMIT_OFFSET(pf_id) (IRO[24].base +        ((pf_id) * IRO[24].m1))
+#define ETH_RX_RATE_LIMIT_SIZE       (IRO[24].size)
 /* Ystorm queue zone */
-#define YSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id)         (IRO[23].base + \
-                                                        ((queue_id) *  \
-                                                         IRO[23].m1))
-#define YSTORM_ETH_QUEUE_ZONE_SIZE                     (IRO[23].size)
+#define YSTORM_ETH_QUEUE_ZONE_OFFSET(queue_id) \
+                       (IRO[25].base + ((queue_id) * IRO[25].m1))
+#define YSTORM_ETH_QUEUE_ZONE_SIZE   (IRO[25].size)
 /* Ystorm cqe producer */
-#define YSTORM_TOE_CQ_PROD_OFFSET(rss_id)              (IRO[24].base + \
-                                                        ((rss_id) *    \
-                                                         IRO[24].m1))
-#define YSTORM_TOE_CQ_PROD_SIZE                                (IRO[24].size)
+#define YSTORM_TOE_CQ_PROD_OFFSET(rss_id) \
+                       (IRO[26].base + ((rss_id) * IRO[26].m1))
+#define YSTORM_TOE_CQ_PROD_SIZE      (IRO[26].size)
 /* Ustorm cqe producer */
-#define USTORM_TOE_CQ_PROD_OFFSET(rss_id)              (IRO[25].base + \
-                                                        ((rss_id) *    \
-                                                         IRO[25].m1))
-#define USTORM_TOE_CQ_PROD_SIZE                                (IRO[25].size)
+#define USTORM_TOE_CQ_PROD_OFFSET(rss_id) \
+                       (IRO[27].base + ((rss_id) * IRO[27].m1))
+#define USTORM_TOE_CQ_PROD_SIZE      (IRO[27].size)
 /* Ustorm grq producer */
-#define USTORM_TOE_GRQ_PROD_OFFSET(pf_id)              (IRO[26].base + \
-                                                        ((pf_id) *     \
-                                                         IRO[26].m1))
-#define USTORM_TOE_GRQ_PROD_SIZE                       (IRO[26].size)
+#define USTORM_TOE_GRQ_PROD_OFFSET(pf_id) \
+                       (IRO[28].base + ((pf_id) * IRO[28].m1))
+#define USTORM_TOE_GRQ_PROD_SIZE     (IRO[28].size)
 /* Tstorm cmdq-cons of given command queue-id */
-#define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id)    (IRO[27].base + \
-                                                        ((cmdq_queue_id) * \
-                                                         IRO[27].m1))
-#define TSTORM_SCSI_CMDQ_CONS_SIZE                     (IRO[27].size)
+#define TSTORM_SCSI_CMDQ_CONS_OFFSET(cmdq_queue_id) \
+                       (IRO[29].base + ((cmdq_queue_id) * IRO[29].m1))
+#define TSTORM_SCSI_CMDQ_CONS_SIZE   (IRO[29].size)
 /* Mstorm rq-cons of given queue-id */
-#define MSTORM_SCSI_RQ_CONS_OFFSET(rq_queue_id)                (IRO[28].base + \
-                                                        ((rq_queue_id) * \
-                                                         IRO[28].m1))
-#define MSTORM_SCSI_RQ_CONS_SIZE                       (IRO[28].size)
+#define MSTORM_SCSI_RQ_CONS_OFFSET(rq_queue_id) \
+               (IRO[30].base + ((rq_queue_id) * IRO[30].m1))
+#define MSTORM_SCSI_RQ_CONS_SIZE     (IRO[30].size)
+/* Mstorm bdq-external-producer of given BDQ function ID, BDqueue-id */
+#define MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \
+       (IRO[31].base + ((func_id) * IRO[31].m1) + ((bdq_id) * IRO[31].m2))
+#define MSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[31].size)
+/* Tstorm (reflects M-Storm) bdq-external-producer of given fn ID, BDqueue-id */
+#define TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(func_id, bdq_id) \
+       (IRO[32].base + ((func_id) * IRO[32].m1) + ((bdq_id) * IRO[32].m2))
+#define TSTORM_SCSI_BDQ_EXT_PROD_SIZE (IRO[32].size)
+/* Tstorm iSCSI RX stats */
+#define TSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
+                               (IRO[33].base + ((pf_id) * IRO[33].m1))
+#define TSTORM_ISCSI_RX_STATS_SIZE    (IRO[33].size)
+/* Mstorm iSCSI RX stats */
+#define MSTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
+                               (IRO[34].base + ((pf_id) * IRO[34].m1))
+#define MSTORM_ISCSI_RX_STATS_SIZE    (IRO[34].size)
+/* Ustorm iSCSI RX stats */
+#define USTORM_ISCSI_RX_STATS_OFFSET(pf_id) \
+                               (IRO[35].base + ((pf_id) * IRO[35].m1))
+#define USTORM_ISCSI_RX_STATS_SIZE    (IRO[35].size)
+/* Xstorm iSCSI TX stats */
+#define XSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
+                               (IRO[36].base + ((pf_id) * IRO[36].m1))
+#define XSTORM_ISCSI_TX_STATS_SIZE    (IRO[36].size)
+/* Ystorm iSCSI TX stats */
+#define YSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
+                               (IRO[37].base + ((pf_id) * IRO[37].m1))
+#define YSTORM_ISCSI_TX_STATS_SIZE    (IRO[37].size)
+/* Pstorm iSCSI TX stats */
+#define PSTORM_ISCSI_TX_STATS_OFFSET(pf_id) \
+                               (IRO[38].base + ((pf_id) * IRO[38].m1))
+#define PSTORM_ISCSI_TX_STATS_SIZE    (IRO[38].size)
+/* Tstorm FCoE RX stats */
+#define TSTORM_FCOE_RX_STATS_OFFSET(pf_id) \
+                               (IRO[39].base + ((pf_id) * IRO[39].m1))
+#define TSTORM_FCOE_RX_STATS_SIZE      (IRO[39].size)
+/* Mstorm FCoE RX stats */
+#define MSTORM_FCOE_RX_STATS_OFFSET(pf_id) \
+                               (IRO[40].base + ((pf_id) * IRO[40].m1))
+#define MSTORM_FCOE_RX_STATS_SIZE      (IRO[40].size)
+/* Pstorm FCoE TX stats */
+#define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \
+                               (IRO[41].base + ((pf_id) * IRO[41].m1))
+#define PSTORM_FCOE_TX_STATS_SIZE      (IRO[41].size)
 /* Pstorm RoCE statistics */
-#define PSTORM_ROCE_STAT_OFFSET(stat_counter_id)       (IRO[29].base + \
-                                                        ((stat_counter_id) * \
-                                                         IRO[29].m1))
-#define PSTORM_ROCE_STAT_SIZE                          (IRO[29].size)
+#define PSTORM_ROCE_STAT_OFFSET(stat_counter_id) \
+                       (IRO[42].base + ((stat_counter_id) * IRO[42].m1))
+#define PSTORM_ROCE_STAT_SIZE          (IRO[42].size)
 /* Tstorm RoCE statistics */
-#define TSTORM_ROCE_STAT_OFFSET(stat_counter_id)       (IRO[30].base + \
-                                                        ((stat_counter_id) * \
-                                                         IRO[30].m1))
-#define TSTORM_ROCE_STAT_SIZE                          (IRO[30].size)
-
-static const struct iro iro_arr[31] = {
-       { 0x10,   0x0,   0x0,   0x0,   0x8     },
-       { 0x4448, 0x60,  0x0,   0x0,   0x60    },
-       { 0x498,  0x8,   0x0,   0x0,   0x4     },
-       { 0x494,  0x0,   0x0,   0x0,   0x4     },
-       { 0x10,   0x8,   0x0,   0x0,   0x2     },
-       { 0x90,   0x8,   0x0,   0x0,   0x2     },
-       { 0x4540, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x39e0, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x2598, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x4350, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x52d0, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x7a48, 0x0,   0x0,   0x0,   0xf8    },
-       { 0x100,  0x8,   0x0,   0x0,   0x8     },
-       { 0x5808, 0x10,  0x0,   0x0,   0x10    },
-       { 0xb100, 0x30,  0x0,   0x0,   0x30    },
-       { 0x95c0, 0x30,  0x0,   0x0,   0x30    },
-       { 0x54f8, 0x40,  0x0,   0x0,   0x40    },
-       { 0x200,  0x10,  0x0,   0x0,   0x8     },
-       { 0x9e70, 0x0,   0x0,   0x0,   0x4     },
-       { 0x7ca0, 0x40,  0x0,   0x0,   0x30    },
-       { 0xd00,  0x8,   0x0,   0x0,   0x8     },
-       { 0x2790, 0x80,  0x0,   0x0,   0x38    },
-       { 0xa520, 0xf0,  0x0,   0x0,   0xf0    },
-       { 0x80,   0x8,   0x0,   0x0,   0x8     },
-       { 0xac0,  0x8,   0x0,   0x0,   0x8     },
-       { 0x2580, 0x8,   0x0,   0x0,   0x8     },
-       { 0x2500, 0x8,   0x0,   0x0,   0x8     },
-       { 0x440,  0x8,   0x0,   0x0,   0x2     },
-       { 0x1800, 0x8,   0x0,   0x0,   0x2     },
-       { 0x27c8, 0x80,  0x0,   0x0,   0x10    },
-       { 0x4710, 0x10,  0x0,   0x0,   0x10    },
+#define TSTORM_ROCE_STAT_OFFSET(stat_counter_id) \
+                       (IRO[43].base + ((stat_counter_id) * IRO[43].m1))
+#define TSTORM_ROCE_STAT_SIZE          (IRO[43].size)
+
+static const struct iro iro_arr[44] = {
+       { 0x10,    0x0,    0x0,    0x0,    0x8      },
+       { 0x47c8,  0x60,   0x0,    0x0,    0x60     },
+       { 0x5e30,  0x20,   0x0,    0x0,    0x20     },
+       { 0x510,   0x8,    0x0,    0x0,    0x4      },
+       { 0x490,   0x8,    0x0,    0x0,    0x4      },
+       { 0x10,    0x8,    0x0,    0x0,    0x2      },
+       { 0x90,    0x8,    0x0,    0x0,    0x2      },
+       { 0x4940,  0x0,    0x0,    0x0,    0x78     },
+       { 0x3de0,  0x0,    0x0,    0x0,    0x78     },
+       { 0x2998,  0x0,    0x0,    0x0,    0x78     },
+       { 0x4750,  0x0,    0x0,    0x0,    0x78     },
+       { 0x56d0,  0x0,    0x0,    0x0,    0x78     },
+       { 0x7e50,  0x0,    0x0,    0x0,    0x78     },
+       { 0x100,   0x8,    0x0,    0x0,    0x8      },
+       { 0x5c10,  0x10,   0x0,    0x0,    0x10     },
+       { 0xb508,  0x30,   0x0,    0x0,    0x30     },
+       { 0x95c0,  0x30,   0x0,    0x0,    0x30     },
+       { 0x58a0,  0x40,   0x0,    0x0,    0x40     },
+       { 0x200,   0x10,   0x0,    0x0,    0x8      },
+       { 0xa230,  0x0,    0x0,    0x0,    0x4      },
+       { 0x8058,  0x40,   0x0,    0x0,    0x30     },
+       { 0xd00,   0x8,    0x0,    0x0,    0x8      },
+       { 0x2b30,  0x80,   0x0,    0x0,    0x38     },
+       { 0xa808,  0x0,    0x0,    0x0,    0xf0     },
+       { 0xa8f8,  0x8,    0x0,    0x0,    0x8      },
+       { 0x80,    0x8,    0x0,    0x0,    0x8      },
+       { 0xac0,   0x8,    0x0,    0x0,    0x8      },
+       { 0x2580,  0x8,    0x0,    0x0,    0x8      },
+       { 0x2500,  0x8,    0x0,    0x0,    0x8      },
+       { 0x440,   0x8,    0x0,    0x0,    0x2      },
+       { 0x1800,  0x8,    0x0,    0x0,    0x2      },
+       { 0x1a00,  0x10,   0x8,    0x0,    0x2      },
+       { 0x640,   0x10,   0x8,    0x0,    0x2      },
+       { 0xd9b8,  0x38,   0x0,    0x0,    0x24     },
+       { 0x11048, 0x10,   0x0,    0x0,    0x8      },
+       { 0x11678, 0x38,   0x0,    0x0,    0x18     },
+       { 0xaec0,  0x30,   0x0,    0x0,    0x10     },
+       { 0x8700,  0x28,   0x0,    0x0,    0x18     },
+       { 0xec00,  0x10,   0x0,    0x0,    0x10     },
+       { 0xde38,  0x40,   0x0,    0x0,    0x30     },
+       { 0x121a8, 0x38,   0x0,    0x0,    0x8      },
+       { 0xf068,  0x20,   0x0,    0x0,    0x20     },
+       { 0x2b68,  0x80,   0x0,    0x0,    0x10     },
+       { 0x4ab8,  0x10,   0x0,    0x0,    0x10     },
 };
 
 /* Runtime array offsets */
@@ -1866,426 +1831,427 @@ static const struct iro iro_arr[31] = {
 #define DORQ_REG_VF_MAX_ICID_6_RT_OFFSET                                14
 #define DORQ_REG_VF_MAX_ICID_7_RT_OFFSET                                15
 #define DORQ_REG_PF_WAKE_ALL_RT_OFFSET                                  16
-#define IGU_REG_PF_CONFIGURATION_RT_OFFSET                              17
-#define IGU_REG_VF_CONFIGURATION_RT_OFFSET                              18
-#define IGU_REG_ATTN_MSG_ADDR_L_RT_OFFSET                               19
-#define IGU_REG_ATTN_MSG_ADDR_H_RT_OFFSET                               20
-#define IGU_REG_LEADING_EDGE_LATCH_RT_OFFSET                            21
-#define IGU_REG_TRAILING_EDGE_LATCH_RT_OFFSET                           22
-#define CAU_REG_CQE_AGG_UNIT_SIZE_RT_OFFSET                             23
-#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET                                 760
+#define DORQ_REG_TAG1_ETHERTYPE_RT_OFFSET                               17
+#define IGU_REG_PF_CONFIGURATION_RT_OFFSET                              18
+#define IGU_REG_VF_CONFIGURATION_RT_OFFSET                              19
+#define IGU_REG_ATTN_MSG_ADDR_L_RT_OFFSET                               20
+#define IGU_REG_ATTN_MSG_ADDR_H_RT_OFFSET                               21
+#define IGU_REG_LEADING_EDGE_LATCH_RT_OFFSET                            22
+#define IGU_REG_TRAILING_EDGE_LATCH_RT_OFFSET                           23
+#define CAU_REG_CQE_AGG_UNIT_SIZE_RT_OFFSET                             24
+#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET                                 761
 #define CAU_REG_SB_VAR_MEMORY_RT_SIZE                                   736
-#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET                                 760
+#define CAU_REG_SB_VAR_MEMORY_RT_OFFSET                                 761
 #define CAU_REG_SB_VAR_MEMORY_RT_SIZE                                   736
-#define CAU_REG_SB_ADDR_MEMORY_RT_OFFSET                                1496
+#define CAU_REG_SB_ADDR_MEMORY_RT_OFFSET                                1497
 #define CAU_REG_SB_ADDR_MEMORY_RT_SIZE                                  736
-#define CAU_REG_PI_MEMORY_RT_OFFSET                                     2232
+#define CAU_REG_PI_MEMORY_RT_OFFSET                                     2233
 #define CAU_REG_PI_MEMORY_RT_SIZE                                       4416
-#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET                    6648
-#define PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET                      6649
-#define PRS_REG_TASK_ID_MAX_INITIATOR_VF_RT_OFFSET                      6650
-#define PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET                         6651
-#define PRS_REG_TASK_ID_MAX_TARGET_VF_RT_OFFSET                         6652
-#define PRS_REG_SEARCH_TCP_RT_OFFSET                                    6653
-#define PRS_REG_SEARCH_FCOE_RT_OFFSET                                   6654
-#define PRS_REG_SEARCH_ROCE_RT_OFFSET                                   6655
-#define PRS_REG_ROCE_DEST_QP_MAX_VF_RT_OFFSET                           6656
-#define PRS_REG_ROCE_DEST_QP_MAX_PF_RT_OFFSET                           6657
-#define PRS_REG_SEARCH_OPENFLOW_RT_OFFSET                               6658
-#define PRS_REG_SEARCH_NON_IP_AS_OPENFLOW_RT_OFFSET                     6659
-#define PRS_REG_OPENFLOW_SUPPORT_ONLY_KNOWN_OVER_IP_RT_OFFSET           6660
-#define PRS_REG_OPENFLOW_SEARCH_KEY_MASK_RT_OFFSET                      6661
-#define PRS_REG_LIGHT_L2_ETHERTYPE_EN_RT_OFFSET                         6662
-#define SRC_REG_FIRSTFREE_RT_OFFSET                                     6663
+#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET                    6649
+#define PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET                      6650
+#define PRS_REG_TASK_ID_MAX_INITIATOR_VF_RT_OFFSET                      6651
+#define PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET                         6652
+#define PRS_REG_TASK_ID_MAX_TARGET_VF_RT_OFFSET                         6653
+#define PRS_REG_SEARCH_TCP_RT_OFFSET                                    6654
+#define PRS_REG_SEARCH_FCOE_RT_OFFSET                                   6655
+#define PRS_REG_SEARCH_ROCE_RT_OFFSET                                   6656
+#define PRS_REG_ROCE_DEST_QP_MAX_VF_RT_OFFSET                           6657
+#define PRS_REG_ROCE_DEST_QP_MAX_PF_RT_OFFSET                           6658
+#define PRS_REG_SEARCH_OPENFLOW_RT_OFFSET                               6659
+#define PRS_REG_SEARCH_NON_IP_AS_OPENFLOW_RT_OFFSET                     6660
+#define PRS_REG_OPENFLOW_SUPPORT_ONLY_KNOWN_OVER_IP_RT_OFFSET           6661
+#define PRS_REG_OPENFLOW_SEARCH_KEY_MASK_RT_OFFSET                      6662
+#define PRS_REG_TAG_ETHERTYPE_0_RT_OFFSET                               6663
+#define PRS_REG_LIGHT_L2_ETHERTYPE_EN_RT_OFFSET                         6664
+#define SRC_REG_FIRSTFREE_RT_OFFSET                                     6665
 #define SRC_REG_FIRSTFREE_RT_SIZE                                       2
-#define SRC_REG_LASTFREE_RT_OFFSET                                      6665
+#define SRC_REG_LASTFREE_RT_OFFSET                                      6667
 #define SRC_REG_LASTFREE_RT_SIZE                                        2
-#define SRC_REG_COUNTFREE_RT_OFFSET                                     6667
-#define SRC_REG_NUMBER_HASH_BITS_RT_OFFSET                              6668
-#define PSWRQ2_REG_CDUT_P_SIZE_RT_OFFSET                                6669
-#define PSWRQ2_REG_CDUC_P_SIZE_RT_OFFSET                                6670
-#define PSWRQ2_REG_TM_P_SIZE_RT_OFFSET                                  6671
-#define PSWRQ2_REG_QM_P_SIZE_RT_OFFSET                                  6672
-#define PSWRQ2_REG_SRC_P_SIZE_RT_OFFSET                                 6673
-#define PSWRQ2_REG_TM_FIRST_ILT_RT_OFFSET                               6674
-#define PSWRQ2_REG_TM_LAST_ILT_RT_OFFSET                                6675
-#define PSWRQ2_REG_QM_FIRST_ILT_RT_OFFSET                               6676
-#define PSWRQ2_REG_QM_LAST_ILT_RT_OFFSET                                6677
-#define PSWRQ2_REG_SRC_FIRST_ILT_RT_OFFSET                              6678
-#define PSWRQ2_REG_SRC_LAST_ILT_RT_OFFSET                               6679
-#define PSWRQ2_REG_CDUC_FIRST_ILT_RT_OFFSET                             6680
-#define PSWRQ2_REG_CDUC_LAST_ILT_RT_OFFSET                              6681
-#define PSWRQ2_REG_CDUT_FIRST_ILT_RT_OFFSET                             6682
-#define PSWRQ2_REG_CDUT_LAST_ILT_RT_OFFSET                              6683
-#define PSWRQ2_REG_TSDM_FIRST_ILT_RT_OFFSET                             6684
-#define PSWRQ2_REG_TSDM_LAST_ILT_RT_OFFSET                              6685
-#define PSWRQ2_REG_TM_NUMBER_OF_PF_BLOCKS_RT_OFFSET                     6686
-#define PSWRQ2_REG_CDUT_NUMBER_OF_PF_BLOCKS_RT_OFFSET                   6687
-#define PSWRQ2_REG_CDUC_NUMBER_OF_PF_BLOCKS_RT_OFFSET                   6688
-#define PSWRQ2_REG_TM_VF_BLOCKS_RT_OFFSET                               6689
-#define PSWRQ2_REG_CDUT_VF_BLOCKS_RT_OFFSET                             6690
-#define PSWRQ2_REG_CDUC_VF_BLOCKS_RT_OFFSET                             6691
-#define PSWRQ2_REG_TM_BLOCKS_FACTOR_RT_OFFSET                           6692
-#define PSWRQ2_REG_CDUT_BLOCKS_FACTOR_RT_OFFSET                         6693
-#define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET                         6694
-#define PSWRQ2_REG_VF_BASE_RT_OFFSET                                    6695
-#define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET                                6696
-#define PSWRQ2_REG_WR_MBS0_RT_OFFSET                                    6697
-#define PSWRQ2_REG_RD_MBS0_RT_OFFSET                                    6698
-#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET                              6699
-#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET                              6700
-#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET                                 6701
+#define SRC_REG_COUNTFREE_RT_OFFSET                                     6669
+#define SRC_REG_NUMBER_HASH_BITS_RT_OFFSET                              6670
+#define PSWRQ2_REG_CDUT_P_SIZE_RT_OFFSET                                6671
+#define PSWRQ2_REG_CDUC_P_SIZE_RT_OFFSET                                6672
+#define PSWRQ2_REG_TM_P_SIZE_RT_OFFSET                                  6673
+#define PSWRQ2_REG_QM_P_SIZE_RT_OFFSET                                  6674
+#define PSWRQ2_REG_SRC_P_SIZE_RT_OFFSET                                 6675
+#define PSWRQ2_REG_TM_FIRST_ILT_RT_OFFSET                               6676
+#define PSWRQ2_REG_TM_LAST_ILT_RT_OFFSET                                6677
+#define PSWRQ2_REG_QM_FIRST_ILT_RT_OFFSET                               6678
+#define PSWRQ2_REG_QM_LAST_ILT_RT_OFFSET                                6679
+#define PSWRQ2_REG_SRC_FIRST_ILT_RT_OFFSET                              6680
+#define PSWRQ2_REG_SRC_LAST_ILT_RT_OFFSET                               6681
+#define PSWRQ2_REG_CDUC_FIRST_ILT_RT_OFFSET                             6682
+#define PSWRQ2_REG_CDUC_LAST_ILT_RT_OFFSET                              6683
+#define PSWRQ2_REG_CDUT_FIRST_ILT_RT_OFFSET                             6684
+#define PSWRQ2_REG_CDUT_LAST_ILT_RT_OFFSET                              6685
+#define PSWRQ2_REG_TSDM_FIRST_ILT_RT_OFFSET                             6686
+#define PSWRQ2_REG_TSDM_LAST_ILT_RT_OFFSET                              6687
+#define PSWRQ2_REG_TM_NUMBER_OF_PF_BLOCKS_RT_OFFSET                     6688
+#define PSWRQ2_REG_CDUT_NUMBER_OF_PF_BLOCKS_RT_OFFSET                   6689
+#define PSWRQ2_REG_CDUC_NUMBER_OF_PF_BLOCKS_RT_OFFSET                   6690
+#define PSWRQ2_REG_TM_VF_BLOCKS_RT_OFFSET                               6691
+#define PSWRQ2_REG_CDUT_VF_BLOCKS_RT_OFFSET                             6692
+#define PSWRQ2_REG_CDUC_VF_BLOCKS_RT_OFFSET                             6693
+#define PSWRQ2_REG_TM_BLOCKS_FACTOR_RT_OFFSET                           6694
+#define PSWRQ2_REG_CDUT_BLOCKS_FACTOR_RT_OFFSET                         6695
+#define PSWRQ2_REG_CDUC_BLOCKS_FACTOR_RT_OFFSET                         6696
+#define PSWRQ2_REG_VF_BASE_RT_OFFSET                                    6697
+#define PSWRQ2_REG_VF_LAST_ILT_RT_OFFSET                                6698
+#define PSWRQ2_REG_WR_MBS0_RT_OFFSET                                    6699
+#define PSWRQ2_REG_RD_MBS0_RT_OFFSET                                    6700
+#define PSWRQ2_REG_DRAM_ALIGN_WR_RT_OFFSET                              6701
+#define PSWRQ2_REG_DRAM_ALIGN_RD_RT_OFFSET                              6702
+#define PSWRQ2_REG_ILT_MEMORY_RT_OFFSET                                 6703
 #define PSWRQ2_REG_ILT_MEMORY_RT_SIZE                                   22000
-#define PGLUE_REG_B_VF_BASE_RT_OFFSET                                   28701
-#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET                           28702
-#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET                              28703
-#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET                              28704
-#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET                              28705
-#define TM_REG_VF_ENABLE_CONN_RT_OFFSET                                 28706
-#define TM_REG_PF_ENABLE_CONN_RT_OFFSET                                 28707
-#define TM_REG_PF_ENABLE_TASK_RT_OFFSET                                 28708
-#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET                     28709
-#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET                     28710
-#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET                                28711
+#define PGLUE_REG_B_VF_BASE_RT_OFFSET                                   28703
+#define PGLUE_REG_B_CACHE_LINE_SIZE_RT_OFFSET                           28704
+#define PGLUE_REG_B_PF_BAR0_SIZE_RT_OFFSET                              28705
+#define PGLUE_REG_B_PF_BAR1_SIZE_RT_OFFSET                              28706
+#define PGLUE_REG_B_VF_BAR1_SIZE_RT_OFFSET                              28707
+#define TM_REG_VF_ENABLE_CONN_RT_OFFSET                                 28708
+#define TM_REG_PF_ENABLE_CONN_RT_OFFSET                                 28709
+#define TM_REG_PF_ENABLE_TASK_RT_OFFSET                                 28710
+#define TM_REG_GROUP_SIZE_RESOLUTION_CONN_RT_OFFSET                     28711
+#define TM_REG_GROUP_SIZE_RESOLUTION_TASK_RT_OFFSET                     28712
+#define TM_REG_CONFIG_CONN_MEM_RT_OFFSET                                28713
 #define TM_REG_CONFIG_CONN_MEM_RT_SIZE                                  416
-#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET                                29127
+#define TM_REG_CONFIG_TASK_MEM_RT_OFFSET                                29129
 #define TM_REG_CONFIG_TASK_MEM_RT_SIZE                                  512
-#define QM_REG_MAXPQSIZE_0_RT_OFFSET                                    29639
-#define QM_REG_MAXPQSIZE_1_RT_OFFSET                                    29640
-#define QM_REG_MAXPQSIZE_2_RT_OFFSET                                    29641
-#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET                               29642
-#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET                               29643
-#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET                               29644
-#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET                               29645
-#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET                               29646
-#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET                               29647
-#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET                               29648
-#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET                               29649
-#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET                               29650
-#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET                               29651
-#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET                              29652
-#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET                              29653
-#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET                              29654
-#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET                              29655
-#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET                              29656
-#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET                              29657
-#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET                              29658
-#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET                              29659
-#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET                              29660
-#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET                              29661
-#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET                              29662
-#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET                              29663
-#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET                              29664
-#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET                              29665
-#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET                              29666
-#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET                              29667
-#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET                              29668
-#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET                              29669
-#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET                              29670
-#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET                              29671
-#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET                              29672
-#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET                              29673
-#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET                              29674
-#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET                              29675
-#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET                              29676
-#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET                              29677
-#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET                              29678
-#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET                              29679
-#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET                              29680
-#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET                              29681
-#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET                              29682
-#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET                              29683
-#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET                              29684
-#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET                              29685
-#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET                              29686
-#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET                              29687
-#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET                              29688
-#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET                              29689
-#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET                              29690
-#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET                              29691
-#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET                              29692
-#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET                              29693
-#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET                              29694
-#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET                              29695
-#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET                              29696
-#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET                              29697
-#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET                              29698
-#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET                              29699
-#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET                              29700
-#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET                              29701
-#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET                              29702
-#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET                              29703
-#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET                              29704
-#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET                              29705
-#define QM_REG_BASEADDROTHERPQ_RT_OFFSET                                29706
+#define QM_REG_MAXPQSIZE_0_RT_OFFSET                                    29641
+#define QM_REG_MAXPQSIZE_1_RT_OFFSET                                    29642
+#define QM_REG_MAXPQSIZE_2_RT_OFFSET                                    29643
+#define QM_REG_MAXPQSIZETXSEL_0_RT_OFFSET                               29644
+#define QM_REG_MAXPQSIZETXSEL_1_RT_OFFSET                               29645
+#define QM_REG_MAXPQSIZETXSEL_2_RT_OFFSET                               29646
+#define QM_REG_MAXPQSIZETXSEL_3_RT_OFFSET                               29647
+#define QM_REG_MAXPQSIZETXSEL_4_RT_OFFSET                               29648
+#define QM_REG_MAXPQSIZETXSEL_5_RT_OFFSET                               29649
+#define QM_REG_MAXPQSIZETXSEL_6_RT_OFFSET                               29650
+#define QM_REG_MAXPQSIZETXSEL_7_RT_OFFSET                               29651
+#define QM_REG_MAXPQSIZETXSEL_8_RT_OFFSET                               29652
+#define QM_REG_MAXPQSIZETXSEL_9_RT_OFFSET                               29653
+#define QM_REG_MAXPQSIZETXSEL_10_RT_OFFSET                              29654
+#define QM_REG_MAXPQSIZETXSEL_11_RT_OFFSET                              29655
+#define QM_REG_MAXPQSIZETXSEL_12_RT_OFFSET                              29656
+#define QM_REG_MAXPQSIZETXSEL_13_RT_OFFSET                              29657
+#define QM_REG_MAXPQSIZETXSEL_14_RT_OFFSET                              29658
+#define QM_REG_MAXPQSIZETXSEL_15_RT_OFFSET                              29659
+#define QM_REG_MAXPQSIZETXSEL_16_RT_OFFSET                              29660
+#define QM_REG_MAXPQSIZETXSEL_17_RT_OFFSET                              29661
+#define QM_REG_MAXPQSIZETXSEL_18_RT_OFFSET                              29662
+#define QM_REG_MAXPQSIZETXSEL_19_RT_OFFSET                              29663
+#define QM_REG_MAXPQSIZETXSEL_20_RT_OFFSET                              29664
+#define QM_REG_MAXPQSIZETXSEL_21_RT_OFFSET                              29665
+#define QM_REG_MAXPQSIZETXSEL_22_RT_OFFSET                              29666
+#define QM_REG_MAXPQSIZETXSEL_23_RT_OFFSET                              29667
+#define QM_REG_MAXPQSIZETXSEL_24_RT_OFFSET                              29668
+#define QM_REG_MAXPQSIZETXSEL_25_RT_OFFSET                              29669
+#define QM_REG_MAXPQSIZETXSEL_26_RT_OFFSET                              29670
+#define QM_REG_MAXPQSIZETXSEL_27_RT_OFFSET                              29671
+#define QM_REG_MAXPQSIZETXSEL_28_RT_OFFSET                              29672
+#define QM_REG_MAXPQSIZETXSEL_29_RT_OFFSET                              29673
+#define QM_REG_MAXPQSIZETXSEL_30_RT_OFFSET                              29674
+#define QM_REG_MAXPQSIZETXSEL_31_RT_OFFSET                              29675
+#define QM_REG_MAXPQSIZETXSEL_32_RT_OFFSET                              29676
+#define QM_REG_MAXPQSIZETXSEL_33_RT_OFFSET                              29677
+#define QM_REG_MAXPQSIZETXSEL_34_RT_OFFSET                              29678
+#define QM_REG_MAXPQSIZETXSEL_35_RT_OFFSET                              29679
+#define QM_REG_MAXPQSIZETXSEL_36_RT_OFFSET                              29680
+#define QM_REG_MAXPQSIZETXSEL_37_RT_OFFSET                              29681
+#define QM_REG_MAXPQSIZETXSEL_38_RT_OFFSET                              29682
+#define QM_REG_MAXPQSIZETXSEL_39_RT_OFFSET                              29683
+#define QM_REG_MAXPQSIZETXSEL_40_RT_OFFSET                              29684
+#define QM_REG_MAXPQSIZETXSEL_41_RT_OFFSET                              29685
+#define QM_REG_MAXPQSIZETXSEL_42_RT_OFFSET                              29686
+#define QM_REG_MAXPQSIZETXSEL_43_RT_OFFSET                              29687
+#define QM_REG_MAXPQSIZETXSEL_44_RT_OFFSET                              29688
+#define QM_REG_MAXPQSIZETXSEL_45_RT_OFFSET                              29689
+#define QM_REG_MAXPQSIZETXSEL_46_RT_OFFSET                              29690
+#define QM_REG_MAXPQSIZETXSEL_47_RT_OFFSET                              29691
+#define QM_REG_MAXPQSIZETXSEL_48_RT_OFFSET                              29692
+#define QM_REG_MAXPQSIZETXSEL_49_RT_OFFSET                              29693
+#define QM_REG_MAXPQSIZETXSEL_50_RT_OFFSET                              29694
+#define QM_REG_MAXPQSIZETXSEL_51_RT_OFFSET                              29695
+#define QM_REG_MAXPQSIZETXSEL_52_RT_OFFSET                              29696
+#define QM_REG_MAXPQSIZETXSEL_53_RT_OFFSET                              29697
+#define QM_REG_MAXPQSIZETXSEL_54_RT_OFFSET                              29698
+#define QM_REG_MAXPQSIZETXSEL_55_RT_OFFSET                              29699
+#define QM_REG_MAXPQSIZETXSEL_56_RT_OFFSET                              29700
+#define QM_REG_MAXPQSIZETXSEL_57_RT_OFFSET                              29701
+#define QM_REG_MAXPQSIZETXSEL_58_RT_OFFSET                              29702
+#define QM_REG_MAXPQSIZETXSEL_59_RT_OFFSET                              29703
+#define QM_REG_MAXPQSIZETXSEL_60_RT_OFFSET                              29704
+#define QM_REG_MAXPQSIZETXSEL_61_RT_OFFSET                              29705
+#define QM_REG_MAXPQSIZETXSEL_62_RT_OFFSET                              29706
+#define QM_REG_MAXPQSIZETXSEL_63_RT_OFFSET                              29707
+#define QM_REG_BASEADDROTHERPQ_RT_OFFSET                                29708
 #define QM_REG_BASEADDROTHERPQ_RT_SIZE                                  128
-#define QM_REG_VOQCRDLINE_RT_OFFSET                                     29834
+#define QM_REG_VOQCRDLINE_RT_OFFSET                                     29836
 #define QM_REG_VOQCRDLINE_RT_SIZE                                       20
-#define QM_REG_VOQINITCRDLINE_RT_OFFSET                                 29854
+#define QM_REG_VOQINITCRDLINE_RT_OFFSET                                 29856
 #define QM_REG_VOQINITCRDLINE_RT_SIZE                                   20
-#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET                             29874
-#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET                             29875
-#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET                              29876
-#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET                            29877
-#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET                           29878
-#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET                                29879
-#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET                                29880
-#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET                                29881
-#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET                                29882
-#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET                                29883
-#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET                                29884
-#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET                                29885
-#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET                                29886
-#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET                                29887
-#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET                                29888
-#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET                               29889
-#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET                               29890
-#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET                               29891
-#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET                               29892
-#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET                               29893
-#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET                               29894
-#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET                            29895
-#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET                            29896
-#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET                            29897
-#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET                            29898
-#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET                               29899
-#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET                               29900
-#define QM_REG_PQTX2PF_0_RT_OFFSET                                      29901
-#define QM_REG_PQTX2PF_1_RT_OFFSET                                      29902
-#define QM_REG_PQTX2PF_2_RT_OFFSET                                      29903
-#define QM_REG_PQTX2PF_3_RT_OFFSET                                      29904
-#define QM_REG_PQTX2PF_4_RT_OFFSET                                      29905
-#define QM_REG_PQTX2PF_5_RT_OFFSET                                      29906
-#define QM_REG_PQTX2PF_6_RT_OFFSET                                      29907
-#define QM_REG_PQTX2PF_7_RT_OFFSET                                      29908
-#define QM_REG_PQTX2PF_8_RT_OFFSET                                      29909
-#define QM_REG_PQTX2PF_9_RT_OFFSET                                      29910
-#define QM_REG_PQTX2PF_10_RT_OFFSET                                     29911
-#define QM_REG_PQTX2PF_11_RT_OFFSET                                     29912
-#define QM_REG_PQTX2PF_12_RT_OFFSET                                     29913
-#define QM_REG_PQTX2PF_13_RT_OFFSET                                     29914
-#define QM_REG_PQTX2PF_14_RT_OFFSET                                     29915
-#define QM_REG_PQTX2PF_15_RT_OFFSET                                     29916
-#define QM_REG_PQTX2PF_16_RT_OFFSET                                     29917
-#define QM_REG_PQTX2PF_17_RT_OFFSET                                     29918
-#define QM_REG_PQTX2PF_18_RT_OFFSET                                     29919
-#define QM_REG_PQTX2PF_19_RT_OFFSET                                     29920
-#define QM_REG_PQTX2PF_20_RT_OFFSET                                     29921
-#define QM_REG_PQTX2PF_21_RT_OFFSET                                     29922
-#define QM_REG_PQTX2PF_22_RT_OFFSET                                     29923
-#define QM_REG_PQTX2PF_23_RT_OFFSET                                     29924
-#define QM_REG_PQTX2PF_24_RT_OFFSET                                     29925
-#define QM_REG_PQTX2PF_25_RT_OFFSET                                     29926
-#define QM_REG_PQTX2PF_26_RT_OFFSET                                     29927
-#define QM_REG_PQTX2PF_27_RT_OFFSET                                     29928
-#define QM_REG_PQTX2PF_28_RT_OFFSET                                     29929
-#define QM_REG_PQTX2PF_29_RT_OFFSET                                     29930
-#define QM_REG_PQTX2PF_30_RT_OFFSET                                     29931
-#define QM_REG_PQTX2PF_31_RT_OFFSET                                     29932
-#define QM_REG_PQTX2PF_32_RT_OFFSET                                     29933
-#define QM_REG_PQTX2PF_33_RT_OFFSET                                     29934
-#define QM_REG_PQTX2PF_34_RT_OFFSET                                     29935
-#define QM_REG_PQTX2PF_35_RT_OFFSET                                     29936
-#define QM_REG_PQTX2PF_36_RT_OFFSET                                     29937
-#define QM_REG_PQTX2PF_37_RT_OFFSET                                     29938
-#define QM_REG_PQTX2PF_38_RT_OFFSET                                     29939
-#define QM_REG_PQTX2PF_39_RT_OFFSET                                     29940
-#define QM_REG_PQTX2PF_40_RT_OFFSET                                     29941
-#define QM_REG_PQTX2PF_41_RT_OFFSET                                     29942
-#define QM_REG_PQTX2PF_42_RT_OFFSET                                     29943
-#define QM_REG_PQTX2PF_43_RT_OFFSET                                     29944
-#define QM_REG_PQTX2PF_44_RT_OFFSET                                     29945
-#define QM_REG_PQTX2PF_45_RT_OFFSET                                     29946
-#define QM_REG_PQTX2PF_46_RT_OFFSET                                     29947
-#define QM_REG_PQTX2PF_47_RT_OFFSET                                     29948
-#define QM_REG_PQTX2PF_48_RT_OFFSET                                     29949
-#define QM_REG_PQTX2PF_49_RT_OFFSET                                     29950
-#define QM_REG_PQTX2PF_50_RT_OFFSET                                     29951
-#define QM_REG_PQTX2PF_51_RT_OFFSET                                     29952
-#define QM_REG_PQTX2PF_52_RT_OFFSET                                     29953
-#define QM_REG_PQTX2PF_53_RT_OFFSET                                     29954
-#define QM_REG_PQTX2PF_54_RT_OFFSET                                     29955
-#define QM_REG_PQTX2PF_55_RT_OFFSET                                     29956
-#define QM_REG_PQTX2PF_56_RT_OFFSET                                     29957
-#define QM_REG_PQTX2PF_57_RT_OFFSET                                     29958
-#define QM_REG_PQTX2PF_58_RT_OFFSET                                     29959
-#define QM_REG_PQTX2PF_59_RT_OFFSET                                     29960
-#define QM_REG_PQTX2PF_60_RT_OFFSET                                     29961
-#define QM_REG_PQTX2PF_61_RT_OFFSET                                     29962
-#define QM_REG_PQTX2PF_62_RT_OFFSET                                     29963
-#define QM_REG_PQTX2PF_63_RT_OFFSET                                     29964
-#define QM_REG_PQOTHER2PF_0_RT_OFFSET                                   29965
-#define QM_REG_PQOTHER2PF_1_RT_OFFSET                                   29966
-#define QM_REG_PQOTHER2PF_2_RT_OFFSET                                   29967
-#define QM_REG_PQOTHER2PF_3_RT_OFFSET                                   29968
-#define QM_REG_PQOTHER2PF_4_RT_OFFSET                                   29969
-#define QM_REG_PQOTHER2PF_5_RT_OFFSET                                   29970
-#define QM_REG_PQOTHER2PF_6_RT_OFFSET                                   29971
-#define QM_REG_PQOTHER2PF_7_RT_OFFSET                                   29972
-#define QM_REG_PQOTHER2PF_8_RT_OFFSET                                   29973
-#define QM_REG_PQOTHER2PF_9_RT_OFFSET                                   29974
-#define QM_REG_PQOTHER2PF_10_RT_OFFSET                                  29975
-#define QM_REG_PQOTHER2PF_11_RT_OFFSET                                  29976
-#define QM_REG_PQOTHER2PF_12_RT_OFFSET                                  29977
-#define QM_REG_PQOTHER2PF_13_RT_OFFSET                                  29978
-#define QM_REG_PQOTHER2PF_14_RT_OFFSET                                  29979
-#define QM_REG_PQOTHER2PF_15_RT_OFFSET                                  29980
-#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET                                 29981
-#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET                                 29982
-#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET                            29983
-#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET                            29984
-#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET                              29985
-#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET                              29986
-#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET                              29987
-#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET                              29988
-#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET                              29989
-#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET                              29990
-#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET                              29991
-#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET                              29992
-#define QM_REG_RLGLBLINCVAL_RT_OFFSET                                   29993
+#define QM_REG_AFULLQMBYPTHRPFWFQ_RT_OFFSET                             29876
+#define QM_REG_AFULLQMBYPTHRVPWFQ_RT_OFFSET                             29877
+#define QM_REG_AFULLQMBYPTHRPFRL_RT_OFFSET                              29878
+#define QM_REG_AFULLQMBYPTHRGLBLRL_RT_OFFSET                            29879
+#define QM_REG_AFULLOPRTNSTCCRDMASK_RT_OFFSET                           29880
+#define QM_REG_WRROTHERPQGRP_0_RT_OFFSET                                29881
+#define QM_REG_WRROTHERPQGRP_1_RT_OFFSET                                29882
+#define QM_REG_WRROTHERPQGRP_2_RT_OFFSET                                29883
+#define QM_REG_WRROTHERPQGRP_3_RT_OFFSET                                29884
+#define QM_REG_WRROTHERPQGRP_4_RT_OFFSET                                29885
+#define QM_REG_WRROTHERPQGRP_5_RT_OFFSET                                29886
+#define QM_REG_WRROTHERPQGRP_6_RT_OFFSET                                29887
+#define QM_REG_WRROTHERPQGRP_7_RT_OFFSET                                29888
+#define QM_REG_WRROTHERPQGRP_8_RT_OFFSET                                29889
+#define QM_REG_WRROTHERPQGRP_9_RT_OFFSET                                29890
+#define QM_REG_WRROTHERPQGRP_10_RT_OFFSET                               29891
+#define QM_REG_WRROTHERPQGRP_11_RT_OFFSET                               29892
+#define QM_REG_WRROTHERPQGRP_12_RT_OFFSET                               29893
+#define QM_REG_WRROTHERPQGRP_13_RT_OFFSET                               29894
+#define QM_REG_WRROTHERPQGRP_14_RT_OFFSET                               29895
+#define QM_REG_WRROTHERPQGRP_15_RT_OFFSET                               29896
+#define QM_REG_WRROTHERGRPWEIGHT_0_RT_OFFSET                            29897
+#define QM_REG_WRROTHERGRPWEIGHT_1_RT_OFFSET                            29898
+#define QM_REG_WRROTHERGRPWEIGHT_2_RT_OFFSET                            29899
+#define QM_REG_WRROTHERGRPWEIGHT_3_RT_OFFSET                            29900
+#define QM_REG_WRRTXGRPWEIGHT_0_RT_OFFSET                               29901
+#define QM_REG_WRRTXGRPWEIGHT_1_RT_OFFSET                               29902
+#define QM_REG_PQTX2PF_0_RT_OFFSET                                      29903
+#define QM_REG_PQTX2PF_1_RT_OFFSET                                      29904
+#define QM_REG_PQTX2PF_2_RT_OFFSET                                      29905
+#define QM_REG_PQTX2PF_3_RT_OFFSET                                      29906
+#define QM_REG_PQTX2PF_4_RT_OFFSET                                      29907
+#define QM_REG_PQTX2PF_5_RT_OFFSET                                      29908
+#define QM_REG_PQTX2PF_6_RT_OFFSET                                      29909
+#define QM_REG_PQTX2PF_7_RT_OFFSET                                      29910
+#define QM_REG_PQTX2PF_8_RT_OFFSET                                      29911
+#define QM_REG_PQTX2PF_9_RT_OFFSET                                      29912
+#define QM_REG_PQTX2PF_10_RT_OFFSET                                     29913
+#define QM_REG_PQTX2PF_11_RT_OFFSET                                     29914
+#define QM_REG_PQTX2PF_12_RT_OFFSET                                     29915
+#define QM_REG_PQTX2PF_13_RT_OFFSET                                     29916
+#define QM_REG_PQTX2PF_14_RT_OFFSET                                     29917
+#define QM_REG_PQTX2PF_15_RT_OFFSET                                     29918
+#define QM_REG_PQTX2PF_16_RT_OFFSET                                     29919
+#define QM_REG_PQTX2PF_17_RT_OFFSET                                     29920
+#define QM_REG_PQTX2PF_18_RT_OFFSET                                     29921
+#define QM_REG_PQTX2PF_19_RT_OFFSET                                     29922
+#define QM_REG_PQTX2PF_20_RT_OFFSET                                     29923
+#define QM_REG_PQTX2PF_21_RT_OFFSET                                     29924
+#define QM_REG_PQTX2PF_22_RT_OFFSET                                     29925
+#define QM_REG_PQTX2PF_23_RT_OFFSET                                     29926
+#define QM_REG_PQTX2PF_24_RT_OFFSET                                     29927
+#define QM_REG_PQTX2PF_25_RT_OFFSET                                     29928
+#define QM_REG_PQTX2PF_26_RT_OFFSET                                     29929
+#define QM_REG_PQTX2PF_27_RT_OFFSET                                     29930
+#define QM_REG_PQTX2PF_28_RT_OFFSET                                     29931
+#define QM_REG_PQTX2PF_29_RT_OFFSET                                     29932
+#define QM_REG_PQTX2PF_30_RT_OFFSET                                     29933
+#define QM_REG_PQTX2PF_31_RT_OFFSET                                     29934
+#define QM_REG_PQTX2PF_32_RT_OFFSET                                     29935
+#define QM_REG_PQTX2PF_33_RT_OFFSET                                     29936
+#define QM_REG_PQTX2PF_34_RT_OFFSET                                     29937
+#define QM_REG_PQTX2PF_35_RT_OFFSET                                     29938
+#define QM_REG_PQTX2PF_36_RT_OFFSET                                     29939
+#define QM_REG_PQTX2PF_37_RT_OFFSET                                     29940
+#define QM_REG_PQTX2PF_38_RT_OFFSET                                     29941
+#define QM_REG_PQTX2PF_39_RT_OFFSET                                     29942
+#define QM_REG_PQTX2PF_40_RT_OFFSET                                     29943
+#define QM_REG_PQTX2PF_41_RT_OFFSET                                     29944
+#define QM_REG_PQTX2PF_42_RT_OFFSET                                     29945
+#define QM_REG_PQTX2PF_43_RT_OFFSET                                     29946
+#define QM_REG_PQTX2PF_44_RT_OFFSET                                     29947
+#define QM_REG_PQTX2PF_45_RT_OFFSET                                     29948
+#define QM_REG_PQTX2PF_46_RT_OFFSET                                     29949
+#define QM_REG_PQTX2PF_47_RT_OFFSET                                     29950
+#define QM_REG_PQTX2PF_48_RT_OFFSET                                     29951
+#define QM_REG_PQTX2PF_49_RT_OFFSET                                     29952
+#define QM_REG_PQTX2PF_50_RT_OFFSET                                     29953
+#define QM_REG_PQTX2PF_51_RT_OFFSET                                     29954
+#define QM_REG_PQTX2PF_52_RT_OFFSET                                     29955
+#define QM_REG_PQTX2PF_53_RT_OFFSET                                     29956
+#define QM_REG_PQTX2PF_54_RT_OFFSET                                     29957
+#define QM_REG_PQTX2PF_55_RT_OFFSET                                     29958
+#define QM_REG_PQTX2PF_56_RT_OFFSET                                     29959
+#define QM_REG_PQTX2PF_57_RT_OFFSET                                     29960
+#define QM_REG_PQTX2PF_58_RT_OFFSET                                     29961
+#define QM_REG_PQTX2PF_59_RT_OFFSET                                     29962
+#define QM_REG_PQTX2PF_60_RT_OFFSET                                     29963
+#define QM_REG_PQTX2PF_61_RT_OFFSET                                     29964
+#define QM_REG_PQTX2PF_62_RT_OFFSET                                     29965
+#define QM_REG_PQTX2PF_63_RT_OFFSET                                     29966
+#define QM_REG_PQOTHER2PF_0_RT_OFFSET                                   29967
+#define QM_REG_PQOTHER2PF_1_RT_OFFSET                                   29968
+#define QM_REG_PQOTHER2PF_2_RT_OFFSET                                   29969
+#define QM_REG_PQOTHER2PF_3_RT_OFFSET                                   29970
+#define QM_REG_PQOTHER2PF_4_RT_OFFSET                                   29971
+#define QM_REG_PQOTHER2PF_5_RT_OFFSET                                   29972
+#define QM_REG_PQOTHER2PF_6_RT_OFFSET                                   29973
+#define QM_REG_PQOTHER2PF_7_RT_OFFSET                                   29974
+#define QM_REG_PQOTHER2PF_8_RT_OFFSET                                   29975
+#define QM_REG_PQOTHER2PF_9_RT_OFFSET                                   29976
+#define QM_REG_PQOTHER2PF_10_RT_OFFSET                                  29977
+#define QM_REG_PQOTHER2PF_11_RT_OFFSET                                  29978
+#define QM_REG_PQOTHER2PF_12_RT_OFFSET                                  29979
+#define QM_REG_PQOTHER2PF_13_RT_OFFSET                                  29980
+#define QM_REG_PQOTHER2PF_14_RT_OFFSET                                  29981
+#define QM_REG_PQOTHER2PF_15_RT_OFFSET                                  29982
+#define QM_REG_RLGLBLPERIOD_0_RT_OFFSET                                 29983
+#define QM_REG_RLGLBLPERIOD_1_RT_OFFSET                                 29984
+#define QM_REG_RLGLBLPERIODTIMER_0_RT_OFFSET                            29985
+#define QM_REG_RLGLBLPERIODTIMER_1_RT_OFFSET                            29986
+#define QM_REG_RLGLBLPERIODSEL_0_RT_OFFSET                              29987
+#define QM_REG_RLGLBLPERIODSEL_1_RT_OFFSET                              29988
+#define QM_REG_RLGLBLPERIODSEL_2_RT_OFFSET                              29989
+#define QM_REG_RLGLBLPERIODSEL_3_RT_OFFSET                              29990
+#define QM_REG_RLGLBLPERIODSEL_4_RT_OFFSET                              29991
+#define QM_REG_RLGLBLPERIODSEL_5_RT_OFFSET                              29992
+#define QM_REG_RLGLBLPERIODSEL_6_RT_OFFSET                              29993
+#define QM_REG_RLGLBLPERIODSEL_7_RT_OFFSET                              29994
+#define QM_REG_RLGLBLINCVAL_RT_OFFSET                                   29995
 #define QM_REG_RLGLBLINCVAL_RT_SIZE                                     256
-#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET                               30249
+#define QM_REG_RLGLBLUPPERBOUND_RT_OFFSET                               30251
 #define QM_REG_RLGLBLUPPERBOUND_RT_SIZE                                 256
-#define QM_REG_RLGLBLCRD_RT_OFFSET                                      30505
+#define QM_REG_RLGLBLCRD_RT_OFFSET                                      30507
 #define QM_REG_RLGLBLCRD_RT_SIZE                                        256
-#define QM_REG_RLGLBLENABLE_RT_OFFSET                                   30761
-#define QM_REG_RLPFPERIOD_RT_OFFSET                                     30762
-#define QM_REG_RLPFPERIODTIMER_RT_OFFSET                                30763
-#define QM_REG_RLPFINCVAL_RT_OFFSET                                     30764
+#define QM_REG_RLGLBLENABLE_RT_OFFSET                                   30763
+#define QM_REG_RLPFPERIOD_RT_OFFSET                                     30764
+#define QM_REG_RLPFPERIODTIMER_RT_OFFSET                                30765
+#define QM_REG_RLPFINCVAL_RT_OFFSET                                     30766
 #define QM_REG_RLPFINCVAL_RT_SIZE                                       16
-#define QM_REG_RLPFUPPERBOUND_RT_OFFSET                                 30780
+#define QM_REG_RLPFUPPERBOUND_RT_OFFSET                                 30782
 #define QM_REG_RLPFUPPERBOUND_RT_SIZE                                   16
-#define QM_REG_RLPFCRD_RT_OFFSET                                        30796
+#define QM_REG_RLPFCRD_RT_OFFSET                                        30798
 #define QM_REG_RLPFCRD_RT_SIZE                                          16
-#define QM_REG_RLPFENABLE_RT_OFFSET                                     30812
-#define QM_REG_RLPFVOQENABLE_RT_OFFSET                                  30813
-#define QM_REG_WFQPFWEIGHT_RT_OFFSET                                    30814
+#define QM_REG_RLPFENABLE_RT_OFFSET                                     30814
+#define QM_REG_RLPFVOQENABLE_RT_OFFSET                                  30815
+#define QM_REG_WFQPFWEIGHT_RT_OFFSET                                    30816
 #define QM_REG_WFQPFWEIGHT_RT_SIZE                                      16
-#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET                                30830
+#define QM_REG_WFQPFUPPERBOUND_RT_OFFSET                                30832
 #define QM_REG_WFQPFUPPERBOUND_RT_SIZE                                  16
-#define QM_REG_WFQPFCRD_RT_OFFSET                                       30846
+#define QM_REG_WFQPFCRD_RT_OFFSET                                       30848
 #define QM_REG_WFQPFCRD_RT_SIZE                                         160
-#define QM_REG_WFQPFENABLE_RT_OFFSET                                    31006
-#define QM_REG_WFQVPENABLE_RT_OFFSET                                    31007
-#define QM_REG_BASEADDRTXPQ_RT_OFFSET                                   31008
+#define QM_REG_WFQPFENABLE_RT_OFFSET                                    31008
+#define QM_REG_WFQVPENABLE_RT_OFFSET                                    31009
+#define QM_REG_BASEADDRTXPQ_RT_OFFSET                                   31010
 #define QM_REG_BASEADDRTXPQ_RT_SIZE                                     512
-#define QM_REG_TXPQMAP_RT_OFFSET                                        31520
+#define QM_REG_TXPQMAP_RT_OFFSET                                        31522
 #define QM_REG_TXPQMAP_RT_SIZE                                          512
-#define QM_REG_WFQVPWEIGHT_RT_OFFSET                                    32032
+#define QM_REG_WFQVPWEIGHT_RT_OFFSET                                    32034
 #define QM_REG_WFQVPWEIGHT_RT_SIZE                                      512
-#define QM_REG_WFQVPUPPERBOUND_RT_OFFSET                                32544
-#define QM_REG_WFQVPUPPERBOUND_RT_SIZE                                  512
-#define QM_REG_WFQVPCRD_RT_OFFSET                                       33056
+#define QM_REG_WFQVPCRD_RT_OFFSET                                       32546
 #define QM_REG_WFQVPCRD_RT_SIZE                                         512
-#define QM_REG_WFQVPMAP_RT_OFFSET                                       33568
+#define QM_REG_WFQVPMAP_RT_OFFSET                                       33058
 #define QM_REG_WFQVPMAP_RT_SIZE                                         512
-#define QM_REG_WFQPFCRD_MSB_RT_OFFSET                                   34080
+#define QM_REG_WFQPFCRD_MSB_RT_OFFSET                                   33570
 #define QM_REG_WFQPFCRD_MSB_RT_SIZE                                     160
-#define NIG_REG_LLH_CLS_TYPE_DUALMODE_RT_OFFSET                         34240
-#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET                         34241
-#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET                         34242
-#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET                         34243
-#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET                         34244
-#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET                          34245
-#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET                      34246
-#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET                               34247
+#define NIG_REG_TAG_ETHERTYPE_0_RT_OFFSET                               33730
+#define NIG_REG_OUTER_TAG_VALUE_LIST0_RT_OFFSET                         33731
+#define NIG_REG_OUTER_TAG_VALUE_LIST1_RT_OFFSET                         33732
+#define NIG_REG_OUTER_TAG_VALUE_LIST2_RT_OFFSET                         33733
+#define NIG_REG_OUTER_TAG_VALUE_LIST3_RT_OFFSET                         33734
+#define NIG_REG_OUTER_TAG_VALUE_MASK_RT_OFFSET                          33735
+#define NIG_REG_LLH_FUNC_TAGMAC_CLS_TYPE_RT_OFFSET                      33736
+#define NIG_REG_LLH_FUNC_TAG_EN_RT_OFFSET                               33737
 #define NIG_REG_LLH_FUNC_TAG_EN_RT_SIZE                                 4
-#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET                          34251
+#define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_OFFSET                          33741
 #define NIG_REG_LLH_FUNC_TAG_HDR_SEL_RT_SIZE                            4
-#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET                            34255
+#define NIG_REG_LLH_FUNC_TAG_VALUE_RT_OFFSET                            33745
 #define NIG_REG_LLH_FUNC_TAG_VALUE_RT_SIZE                              4
-#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET                               34259
-#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET                         34260
+#define NIG_REG_LLH_FUNC_NO_TAG_RT_OFFSET                               33749
+#define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_OFFSET                         33750
 #define NIG_REG_LLH_FUNC_FILTER_VALUE_RT_SIZE                           32
-#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET                            34292
+#define NIG_REG_LLH_FUNC_FILTER_EN_RT_OFFSET                            33782
 #define NIG_REG_LLH_FUNC_FILTER_EN_RT_SIZE                              16
-#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET                          34308
+#define NIG_REG_LLH_FUNC_FILTER_MODE_RT_OFFSET                          33798
 #define NIG_REG_LLH_FUNC_FILTER_MODE_RT_SIZE                            16
-#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET                 34324
+#define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_OFFSET                 33814
 #define NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_RT_SIZE                   16
-#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET                       34340
+#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_OFFSET                       33830
 #define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_RT_SIZE                         16
-#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET                                  34356
-#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET                               34357
-#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET                               34358
-#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET                               34359
-#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET                           34360
-#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET                           34361
-#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET                           34362
-#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET                           34363
-#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET                        34364
-#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET                        34365
-#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET                        34366
-#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET                        34367
-#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET                            34368
-#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET                         34369
-#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET                          34370
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET                        34371
-#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET                           34372
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET                    34373
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET                        34374
-#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET                           34375
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET                    34376
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET                        34377
-#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET                           34378
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET                    34379
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET                        34380
-#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET                           34381
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET                    34382
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET                        34383
-#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET                           34384
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET                    34385
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET                        34386
-#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET                           34387
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET                    34388
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET                        34389
-#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET                           34390
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET                    34391
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET                        34392
-#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET                           34393
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET                    34394
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET                        34395
-#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET                           34396
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET                    34397
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET                        34398
-#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET                           34399
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET                    34400
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET                       34401
-#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET                          34402
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET                   34403
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET                       34404
-#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET                          34405
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET                   34406
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET                       34407
-#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET                          34408
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET                   34409
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET                       34410
-#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET                          34411
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET                   34412
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET                       34413
-#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET                          34414
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET                   34415
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET                       34416
-#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET                          34417
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET                   34418
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET                       34419
-#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET                          34420
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET                   34421
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET                       34422
-#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET                          34423
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET                   34424
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET                       34425
-#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET                          34426
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET                   34427
-#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET                       34428
-#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET                          34429
-#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET                   34430
-#define XCM_REG_CON_PHY_Q3_RT_OFFSET                                    34431
-
-#define RUNTIME_ARRAY_SIZE 34432
+#define NIG_REG_TX_EDPM_CTRL_RT_OFFSET                                  33846
+#define CDU_REG_CID_ADDR_PARAMS_RT_OFFSET                               33847
+#define CDU_REG_SEGMENT0_PARAMS_RT_OFFSET                               33848
+#define CDU_REG_SEGMENT1_PARAMS_RT_OFFSET                               33849
+#define CDU_REG_PF_SEG0_TYPE_OFFSET_RT_OFFSET                           33850
+#define CDU_REG_PF_SEG1_TYPE_OFFSET_RT_OFFSET                           33851
+#define CDU_REG_PF_SEG2_TYPE_OFFSET_RT_OFFSET                           33852
+#define CDU_REG_PF_SEG3_TYPE_OFFSET_RT_OFFSET                           33853
+#define CDU_REG_PF_FL_SEG0_TYPE_OFFSET_RT_OFFSET                        33854
+#define CDU_REG_PF_FL_SEG1_TYPE_OFFSET_RT_OFFSET                        33855
+#define CDU_REG_PF_FL_SEG2_TYPE_OFFSET_RT_OFFSET                        33856
+#define CDU_REG_PF_FL_SEG3_TYPE_OFFSET_RT_OFFSET                        33857
+#define CDU_REG_VF_SEG_TYPE_OFFSET_RT_OFFSET                            33858
+#define CDU_REG_VF_FL_SEG_TYPE_OFFSET_RT_OFFSET                         33859
+#define PBF_REG_TAG_ETHERTYPE_0_RT_OFFSET                               33860
+#define PBF_REG_BTB_SHARED_AREA_SIZE_RT_OFFSET                          33861
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ0_RT_OFFSET                        33862
+#define PBF_REG_BTB_GUARANTEED_VOQ0_RT_OFFSET                           33863
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ0_RT_OFFSET                    33864
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ1_RT_OFFSET                        33865
+#define PBF_REG_BTB_GUARANTEED_VOQ1_RT_OFFSET                           33866
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ1_RT_OFFSET                    33867
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ2_RT_OFFSET                        33868
+#define PBF_REG_BTB_GUARANTEED_VOQ2_RT_OFFSET                           33869
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ2_RT_OFFSET                    33870
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ3_RT_OFFSET                        33871
+#define PBF_REG_BTB_GUARANTEED_VOQ3_RT_OFFSET                           33872
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ3_RT_OFFSET                    33873
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ4_RT_OFFSET                        33874
+#define PBF_REG_BTB_GUARANTEED_VOQ4_RT_OFFSET                           33875
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ4_RT_OFFSET                    33876
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ5_RT_OFFSET                        33877
+#define PBF_REG_BTB_GUARANTEED_VOQ5_RT_OFFSET                           33878
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ5_RT_OFFSET                    33879
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ6_RT_OFFSET                        33880
+#define PBF_REG_BTB_GUARANTEED_VOQ6_RT_OFFSET                           33881
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ6_RT_OFFSET                    33882
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ7_RT_OFFSET                        33883
+#define PBF_REG_BTB_GUARANTEED_VOQ7_RT_OFFSET                           33884
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ7_RT_OFFSET                    33885
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ8_RT_OFFSET                        33886
+#define PBF_REG_BTB_GUARANTEED_VOQ8_RT_OFFSET                           33887
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ8_RT_OFFSET                    33888
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ9_RT_OFFSET                        33889
+#define PBF_REG_BTB_GUARANTEED_VOQ9_RT_OFFSET                           33890
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ9_RT_OFFSET                    33891
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ10_RT_OFFSET                       33892
+#define PBF_REG_BTB_GUARANTEED_VOQ10_RT_OFFSET                          33893
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ10_RT_OFFSET                   33894
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ11_RT_OFFSET                       33895
+#define PBF_REG_BTB_GUARANTEED_VOQ11_RT_OFFSET                          33896
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ11_RT_OFFSET                   33897
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ12_RT_OFFSET                       33898
+#define PBF_REG_BTB_GUARANTEED_VOQ12_RT_OFFSET                          33899
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ12_RT_OFFSET                   33900
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ13_RT_OFFSET                       33901
+#define PBF_REG_BTB_GUARANTEED_VOQ13_RT_OFFSET                          33902
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ13_RT_OFFSET                   33903
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ14_RT_OFFSET                       33904
+#define PBF_REG_BTB_GUARANTEED_VOQ14_RT_OFFSET                          33905
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ14_RT_OFFSET                   33906
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ15_RT_OFFSET                       33907
+#define PBF_REG_BTB_GUARANTEED_VOQ15_RT_OFFSET                          33908
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ15_RT_OFFSET                   33909
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ16_RT_OFFSET                       33910
+#define PBF_REG_BTB_GUARANTEED_VOQ16_RT_OFFSET                          33911
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ16_RT_OFFSET                   33912
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ17_RT_OFFSET                       33913
+#define PBF_REG_BTB_GUARANTEED_VOQ17_RT_OFFSET                          33914
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ17_RT_OFFSET                   33915
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ18_RT_OFFSET                       33916
+#define PBF_REG_BTB_GUARANTEED_VOQ18_RT_OFFSET                          33917
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ18_RT_OFFSET                   33918
+#define PBF_REG_YCMD_QS_NUM_LINES_VOQ19_RT_OFFSET                       33919
+#define PBF_REG_BTB_GUARANTEED_VOQ19_RT_OFFSET                          33920
+#define PBF_REG_BTB_SHARED_AREA_SETUP_VOQ19_RT_OFFSET                   33921
+#define XCM_REG_CON_PHY_Q3_RT_OFFSET                                    33922
+
+#define RUNTIME_ARRAY_SIZE 33923
 
-/* The eth storm context for the Ystorm */
-struct ystorm_eth_conn_st_ctx {
+/* The eth storm context for the Tstorm */
+struct tstorm_eth_conn_st_ctx {
        __le32 reserved[4];
 };
 
@@ -2535,41 +2501,253 @@ struct xstorm_eth_conn_ag_ctx {
        __le32  reg7 /* reg7 */;
        __le32  reg8 /* reg8 */;
        __le32  reg9 /* reg9 */;
-       u8      byte7 /* byte7 */;
-       u8      byte8 /* byte8 */;
-       u8      byte9 /* byte9 */;
-       u8      byte10 /* byte10 */;
-       u8      byte11 /* byte11 */;
-       u8      byte12 /* byte12 */;
-       u8      byte13 /* byte13 */;
-       u8      byte14 /* byte14 */;
-       u8      byte15 /* byte15 */;
-       u8      byte16 /* byte16 */;
-       __le16  word11 /* word11 */;
+       u8      byte7 /* byte7 */;
+       u8      byte8 /* byte8 */;
+       u8      byte9 /* byte9 */;
+       u8      byte10 /* byte10 */;
+       u8      byte11 /* byte11 */;
+       u8      byte12 /* byte12 */;
+       u8      byte13 /* byte13 */;
+       u8      byte14 /* byte14 */;
+       u8      byte15 /* byte15 */;
+       u8      byte16 /* byte16 */;
+       __le16  word11 /* word11 */;
+       __le32  reg10 /* reg10 */;
+       __le32  reg11 /* reg11 */;
+       __le32  reg12 /* reg12 */;
+       __le32  reg13 /* reg13 */;
+       __le32  reg14 /* reg14 */;
+       __le32  reg15 /* reg15 */;
+       __le32  reg16 /* reg16 */;
+       __le32  reg17 /* reg17 */;
+       __le32  reg18 /* reg18 */;
+       __le32  reg19 /* reg19 */;
+       __le16  word12 /* word12 */;
+       __le16  word13 /* word13 */;
+       __le16  word14 /* word14 */;
+       __le16  word15 /* word15 */;
+};
+
+/* The eth storm context for the Ystorm */
+struct ystorm_eth_conn_st_ctx {
+       __le32 reserved[8];
+};
+
+struct ystorm_eth_conn_ag_ctx {
+       u8      byte0 /* cdu_validation */;
+       u8      byte1 /* state */;
+       u8      flags0;
+#define YSTORM_ETH_CONN_AG_CTX_BIT0_MASK                  0x1 /* exist_in_qm0 */
+#define YSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT                 0
+#define YSTORM_ETH_CONN_AG_CTX_BIT1_MASK                  0x1 /* exist_in_qm1 */
+#define YSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT                 1
+#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK     0x3   /* cf0 */
+#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT    2
+#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_MASK      0x3   /* cf1 */
+#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_SHIFT     4
+#define YSTORM_ETH_CONN_AG_CTX_CF2_MASK                   0x3   /* cf2 */
+#define YSTORM_ETH_CONN_AG_CTX_CF2_SHIFT                  6
+       u8 flags1;
+#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK  0x1   /* cf0en */
+#define YSTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 0
+#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_MASK   0x1   /* cf1en */
+#define YSTORM_ETH_CONN_AG_CTX_PMD_TERMINATE_CF_EN_SHIFT  1
+#define YSTORM_ETH_CONN_AG_CTX_CF2EN_MASK                 0x1   /* cf2en */
+#define YSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT                2
+#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK               0x1   /* rule0en */
+#define YSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT              3
+#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK               0x1   /* rule1en */
+#define YSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT              4
+#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK               0x1   /* rule2en */
+#define YSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT              5
+#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK               0x1   /* rule3en */
+#define YSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT              6
+#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK               0x1   /* rule4en */
+#define YSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT              7
+       u8      byte2 /* byte2 */;
+       u8      byte3 /* byte3 */;
+       __le16  word0 /* word0 */;
+       __le32  terminate_spqe /* reg0 */;
+       __le32  reg1 /* reg1 */;
+       __le16  tx_bd_cons_upd /* word1 */;
+       __le16  word2 /* word2 */;
+       __le16  word3 /* word3 */;
+       __le16  word4 /* word4 */;
+       __le32  reg2 /* reg2 */;
+       __le32  reg3 /* reg3 */;
+};
+
+struct tstorm_eth_conn_ag_ctx {
+       u8      byte0 /* cdu_validation */;
+       u8      byte1 /* state */;
+       u8      flags0;
+#define TSTORM_ETH_CONN_AG_CTX_BIT0_MASK      0x1       /* exist_in_qm0 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT     0
+#define TSTORM_ETH_CONN_AG_CTX_BIT1_MASK      0x1       /* exist_in_qm1 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT     1
+#define TSTORM_ETH_CONN_AG_CTX_BIT2_MASK      0x1       /* bit2 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT2_SHIFT     2
+#define TSTORM_ETH_CONN_AG_CTX_BIT3_MASK      0x1       /* bit3 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT3_SHIFT     3
+#define TSTORM_ETH_CONN_AG_CTX_BIT4_MASK      0x1       /* bit4 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT4_SHIFT     4
+#define TSTORM_ETH_CONN_AG_CTX_BIT5_MASK      0x1       /* bit5 */
+#define TSTORM_ETH_CONN_AG_CTX_BIT5_SHIFT     5
+#define TSTORM_ETH_CONN_AG_CTX_CF0_MASK       0x3       /* timer0cf */
+#define TSTORM_ETH_CONN_AG_CTX_CF0_SHIFT      6
+       u8 flags1;
+#define TSTORM_ETH_CONN_AG_CTX_CF1_MASK       0x3       /* timer1cf */
+#define TSTORM_ETH_CONN_AG_CTX_CF1_SHIFT      0
+#define TSTORM_ETH_CONN_AG_CTX_CF2_MASK       0x3       /* timer2cf */
+#define TSTORM_ETH_CONN_AG_CTX_CF2_SHIFT      2
+#define TSTORM_ETH_CONN_AG_CTX_CF3_MASK       0x3       /* timer_stop_all */
+#define TSTORM_ETH_CONN_AG_CTX_CF3_SHIFT      4
+#define TSTORM_ETH_CONN_AG_CTX_CF4_MASK       0x3       /* cf4 */
+#define TSTORM_ETH_CONN_AG_CTX_CF4_SHIFT      6
+       u8 flags2;
+#define TSTORM_ETH_CONN_AG_CTX_CF5_MASK       0x3       /* cf5 */
+#define TSTORM_ETH_CONN_AG_CTX_CF5_SHIFT      0
+#define TSTORM_ETH_CONN_AG_CTX_CF6_MASK       0x3       /* cf6 */
+#define TSTORM_ETH_CONN_AG_CTX_CF6_SHIFT      2
+#define TSTORM_ETH_CONN_AG_CTX_CF7_MASK       0x3       /* cf7 */
+#define TSTORM_ETH_CONN_AG_CTX_CF7_SHIFT      4
+#define TSTORM_ETH_CONN_AG_CTX_CF8_MASK       0x3       /* cf8 */
+#define TSTORM_ETH_CONN_AG_CTX_CF8_SHIFT      6
+       u8 flags3;
+#define TSTORM_ETH_CONN_AG_CTX_CF9_MASK       0x3       /* cf9 */
+#define TSTORM_ETH_CONN_AG_CTX_CF9_SHIFT      0
+#define TSTORM_ETH_CONN_AG_CTX_CF10_MASK      0x3       /* cf10 */
+#define TSTORM_ETH_CONN_AG_CTX_CF10_SHIFT     2
+#define TSTORM_ETH_CONN_AG_CTX_CF0EN_MASK     0x1       /* cf0en */
+#define TSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT    4
+#define TSTORM_ETH_CONN_AG_CTX_CF1EN_MASK     0x1       /* cf1en */
+#define TSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT    5
+#define TSTORM_ETH_CONN_AG_CTX_CF2EN_MASK     0x1       /* cf2en */
+#define TSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT    6
+#define TSTORM_ETH_CONN_AG_CTX_CF3EN_MASK     0x1       /* cf3en */
+#define TSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT    7
+       u8 flags4;
+#define TSTORM_ETH_CONN_AG_CTX_CF4EN_MASK     0x1       /* cf4en */
+#define TSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT    0
+#define TSTORM_ETH_CONN_AG_CTX_CF5EN_MASK     0x1       /* cf5en */
+#define TSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT    1
+#define TSTORM_ETH_CONN_AG_CTX_CF6EN_MASK     0x1       /* cf6en */
+#define TSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT    2
+#define TSTORM_ETH_CONN_AG_CTX_CF7EN_MASK     0x1       /* cf7en */
+#define TSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT    3
+#define TSTORM_ETH_CONN_AG_CTX_CF8EN_MASK     0x1       /* cf8en */
+#define TSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT    4
+#define TSTORM_ETH_CONN_AG_CTX_CF9EN_MASK     0x1       /* cf9en */
+#define TSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT    5
+#define TSTORM_ETH_CONN_AG_CTX_CF10EN_MASK    0x1       /* cf10en */
+#define TSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT   6
+#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK   0x1       /* rule0en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT  7
+       u8 flags5;
+#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK   0x1       /* rule1en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT  0
+#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK   0x1       /* rule2en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT  1
+#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK   0x1       /* rule3en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT  2
+#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK   0x1       /* rule4en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT  3
+#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK   0x1       /* rule5en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT  4
+#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_MASK  0x1       /* rule6en */
+#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_SHIFT 5
+#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK   0x1       /* rule7en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT  6
+#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_MASK   0x1       /* rule8en */
+#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT  7
+       __le32  reg0 /* reg0 */;
+       __le32  reg1 /* reg1 */;
+       __le32  reg2 /* reg2 */;
+       __le32  reg3 /* reg3 */;
+       __le32  reg4 /* reg4 */;
+       __le32  reg5 /* reg5 */;
+       __le32  reg6 /* reg6 */;
+       __le32  reg7 /* reg7 */;
+       __le32  reg8 /* reg8 */;
+       u8      byte2 /* byte2 */;
+       u8      byte3 /* byte3 */;
+       __le16  rx_bd_cons /* word0 */;
+       u8      byte4 /* byte4 */;
+       u8      byte5 /* byte5 */;
+       __le16  rx_bd_prod /* word1 */;
+       __le16  word2 /* conn_dpi */;
+       __le16  word3 /* word3 */;
+       __le32  reg9 /* reg9 */;
        __le32  reg10 /* reg10 */;
-       __le32  reg11 /* reg11 */;
-       __le32  reg12 /* reg12 */;
-       __le32  reg13 /* reg13 */;
-       __le32  reg14 /* reg14 */;
-       __le32  reg15 /* reg15 */;
-       __le32  reg16 /* reg16 */;
-       __le32  reg17 /* reg17 */;
-       __le32  reg18 /* reg18 */;
-       __le32  reg19 /* reg19 */;
-       __le16  word12 /* word12 */;
-       __le16  word13 /* word13 */;
-       __le16  word14 /* word14 */;
-       __le16  word15 /* word15 */;
 };
 
-/* The eth storm context for the Tstorm */
-struct tstorm_eth_conn_st_ctx {
-       __le32 reserved[4];
-};
-
-/* The eth storm context for the Mstorm */
-struct mstorm_eth_conn_st_ctx {
-       __le32 reserved[8];
+struct ustorm_eth_conn_ag_ctx {
+       u8      byte0 /* cdu_validation */;
+       u8      byte1 /* state */;
+       u8      flags0;
+#define USTORM_ETH_CONN_AG_CTX_BIT0_MASK                  0x1 /* exist_in_qm0 */
+#define USTORM_ETH_CONN_AG_CTX_BIT0_SHIFT                 0
+#define USTORM_ETH_CONN_AG_CTX_BIT1_MASK                  0x1 /* exist_in_qm1 */
+#define USTORM_ETH_CONN_AG_CTX_BIT1_SHIFT                 1
+#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_MASK   0x3 /* timer0cf */
+#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_SHIFT  2
+#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_MASK   0x3 /* timer1cf */
+#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_SHIFT  4
+#define USTORM_ETH_CONN_AG_CTX_CF2_MASK                   0x3 /* timer2cf */
+#define USTORM_ETH_CONN_AG_CTX_CF2_SHIFT                  6
+       u8 flags1;
+#define USTORM_ETH_CONN_AG_CTX_CF3_MASK                 0x3 /* timer_stop_all */
+#define USTORM_ETH_CONN_AG_CTX_CF3_SHIFT                0
+#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_MASK           0x3 /* cf4 */
+#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_SHIFT          2
+#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_MASK           0x3 /* cf5 */
+#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_SHIFT          4
+#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK   0x3 /* cf6 */
+#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT  6
+       u8 flags2;
+#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_MASK  0x1 /* cf0en */
+#define USTORM_ETH_CONN_AG_CTX_TX_PMD_TERMINATE_CF_EN_SHIFT 0
+#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_MASK  0x1 /* cf1en */
+#define USTORM_ETH_CONN_AG_CTX_RX_PMD_TERMINATE_CF_EN_SHIFT 1
+#define USTORM_ETH_CONN_AG_CTX_CF2EN_MASK                   0x1 /* cf2en */
+#define USTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT                  2
+#define USTORM_ETH_CONN_AG_CTX_CF3EN_MASK                   0x1 /* cf3en */
+#define USTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT                  3
+#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_MASK            0x1 /* cf4en */
+#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_SHIFT           4
+#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_MASK            0x1 /* cf5en */
+#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_SHIFT           5
+#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK    0x1 /* cf6en */
+#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT   6
+#define USTORM_ETH_CONN_AG_CTX_RULE0EN_MASK                 0x1 /* rule0en */
+#define USTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT                7
+       u8 flags3;
+#define USTORM_ETH_CONN_AG_CTX_RULE1EN_MASK                 0x1 /* rule1en */
+#define USTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT                0
+#define USTORM_ETH_CONN_AG_CTX_RULE2EN_MASK                 0x1 /* rule2en */
+#define USTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT                1
+#define USTORM_ETH_CONN_AG_CTX_RULE3EN_MASK                 0x1 /* rule3en */
+#define USTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT                2
+#define USTORM_ETH_CONN_AG_CTX_RULE4EN_MASK                 0x1 /* rule4en */
+#define USTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT                3
+#define USTORM_ETH_CONN_AG_CTX_RULE5EN_MASK                 0x1 /* rule5en */
+#define USTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT                4
+#define USTORM_ETH_CONN_AG_CTX_RULE6EN_MASK                 0x1 /* rule6en */
+#define USTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT                5
+#define USTORM_ETH_CONN_AG_CTX_RULE7EN_MASK                 0x1 /* rule7en */
+#define USTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT                6
+#define USTORM_ETH_CONN_AG_CTX_RULE8EN_MASK                 0x1 /* rule8en */
+#define USTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT                7
+       u8      byte2 /* byte2 */;
+       u8      byte3 /* byte3 */;
+       __le16  word0 /* conn_dpi */;
+       __le16  tx_bd_cons /* word1 */;
+       __le32  reg0 /* reg0 */;
+       __le32  reg1 /* reg1 */;
+       __le32  reg2 /* reg2 */;
+       __le32  tx_int_coallecing_timeset /* reg3 */;
+       __le16  tx_drv_bd_cons /* word2 */;
+       __le16  rx_drv_cqe_cons /* word3 */;
 };
 
 /* The eth storm context for the Ustorm */
@@ -2577,24 +2755,30 @@ struct ustorm_eth_conn_st_ctx {
        __le32 reserved[40];
 };
 
+/* The eth storm context for the Mstorm */
+struct mstorm_eth_conn_st_ctx {
+       __le32 reserved[8];
+};
+
 /* eth connection context */
 struct eth_conn_context {
-       struct ystorm_eth_conn_st_ctx   ystorm_st_context;
-       struct regpair                  ystorm_st_padding[2] /* padding */;
+       struct tstorm_eth_conn_st_ctx   tstorm_st_context;
+       struct regpair                  tstorm_st_padding[2];
        struct pstorm_eth_conn_st_ctx   pstorm_st_context;
-       struct regpair                  pstorm_st_padding[2] /* padding */;
        struct xstorm_eth_conn_st_ctx   xstorm_st_context;
        struct xstorm_eth_conn_ag_ctx   xstorm_ag_context;
-       struct tstorm_eth_conn_st_ctx   tstorm_st_context;
-       struct regpair                  tstorm_st_padding[2] /* padding */;
-       struct mstorm_eth_conn_st_ctx   mstorm_st_context;
+       struct ystorm_eth_conn_st_ctx   ystorm_st_context;
+       struct ystorm_eth_conn_ag_ctx   ystorm_ag_context;
+       struct tstorm_eth_conn_ag_ctx   tstorm_ag_context;
+       struct ustorm_eth_conn_ag_ctx   ustorm_ag_context;
        struct ustorm_eth_conn_st_ctx   ustorm_st_context;
+       struct mstorm_eth_conn_st_ctx   mstorm_st_context;
 };
 
 enum eth_filter_action {
        ETH_FILTER_ACTION_REMOVE,
        ETH_FILTER_ACTION_ADD,
-       ETH_FILTER_ACTION_REPLACE,
+       ETH_FILTER_ACTION_REMOVE_ALL,
        MAX_ETH_FILTER_ACTION
 };
 
@@ -2653,6 +2837,32 @@ enum eth_ramrod_cmd_id {
        MAX_ETH_RAMROD_CMD_ID
 };
 
+enum eth_tx_err {
+       ETH_TX_ERR_DROP /* Drop erronous packet. */,
+       ETH_TX_ERR_ASSERT_MALICIOUS,
+       MAX_ETH_TX_ERR
+};
+
+struct eth_tx_err_vals {
+       __le16 values;
+#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_MASK            0x1
+#define ETH_TX_ERR_VALS_ILLEGAL_VLAN_MODE_SHIFT           0
+#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_MASK             0x1
+#define ETH_TX_ERR_VALS_PACKET_TOO_SMALL_SHIFT            1
+#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_MASK            0x1
+#define ETH_TX_ERR_VALS_ANTI_SPOOFING_ERR_SHIFT           2
+#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_MASK          0x1
+#define ETH_TX_ERR_VALS_ILLEGAL_INBAND_TAGS_SHIFT         3
+#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_MASK  0x1
+#define ETH_TX_ERR_VALS_VLAN_INSERTION_W_INBAND_TAG_SHIFT 4
+#define ETH_TX_ERR_VALS_MTU_VIOLATION_MASK                0x1
+#define ETH_TX_ERR_VALS_MTU_VIOLATION_SHIFT               5
+#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_MASK        0x1
+#define ETH_TX_ERR_VALS_ILLEGAL_CONTROL_FRAME_SHIFT       6
+#define ETH_TX_ERR_VALS_RESERVED_MASK                     0x1FF
+#define ETH_TX_ERR_VALS_RESERVED_SHIFT                    7
+};
+
 struct eth_vport_rss_config {
        __le16 capabilities;
 #define ETH_VPORT_RSS_CONFIG_IPV4_CAPABILITY_MASK      0x1
@@ -2669,12 +2879,8 @@ struct eth_vport_rss_config {
 #define ETH_VPORT_RSS_CONFIG_IPV6_UDP_CAPABILITY_SHIFT   5
 #define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_MASK  0x1
 #define ETH_VPORT_RSS_CONFIG_EN_5_TUPLE_CAPABILITY_SHIFT 6
-#define ETH_VPORT_RSS_CONFIG_CALC_4TUP_TCP_FRAG_MASK     0x1
-#define ETH_VPORT_RSS_CONFIG_CALC_4TUP_TCP_FRAG_SHIFT    7
-#define ETH_VPORT_RSS_CONFIG_CALC_4TUP_UDP_FRAG_MASK     0x1
-#define ETH_VPORT_RSS_CONFIG_CALC_4TUP_UDP_FRAG_SHIFT    8
-#define ETH_VPORT_RSS_CONFIG_RESERVED0_MASK          0x7F
-#define ETH_VPORT_RSS_CONFIG_RESERVED0_SHIFT        9
+#define ETH_VPORT_RSS_CONFIG_RESERVED0_MASK          0x1FF
+#define ETH_VPORT_RSS_CONFIG_RESERVED0_SHIFT        7
        u8      rss_id;
        u8      rss_mode;
        u8      update_rss_key;
@@ -2713,7 +2919,19 @@ struct eth_vport_rx_mode {
 };
 
 struct eth_vport_tpa_param {
-       u64     reserved[2];
+       u8      tpa_ipv4_en_flg;
+       u8      tpa_ipv6_en_flg;
+       u8      tpa_ipv4_tunn_en_flg;
+       u8      tpa_ipv6_tunn_en_flg;
+       u8      tpa_pkt_split_flg;
+       u8      tpa_hdr_data_split_flg;
+       u8      tpa_gro_consistent_flg;
+       u8      tpa_max_aggs_num;
+       u16     tpa_max_size;
+       u16     tpa_min_size_to_start;
+       u16     tpa_min_size_to_cont;
+       u8      max_buff_num;
+       u8      reserved;
 };
 
 struct eth_vport_tx_mode {
@@ -2749,10 +2967,14 @@ struct rx_queue_start_ramrod_data {
        u8            pxp_tph_valid_pkt;
        u8            pxp_st_hint;
        __le16    pxp_st_index;
-       u8            reserved[4];
-       struct regpair  cqe_pbl_addr;
-       struct regpair  bd_base;
-       struct regpair  sge_base;
+       u8              pmd_mode;
+       u8              notify_en;
+       u8              toggle_val;
+       u8              reserved[7];
+       __le16          reserved1;
+       struct regpair  cqe_pbl_addr;
+       struct regpair  bd_base;
+       struct regpair  reserved2;
 };
 
 struct rx_queue_stop_ramrod_data {
@@ -2764,23 +2986,24 @@ struct rx_queue_stop_ramrod_data {
 };
 
 struct rx_queue_update_ramrod_data {
-       __le16    rx_queue_id;
-       u8            complete_cqe_flg;
-       u8            complete_event_flg;
-       u8            init_sge_ring_flg;
-       u8            vport_id;
-       u8            pxp_tph_valid_sge;
-       u8            pxp_st_hint;
-       __le16    pxp_st_index;
-       u8            reserved[6];
-       struct regpair  sge_base;
+       __le16  rx_queue_id;
+       u8      complete_cqe_flg;
+       u8      complete_event_flg;
+       u8      vport_id;
+       u8      reserved[4];
+       u8      reserved1;
+       u8      reserved2;
+       u8      reserved3;
+       __le16  reserved4;
+       __le16  reserved5;
+       struct regpair reserved6;
 };
 
 struct tx_queue_start_ramrod_data {
        __le16  sb_id;
        u8      sb_index;
        u8      vport_id;
-       u8      tc;
+       u8      reserved0;
        u8      stats_counter_id;
        __le16  qm_pq_id;
        u8      flags;
@@ -2790,18 +3013,25 @@ struct tx_queue_start_ramrod_data {
 #define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_PKT_DUP_SHIFT     1
 #define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_MASK      0x1
 #define TX_QUEUE_START_RAMROD_DATA_TEST_MODE_TX_DEST_SHIFT     2
-#define TX_QUEUE_START_RAMROD_DATA_RESERVED0_MASK            0x1F
-#define TX_QUEUE_START_RAMROD_DATA_RESERVED0_SHIFT          3
-       u8            pin_context;
-       u8            pxp_tph_valid_bd;
-       u8            pxp_tph_valid_pkt;
-       __le16    pxp_st_index;
-       u8            pxp_st_hint;
-       u8            reserved1[3];
-       __le16    queue_zone_id;
-       __le16    test_dup_count;
-       __le16    pbl_size;
-       struct regpair  pbl_base_addr;
+#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_MASK               0x1
+#define TX_QUEUE_START_RAMROD_DATA_PMD_MODE_SHIFT              3
+#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_MASK              0x1
+#define TX_QUEUE_START_RAMROD_DATA_NOTIFY_EN_SHIFT             4
+#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_MASK            0x1
+#define TX_QUEUE_START_RAMROD_DATA_PIN_CONTEXT_SHIFT           5
+#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_MASK              0x3
+#define TX_QUEUE_START_RAMROD_DATA_RESERVED1_SHIFT             6
+       u8      pxp_st_hint;
+       u8      pxp_tph_valid_bd;
+       u8      pxp_tph_valid_pkt;
+       __le16  pxp_st_index;
+       __le16  comp_agg_size;
+       __le16  queue_zone_id;
+       __le16  test_dup_count;
+       __le16  pbl_size;
+       __le16  tx_queue_id;
+       struct regpair  pbl_base_addr;
+       struct regpair  bd_cons_address;
 };
 
 struct tx_queue_stop_ramrod_data {
@@ -2822,16 +3052,16 @@ struct vport_start_ramrod_data {
        struct eth_vport_rx_mode        rx_mode;
        struct eth_vport_tx_mode        tx_mode;
        struct eth_vport_tpa_param      tpa_param;
-       __le16                    sge_buff_size;
-       u8                            max_sges_num;
-       u8                            tx_switching_en;
-       u8                            anti_spoofing_en;
-       u8                            default_vlan_en;
-       u8                            handle_ptp_pkts;
-       u8                            silent_vlan_removal_en;
-       __le16                    default_vlan;
-       u8                            untagged;
-       u8                            reserved[7];
+       __le16                          default_vlan;
+       u8                              tx_switching_en;
+       u8                              anti_spoofing_en;
+       u8                              default_vlan_en;
+       u8                              handle_ptp_pkts;
+       u8                              silent_vlan_removal_en;
+       u8                              untagged;
+       struct eth_tx_err_vals          tx_err_behav;
+       u8                              zero_placement_offset;
+       u8                              reserved[7];
 };
 
 struct vport_stop_ramrod_data {
@@ -2840,36 +3070,35 @@ struct vport_stop_ramrod_data {
 };
 
 struct vport_update_ramrod_data_cmn {
-       u8      vport_id;
-       u8      update_rx_active_flg;
-       u8      rx_active_flg;
-       u8      update_tx_active_flg;
-       u8      tx_active_flg;
-       u8      update_rx_mode_flg;
-       u8      update_tx_mode_flg;
-       u8      update_approx_mcast_flg;
-       u8      update_rss_flg;
-       u8      update_inner_vlan_removal_en_flg;
-       u8      inner_vlan_removal_en;
-       u8      update_tpa_param_flg;
-       u8      update_tpa_en_flg;
-       u8      update_sge_param_flg;
-       __le16  sge_buff_size;
-       u8      max_sges_num;
-       u8      update_tx_switching_en_flg;
-       u8      tx_switching_en;
-       u8      update_anti_spoofing_en_flg;
-       u8      anti_spoofing_en;
-       u8      update_handle_ptp_pkts;
-       u8      handle_ptp_pkts;
-       u8      update_default_vlan_en_flg;
-       u8      default_vlan_en;
-       u8      update_default_vlan_flg;
-       __le16  default_vlan;
-       u8      update_accept_any_vlan_flg;
-       u8      accept_any_vlan;
-       u8      silent_vlan_removal_en;
-       u8      reserved;
+       u8      vport_id;
+       u8      update_rx_active_flg;
+       u8      rx_active_flg;
+       u8      update_tx_active_flg;
+       u8      tx_active_flg;
+       u8      update_rx_mode_flg;
+       u8      update_tx_mode_flg;
+       u8      update_approx_mcast_flg;
+       u8      update_rss_flg;
+       u8      update_inner_vlan_removal_en_flg;
+       u8      inner_vlan_removal_en;
+       u8      update_tpa_param_flg;
+       u8      update_tpa_en_flg;
+       u8      update_tx_switching_en_flg;
+       u8      tx_switching_en;
+       u8      update_anti_spoofing_en_flg;
+       u8      anti_spoofing_en;
+       u8      update_handle_ptp_pkts;
+       u8      handle_ptp_pkts;
+       u8      update_default_vlan_en_flg;
+       u8      default_vlan_en;
+       u8      update_default_vlan_flg;
+       __le16  default_vlan;
+       u8      update_accept_any_vlan_flg;
+       u8      accept_any_vlan;
+       u8      silent_vlan_removal_en;
+       u8      update_mtu_flg;
+       __le16  mtu;
+       u8      reserved[2];
 };
 
 struct vport_update_ramrod_mcast {
@@ -2885,436 +3114,6 @@ struct vport_update_ramrod_data {
        struct eth_vport_rss_config          rss_config;
 };
 
-struct mstorm_eth_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_MASK  0x1   /* exist_in_qm0 */
-#define MSTORM_ETH_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0
-#define MSTORM_ETH_CONN_AG_CTX_BIT1_MASK          0x1   /* exist_in_qm1 */
-#define MSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT         1
-#define MSTORM_ETH_CONN_AG_CTX_CF0_MASK           0x3   /* cf0 */
-#define MSTORM_ETH_CONN_AG_CTX_CF0_SHIFT          2
-#define MSTORM_ETH_CONN_AG_CTX_CF1_MASK           0x3   /* cf1 */
-#define MSTORM_ETH_CONN_AG_CTX_CF1_SHIFT          4
-#define MSTORM_ETH_CONN_AG_CTX_CF2_MASK           0x3   /* cf2 */
-#define MSTORM_ETH_CONN_AG_CTX_CF2_SHIFT          6
-       u8 flags1;
-#define MSTORM_ETH_CONN_AG_CTX_CF0EN_MASK         0x1   /* cf0en */
-#define MSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT        0
-#define MSTORM_ETH_CONN_AG_CTX_CF1EN_MASK         0x1   /* cf1en */
-#define MSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT        1
-#define MSTORM_ETH_CONN_AG_CTX_CF2EN_MASK         0x1   /* cf2en */
-#define MSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT        2
-#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK       0x1   /* rule0en */
-#define MSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT      3
-#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK       0x1   /* rule1en */
-#define MSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT      4
-#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK       0x1   /* rule2en */
-#define MSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT      5
-#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK       0x1   /* rule3en */
-#define MSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT      6
-#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK       0x1   /* rule4en */
-#define MSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT      7
-       __le16  word0 /* word0 */;
-       __le16  word1 /* word1 */;
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-};
-
-struct tstorm_eth_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define TSTORM_ETH_CONN_AG_CTX_BIT0_MASK      0x1       /* exist_in_qm0 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT0_SHIFT     0
-#define TSTORM_ETH_CONN_AG_CTX_BIT1_MASK      0x1       /* exist_in_qm1 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT1_SHIFT     1
-#define TSTORM_ETH_CONN_AG_CTX_BIT2_MASK      0x1       /* bit2 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT2_SHIFT     2
-#define TSTORM_ETH_CONN_AG_CTX_BIT3_MASK      0x1       /* bit3 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT3_SHIFT     3
-#define TSTORM_ETH_CONN_AG_CTX_BIT4_MASK      0x1       /* bit4 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT4_SHIFT     4
-#define TSTORM_ETH_CONN_AG_CTX_BIT5_MASK      0x1       /* bit5 */
-#define TSTORM_ETH_CONN_AG_CTX_BIT5_SHIFT     5
-#define TSTORM_ETH_CONN_AG_CTX_CF0_MASK       0x3       /* timer0cf */
-#define TSTORM_ETH_CONN_AG_CTX_CF0_SHIFT      6
-       u8 flags1;
-#define TSTORM_ETH_CONN_AG_CTX_CF1_MASK       0x3       /* timer1cf */
-#define TSTORM_ETH_CONN_AG_CTX_CF1_SHIFT      0
-#define TSTORM_ETH_CONN_AG_CTX_CF2_MASK       0x3       /* timer2cf */
-#define TSTORM_ETH_CONN_AG_CTX_CF2_SHIFT      2
-#define TSTORM_ETH_CONN_AG_CTX_CF3_MASK       0x3       /* timer_stop_all */
-#define TSTORM_ETH_CONN_AG_CTX_CF3_SHIFT      4
-#define TSTORM_ETH_CONN_AG_CTX_CF4_MASK       0x3       /* cf4 */
-#define TSTORM_ETH_CONN_AG_CTX_CF4_SHIFT      6
-       u8 flags2;
-#define TSTORM_ETH_CONN_AG_CTX_CF5_MASK       0x3       /* cf5 */
-#define TSTORM_ETH_CONN_AG_CTX_CF5_SHIFT      0
-#define TSTORM_ETH_CONN_AG_CTX_CF6_MASK       0x3       /* cf6 */
-#define TSTORM_ETH_CONN_AG_CTX_CF6_SHIFT      2
-#define TSTORM_ETH_CONN_AG_CTX_CF7_MASK       0x3       /* cf7 */
-#define TSTORM_ETH_CONN_AG_CTX_CF7_SHIFT      4
-#define TSTORM_ETH_CONN_AG_CTX_CF8_MASK       0x3       /* cf8 */
-#define TSTORM_ETH_CONN_AG_CTX_CF8_SHIFT      6
-       u8 flags3;
-#define TSTORM_ETH_CONN_AG_CTX_CF9_MASK       0x3       /* cf9 */
-#define TSTORM_ETH_CONN_AG_CTX_CF9_SHIFT      0
-#define TSTORM_ETH_CONN_AG_CTX_CF10_MASK      0x3       /* cf10 */
-#define TSTORM_ETH_CONN_AG_CTX_CF10_SHIFT     2
-#define TSTORM_ETH_CONN_AG_CTX_CF0EN_MASK     0x1       /* cf0en */
-#define TSTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT    4
-#define TSTORM_ETH_CONN_AG_CTX_CF1EN_MASK     0x1       /* cf1en */
-#define TSTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT    5
-#define TSTORM_ETH_CONN_AG_CTX_CF2EN_MASK     0x1       /* cf2en */
-#define TSTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT    6
-#define TSTORM_ETH_CONN_AG_CTX_CF3EN_MASK     0x1       /* cf3en */
-#define TSTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT    7
-       u8 flags4;
-#define TSTORM_ETH_CONN_AG_CTX_CF4EN_MASK     0x1       /* cf4en */
-#define TSTORM_ETH_CONN_AG_CTX_CF4EN_SHIFT    0
-#define TSTORM_ETH_CONN_AG_CTX_CF5EN_MASK     0x1       /* cf5en */
-#define TSTORM_ETH_CONN_AG_CTX_CF5EN_SHIFT    1
-#define TSTORM_ETH_CONN_AG_CTX_CF6EN_MASK     0x1       /* cf6en */
-#define TSTORM_ETH_CONN_AG_CTX_CF6EN_SHIFT    2
-#define TSTORM_ETH_CONN_AG_CTX_CF7EN_MASK     0x1       /* cf7en */
-#define TSTORM_ETH_CONN_AG_CTX_CF7EN_SHIFT    3
-#define TSTORM_ETH_CONN_AG_CTX_CF8EN_MASK     0x1       /* cf8en */
-#define TSTORM_ETH_CONN_AG_CTX_CF8EN_SHIFT    4
-#define TSTORM_ETH_CONN_AG_CTX_CF9EN_MASK     0x1       /* cf9en */
-#define TSTORM_ETH_CONN_AG_CTX_CF9EN_SHIFT    5
-#define TSTORM_ETH_CONN_AG_CTX_CF10EN_MASK    0x1       /* cf10en */
-#define TSTORM_ETH_CONN_AG_CTX_CF10EN_SHIFT   6
-#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_MASK   0x1       /* rule0en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT  7
-       u8 flags5;
-#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_MASK   0x1       /* rule1en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT  0
-#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_MASK   0x1       /* rule2en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT  1
-#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_MASK   0x1       /* rule3en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT  2
-#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_MASK   0x1       /* rule4en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT  3
-#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_MASK   0x1       /* rule5en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT  4
-#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_MASK  0x1       /* rule6en */
-#define TSTORM_ETH_CONN_AG_CTX_RX_BD_EN_SHIFT 5
-#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_MASK   0x1       /* rule7en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT  6
-#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_MASK   0x1       /* rule8en */
-#define TSTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT  7
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-       __le32  reg2 /* reg2 */;
-       __le32  reg3 /* reg3 */;
-       __le32  reg4 /* reg4 */;
-       __le32  reg5 /* reg5 */;
-       __le32  reg6 /* reg6 */;
-       __le32  reg7 /* reg7 */;
-       __le32  reg8 /* reg8 */;
-       u8      byte2 /* byte2 */;
-       u8      byte3 /* byte3 */;
-       __le16  rx_bd_cons /* word0 */;
-       u8      byte4 /* byte4 */;
-       u8      byte5 /* byte5 */;
-       __le16  rx_bd_prod /* word1 */;
-       __le16  word2 /* conn_dpi */;
-       __le16  word3 /* word3 */;
-       __le32  reg9 /* reg9 */;
-       __le32  reg10 /* reg10 */;
-};
-
-struct ustorm_eth_conn_ag_ctx {
-       u8      byte0 /* cdu_validation */;
-       u8      byte1 /* state */;
-       u8      flags0;
-#define USTORM_ETH_CONN_AG_CTX_BIT0_MASK                  0x1
-#define USTORM_ETH_CONN_AG_CTX_BIT0_SHIFT                 0
-#define USTORM_ETH_CONN_AG_CTX_BIT1_MASK                  0x1
-#define USTORM_ETH_CONN_AG_CTX_BIT1_SHIFT                 1
-#define USTORM_ETH_CONN_AG_CTX_CF0_MASK                   0x3   /* timer0cf */
-#define USTORM_ETH_CONN_AG_CTX_CF0_SHIFT                  2
-#define USTORM_ETH_CONN_AG_CTX_CF1_MASK                   0x3   /* timer1cf */
-#define USTORM_ETH_CONN_AG_CTX_CF1_SHIFT                  4
-#define USTORM_ETH_CONN_AG_CTX_CF2_MASK                   0x3   /* timer2cf */
-#define USTORM_ETH_CONN_AG_CTX_CF2_SHIFT                  6
-       u8 flags1;
-#define USTORM_ETH_CONN_AG_CTX_CF3_MASK                   0x3
-#define USTORM_ETH_CONN_AG_CTX_CF3_SHIFT                  0
-#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_MASK             0x3   /* cf4 */
-#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_SHIFT            2
-#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_MASK             0x3   /* cf5 */
-#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_SHIFT            4
-#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_MASK     0x3   /* cf6 */
-#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_SHIFT    6
-       u8 flags2;
-#define USTORM_ETH_CONN_AG_CTX_CF0EN_MASK                 0x1   /* cf0en */
-#define USTORM_ETH_CONN_AG_CTX_CF0EN_SHIFT                0
-#define USTORM_ETH_CONN_AG_CTX_CF1EN_MASK                 0x1   /* cf1en */
-#define USTORM_ETH_CONN_AG_CTX_CF1EN_SHIFT                1
-#define USTORM_ETH_CONN_AG_CTX_CF2EN_MASK                 0x1   /* cf2en */
-#define USTORM_ETH_CONN_AG_CTX_CF2EN_SHIFT                2
-#define USTORM_ETH_CONN_AG_CTX_CF3EN_MASK                 0x1   /* cf3en */
-#define USTORM_ETH_CONN_AG_CTX_CF3EN_SHIFT                3
-#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_MASK          0x1   /* cf4en */
-#define USTORM_ETH_CONN_AG_CTX_TX_ARM_CF_EN_SHIFT         4
-#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_MASK          0x1   /* cf5en */
-#define USTORM_ETH_CONN_AG_CTX_RX_ARM_CF_EN_SHIFT         5
-#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_MASK  0x1   /* cf6en */
-#define USTORM_ETH_CONN_AG_CTX_TX_BD_CONS_UPD_CF_EN_SHIFT 6
-#define USTORM_ETH_CONN_AG_CTX_RULE0EN_MASK               0x1   /* rule0en */
-#define USTORM_ETH_CONN_AG_CTX_RULE0EN_SHIFT              7
-       u8 flags3;
-#define USTORM_ETH_CONN_AG_CTX_RULE1EN_MASK               0x1   /* rule1en */
-#define USTORM_ETH_CONN_AG_CTX_RULE1EN_SHIFT              0
-#define USTORM_ETH_CONN_AG_CTX_RULE2EN_MASK               0x1   /* rule2en */
-#define USTORM_ETH_CONN_AG_CTX_RULE2EN_SHIFT              1
-#define USTORM_ETH_CONN_AG_CTX_RULE3EN_MASK               0x1   /* rule3en */
-#define USTORM_ETH_CONN_AG_CTX_RULE3EN_SHIFT              2
-#define USTORM_ETH_CONN_AG_CTX_RULE4EN_MASK               0x1   /* rule4en */
-#define USTORM_ETH_CONN_AG_CTX_RULE4EN_SHIFT              3
-#define USTORM_ETH_CONN_AG_CTX_RULE5EN_MASK               0x1   /* rule5en */
-#define USTORM_ETH_CONN_AG_CTX_RULE5EN_SHIFT              4
-#define USTORM_ETH_CONN_AG_CTX_RULE6EN_MASK               0x1   /* rule6en */
-#define USTORM_ETH_CONN_AG_CTX_RULE6EN_SHIFT              5
-#define USTORM_ETH_CONN_AG_CTX_RULE7EN_MASK               0x1   /* rule7en */
-#define USTORM_ETH_CONN_AG_CTX_RULE7EN_SHIFT              6
-#define USTORM_ETH_CONN_AG_CTX_RULE8EN_MASK               0x1   /* rule8en */
-#define USTORM_ETH_CONN_AG_CTX_RULE8EN_SHIFT              7
-       u8      byte2 /* byte2 */;
-       u8      byte3 /* byte3 */;
-       __le16  word0 /* conn_dpi */;
-       __le16  tx_bd_cons /* word1 */;
-       __le32  reg0 /* reg0 */;
-       __le32  reg1 /* reg1 */;
-       __le32  reg2 /* reg2 */;
-       __le32  reg3 /* reg3 */;
-       __le16  tx_drv_bd_cons /* word2 */;
-       __le16  rx_drv_cqe_cons /* word3 */;
-};
-
-struct xstorm_eth_hw_conn_ag_ctx {
-       u8      reserved0 /* cdu_validation */;
-       u8      eth_state /* state */;
-       u8      flags0;
-#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM0_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM0_SHIFT           0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED1_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED1_SHIFT              1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED2_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED2_SHIFT              2
-#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM3_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EXIST_IN_QM3_SHIFT           3
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED3_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED3_SHIFT              4
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED4_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED4_SHIFT              5
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED5_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED5_SHIFT              6
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED6_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED6_SHIFT              7
-       u8 flags1;
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED7_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED7_SHIFT              0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED8_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED8_SHIFT              1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED9_MASK               0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED9_SHIFT              2
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT11_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT11_SHIFT                  3
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT12_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT12_SHIFT                  4
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT13_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_BIT13_SHIFT                  5
-#define XSTORM_ETH_HW_CONN_AG_CTX_TX_RULE_ACTIVE_MASK          0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_TX_RULE_ACTIVE_SHIFT         6
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_ACTIVE_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT           7
-       u8 flags2;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF0_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF0_SHIFT                    0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF1_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF1_SHIFT                    2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF2_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF2_SHIFT                    4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF3_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF3_SHIFT                    6
-       u8 flags3;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF4_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF4_SHIFT                    0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF5_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF5_SHIFT                    2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF6_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF6_SHIFT                    4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF7_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF7_SHIFT                    6
-       u8 flags4;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF8_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF8_SHIFT                    0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF9_MASK                     0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF9_SHIFT                    2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF10_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF10_SHIFT                   4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF11_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF11_SHIFT                   6
-       u8 flags5;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF12_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF12_SHIFT                   0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF13_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF13_SHIFT                   2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF14_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF14_SHIFT                   4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF15_MASK                    0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF15_SHIFT                   6
-       u8 flags6;
-#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_MASK        0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_SHIFT       0
-#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_MASK        0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_SHIFT       2
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_MASK                   0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_SHIFT                  4
-#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_MASK            0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_SHIFT           6
-       u8 flags7;
-#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_MASK                0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_SHIFT               0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED10_MASK              0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED10_SHIFT             2
-#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_MASK               0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_SHIFT              4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF0EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF0EN_SHIFT                  6
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF1EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF1EN_SHIFT                  7
-       u8 flags8;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF2EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF2EN_SHIFT                  0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF3EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF3EN_SHIFT                  1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF4EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF4EN_SHIFT                  2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF5EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF5EN_SHIFT                  3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF6EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF6EN_SHIFT                  4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF7EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF7EN_SHIFT                  5
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF8EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF8EN_SHIFT                  6
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF9EN_MASK                   0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF9EN_SHIFT                  7
-       u8 flags9;
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF10EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF10EN_SHIFT                 0
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF11EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF11EN_SHIFT                 1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF12EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF12EN_SHIFT                 2
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF13EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF13EN_SHIFT                 3
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF14EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF14EN_SHIFT                 4
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF15EN_MASK                  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_CF15EN_SHIFT                 5
-#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_MASK     0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_GO_TO_BD_CONS_CF_EN_SHIFT    6
-#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_EN_MASK     0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_MULTI_UNICAST_CF_EN_SHIFT    7
-       u8 flags10;
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_DQ_CF_EN_SHIFT               0
-#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_EN_MASK         0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_TERMINATE_CF_EN_SHIFT        1
-#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_EN_MASK             0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT            2
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED11_MASK              0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED11_SHIFT             3
-#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_EN_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_SLOW_PATH_EN_SHIFT           4
-#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_MASK  0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_EN_RESERVED_SHIFT 5
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED12_MASK              0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED12_SHIFT             6
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED13_MASK              0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED13_SHIFT             7
-       u8 flags11;
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED14_MASK              0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED14_SHIFT             0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED15_MASK              0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RESERVED15_SHIFT             1
-#define XSTORM_ETH_HW_CONN_AG_CTX_TX_DEC_RULE_EN_MASK          0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_TX_DEC_RULE_EN_SHIFT         2
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE5EN_MASK                 0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE5EN_SHIFT                3
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE6EN_MASK                 0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE6EN_SHIFT                4
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE7EN_MASK                 0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE7EN_SHIFT                5
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED1_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED1_SHIFT           6
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE9EN_MASK                 0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE9EN_SHIFT                7
-       u8 flags12;
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE10EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE10EN_SHIFT               0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE11EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE11EN_SHIFT               1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED2_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED2_SHIFT           2
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED3_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED3_SHIFT           3
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE14EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE14EN_SHIFT               4
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE15EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE15EN_SHIFT               5
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE16EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE16EN_SHIFT               6
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE17EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE17EN_SHIFT               7
-       u8 flags13;
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE18EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE18EN_SHIFT               0
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE19EN_MASK                0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_RULE19EN_SHIFT               1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED4_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED4_SHIFT           2
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED5_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED5_SHIFT           3
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED6_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED6_SHIFT           4
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED7_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED7_SHIFT           5
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED8_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED8_SHIFT           6
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED9_MASK            0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_A0_RESERVED9_SHIFT           7
-       u8 flags14;
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_USE_EXT_HDR_MASK        0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_USE_EXT_HDR_SHIFT       0
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_MASK      0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_RAW_L3L4_SHIFT     1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_MASK    0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_INBAND_PROP_HDR_SHIFT   2
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_MASK    0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_EDPM_SEND_EXT_TUNNEL_SHIFT   3
-#define XSTORM_ETH_HW_CONN_AG_CTX_L2_EDPM_ENABLE_MASK          0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_L2_EDPM_ENABLE_SHIFT         4
-#define XSTORM_ETH_HW_CONN_AG_CTX_ROCE_EDPM_ENABLE_MASK        0x1
-#define XSTORM_ETH_HW_CONN_AG_CTX_ROCE_EDPM_ENABLE_SHIFT       5
-#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_MASK              0x3
-#define XSTORM_ETH_HW_CONN_AG_CTX_TPH_ENABLE_SHIFT             6
-       u8      edpm_event_id /* byte2 */;
-       __le16  physical_q0 /* physical_q0 */;
-       __le16  word1 /* physical_q1 */;
-       __le16  edpm_num_bds /* physical_q2 */;
-       __le16  tx_bd_cons /* word3 */;
-       __le16  tx_bd_prod /* word4 */;
-       __le16  go_to_bd_cons /* word5 */;
-       __le16  conn_dpi /* conn_dpi */;
-};
-
 #define VF_MAX_STATIC 192       /* In case of K2 */
 
 #define MCP_GLOB_PATH_MAX       2
@@ -3818,6 +3617,13 @@ struct public_port {
        struct dcbx_local_params                local_admin_dcbx_mib;
        struct dcbx_mib                         remote_dcbx_mib;
        struct dcbx_mib                         operational_dcbx_mib;
+
+       u32                                     fc_npiv_nvram_tbl_addr;
+       u32                                     fc_npiv_nvram_tbl_size;
+       u32                                     transceiver_data;
+#define PMM_TRANSCEIVER_STATE_MASK             0x000000FF
+#define PMM_TRANSCEIVER_STATE_SHIFT            0x00000000
+#define PMM_TRANSCEIVER_STATE_PRESENT          0x00000001
 };
 
 /**************************************/
@@ -3830,7 +3636,11 @@ struct public_func {
        u32     iscsi_boot_signature;
        u32     iscsi_boot_block_offset;
 
-       u32     reserved[8];
+       u32     mtu_size;
+       u32     c2s_pcp_map_lower;
+       u32     c2s_pcp_map_upper;
+       u32     c2s_pcp_map_default;
+       u32     reserved[4];
 
        u32     config;
 
@@ -3894,10 +3704,10 @@ struct public_func {
 #define DRV_ID_MCP_HSI_VER_SHIFT        16
 #define DRV_ID_MCP_HSI_VER_CURRENT     BIT(DRV_ID_MCP_HSI_VER_SHIFT)
 
-#define DRV_ID_DRV_TYPE_MASK            0xff000000
+#define DRV_ID_DRV_TYPE_MASK            0x7f000000
 #define DRV_ID_DRV_TYPE_SHIFT           24
 #define DRV_ID_DRV_TYPE_UNKNOWN         (0 << DRV_ID_DRV_TYPE_SHIFT)
-#define DRV_ID_DRV_TYPE_LINUX          BIT(DRV_ID_DRV_TYPE_SHIFT)
+#define DRV_ID_DRV_TYPE_LINUX           (1 << DRV_ID_DRV_TYPE_SHIFT)
 #define DRV_ID_DRV_TYPE_WINDOWS         (2 << DRV_ID_DRV_TYPE_SHIFT)
 #define DRV_ID_DRV_TYPE_DIAG            (3 << DRV_ID_DRV_TYPE_SHIFT)
 #define DRV_ID_DRV_TYPE_PREBOOT         (4 << DRV_ID_DRV_TYPE_SHIFT)
@@ -3905,6 +3715,10 @@ struct public_func {
 #define DRV_ID_DRV_TYPE_VMWARE          (6 << DRV_ID_DRV_TYPE_SHIFT)
 #define DRV_ID_DRV_TYPE_FREEBSD         (7 << DRV_ID_DRV_TYPE_SHIFT)
 #define DRV_ID_DRV_TYPE_AIX             (8 << DRV_ID_DRV_TYPE_SHIFT)
+
+#define DRV_ID_DRV_INIT_HW_MASK         0x80000000
+#define DRV_ID_DRV_INIT_HW_SHIFT        31
+#define DRV_ID_DRV_INIT_HW_FLAG         BIT(DRV_ID_DRV_INIT_HW_SHIFT)
 };
 
 /**************************************/
@@ -3964,6 +3778,7 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_MASK                       0xffff0000
 #define DRV_MSG_CODE_LOAD_REQ                   0x10000000
 #define DRV_MSG_CODE_LOAD_DONE                  0x11000000
+#define DRV_MSG_CODE_INIT_HW                    0x12000000
 #define DRV_MSG_CODE_UNLOAD_REQ                 0x20000000
 #define DRV_MSG_CODE_UNLOAD_DONE                0x21000000
 #define DRV_MSG_CODE_INIT_PHY                   0x22000000
@@ -4100,6 +3915,7 @@ struct public_drv_mb {
 #define FW_MSG_CODE_SET_SECURE_MODE_ERROR       0x00130000
 #define FW_MSG_CODE_SET_SECURE_MODE_OK          0x00140000
 #define FW_MSG_MODE_PHY_PRIVILEGE_ERROR         0x00150000
+#define FW_MSG_CODE_OK                          0x00160000
 
 #define FW_MSG_SEQ_NUMBER_MASK                  0x0000ffff
 
@@ -4142,6 +3958,14 @@ enum MFW_DRV_MSG_TYPE {
        MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED,
        MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED,
        MFW_DRV_MSG_ERROR_RECOVERY,
+       MFW_DRV_MSG_BW_UPDATE,
+       MFW_DRV_MSG_S_TAG_UPDATE,
+       MFW_DRV_MSG_GET_LAN_STATS,
+       MFW_DRV_MSG_GET_FCOE_STATS,
+       MFW_DRV_MSG_GET_ISCSI_STATS,
+       MFW_DRV_MSG_GET_RDMA_STATS,
+       MFW_DRV_MSG_FAILURE_DETECTED,
+       MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE,
        MFW_DRV_MSG_MAX
 };
 
@@ -4212,7 +4036,7 @@ struct nvm_cfg1_glob {
 #define NVM_CFG1_GLOB_MF_MODE_MASK                              0x00000FF0
 #define NVM_CFG1_GLOB_MF_MODE_OFFSET                            4
 #define NVM_CFG1_GLOB_MF_MODE_MF_ALLOWED                        0x0
-#define NVM_CFG1_GLOB_MF_MODE_FORCED_SF                         0x1
+#define NVM_CFG1_GLOB_MF_MODE_DEFAULT                           0x1
 #define NVM_CFG1_GLOB_MF_MODE_SPIO4                             0x2
 #define NVM_CFG1_GLOB_MF_MODE_NPAR1_0                           0x3
 #define NVM_CFG1_GLOB_MF_MODE_NPAR1_5                           0x4
@@ -4643,8 +4467,12 @@ struct nvm_cfg1_glob {
 #define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO29                  0x1E
 #define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO30                  0x1F
 #define NVM_CFG1_GLOB_I2C_MUX_SEL_GPIO__GPIO31                  0x20
-
-       u32 reserved[46];                                       /* 0x88 */
+       u32     device_capabilities;                            /* 0x88 */
+#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET              0x1
+       u32     power_dissipated;                               /* 0x8C */
+       u32 power_consumed;                                     /* 0x90 */
+       u32     efi_version;                                    /* 0x94 */
+       u32     reserved[42];                                   /* 0x98 */
 };
 
 struct nvm_cfg1_path {
@@ -4652,26 +4480,8 @@ struct nvm_cfg1_path {
 };
 
 struct nvm_cfg1_port {
-       u32 power_dissipated;                                   /* 0x0 */
-#define NVM_CFG1_PORT_POWER_DIS_D0_MASK                         0x000000FF
-#define NVM_CFG1_PORT_POWER_DIS_D0_OFFSET                       0
-#define NVM_CFG1_PORT_POWER_DIS_D1_MASK                         0x0000FF00
-#define NVM_CFG1_PORT_POWER_DIS_D1_OFFSET                       8
-#define NVM_CFG1_PORT_POWER_DIS_D2_MASK                         0x00FF0000
-#define NVM_CFG1_PORT_POWER_DIS_D2_OFFSET                       16
-#define NVM_CFG1_PORT_POWER_DIS_D3_MASK                         0xFF000000
-#define NVM_CFG1_PORT_POWER_DIS_D3_OFFSET                       24
-
-       u32 power_consumed;                                     /* 0x4 */
-#define NVM_CFG1_PORT_POWER_CONS_D0_MASK                        0x000000FF
-#define NVM_CFG1_PORT_POWER_CONS_D0_OFFSET                      0
-#define NVM_CFG1_PORT_POWER_CONS_D1_MASK                        0x0000FF00
-#define NVM_CFG1_PORT_POWER_CONS_D1_OFFSET                      8
-#define NVM_CFG1_PORT_POWER_CONS_D2_MASK                        0x00FF0000
-#define NVM_CFG1_PORT_POWER_CONS_D2_OFFSET                      16
-#define NVM_CFG1_PORT_POWER_CONS_D3_MASK                        0xFF000000
-#define NVM_CFG1_PORT_POWER_CONS_D3_OFFSET                      24
-
+       u32     reserved__m_relocated_to_option_123;           /* 0x0 */
+       u32     reserved__m_relocated_to_option_124;           /* 0x4 */
        u32 generic_cont0;                                      /* 0x8 */
 #define NVM_CFG1_PORT_LED_MODE_MASK                             0x000000FF
 #define NVM_CFG1_PORT_LED_MODE_OFFSET                           0
@@ -4699,7 +4509,9 @@ struct nvm_cfg1_port {
 #define NVM_CFG1_PORT_DCBX_MODE_IEEE                            0x1
 #define NVM_CFG1_PORT_DCBX_MODE_CEE                             0x2
 #define NVM_CFG1_PORT_DCBX_MODE_DYNAMIC                         0x3
-
+#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_MASK            0x00F00000
+#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_OFFSET          20
+#define NVM_CFG1_PORT_DEFAULT_ENABLED_PROTOCOLS_ETHERNET        0x1
        u32     pcie_cfg;                                       /* 0xC */
 #define NVM_CFG1_PORT_RESERVED15_MASK                           0x00000007
 #define NVM_CFG1_PORT_RESERVED15_OFFSET                         0
@@ -4784,10 +4596,11 @@ struct nvm_cfg1_port {
 #define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SFI                  0x9
 #define NVM_CFG1_PORT_SERDES_NET_INTERFACE_1000X                0xB
 #define NVM_CFG1_PORT_SERDES_NET_INTERFACE_SGMII                0xC
-#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLAUI                0xD
-#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CAUI                 0xE
-#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLPPI                0xF
-#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CPPI                 0x10
+#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLAUI                0x11
+#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_XLPPI                0x12
+#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CAUI                 0x21
+#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_CPPI                 0x22
+#define NVM_CFG1_PORT_SERDES_NET_INTERFACE_25GAUI               0x31
 #define NVM_CFG1_PORT_AN_MODE_MASK                              0xFF000000
 #define NVM_CFG1_PORT_AN_MODE_OFFSET                            24
 #define NVM_CFG1_PORT_AN_MODE_NONE                              0x0
@@ -4801,9 +4614,6 @@ struct nvm_cfg1_port {
        u32 mgmt_traffic;                                       /* 0x20 */
 #define NVM_CFG1_PORT_RESERVED61_MASK                           0x0000000F
 #define NVM_CFG1_PORT_RESERVED61_OFFSET                         0
-#define NVM_CFG1_PORT_RESERVED61_DISABLED                       0x0
-#define NVM_CFG1_PORT_RESERVED61_NCSI_OVER_RMII                 0x1
-#define NVM_CFG1_PORT_RESERVED61_NCSI_OVER_SMBUS                0x2
 
        u32 ext_phy;                                            /* 0x24 */
 #define NVM_CFG1_PORT_EXTERNAL_PHY_TYPE_MASK                    0x000000FF
@@ -4814,16 +4624,12 @@ struct nvm_cfg1_port {
 #define NVM_CFG1_PORT_EXTERNAL_PHY_ADDRESS_OFFSET               8
 
        u32 mba_cfg1;                                           /* 0x28 */
-#define NVM_CFG1_PORT_MBA_MASK                                  0x00000001
-#define NVM_CFG1_PORT_MBA_OFFSET                                0
-#define NVM_CFG1_PORT_MBA_DISABLED                              0x0
-#define NVM_CFG1_PORT_MBA_ENABLED                               0x1
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_MASK                        0x00000006
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_OFFSET                      1
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_AUTO                        0x0
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_BBS                         0x1
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_INT18H                      0x2
-#define NVM_CFG1_PORT_MBA_BOOT_TYPE_INT19H                      0x3
+#define NVM_CFG1_PORT_PREBOOT_OPROM_MASK                        0x00000001
+#define NVM_CFG1_PORT_PREBOOT_OPROM_OFFSET                      0
+#define NVM_CFG1_PORT_PREBOOT_OPROM_DISABLED                    0x0
+#define NVM_CFG1_PORT_PREBOOT_OPROM_ENABLED                     0x1
+#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_TYPE_MASK            0x00000006
+#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_TYPE_OFFSET          1
 #define NVM_CFG1_PORT_MBA_DELAY_TIME_MASK                       0x00000078
 #define NVM_CFG1_PORT_MBA_DELAY_TIME_OFFSET                     3
 #define NVM_CFG1_PORT_MBA_SETUP_HOT_KEY_MASK                    0x00000080
@@ -4836,61 +4642,30 @@ struct nvm_cfg1_port {
 #define NVM_CFG1_PORT_MBA_HIDE_SETUP_PROMPT_ENABLED             0x1
 #define NVM_CFG1_PORT_RESERVED5_MASK                            0x0001FE00
 #define NVM_CFG1_PORT_RESERVED5_OFFSET                          9
-#define NVM_CFG1_PORT_RESERVED5_DISABLED                        0x0
-#define NVM_CFG1_PORT_RESERVED5_2K                              0x1
-#define NVM_CFG1_PORT_RESERVED5_4K                              0x2
-#define NVM_CFG1_PORT_RESERVED5_8K                              0x3
-#define NVM_CFG1_PORT_RESERVED5_16K                             0x4
-#define NVM_CFG1_PORT_RESERVED5_32K                             0x5
-#define NVM_CFG1_PORT_RESERVED5_64K                             0x6
-#define NVM_CFG1_PORT_RESERVED5_128K                            0x7
-#define NVM_CFG1_PORT_RESERVED5_256K                            0x8
-#define NVM_CFG1_PORT_RESERVED5_512K                            0x9
-#define NVM_CFG1_PORT_RESERVED5_1M                              0xA
-#define NVM_CFG1_PORT_RESERVED5_2M                              0xB
-#define NVM_CFG1_PORT_RESERVED5_4M                              0xC
-#define NVM_CFG1_PORT_RESERVED5_8M                              0xD
-#define NVM_CFG1_PORT_RESERVED5_16M                             0xE
-#define NVM_CFG1_PORT_RESERVED5_32M                             0xF
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_MASK                       0x001E0000
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_OFFSET                     17
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_AUTONEG                    0x0
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_1G                         0x1
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_10G                        0x2
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_25G                        0x4
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_40G                        0x5
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_50G                        0x6
-#define NVM_CFG1_PORT_MBA_LINK_SPEED_100G                       0x7
-#define NVM_CFG1_PORT_MBA_BOOT_RETRY_COUNT_MASK                 0x00E00000
-#define NVM_CFG1_PORT_MBA_BOOT_RETRY_COUNT_OFFSET               21
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_MASK                   0x001E0000
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_OFFSET                 17
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_AUTONEG                0x0
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_1G                     0x1
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_10G                    0x2
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_25G                    0x4
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_40G                    0x5
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_50G                    0x6
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_100G                   0x7
+#define NVM_CFG1_PORT_PREBOOT_LINK_SPEED_SMARTLINQ              0x8
+#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_RETRY_COUNT_MASK     0x00E00000
+#define NVM_CFG1_PORT_RESERVED__M_MBA_BOOT_RETRY_COUNT_OFFSET   21
 
        u32     mba_cfg2;                                       /* 0x2C */
-#define NVM_CFG1_PORT_MBA_VLAN_VALUE_MASK                       0x0000FFFF
-#define NVM_CFG1_PORT_MBA_VLAN_VALUE_OFFSET                     0
-#define NVM_CFG1_PORT_MBA_VLAN_MASK                             0x00010000
-#define NVM_CFG1_PORT_MBA_VLAN_OFFSET                           16
+#define NVM_CFG1_PORT_RESERVED65_MASK                           0x0000FFFF
+#define NVM_CFG1_PORT_RESERVED65_OFFSET                         0
+#define NVM_CFG1_PORT_RESERVED66_MASK                           0x00010000
+#define NVM_CFG1_PORT_RESERVED66_OFFSET                         16
 
        u32     vf_cfg;                                         /* 0x30 */
 #define NVM_CFG1_PORT_RESERVED8_MASK                            0x0000FFFF
 #define NVM_CFG1_PORT_RESERVED8_OFFSET                          0
 #define NVM_CFG1_PORT_RESERVED6_MASK                            0x000F0000
 #define NVM_CFG1_PORT_RESERVED6_OFFSET                          16
-#define NVM_CFG1_PORT_RESERVED6_DISABLED                        0x0
-#define NVM_CFG1_PORT_RESERVED6_4K                              0x1
-#define NVM_CFG1_PORT_RESERVED6_8K                              0x2
-#define NVM_CFG1_PORT_RESERVED6_16K                             0x3
-#define NVM_CFG1_PORT_RESERVED6_32K                             0x4
-#define NVM_CFG1_PORT_RESERVED6_64K                             0x5
-#define NVM_CFG1_PORT_RESERVED6_128K                            0x6
-#define NVM_CFG1_PORT_RESERVED6_256K                            0x7
-#define NVM_CFG1_PORT_RESERVED6_512K                            0x8
-#define NVM_CFG1_PORT_RESERVED6_1M                              0x9
-#define NVM_CFG1_PORT_RESERVED6_2M                              0xA
-#define NVM_CFG1_PORT_RESERVED6_4M                              0xB
-#define NVM_CFG1_PORT_RESERVED6_8M                              0xC
-#define NVM_CFG1_PORT_RESERVED6_16M                             0xD
-#define NVM_CFG1_PORT_RESERVED6_32M                             0xE
-#define NVM_CFG1_PORT_RESERVED6_64M                             0xF
 
        struct nvm_cfg_mac_address      lldp_mac_address;       /* 0x34 */
 
@@ -4973,18 +4748,16 @@ struct nvm_cfg1_func {
        u32                             device_id;              /* 0x10 */
 #define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_MASK                  0x0000FFFF
 #define NVM_CFG1_FUNC_MF_VENDOR_DEVICE_ID_OFFSET                0
-#define NVM_CFG1_FUNC_VENDOR_DEVICE_ID_MASK                     0xFFFF0000
-#define NVM_CFG1_FUNC_VENDOR_DEVICE_ID_OFFSET                   16
+#define NVM_CFG1_FUNC_RESERVED77_MASK                           0xFFFF0000
+#define NVM_CFG1_FUNC_RESERVED77_OFFSET                         16
 
        u32                             cmn_cfg;                /* 0x14 */
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_MASK                    0x00000007
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_OFFSET                  0
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_PXE                     0x0
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_RPL                     0x1
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_BOOTP                   0x2
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_ISCSI_BOOT              0x3
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_FCOE_BOOT               0x4
-#define NVM_CFG1_FUNC_MBA_BOOT_PROTOCOL_NONE                    0x7
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_MASK                0x00000007
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_OFFSET              0
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_PXE                 0x0
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_ISCSI_BOOT          0x3
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_FCOE_BOOT           0x4
+#define NVM_CFG1_FUNC_PREBOOT_BOOT_PROTOCOL_NONE                0x7
 #define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_MASK                     0x0007FFF8
 #define NVM_CFG1_FUNC_VF_PCI_DEVICE_ID_OFFSET                   3
 #define NVM_CFG1_FUNC_PERSONALITY_MASK                          0x00780000
@@ -5029,8 +4802,8 @@ struct nvm_cfg1_func {
        struct nvm_cfg_mac_address      fcoe_node_wwn_mac_addr; /* 0x1C */
 
        struct nvm_cfg_mac_address      fcoe_port_wwn_mac_addr; /* 0x24 */
-
-       u32                             reserved[9];            /* 0x2C */
+       u32                             preboot_generic_cfg;    /* 0x2C */
+       u32                             reserved[8];            /* 0x30 */
 };
 
 struct nvm_cfg1 {
index ffa99273b3533ab372f870c0f5afbbcb9fec03d8..a95a3e4b31011afa937296662ebcf328b0b53cbb 100644 (file)
@@ -44,7 +44,7 @@ struct qed_ptt_pool {
 int qed_ptt_pool_alloc(struct qed_hwfn *p_hwfn)
 {
        struct qed_ptt_pool *p_pool = kmalloc(sizeof(*p_pool),
-                                             GFP_ATOMIC);
+                                             GFP_KERNEL);
        int i;
 
        if (!p_pool)
index 0b21a553cc7d5fccc90878943fe23826028c0a84..f55ebdc3c8322ac5255ba779beadcdee25e3e309 100644 (file)
@@ -513,17 +513,14 @@ static int qed_pf_rl_rt_init(struct qed_hwfn *p_hwfn,
  * Return -1 on error.
  */
 static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn,
-                             u8 start_vport,
                              u8 num_vports,
                              struct init_qm_vport_params *vport_params)
 {
-       u8 tc, i, vport_id;
        u32 inc_val;
+       u8 tc, i;
 
        /* go over all PF VPORTs */
-       for (i = 0, vport_id = start_vport; i < num_vports; i++, vport_id++) {
-               u32 temp = QM_REG_WFQVPUPPERBOUND_RT_OFFSET;
-               u16 *pq_ids = &vport_params[i].first_tx_pq_id[0];
+       for (i = 0; i < num_vports; i++) {
 
                if (!vport_params[i].vport_wfq)
                        continue;
@@ -539,20 +536,16 @@ static int qed_vp_wfq_rt_init(struct qed_hwfn *p_hwfn,
                 * different TCs
                 */
                for (tc = 0; tc < NUM_OF_TCS; tc++) {
-                       u16 vport_pq_id = pq_ids[tc];
+                       u16 vport_pq_id = vport_params[i].first_tx_pq_id[tc];
 
                        if (vport_pq_id != QM_INVALID_PQ_ID) {
-                               STORE_RT_REG(p_hwfn,
-                                            QM_REG_WFQVPWEIGHT_RT_OFFSET +
-                                            vport_pq_id, inc_val);
-                               STORE_RT_REG(p_hwfn, temp + vport_pq_id,
-                                            QM_WFQ_UPPER_BOUND |
-                                            QM_WFQ_CRD_REG_SIGN_BIT);
                                STORE_RT_REG(p_hwfn,
                                             QM_REG_WFQVPCRD_RT_OFFSET +
                                             vport_pq_id,
-                                            QM_WFQ_INIT_CRD(inc_val) |
                                             QM_WFQ_CRD_REG_SIGN_BIT);
+                               STORE_RT_REG(p_hwfn,
+                                            QM_REG_WFQVPWEIGHT_RT_OFFSET +
+                                            vport_pq_id, inc_val);
                        }
                }
        }
@@ -709,8 +702,7 @@ int qed_qm_pf_rt_init(struct qed_hwfn *p_hwfn,
        if (qed_pf_rl_rt_init(p_hwfn, p_params->pf_id, p_params->pf_rl))
                return -1;
 
-       if (qed_vp_wfq_rt_init(p_hwfn, p_params->start_vport,
-                              p_params->num_vports, vport_params))
+       if (qed_vp_wfq_rt_init(p_hwfn, p_params->num_vports, vport_params))
                return -1;
 
        if (qed_vport_rl_rt_init(p_hwfn, p_params->start_vport,
index 796f1390e598338a25e96f95d61e3f522425d348..3269b3610e03993aab05ef197834775fbbb558a9 100644 (file)
@@ -55,63 +55,98 @@ void qed_init_clear_rt_data(struct qed_hwfn *p_hwfn)
        int i;
 
        for (i = 0; i < RUNTIME_ARRAY_SIZE; i++)
-               p_hwfn->rt_data[i].b_valid = false;
+               p_hwfn->rt_data.b_valid[i] = false;
 }
 
 void qed_init_store_rt_reg(struct qed_hwfn *p_hwfn,
                           u32 rt_offset,
                           u32 val)
 {
-       p_hwfn->rt_data[rt_offset].init_val = val;
-       p_hwfn->rt_data[rt_offset].b_valid = true;
+       p_hwfn->rt_data.init_val[rt_offset] = val;
+       p_hwfn->rt_data.b_valid[rt_offset] = true;
 }
 
 void qed_init_store_rt_agg(struct qed_hwfn *p_hwfn,
-                          u32 rt_offset,
-                          u32 *val,
+                          u32 rt_offset, u32 *p_val,
                           size_t size)
 {
        size_t i;
 
        for (i = 0; i < size / sizeof(u32); i++) {
-               p_hwfn->rt_data[rt_offset + i].init_val = val[i];
-               p_hwfn->rt_data[rt_offset + i].b_valid = true;
+               p_hwfn->rt_data.init_val[rt_offset + i] = p_val[i];
+               p_hwfn->rt_data.b_valid[rt_offset + i]  = true;
        }
 }
 
-static void qed_init_rt(struct qed_hwfn *p_hwfn,
-                       struct qed_ptt *p_ptt,
-                       u32 addr,
-                       u32 rt_offset,
-                       u32 size)
+static int qed_init_rt(struct qed_hwfn *p_hwfn,
+                      struct qed_ptt *p_ptt,
+                      u32 addr,
+                      u16 rt_offset,
+                      u16 size,
+                      bool b_must_dmae)
 {
-       struct qed_rt_data *rt_data = p_hwfn->rt_data + rt_offset;
-       u32 i;
+       u32 *p_init_val = &p_hwfn->rt_data.init_val[rt_offset];
+       bool *p_valid = &p_hwfn->rt_data.b_valid[rt_offset];
+       u16 i, segment;
+       int rc = 0;
 
+       /* Since not all RT entries are initialized, go over the RT and
+        * for each segment of initialized values use DMA.
+        */
        for (i = 0; i < size; i++) {
-               if (!rt_data[i].b_valid)
+               if (!p_valid[i])
                        continue;
-               qed_wr(p_hwfn, p_ptt, addr + (i << 2), rt_data[i].init_val);
+
+               /* In case there isn't any wide-bus configuration here,
+                * simply write the data instead of using dmae.
+                */
+               if (!b_must_dmae) {
+                       qed_wr(p_hwfn, p_ptt, addr + (i << 2),
+                              p_init_val[i]);
+                       continue;
+               }
+
+               /* Start of a new segment */
+               for (segment = 1; i + segment < size; segment++)
+                       if (!p_valid[i + segment])
+                               break;
+
+               rc = qed_dmae_host2grc(p_hwfn, p_ptt,
+                                      (uintptr_t)(p_init_val + i),
+                                      addr + (i << 2), segment, 0);
+               if (rc != 0)
+                       return rc;
+
+               /* Jump over the entire segment, including invalid entry */
+               i += segment;
        }
+
+       return rc;
 }
 
 int qed_init_alloc(struct qed_hwfn *p_hwfn)
 {
-       struct qed_rt_data *rt_data;
+       struct qed_rt_data *rt_data = &p_hwfn->rt_data;
 
-       rt_data = kzalloc(sizeof(*rt_data) * RUNTIME_ARRAY_SIZE, GFP_ATOMIC);
-       if (!rt_data)
+       rt_data->b_valid = kzalloc(sizeof(bool) * RUNTIME_ARRAY_SIZE,
+                                  GFP_KERNEL);
+       if (!rt_data->b_valid)
                return -ENOMEM;
 
-       p_hwfn->rt_data = rt_data;
+       rt_data->init_val = kzalloc(sizeof(u32) * RUNTIME_ARRAY_SIZE,
+                                   GFP_KERNEL);
+       if (!rt_data->init_val) {
+               kfree(rt_data->b_valid);
+               return -ENOMEM;
+       }
 
        return 0;
 }
 
 void qed_init_free(struct qed_hwfn *p_hwfn)
 {
-       kfree(p_hwfn->rt_data);
-       p_hwfn->rt_data = NULL;
+       kfree(p_hwfn->rt_data.init_val);
+       kfree(p_hwfn->rt_data.b_valid);
 }
 
 static int qed_init_array_dmae(struct qed_hwfn *p_hwfn,
@@ -289,7 +324,8 @@ static int qed_init_cmd_wr(struct qed_hwfn *p_hwfn,
        case INIT_SRC_RUNTIME:
                qed_init_rt(p_hwfn, p_ptt, addr,
                            le16_to_cpu(arg->runtime.offset),
-                           le16_to_cpu(arg->runtime.size));
+                           le16_to_cpu(arg->runtime.size),
+                           b_must_dmae);
                break;
        }
 
@@ -316,49 +352,50 @@ static void qed_init_cmd_rd(struct qed_hwfn *p_hwfn,
                            struct qed_ptt *p_ptt,
                            struct init_read_op *cmd)
 {
-       u32 data = le32_to_cpu(cmd->op_data);
-       u32 addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2;
+       bool (*comp_check)(u32 val, u32 expected_val);
+       u32 delay = QED_INIT_POLL_PERIOD_US, val;
+       u32 data, addr, poll;
+       int i;
+
+       data = le32_to_cpu(cmd->op_data);
+       addr = GET_FIELD(data, INIT_READ_OP_ADDRESS) << 2;
+       poll = GET_FIELD(data, INIT_READ_OP_POLL_TYPE);
 
-       bool    (*comp_check)(u32       val,
-                             u32       expected_val);
-       u32     delay = QED_INIT_POLL_PERIOD_US, val;
 
        val = qed_rd(p_hwfn, p_ptt, addr);
 
-       data = le32_to_cpu(cmd->op_data);
-       if (GET_FIELD(data, INIT_READ_OP_POLL)) {
-               int i;
+       if (poll == INIT_POLL_NONE)
+               return;
 
-               switch (GET_FIELD(data, INIT_READ_OP_POLL_COMP)) {
-               case INIT_COMPARISON_EQ:
-                       comp_check = comp_eq;
-                       break;
-               case INIT_COMPARISON_OR:
-                       comp_check = comp_or;
-                       break;
-               case INIT_COMPARISON_AND:
-                       comp_check = comp_and;
-                       break;
-               default:
-                       comp_check = NULL;
-                       DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n",
-                              data);
-                       return;
-               }
+       switch (poll) {
+       case INIT_POLL_EQ:
+               comp_check = comp_eq;
+               break;
+       case INIT_POLL_OR:
+               comp_check = comp_or;
+               break;
+       case INIT_POLL_AND:
+               comp_check = comp_and;
+               break;
+       default:
+               DP_ERR(p_hwfn, "Invalid poll comparison type %08x\n",
+                      cmd->op_data);
+               return;
+       }
 
-               for (i = 0;
-                    i < QED_INIT_MAX_POLL_COUNT &&
-                    !comp_check(val, le32_to_cpu(cmd->expected_val));
-                    i++) {
-                       udelay(delay);
-                       val = qed_rd(p_hwfn, p_ptt, addr);
-               }
+       data = le32_to_cpu(cmd->expected_val);
+       for (i = 0;
+            i < QED_INIT_MAX_POLL_COUNT && !comp_check(val, data);
+            i++) {
+               udelay(delay);
+               val = qed_rd(p_hwfn, p_ptt, addr);
+       }
 
-               if (i == QED_INIT_MAX_POLL_COUNT)
-                       DP_ERR(p_hwfn,
-                              "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparsion %08x)]\n",
-                              addr, le32_to_cpu(cmd->expected_val),
-                              val, data);
+       if (i == QED_INIT_MAX_POLL_COUNT) {
+               DP_ERR(p_hwfn,
+                      "Timeout when polling reg: 0x%08x [ Waiting-for: %08x Got: %08x (comparsion %08x)]\n",
+                      addr, le32_to_cpu(cmd->expected_val),
+                      val, le32_to_cpu(cmd->op_data));
        }
 }
 
index 9cc9d62c1fec64844eba85ca10213a77d3158227..ffd0accc2ec9efcac9a124401ef88a85dcffe99c 100644 (file)
@@ -39,24 +39,1737 @@ struct qed_sb_sp_info {
        struct qed_pi_info      pi_info_arr[PIS_PER_SB];
 };
 
+enum qed_attention_type {
+       QED_ATTN_TYPE_ATTN,
+       QED_ATTN_TYPE_PARITY,
+};
+
 #define SB_ATTN_ALIGNED_SIZE(p_hwfn) \
        ALIGNED_TYPE_SIZE(struct atten_status_block, p_hwfn)
 
-#define ATTN_STATE_BITS (0xfff)
+struct aeu_invert_reg_bit {
+       char bit_name[30];
+
+#define ATTENTION_PARITY                (1 << 0)
+
+#define ATTENTION_LENGTH_MASK           (0x00000ff0)
+#define ATTENTION_LENGTH_SHIFT          (4)
+#define ATTENTION_LENGTH(flags)         (((flags) & ATTENTION_LENGTH_MASK) >> \
+                                        ATTENTION_LENGTH_SHIFT)
+#define ATTENTION_SINGLE                (1 << ATTENTION_LENGTH_SHIFT)
+#define ATTENTION_PAR                   (ATTENTION_SINGLE | ATTENTION_PARITY)
+#define ATTENTION_PAR_INT               ((2 << ATTENTION_LENGTH_SHIFT) | \
+                                        ATTENTION_PARITY)
+
+/* Multiple bits start with this offset */
+#define ATTENTION_OFFSET_MASK           (0x000ff000)
+#define ATTENTION_OFFSET_SHIFT          (12)
+       unsigned int flags;
+
+       /* Callback to call if attention will be triggered */
+       int (*cb)(struct qed_hwfn *p_hwfn);
+
+       enum block_id block_index;
+};
+
+struct aeu_invert_reg {
+       struct aeu_invert_reg_bit bits[32];
+};
+
+#define MAX_ATTN_GRPS           (8)
+#define NUM_ATTN_REGS           (9)
+
+/* HW Attention register */
+struct attn_hw_reg {
+       u16 reg_idx;             /* Index of this register in its block */
+       u16 num_of_bits;         /* number of valid attention bits */
+       u32 sts_addr;            /* Address of the STS register */
+       u32 sts_clr_addr;        /* Address of the STS_CLR register */
+       u32 sts_wr_addr;         /* Address of the STS_WR register */
+       u32 mask_addr;           /* Address of the MASK register */
+};
+
+/* HW block attention registers */
+struct attn_hw_regs {
+       u16 num_of_int_regs;            /* Number of interrupt regs */
+       u16 num_of_prty_regs;           /* Number of parity regs */
+       struct attn_hw_reg **int_regs;  /* interrupt regs */
+       struct attn_hw_reg **prty_regs; /* parity regs */
+};
+
+/* HW block attention registers */
+struct attn_hw_block {
+       const char *name;                 /* Block name */
+       struct attn_hw_regs chip_regs[1];
+};
+
+static struct attn_hw_reg grc_int0_bb_b0 = {
+       0, 4, 0x50180, 0x5018c, 0x50188, 0x50184};
+
+static struct attn_hw_reg *grc_int_bb_b0_regs[1] = {
+       &grc_int0_bb_b0};
+
+static struct attn_hw_reg grc_prty1_bb_b0 = {
+       0, 2, 0x50200, 0x5020c, 0x50208, 0x50204};
+
+static struct attn_hw_reg *grc_prty_bb_b0_regs[1] = {
+       &grc_prty1_bb_b0};
+
+static struct attn_hw_reg miscs_int0_bb_b0 = {
+       0, 3, 0x9180, 0x918c, 0x9188, 0x9184};
+
+static struct attn_hw_reg miscs_int1_bb_b0 = {
+       1, 11, 0x9190, 0x919c, 0x9198, 0x9194};
+
+static struct attn_hw_reg *miscs_int_bb_b0_regs[2] = {
+       &miscs_int0_bb_b0, &miscs_int1_bb_b0};
+
+static struct attn_hw_reg miscs_prty0_bb_b0 = {
+       0, 1, 0x91a0, 0x91ac, 0x91a8, 0x91a4};
+
+static struct attn_hw_reg *miscs_prty_bb_b0_regs[1] = {
+       &miscs_prty0_bb_b0};
+
+static struct attn_hw_reg misc_int0_bb_b0 = {
+       0, 1, 0x8180, 0x818c, 0x8188, 0x8184};
+
+static struct attn_hw_reg *misc_int_bb_b0_regs[1] = {
+       &misc_int0_bb_b0};
+
+static struct attn_hw_reg pglue_b_int0_bb_b0 = {
+       0, 23, 0x2a8180, 0x2a818c, 0x2a8188, 0x2a8184};
+
+static struct attn_hw_reg *pglue_b_int_bb_b0_regs[1] = {
+       &pglue_b_int0_bb_b0};
+
+static struct attn_hw_reg pglue_b_prty0_bb_b0 = {
+       0, 1, 0x2a8190, 0x2a819c, 0x2a8198, 0x2a8194};
+
+static struct attn_hw_reg pglue_b_prty1_bb_b0 = {
+       1, 22, 0x2a8200, 0x2a820c, 0x2a8208, 0x2a8204};
+
+static struct attn_hw_reg *pglue_b_prty_bb_b0_regs[2] = {
+       &pglue_b_prty0_bb_b0, &pglue_b_prty1_bb_b0};
+
+static struct attn_hw_reg cnig_int0_bb_b0 = {
+       0, 6, 0x2182e8, 0x2182f4, 0x2182f0, 0x2182ec};
+
+static struct attn_hw_reg *cnig_int_bb_b0_regs[1] = {
+       &cnig_int0_bb_b0};
+
+static struct attn_hw_reg cnig_prty0_bb_b0 = {
+       0, 2, 0x218348, 0x218354, 0x218350, 0x21834c};
+
+static struct attn_hw_reg *cnig_prty_bb_b0_regs[1] = {
+       &cnig_prty0_bb_b0};
+
+static struct attn_hw_reg cpmu_int0_bb_b0 = {
+       0, 1, 0x303e0, 0x303ec, 0x303e8, 0x303e4};
+
+static struct attn_hw_reg *cpmu_int_bb_b0_regs[1] = {
+       &cpmu_int0_bb_b0};
+
+static struct attn_hw_reg ncsi_int0_bb_b0 = {
+       0, 1, 0x404cc, 0x404d8, 0x404d4, 0x404d0};
+
+static struct attn_hw_reg *ncsi_int_bb_b0_regs[1] = {
+       &ncsi_int0_bb_b0};
+
+static struct attn_hw_reg ncsi_prty1_bb_b0 = {
+       0, 1, 0x40000, 0x4000c, 0x40008, 0x40004};
+
+static struct attn_hw_reg *ncsi_prty_bb_b0_regs[1] = {
+       &ncsi_prty1_bb_b0};
+
+static struct attn_hw_reg opte_prty1_bb_b0 = {
+       0, 11, 0x53000, 0x5300c, 0x53008, 0x53004};
+
+static struct attn_hw_reg opte_prty0_bb_b0 = {
+       1, 1, 0x53208, 0x53214, 0x53210, 0x5320c};
+
+static struct attn_hw_reg *opte_prty_bb_b0_regs[2] = {
+       &opte_prty1_bb_b0, &opte_prty0_bb_b0};
+
+static struct attn_hw_reg bmb_int0_bb_b0 = {
+       0, 16, 0x5400c0, 0x5400cc, 0x5400c8, 0x5400c4};
+
+static struct attn_hw_reg bmb_int1_bb_b0 = {
+       1, 28, 0x5400d8, 0x5400e4, 0x5400e0, 0x5400dc};
+
+static struct attn_hw_reg bmb_int2_bb_b0 = {
+       2, 26, 0x5400f0, 0x5400fc, 0x5400f8, 0x5400f4};
+
+static struct attn_hw_reg bmb_int3_bb_b0 = {
+       3, 31, 0x540108, 0x540114, 0x540110, 0x54010c};
+
+static struct attn_hw_reg bmb_int4_bb_b0 = {
+       4, 27, 0x540120, 0x54012c, 0x540128, 0x540124};
+
+static struct attn_hw_reg bmb_int5_bb_b0 = {
+       5, 29, 0x540138, 0x540144, 0x540140, 0x54013c};
+
+static struct attn_hw_reg bmb_int6_bb_b0 = {
+       6, 30, 0x540150, 0x54015c, 0x540158, 0x540154};
+
+static struct attn_hw_reg bmb_int7_bb_b0 = {
+       7, 32, 0x540168, 0x540174, 0x540170, 0x54016c};
+
+static struct attn_hw_reg bmb_int8_bb_b0 = {
+       8, 32, 0x540184, 0x540190, 0x54018c, 0x540188};
+
+static struct attn_hw_reg bmb_int9_bb_b0 = {
+       9, 32, 0x54019c, 0x5401a8, 0x5401a4, 0x5401a0};
+
+static struct attn_hw_reg bmb_int10_bb_b0 = {
+       10, 3, 0x5401b4, 0x5401c0, 0x5401bc, 0x5401b8};
+
+static struct attn_hw_reg bmb_int11_bb_b0 = {
+       11, 4, 0x5401cc, 0x5401d8, 0x5401d4, 0x5401d0};
+
+static struct attn_hw_reg *bmb_int_bb_b0_regs[12] = {
+       &bmb_int0_bb_b0, &bmb_int1_bb_b0, &bmb_int2_bb_b0, &bmb_int3_bb_b0,
+       &bmb_int4_bb_b0, &bmb_int5_bb_b0, &bmb_int6_bb_b0, &bmb_int7_bb_b0,
+       &bmb_int8_bb_b0, &bmb_int9_bb_b0, &bmb_int10_bb_b0, &bmb_int11_bb_b0};
+
+static struct attn_hw_reg bmb_prty0_bb_b0 = {
+       0, 5, 0x5401dc, 0x5401e8, 0x5401e4, 0x5401e0};
+
+static struct attn_hw_reg bmb_prty1_bb_b0 = {
+       1, 31, 0x540400, 0x54040c, 0x540408, 0x540404};
+
+static struct attn_hw_reg bmb_prty2_bb_b0 = {
+       2, 15, 0x540410, 0x54041c, 0x540418, 0x540414};
+
+static struct attn_hw_reg *bmb_prty_bb_b0_regs[3] = {
+       &bmb_prty0_bb_b0, &bmb_prty1_bb_b0, &bmb_prty2_bb_b0};
+
+static struct attn_hw_reg pcie_prty1_bb_b0 = {
+       0, 17, 0x54000, 0x5400c, 0x54008, 0x54004};
+
+static struct attn_hw_reg *pcie_prty_bb_b0_regs[1] = {
+       &pcie_prty1_bb_b0};
+
+static struct attn_hw_reg mcp2_prty0_bb_b0 = {
+       0, 1, 0x52040, 0x5204c, 0x52048, 0x52044};
+
+static struct attn_hw_reg mcp2_prty1_bb_b0 = {
+       1, 12, 0x52204, 0x52210, 0x5220c, 0x52208};
+
+static struct attn_hw_reg *mcp2_prty_bb_b0_regs[2] = {
+       &mcp2_prty0_bb_b0, &mcp2_prty1_bb_b0};
+
+static struct attn_hw_reg pswhst_int0_bb_b0 = {
+       0, 18, 0x2a0180, 0x2a018c, 0x2a0188, 0x2a0184};
+
+static struct attn_hw_reg *pswhst_int_bb_b0_regs[1] = {
+       &pswhst_int0_bb_b0};
+
+static struct attn_hw_reg pswhst_prty0_bb_b0 = {
+       0, 1, 0x2a0190, 0x2a019c, 0x2a0198, 0x2a0194};
+
+static struct attn_hw_reg pswhst_prty1_bb_b0 = {
+       1, 17, 0x2a0200, 0x2a020c, 0x2a0208, 0x2a0204};
+
+static struct attn_hw_reg *pswhst_prty_bb_b0_regs[2] = {
+       &pswhst_prty0_bb_b0, &pswhst_prty1_bb_b0};
+
+static struct attn_hw_reg pswhst2_int0_bb_b0 = {
+       0, 5, 0x29e180, 0x29e18c, 0x29e188, 0x29e184};
+
+static struct attn_hw_reg *pswhst2_int_bb_b0_regs[1] = {
+       &pswhst2_int0_bb_b0};
+
+static struct attn_hw_reg pswhst2_prty0_bb_b0 = {
+       0, 1, 0x29e190, 0x29e19c, 0x29e198, 0x29e194};
+
+static struct attn_hw_reg *pswhst2_prty_bb_b0_regs[1] = {
+       &pswhst2_prty0_bb_b0};
+
+static struct attn_hw_reg pswrd_int0_bb_b0 = {
+       0, 3, 0x29c180, 0x29c18c, 0x29c188, 0x29c184};
+
+static struct attn_hw_reg *pswrd_int_bb_b0_regs[1] = {
+       &pswrd_int0_bb_b0};
+
+static struct attn_hw_reg pswrd_prty0_bb_b0 = {
+       0, 1, 0x29c190, 0x29c19c, 0x29c198, 0x29c194};
+
+static struct attn_hw_reg *pswrd_prty_bb_b0_regs[1] = {
+       &pswrd_prty0_bb_b0};
+
+static struct attn_hw_reg pswrd2_int0_bb_b0 = {
+       0, 5, 0x29d180, 0x29d18c, 0x29d188, 0x29d184};
+
+static struct attn_hw_reg *pswrd2_int_bb_b0_regs[1] = {
+       &pswrd2_int0_bb_b0};
+
+static struct attn_hw_reg pswrd2_prty0_bb_b0 = {
+       0, 1, 0x29d190, 0x29d19c, 0x29d198, 0x29d194};
+
+static struct attn_hw_reg pswrd2_prty1_bb_b0 = {
+       1, 31, 0x29d200, 0x29d20c, 0x29d208, 0x29d204};
+
+static struct attn_hw_reg pswrd2_prty2_bb_b0 = {
+       2, 3, 0x29d210, 0x29d21c, 0x29d218, 0x29d214};
+
+static struct attn_hw_reg *pswrd2_prty_bb_b0_regs[3] = {
+       &pswrd2_prty0_bb_b0, &pswrd2_prty1_bb_b0, &pswrd2_prty2_bb_b0};
+
+static struct attn_hw_reg pswwr_int0_bb_b0 = {
+       0, 16, 0x29a180, 0x29a18c, 0x29a188, 0x29a184};
+
+static struct attn_hw_reg *pswwr_int_bb_b0_regs[1] = {
+       &pswwr_int0_bb_b0};
+
+static struct attn_hw_reg pswwr_prty0_bb_b0 = {
+       0, 1, 0x29a190, 0x29a19c, 0x29a198, 0x29a194};
+
+static struct attn_hw_reg *pswwr_prty_bb_b0_regs[1] = {
+       &pswwr_prty0_bb_b0};
+
+static struct attn_hw_reg pswwr2_int0_bb_b0 = {
+       0, 19, 0x29b180, 0x29b18c, 0x29b188, 0x29b184};
+
+static struct attn_hw_reg *pswwr2_int_bb_b0_regs[1] = {
+       &pswwr2_int0_bb_b0};
+
+static struct attn_hw_reg pswwr2_prty0_bb_b0 = {
+       0, 1, 0x29b190, 0x29b19c, 0x29b198, 0x29b194};
+
+static struct attn_hw_reg pswwr2_prty1_bb_b0 = {
+       1, 31, 0x29b200, 0x29b20c, 0x29b208, 0x29b204};
+
+static struct attn_hw_reg pswwr2_prty2_bb_b0 = {
+       2, 31, 0x29b210, 0x29b21c, 0x29b218, 0x29b214};
+
+static struct attn_hw_reg pswwr2_prty3_bb_b0 = {
+       3, 31, 0x29b220, 0x29b22c, 0x29b228, 0x29b224};
+
+static struct attn_hw_reg pswwr2_prty4_bb_b0 = {
+       4, 20, 0x29b230, 0x29b23c, 0x29b238, 0x29b234};
+
+static struct attn_hw_reg *pswwr2_prty_bb_b0_regs[5] = {
+       &pswwr2_prty0_bb_b0, &pswwr2_prty1_bb_b0, &pswwr2_prty2_bb_b0,
+       &pswwr2_prty3_bb_b0, &pswwr2_prty4_bb_b0};
+
+static struct attn_hw_reg pswrq_int0_bb_b0 = {
+       0, 21, 0x280180, 0x28018c, 0x280188, 0x280184};
+
+static struct attn_hw_reg *pswrq_int_bb_b0_regs[1] = {
+       &pswrq_int0_bb_b0};
+
+static struct attn_hw_reg pswrq_prty0_bb_b0 = {
+       0, 1, 0x280190, 0x28019c, 0x280198, 0x280194};
+
+static struct attn_hw_reg *pswrq_prty_bb_b0_regs[1] = {
+       &pswrq_prty0_bb_b0};
+
+static struct attn_hw_reg pswrq2_int0_bb_b0 = {
+       0, 15, 0x240180, 0x24018c, 0x240188, 0x240184};
+
+static struct attn_hw_reg *pswrq2_int_bb_b0_regs[1] = {
+       &pswrq2_int0_bb_b0};
+
+static struct attn_hw_reg pswrq2_prty1_bb_b0 = {
+       0, 9, 0x240200, 0x24020c, 0x240208, 0x240204};
+
+static struct attn_hw_reg *pswrq2_prty_bb_b0_regs[1] = {
+       &pswrq2_prty1_bb_b0};
+
+static struct attn_hw_reg pglcs_int0_bb_b0 = {
+       0, 1, 0x1d00, 0x1d0c, 0x1d08, 0x1d04};
+
+static struct attn_hw_reg *pglcs_int_bb_b0_regs[1] = {
+       &pglcs_int0_bb_b0};
+
+static struct attn_hw_reg dmae_int0_bb_b0 = {
+       0, 2, 0xc180, 0xc18c, 0xc188, 0xc184};
+
+static struct attn_hw_reg *dmae_int_bb_b0_regs[1] = {
+       &dmae_int0_bb_b0};
+
+static struct attn_hw_reg dmae_prty1_bb_b0 = {
+       0, 3, 0xc200, 0xc20c, 0xc208, 0xc204};
+
+static struct attn_hw_reg *dmae_prty_bb_b0_regs[1] = {
+       &dmae_prty1_bb_b0};
+
+static struct attn_hw_reg ptu_int0_bb_b0 = {
+       0, 8, 0x560180, 0x56018c, 0x560188, 0x560184};
+
+static struct attn_hw_reg *ptu_int_bb_b0_regs[1] = {
+       &ptu_int0_bb_b0};
+
+static struct attn_hw_reg ptu_prty1_bb_b0 = {
+       0, 18, 0x560200, 0x56020c, 0x560208, 0x560204};
+
+static struct attn_hw_reg *ptu_prty_bb_b0_regs[1] = {
+       &ptu_prty1_bb_b0};
+
+static struct attn_hw_reg tcm_int0_bb_b0 = {
+       0, 8, 0x1180180, 0x118018c, 0x1180188, 0x1180184};
+
+static struct attn_hw_reg tcm_int1_bb_b0 = {
+       1, 32, 0x1180190, 0x118019c, 0x1180198, 0x1180194};
+
+static struct attn_hw_reg tcm_int2_bb_b0 = {
+       2, 1, 0x11801a0, 0x11801ac, 0x11801a8, 0x11801a4};
+
+static struct attn_hw_reg *tcm_int_bb_b0_regs[3] = {
+       &tcm_int0_bb_b0, &tcm_int1_bb_b0, &tcm_int2_bb_b0};
+
+static struct attn_hw_reg tcm_prty1_bb_b0 = {
+       0, 31, 0x1180200, 0x118020c, 0x1180208, 0x1180204};
+
+static struct attn_hw_reg tcm_prty2_bb_b0 = {
+       1, 2, 0x1180210, 0x118021c, 0x1180218, 0x1180214};
+
+static struct attn_hw_reg *tcm_prty_bb_b0_regs[2] = {
+       &tcm_prty1_bb_b0, &tcm_prty2_bb_b0};
+
+static struct attn_hw_reg mcm_int0_bb_b0 = {
+       0, 14, 0x1200180, 0x120018c, 0x1200188, 0x1200184};
+
+static struct attn_hw_reg mcm_int1_bb_b0 = {
+       1, 26, 0x1200190, 0x120019c, 0x1200198, 0x1200194};
+
+static struct attn_hw_reg mcm_int2_bb_b0 = {
+       2, 1, 0x12001a0, 0x12001ac, 0x12001a8, 0x12001a4};
+
+static struct attn_hw_reg *mcm_int_bb_b0_regs[3] = {
+       &mcm_int0_bb_b0, &mcm_int1_bb_b0, &mcm_int2_bb_b0};
+
+static struct attn_hw_reg mcm_prty1_bb_b0 = {
+       0, 31, 0x1200200, 0x120020c, 0x1200208, 0x1200204};
+
+static struct attn_hw_reg mcm_prty2_bb_b0 = {
+       1, 4, 0x1200210, 0x120021c, 0x1200218, 0x1200214};
+
+static struct attn_hw_reg *mcm_prty_bb_b0_regs[2] = {
+       &mcm_prty1_bb_b0, &mcm_prty2_bb_b0};
+
+static struct attn_hw_reg ucm_int0_bb_b0 = {
+       0, 17, 0x1280180, 0x128018c, 0x1280188, 0x1280184};
+
+static struct attn_hw_reg ucm_int1_bb_b0 = {
+       1, 29, 0x1280190, 0x128019c, 0x1280198, 0x1280194};
+
+static struct attn_hw_reg ucm_int2_bb_b0 = {
+       2, 1, 0x12801a0, 0x12801ac, 0x12801a8, 0x12801a4};
+
+static struct attn_hw_reg *ucm_int_bb_b0_regs[3] = {
+       &ucm_int0_bb_b0, &ucm_int1_bb_b0, &ucm_int2_bb_b0};
+
+static struct attn_hw_reg ucm_prty1_bb_b0 = {
+       0, 31, 0x1280200, 0x128020c, 0x1280208, 0x1280204};
+
+static struct attn_hw_reg ucm_prty2_bb_b0 = {
+       1, 7, 0x1280210, 0x128021c, 0x1280218, 0x1280214};
+
+static struct attn_hw_reg *ucm_prty_bb_b0_regs[2] = {
+       &ucm_prty1_bb_b0, &ucm_prty2_bb_b0};
+
+static struct attn_hw_reg xcm_int0_bb_b0 = {
+       0, 16, 0x1000180, 0x100018c, 0x1000188, 0x1000184};
+
+static struct attn_hw_reg xcm_int1_bb_b0 = {
+       1, 25, 0x1000190, 0x100019c, 0x1000198, 0x1000194};
+
+static struct attn_hw_reg xcm_int2_bb_b0 = {
+       2, 8, 0x10001a0, 0x10001ac, 0x10001a8, 0x10001a4};
+
+static struct attn_hw_reg *xcm_int_bb_b0_regs[3] = {
+       &xcm_int0_bb_b0, &xcm_int1_bb_b0, &xcm_int2_bb_b0};
+
+static struct attn_hw_reg xcm_prty1_bb_b0 = {
+       0, 31, 0x1000200, 0x100020c, 0x1000208, 0x1000204};
+
+static struct attn_hw_reg xcm_prty2_bb_b0 = {
+       1, 11, 0x1000210, 0x100021c, 0x1000218, 0x1000214};
+
+static struct attn_hw_reg *xcm_prty_bb_b0_regs[2] = {
+       &xcm_prty1_bb_b0, &xcm_prty2_bb_b0};
+
+static struct attn_hw_reg ycm_int0_bb_b0 = {
+       0, 13, 0x1080180, 0x108018c, 0x1080188, 0x1080184};
+
+static struct attn_hw_reg ycm_int1_bb_b0 = {
+       1, 23, 0x1080190, 0x108019c, 0x1080198, 0x1080194};
+
+static struct attn_hw_reg ycm_int2_bb_b0 = {
+       2, 1, 0x10801a0, 0x10801ac, 0x10801a8, 0x10801a4};
+
+static struct attn_hw_reg *ycm_int_bb_b0_regs[3] = {
+       &ycm_int0_bb_b0, &ycm_int1_bb_b0, &ycm_int2_bb_b0};
+
+static struct attn_hw_reg ycm_prty1_bb_b0 = {
+       0, 31, 0x1080200, 0x108020c, 0x1080208, 0x1080204};
+
+static struct attn_hw_reg ycm_prty2_bb_b0 = {
+       1, 3, 0x1080210, 0x108021c, 0x1080218, 0x1080214};
+
+static struct attn_hw_reg *ycm_prty_bb_b0_regs[2] = {
+       &ycm_prty1_bb_b0, &ycm_prty2_bb_b0};
+
+static struct attn_hw_reg pcm_int0_bb_b0 = {
+       0, 5, 0x1100180, 0x110018c, 0x1100188, 0x1100184};
+
+static struct attn_hw_reg pcm_int1_bb_b0 = {
+       1, 14, 0x1100190, 0x110019c, 0x1100198, 0x1100194};
+
+static struct attn_hw_reg pcm_int2_bb_b0 = {
+       2, 1, 0x11001a0, 0x11001ac, 0x11001a8, 0x11001a4};
+
+static struct attn_hw_reg *pcm_int_bb_b0_regs[3] = {
+       &pcm_int0_bb_b0, &pcm_int1_bb_b0, &pcm_int2_bb_b0};
+
+static struct attn_hw_reg pcm_prty1_bb_b0 = {
+       0, 11, 0x1100200, 0x110020c, 0x1100208, 0x1100204};
+
+static struct attn_hw_reg *pcm_prty_bb_b0_regs[1] = {
+       &pcm_prty1_bb_b0};
+
+static struct attn_hw_reg qm_int0_bb_b0 = {
+       0, 22, 0x2f0180, 0x2f018c, 0x2f0188, 0x2f0184};
+
+static struct attn_hw_reg *qm_int_bb_b0_regs[1] = {
+       &qm_int0_bb_b0};
+
+static struct attn_hw_reg qm_prty0_bb_b0 = {
+       0, 11, 0x2f0190, 0x2f019c, 0x2f0198, 0x2f0194};
+
+static struct attn_hw_reg qm_prty1_bb_b0 = {
+       1, 31, 0x2f0200, 0x2f020c, 0x2f0208, 0x2f0204};
+
+static struct attn_hw_reg qm_prty2_bb_b0 = {
+       2, 31, 0x2f0210, 0x2f021c, 0x2f0218, 0x2f0214};
+
+static struct attn_hw_reg qm_prty3_bb_b0 = {
+       3, 11, 0x2f0220, 0x2f022c, 0x2f0228, 0x2f0224};
+
+static struct attn_hw_reg *qm_prty_bb_b0_regs[4] = {
+       &qm_prty0_bb_b0, &qm_prty1_bb_b0, &qm_prty2_bb_b0, &qm_prty3_bb_b0};
+
+static struct attn_hw_reg tm_int0_bb_b0 = {
+       0, 32, 0x2c0180, 0x2c018c, 0x2c0188, 0x2c0184};
+
+static struct attn_hw_reg tm_int1_bb_b0 = {
+       1, 11, 0x2c0190, 0x2c019c, 0x2c0198, 0x2c0194};
+
+static struct attn_hw_reg *tm_int_bb_b0_regs[2] = {
+       &tm_int0_bb_b0, &tm_int1_bb_b0};
+
+static struct attn_hw_reg tm_prty1_bb_b0 = {
+       0, 17, 0x2c0200, 0x2c020c, 0x2c0208, 0x2c0204};
+
+static struct attn_hw_reg *tm_prty_bb_b0_regs[1] = {
+       &tm_prty1_bb_b0};
+
+static struct attn_hw_reg dorq_int0_bb_b0 = {
+       0, 9, 0x100180, 0x10018c, 0x100188, 0x100184};
+
+static struct attn_hw_reg *dorq_int_bb_b0_regs[1] = {
+       &dorq_int0_bb_b0};
+
+static struct attn_hw_reg dorq_prty0_bb_b0 = {
+       0, 1, 0x100190, 0x10019c, 0x100198, 0x100194};
+
+static struct attn_hw_reg dorq_prty1_bb_b0 = {
+       1, 6, 0x100200, 0x10020c, 0x100208, 0x100204};
+
+static struct attn_hw_reg *dorq_prty_bb_b0_regs[2] = {
+       &dorq_prty0_bb_b0, &dorq_prty1_bb_b0};
+
+static struct attn_hw_reg brb_int0_bb_b0 = {
+       0, 32, 0x3400c0, 0x3400cc, 0x3400c8, 0x3400c4};
+
+static struct attn_hw_reg brb_int1_bb_b0 = {
+       1, 30, 0x3400d8, 0x3400e4, 0x3400e0, 0x3400dc};
+
+static struct attn_hw_reg brb_int2_bb_b0 = {
+       2, 28, 0x3400f0, 0x3400fc, 0x3400f8, 0x3400f4};
+
+static struct attn_hw_reg brb_int3_bb_b0 = {
+       3, 31, 0x340108, 0x340114, 0x340110, 0x34010c};
+
+static struct attn_hw_reg brb_int4_bb_b0 = {
+       4, 27, 0x340120, 0x34012c, 0x340128, 0x340124};
+
+static struct attn_hw_reg brb_int5_bb_b0 = {
+       5, 1, 0x340138, 0x340144, 0x340140, 0x34013c};
+
+static struct attn_hw_reg brb_int6_bb_b0 = {
+       6, 8, 0x340150, 0x34015c, 0x340158, 0x340154};
+
+static struct attn_hw_reg brb_int7_bb_b0 = {
+       7, 32, 0x340168, 0x340174, 0x340170, 0x34016c};
+
+static struct attn_hw_reg brb_int8_bb_b0 = {
+       8, 17, 0x340184, 0x340190, 0x34018c, 0x340188};
+
+static struct attn_hw_reg brb_int9_bb_b0 = {
+       9, 1, 0x34019c, 0x3401a8, 0x3401a4, 0x3401a0};
+
+static struct attn_hw_reg brb_int10_bb_b0 = {
+       10, 14, 0x3401b4, 0x3401c0, 0x3401bc, 0x3401b8};
+
+static struct attn_hw_reg brb_int11_bb_b0 = {
+       11, 8, 0x3401cc, 0x3401d8, 0x3401d4, 0x3401d0};
+
+static struct attn_hw_reg *brb_int_bb_b0_regs[12] = {
+       &brb_int0_bb_b0, &brb_int1_bb_b0, &brb_int2_bb_b0, &brb_int3_bb_b0,
+       &brb_int4_bb_b0, &brb_int5_bb_b0, &brb_int6_bb_b0, &brb_int7_bb_b0,
+       &brb_int8_bb_b0, &brb_int9_bb_b0, &brb_int10_bb_b0, &brb_int11_bb_b0};
+
+static struct attn_hw_reg brb_prty0_bb_b0 = {
+       0, 5, 0x3401dc, 0x3401e8, 0x3401e4, 0x3401e0};
+
+static struct attn_hw_reg brb_prty1_bb_b0 = {
+       1, 31, 0x340400, 0x34040c, 0x340408, 0x340404};
+
+static struct attn_hw_reg brb_prty2_bb_b0 = {
+       2, 14, 0x340410, 0x34041c, 0x340418, 0x340414};
+
+static struct attn_hw_reg *brb_prty_bb_b0_regs[3] = {
+       &brb_prty0_bb_b0, &brb_prty1_bb_b0, &brb_prty2_bb_b0};
+
+static struct attn_hw_reg src_int0_bb_b0 = {
+       0, 1, 0x2381d8, 0x2381dc, 0x2381e0, 0x2381e4};
+
+static struct attn_hw_reg *src_int_bb_b0_regs[1] = {
+       &src_int0_bb_b0};
+
+static struct attn_hw_reg prs_int0_bb_b0 = {
+       0, 2, 0x1f0040, 0x1f004c, 0x1f0048, 0x1f0044};
+
+static struct attn_hw_reg *prs_int_bb_b0_regs[1] = {
+       &prs_int0_bb_b0};
+
+static struct attn_hw_reg prs_prty0_bb_b0 = {
+       0, 2, 0x1f0050, 0x1f005c, 0x1f0058, 0x1f0054};
+
+static struct attn_hw_reg prs_prty1_bb_b0 = {
+       1, 31, 0x1f0204, 0x1f0210, 0x1f020c, 0x1f0208};
+
+static struct attn_hw_reg prs_prty2_bb_b0 = {
+       2, 5, 0x1f0214, 0x1f0220, 0x1f021c, 0x1f0218};
+
+static struct attn_hw_reg *prs_prty_bb_b0_regs[3] = {
+       &prs_prty0_bb_b0, &prs_prty1_bb_b0, &prs_prty2_bb_b0};
+
+static struct attn_hw_reg tsdm_int0_bb_b0 = {
+       0, 26, 0xfb0040, 0xfb004c, 0xfb0048, 0xfb0044};
+
+static struct attn_hw_reg *tsdm_int_bb_b0_regs[1] = {
+       &tsdm_int0_bb_b0};
+
+static struct attn_hw_reg tsdm_prty1_bb_b0 = {
+       0, 10, 0xfb0200, 0xfb020c, 0xfb0208, 0xfb0204};
+
+static struct attn_hw_reg *tsdm_prty_bb_b0_regs[1] = {
+       &tsdm_prty1_bb_b0};
+
+static struct attn_hw_reg msdm_int0_bb_b0 = {
+       0, 26, 0xfc0040, 0xfc004c, 0xfc0048, 0xfc0044};
+
+static struct attn_hw_reg *msdm_int_bb_b0_regs[1] = {
+       &msdm_int0_bb_b0};
+
+static struct attn_hw_reg msdm_prty1_bb_b0 = {
+       0, 11, 0xfc0200, 0xfc020c, 0xfc0208, 0xfc0204};
+
+static struct attn_hw_reg *msdm_prty_bb_b0_regs[1] = {
+       &msdm_prty1_bb_b0};
+
+static struct attn_hw_reg usdm_int0_bb_b0 = {
+       0, 26, 0xfd0040, 0xfd004c, 0xfd0048, 0xfd0044};
+
+static struct attn_hw_reg *usdm_int_bb_b0_regs[1] = {
+       &usdm_int0_bb_b0};
+
+static struct attn_hw_reg usdm_prty1_bb_b0 = {
+       0, 10, 0xfd0200, 0xfd020c, 0xfd0208, 0xfd0204};
+
+static struct attn_hw_reg *usdm_prty_bb_b0_regs[1] = {
+       &usdm_prty1_bb_b0};
+
+static struct attn_hw_reg xsdm_int0_bb_b0 = {
+       0, 26, 0xf80040, 0xf8004c, 0xf80048, 0xf80044};
+
+static struct attn_hw_reg *xsdm_int_bb_b0_regs[1] = {
+       &xsdm_int0_bb_b0};
+
+static struct attn_hw_reg xsdm_prty1_bb_b0 = {
+       0, 10, 0xf80200, 0xf8020c, 0xf80208, 0xf80204};
+
+static struct attn_hw_reg *xsdm_prty_bb_b0_regs[1] = {
+       &xsdm_prty1_bb_b0};
+
+static struct attn_hw_reg ysdm_int0_bb_b0 = {
+       0, 26, 0xf90040, 0xf9004c, 0xf90048, 0xf90044};
+
+static struct attn_hw_reg *ysdm_int_bb_b0_regs[1] = {
+       &ysdm_int0_bb_b0};
+
+static struct attn_hw_reg ysdm_prty1_bb_b0 = {
+       0, 9, 0xf90200, 0xf9020c, 0xf90208, 0xf90204};
+
+static struct attn_hw_reg *ysdm_prty_bb_b0_regs[1] = {
+       &ysdm_prty1_bb_b0};
+
+static struct attn_hw_reg psdm_int0_bb_b0 = {
+       0, 26, 0xfa0040, 0xfa004c, 0xfa0048, 0xfa0044};
+
+static struct attn_hw_reg *psdm_int_bb_b0_regs[1] = {
+       &psdm_int0_bb_b0};
+
+static struct attn_hw_reg psdm_prty1_bb_b0 = {
+       0, 9, 0xfa0200, 0xfa020c, 0xfa0208, 0xfa0204};
+
+static struct attn_hw_reg *psdm_prty_bb_b0_regs[1] = {
+       &psdm_prty1_bb_b0};
+
+static struct attn_hw_reg tsem_int0_bb_b0 = {
+       0, 32, 0x1700040, 0x170004c, 0x1700048, 0x1700044};
+
+static struct attn_hw_reg tsem_int1_bb_b0 = {
+       1, 13, 0x1700050, 0x170005c, 0x1700058, 0x1700054};
+
+static struct attn_hw_reg tsem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1740040, 0x174004c, 0x1740048, 0x1740044};
+
+static struct attn_hw_reg *tsem_int_bb_b0_regs[3] = {
+       &tsem_int0_bb_b0, &tsem_int1_bb_b0, &tsem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg tsem_prty0_bb_b0 = {
+       0, 3, 0x17000c8, 0x17000d4, 0x17000d0, 0x17000cc};
+
+static struct attn_hw_reg tsem_prty1_bb_b0 = {
+       1, 6, 0x1700200, 0x170020c, 0x1700208, 0x1700204};
+
+static struct attn_hw_reg tsem_fast_memory_vfc_config_prty1_bb_b0 = {
+       2, 6, 0x174a200, 0x174a20c, 0x174a208, 0x174a204};
+
+static struct attn_hw_reg *tsem_prty_bb_b0_regs[3] = {
+       &tsem_prty0_bb_b0, &tsem_prty1_bb_b0,
+       &tsem_fast_memory_vfc_config_prty1_bb_b0};
+
+static struct attn_hw_reg msem_int0_bb_b0 = {
+       0, 32, 0x1800040, 0x180004c, 0x1800048, 0x1800044};
+
+static struct attn_hw_reg msem_int1_bb_b0 = {
+       1, 13, 0x1800050, 0x180005c, 0x1800058, 0x1800054};
+
+static struct attn_hw_reg msem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1840040, 0x184004c, 0x1840048, 0x1840044};
+
+static struct attn_hw_reg *msem_int_bb_b0_regs[3] = {
+       &msem_int0_bb_b0, &msem_int1_bb_b0, &msem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg msem_prty0_bb_b0 = {
+       0, 3, 0x18000c8, 0x18000d4, 0x18000d0, 0x18000cc};
+
+static struct attn_hw_reg msem_prty1_bb_b0 = {
+       1, 6, 0x1800200, 0x180020c, 0x1800208, 0x1800204};
+
+static struct attn_hw_reg *msem_prty_bb_b0_regs[2] = {
+       &msem_prty0_bb_b0, &msem_prty1_bb_b0};
+
+static struct attn_hw_reg usem_int0_bb_b0 = {
+       0, 32, 0x1900040, 0x190004c, 0x1900048, 0x1900044};
+
+static struct attn_hw_reg usem_int1_bb_b0 = {
+       1, 13, 0x1900050, 0x190005c, 0x1900058, 0x1900054};
+
+static struct attn_hw_reg usem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1940040, 0x194004c, 0x1940048, 0x1940044};
+
+static struct attn_hw_reg *usem_int_bb_b0_regs[3] = {
+       &usem_int0_bb_b0, &usem_int1_bb_b0, &usem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg usem_prty0_bb_b0 = {
+       0, 3, 0x19000c8, 0x19000d4, 0x19000d0, 0x19000cc};
+
+static struct attn_hw_reg usem_prty1_bb_b0 = {
+       1, 6, 0x1900200, 0x190020c, 0x1900208, 0x1900204};
+
+static struct attn_hw_reg *usem_prty_bb_b0_regs[2] = {
+       &usem_prty0_bb_b0, &usem_prty1_bb_b0};
+
+static struct attn_hw_reg xsem_int0_bb_b0 = {
+       0, 32, 0x1400040, 0x140004c, 0x1400048, 0x1400044};
+
+static struct attn_hw_reg xsem_int1_bb_b0 = {
+       1, 13, 0x1400050, 0x140005c, 0x1400058, 0x1400054};
+
+static struct attn_hw_reg xsem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1440040, 0x144004c, 0x1440048, 0x1440044};
+
+static struct attn_hw_reg *xsem_int_bb_b0_regs[3] = {
+       &xsem_int0_bb_b0, &xsem_int1_bb_b0, &xsem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg xsem_prty0_bb_b0 = {
+       0, 3, 0x14000c8, 0x14000d4, 0x14000d0, 0x14000cc};
+
+static struct attn_hw_reg xsem_prty1_bb_b0 = {
+       1, 7, 0x1400200, 0x140020c, 0x1400208, 0x1400204};
+
+static struct attn_hw_reg *xsem_prty_bb_b0_regs[2] = {
+       &xsem_prty0_bb_b0, &xsem_prty1_bb_b0};
+
+static struct attn_hw_reg ysem_int0_bb_b0 = {
+       0, 32, 0x1500040, 0x150004c, 0x1500048, 0x1500044};
+
+static struct attn_hw_reg ysem_int1_bb_b0 = {
+       1, 13, 0x1500050, 0x150005c, 0x1500058, 0x1500054};
+
+static struct attn_hw_reg ysem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1540040, 0x154004c, 0x1540048, 0x1540044};
+
+static struct attn_hw_reg *ysem_int_bb_b0_regs[3] = {
+       &ysem_int0_bb_b0, &ysem_int1_bb_b0, &ysem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg ysem_prty0_bb_b0 = {
+       0, 3, 0x15000c8, 0x15000d4, 0x15000d0, 0x15000cc};
+
+static struct attn_hw_reg ysem_prty1_bb_b0 = {
+       1, 7, 0x1500200, 0x150020c, 0x1500208, 0x1500204};
+
+static struct attn_hw_reg *ysem_prty_bb_b0_regs[2] = {
+       &ysem_prty0_bb_b0, &ysem_prty1_bb_b0};
+
+static struct attn_hw_reg psem_int0_bb_b0 = {
+       0, 32, 0x1600040, 0x160004c, 0x1600048, 0x1600044};
+
+static struct attn_hw_reg psem_int1_bb_b0 = {
+       1, 13, 0x1600050, 0x160005c, 0x1600058, 0x1600054};
+
+static struct attn_hw_reg psem_fast_memory_int0_bb_b0 = {
+       2, 1, 0x1640040, 0x164004c, 0x1640048, 0x1640044};
+
+static struct attn_hw_reg *psem_int_bb_b0_regs[3] = {
+       &psem_int0_bb_b0, &psem_int1_bb_b0, &psem_fast_memory_int0_bb_b0};
+
+static struct attn_hw_reg psem_prty0_bb_b0 = {
+       0, 3, 0x16000c8, 0x16000d4, 0x16000d0, 0x16000cc};
+
+static struct attn_hw_reg psem_prty1_bb_b0 = {
+       1, 6, 0x1600200, 0x160020c, 0x1600208, 0x1600204};
+
+static struct attn_hw_reg psem_fast_memory_vfc_config_prty1_bb_b0 = {
+       2, 6, 0x164a200, 0x164a20c, 0x164a208, 0x164a204};
+
+static struct attn_hw_reg *psem_prty_bb_b0_regs[3] = {
+       &psem_prty0_bb_b0, &psem_prty1_bb_b0,
+       &psem_fast_memory_vfc_config_prty1_bb_b0};
+
+static struct attn_hw_reg rss_int0_bb_b0 = {
+       0, 12, 0x238980, 0x23898c, 0x238988, 0x238984};
+
+static struct attn_hw_reg *rss_int_bb_b0_regs[1] = {
+       &rss_int0_bb_b0};
+
+static struct attn_hw_reg rss_prty1_bb_b0 = {
+       0, 4, 0x238a00, 0x238a0c, 0x238a08, 0x238a04};
+
+static struct attn_hw_reg *rss_prty_bb_b0_regs[1] = {
+       &rss_prty1_bb_b0};
+
+static struct attn_hw_reg tmld_int0_bb_b0 = {
+       0, 6, 0x4d0180, 0x4d018c, 0x4d0188, 0x4d0184};
+
+static struct attn_hw_reg *tmld_int_bb_b0_regs[1] = {
+       &tmld_int0_bb_b0};
+
+static struct attn_hw_reg tmld_prty1_bb_b0 = {
+       0, 8, 0x4d0200, 0x4d020c, 0x4d0208, 0x4d0204};
+
+static struct attn_hw_reg *tmld_prty_bb_b0_regs[1] = {
+       &tmld_prty1_bb_b0};
+
+static struct attn_hw_reg muld_int0_bb_b0 = {
+       0, 6, 0x4e0180, 0x4e018c, 0x4e0188, 0x4e0184};
+
+static struct attn_hw_reg *muld_int_bb_b0_regs[1] = {
+       &muld_int0_bb_b0};
+
+static struct attn_hw_reg muld_prty1_bb_b0 = {
+       0, 10, 0x4e0200, 0x4e020c, 0x4e0208, 0x4e0204};
+
+static struct attn_hw_reg *muld_prty_bb_b0_regs[1] = {
+       &muld_prty1_bb_b0};
+
+static struct attn_hw_reg yuld_int0_bb_b0 = {
+       0, 6, 0x4c8180, 0x4c818c, 0x4c8188, 0x4c8184};
+
+static struct attn_hw_reg *yuld_int_bb_b0_regs[1] = {
+       &yuld_int0_bb_b0};
+
+static struct attn_hw_reg yuld_prty1_bb_b0 = {
+       0, 6, 0x4c8200, 0x4c820c, 0x4c8208, 0x4c8204};
+
+static struct attn_hw_reg *yuld_prty_bb_b0_regs[1] = {
+       &yuld_prty1_bb_b0};
+
+static struct attn_hw_reg xyld_int0_bb_b0 = {
+       0, 6, 0x4c0180, 0x4c018c, 0x4c0188, 0x4c0184};
+
+static struct attn_hw_reg *xyld_int_bb_b0_regs[1] = {
+       &xyld_int0_bb_b0};
+
+static struct attn_hw_reg xyld_prty1_bb_b0 = {
+       0, 9, 0x4c0200, 0x4c020c, 0x4c0208, 0x4c0204};
+
+static struct attn_hw_reg *xyld_prty_bb_b0_regs[1] = {
+       &xyld_prty1_bb_b0};
+
+static struct attn_hw_reg prm_int0_bb_b0 = {
+       0, 11, 0x230040, 0x23004c, 0x230048, 0x230044};
+
+static struct attn_hw_reg *prm_int_bb_b0_regs[1] = {
+       &prm_int0_bb_b0};
+
+static struct attn_hw_reg prm_prty0_bb_b0 = {
+       0, 1, 0x230050, 0x23005c, 0x230058, 0x230054};
+
+static struct attn_hw_reg prm_prty1_bb_b0 = {
+       1, 24, 0x230200, 0x23020c, 0x230208, 0x230204};
+
+static struct attn_hw_reg *prm_prty_bb_b0_regs[2] = {
+       &prm_prty0_bb_b0, &prm_prty1_bb_b0};
+
+static struct attn_hw_reg pbf_pb1_int0_bb_b0 = {
+       0, 9, 0xda0040, 0xda004c, 0xda0048, 0xda0044};
+
+static struct attn_hw_reg *pbf_pb1_int_bb_b0_regs[1] = {
+       &pbf_pb1_int0_bb_b0};
+
+static struct attn_hw_reg pbf_pb1_prty0_bb_b0 = {
+       0, 1, 0xda0050, 0xda005c, 0xda0058, 0xda0054};
+
+static struct attn_hw_reg *pbf_pb1_prty_bb_b0_regs[1] = {
+       &pbf_pb1_prty0_bb_b0};
+
+static struct attn_hw_reg pbf_pb2_int0_bb_b0 = {
+       0, 9, 0xda4040, 0xda404c, 0xda4048, 0xda4044};
+
+static struct attn_hw_reg *pbf_pb2_int_bb_b0_regs[1] = {
+       &pbf_pb2_int0_bb_b0};
+
+static struct attn_hw_reg pbf_pb2_prty0_bb_b0 = {
+       0, 1, 0xda4050, 0xda405c, 0xda4058, 0xda4054};
+
+static struct attn_hw_reg *pbf_pb2_prty_bb_b0_regs[1] = {
+       &pbf_pb2_prty0_bb_b0};
+
+static struct attn_hw_reg rpb_int0_bb_b0 = {
+       0, 9, 0x23c040, 0x23c04c, 0x23c048, 0x23c044};
+
+static struct attn_hw_reg *rpb_int_bb_b0_regs[1] = {
+       &rpb_int0_bb_b0};
+
+static struct attn_hw_reg rpb_prty0_bb_b0 = {
+       0, 1, 0x23c050, 0x23c05c, 0x23c058, 0x23c054};
+
+static struct attn_hw_reg *rpb_prty_bb_b0_regs[1] = {
+       &rpb_prty0_bb_b0};
+
+static struct attn_hw_reg btb_int0_bb_b0 = {
+       0, 16, 0xdb00c0, 0xdb00cc, 0xdb00c8, 0xdb00c4};
+
+static struct attn_hw_reg btb_int1_bb_b0 = {
+       1, 16, 0xdb00d8, 0xdb00e4, 0xdb00e0, 0xdb00dc};
+
+static struct attn_hw_reg btb_int2_bb_b0 = {
+       2, 4, 0xdb00f0, 0xdb00fc, 0xdb00f8, 0xdb00f4};
+
+static struct attn_hw_reg btb_int3_bb_b0 = {
+       3, 32, 0xdb0108, 0xdb0114, 0xdb0110, 0xdb010c};
+
+static struct attn_hw_reg btb_int4_bb_b0 = {
+       4, 23, 0xdb0120, 0xdb012c, 0xdb0128, 0xdb0124};
+
+static struct attn_hw_reg btb_int5_bb_b0 = {
+       5, 32, 0xdb0138, 0xdb0144, 0xdb0140, 0xdb013c};
+
+static struct attn_hw_reg btb_int6_bb_b0 = {
+       6, 1, 0xdb0150, 0xdb015c, 0xdb0158, 0xdb0154};
+
+static struct attn_hw_reg btb_int8_bb_b0 = {
+       7, 1, 0xdb0184, 0xdb0190, 0xdb018c, 0xdb0188};
+
+static struct attn_hw_reg btb_int9_bb_b0 = {
+       8, 1, 0xdb019c, 0xdb01a8, 0xdb01a4, 0xdb01a0};
+
+static struct attn_hw_reg btb_int10_bb_b0 = {
+       9, 1, 0xdb01b4, 0xdb01c0, 0xdb01bc, 0xdb01b8};
+
+static struct attn_hw_reg btb_int11_bb_b0 = {
+       10, 2, 0xdb01cc, 0xdb01d8, 0xdb01d4, 0xdb01d0};
+
+static struct attn_hw_reg *btb_int_bb_b0_regs[11] = {
+       &btb_int0_bb_b0, &btb_int1_bb_b0, &btb_int2_bb_b0, &btb_int3_bb_b0,
+       &btb_int4_bb_b0, &btb_int5_bb_b0, &btb_int6_bb_b0, &btb_int8_bb_b0,
+       &btb_int9_bb_b0, &btb_int10_bb_b0, &btb_int11_bb_b0};
+
+static struct attn_hw_reg btb_prty0_bb_b0 = {
+       0, 5, 0xdb01dc, 0xdb01e8, 0xdb01e4, 0xdb01e0};
+
+static struct attn_hw_reg btb_prty1_bb_b0 = {
+       1, 23, 0xdb0400, 0xdb040c, 0xdb0408, 0xdb0404};
+
+static struct attn_hw_reg *btb_prty_bb_b0_regs[2] = {
+       &btb_prty0_bb_b0, &btb_prty1_bb_b0};
+
+static struct attn_hw_reg pbf_int0_bb_b0 = {
+       0, 1, 0xd80180, 0xd8018c, 0xd80188, 0xd80184};
+
+static struct attn_hw_reg *pbf_int_bb_b0_regs[1] = {
+       &pbf_int0_bb_b0};
+
+static struct attn_hw_reg pbf_prty0_bb_b0 = {
+       0, 1, 0xd80190, 0xd8019c, 0xd80198, 0xd80194};
+
+static struct attn_hw_reg pbf_prty1_bb_b0 = {
+       1, 31, 0xd80200, 0xd8020c, 0xd80208, 0xd80204};
+
+static struct attn_hw_reg pbf_prty2_bb_b0 = {
+       2, 27, 0xd80210, 0xd8021c, 0xd80218, 0xd80214};
+
+static struct attn_hw_reg *pbf_prty_bb_b0_regs[3] = {
+       &pbf_prty0_bb_b0, &pbf_prty1_bb_b0, &pbf_prty2_bb_b0};
+
+static struct attn_hw_reg rdif_int0_bb_b0 = {
+       0, 8, 0x300180, 0x30018c, 0x300188, 0x300184};
+
+static struct attn_hw_reg *rdif_int_bb_b0_regs[1] = {
+       &rdif_int0_bb_b0};
+
+static struct attn_hw_reg rdif_prty0_bb_b0 = {
+       0, 1, 0x300190, 0x30019c, 0x300198, 0x300194};
+
+static struct attn_hw_reg *rdif_prty_bb_b0_regs[1] = {
+       &rdif_prty0_bb_b0};
+
+static struct attn_hw_reg tdif_int0_bb_b0 = {
+       0, 8, 0x310180, 0x31018c, 0x310188, 0x310184};
+
+static struct attn_hw_reg *tdif_int_bb_b0_regs[1] = {
+       &tdif_int0_bb_b0};
+
+static struct attn_hw_reg tdif_prty0_bb_b0 = {
+       0, 1, 0x310190, 0x31019c, 0x310198, 0x310194};
+
+static struct attn_hw_reg tdif_prty1_bb_b0 = {
+       1, 11, 0x310200, 0x31020c, 0x310208, 0x310204};
+
+static struct attn_hw_reg *tdif_prty_bb_b0_regs[2] = {
+       &tdif_prty0_bb_b0, &tdif_prty1_bb_b0};
+
+static struct attn_hw_reg cdu_int0_bb_b0 = {
+       0, 8, 0x5801c0, 0x5801c4, 0x5801c8, 0x5801cc};
+
+static struct attn_hw_reg *cdu_int_bb_b0_regs[1] = {
+       &cdu_int0_bb_b0};
+
+static struct attn_hw_reg cdu_prty1_bb_b0 = {
+       0, 5, 0x580200, 0x58020c, 0x580208, 0x580204};
+
+static struct attn_hw_reg *cdu_prty_bb_b0_regs[1] = {
+       &cdu_prty1_bb_b0};
+
+static struct attn_hw_reg ccfc_int0_bb_b0 = {
+       0, 2, 0x2e0180, 0x2e018c, 0x2e0188, 0x2e0184};
+
+static struct attn_hw_reg *ccfc_int_bb_b0_regs[1] = {
+       &ccfc_int0_bb_b0};
+
+static struct attn_hw_reg ccfc_prty1_bb_b0 = {
+       0, 2, 0x2e0200, 0x2e020c, 0x2e0208, 0x2e0204};
+
+static struct attn_hw_reg ccfc_prty0_bb_b0 = {
+       1, 6, 0x2e05e4, 0x2e05f0, 0x2e05ec, 0x2e05e8};
+
+static struct attn_hw_reg *ccfc_prty_bb_b0_regs[2] = {
+       &ccfc_prty1_bb_b0, &ccfc_prty0_bb_b0};
+
+static struct attn_hw_reg tcfc_int0_bb_b0 = {
+       0, 2, 0x2d0180, 0x2d018c, 0x2d0188, 0x2d0184};
+
+static struct attn_hw_reg *tcfc_int_bb_b0_regs[1] = {
+       &tcfc_int0_bb_b0};
+
+static struct attn_hw_reg tcfc_prty1_bb_b0 = {
+       0, 2, 0x2d0200, 0x2d020c, 0x2d0208, 0x2d0204};
+
+static struct attn_hw_reg tcfc_prty0_bb_b0 = {
+       1, 6, 0x2d05e4, 0x2d05f0, 0x2d05ec, 0x2d05e8};
+
+static struct attn_hw_reg *tcfc_prty_bb_b0_regs[2] = {
+       &tcfc_prty1_bb_b0, &tcfc_prty0_bb_b0};
+
+static struct attn_hw_reg igu_int0_bb_b0 = {
+       0, 11, 0x180180, 0x18018c, 0x180188, 0x180184};
+
+static struct attn_hw_reg *igu_int_bb_b0_regs[1] = {
+       &igu_int0_bb_b0};
+
+static struct attn_hw_reg igu_prty0_bb_b0 = {
+       0, 1, 0x180190, 0x18019c, 0x180198, 0x180194};
+
+static struct attn_hw_reg igu_prty1_bb_b0 = {
+       1, 31, 0x180200, 0x18020c, 0x180208, 0x180204};
+
+static struct attn_hw_reg igu_prty2_bb_b0 = {
+       2, 1, 0x180210, 0x18021c, 0x180218, 0x180214};
+
+static struct attn_hw_reg *igu_prty_bb_b0_regs[3] = {
+       &igu_prty0_bb_b0, &igu_prty1_bb_b0, &igu_prty2_bb_b0};
+
+static struct attn_hw_reg cau_int0_bb_b0 = {
+       0, 11, 0x1c00d4, 0x1c00d8, 0x1c00dc, 0x1c00e0};
+
+static struct attn_hw_reg *cau_int_bb_b0_regs[1] = {
+       &cau_int0_bb_b0};
+
+static struct attn_hw_reg cau_prty1_bb_b0 = {
+       0, 13, 0x1c0200, 0x1c020c, 0x1c0208, 0x1c0204};
+
+static struct attn_hw_reg *cau_prty_bb_b0_regs[1] = {
+       &cau_prty1_bb_b0};
+
+static struct attn_hw_reg dbg_int0_bb_b0 = {
+       0, 1, 0x10180, 0x1018c, 0x10188, 0x10184};
+
+static struct attn_hw_reg *dbg_int_bb_b0_regs[1] = {
+       &dbg_int0_bb_b0};
+
+static struct attn_hw_reg dbg_prty1_bb_b0 = {
+       0, 1, 0x10200, 0x1020c, 0x10208, 0x10204};
+
+static struct attn_hw_reg *dbg_prty_bb_b0_regs[1] = {
+       &dbg_prty1_bb_b0};
+
+static struct attn_hw_reg nig_int0_bb_b0 = {
+       0, 12, 0x500040, 0x50004c, 0x500048, 0x500044};
+
+static struct attn_hw_reg nig_int1_bb_b0 = {
+       1, 32, 0x500050, 0x50005c, 0x500058, 0x500054};
+
+static struct attn_hw_reg nig_int2_bb_b0 = {
+       2, 20, 0x500060, 0x50006c, 0x500068, 0x500064};
+
+static struct attn_hw_reg nig_int3_bb_b0 = {
+       3, 18, 0x500070, 0x50007c, 0x500078, 0x500074};
+
+static struct attn_hw_reg nig_int4_bb_b0 = {
+       4, 20, 0x500080, 0x50008c, 0x500088, 0x500084};
+
+static struct attn_hw_reg nig_int5_bb_b0 = {
+       5, 18, 0x500090, 0x50009c, 0x500098, 0x500094};
+
+static struct attn_hw_reg *nig_int_bb_b0_regs[6] = {
+       &nig_int0_bb_b0, &nig_int1_bb_b0, &nig_int2_bb_b0, &nig_int3_bb_b0,
+       &nig_int4_bb_b0, &nig_int5_bb_b0};
+
+static struct attn_hw_reg nig_prty0_bb_b0 = {
+       0, 1, 0x5000a0, 0x5000ac, 0x5000a8, 0x5000a4};
+
+static struct attn_hw_reg nig_prty1_bb_b0 = {
+       1, 31, 0x500200, 0x50020c, 0x500208, 0x500204};
+
+static struct attn_hw_reg nig_prty2_bb_b0 = {
+       2, 31, 0x500210, 0x50021c, 0x500218, 0x500214};
+
+static struct attn_hw_reg nig_prty3_bb_b0 = {
+       3, 31, 0x500220, 0x50022c, 0x500228, 0x500224};
+
+static struct attn_hw_reg nig_prty4_bb_b0 = {
+       4, 17, 0x500230, 0x50023c, 0x500238, 0x500234};
+
+static struct attn_hw_reg *nig_prty_bb_b0_regs[5] = {
+       &nig_prty0_bb_b0, &nig_prty1_bb_b0, &nig_prty2_bb_b0,
+       &nig_prty3_bb_b0, &nig_prty4_bb_b0};
+
+static struct attn_hw_reg ipc_int0_bb_b0 = {
+       0, 13, 0x2050c, 0x20518, 0x20514, 0x20510};
+
+static struct attn_hw_reg *ipc_int_bb_b0_regs[1] = {
+       &ipc_int0_bb_b0};
+
+static struct attn_hw_reg ipc_prty0_bb_b0 = {
+       0, 1, 0x2051c, 0x20528, 0x20524, 0x20520};
+
+static struct attn_hw_reg *ipc_prty_bb_b0_regs[1] = {
+       &ipc_prty0_bb_b0};
+
+static struct attn_hw_block attn_blocks[] = {
+       {"grc", {{1, 1, grc_int_bb_b0_regs, grc_prty_bb_b0_regs} } },
+       {"miscs", {{2, 1, miscs_int_bb_b0_regs, miscs_prty_bb_b0_regs} } },
+       {"misc", {{1, 0, misc_int_bb_b0_regs, NULL} } },
+       {"dbu", {{0, 0, NULL, NULL} } },
+       {"pglue_b", {{1, 2, pglue_b_int_bb_b0_regs,
+                     pglue_b_prty_bb_b0_regs} } },
+       {"cnig", {{1, 1, cnig_int_bb_b0_regs, cnig_prty_bb_b0_regs} } },
+       {"cpmu", {{1, 0, cpmu_int_bb_b0_regs, NULL} } },
+       {"ncsi", {{1, 1, ncsi_int_bb_b0_regs, ncsi_prty_bb_b0_regs} } },
+       {"opte", {{0, 2, NULL, opte_prty_bb_b0_regs} } },
+       {"bmb", {{12, 3, bmb_int_bb_b0_regs, bmb_prty_bb_b0_regs} } },
+       {"pcie", {{0, 1, NULL, pcie_prty_bb_b0_regs} } },
+       {"mcp", {{0, 0, NULL, NULL} } },
+       {"mcp2", {{0, 2, NULL, mcp2_prty_bb_b0_regs} } },
+       {"pswhst", {{1, 2, pswhst_int_bb_b0_regs, pswhst_prty_bb_b0_regs} } },
+       {"pswhst2", {{1, 1, pswhst2_int_bb_b0_regs,
+                     pswhst2_prty_bb_b0_regs} } },
+       {"pswrd", {{1, 1, pswrd_int_bb_b0_regs, pswrd_prty_bb_b0_regs} } },
+       {"pswrd2", {{1, 3, pswrd2_int_bb_b0_regs, pswrd2_prty_bb_b0_regs} } },
+       {"pswwr", {{1, 1, pswwr_int_bb_b0_regs, pswwr_prty_bb_b0_regs} } },
+       {"pswwr2", {{1, 5, pswwr2_int_bb_b0_regs, pswwr2_prty_bb_b0_regs} } },
+       {"pswrq", {{1, 1, pswrq_int_bb_b0_regs, pswrq_prty_bb_b0_regs} } },
+       {"pswrq2", {{1, 1, pswrq2_int_bb_b0_regs, pswrq2_prty_bb_b0_regs} } },
+       {"pglcs", {{1, 0, pglcs_int_bb_b0_regs, NULL} } },
+       {"dmae", {{1, 1, dmae_int_bb_b0_regs, dmae_prty_bb_b0_regs} } },
+       {"ptu", {{1, 1, ptu_int_bb_b0_regs, ptu_prty_bb_b0_regs} } },
+       {"tcm", {{3, 2, tcm_int_bb_b0_regs, tcm_prty_bb_b0_regs} } },
+       {"mcm", {{3, 2, mcm_int_bb_b0_regs, mcm_prty_bb_b0_regs} } },
+       {"ucm", {{3, 2, ucm_int_bb_b0_regs, ucm_prty_bb_b0_regs} } },
+       {"xcm", {{3, 2, xcm_int_bb_b0_regs, xcm_prty_bb_b0_regs} } },
+       {"ycm", {{3, 2, ycm_int_bb_b0_regs, ycm_prty_bb_b0_regs} } },
+       {"pcm", {{3, 1, pcm_int_bb_b0_regs, pcm_prty_bb_b0_regs} } },
+       {"qm", {{1, 4, qm_int_bb_b0_regs, qm_prty_bb_b0_regs} } },
+       {"tm", {{2, 1, tm_int_bb_b0_regs, tm_prty_bb_b0_regs} } },
+       {"dorq", {{1, 2, dorq_int_bb_b0_regs, dorq_prty_bb_b0_regs} } },
+       {"brb", {{12, 3, brb_int_bb_b0_regs, brb_prty_bb_b0_regs} } },
+       {"src", {{1, 0, src_int_bb_b0_regs, NULL} } },
+       {"prs", {{1, 3, prs_int_bb_b0_regs, prs_prty_bb_b0_regs} } },
+       {"tsdm", {{1, 1, tsdm_int_bb_b0_regs, tsdm_prty_bb_b0_regs} } },
+       {"msdm", {{1, 1, msdm_int_bb_b0_regs, msdm_prty_bb_b0_regs} } },
+       {"usdm", {{1, 1, usdm_int_bb_b0_regs, usdm_prty_bb_b0_regs} } },
+       {"xsdm", {{1, 1, xsdm_int_bb_b0_regs, xsdm_prty_bb_b0_regs} } },
+       {"ysdm", {{1, 1, ysdm_int_bb_b0_regs, ysdm_prty_bb_b0_regs} } },
+       {"psdm", {{1, 1, psdm_int_bb_b0_regs, psdm_prty_bb_b0_regs} } },
+       {"tsem", {{3, 3, tsem_int_bb_b0_regs, tsem_prty_bb_b0_regs} } },
+       {"msem", {{3, 2, msem_int_bb_b0_regs, msem_prty_bb_b0_regs} } },
+       {"usem", {{3, 2, usem_int_bb_b0_regs, usem_prty_bb_b0_regs} } },
+       {"xsem", {{3, 2, xsem_int_bb_b0_regs, xsem_prty_bb_b0_regs} } },
+       {"ysem", {{3, 2, ysem_int_bb_b0_regs, ysem_prty_bb_b0_regs} } },
+       {"psem", {{3, 3, psem_int_bb_b0_regs, psem_prty_bb_b0_regs} } },
+       {"rss", {{1, 1, rss_int_bb_b0_regs, rss_prty_bb_b0_regs} } },
+       {"tmld", {{1, 1, tmld_int_bb_b0_regs, tmld_prty_bb_b0_regs} } },
+       {"muld", {{1, 1, muld_int_bb_b0_regs, muld_prty_bb_b0_regs} } },
+       {"yuld", {{1, 1, yuld_int_bb_b0_regs, yuld_prty_bb_b0_regs} } },
+       {"xyld", {{1, 1, xyld_int_bb_b0_regs, xyld_prty_bb_b0_regs} } },
+       {"prm", {{1, 2, prm_int_bb_b0_regs, prm_prty_bb_b0_regs} } },
+       {"pbf_pb1", {{1, 1, pbf_pb1_int_bb_b0_regs,
+                     pbf_pb1_prty_bb_b0_regs} } },
+       {"pbf_pb2", {{1, 1, pbf_pb2_int_bb_b0_regs,
+                     pbf_pb2_prty_bb_b0_regs} } },
+       {"rpb", { {1, 1, rpb_int_bb_b0_regs, rpb_prty_bb_b0_regs} } },
+       {"btb", { {11, 2, btb_int_bb_b0_regs, btb_prty_bb_b0_regs} } },
+       {"pbf", { {1, 3, pbf_int_bb_b0_regs, pbf_prty_bb_b0_regs} } },
+       {"rdif", { {1, 1, rdif_int_bb_b0_regs, rdif_prty_bb_b0_regs} } },
+       {"tdif", { {1, 2, tdif_int_bb_b0_regs, tdif_prty_bb_b0_regs} } },
+       {"cdu", { {1, 1, cdu_int_bb_b0_regs, cdu_prty_bb_b0_regs} } },
+       {"ccfc", { {1, 2, ccfc_int_bb_b0_regs, ccfc_prty_bb_b0_regs} } },
+       {"tcfc", { {1, 2, tcfc_int_bb_b0_regs, tcfc_prty_bb_b0_regs} } },
+       {"igu", { {1, 3, igu_int_bb_b0_regs, igu_prty_bb_b0_regs} } },
+       {"cau", { {1, 1, cau_int_bb_b0_regs, cau_prty_bb_b0_regs} } },
+       {"umac", { {0, 0, NULL, NULL} } },
+       {"xmac", { {0, 0, NULL, NULL} } },
+       {"dbg", { {1, 1, dbg_int_bb_b0_regs, dbg_prty_bb_b0_regs} } },
+       {"nig", { {6, 5, nig_int_bb_b0_regs, nig_prty_bb_b0_regs} } },
+       {"wol", { {0, 0, NULL, NULL} } },
+       {"bmbn", { {0, 0, NULL, NULL} } },
+       {"ipc", { {1, 1, ipc_int_bb_b0_regs, ipc_prty_bb_b0_regs} } },
+       {"nwm", { {0, 0, NULL, NULL} } },
+       {"nws", { {0, 0, NULL, NULL} } },
+       {"ms", { {0, 0, NULL, NULL} } },
+       {"phy_pcie", { {0, 0, NULL, NULL} } },
+       {"misc_aeu", { {0, 0, NULL, NULL} } },
+       {"bar0_map", { {0, 0, NULL, NULL} } },};
+
+/* Specific HW attention callbacks */
+static int qed_mcp_attn_cb(struct qed_hwfn *p_hwfn)
+{
+       u32 tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, MCP_REG_CPU_STATE);
+
+       /* This might occur on certain instances; Log it once then mask it */
+       DP_INFO(p_hwfn->cdev, "MCP_REG_CPU_STATE: %08x - Masking...\n",
+               tmp);
+       qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, MCP_REG_CPU_EVENT_MASK,
+              0xffffffff);
+
+       return 0;
+}
+
+#define QED_PSWHST_ATTENTION_INCORRECT_ACCESS          (0x1)
+#define ATTENTION_INCORRECT_ACCESS_WR_MASK             (0x1)
+#define ATTENTION_INCORRECT_ACCESS_WR_SHIFT            (0)
+#define ATTENTION_INCORRECT_ACCESS_CLIENT_MASK         (0xf)
+#define ATTENTION_INCORRECT_ACCESS_CLIENT_SHIFT                (1)
+#define ATTENTION_INCORRECT_ACCESS_VF_VALID_MASK       (0x1)
+#define ATTENTION_INCORRECT_ACCESS_VF_VALID_SHIFT      (5)
+#define ATTENTION_INCORRECT_ACCESS_VF_ID_MASK          (0xff)
+#define ATTENTION_INCORRECT_ACCESS_VF_ID_SHIFT         (6)
+#define ATTENTION_INCORRECT_ACCESS_PF_ID_MASK          (0xf)
+#define ATTENTION_INCORRECT_ACCESS_PF_ID_SHIFT         (14)
+#define ATTENTION_INCORRECT_ACCESS_BYTE_EN_MASK                (0xff)
+#define ATTENTION_INCORRECT_ACCESS_BYTE_EN_SHIFT       (18)
+static int qed_pswhst_attn_cb(struct qed_hwfn *p_hwfn)
+{
+       u32 tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                        PSWHST_REG_INCORRECT_ACCESS_VALID);
+
+       if (tmp & QED_PSWHST_ATTENTION_INCORRECT_ACCESS) {
+               u32 addr, data, length;
+
+               addr = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                             PSWHST_REG_INCORRECT_ACCESS_ADDRESS);
+               data = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                             PSWHST_REG_INCORRECT_ACCESS_DATA);
+               length = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                               PSWHST_REG_INCORRECT_ACCESS_LENGTH);
+
+               DP_INFO(p_hwfn->cdev,
+                       "Incorrect access to %08x of length %08x - PF [%02x] VF [%04x] [valid %02x] client [%02x] write [%02x] Byte-Enable [%04x] [%08x]\n",
+                       addr, length,
+                       (u8) GET_FIELD(data, ATTENTION_INCORRECT_ACCESS_PF_ID),
+                       (u8) GET_FIELD(data, ATTENTION_INCORRECT_ACCESS_VF_ID),
+                       (u8) GET_FIELD(data,
+                                      ATTENTION_INCORRECT_ACCESS_VF_VALID),
+                       (u8) GET_FIELD(data,
+                                      ATTENTION_INCORRECT_ACCESS_CLIENT),
+                       (u8) GET_FIELD(data, ATTENTION_INCORRECT_ACCESS_WR),
+                       (u8) GET_FIELD(data,
+                                      ATTENTION_INCORRECT_ACCESS_BYTE_EN),
+                       data);
+       }
+
+       return 0;
+}
+
+#define QED_GRC_ATTENTION_VALID_BIT    (1 << 0)
+#define QED_GRC_ATTENTION_ADDRESS_MASK (0x7fffff)
+#define QED_GRC_ATTENTION_ADDRESS_SHIFT        (0)
+#define QED_GRC_ATTENTION_RDWR_BIT     (1 << 23)
+#define QED_GRC_ATTENTION_MASTER_MASK  (0xf)
+#define QED_GRC_ATTENTION_MASTER_SHIFT (24)
+#define QED_GRC_ATTENTION_PF_MASK      (0xf)
+#define QED_GRC_ATTENTION_PF_SHIFT     (0)
+#define QED_GRC_ATTENTION_VF_MASK      (0xff)
+#define QED_GRC_ATTENTION_VF_SHIFT     (4)
+#define QED_GRC_ATTENTION_PRIV_MASK    (0x3)
+#define QED_GRC_ATTENTION_PRIV_SHIFT   (14)
+#define QED_GRC_ATTENTION_PRIV_VF      (0)
+static const char *attn_master_to_str(u8 master)
+{
+       switch (master) {
+       case 1: return "PXP";
+       case 2: return "MCP";
+       case 3: return "MSDM";
+       case 4: return "PSDM";
+       case 5: return "YSDM";
+       case 6: return "USDM";
+       case 7: return "TSDM";
+       case 8: return "XSDM";
+       case 9: return "DBU";
+       case 10: return "DMAE";
+       default:
+               return "Unkown";
+       }
+}
+
+static int qed_grc_attn_cb(struct qed_hwfn *p_hwfn)
+{
+       u32 tmp, tmp2;
+
+       /* We've already cleared the timeout interrupt register, so we learn
+        * of interrupts via the validity register
+        */
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    GRC_REG_TIMEOUT_ATTN_ACCESS_VALID);
+       if (!(tmp & QED_GRC_ATTENTION_VALID_BIT))
+               goto out;
+
+       /* Read the GRC timeout information */
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    GRC_REG_TIMEOUT_ATTN_ACCESS_DATA_0);
+       tmp2 = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                     GRC_REG_TIMEOUT_ATTN_ACCESS_DATA_1);
+
+       DP_INFO(p_hwfn->cdev,
+               "GRC timeout [%08x:%08x] - %s Address [%08x] [Master %s] [PF: %02x %s %02x]\n",
+               tmp2, tmp,
+               (tmp & QED_GRC_ATTENTION_RDWR_BIT) ? "Write to" : "Read from",
+               GET_FIELD(tmp, QED_GRC_ATTENTION_ADDRESS) << 2,
+               attn_master_to_str(GET_FIELD(tmp, QED_GRC_ATTENTION_MASTER)),
+               GET_FIELD(tmp2, QED_GRC_ATTENTION_PF),
+               (GET_FIELD(tmp2, QED_GRC_ATTENTION_PRIV) ==
+                QED_GRC_ATTENTION_PRIV_VF) ? "VF" : "(Ireelevant)",
+               GET_FIELD(tmp2, QED_GRC_ATTENTION_VF));
+
+out:
+       /* Regardles of anything else, clean the validity bit */
+       qed_wr(p_hwfn, p_hwfn->p_dpc_ptt,
+              GRC_REG_TIMEOUT_ATTN_ACCESS_VALID, 0);
+       return 0;
+}
+
+#define PGLUE_ATTENTION_VALID                  (1 << 29)
+#define PGLUE_ATTENTION_RD_VALID               (1 << 26)
+#define PGLUE_ATTENTION_DETAILS_PFID_MASK      (0xf)
+#define PGLUE_ATTENTION_DETAILS_PFID_SHIFT     (20)
+#define PGLUE_ATTENTION_DETAILS_VF_VALID_MASK  (0x1)
+#define PGLUE_ATTENTION_DETAILS_VF_VALID_SHIFT (19)
+#define PGLUE_ATTENTION_DETAILS_VFID_MASK      (0xff)
+#define PGLUE_ATTENTION_DETAILS_VFID_SHIFT     (24)
+#define PGLUE_ATTENTION_DETAILS2_WAS_ERR_MASK  (0x1)
+#define PGLUE_ATTENTION_DETAILS2_WAS_ERR_SHIFT (21)
+#define PGLUE_ATTENTION_DETAILS2_BME_MASK      (0x1)
+#define PGLUE_ATTENTION_DETAILS2_BME_SHIFT     (22)
+#define PGLUE_ATTENTION_DETAILS2_FID_EN_MASK   (0x1)
+#define PGLUE_ATTENTION_DETAILS2_FID_EN_SHIFT  (23)
+#define PGLUE_ATTENTION_ICPL_VALID             (1 << 23)
+#define PGLUE_ATTENTION_ZLR_VALID              (1 << 25)
+#define PGLUE_ATTENTION_ILT_VALID              (1 << 23)
+static int qed_pglub_rbc_attn_cb(struct qed_hwfn *p_hwfn)
+{
+       u32 tmp;
+
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    PGLUE_B_REG_TX_ERR_WR_DETAILS2);
+       if (tmp & PGLUE_ATTENTION_VALID) {
+               u32 addr_lo, addr_hi, details;
+
+               addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_WR_ADD_31_0);
+               addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_WR_ADD_63_32);
+               details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_WR_DETAILS);
+
+               DP_INFO(p_hwfn,
+                       "Illegal write by chip to [%08x:%08x] blocked.\n"
+                       "Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n"
+                       "Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n",
+                       addr_hi, addr_lo, details,
+                       (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID),
+                       (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID),
+                       GET_FIELD(details,
+                                 PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0,
+                       tmp,
+                       GET_FIELD(tmp,
+                                 PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1 : 0,
+                       GET_FIELD(tmp,
+                                 PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0,
+                       GET_FIELD(tmp,
+                                 PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1 : 0);
+       }
+
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    PGLUE_B_REG_TX_ERR_RD_DETAILS2);
+       if (tmp & PGLUE_ATTENTION_RD_VALID) {
+               u32 addr_lo, addr_hi, details;
+
+               addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_RD_ADD_31_0);
+               addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_RD_ADD_63_32);
+               details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_TX_ERR_RD_DETAILS);
+
+               DP_INFO(p_hwfn,
+                       "Illegal read by chip from [%08x:%08x] blocked.\n"
+                       " Details: %08x [PFID %02x, VFID %02x, VF_VALID %02x]\n"
+                       " Details2 %08x [Was_error %02x BME deassert %02x FID_enable deassert %02x]\n",
+                       addr_hi, addr_lo, details,
+                       (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_PFID),
+                       (u8)GET_FIELD(details, PGLUE_ATTENTION_DETAILS_VFID),
+                       GET_FIELD(details,
+                                 PGLUE_ATTENTION_DETAILS_VF_VALID) ? 1 : 0,
+                       tmp,
+                       GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_WAS_ERR) ? 1
+                                                                        : 0,
+                       GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_BME) ? 1 : 0,
+                       GET_FIELD(tmp, PGLUE_ATTENTION_DETAILS2_FID_EN) ? 1
+                                                                       : 0);
+       }
+
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL);
+       if (tmp & PGLUE_ATTENTION_ICPL_VALID)
+               DP_INFO(p_hwfn, "ICPL eror - %08x\n", tmp);
+
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS);
+       if (tmp & PGLUE_ATTENTION_ZLR_VALID) {
+               u32 addr_hi, addr_lo;
+
+               addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_MASTER_ZLR_ERR_ADD_31_0);
+               addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_MASTER_ZLR_ERR_ADD_63_32);
+
+               DP_INFO(p_hwfn, "ZLR eror - %08x [Address %08x:%08x]\n",
+                       tmp, addr_hi, addr_lo);
+       }
+
+       tmp = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                    PGLUE_B_REG_VF_ILT_ERR_DETAILS2);
+       if (tmp & PGLUE_ATTENTION_ILT_VALID) {
+               u32 addr_hi, addr_lo, details;
+
+               addr_lo = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_VF_ILT_ERR_ADD_31_0);
+               addr_hi = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_VF_ILT_ERR_ADD_63_32);
+               details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                PGLUE_B_REG_VF_ILT_ERR_DETAILS);
+
+               DP_INFO(p_hwfn,
+                       "ILT error - Details %08x Details2 %08x [Address %08x:%08x]\n",
+                       details, tmp, addr_hi, addr_lo);
+       }
+
+       /* Clear the indications */
+       qed_wr(p_hwfn, p_hwfn->p_dpc_ptt,
+              PGLUE_B_REG_LATCHED_ERRORS_CLR, (1 << 2));
+
+       return 0;
+}
+
+#define QED_DORQ_ATTENTION_REASON_MASK (0xfffff)
+#define QED_DORQ_ATTENTION_OPAQUE_MASK (0xffff)
+#define QED_DORQ_ATTENTION_SIZE_MASK   (0x7f)
+#define QED_DORQ_ATTENTION_SIZE_SHIFT  (16)
+static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn)
+{
+       u32 reason;
+
+       reason = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, DORQ_REG_DB_DROP_REASON) &
+                       QED_DORQ_ATTENTION_REASON_MASK;
+       if (reason) {
+               u32 details = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                    DORQ_REG_DB_DROP_DETAILS);
+
+               DP_INFO(p_hwfn->cdev,
+                       "DORQ db_drop: adress 0x%08x Opaque FID 0x%04x Size [bytes] 0x%08x Reason: 0x%08x\n",
+                       qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                              DORQ_REG_DB_DROP_DETAILS_ADDRESS),
+                       (u16)(details & QED_DORQ_ATTENTION_OPAQUE_MASK),
+                       GET_FIELD(details, QED_DORQ_ATTENTION_SIZE) * 4,
+                       reason);
+       }
+
+       return -EINVAL;
+}
+
+/* Notice aeu_invert_reg must be defined in the same order of bits as HW;  */
+static struct aeu_invert_reg aeu_descs[NUM_ATTN_REGS] = {
+       {
+               {       /* After Invert 1 */
+                       {"GPIO0 function%d",
+                        (32 << ATTENTION_LENGTH_SHIFT), NULL, MAX_BLOCK_ID},
+               }
+       },
+
+       {
+               {       /* After Invert 2 */
+                       {"PGLUE config_space", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"PGLUE misc_flr", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"PGLUE B RBC", ATTENTION_PAR_INT,
+                        qed_pglub_rbc_attn_cb, BLOCK_PGLUE_B},
+                       {"PGLUE misc_mctp", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"Flash event", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID},
+                       {"SMB event", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID},
+                       {"Main Power", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID},
+                       {"SW timers #%d", (8 << ATTENTION_LENGTH_SHIFT) |
+                                         (1 << ATTENTION_OFFSET_SHIFT),
+                        NULL, MAX_BLOCK_ID},
+                       {"PCIE glue/PXP VPD %d",
+                        (16 << ATTENTION_LENGTH_SHIFT), NULL, BLOCK_PGLCS},
+               }
+       },
+
+       {
+               {       /* After Invert 3 */
+                       {"General Attention %d",
+                        (32 << ATTENTION_LENGTH_SHIFT), NULL, MAX_BLOCK_ID},
+               }
+       },
+
+       {
+               {       /* After Invert 4 */
+                       {"General Attention 32", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"General Attention %d",
+                        (2 << ATTENTION_LENGTH_SHIFT) |
+                        (33 << ATTENTION_OFFSET_SHIFT), NULL, MAX_BLOCK_ID},
+                       {"General Attention 35", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"CNIG port %d", (4 << ATTENTION_LENGTH_SHIFT),
+                        NULL, BLOCK_CNIG},
+                       {"MCP CPU", ATTENTION_SINGLE,
+                        qed_mcp_attn_cb, MAX_BLOCK_ID},
+                       {"MCP Watchdog timer", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"MCP M2P", ATTENTION_SINGLE, NULL, MAX_BLOCK_ID},
+                       {"AVS stop status ready", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"MSTAT", ATTENTION_PAR_INT, NULL, MAX_BLOCK_ID},
+                       {"MSTAT per-path", ATTENTION_PAR_INT,
+                        NULL, MAX_BLOCK_ID},
+                       {"Reserved %d", (6 << ATTENTION_LENGTH_SHIFT),
+                        NULL, MAX_BLOCK_ID},
+                       {"NIG", ATTENTION_PAR_INT, NULL, BLOCK_NIG},
+                       {"BMB/OPTE/MCP", ATTENTION_PAR_INT, NULL, BLOCK_BMB},
+                       {"BTB", ATTENTION_PAR_INT, NULL, BLOCK_BTB},
+                       {"BRB", ATTENTION_PAR_INT, NULL, BLOCK_BRB},
+                       {"PRS", ATTENTION_PAR_INT, NULL, BLOCK_PRS},
+               }
+       },
+
+       {
+               {       /* After Invert 5 */
+                       {"SRC", ATTENTION_PAR_INT, NULL, BLOCK_SRC},
+                       {"PB Client1", ATTENTION_PAR_INT, NULL, BLOCK_PBF_PB1},
+                       {"PB Client2", ATTENTION_PAR_INT, NULL, BLOCK_PBF_PB2},
+                       {"RPB", ATTENTION_PAR_INT, NULL, BLOCK_RPB},
+                       {"PBF", ATTENTION_PAR_INT, NULL, BLOCK_PBF},
+                       {"QM", ATTENTION_PAR_INT, NULL, BLOCK_QM},
+                       {"TM", ATTENTION_PAR_INT, NULL, BLOCK_TM},
+                       {"MCM",  ATTENTION_PAR_INT, NULL, BLOCK_MCM},
+                       {"MSDM", ATTENTION_PAR_INT, NULL, BLOCK_MSDM},
+                       {"MSEM", ATTENTION_PAR_INT, NULL, BLOCK_MSEM},
+                       {"PCM", ATTENTION_PAR_INT, NULL, BLOCK_PCM},
+                       {"PSDM", ATTENTION_PAR_INT, NULL, BLOCK_PSDM},
+                       {"PSEM", ATTENTION_PAR_INT, NULL, BLOCK_PSEM},
+                       {"TCM", ATTENTION_PAR_INT, NULL, BLOCK_TCM},
+                       {"TSDM", ATTENTION_PAR_INT, NULL, BLOCK_TSDM},
+                       {"TSEM", ATTENTION_PAR_INT, NULL, BLOCK_TSEM},
+               }
+       },
+
+       {
+               {       /* After Invert 6 */
+                       {"UCM", ATTENTION_PAR_INT, NULL, BLOCK_UCM},
+                       {"USDM", ATTENTION_PAR_INT, NULL, BLOCK_USDM},
+                       {"USEM", ATTENTION_PAR_INT, NULL, BLOCK_USEM},
+                       {"XCM", ATTENTION_PAR_INT, NULL, BLOCK_XCM},
+                       {"XSDM", ATTENTION_PAR_INT, NULL, BLOCK_XSDM},
+                       {"XSEM", ATTENTION_PAR_INT, NULL, BLOCK_XSEM},
+                       {"YCM", ATTENTION_PAR_INT, NULL, BLOCK_YCM},
+                       {"YSDM", ATTENTION_PAR_INT, NULL, BLOCK_YSDM},
+                       {"YSEM", ATTENTION_PAR_INT, NULL, BLOCK_YSEM},
+                       {"XYLD", ATTENTION_PAR_INT, NULL, BLOCK_XYLD},
+                       {"TMLD", ATTENTION_PAR_INT, NULL, BLOCK_TMLD},
+                       {"MYLD", ATTENTION_PAR_INT, NULL, BLOCK_MULD},
+                       {"YULD", ATTENTION_PAR_INT, NULL, BLOCK_YULD},
+                       {"DORQ", ATTENTION_PAR_INT,
+                        qed_dorq_attn_cb, BLOCK_DORQ},
+                       {"DBG", ATTENTION_PAR_INT, NULL, BLOCK_DBG},
+                       {"IPC", ATTENTION_PAR_INT, NULL, BLOCK_IPC},
+               }
+       },
+
+       {
+               {       /* After Invert 7 */
+                       {"CCFC", ATTENTION_PAR_INT, NULL, BLOCK_CCFC},
+                       {"CDU", ATTENTION_PAR_INT, NULL, BLOCK_CDU},
+                       {"DMAE", ATTENTION_PAR_INT, NULL, BLOCK_DMAE},
+                       {"IGU", ATTENTION_PAR_INT, NULL, BLOCK_IGU},
+                       {"ATC", ATTENTION_PAR_INT, NULL, MAX_BLOCK_ID},
+                       {"CAU", ATTENTION_PAR_INT, NULL, BLOCK_CAU},
+                       {"PTU", ATTENTION_PAR_INT, NULL, BLOCK_PTU},
+                       {"PRM", ATTENTION_PAR_INT, NULL, BLOCK_PRM},
+                       {"TCFC", ATTENTION_PAR_INT, NULL, BLOCK_TCFC},
+                       {"RDIF", ATTENTION_PAR_INT, NULL, BLOCK_RDIF},
+                       {"TDIF", ATTENTION_PAR_INT, NULL, BLOCK_TDIF},
+                       {"RSS", ATTENTION_PAR_INT, NULL, BLOCK_RSS},
+                       {"MISC", ATTENTION_PAR_INT, NULL, BLOCK_MISC},
+                       {"MISCS", ATTENTION_PAR_INT, NULL, BLOCK_MISCS},
+                       {"PCIE", ATTENTION_PAR, NULL, BLOCK_PCIE},
+                       {"Vaux PCI core", ATTENTION_SINGLE, NULL, BLOCK_PGLCS},
+                       {"PSWRQ", ATTENTION_PAR_INT, NULL, BLOCK_PSWRQ},
+               }
+       },
+
+       {
+               {       /* After Invert 8 */
+                       {"PSWRQ (pci_clk)", ATTENTION_PAR_INT,
+                        NULL, BLOCK_PSWRQ2},
+                       {"PSWWR", ATTENTION_PAR_INT, NULL, BLOCK_PSWWR},
+                       {"PSWWR (pci_clk)", ATTENTION_PAR_INT,
+                        NULL, BLOCK_PSWWR2},
+                       {"PSWRD", ATTENTION_PAR_INT, NULL, BLOCK_PSWRD},
+                       {"PSWRD (pci_clk)", ATTENTION_PAR_INT,
+                        NULL, BLOCK_PSWRD2},
+                       {"PSWHST", ATTENTION_PAR_INT,
+                        qed_pswhst_attn_cb, BLOCK_PSWHST},
+                       {"PSWHST (pci_clk)", ATTENTION_PAR_INT,
+                        NULL, BLOCK_PSWHST2},
+                       {"GRC", ATTENTION_PAR_INT,
+                        qed_grc_attn_cb, BLOCK_GRC},
+                       {"CPMU", ATTENTION_PAR_INT, NULL, BLOCK_CPMU},
+                       {"NCSI", ATTENTION_PAR_INT, NULL, BLOCK_NCSI},
+                       {"MSEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"PSEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"TSEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"USEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"XSEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"YSEM PRAM", ATTENTION_PAR, NULL, MAX_BLOCK_ID},
+                       {"pxp_misc_mps", ATTENTION_PAR, NULL, BLOCK_PGLCS},
+                       {"PCIE glue/PXP Exp. ROM", ATTENTION_SINGLE,
+                        NULL, BLOCK_PGLCS},
+                       {"PERST_B assertion", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"PERST_B deassertion", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"Reserved %d", (2 << ATTENTION_LENGTH_SHIFT),
+                        NULL, MAX_BLOCK_ID},
+               }
+       },
+
+       {
+               {       /* After Invert 9 */
+                       {"MCP Latched memory", ATTENTION_PAR,
+                        NULL, MAX_BLOCK_ID},
+                       {"MCP Latched scratchpad cache", ATTENTION_SINGLE,
+                        NULL, MAX_BLOCK_ID},
+                       {"MCP Latched ump_tx", ATTENTION_PAR,
+                        NULL, MAX_BLOCK_ID},
+                       {"MCP Latched scratchpad", ATTENTION_PAR,
+                        NULL, MAX_BLOCK_ID},
+                       {"Reserved %d", (28 << ATTENTION_LENGTH_SHIFT),
+                        NULL, MAX_BLOCK_ID},
+               }
+       },
+};
+
+#define ATTN_STATE_BITS         (0xfff)
 #define ATTN_BITS_MASKABLE      (0x3ff)
 struct qed_sb_attn_info {
        /* Virtual & Physical address of the SB */
        struct atten_status_block       *sb_attn;
-       dma_addr_t                    sb_phys;
+       dma_addr_t                      sb_phys;
 
        /* Last seen running index */
-       u16                          index;
+       u16                             index;
+
+       /* A mask of the AEU bits resulting in a parity error */
+       u32                             parity_mask[NUM_ATTN_REGS];
+
+       /* A pointer to the attention description structure */
+       struct aeu_invert_reg           *p_aeu_desc;
 
        /* Previously asserted attentions, which are still unasserted */
-       u16                          known_attn;
+       u16                             known_attn;
 
        /* Cleanup address for the link's general hw attention */
-       u32                          mfw_attn_addr;
+       u32                             mfw_attn_addr;
 };
 
 static inline u16 qed_attn_update_idx(struct qed_hwfn *p_hwfn,
@@ -127,6 +1840,162 @@ static int qed_int_assertion(struct qed_hwfn *p_hwfn,
        return 0;
 }
 
+static void qed_int_deassertion_print_bit(struct qed_hwfn *p_hwfn,
+                                         struct attn_hw_reg *p_reg_desc,
+                                         struct attn_hw_block *p_block,
+                                         enum qed_attention_type type,
+                                         u32 val, u32 mask)
+{
+       int j;
+
+       for (j = 0; j < p_reg_desc->num_of_bits; j++) {
+               if (!(val & (1 << j)))
+                       continue;
+
+               DP_NOTICE(p_hwfn,
+                         "%s (%s): reg %d [0x%08x], bit %d [%s]\n",
+                         p_block->name,
+                         type == QED_ATTN_TYPE_ATTN ? "Interrupt" :
+                                                      "Parity",
+                         p_reg_desc->reg_idx, p_reg_desc->sts_addr,
+                         j, (mask & (1 << j)) ? " [MASKED]" : "");
+       }
+}
+
+/**
+ * @brief qed_int_deassertion_aeu_bit - handles the effects of a single
+ * cause of the attention
+ *
+ * @param p_hwfn
+ * @param p_aeu - descriptor of an AEU bit which caused the attention
+ * @param aeu_en_reg - register offset of the AEU enable reg. which configured
+ *  this bit to this group.
+ * @param bit_index - index of this bit in the aeu_en_reg
+ *
+ * @return int
+ */
+static int
+qed_int_deassertion_aeu_bit(struct qed_hwfn *p_hwfn,
+                           struct aeu_invert_reg_bit *p_aeu,
+                           u32 aeu_en_reg,
+                           u32 bitmask)
+{
+       int rc = -EINVAL;
+       u32 val;
+
+       DP_INFO(p_hwfn, "Deasserted attention `%s'[%08x]\n",
+               p_aeu->bit_name, bitmask);
+
+       /* Call callback before clearing the interrupt status */
+       if (p_aeu->cb) {
+               DP_INFO(p_hwfn, "`%s (attention)': Calling Callback function\n",
+                       p_aeu->bit_name);
+               rc = p_aeu->cb(p_hwfn);
+       }
+
+       /* Handle HW block interrupt registers */
+       if (p_aeu->block_index != MAX_BLOCK_ID) {
+               struct attn_hw_block *p_block;
+               u32 mask;
+               int i;
+
+               p_block = &attn_blocks[p_aeu->block_index];
+
+               /* Handle each interrupt register */
+               for (i = 0; i < p_block->chip_regs[0].num_of_int_regs; i++) {
+                       struct attn_hw_reg *p_reg_desc;
+                       u32 sts_addr;
+
+                       p_reg_desc = p_block->chip_regs[0].int_regs[i];
+
+                       /* In case of fatal attention, don't clear the status
+                        * so it would appear in following idle check.
+                        */
+                       if (rc == 0)
+                               sts_addr = p_reg_desc->sts_clr_addr;
+                       else
+                               sts_addr = p_reg_desc->sts_addr;
+
+                       val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, sts_addr);
+                       mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                     p_reg_desc->mask_addr);
+                       qed_int_deassertion_print_bit(p_hwfn, p_reg_desc,
+                                                     p_block,
+                                                     QED_ATTN_TYPE_ATTN,
+                                                     val, mask);
+               }
+       }
+
+       /* If the attention is benign, no need to prevent it */
+       if (!rc)
+               goto out;
+
+       /* Prevent this Attention from being asserted in the future */
+       val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg);
+       qed_wr(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en_reg, (val & ~bitmask));
+       DP_INFO(p_hwfn, "`%s' - Disabled future attentions\n",
+               p_aeu->bit_name);
+
+out:
+       return rc;
+}
+
+static void qed_int_parity_print(struct qed_hwfn *p_hwfn,
+                                struct aeu_invert_reg_bit *p_aeu,
+                                struct attn_hw_block *p_block,
+                                u8 bit_index)
+{
+       int i;
+
+       for (i = 0; i < p_block->chip_regs[0].num_of_prty_regs; i++) {
+               struct attn_hw_reg *p_reg_desc;
+               u32 val, mask;
+
+               p_reg_desc = p_block->chip_regs[0].prty_regs[i];
+
+               val = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                            p_reg_desc->sts_clr_addr);
+               mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                             p_reg_desc->mask_addr);
+               qed_int_deassertion_print_bit(p_hwfn, p_reg_desc,
+                                             p_block,
+                                             QED_ATTN_TYPE_PARITY,
+                                             val, mask);
+       }
+}
+
+/**
+ * @brief qed_int_deassertion_parity - handle a single parity AEU source
+ *
+ * @param p_hwfn
+ * @param p_aeu - descriptor of an AEU bit which caused the parity
+ * @param bit_index
+ */
+static void qed_int_deassertion_parity(struct qed_hwfn *p_hwfn,
+                                      struct aeu_invert_reg_bit *p_aeu,
+                                      u8 bit_index)
+{
+       u32 block_id = p_aeu->block_index;
+
+       DP_INFO(p_hwfn->cdev, "%s[%d] parity attention is set\n",
+               p_aeu->bit_name, bit_index);
+
+       if (block_id != MAX_BLOCK_ID) {
+               qed_int_parity_print(p_hwfn, p_aeu, &attn_blocks[block_id],
+                                    bit_index);
+
+               /* In BB, there's a single parity bit for several blocks */
+               if (block_id == BLOCK_BTB) {
+                       qed_int_parity_print(p_hwfn, p_aeu,
+                                            &attn_blocks[BLOCK_OPTE],
+                                            bit_index);
+                       qed_int_parity_print(p_hwfn, p_aeu,
+                                            &attn_blocks[BLOCK_MCP],
+                                            bit_index);
+               }
+       }
+}
+
 /**
  * @brief - handles deassertion of previously asserted attentions.
  *
@@ -139,17 +2008,108 @@ static int qed_int_deassertion(struct qed_hwfn  *p_hwfn,
                               u16 deasserted_bits)
 {
        struct qed_sb_attn_info *sb_attn_sw = p_hwfn->p_sb_attn;
-       u32 aeu_mask;
+       u32 aeu_inv_arr[NUM_ATTN_REGS], aeu_mask;
+       u8 i, j, k, bit_idx;
+       int rc = 0;
+
+       /* Read the attention registers in the AEU */
+       for (i = 0; i < NUM_ATTN_REGS; i++) {
+               aeu_inv_arr[i] = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                                       MISC_REG_AEU_AFTER_INVERT_1_IGU +
+                                       i * 0x4);
+               DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
+                          "Deasserted bits [%d]: %08x\n",
+                          i, aeu_inv_arr[i]);
+       }
+
+       /* Find parity attentions first */
+       for (i = 0; i < NUM_ATTN_REGS; i++) {
+               struct aeu_invert_reg *p_aeu = &sb_attn_sw->p_aeu_desc[i];
+               u32 en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
+                               MISC_REG_AEU_ENABLE1_IGU_OUT_0 +
+                               i * sizeof(u32));
+               u32 parities;
+
+               /* Skip register in which no parity bit is currently set */
+               parities = sb_attn_sw->parity_mask[i] & aeu_inv_arr[i] & en;
+               if (!parities)
+                       continue;
+
+               for (j = 0, bit_idx = 0; bit_idx < 32; j++) {
+                       struct aeu_invert_reg_bit *p_bit = &p_aeu->bits[j];
+
+                       if ((p_bit->flags & ATTENTION_PARITY) &&
+                           !!(parities & (1 << bit_idx)))
+                               qed_int_deassertion_parity(p_hwfn, p_bit,
+                                                          bit_idx);
 
-       if (deasserted_bits != 0x100)
-               DP_ERR(p_hwfn, "Unexpected - non-link deassertion\n");
+                       bit_idx += ATTENTION_LENGTH(p_bit->flags);
+               }
+       }
+
+       /* Find non-parity cause for attention and act */
+       for (k = 0; k < MAX_ATTN_GRPS; k++) {
+               struct aeu_invert_reg_bit *p_aeu;
+
+               /* Handle only groups whose attention is currently deasserted */
+               if (!(deasserted_bits & (1 << k)))
+                       continue;
+
+               for (i = 0; i < NUM_ATTN_REGS; i++) {
+                       u32 aeu_en = MISC_REG_AEU_ENABLE1_IGU_OUT_0 +
+                                    i * sizeof(u32) +
+                                    k * sizeof(u32) * NUM_ATTN_REGS;
+                       u32 en, bits;
+
+                       en = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, aeu_en);
+                       bits = aeu_inv_arr[i] & en;
+
+                       /* Skip if no bit from this group is currently set */
+                       if (!bits)
+                               continue;
+
+                       /* Find all set bits from current register which belong
+                        * to current group, making them responsible for the
+                        * previous assertion.
+                        */
+                       for (j = 0, bit_idx = 0; bit_idx < 32; j++) {
+                               u8 bit, bit_len;
+                               u32 bitmask;
+
+                               p_aeu = &sb_attn_sw->p_aeu_desc[i].bits[j];
+
+                               /* No need to handle parity-only bits */
+                               if (p_aeu->flags == ATTENTION_PAR)
+                                       continue;
+
+                               bit = bit_idx;
+                               bit_len = ATTENTION_LENGTH(p_aeu->flags);
+                               if (p_aeu->flags & ATTENTION_PAR_INT) {
+                                       /* Skip Parity */
+                                       bit++;
+                                       bit_len--;
+                               }
+
+                               bitmask = bits & (((1 << bit_len) - 1) << bit);
+                               if (bitmask) {
+                                       /* Handle source of the attention */
+                                       qed_int_deassertion_aeu_bit(p_hwfn,
+                                                                   p_aeu,
+                                                                   aeu_en,
+                                                                   bitmask);
+                               }
+
+                               bit_idx += ATTENTION_LENGTH(p_aeu->flags);
+                       }
+               }
+       }
 
        /* Clear IGU indication for the deasserted bits */
        DIRECT_REG_WR((u8 __iomem *)p_hwfn->regview +
-                     GTT_BAR0_MAP_REG_IGU_CMD +
-                     ((IGU_CMD_ATTN_BIT_CLR_UPPER -
-                       IGU_CMD_INT_ACK_BASE) << 3),
-                     ~((u32)deasserted_bits));
+                                   GTT_BAR0_MAP_REG_IGU_CMD +
+                                   ((IGU_CMD_ATTN_BIT_CLR_UPPER -
+                                     IGU_CMD_INT_ACK_BASE) << 3),
+                                   ~((u32)deasserted_bits));
 
        /* Unmask deasserted attentions in IGU */
        aeu_mask = qed_rd(p_hwfn, p_hwfn->p_dpc_ptt,
@@ -160,7 +2120,7 @@ static int qed_int_deassertion(struct qed_hwfn  *p_hwfn,
        /* Clear deassertion from inner state */
        sb_attn_sw->known_attn &= ~deasserted_bits;
 
-       return 0;
+       return rc;
 }
 
 static int qed_int_attentions(struct qed_hwfn *p_hwfn)
@@ -343,17 +2303,17 @@ void qed_int_sp_dpc(unsigned long hwfn_cookie)
 
 static void qed_int_sb_attn_free(struct qed_hwfn *p_hwfn)
 {
-       struct qed_dev *cdev   = p_hwfn->cdev;
-       struct qed_sb_attn_info *p_sb   = p_hwfn->p_sb_attn;
-
-       if (p_sb) {
-               if (p_sb->sb_attn)
-                       dma_free_coherent(&cdev->pdev->dev,
-                                         SB_ATTN_ALIGNED_SIZE(p_hwfn),
-                                         p_sb->sb_attn,
-                                         p_sb->sb_phys);
-               kfree(p_sb);
-       }
+       struct qed_sb_attn_info *p_sb = p_hwfn->p_sb_attn;
+
+       if (!p_sb)
+               return;
+
+       if (p_sb->sb_attn)
+               dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+                                 SB_ATTN_ALIGNED_SIZE(p_hwfn),
+                                 p_sb->sb_attn,
+                                 p_sb->sb_phys);
+       kfree(p_sb);
 }
 
 static void qed_int_sb_attn_setup(struct qed_hwfn *p_hwfn,
@@ -379,10 +2339,31 @@ static void qed_int_sb_attn_init(struct qed_hwfn *p_hwfn,
                                 dma_addr_t sb_phy_addr)
 {
        struct qed_sb_attn_info *sb_info = p_hwfn->p_sb_attn;
+       int i, j, k;
 
        sb_info->sb_attn = sb_virt_addr;
        sb_info->sb_phys = sb_phy_addr;
 
+       /* Set the pointer to the AEU descriptors */
+       sb_info->p_aeu_desc = aeu_descs;
+
+       /* Calculate Parity Masks */
+       memset(sb_info->parity_mask, 0, sizeof(u32) * NUM_ATTN_REGS);
+       for (i = 0; i < NUM_ATTN_REGS; i++) {
+               /* j is array index, k is bit index */
+               for (j = 0, k = 0; k < 32; j++) {
+                       unsigned int flags = aeu_descs[i].bits[j].flags;
+
+                       if (flags & ATTENTION_PARITY)
+                               sb_info->parity_mask[i] |= 1 << k;
+
+                       k += ATTENTION_LENGTH(flags);
+               }
+               DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
+                          "Attn Mask [Reg %d]: 0x%08x\n",
+                          i, sb_info->parity_mask[i]);
+       }
+
        /* Set the address of cleanup for the mcp attention */
        sb_info->mfw_attn_addr = (p_hwfn->rel_pf_id << 3) +
                                 MISC_REG_AEU_GENERAL_ATTN_0;
@@ -399,7 +2380,7 @@ static int qed_int_sb_attn_alloc(struct qed_hwfn *p_hwfn,
        dma_addr_t p_phys = 0;
 
        /* SB struct */
-       p_sb = kmalloc(sizeof(*p_sb), GFP_ATOMIC);
+       p_sb = kmalloc(sizeof(*p_sb), GFP_KERNEL);
        if (!p_sb) {
                DP_NOTICE(cdev, "Failed to allocate `struct qed_sb_attn_info'\n");
                return -ENOMEM;
@@ -433,6 +2414,7 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
                           u16 vf_number,
                           u8 vf_valid)
 {
+       struct qed_dev *cdev = p_hwfn->cdev;
        u32 cau_state;
 
        memset(p_sb_entry, 0, sizeof(*p_sb_entry));
@@ -451,14 +2433,12 @@ void qed_init_cau_sb_entry(struct qed_hwfn *p_hwfn,
 
        cau_state = CAU_HC_DISABLE_STATE;
 
-       if (p_hwfn->cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) {
+       if (cdev->int_coalescing_mode == QED_COAL_MODE_ENABLE) {
                cau_state = CAU_HC_ENABLE_STATE;
-               if (!p_hwfn->cdev->rx_coalesce_usecs)
-                       p_hwfn->cdev->rx_coalesce_usecs =
-                               QED_CAU_DEF_RX_USECS;
-               if (!p_hwfn->cdev->tx_coalesce_usecs)
-                       p_hwfn->cdev->tx_coalesce_usecs =
-                               QED_CAU_DEF_TX_USECS;
+               if (!cdev->rx_coalesce_usecs)
+                       cdev->rx_coalesce_usecs = QED_CAU_DEF_RX_USECS;
+               if (!cdev->tx_coalesce_usecs)
+                       cdev->tx_coalesce_usecs = QED_CAU_DEF_TX_USECS;
        }
 
        SET_FIELD(p_sb_entry->data, CAU_SB_ENTRY_STATE0, cau_state);
@@ -473,20 +2453,20 @@ void qed_int_cau_conf_sb(struct qed_hwfn *p_hwfn,
                         u8 vf_valid)
 {
        struct cau_sb_entry sb_entry;
-       u32 val;
 
        qed_init_cau_sb_entry(p_hwfn, &sb_entry, p_hwfn->rel_pf_id,
                              vf_number, vf_valid);
 
        if (p_hwfn->hw_init_done) {
-               val = CAU_REG_SB_ADDR_MEMORY + igu_sb_id * sizeof(u64);
-               qed_wr(p_hwfn, p_ptt, val, lower_32_bits(sb_phys));
-               qed_wr(p_hwfn, p_ptt, val + sizeof(u32),
-                      upper_32_bits(sb_phys));
-
-               val = CAU_REG_SB_VAR_MEMORY + igu_sb_id * sizeof(u64);
-               qed_wr(p_hwfn, p_ptt, val, sb_entry.data);
-               qed_wr(p_hwfn, p_ptt, val + sizeof(u32), sb_entry.params);
+               /* Wide-bus, initialize via DMAE */
+               u64 phys_addr = (u64)sb_phys;
+
+               qed_dmae_host2grc(p_hwfn, p_ptt, (u64)(uintptr_t)&phys_addr,
+                                 CAU_REG_SB_ADDR_MEMORY +
+                                 igu_sb_id * sizeof(u64), 2, 0);
+               qed_dmae_host2grc(p_hwfn, p_ptt, (u64)(uintptr_t)&sb_entry,
+                                 CAU_REG_SB_VAR_MEMORY +
+                                 igu_sb_id * sizeof(u64), 2, 0);
        } else {
                /* Initialize Status Block Address */
                STORE_RT_REG_AGG(p_hwfn,
@@ -638,8 +2618,10 @@ int qed_int_sb_release(struct qed_hwfn *p_hwfn,
        sb_info->sb_ack = 0;
        memset(sb_info->sb_virt, 0, sizeof(*sb_info->sb_virt));
 
-       p_hwfn->sbs_info[sb_id] = NULL;
-       p_hwfn->num_sbs--;
+       if (p_hwfn->sbs_info[sb_id] != NULL) {
+               p_hwfn->sbs_info[sb_id] = NULL;
+               p_hwfn->num_sbs--;
+       }
 
        return 0;
 }
@@ -648,14 +2630,15 @@ static void qed_int_sp_sb_free(struct qed_hwfn *p_hwfn)
 {
        struct qed_sb_sp_info *p_sb = p_hwfn->p_sp_sb;
 
-       if (p_sb) {
-               if (p_sb->sb_info.sb_virt)
-                       dma_free_coherent(&p_hwfn->cdev->pdev->dev,
-                                         SB_ALIGNED_SIZE(p_hwfn),
-                                         p_sb->sb_info.sb_virt,
-                                         p_sb->sb_info.sb_phys);
-               kfree(p_sb);
-       }
+       if (!p_sb)
+               return;
+
+       if (p_sb->sb_info.sb_virt)
+               dma_free_coherent(&p_hwfn->cdev->pdev->dev,
+                                 SB_ALIGNED_SIZE(p_hwfn),
+                                 p_sb->sb_info.sb_virt,
+                                 p_sb->sb_info.sb_phys);
+       kfree(p_sb);
 }
 
 static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn,
@@ -666,7 +2649,7 @@ static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn,
        void *p_virt;
 
        /* SB struct */
-       p_sb = kmalloc(sizeof(*p_sb), GFP_ATOMIC);
+       p_sb = kmalloc(sizeof(*p_sb), GFP_KERNEL);
        if (!p_sb) {
                DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_sb_info'\n");
                return -ENOMEM;
@@ -692,25 +2675,6 @@ static int qed_int_sp_sb_alloc(struct qed_hwfn *p_hwfn,
        return 0;
 }
 
-static void qed_int_sp_sb_setup(struct qed_hwfn *p_hwfn,
-                               struct qed_ptt *p_ptt)
-{
-       if (!p_hwfn)
-               return;
-
-       if (p_hwfn->p_sp_sb)
-               qed_int_sb_setup(p_hwfn, p_ptt, &p_hwfn->p_sp_sb->sb_info);
-       else
-               DP_NOTICE(p_hwfn->cdev,
-                         "Failed to setup Slow path status block - NULL pointer\n");
-
-       if (p_hwfn->p_sb_attn)
-               qed_int_sb_attn_setup(p_hwfn, p_ptt);
-       else
-               DP_NOTICE(p_hwfn->cdev,
-                         "Failed to setup attentions status block - NULL pointer\n");
-}
-
 int qed_int_register_cb(struct qed_hwfn *p_hwfn,
                        qed_int_comp_cb_t comp_cb,
                        void *cookie,
@@ -718,36 +2682,36 @@ int qed_int_register_cb(struct qed_hwfn *p_hwfn,
                        __le16 **p_fw_cons)
 {
        struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb;
-       int qed_status = -ENOMEM;
+       int rc = -ENOMEM;
        u8 pi;
 
        /* Look for a free index */
        for (pi = 0; pi < ARRAY_SIZE(p_sp_sb->pi_info_arr); pi++) {
-               if (!p_sp_sb->pi_info_arr[pi].comp_cb) {
-                       p_sp_sb->pi_info_arr[pi].comp_cb = comp_cb;
-                       p_sp_sb->pi_info_arr[pi].cookie = cookie;
-                       *sb_idx = pi;
-                       *p_fw_cons = &p_sp_sb->sb_info.sb_virt->pi_array[pi];
-                       qed_status = 0;
-                       break;
-               }
+               if (p_sp_sb->pi_info_arr[pi].comp_cb)
+                       continue;
+
+               p_sp_sb->pi_info_arr[pi].comp_cb = comp_cb;
+               p_sp_sb->pi_info_arr[pi].cookie = cookie;
+               *sb_idx = pi;
+               *p_fw_cons = &p_sp_sb->sb_info.sb_virt->pi_array[pi];
+               rc = 0;
+               break;
        }
 
-       return qed_status;
+       return rc;
 }
 
 int qed_int_unregister_cb(struct qed_hwfn *p_hwfn, u8 pi)
 {
        struct qed_sb_sp_info *p_sp_sb = p_hwfn->p_sp_sb;
-       int qed_status = -ENOMEM;
 
-       if (p_sp_sb->pi_info_arr[pi].comp_cb) {
-               p_sp_sb->pi_info_arr[pi].comp_cb = NULL;
-               p_sp_sb->pi_info_arr[pi].cookie = NULL;
-               qed_status = 0;
-       }
+       if (p_sp_sb->pi_info_arr[pi].comp_cb == NULL)
+               return -ENOMEM;
 
-       return qed_status;
+       p_sp_sb->pi_info_arr[pi].comp_cb = NULL;
+       p_sp_sb->pi_info_arr[pi].cookie = NULL;
+
+       return 0;
 }
 
 u16 qed_int_get_sp_sb_id(struct qed_hwfn *p_hwfn)
@@ -786,16 +2750,13 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn,
 int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
                       enum qed_int_mode int_mode)
 {
-       int rc, i;
-
-       /* Mask non-link attentions */
-       for (i = 0; i < 9; i++)
-               qed_wr(p_hwfn, p_ptt,
-                      MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0);
+       int rc;
 
-       /* Configure AEU signal change to produce attentions for link */
+       /* Configure AEU signal change to produce attentions */
+       qed_wr(p_hwfn, p_ptt, IGU_REG_ATTENTION_ENABLE, 0);
        qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0xfff);
        qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0xfff);
+       qed_wr(p_hwfn, p_ptt, IGU_REG_ATTENTION_ENABLE, 0xfff);
 
        /* Flush the writes to IGU */
        mmiowb();
@@ -937,6 +2898,39 @@ void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn,
        }
 }
 
+static u32 qed_int_igu_read_cam_block(struct qed_hwfn  *p_hwfn,
+                                     struct qed_ptt    *p_ptt,
+                                     u16               sb_id)
+{
+       u32 val = qed_rd(p_hwfn, p_ptt,
+                        IGU_REG_MAPPING_MEMORY +
+                        sizeof(u32) * sb_id);
+       struct qed_igu_block *p_block;
+
+       p_block = &p_hwfn->hw_info.p_igu_info->igu_map.igu_blocks[sb_id];
+
+       /* stop scanning when hit first invalid PF entry */
+       if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) &&
+           GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID))
+               goto out;
+
+       /* Fill the block information */
+       p_block->status         = QED_IGU_STATUS_VALID;
+       p_block->function_id    = GET_FIELD(val,
+                                           IGU_MAPPING_LINE_FUNCTION_NUMBER);
+       p_block->is_pf          = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID);
+       p_block->vector_number  = GET_FIELD(val,
+                                           IGU_MAPPING_LINE_VECTOR_NUMBER);
+
+       DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
+                  "IGU_BLOCK: [SB 0x%04x, Value in CAM 0x%08x] func_id = %d is_pf = %d vector_num = 0x%x\n",
+                  sb_id, val, p_block->function_id,
+                  p_block->is_pf, p_block->vector_number);
+
+out:
+       return val;
+}
+
 int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn,
                         struct qed_ptt *p_ptt)
 {
@@ -946,7 +2940,7 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn,
        u16 sb_id;
        u16 prev_sb_id = 0xFF;
 
-       p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_ATOMIC);
+       p_hwfn->hw_info.p_igu_info = kzalloc(sizeof(*p_igu_info), GFP_KERNEL);
 
        if (!p_hwfn->hw_info.p_igu_info)
                return -ENOMEM;
@@ -963,26 +2957,13 @@ int qed_int_igu_read_cam(struct qed_hwfn *p_hwfn,
             sb_id++) {
                blk = &p_igu_info->igu_map.igu_blocks[sb_id];
 
-               val = qed_rd(p_hwfn, p_ptt,
-                            IGU_REG_MAPPING_MEMORY + sizeof(u32) * sb_id);
+               val     = qed_int_igu_read_cam_block(p_hwfn, p_ptt, sb_id);
 
                /* stop scanning when hit first invalid PF entry */
                if (!GET_FIELD(val, IGU_MAPPING_LINE_VALID) &&
                    GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID))
                        break;
 
-               blk->status = QED_IGU_STATUS_VALID;
-               blk->function_id = GET_FIELD(val,
-                                            IGU_MAPPING_LINE_FUNCTION_NUMBER);
-               blk->is_pf = GET_FIELD(val, IGU_MAPPING_LINE_PF_VALID);
-               blk->vector_number = GET_FIELD(val,
-                                              IGU_MAPPING_LINE_VECTOR_NUMBER);
-
-               DP_VERBOSE(p_hwfn, NETIF_MSG_INTR,
-                          "IGU_BLOCK[sb_id]:%x:func_id = %d is_pf = %d vector_num = 0x%x\n",
-                          val, blk->function_id, blk->is_pf,
-                          blk->vector_number);
-
                if (blk->is_pf) {
                        if (blk->function_id == p_hwfn->rel_pf_id) {
                                blk->status |= QED_IGU_STATUS_PF;
@@ -1072,7 +3053,7 @@ static void qed_int_sp_dpc_setup(struct qed_hwfn *p_hwfn)
 
 static int qed_int_sp_dpc_alloc(struct qed_hwfn *p_hwfn)
 {
-       p_hwfn->sp_dpc = kmalloc(sizeof(*p_hwfn->sp_dpc), GFP_ATOMIC);
+       p_hwfn->sp_dpc = kmalloc(sizeof(*p_hwfn->sp_dpc), GFP_KERNEL);
        if (!p_hwfn->sp_dpc)
                return -ENOMEM;
 
@@ -1117,22 +3098,22 @@ void qed_int_free(struct qed_hwfn *p_hwfn)
 void qed_int_setup(struct qed_hwfn *p_hwfn,
                   struct qed_ptt *p_ptt)
 {
-       qed_int_sp_sb_setup(p_hwfn, p_ptt);
+       qed_int_sb_setup(p_hwfn, p_ptt, &p_hwfn->p_sp_sb->sb_info);
+       qed_int_sb_attn_setup(p_hwfn, p_ptt);
        qed_int_sp_dpc_setup(p_hwfn);
 }
 
-int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
-                       int *p_iov_blks)
+void qed_int_get_num_sbs(struct qed_hwfn       *p_hwfn,
+                        struct qed_sb_cnt_info *p_sb_cnt_info)
 {
        struct qed_igu_info *info = p_hwfn->hw_info.p_igu_info;
 
-       if (!info)
-               return 0;
-
-       if (p_iov_blks)
-               *p_iov_blks = info->free_blks;
+       if (!info || !p_sb_cnt_info)
+               return;
 
-       return info->igu_sb_cnt;
+       p_sb_cnt_info->sb_cnt           = info->igu_sb_cnt;
+       p_sb_cnt_info->sb_iov_cnt       = info->igu_sb_cnt_iov;
+       p_sb_cnt_info->sb_free_blk      = info->free_blks;
 }
 
 void qed_int_disable_post_isr_release(struct qed_dev *cdev)
index 51e0b09a7f47d3da8ca9c1d2d0982aa2e77d51f4..c57f2e68077059b2879c31d1b1184f0663510e32 100644 (file)
@@ -161,12 +161,12 @@ void qed_int_sp_dpc(unsigned long hwfn_cookie);
  *        blocks configured for this funciton in the igu.
  *
  * @param p_hwfn
- * @param p_iov_blks - configured free blks for vfs
+ * @param p_sb_cnt_info
  *
  * @return int - number of status blocks configured
  */
-int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
-                       int *p_iov_blks);
+void qed_int_get_num_sbs(struct qed_hwfn       *p_hwfn,
+                        struct qed_sb_cnt_info *p_sb_cnt_info);
 
 /**
  * @brief qed_int_disable_post_isr_release - performs the cleanup post ISR
index f72036a2ef5b1c9a93618aa96159232964c7ee24..3f35c6ca92528d3cc1951df3d09f8ef19c3dd8ba 100644 (file)
@@ -31,6 +31,7 @@
 #include "qed_hsi.h"
 #include "qed_hw.h"
 #include "qed_int.h"
+#include "qed_mcp.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
 
@@ -124,52 +125,65 @@ struct qed_sp_vport_update_params {
        u8                              update_vport_active_tx_flg;
        u8                              vport_active_tx_flg;
        u8                              update_approx_mcast_flg;
+       u8                              update_accept_any_vlan_flg;
+       u8                              accept_any_vlan;
        unsigned long                   bins[8];
        struct qed_rss_params           *rss_params;
        struct qed_filter_accept_flags  accept_flags;
 };
 
+enum qed_tpa_mode {
+       QED_TPA_MODE_NONE,
+       QED_TPA_MODE_UNUSED,
+       QED_TPA_MODE_GRO,
+       QED_TPA_MODE_MAX
+};
+
+struct qed_sp_vport_start_params {
+       enum qed_tpa_mode       tpa_mode;
+       bool                    remove_inner_vlan;
+       bool                    drop_ttl0;
+       u8                      max_buffers_per_cqe;
+       u32                     concrete_fid;
+       u16                     opaque_fid;
+       u8                      vport_id;
+       u16                     mtu;
+};
+
 #define QED_MAX_SGES_NUM 16
 #define CRC32_POLY 0x1edc6f41
 
 static int qed_sp_vport_start(struct qed_hwfn *p_hwfn,
-                             u32 concrete_fid,
-                             u16 opaque_fid,
-                             u8 vport_id,
-                             u16 mtu,
-                             u8 drop_ttl0_flg,
-                             u8 inner_vlan_removal_en_flg)
+                             struct qed_sp_vport_start_params *p_params)
 {
-       struct qed_sp_init_request_params params;
        struct vport_start_ramrod_data *p_ramrod = NULL;
        struct qed_spq_entry *p_ent =  NULL;
+       struct qed_sp_init_data init_data;
        int rc = -EINVAL;
        u16 rx_mode = 0;
        u8 abs_vport_id = 0;
 
-       rc = qed_fw_vport(p_hwfn, vport_id, &abs_vport_id);
+       rc = qed_fw_vport(p_hwfn, p_params->vport_id, &abs_vport_id);
        if (rc != 0)
                return rc;
 
-       memset(&params, 0, sizeof(params));
-       params.ramrod_data_size = sizeof(*p_ramrod);
-       params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = p_params->opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                opaque_fid,
                                 ETH_RAMROD_VPORT_START,
-                                PROTOCOLID_ETH,
-                                &params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
        p_ramrod                = &p_ent->ramrod.vport_start;
        p_ramrod->vport_id      = abs_vport_id;
 
-       p_ramrod->mtu                   = cpu_to_le16(mtu);
-       p_ramrod->inner_vlan_removal_en = inner_vlan_removal_en_flg;
-       p_ramrod->drop_ttl0_en          = drop_ttl0_flg;
+       p_ramrod->mtu                   = cpu_to_le16(p_params->mtu);
+       p_ramrod->inner_vlan_removal_en = p_params->remove_inner_vlan;
+       p_ramrod->drop_ttl0_en          = p_params->drop_ttl0;
 
        SET_FIELD(rx_mode, ETH_VPORT_RX_MODE_UCAST_DROP_ALL, 1);
        SET_FIELD(rx_mode, ETH_VPORT_RX_MODE_MCAST_DROP_ALL, 1);
@@ -180,9 +194,26 @@ static int qed_sp_vport_start(struct qed_hwfn *p_hwfn,
        memset(&p_ramrod->tpa_param, 0,
               sizeof(struct eth_vport_tpa_param));
 
+       p_ramrod->tpa_param.max_buff_num = p_params->max_buffers_per_cqe;
+
+       switch (p_params->tpa_mode) {
+       case QED_TPA_MODE_GRO:
+               p_ramrod->tpa_param.tpa_max_aggs_num = ETH_TPA_MAX_AGGS_NUM;
+               p_ramrod->tpa_param.tpa_max_size = (u16)-1;
+               p_ramrod->tpa_param.tpa_min_size_to_cont = p_params->mtu / 2;
+               p_ramrod->tpa_param.tpa_min_size_to_start = p_params->mtu / 2;
+               p_ramrod->tpa_param.tpa_ipv4_en_flg = 1;
+               p_ramrod->tpa_param.tpa_ipv6_en_flg = 1;
+               p_ramrod->tpa_param.tpa_pkt_split_flg = 1;
+               p_ramrod->tpa_param.tpa_gro_consistent_flg = 1;
+               break;
+       default:
+               break;
+       }
+
        /* Software Function ID in hwfn (PFs are 0 - 15, VFs are 16 - 135) */
        p_ramrod->sw_fid = qed_concrete_to_sw_fid(p_hwfn->cdev,
-                                                 concrete_fid);
+                                                 p_params->concrete_fid);
 
        return qed_spq_post(p_hwfn, p_ent, NULL);
 }
@@ -360,7 +391,7 @@ qed_sp_vport_update(struct qed_hwfn *p_hwfn,
 {
        struct qed_rss_params *p_rss_params = p_params->rss_params;
        struct vport_update_ramrod_data_cmn *p_cmn;
-       struct qed_sp_init_request_params sp_params;
+       struct qed_sp_init_data init_data;
        struct vport_update_ramrod_data *p_ramrod = NULL;
        struct qed_spq_entry *p_ent = NULL;
        u8 abs_vport_id = 0;
@@ -370,17 +401,15 @@ qed_sp_vport_update(struct qed_hwfn *p_hwfn,
        if (rc != 0)
                return rc;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
-       sp_params.comp_mode = comp_mode;
-       sp_params.p_comp_data = p_comp_data;
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = p_params->opaque_fid;
+       init_data.comp_mode = comp_mode;
+       init_data.p_comp_data = p_comp_data;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                p_params->opaque_fid,
                                 ETH_RAMROD_VPORT_UPDATE,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -393,7 +422,9 @@ qed_sp_vport_update(struct qed_hwfn *p_hwfn,
        p_cmn->update_rx_active_flg = p_params->update_vport_active_rx_flg;
        p_cmn->tx_active_flg = p_params->vport_active_tx_flg;
        p_cmn->update_tx_active_flg = p_params->update_vport_active_tx_flg;
-
+       p_cmn->accept_any_vlan = p_params->accept_any_vlan;
+       p_cmn->update_accept_any_vlan_flg =
+                       p_params->update_accept_any_vlan_flg;
        rc = qed_sp_vport_update_rss(p_hwfn, p_ramrod, p_rss_params);
        if (rc) {
                /* Return spq entry which is taken in qed_sp_init_request()*/
@@ -412,8 +443,8 @@ static int qed_sp_vport_stop(struct qed_hwfn *p_hwfn,
                             u16 opaque_fid,
                             u8 vport_id)
 {
-       struct qed_sp_init_request_params sp_params;
        struct vport_stop_ramrod_data *p_ramrod;
+       struct qed_sp_init_data init_data;
        struct qed_spq_entry *p_ent;
        u8 abs_vport_id = 0;
        int rc;
@@ -422,16 +453,14 @@ static int qed_sp_vport_stop(struct qed_hwfn *p_hwfn,
        if (rc != 0)
                return rc;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
-       sp_params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                opaque_fid,
                                 ETH_RAMROD_VPORT_STOP,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -444,8 +473,10 @@ static int qed_sp_vport_stop(struct qed_hwfn *p_hwfn,
 static int qed_filter_accept_cmd(struct qed_dev *cdev,
                                 u8 vport,
                                 struct qed_filter_accept_flags accept_flags,
-                                enum spq_mode comp_mode,
-                                struct qed_spq_comp_cb *p_comp_data)
+                                u8 update_accept_any_vlan,
+                                u8 accept_any_vlan,
+                               enum spq_mode comp_mode,
+                               struct qed_spq_comp_cb *p_comp_data)
 {
        struct qed_sp_vport_update_params vport_update_params;
        int i, rc;
@@ -454,6 +485,8 @@ static int qed_filter_accept_cmd(struct qed_dev *cdev,
        memset(&vport_update_params, 0, sizeof(vport_update_params));
        vport_update_params.vport_id = vport;
        vport_update_params.accept_flags = accept_flags;
+       vport_update_params.update_accept_any_vlan_flg = update_accept_any_vlan;
+       vport_update_params.accept_any_vlan = accept_any_vlan;
 
        for_each_hwfn(cdev, i) {
                struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
@@ -471,6 +504,10 @@ static int qed_filter_accept_cmd(struct qed_dev *cdev,
                           "Accept filter configured, flags = [Rx]%x [Tx]%x\n",
                           accept_flags.rx_accept_filter,
                           accept_flags.tx_accept_filter);
+               if (update_accept_any_vlan)
+                       DP_VERBOSE(p_hwfn, QED_MSG_SP,
+                                  "accept_any_vlan=%d configured\n",
+                                  accept_any_vlan);
        }
 
        return 0;
@@ -502,8 +539,8 @@ qed_sp_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn,
                            u16 cqe_pbl_size)
 {
        struct rx_queue_start_ramrod_data *p_ramrod = NULL;
-       struct qed_sp_init_request_params sp_params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        struct qed_hw_cid_data *p_rx_cid;
        u16 abs_rx_q_id = 0;
        u8 abs_vport_id = 0;
@@ -528,15 +565,15 @@ qed_sp_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn,
                   opaque_fid, cid, params->queue_id, params->vport_id,
                   params->sb);
 
-       memset(&sp_params, 0, sizeof(params));
-       sp_params.comp_mode = QED_SPQ_MODE_EBLOCK;
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = cid;
+       init_data.opaque_fid = opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                cid, opaque_fid,
                                 ETH_RAMROD_RX_QUEUE_START,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -551,12 +588,10 @@ qed_sp_eth_rxq_start_ramrod(struct qed_hwfn *p_hwfn,
        p_ramrod->complete_event_flg    = 1;
 
        p_ramrod->bd_max_bytes  = cpu_to_le16(bd_max_bytes);
-       p_ramrod->bd_base.hi    = DMA_HI_LE(bd_chain_phys_addr);
-       p_ramrod->bd_base.lo    = DMA_LO_LE(bd_chain_phys_addr);
+       DMA_REGPAIR_LE(p_ramrod->bd_base, bd_chain_phys_addr);
 
        p_ramrod->num_of_pbl_pages      = cpu_to_le16(cqe_pbl_size);
-       p_ramrod->cqe_pbl_addr.hi       = DMA_HI_LE(cqe_pbl_addr);
-       p_ramrod->cqe_pbl_addr.lo       = DMA_LO_LE(cqe_pbl_addr);
+       DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, cqe_pbl_addr);
 
        rc = qed_spq_post(p_hwfn, p_ent, NULL);
 
@@ -628,21 +663,20 @@ static int qed_sp_eth_rx_queue_stop(struct qed_hwfn *p_hwfn,
 {
        struct qed_hw_cid_data *p_rx_cid = &p_hwfn->p_rx_cids[rx_queue_id];
        struct rx_queue_stop_ramrod_data *p_ramrod = NULL;
-       struct qed_sp_init_request_params sp_params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        u16 abs_rx_q_id = 0;
        int rc = -EINVAL;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
-       sp_params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = p_rx_cid->cid;
+       init_data.opaque_fid = p_rx_cid->opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                p_rx_cid->cid,
-                                p_rx_cid->opaque_fid,
                                 ETH_RAMROD_RX_QUEUE_STOP,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -680,8 +714,8 @@ qed_sp_eth_txq_start_ramrod(struct qed_hwfn  *p_hwfn,
                            union qed_qm_pq_params *p_pq_params)
 {
        struct tx_queue_start_ramrod_data *p_ramrod = NULL;
-       struct qed_sp_init_request_params sp_params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        struct qed_hw_cid_data *p_tx_cid;
        u8 abs_vport_id;
        int rc = -EINVAL;
@@ -696,15 +730,15 @@ qed_sp_eth_txq_start_ramrod(struct qed_hwfn  *p_hwfn,
        if (rc)
                return rc;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
-       sp_params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = cid;
+       init_data.opaque_fid = opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
-       rc = qed_sp_init_request(p_hwfn, &p_ent, cid,
-                                opaque_fid,
+       rc = qed_sp_init_request(p_hwfn, &p_ent,
                                 ETH_RAMROD_TX_QUEUE_START,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -714,11 +748,9 @@ qed_sp_eth_txq_start_ramrod(struct qed_hwfn  *p_hwfn,
        p_ramrod->sb_id                 = cpu_to_le16(p_params->sb);
        p_ramrod->sb_index              = p_params->sb_idx;
        p_ramrod->stats_counter_id      = stats_id;
-       p_ramrod->tc                    = p_pq_params->eth.tc;
 
        p_ramrod->pbl_size              = cpu_to_le16(pbl_size);
-       p_ramrod->pbl_base_addr.hi      = DMA_HI_LE(pbl_addr);
-       p_ramrod->pbl_base_addr.lo      = DMA_LO_LE(pbl_addr);
+       DMA_REGPAIR_LE(p_ramrod->pbl_base_addr, pbl_addr);
 
        pq_id                   = qed_get_qm_pq(p_hwfn,
                                                PROTOCOLID_ETH,
@@ -785,20 +817,19 @@ static int qed_sp_eth_tx_queue_stop(struct qed_hwfn *p_hwfn,
                                    u16 tx_queue_id)
 {
        struct qed_hw_cid_data *p_tx_cid = &p_hwfn->p_tx_cids[tx_queue_id];
-       struct qed_sp_init_request_params sp_params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        int rc = -EINVAL;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(struct tx_queue_stop_ramrod_data);
-       sp_params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = p_tx_cid->cid;
+       init_data.opaque_fid = p_tx_cid->opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                p_tx_cid->cid,
-                                p_tx_cid->opaque_fid,
                                 ETH_RAMROD_TX_QUEUE_STOP,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -821,9 +852,8 @@ qed_filter_action(enum qed_filter_opcode opcode)
        case QED_FILTER_REMOVE:
                action = ETH_FILTER_ACTION_REMOVE;
                break;
-       case QED_FILTER_REPLACE:
        case QED_FILTER_FLUSH:
-               action = ETH_FILTER_ACTION_REPLACE;
+               action = ETH_FILTER_ACTION_REMOVE_ALL;
                break;
        default:
                action = MAX_ETH_FILTER_ACTION;
@@ -856,9 +886,9 @@ qed_filter_ucast_common(struct qed_hwfn *p_hwfn,
 {
        u8 vport_to_add_to = 0, vport_to_remove_from = 0;
        struct vport_filter_update_ramrod_data *p_ramrod;
-       struct qed_sp_init_request_params sp_params;
        struct eth_filter_cmd *p_first_filter;
        struct eth_filter_cmd *p_second_filter;
+       struct qed_sp_init_data init_data;
        enum eth_filter_action action;
        int rc;
 
@@ -872,17 +902,16 @@ qed_filter_ucast_common(struct qed_hwfn *p_hwfn,
        if (rc)
                return rc;
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(**pp_ramrod);
-       sp_params.comp_mode = comp_mode;
-       sp_params.p_comp_data = p_comp_data;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = opaque_fid;
+       init_data.comp_mode = comp_mode;
+       init_data.p_comp_data = p_comp_data;
 
        rc = qed_sp_init_request(p_hwfn, pp_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                opaque_fid,
                                 ETH_RAMROD_FILTERS_UPDATE,
-                                PROTOCOLID_ETH,
-                                &sp_params);
+                                PROTOCOLID_ETH, &init_data);
        if (rc)
                return rc;
 
@@ -892,8 +921,7 @@ qed_filter_ucast_common(struct qed_hwfn *p_hwfn,
        p_ramrod->filter_cmd_hdr.tx = p_filter_cmd->is_tx_filter ? 1 : 0;
 
        switch (p_filter_cmd->opcode) {
-       case QED_FILTER_FLUSH:
-               p_ramrod->filter_cmd_hdr.cmd_cnt = 0; break;
+       case QED_FILTER_REPLACE:
        case QED_FILTER_MOVE:
                p_ramrod->filter_cmd_hdr.cmd_cnt = 2; break;
        default:
@@ -962,6 +990,12 @@ qed_filter_ucast_common(struct qed_hwfn *p_hwfn,
 
                p_second_filter->action         = ETH_FILTER_ACTION_ADD;
                p_second_filter->vport_id       = vport_to_add_to;
+       } else if (p_filter_cmd->opcode == QED_FILTER_REPLACE) {
+               p_first_filter->vport_id = vport_to_add_to;
+               memcpy(p_second_filter, p_first_filter,
+                      sizeof(*p_second_filter));
+               p_first_filter->action  = ETH_FILTER_ACTION_REMOVE_ALL;
+               p_second_filter->action = ETH_FILTER_ACTION_ADD;
        } else {
                action = qed_filter_action(p_filter_cmd->opcode);
 
@@ -1101,8 +1135,8 @@ qed_sp_eth_filter_mcast(struct qed_hwfn *p_hwfn,
 {
        unsigned long bins[ETH_MULTICAST_MAC_BINS_IN_REGS];
        struct vport_update_ramrod_data *p_ramrod = NULL;
-       struct qed_sp_init_request_params sp_params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        u8 abs_vport_id = 0;
        int rc, i;
 
@@ -1118,18 +1152,16 @@ qed_sp_eth_filter_mcast(struct qed_hwfn *p_hwfn,
                        return rc;
        }
 
-       memset(&sp_params, 0, sizeof(sp_params));
-       sp_params.ramrod_data_size = sizeof(*p_ramrod);
-       sp_params.comp_mode = comp_mode;
-       sp_params.p_comp_data = p_comp_data;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+       init_data.comp_mode = comp_mode;
+       init_data.p_comp_data = p_comp_data;
 
        rc = qed_sp_init_request(p_hwfn, &p_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                p_hwfn->hw_info.opaque_fid,
                                 ETH_RAMROD_VPORT_UPDATE,
-                                PROTOCOLID_ETH,
-                                &sp_params);
-
+                                PROTOCOLID_ETH, &init_data);
        if (rc) {
                DP_ERR(p_hwfn, "Multi-cast command failed %d\n", rc);
                return rc;
@@ -1230,6 +1262,328 @@ static int qed_filter_ucast_cmd(struct qed_dev *cdev,
        return rc;
 }
 
+/* Statistics related code */
+static void __qed_get_vport_pstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_PSDM_RAM +
+                 PSTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_pstorm_per_queue_stat);
+}
+
+static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_pstorm_per_queue_stat pstats;
+       u32 pstats_addr = 0, pstats_len = 0;
+
+       __qed_get_vport_pstats_addrlen(p_hwfn, &pstats_addr, &pstats_len,
+                                      statistics_bin);
+
+       memset(&pstats, 0, sizeof(pstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &pstats,
+                       pstats_addr, pstats_len);
+
+       p_stats->tx_ucast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_ucast_bytes);
+       p_stats->tx_mcast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_mcast_bytes);
+       p_stats->tx_bcast_bytes +=
+               HILO_64_REGPAIR(pstats.sent_bcast_bytes);
+       p_stats->tx_ucast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_ucast_pkts);
+       p_stats->tx_mcast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_mcast_pkts);
+       p_stats->tx_bcast_pkts +=
+               HILO_64_REGPAIR(pstats.sent_bcast_pkts);
+       p_stats->tx_err_drop_pkts +=
+               HILO_64_REGPAIR(pstats.error_drop_pkts);
+}
+
+static void __qed_get_vport_tstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len)
+{
+       *p_addr = BAR0_MAP_REG_TSDM_RAM +
+                 TSTORM_PORT_STAT_OFFSET(MFW_PORT(p_hwfn));
+       *p_len = sizeof(struct tstorm_per_port_stat);
+}
+
+static void __qed_get_vport_tstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       u32 tstats_addr = 0, tstats_len = 0;
+       struct tstorm_per_port_stat tstats;
+
+       __qed_get_vport_tstats_addrlen(p_hwfn, &tstats_addr, &tstats_len);
+
+       memset(&tstats, 0, sizeof(tstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &tstats,
+                       tstats_addr, tstats_len);
+
+       p_stats->mftag_filter_discards +=
+               HILO_64_REGPAIR(tstats.mftag_filter_discard);
+       p_stats->mac_filter_discards +=
+               HILO_64_REGPAIR(tstats.eth_mac_filter_discard);
+}
+
+static void __qed_get_vport_ustats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_USDM_RAM +
+                 USTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_ustorm_per_queue_stat);
+}
+
+static void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_ustorm_per_queue_stat ustats;
+       u32 ustats_addr = 0, ustats_len = 0;
+
+       __qed_get_vport_ustats_addrlen(p_hwfn, &ustats_addr, &ustats_len,
+                                      statistics_bin);
+
+       memset(&ustats, 0, sizeof(ustats));
+       qed_memcpy_from(p_hwfn, p_ptt, &ustats,
+                       ustats_addr, ustats_len);
+
+       p_stats->rx_ucast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_ucast_bytes);
+       p_stats->rx_mcast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_mcast_bytes);
+       p_stats->rx_bcast_bytes +=
+               HILO_64_REGPAIR(ustats.rcv_bcast_bytes);
+       p_stats->rx_ucast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_ucast_pkts);
+       p_stats->rx_mcast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_mcast_pkts);
+       p_stats->rx_bcast_pkts +=
+               HILO_64_REGPAIR(ustats.rcv_bcast_pkts);
+}
+
+static void __qed_get_vport_mstats_addrlen(struct qed_hwfn *p_hwfn,
+                                          u32 *p_addr,
+                                          u32 *p_len,
+                                          u16 statistics_bin)
+{
+       *p_addr = BAR0_MAP_REG_MSDM_RAM +
+                 MSTORM_QUEUE_STAT_OFFSET(statistics_bin);
+       *p_len = sizeof(struct eth_mstorm_per_queue_stat);
+}
+
+static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn,
+                                  struct qed_ptt *p_ptt,
+                                  struct qed_eth_stats *p_stats,
+                                  u16 statistics_bin)
+{
+       struct eth_mstorm_per_queue_stat mstats;
+       u32 mstats_addr = 0, mstats_len = 0;
+
+       __qed_get_vport_mstats_addrlen(p_hwfn, &mstats_addr, &mstats_len,
+                                      statistics_bin);
+
+       memset(&mstats, 0, sizeof(mstats));
+       qed_memcpy_from(p_hwfn, p_ptt, &mstats,
+                       mstats_addr, mstats_len);
+
+       p_stats->no_buff_discards +=
+               HILO_64_REGPAIR(mstats.no_buff_discard);
+       p_stats->packet_too_big_discard +=
+               HILO_64_REGPAIR(mstats.packet_too_big_discard);
+       p_stats->ttl0_discard +=
+               HILO_64_REGPAIR(mstats.ttl0_discard);
+       p_stats->tpa_coalesced_pkts +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_pkts);
+       p_stats->tpa_coalesced_events +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_events);
+       p_stats->tpa_aborts_num +=
+               HILO_64_REGPAIR(mstats.tpa_aborts_num);
+       p_stats->tpa_coalesced_bytes +=
+               HILO_64_REGPAIR(mstats.tpa_coalesced_bytes);
+}
+
+static void __qed_get_vport_port_stats(struct qed_hwfn *p_hwfn,
+                                      struct qed_ptt *p_ptt,
+                                      struct qed_eth_stats *p_stats)
+{
+       struct port_stats port_stats;
+       int j;
+
+       memset(&port_stats, 0, sizeof(port_stats));
+
+       qed_memcpy_from(p_hwfn, p_ptt, &port_stats,
+                       p_hwfn->mcp_info->port_addr +
+                       offsetof(struct public_port, stats),
+                       sizeof(port_stats));
+
+       p_stats->rx_64_byte_packets             += port_stats.pmm.r64;
+       p_stats->rx_127_byte_packets            += port_stats.pmm.r127;
+       p_stats->rx_255_byte_packets            += port_stats.pmm.r255;
+       p_stats->rx_511_byte_packets            += port_stats.pmm.r511;
+       p_stats->rx_1023_byte_packets           += port_stats.pmm.r1023;
+       p_stats->rx_1518_byte_packets           += port_stats.pmm.r1518;
+       p_stats->rx_1522_byte_packets           += port_stats.pmm.r1522;
+       p_stats->rx_2047_byte_packets           += port_stats.pmm.r2047;
+       p_stats->rx_4095_byte_packets           += port_stats.pmm.r4095;
+       p_stats->rx_9216_byte_packets           += port_stats.pmm.r9216;
+       p_stats->rx_16383_byte_packets          += port_stats.pmm.r16383;
+       p_stats->rx_crc_errors                  += port_stats.pmm.rfcs;
+       p_stats->rx_mac_crtl_frames             += port_stats.pmm.rxcf;
+       p_stats->rx_pause_frames                += port_stats.pmm.rxpf;
+       p_stats->rx_pfc_frames                  += port_stats.pmm.rxpp;
+       p_stats->rx_align_errors                += port_stats.pmm.raln;
+       p_stats->rx_carrier_errors              += port_stats.pmm.rfcr;
+       p_stats->rx_oversize_packets            += port_stats.pmm.rovr;
+       p_stats->rx_jabbers                     += port_stats.pmm.rjbr;
+       p_stats->rx_undersize_packets           += port_stats.pmm.rund;
+       p_stats->rx_fragments                   += port_stats.pmm.rfrg;
+       p_stats->tx_64_byte_packets             += port_stats.pmm.t64;
+       p_stats->tx_65_to_127_byte_packets      += port_stats.pmm.t127;
+       p_stats->tx_128_to_255_byte_packets     += port_stats.pmm.t255;
+       p_stats->tx_256_to_511_byte_packets     += port_stats.pmm.t511;
+       p_stats->tx_512_to_1023_byte_packets    += port_stats.pmm.t1023;
+       p_stats->tx_1024_to_1518_byte_packets   += port_stats.pmm.t1518;
+       p_stats->tx_1519_to_2047_byte_packets   += port_stats.pmm.t2047;
+       p_stats->tx_2048_to_4095_byte_packets   += port_stats.pmm.t4095;
+       p_stats->tx_4096_to_9216_byte_packets   += port_stats.pmm.t9216;
+       p_stats->tx_9217_to_16383_byte_packets  += port_stats.pmm.t16383;
+       p_stats->tx_pause_frames                += port_stats.pmm.txpf;
+       p_stats->tx_pfc_frames                  += port_stats.pmm.txpp;
+       p_stats->tx_lpi_entry_count             += port_stats.pmm.tlpiec;
+       p_stats->tx_total_collisions            += port_stats.pmm.tncl;
+       p_stats->rx_mac_bytes                   += port_stats.pmm.rbyte;
+       p_stats->rx_mac_uc_packets              += port_stats.pmm.rxuca;
+       p_stats->rx_mac_mc_packets              += port_stats.pmm.rxmca;
+       p_stats->rx_mac_bc_packets              += port_stats.pmm.rxbca;
+       p_stats->rx_mac_frames_ok               += port_stats.pmm.rxpok;
+       p_stats->tx_mac_bytes                   += port_stats.pmm.tbyte;
+       p_stats->tx_mac_uc_packets              += port_stats.pmm.txuca;
+       p_stats->tx_mac_mc_packets              += port_stats.pmm.txmca;
+       p_stats->tx_mac_bc_packets              += port_stats.pmm.txbca;
+       p_stats->tx_mac_ctrl_frames             += port_stats.pmm.txcf;
+       for (j = 0; j < 8; j++) {
+               p_stats->brb_truncates  += port_stats.brb.brb_truncate[j];
+               p_stats->brb_discards   += port_stats.brb.brb_discard[j];
+       }
+}
+
+static void __qed_get_vport_stats(struct qed_hwfn *p_hwfn,
+                                 struct qed_ptt *p_ptt,
+                                 struct qed_eth_stats *stats,
+                                 u16 statistics_bin)
+{
+       __qed_get_vport_mstats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_ustats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_tstats(p_hwfn, p_ptt, stats, statistics_bin);
+       __qed_get_vport_pstats(p_hwfn, p_ptt, stats, statistics_bin);
+
+       if (p_hwfn->mcp_info)
+               __qed_get_vport_port_stats(p_hwfn, p_ptt, stats);
+}
+
+static void _qed_get_vport_stats(struct qed_dev *cdev,
+                                struct qed_eth_stats *stats)
+{
+       u8      fw_vport = 0;
+       int     i;
+
+       memset(stats, 0, sizeof(*stats));
+
+       for_each_hwfn(cdev, i) {
+               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
+               struct qed_ptt *p_ptt;
+
+               /* The main vport index is relative first */
+               if (qed_fw_vport(p_hwfn, 0, &fw_vport)) {
+                       DP_ERR(p_hwfn, "No vport available!\n");
+                       continue;
+               }
+
+               p_ptt = qed_ptt_acquire(p_hwfn);
+               if (!p_ptt) {
+                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
+                       continue;
+               }
+
+               __qed_get_vport_stats(p_hwfn, p_ptt, stats, fw_vport);
+
+               qed_ptt_release(p_hwfn, p_ptt);
+       }
+}
+
+void qed_get_vport_stats(struct qed_dev *cdev,
+                        struct qed_eth_stats *stats)
+{
+       u32 i;
+
+       if (!cdev) {
+               memset(stats, 0, sizeof(*stats));
+               return;
+       }
+
+       _qed_get_vport_stats(cdev, stats);
+
+       if (!cdev->reset_stats)
+               return;
+
+       /* Reduce the statistics baseline */
+       for (i = 0; i < sizeof(struct qed_eth_stats) / sizeof(u64); i++)
+               ((u64 *)stats)[i] -= ((u64 *)cdev->reset_stats)[i];
+}
+
+/* zeroes V-PORT specific portion of stats (Port stats remains untouched) */
+void qed_reset_vport_stats(struct qed_dev *cdev)
+{
+       int i;
+
+       for_each_hwfn(cdev, i) {
+               struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
+               struct eth_mstorm_per_queue_stat mstats;
+               struct eth_ustorm_per_queue_stat ustats;
+               struct eth_pstorm_per_queue_stat pstats;
+               struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
+               u32 addr = 0, len = 0;
+
+               if (!p_ptt) {
+                       DP_ERR(p_hwfn, "Failed to acquire ptt\n");
+                       continue;
+               }
+
+               memset(&mstats, 0, sizeof(mstats));
+               __qed_get_vport_mstats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &mstats, len);
+
+               memset(&ustats, 0, sizeof(ustats));
+               __qed_get_vport_ustats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &ustats, len);
+
+               memset(&pstats, 0, sizeof(pstats));
+               __qed_get_vport_pstats_addrlen(p_hwfn, &addr, &len, 0);
+               qed_memcpy_to(p_hwfn, p_ptt, addr, &pstats, len);
+
+               qed_ptt_release(p_hwfn, p_ptt);
+       }
+
+       /* PORT statistics are not necessarily reset, so we need to
+        * read and create a baseline for future statistics.
+        */
+       if (!cdev->reset_stats)
+               DP_INFO(cdev, "Reset stats not allocated\n");
+       else
+               _qed_get_vport_stats(cdev, cdev->reset_stats);
+}
+
 static int qed_fill_eth_dev_info(struct qed_dev *cdev,
                                 struct qed_dev_eth_info *info)
 {
@@ -1268,24 +1622,25 @@ static void qed_register_eth_ops(struct qed_dev *cdev,
 }
 
 static int qed_start_vport(struct qed_dev *cdev,
-                          u8 vport_id,
-                          u16 mtu,
-                          u8 drop_ttl0_flg,
-                          u8 inner_vlan_removal_en_flg)
+                          struct qed_start_vport_params *params)
 {
        int rc, i;
 
        for_each_hwfn(cdev, i) {
+               struct qed_sp_vport_start_params start = { 0 };
                struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
 
-               rc = qed_sp_vport_start(p_hwfn,
-                                       p_hwfn->hw_info.concrete_fid,
-                                       p_hwfn->hw_info.opaque_fid,
-                                       vport_id,
-                                       mtu,
-                                       drop_ttl0_flg,
-                                       inner_vlan_removal_en_flg);
-
+               start.tpa_mode = params->gro_enable ? QED_TPA_MODE_GRO :
+                                                       QED_TPA_MODE_NONE;
+               start.remove_inner_vlan = params->remove_inner_vlan;
+               start.drop_ttl0 = params->drop_ttl0;
+               start.opaque_fid = p_hwfn->hw_info.opaque_fid;
+               start.concrete_fid = p_hwfn->hw_info.concrete_fid;
+               start.vport_id = params->vport_id;
+               start.max_buffers_per_cqe = 16;
+               start.mtu = params->mtu;
+
+               rc = qed_sp_vport_start(p_hwfn, &start);
                if (rc) {
                        DP_ERR(cdev, "Failed to start VPORT\n");
                        return rc;
@@ -1295,7 +1650,7 @@ static int qed_start_vport(struct qed_dev *cdev,
 
                DP_VERBOSE(cdev, (QED_MSG_SPQ | NETIF_MSG_IFUP),
                           "Started V-PORT %d with MTU %d\n",
-                          vport_id, mtu);
+                          start.vport_id, start.mtu);
        }
 
        qed_reset_vport_stats(cdev);
@@ -1344,6 +1699,9 @@ static int qed_update_vport(struct qed_dev *cdev,
                params->update_vport_active_flg;
        sp_params.vport_active_rx_flg = params->vport_active_flg;
        sp_params.vport_active_tx_flg = params->vport_active_flg;
+       sp_params.accept_any_vlan = params->accept_any_vlan;
+       sp_params.update_accept_any_vlan_flg =
+               params->update_accept_any_vlan_flg;
 
        /* RSS - is a bit tricky, since upper-layer isn't familiar with hwfns.
         * We need to re-fix the rss values per engine for CMT.
@@ -1563,7 +1921,7 @@ static int qed_configure_filter_rx_mode(struct qed_dev *cdev,
        else if (type == QED_FILTER_RX_MODE_TYPE_MULTI_PROMISC)
                accept_flags.rx_accept_filter |= QED_ACCEPT_MCAST_UNMATCHED;
 
-       return qed_filter_accept_cmd(cdev, 0, accept_flags,
+       return qed_filter_accept_cmd(cdev, 0, accept_flags, false, false,
                                     QED_SPQ_MODE_CB, NULL);
 }
 
index 9d76ce249277a3cef7bdfc45faf06d93582c577f..26d40db07ddd12a13ae07f7494e3244e03f70af4 100644 (file)
 #include "qed_mcp.h"
 #include "qed_hw.h"
 
-static const char version[] =
-       "QLogic QL4xxx 40G/100G Ethernet Driver qed " DRV_MODULE_VERSION "\n";
+static char version[] =
+       "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n";
 
-MODULE_DESCRIPTION("QLogic 25G/40G/50G/100G Core Module");
+MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Core Module");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -45,6 +45,8 @@ MODULE_VERSION(DRV_MODULE_VERSION);
 #define QED_FW_FILE_NAME       \
        "qed/qed_init_values_zipped-" FW_FILE_VERSION ".bin"
 
+MODULE_FIRMWARE(QED_FW_FILE_NAME);
+
 static int __init qed_init(void)
 {
        pr_notice("qed_init called\n");
@@ -97,12 +99,15 @@ static void qed_free_pci(struct qed_dev *cdev)
        pci_disable_device(pdev);
 }
 
+#define PCI_REVISION_ID_ERROR_VAL      0xff
+
 /* Performs PCI initializations as well as initializing PCI-related parameters
  * in the device structrue. Returns 0 in case of success.
  */
 static int qed_init_pci(struct qed_dev *cdev,
                        struct pci_dev *pdev)
 {
+       u8 rev_id;
        int rc;
 
        cdev->pdev = pdev;
@@ -136,6 +141,14 @@ static int qed_init_pci(struct qed_dev *cdev,
                pci_save_state(pdev);
        }
 
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+       if (rev_id == PCI_REVISION_ID_ERROR_VAL) {
+               DP_NOTICE(cdev,
+                         "Detected PCI device error [rev_id 0x%x]. Probably due to prior indication. Aborting.\n",
+                         rev_id);
+               rc = -ENODEV;
+               goto err2;
+       }
        if (!pci_is_pcie(pdev)) {
                DP_NOTICE(cdev, "The bus is not PCI Express\n");
                rc = -EIO;
@@ -190,7 +203,7 @@ int qed_fill_dev_info(struct qed_dev *cdev,
        dev_info->pci_mem_start = cdev->pci_params.mem_start;
        dev_info->pci_mem_end = cdev->pci_params.mem_end;
        dev_info->pci_irq = cdev->pci_params.irq;
-       dev_info->is_mf = IS_MF(&cdev->hwfns[0]);
+       dev_info->is_mf_default = IS_MF_DEFAULT(&cdev->hwfns[0]);
        ether_addr_copy(dev_info->hw_mac, cdev->hwfns[0].hw_info.hw_mac_addr);
 
        dev_info->fw_major = FW_MAJOR_VERSION;
@@ -621,15 +634,18 @@ static int qed_get_int_fp(struct qed_dev *cdev, struct qed_int_info *info)
 static int qed_slowpath_setup_int(struct qed_dev *cdev,
                                  enum qed_int_mode int_mode)
 {
-       int rc, i;
-       u8 num_vectors = 0;
-
+       struct qed_sb_cnt_info sb_cnt_info;
+       int rc;
+       int i;
        memset(&cdev->int_params, 0, sizeof(struct qed_int_params));
 
        cdev->int_params.in.int_mode = int_mode;
-       for_each_hwfn(cdev, i)
-               num_vectors +=  qed_int_get_num_sbs(&cdev->hwfns[i], NULL) + 1;
-       cdev->int_params.in.num_vectors = num_vectors;
+       for_each_hwfn(cdev, i) {
+               memset(&sb_cnt_info, 0, sizeof(sb_cnt_info));
+               qed_int_get_num_sbs(&cdev->hwfns[i], &sb_cnt_info);
+               cdev->int_params.in.num_vectors += sb_cnt_info.sb_cnt;
+               cdev->int_params.in.num_vectors++; /* slowpath */
+       }
 
        /* We want a minimum of one slowpath and one fastpath vector per hwfn */
        cdev->int_params.in.min_msix_cnt = cdev->num_hwfns * 2;
@@ -763,7 +779,7 @@ static int qed_slowpath_start(struct qed_dev *cdev,
        rc = qed_hw_init(cdev, true, cdev->int_params.out.int_mode,
                         true, data);
        if (rc)
-               goto err3;
+               goto err2;
 
        DP_INFO(cdev,
                "HW initialization and function start completed successfully\n");
@@ -782,12 +798,14 @@ static int qed_slowpath_start(struct qed_dev *cdev,
                return rc;
        }
 
+       qed_reset_vport_stats(cdev);
+
        return 0;
 
-err3:
-       qed_free_stream_mem(cdev);
-       qed_slowpath_irq_free(cdev);
 err2:
+       qed_hw_timers_stop_all(cdev);
+       qed_slowpath_irq_free(cdev);
+       qed_free_stream_mem(cdev);
        qed_disable_msix(cdev);
 err1:
        qed_resc_free(cdev);
index ba1b1f1ef789b65381b47692c66d00a8556ba9be..b89c9a8e16557869cfa6682e09c06111327d730f 100644 (file)
@@ -11,8 +11,8 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 #include "qed.h"
 #include "qed_hsi.h"
@@ -147,7 +147,7 @@ int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn,
        u32 size;
 
        /* Allocate mcp_info structure */
-       p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_ATOMIC);
+       p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL);
        if (!p_hwfn->mcp_info)
                goto err;
        p_info = p_hwfn->mcp_info;
@@ -161,15 +161,15 @@ int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn,
        }
 
        size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32);
-       p_info->mfw_mb_cur = kzalloc(size, GFP_ATOMIC);
+       p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL);
        p_info->mfw_mb_shadow =
                kzalloc(sizeof(u32) * MFW_DRV_MSG_MAX_DWORDS(
-                               p_info->mfw_mb_length), GFP_ATOMIC);
+                               p_info->mfw_mb_length), GFP_KERNEL);
        if (!p_info->mfw_mb_shadow || !p_info->mfw_mb_addr)
                goto err;
 
-       /* Initialize the MFW mutex */
-       mutex_init(&p_info->mutex);
+       /* Initialize the MFW spinlock */
+       spin_lock_init(&p_info->lock);
 
        return 0;
 
@@ -179,6 +179,52 @@ err:
        return -ENOMEM;
 }
 
+/* Locks the MFW mailbox of a PF to ensure a single access.
+ * The lock is achieved in most cases by holding a spinlock, causing other
+ * threads to wait till a previous access is done.
+ * In some cases (currently when a [UN]LOAD_REQ commands are sent), the single
+ * access is achieved by setting a blocking flag, which will fail other
+ * competing contexts to send their mailboxes.
+ */
+static int qed_mcp_mb_lock(struct qed_hwfn *p_hwfn,
+                          u32 cmd)
+{
+       spin_lock_bh(&p_hwfn->mcp_info->lock);
+
+       /* The spinlock shouldn't be acquired when the mailbox command is
+        * [UN]LOAD_REQ, since the engine is locked by the MFW, and a parallel
+        * pending [UN]LOAD_REQ command of another PF together with a spinlock
+        * (i.e. interrupts are disabled) - can lead to a deadlock.
+        * It is assumed that for a single PF, no other mailbox commands can be
+        * sent from another context while sending LOAD_REQ, and that any
+        * parallel commands to UNLOAD_REQ can be cancelled.
+        */
+       if (cmd == DRV_MSG_CODE_LOAD_DONE || cmd == DRV_MSG_CODE_UNLOAD_DONE)
+               p_hwfn->mcp_info->block_mb_sending = false;
+
+       if (p_hwfn->mcp_info->block_mb_sending) {
+               DP_NOTICE(p_hwfn,
+                         "Trying to send a MFW mailbox command [0x%x] in parallel to [UN]LOAD_REQ. Aborting.\n",
+                         cmd);
+               spin_unlock_bh(&p_hwfn->mcp_info->lock);
+               return -EBUSY;
+       }
+
+       if (cmd == DRV_MSG_CODE_LOAD_REQ || cmd == DRV_MSG_CODE_UNLOAD_REQ) {
+               p_hwfn->mcp_info->block_mb_sending = true;
+               spin_unlock_bh(&p_hwfn->mcp_info->lock);
+       }
+
+       return 0;
+}
+
+static void qed_mcp_mb_unlock(struct qed_hwfn  *p_hwfn,
+                             u32               cmd)
+{
+       if (cmd != DRV_MSG_CODE_LOAD_REQ && cmd != DRV_MSG_CODE_UNLOAD_REQ)
+               spin_unlock_bh(&p_hwfn->mcp_info->lock);
+}
+
 int qed_mcp_reset(struct qed_hwfn *p_hwfn,
                  struct qed_ptt *p_ptt)
 {
@@ -187,6 +233,13 @@ int qed_mcp_reset(struct qed_hwfn *p_hwfn,
        u32 org_mcp_reset_seq, cnt = 0;
        int rc = 0;
 
+       /* Ensure that only a single thread is accessing the mailbox at a
+        * certain time.
+        */
+       rc = qed_mcp_mb_lock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
+       if (rc != 0)
+               return rc;
+
        /* Set drv command along with the updated sequence */
        org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0);
        DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header,
@@ -209,6 +262,8 @@ int qed_mcp_reset(struct qed_hwfn *p_hwfn,
                rc = -EAGAIN;
        }
 
+       qed_mcp_mb_unlock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
+
        return rc;
 }
 
@@ -275,14 +330,12 @@ static int qed_do_mcp_cmd(struct qed_hwfn *p_hwfn,
        return rc;
 }
 
-int qed_mcp_cmd(struct qed_hwfn *p_hwfn,
-               struct qed_ptt *p_ptt,
-               u32 cmd,
-               u32 param,
-               u32 *o_mcp_resp,
-               u32 *o_mcp_param)
+static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn,
+                                struct qed_ptt *p_ptt,
+                                struct qed_mcp_mb_params *p_mb_params)
 {
-       int rc = 0;
+       u32 union_data_addr;
+       int rc;
 
        /* MCP not initialized */
        if (!qed_mcp_is_init(p_hwfn)) {
@@ -290,28 +343,56 @@ int qed_mcp_cmd(struct qed_hwfn *p_hwfn,
                return -EBUSY;
        }
 
-       /* Lock Mutex to ensure only single thread is
-        * accessing the MCP at one time
+       union_data_addr = p_hwfn->mcp_info->drv_mb_addr +
+                         offsetof(struct public_drv_mb, union_data);
+
+       /* Ensure that only a single thread is accessing the mailbox at a
+        * certain time.
         */
-       mutex_lock(&p_hwfn->mcp_info->mutex);
-       rc = qed_do_mcp_cmd(p_hwfn, p_ptt, cmd, param,
-                           o_mcp_resp, o_mcp_param);
-       /* Release Mutex */
-       mutex_unlock(&p_hwfn->mcp_info->mutex);
+       rc = qed_mcp_mb_lock(p_hwfn, p_mb_params->cmd);
+       if (rc)
+               return rc;
+
+       if (p_mb_params->p_data_src != NULL)
+               qed_memcpy_to(p_hwfn, p_ptt, union_data_addr,
+                             p_mb_params->p_data_src,
+                             sizeof(*p_mb_params->p_data_src));
+
+       rc = qed_do_mcp_cmd(p_hwfn, p_ptt, p_mb_params->cmd,
+                           p_mb_params->param, &p_mb_params->mcp_resp,
+                           &p_mb_params->mcp_param);
+
+       if (p_mb_params->p_data_dst != NULL)
+               qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst,
+                               union_data_addr,
+                               sizeof(*p_mb_params->p_data_dst));
+
+       qed_mcp_mb_unlock(p_hwfn, p_mb_params->cmd);
 
        return rc;
 }
 
-static void qed_mcp_set_drv_ver(struct qed_dev *cdev,
-                               struct qed_hwfn *p_hwfn,
-                               struct qed_ptt *p_ptt)
+int qed_mcp_cmd(struct qed_hwfn *p_hwfn,
+               struct qed_ptt *p_ptt,
+               u32 cmd,
+               u32 param,
+               u32 *o_mcp_resp,
+               u32 *o_mcp_param)
 {
-       u32 i;
+       struct qed_mcp_mb_params mb_params;
+       int rc;
 
-       /* Copy version string to MCP */
-       for (i = 0; i < MCP_DRV_VER_STR_SIZE_DWORD; i++)
-               DRV_MB_WR(p_hwfn, p_ptt, union_data.ver_str[i],
-                         *(u32 *)&cdev->ver_str[i * sizeof(u32)]);
+       memset(&mb_params, 0, sizeof(mb_params));
+       mb_params.cmd = cmd;
+       mb_params.param = param;
+       rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+       if (rc)
+               return rc;
+
+       *o_mcp_resp = mb_params.mcp_resp;
+       *o_mcp_param = mb_params.mcp_param;
+
+       return 0;
 }
 
 int qed_mcp_load_req(struct qed_hwfn *p_hwfn,
@@ -319,26 +400,18 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn,
                     u32 *p_load_code)
 {
        struct qed_dev *cdev = p_hwfn->cdev;
-       u32 param;
+       struct qed_mcp_mb_params mb_params;
+       union drv_union_data union_data;
        int rc;
 
-       if (!qed_mcp_is_init(p_hwfn)) {
-               DP_NOTICE(p_hwfn, "MFW is not initialized !\n");
-               return -EBUSY;
-       }
-
-       /* Save driver's version to shmem */
-       qed_mcp_set_drv_ver(cdev, p_hwfn, p_ptt);
-
-       DP_VERBOSE(p_hwfn, QED_MSG_SP, "fw_seq 0x%08x, drv_pulse 0x%x\n",
-                  p_hwfn->mcp_info->drv_mb_seq,
-                  p_hwfn->mcp_info->drv_pulse_seq);
-
+       memset(&mb_params, 0, sizeof(mb_params));
        /* Load Request */
-       rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_REQ,
-                        (PDA_COMP | DRV_ID_MCP_HSI_VER_CURRENT |
-                         cdev->drv_type),
-                        p_load_code, &param);
+       mb_params.cmd = DRV_MSG_CODE_LOAD_REQ;
+       mb_params.param = PDA_COMP | DRV_ID_MCP_HSI_VER_CURRENT |
+                         cdev->drv_type;
+       memcpy(&union_data.ver_str, cdev->ver_str, MCP_DRV_VER_STR_SIZE);
+       mb_params.p_data_src = &union_data;
+       rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
 
        /* if mcp fails to respond we must abort */
        if (rc) {
@@ -346,6 +419,8 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn,
                return rc;
        }
 
+       *p_load_code = mb_params.mcp_resp;
+
        /* If MFW refused (e.g. other port is in diagnostic mode) we
         * must abort. This can happen in the following cases:
         * - Other port is in diagnostic mode
@@ -365,6 +440,33 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn,
        return 0;
 }
 
+static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn,
+                                             struct qed_ptt *p_ptt)
+{
+       u32 transceiver_state;
+
+       transceiver_state = qed_rd(p_hwfn, p_ptt,
+                                  p_hwfn->mcp_info->port_addr +
+                                  offsetof(struct public_port,
+                                           transceiver_data));
+
+       DP_VERBOSE(p_hwfn,
+                  (NETIF_MSG_HW | QED_MSG_SP),
+                  "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n",
+                  transceiver_state,
+                  (u32)(p_hwfn->mcp_info->port_addr +
+                        offsetof(struct public_port,
+                                 transceiver_data)));
+
+       transceiver_state = GET_FIELD(transceiver_state,
+                                     PMM_TRANSCEIVER_STATE);
+
+       if (transceiver_state == PMM_TRANSCEIVER_STATE_PRESENT)
+               DP_NOTICE(p_hwfn, "Transceiver is present.\n");
+       else
+               DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n");
+}
+
 static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
                                       struct qed_ptt *p_ptt,
                                       bool b_reset)
@@ -390,7 +492,10 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
                return;
        }
 
-       p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
+       if (p_hwfn->b_drv_link_init)
+               p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
+       else
+               p_link->link_up = false;
 
        p_link->full_duplex = true;
        switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) {
@@ -492,53 +597,43 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn,
                     bool b_up)
 {
        struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input;
-       u32 param = 0, reply = 0, cmd;
-       struct pmm_phy_cfg phy_cfg;
+       struct qed_mcp_mb_params mb_params;
+       union drv_union_data union_data;
+       struct pmm_phy_cfg *phy_cfg;
        int rc = 0;
-       u32 i;
-
-       if (!qed_mcp_is_init(p_hwfn)) {
-               DP_NOTICE(p_hwfn, "MFW is not initialized !\n");
-               return -EBUSY;
-       }
+       u32 cmd;
 
        /* Set the shmem configuration according to params */
-       memset(&phy_cfg, 0, sizeof(phy_cfg));
+       phy_cfg = &union_data.drv_phy_cfg;
+       memset(phy_cfg, 0, sizeof(*phy_cfg));
        cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET;
        if (!params->speed.autoneg)
-               phy_cfg.speed = params->speed.forced_speed;
-       phy_cfg.pause |= (params->pause.autoneg) ? PMM_PAUSE_AUTONEG : 0;
-       phy_cfg.pause |= (params->pause.forced_rx) ? PMM_PAUSE_RX : 0;
-       phy_cfg.pause |= (params->pause.forced_tx) ? PMM_PAUSE_TX : 0;
-       phy_cfg.adv_speed = params->speed.advertised_speeds;
-       phy_cfg.loopback_mode = params->loopback_mode;
-
-       /* Write the requested configuration to shmem */
-       for (i = 0; i < sizeof(phy_cfg); i += 4)
-               qed_wr(p_hwfn, p_ptt,
-                      p_hwfn->mcp_info->drv_mb_addr +
-                      offsetof(struct public_drv_mb, union_data) + i,
-                      ((u32 *)&phy_cfg)[i >> 2]);
+               phy_cfg->speed = params->speed.forced_speed;
+       phy_cfg->pause |= (params->pause.autoneg) ? PMM_PAUSE_AUTONEG : 0;
+       phy_cfg->pause |= (params->pause.forced_rx) ? PMM_PAUSE_RX : 0;
+       phy_cfg->pause |= (params->pause.forced_tx) ? PMM_PAUSE_TX : 0;
+       phy_cfg->adv_speed = params->speed.advertised_speeds;
+       phy_cfg->loopback_mode = params->loopback_mode;
+
+       p_hwfn->b_drv_link_init = b_up;
 
        if (b_up) {
                DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
                           "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n",
-                          phy_cfg.speed,
-                          phy_cfg.pause,
-                          phy_cfg.adv_speed,
-                          phy_cfg.loopback_mode,
-                          phy_cfg.feature_config_flags);
+                          phy_cfg->speed,
+                          phy_cfg->pause,
+                          phy_cfg->adv_speed,
+                          phy_cfg->loopback_mode,
+                          phy_cfg->feature_config_flags);
        } else {
                DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
                           "Resetting link\n");
        }
 
-       DP_VERBOSE(p_hwfn, QED_MSG_SP, "fw_seq 0x%08x, drv_pulse 0x%x\n",
-                  p_hwfn->mcp_info->drv_mb_seq,
-                  p_hwfn->mcp_info->drv_pulse_seq);
-
-       /* Load Request */
-       rc = qed_mcp_cmd(p_hwfn, p_ptt, cmd, 0, &reply, &param);
+       memset(&mb_params, 0, sizeof(mb_params));
+       mb_params.cmd = cmd;
+       mb_params.p_data_src = &union_data;
+       rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
 
        /* if mcp fails to respond we must abort */
        if (rc) {
@@ -581,6 +676,9 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn,
                case MFW_DRV_MSG_LINK_CHANGE:
                        qed_mcp_handle_link_change(p_hwfn, p_ptt, false);
                        break;
+               case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE:
+                       qed_mcp_handle_transceiver_change(p_hwfn, p_ptt);
+                       break;
                default:
                        DP_NOTICE(p_hwfn, "Unimplemented MFW message %d\n", i);
                        rc = -EINVAL;
@@ -720,26 +818,25 @@ int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn,
                return -EINVAL;
        }
 
-       if (p_hwfn->cdev->mf_mode != SF) {
-               info->bandwidth_min = (shmem_info.config &
-                                      FUNC_MF_CFG_MIN_BW_MASK) >>
-                                     FUNC_MF_CFG_MIN_BW_SHIFT;
-               if (info->bandwidth_min < 1 || info->bandwidth_min > 100) {
-                       DP_INFO(p_hwfn,
-                               "bandwidth minimum out of bounds [%02x]. Set to 1\n",
-                               info->bandwidth_min);
-                       info->bandwidth_min = 1;
-               }
 
-               info->bandwidth_max = (shmem_info.config &
-                                      FUNC_MF_CFG_MAX_BW_MASK) >>
-                                     FUNC_MF_CFG_MAX_BW_SHIFT;
-               if (info->bandwidth_max < 1 || info->bandwidth_max > 100) {
-                       DP_INFO(p_hwfn,
-                               "bandwidth maximum out of bounds [%02x]. Set to 100\n",
-                               info->bandwidth_max);
-                       info->bandwidth_max = 100;
-               }
+       info->bandwidth_min = (shmem_info.config &
+                              FUNC_MF_CFG_MIN_BW_MASK) >>
+                             FUNC_MF_CFG_MIN_BW_SHIFT;
+       if (info->bandwidth_min < 1 || info->bandwidth_min > 100) {
+               DP_INFO(p_hwfn,
+                       "bandwidth minimum out of bounds [%02x]. Set to 1\n",
+                       info->bandwidth_min);
+               info->bandwidth_min = 1;
+       }
+
+       info->bandwidth_max = (shmem_info.config &
+                              FUNC_MF_CFG_MAX_BW_MASK) >>
+                             FUNC_MF_CFG_MAX_BW_SHIFT;
+       if (info->bandwidth_max < 1 || info->bandwidth_max > 100) {
+               DP_INFO(p_hwfn,
+                       "bandwidth maximum out of bounds [%02x]. Set to 100\n",
+                       info->bandwidth_max);
+               info->bandwidth_max = 100;
        }
 
        if (shmem_info.mac_upper || shmem_info.mac_lower) {
@@ -802,11 +899,11 @@ int qed_mcp_drain(struct qed_hwfn *p_hwfn,
        int rc;
 
        rc = qed_mcp_cmd(p_hwfn, p_ptt,
-                        DRV_MSG_CODE_NIG_DRAIN, 100,
+                        DRV_MSG_CODE_NIG_DRAIN, 1000,
                         &resp, &param);
 
        /* Wait for the drain to complete before returning */
-       msleep(120);
+       msleep(1020);
 
        return rc;
 }
@@ -832,31 +929,28 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn,
                         struct qed_ptt *p_ptt,
                         struct qed_mcp_drv_version *p_ver)
 {
-       int rc = 0;
-       u32 param = 0, reply = 0, i;
-
-       if (!qed_mcp_is_init(p_hwfn)) {
-               DP_NOTICE(p_hwfn, "MFW is not initialized !\n");
-               return -EBUSY;
-       }
+       struct drv_version_stc *p_drv_version;
+       struct qed_mcp_mb_params mb_params;
+       union drv_union_data union_data;
+       __be32 val;
+       u32 i;
+       int rc;
 
-       DRV_MB_WR(p_hwfn, p_ptt, union_data.drv_version.version,
-                 p_ver->version);
-       /* Copy version string to shmem */
-       for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / 4; i++) {
-               DRV_MB_WR(p_hwfn, p_ptt,
-                         union_data.drv_version.name[i * sizeof(u32)],
-                         *(u32 *)&p_ver->name[i * sizeof(u32)]);
+       p_drv_version = &union_data.drv_version;
+       p_drv_version->version = p_ver->version;
+       for (i = 0; i < MCP_DRV_VER_STR_SIZE - 1; i += 4) {
+               val = cpu_to_be32(p_ver->name[i]);
+               *(u32 *)&p_drv_version->name[i * sizeof(u32)] = val;
        }
 
-       rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_VERSION, 0, &reply,
-                        &param);
-       if (rc) {
+       memset(&mb_params, 0, sizeof(mb_params));
+       mb_params.cmd = DRV_MSG_CODE_SET_VERSION;
+       mb_params.p_data_src = &union_data;
+       rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+       if (rc)
                DP_ERR(p_hwfn, "MCP response failure, aborting\n");
-               return rc;
-       }
 
-       return 0;
+       return rc;
 }
 
 int qed_mcp_set_led(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
index 506197d5c3dda19c6404bf8c382769f2ac64c26d..50917a2131a5da04e0134f183f6cce4509175c29 100644 (file)
@@ -11,8 +11,8 @@
 
 #include <linux/types.h>
 #include <linux/delay.h>
-#include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include "qed_hsi.h"
 
 struct qed_mcp_link_speed_params {
@@ -255,7 +255,8 @@ int qed_mcp_set_led(struct qed_hwfn *p_hwfn,
 #define MFW_PORT(_p_hwfn)       ((_p_hwfn)->abs_pf_id %        \
                                 ((_p_hwfn)->cdev->num_ports_in_engines * 2))
 struct qed_mcp_info {
-       struct mutex                            mutex; /* MCP access lock */
+       spinlock_t                              lock;
+       bool                                    block_mb_sending;
        u32                                     public_base;
        u32                                     drv_mb_addr;
        u32                                     mfw_mb_addr;
@@ -272,6 +273,15 @@ struct qed_mcp_info {
        u16                                     mcp_hist;
 };
 
+struct qed_mcp_mb_params {
+       u32                     cmd;
+       u32                     param;
+       union drv_union_data    *p_data_src;
+       union drv_union_data    *p_data_dst;
+       u32                     mcp_resp;
+       u32                     mcp_param;
+};
+
 /**
  * @brief Initialize the interface with the MCP
  *
index e8df12335a972cd3092cbefa8b675408446f06c9..c15b1622e636e4509c6e537fb3a68018d661a43e 100644 (file)
        0x00c000UL
 #define  DORQ_REG_IFEN \
        0x100040UL
+#define DORQ_REG_DB_DROP_REASON \
+       0x100a2cUL
+#define DORQ_REG_DB_DROP_DETAILS \
+       0x100a24UL
+#define DORQ_REG_DB_DROP_DETAILS_ADDRESS \
+       0x100a1cUL
 #define  GRC_REG_TIMEOUT_EN \
        0x050404UL
+#define GRC_REG_TIMEOUT_ATTN_ACCESS_VALID \
+       0x050054UL
+#define GRC_REG_TIMEOUT_ATTN_ACCESS_DATA_0 \
+       0x05004cUL
+#define GRC_REG_TIMEOUT_ATTN_ACCESS_DATA_1 \
+       0x050050UL
 #define  IGU_REG_BLOCK_CONFIGURATION \
        0x180040UL
 #define  MCM_REG_INIT \
        0x1100000UL
 #define  PGLUE_B_REG_ADMIN_PER_PF_REGION       \
        0x2a9000UL
+#define PGLUE_B_REG_TX_ERR_WR_DETAILS2 \
+       0x2aa150UL
+#define PGLUE_B_REG_TX_ERR_WR_ADD_31_0 \
+       0x2aa144UL
+#define PGLUE_B_REG_TX_ERR_WR_ADD_63_32 \
+       0x2aa148UL
+#define PGLUE_B_REG_TX_ERR_WR_DETAILS \
+       0x2aa14cUL
+#define PGLUE_B_REG_TX_ERR_RD_ADD_31_0 \
+       0x2aa154UL
+#define PGLUE_B_REG_TX_ERR_RD_ADD_63_32 \
+       0x2aa158UL
+#define PGLUE_B_REG_TX_ERR_RD_DETAILS \
+       0x2aa15cUL
+#define PGLUE_B_REG_TX_ERR_RD_DETAILS2 \
+       0x2aa160UL
+#define PGLUE_B_REG_TX_ERR_WR_DETAILS_ICPL \
+       0x2aa164UL
+#define PGLUE_B_REG_MASTER_ZLR_ERR_DETAILS \
+       0x2aa54cUL
+#define PGLUE_B_REG_MASTER_ZLR_ERR_ADD_31_0 \
+       0x2aa544UL
+#define PGLUE_B_REG_MASTER_ZLR_ERR_ADD_63_32 \
+       0x2aa548UL
+#define PGLUE_B_REG_VF_ILT_ERR_ADD_31_0 \
+       0x2aae74UL
+#define PGLUE_B_REG_VF_ILT_ERR_ADD_63_32 \
+       0x2aae78UL
+#define PGLUE_B_REG_VF_ILT_ERR_DETAILS \
+       0x2aae7cUL
+#define PGLUE_B_REG_VF_ILT_ERR_DETAILS2 \
+       0x2aae80UL
+#define PGLUE_B_REG_LATCHED_ERRORS_CLR \
+       0x2aa3bcUL
 #define  PRM_REG_DISABLE_PRM \
        0x230000UL
 #define  PRS_REG_SOFT_RST \
        0x2a0040UL
 #define  PSWHST2_REG_DBGSYN_ALMOST_FULL_THR \
        0x29e050UL
+#define PSWHST_REG_INCORRECT_ACCESS_VALID \
+       0x2a0070UL
+#define PSWHST_REG_INCORRECT_ACCESS_ADDRESS \
+       0x2a0074UL
+#define PSWHST_REG_INCORRECT_ACCESS_DATA \
+       0x2a0068UL
+#define PSWHST_REG_INCORRECT_ACCESS_LENGTH \
+       0x2a006cUL
 #define  PSWRD_REG_DBG_SELECT \
        0x29c040UL
 #define  PSWRD2_REG_CONF11 \
        0x180800UL
 #define  MISC_REG_AEU_ENABLE1_IGU_OUT_0 \
        0x00849cUL
+#define MISC_REG_AEU_AFTER_INVERT_1_IGU        \
+       0x0087b4UL
 #define  MISC_REG_AEU_MASK_ATTN_IGU \
        0x008494UL
 #define  IGU_REG_CLEANUP_STATUS_0 \
                0x7 << 0)
 #define  MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT \
        0
+#define MCP_REG_CPU_STATE \
+       0xe05004UL
+#define MCP_REG_CPU_EVENT_MASK \
+       0xe05008UL
 #define PGLUE_B_REG_PF_BAR0_SIZE \
        0x2aae60UL
 #define PGLUE_B_REG_PF_BAR1_SIZE \
index 287fadfab52d754e0a913d4ed044ca7e50cf1a09..d39f914b66ee869714b023fad1fd1a557c369208 100644 (file)
@@ -311,19 +311,20 @@ void qed_consq_free(struct qed_hwfn *p_hwfn,
 #define QED_SP_EQ_COMPLETION  0x01
 #define QED_SP_CQE_COMPLETION 0x02
 
-struct qed_sp_init_request_params {
-       size_t                  ramrod_data_size;
+struct qed_sp_init_data {
+       u32                     cid;
+       u16                     opaque_fid;
+
+       /* Information regarding operation upon sending & completion */
        enum spq_mode           comp_mode;
        struct qed_spq_comp_cb *p_comp_data;
 };
 
 int qed_sp_init_request(struct qed_hwfn *p_hwfn,
                        struct qed_spq_entry **pp_ent,
-                       u32 cid,
-                       u16 opaque_fid,
                        u8 cmd,
                        u8 protocol,
-                       struct qed_sp_init_request_params *p_params);
+                       struct qed_sp_init_data *p_data);
 
 /**
  * @brief qed_sp_pf_start - PF Function Start Ramrod
@@ -343,7 +344,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
  */
 
 int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
-                   enum mf_mode mode);
+                   enum qed_mf_mode mode);
 
 /**
  * @brief qed_sp_pf_stop - PF Function Stop Ramrod
index 6f787913663362f39efd707f136a12a967a894a4..1c06c37d4c3d75a1650dcb82cd6de9385589db8f 100644 (file)
 
 int qed_sp_init_request(struct qed_hwfn *p_hwfn,
                        struct qed_spq_entry **pp_ent,
-                       u32 cid,
-                       u16 opaque_fid,
                        u8 cmd,
                        u8 protocol,
-                       struct qed_sp_init_request_params *p_params)
+                       struct qed_sp_init_data *p_data)
 {
-       int rc = -EINVAL;
+       u32 opaque_cid = p_data->opaque_fid << 16 | p_data->cid;
        struct qed_spq_entry *p_ent = NULL;
-       u32 opaque_cid = opaque_fid << 16 | cid;
+       int rc;
 
        if (!pp_ent)
                return -ENOMEM;
@@ -48,7 +46,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
        p_ent->elem.hdr.protocol_id     = protocol;
 
        p_ent->priority         = QED_SPQ_PRIORITY_NORMAL;
-       p_ent->comp_mode        = p_params->comp_mode;
+       p_ent->comp_mode        = p_data->comp_mode;
        p_ent->comp_done.done   = 0;
 
        switch (p_ent->comp_mode) {
@@ -57,17 +55,17 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
                break;
 
        case QED_SPQ_MODE_BLOCK:
-               if (!p_params->p_comp_data)
+               if (!p_data->p_comp_data)
                        return -EINVAL;
 
-               p_ent->comp_cb.cookie = p_params->p_comp_data->cookie;
+               p_ent->comp_cb.cookie = p_data->p_comp_data->cookie;
                break;
 
        case QED_SPQ_MODE_CB:
-               if (!p_params->p_comp_data)
+               if (!p_data->p_comp_data)
                        p_ent->comp_cb.function = NULL;
                else
-                       p_ent->comp_cb = *p_params->p_comp_data;
+                       p_ent->comp_cb = *p_data->p_comp_data;
                break;
 
        default:
@@ -83,37 +81,35 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
                   D_TRINE(p_ent->comp_mode, QED_SPQ_MODE_EBLOCK,
                           QED_SPQ_MODE_BLOCK, "MODE_EBLOCK", "MODE_BLOCK",
                           "MODE_CB"));
-       if (p_params->ramrod_data_size)
-               memset(&p_ent->ramrod, 0, p_params->ramrod_data_size);
+
+       memset(&p_ent->ramrod, 0, sizeof(p_ent->ramrod));
 
        return 0;
 }
 
 int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
-                   enum mf_mode mode)
+                   enum qed_mf_mode mode)
 {
-       struct qed_sp_init_request_params params;
        struct pf_start_ramrod_data *p_ramrod = NULL;
        u16 sb = qed_int_get_sp_sb_id(p_hwfn);
        u8 sb_index = p_hwfn->p_eq->eq_sb_index;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        int rc = -EINVAL;
 
        /* update initial eq producer */
        qed_eq_prod_update(p_hwfn,
                           qed_chain_get_prod_idx(&p_hwfn->p_eq->chain));
 
-       memset(&params, 0, sizeof(params));
-       params.ramrod_data_size = sizeof(*p_ramrod);
-       params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
-       rc = qed_sp_init_request(p_hwfn,
-                                &p_ent,
-                                qed_spq_get_cid(p_hwfn),
-                                p_hwfn->hw_info.opaque_fid,
+       rc = qed_sp_init_request(p_hwfn, &p_ent,
                                 COMMON_RAMROD_PF_START,
                                 PROTOCOLID_COMMON,
-                                &params);
+                                &init_data);
        if (rc)
                return rc;
 
@@ -125,26 +121,33 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
        p_ramrod->dont_log_ramrods      = 0;
        p_ramrod->log_type_mask         = cpu_to_le16(0xf);
        p_ramrod->mf_mode = mode;
+       switch (mode) {
+       case QED_MF_DEFAULT:
+       case QED_MF_NPAR:
+               p_ramrod->mf_mode = MF_NPAR;
+               break;
+       case QED_MF_OVLAN:
+               p_ramrod->mf_mode = MF_OVLAN;
+               break;
+       default:
+               DP_NOTICE(p_hwfn, "Unsupported MF mode, init as DEFAULT\n");
+               p_ramrod->mf_mode = MF_NPAR;
+       }
        p_ramrod->outer_tag = p_hwfn->hw_info.ovlan;
 
        /* Place EQ address in RAMROD */
-       p_ramrod->event_ring_pbl_addr.hi =
-                       DMA_HI_LE(p_hwfn->p_eq->chain.pbl.p_phys_table);
-       p_ramrod->event_ring_pbl_addr.lo =
-                       DMA_LO_LE(p_hwfn->p_eq->chain.pbl.p_phys_table);
+       DMA_REGPAIR_LE(p_ramrod->event_ring_pbl_addr,
+                      p_hwfn->p_eq->chain.pbl.p_phys_table);
        p_ramrod->event_ring_num_pages = (u8)p_hwfn->p_eq->chain.page_cnt;
 
-       p_ramrod->consolid_q_pbl_addr.hi =
-                       DMA_HI_LE(p_hwfn->p_consq->chain.pbl.p_phys_table);
-       p_ramrod->consolid_q_pbl_addr.lo =
-                       DMA_LO_LE(p_hwfn->p_consq->chain.pbl.p_phys_table);
+       DMA_REGPAIR_LE(p_ramrod->consolid_q_pbl_addr,
+                      p_hwfn->p_consq->chain.pbl.p_phys_table);
 
        p_hwfn->hw_info.personality = PERSONALITY_ETH;
 
        DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
-                  "Setting event_ring_sb [id %04x index %02x], mf [%s] outer_tag [%d]\n",
+                  "Setting event_ring_sb [id %04x index %02x], outer_tag [%d]\n",
                   sb, sb_index,
-                  (p_ramrod->mf_mode == SF) ? "SF" : "Multi-Pf",
                   p_ramrod->outer_tag);
 
        return qed_spq_post(p_hwfn, p_ent, NULL);
@@ -152,17 +155,19 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
 
 int qed_sp_pf_stop(struct qed_hwfn *p_hwfn)
 {
-       struct qed_sp_init_request_params params;
        struct qed_spq_entry *p_ent = NULL;
+       struct qed_sp_init_data init_data;
        int rc = -EINVAL;
 
-       memset(&params, 0, sizeof(params));
-       params.comp_mode = QED_SPQ_MODE_EBLOCK;
+       /* Get SPQ entry */
+       memset(&init_data, 0, sizeof(init_data));
+       init_data.cid = qed_spq_get_cid(p_hwfn);
+       init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
+       init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
-       rc = qed_sp_init_request(p_hwfn, &p_ent, qed_spq_get_cid(p_hwfn),
-                                p_hwfn->hw_info.opaque_fid,
+       rc = qed_sp_init_request(p_hwfn, &p_ent,
                                 COMMON_RAMROD_PF_STOP, PROTOCOLID_COMMON,
-                                &params);
+                                &init_data);
        if (rc)
                return rc;
 
index 3dd548ab8df14aabf9fa6a551cf54aa97f704d12..89469d5aae25cc709d366f9112d225ec481714f6 100644 (file)
@@ -183,10 +183,8 @@ static void qed_spq_hw_initialize(struct qed_hwfn *p_hwfn,
        p_cxt->xstorm_st_context.spq_base_hi =
                DMA_HI_LE(p_spq->chain.p_phys_addr);
 
-       p_cxt->xstorm_st_context.consolid_base_addr.lo =
-               DMA_LO_LE(p_hwfn->p_consq->chain.p_phys_addr);
-       p_cxt->xstorm_st_context.consolid_base_addr.hi =
-               DMA_HI_LE(p_hwfn->p_consq->chain.p_phys_addr);
+       DMA_REGPAIR_LE(p_cxt->xstorm_st_context.consolid_base_addr,
+                      p_hwfn->p_consq->chain.p_phys_addr);
 }
 
 static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
@@ -327,7 +325,7 @@ struct qed_eq *qed_eq_alloc(struct qed_hwfn *p_hwfn,
        struct qed_eq *p_eq;
 
        /* Allocate EQ struct */
-       p_eq = kzalloc(sizeof(*p_eq), GFP_ATOMIC);
+       p_eq = kzalloc(sizeof(*p_eq), GFP_KERNEL);
        if (!p_eq) {
                DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_eq'\n");
                return NULL;
@@ -423,8 +421,7 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn)
        p_virt  = p_spq->p_virt;
 
        for (i = 0; i < p_spq->chain.capacity; i++) {
-               p_virt->elem.data_ptr.hi = DMA_HI_LE(p_phys);
-               p_virt->elem.data_ptr.lo = DMA_LO_LE(p_phys);
+               DMA_REGPAIR_LE(p_virt->elem.data_ptr, p_phys);
 
                list_add_tail(&p_virt->list, &p_spq->free_pool);
 
@@ -457,7 +454,7 @@ int qed_spq_alloc(struct qed_hwfn *p_hwfn)
 
        /* SPQ struct */
        p_spq =
-               kzalloc(sizeof(struct qed_spq), GFP_ATOMIC);
+               kzalloc(sizeof(struct qed_spq), GFP_KERNEL);
        if (!p_spq) {
                DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_spq'\n");
                return -ENOMEM;
@@ -853,7 +850,7 @@ struct qed_consq *qed_consq_alloc(struct qed_hwfn *p_hwfn)
        struct qed_consq *p_consq;
 
        /* Allocate ConsQ struct */
-       p_consq = kzalloc(sizeof(*p_consq), GFP_ATOMIC);
+       p_consq = kzalloc(sizeof(*p_consq), GFP_KERNEL);
        if (!p_consq) {
                DP_NOTICE(p_hwfn, "Failed to allocate `struct qed_consq'\n");
                return NULL;
index 7c6caf7f66122ea9452b5d131f7449a5a59a09b2..d023251544d9e7f8df8a1e6c897293385bd45fc1 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/qed/qed_eth_if.h>
 
 #define QEDE_MAJOR_VERSION             8
-#define QEDE_MINOR_VERSION             4
+#define QEDE_MINOR_VERSION             7
 #define QEDE_REVISION_VERSION          0
 #define QEDE_ENGINEERING_VERSION       0
 #define DRV_MODULE_VERSION __stringify(QEDE_MAJOR_VERSION) "." \
@@ -100,6 +100,12 @@ struct qede_stats {
        u64 tx_mac_ctrl_frames;
 };
 
+struct qede_vlan {
+       struct list_head list;
+       u16 vid;
+       bool configured;
+};
+
 struct qede_dev {
        struct qed_dev                  *cdev;
        struct net_device               *ndev;
@@ -154,6 +160,11 @@ struct qede_dev {
        u16                     q_num_rx_buffers; /* Must be a power of two */
        u16                     q_num_tx_buffers; /* Must be a power of two */
 
+       bool gro_disable;
+       struct list_head vlan_list;
+       u16 configured_vlans;
+       u16 non_configured_vlans;
+       bool accept_any_vlan;
        struct delayed_work             sp_task;
        unsigned long                   sp_flags;
 };
@@ -173,9 +184,27 @@ enum QEDE_STATE {
  * skb are built only after the frame was DMA-ed.
  */
 struct sw_rx_data {
-       u8 *data;
+       struct page *data;
+       dma_addr_t mapping;
+       unsigned int page_offset;
+};
 
-       DEFINE_DMA_UNMAP_ADDR(mapping);
+enum qede_agg_state {
+       QEDE_AGG_STATE_NONE  = 0,
+       QEDE_AGG_STATE_START = 1,
+       QEDE_AGG_STATE_ERROR = 2
+};
+
+struct qede_agg_info {
+       struct sw_rx_data replace_buf;
+       dma_addr_t replace_buf_mapping;
+       struct sw_rx_data start_buf;
+       dma_addr_t start_buf_mapping;
+       struct eth_fast_path_rx_tpa_start_cqe start_cqe;
+       enum qede_agg_state agg_state;
+       struct sk_buff *skb;
+       int frag_id;
+       u16 vlan_tag;
 };
 
 struct qede_rx_queue {
@@ -187,7 +216,11 @@ struct qede_rx_queue {
        struct qed_chain        rx_comp_ring;
        void __iomem            *hw_rxq_prod_addr;
 
+       /* GRO */
+       struct qede_agg_info    tpa_info[ETH_TPA_MAX_AGGS_NUM];
+
        int                     rx_buf_size;
+       unsigned int            rx_buf_seg_size;
 
        u16                     num_rx_buffers;
        u16                     rxq_id;
@@ -281,6 +314,7 @@ void qede_fill_by_demand_stats(struct qede_dev *edev);
 #define NUM_TX_BDS_MIN         128
 #define NUM_TX_BDS_DEF         NUM_TX_BDS_MAX
 
+#define QEDE_RX_HDR_SIZE       256
 #define        for_each_rss(i) for (i = 0; i < edev->num_rss; i++)
 
 #endif /* _QEDE_H_ */
index e442b85c9a5e9c2582ecaee835993cd8180c29d9..c49dc10ce15105bea0e676b3e3f9586d096298c4 100644 (file)
@@ -217,9 +217,9 @@ static int qede_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        struct qed_link_params params;
        u32 speed;
 
-       if (edev->dev_info.common.is_mf) {
+       if (!edev->dev_info.common.is_mf_default) {
                DP_INFO(edev,
-                       "Link parameters can not be changed in MF mode\n");
+                       "Link parameters can not be changed in non-default mode\n");
                return -EOPNOTSUPP;
        }
 
@@ -428,7 +428,7 @@ static int qede_set_pauseparam(struct net_device *dev,
        struct qed_link_params params;
        struct qed_link_output current_link;
 
-       if (!edev->dev_info.common.is_mf) {
+       if (!edev->dev_info.common.is_mf_default) {
                DP_INFO(edev,
                        "Pause parameters can not be updated in non-default mode\n");
                return -EOPNOTSUPP;
index 6237f10b5119faae8c6149bae8b6eea31f607deb..518af329502ddff20c8fc322ebed3303b7b0b9a9 100644 (file)
 
 #include "qede.h"
 
-static const char version[] = "QLogic QL4xxx 40G/100G Ethernet Driver qede "
-                             DRV_MODULE_VERSION "\n";
+static char version[] =
+       "QLogic FastLinQ 4xxxx Ethernet Driver qede " DRV_MODULE_VERSION "\n";
 
-MODULE_DESCRIPTION("QLogic 40G/100G Ethernet Driver");
+MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(debug, " Default debug msglevel");
 static const struct qed_eth_ops *qed_ops;
 
 #define CHIP_NUM_57980S_40             0x1634
-#define CHIP_NUM_57980S_10             0x1635
+#define CHIP_NUM_57980S_10             0x1666
 #define CHIP_NUM_57980S_MF             0x1636
 #define CHIP_NUM_57980S_100            0x1644
 #define CHIP_NUM_57980S_50             0x1654
@@ -330,15 +330,15 @@ static void qede_set_params_for_ipv6_ext(struct sk_buff *skb,
                                         struct eth_tx_3rd_bd *third_bd)
 {
        u8 l4_proto;
-       u16 bd2_bits = 0, bd2_bits2 = 0;
+       u16 bd2_bits1 = 0, bd2_bits2 = 0;
 
-       bd2_bits2 |= (1 << ETH_TX_DATA_2ND_BD_IPV6_EXT_SHIFT);
+       bd2_bits1 |= (1 << ETH_TX_DATA_2ND_BD_IPV6_EXT_SHIFT);
 
-       bd2_bits |= ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) &
+       bd2_bits2 |= ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) &
                     ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_MASK)
                    << ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_SHIFT;
 
-       bd2_bits2 |= (ETH_L4_PSEUDO_CSUM_CORRECT_LENGTH <<
+       bd2_bits1 |= (ETH_L4_PSEUDO_CSUM_CORRECT_LENGTH <<
                      ETH_TX_DATA_2ND_BD_L4_PSEUDO_CSUM_MODE_SHIFT);
 
        if (vlan_get_protocol(skb) == htons(ETH_P_IPV6))
@@ -347,16 +347,15 @@ static void qede_set_params_for_ipv6_ext(struct sk_buff *skb,
                l4_proto = ip_hdr(skb)->protocol;
 
        if (l4_proto == IPPROTO_UDP)
-               bd2_bits2 |= 1 << ETH_TX_DATA_2ND_BD_L4_UDP_SHIFT;
+               bd2_bits1 |= 1 << ETH_TX_DATA_2ND_BD_L4_UDP_SHIFT;
 
-       if (third_bd) {
+       if (third_bd)
                third_bd->data.bitfields |=
-                       ((tcp_hdrlen(skb) / 4) &
-                        ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_MASK) <<
-                       ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_SHIFT;
-       }
+                       cpu_to_le16(((tcp_hdrlen(skb) / 4) &
+                               ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_MASK) <<
+                               ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_SHIFT);
 
-       second_bd->data.bitfields = cpu_to_le16(bd2_bits);
+       second_bd->data.bitfields1 = cpu_to_le16(bd2_bits1);
        second_bd->data.bitfields2 = cpu_to_le16(bd2_bits2);
 }
 
@@ -381,6 +380,28 @@ static int map_frag_to_bd(struct qede_dev *edev,
        return 0;
 }
 
+/* +2 for 1st BD for headers and 2nd BD for headlen (if required) */
+#if ((MAX_SKB_FRAGS + 2) > ETH_TX_MAX_BDS_PER_NON_LSO_PACKET)
+static bool qede_pkt_req_lin(struct qede_dev *edev, struct sk_buff *skb,
+                            u8 xmit_type)
+{
+       int allowed_frags = ETH_TX_MAX_BDS_PER_NON_LSO_PACKET - 1;
+
+       if (xmit_type & XMIT_LSO) {
+               int hlen;
+
+               hlen = skb_transport_header(skb) +
+                      tcp_hdrlen(skb) - skb->data;
+
+               /* linear payload would require its own BD */
+               if (skb_headlen(skb) > hlen)
+                       allowed_frags--;
+       }
+
+       return (skb_shinfo(skb)->nr_frags > allowed_frags);
+}
+#endif
+
 /* Main transmit function */
 static
 netdev_tx_t qede_start_xmit(struct sk_buff *skb,
@@ -408,16 +429,22 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb,
        txq = QEDE_TX_QUEUE(edev, txq_index);
        netdev_txq = netdev_get_tx_queue(ndev, txq_index);
 
-       /* Current code doesn't support SKB linearization, since the max number
-        * of skb frags can be passed in the FW HSI.
-        */
-       BUILD_BUG_ON(MAX_SKB_FRAGS > ETH_TX_MAX_BDS_PER_NON_LSO_PACKET);
-
        WARN_ON(qed_chain_get_elem_left(&txq->tx_pbl) <
                               (MAX_SKB_FRAGS + 1));
 
        xmit_type = qede_xmit_type(edev, skb, &ipv6_ext);
 
+#if ((MAX_SKB_FRAGS + 2) > ETH_TX_MAX_BDS_PER_NON_LSO_PACKET)
+       if (qede_pkt_req_lin(edev, skb, xmit_type)) {
+               if (skb_linearize(skb)) {
+                       DP_NOTICE(edev,
+                                 "SKB linearization failed - silently dropping this SKB\n");
+                       dev_kfree_skb_any(skb);
+                       return NETDEV_TX_OK;
+               }
+       }
+#endif
+
        /* Fill the entry in the SW ring and the BDs in the FW ring */
        idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
        txq->sw_tx_ring[idx].skb = skb;
@@ -464,12 +491,16 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb,
 
        /* Fill the parsing flags & params according to the requested offload */
        if (xmit_type & XMIT_L4_CSUM) {
+               u16 temp = 1 << ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_SHIFT;
+
                /* We don't re-calculate IP checksum as it is already done by
                 * the upper stack
                 */
                first_bd->data.bd_flags.bitfields |=
                        1 << ETH_TX_1ST_BD_FLAGS_L4_CSUM_SHIFT;
 
+               first_bd->data.bitfields |= cpu_to_le16(temp);
+
                /* If the packet is IPv6 with extension header, indicate that
                 * to FW and pass few params, since the device cracker doesn't
                 * support parsing IPv6 with extension header/s.
@@ -491,7 +522,7 @@ netdev_tx_t qede_start_xmit(struct sk_buff *skb,
 
                /* @@@TBD - if will not be removed need to check */
                third_bd->data.bitfields |=
-                       (1 << ETH_TX_DATA_3RD_BD_HDR_NBD_SHIFT);
+                       cpu_to_le16((1 << ETH_TX_DATA_3RD_BD_HDR_NBD_SHIFT));
 
                /* Make life easier for FW guys who can't deal with header and
                 * data on same BD. If we need to split, use the second bd...
@@ -719,26 +750,52 @@ static bool qede_has_tx_work(struct qede_fastpath *fp)
        return false;
 }
 
-/* This function copies the Rx buffer from the CONS position to the PROD
- * position, since we failed to allocate a new Rx buffer.
+/* This function reuses the buffer(from an offset) from
+ * consumer index to producer index in the bd ring
  */
-static void qede_reuse_rx_data(struct qede_rx_queue *rxq)
+static inline void qede_reuse_page(struct qede_dev *edev,
+                                  struct qede_rx_queue *rxq,
+                                  struct sw_rx_data *curr_cons)
 {
-       struct eth_rx_bd *rx_bd_cons = qed_chain_consume(&rxq->rx_bd_ring);
        struct eth_rx_bd *rx_bd_prod = qed_chain_produce(&rxq->rx_bd_ring);
-       struct sw_rx_data *sw_rx_data_cons =
-               &rxq->sw_rx_ring[rxq->sw_rx_cons & NUM_RX_BDS_MAX];
-       struct sw_rx_data *sw_rx_data_prod =
-               &rxq->sw_rx_ring[rxq->sw_rx_prod & NUM_RX_BDS_MAX];
+       struct sw_rx_data *curr_prod;
+       dma_addr_t new_mapping;
 
-       dma_unmap_addr_set(sw_rx_data_prod, mapping,
-                          dma_unmap_addr(sw_rx_data_cons, mapping));
+       curr_prod = &rxq->sw_rx_ring[rxq->sw_rx_prod & NUM_RX_BDS_MAX];
+       *curr_prod = *curr_cons;
 
-       sw_rx_data_prod->data = sw_rx_data_cons->data;
-       memcpy(rx_bd_prod, rx_bd_cons, sizeof(struct eth_rx_bd));
+       new_mapping = curr_prod->mapping + curr_prod->page_offset;
+
+       rx_bd_prod->addr.hi = cpu_to_le32(upper_32_bits(new_mapping));
+       rx_bd_prod->addr.lo = cpu_to_le32(lower_32_bits(new_mapping));
 
-       rxq->sw_rx_cons++;
        rxq->sw_rx_prod++;
+       curr_cons->data = NULL;
+}
+
+static inline int qede_realloc_rx_buffer(struct qede_dev *edev,
+                                        struct qede_rx_queue *rxq,
+                                        struct sw_rx_data *curr_cons)
+{
+       /* Move to the next segment in the page */
+       curr_cons->page_offset += rxq->rx_buf_seg_size;
+
+       if (curr_cons->page_offset == PAGE_SIZE) {
+               if (unlikely(qede_alloc_rx_buffer(edev, rxq)))
+                       return -ENOMEM;
+
+               dma_unmap_page(&edev->pdev->dev, curr_cons->mapping,
+                              PAGE_SIZE, DMA_FROM_DEVICE);
+       } else {
+               /* Increment refcount of the page as we don't want
+                * network stack to take the ownership of the page
+                * which can be recycled multiple times by the driver.
+                */
+               atomic_inc(&curr_cons->data->_count);
+               qede_reuse_page(edev, rxq, curr_cons);
+       }
+
+       return 0;
 }
 
 static inline void qede_update_rx_prod(struct qede_dev *edev,
@@ -809,6 +866,281 @@ static inline void qede_skb_receive(struct qede_dev *edev,
        napi_gro_receive(&fp->napi, skb);
 }
 
+static void qede_set_gro_params(struct qede_dev *edev,
+                               struct sk_buff *skb,
+                               struct eth_fast_path_rx_tpa_start_cqe *cqe)
+{
+       u16 parsing_flags = le16_to_cpu(cqe->pars_flags.flags);
+
+       if (((parsing_flags >> PARSING_AND_ERR_FLAGS_L3TYPE_SHIFT) &
+           PARSING_AND_ERR_FLAGS_L3TYPE_MASK) == 2)
+               skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+       else
+               skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+       skb_shinfo(skb)->gso_size = __le16_to_cpu(cqe->len_on_first_bd) -
+                                       cqe->header_len;
+}
+
+static int qede_fill_frag_skb(struct qede_dev *edev,
+                             struct qede_rx_queue *rxq,
+                             u8 tpa_agg_index,
+                             u16 len_on_bd)
+{
+       struct sw_rx_data *current_bd = &rxq->sw_rx_ring[rxq->sw_rx_cons &
+                                                        NUM_RX_BDS_MAX];
+       struct qede_agg_info *tpa_info = &rxq->tpa_info[tpa_agg_index];
+       struct sk_buff *skb = tpa_info->skb;
+
+       if (unlikely(tpa_info->agg_state != QEDE_AGG_STATE_START))
+               goto out;
+
+       /* Add one frag and update the appropriate fields in the skb */
+       skb_fill_page_desc(skb, tpa_info->frag_id++,
+                          current_bd->data, current_bd->page_offset,
+                          len_on_bd);
+
+       if (unlikely(qede_realloc_rx_buffer(edev, rxq, current_bd))) {
+               tpa_info->agg_state = QEDE_AGG_STATE_ERROR;
+               goto out;
+       }
+
+       qed_chain_consume(&rxq->rx_bd_ring);
+       rxq->sw_rx_cons++;
+
+       skb->data_len += len_on_bd;
+       skb->truesize += rxq->rx_buf_seg_size;
+       skb->len += len_on_bd;
+
+       return 0;
+
+out:
+       return -ENOMEM;
+}
+
+static void qede_tpa_start(struct qede_dev *edev,
+                          struct qede_rx_queue *rxq,
+                          struct eth_fast_path_rx_tpa_start_cqe *cqe)
+{
+       struct qede_agg_info *tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
+       struct eth_rx_bd *rx_bd_cons = qed_chain_consume(&rxq->rx_bd_ring);
+       struct eth_rx_bd *rx_bd_prod = qed_chain_produce(&rxq->rx_bd_ring);
+       struct sw_rx_data *replace_buf = &tpa_info->replace_buf;
+       dma_addr_t mapping = tpa_info->replace_buf_mapping;
+       struct sw_rx_data *sw_rx_data_cons;
+       struct sw_rx_data *sw_rx_data_prod;
+       enum pkt_hash_types rxhash_type;
+       u32 rxhash;
+
+       sw_rx_data_cons = &rxq->sw_rx_ring[rxq->sw_rx_cons & NUM_RX_BDS_MAX];
+       sw_rx_data_prod = &rxq->sw_rx_ring[rxq->sw_rx_prod & NUM_RX_BDS_MAX];
+
+       /* Use pre-allocated replacement buffer - we can't release the agg.
+        * start until its over and we don't want to risk allocation failing
+        * here, so re-allocate when aggregation will be over.
+        */
+       dma_unmap_addr_set(sw_rx_data_prod, mapping,
+                          dma_unmap_addr(replace_buf, mapping));
+
+       sw_rx_data_prod->data = replace_buf->data;
+       rx_bd_prod->addr.hi = cpu_to_le32(upper_32_bits(mapping));
+       rx_bd_prod->addr.lo = cpu_to_le32(lower_32_bits(mapping));
+       sw_rx_data_prod->page_offset = replace_buf->page_offset;
+
+       rxq->sw_rx_prod++;
+
+       /* move partial skb from cons to pool (don't unmap yet)
+        * save mapping, incase we drop the packet later on.
+        */
+       tpa_info->start_buf = *sw_rx_data_cons;
+       mapping = HILO_U64(le32_to_cpu(rx_bd_cons->addr.hi),
+                          le32_to_cpu(rx_bd_cons->addr.lo));
+
+       tpa_info->start_buf_mapping = mapping;
+       rxq->sw_rx_cons++;
+
+       /* set tpa state to start only if we are able to allocate skb
+        * for this aggregation, otherwise mark as error and aggregation will
+        * be dropped
+        */
+       tpa_info->skb = netdev_alloc_skb(edev->ndev,
+                                        le16_to_cpu(cqe->len_on_first_bd));
+       if (unlikely(!tpa_info->skb)) {
+               tpa_info->agg_state = QEDE_AGG_STATE_ERROR;
+               return;
+       }
+
+       skb_put(tpa_info->skb, le16_to_cpu(cqe->len_on_first_bd));
+       memcpy(&tpa_info->start_cqe, cqe, sizeof(tpa_info->start_cqe));
+
+       /* Start filling in the aggregation info */
+       tpa_info->frag_id = 0;
+       tpa_info->agg_state = QEDE_AGG_STATE_START;
+
+       rxhash = qede_get_rxhash(edev, cqe->bitfields,
+                                cqe->rss_hash, &rxhash_type);
+       skb_set_hash(tpa_info->skb, rxhash, rxhash_type);
+       if ((le16_to_cpu(cqe->pars_flags.flags) >>
+            PARSING_AND_ERR_FLAGS_TAG8021QEXIST_SHIFT) &
+                   PARSING_AND_ERR_FLAGS_TAG8021QEXIST_MASK)
+               tpa_info->vlan_tag = le16_to_cpu(cqe->vlan_tag);
+       else
+               tpa_info->vlan_tag = 0;
+
+       /* This is needed in order to enable forwarding support */
+       qede_set_gro_params(edev, tpa_info->skb, cqe);
+
+       if (likely(cqe->ext_bd_len_list[0]))
+               qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
+                                  le16_to_cpu(cqe->ext_bd_len_list[0]));
+
+       if (unlikely(cqe->ext_bd_len_list[1])) {
+               DP_ERR(edev,
+                      "Unlikely - got a TPA aggregation with more than one ext_bd_len_list entry in the TPA start\n");
+               tpa_info->agg_state = QEDE_AGG_STATE_ERROR;
+       }
+}
+
+#ifdef CONFIG_INET
+static void qede_gro_ip_csum(struct sk_buff *skb)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       struct tcphdr *th;
+
+       skb_set_network_header(skb, 0);
+       skb_set_transport_header(skb, sizeof(struct iphdr));
+       th = tcp_hdr(skb);
+
+       th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb),
+                                 iph->saddr, iph->daddr, 0);
+
+       tcp_gro_complete(skb);
+}
+
+static void qede_gro_ipv6_csum(struct sk_buff *skb)
+{
+       struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct tcphdr *th;
+
+       skb_set_network_header(skb, 0);
+       skb_set_transport_header(skb, sizeof(struct ipv6hdr));
+       th = tcp_hdr(skb);
+
+       th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+                                 &iph->saddr, &iph->daddr, 0);
+       tcp_gro_complete(skb);
+}
+#endif
+
+static void qede_gro_receive(struct qede_dev *edev,
+                            struct qede_fastpath *fp,
+                            struct sk_buff *skb,
+                            u16 vlan_tag)
+{
+#ifdef CONFIG_INET
+       if (skb_shinfo(skb)->gso_size) {
+               switch (skb->protocol) {
+               case htons(ETH_P_IP):
+                       qede_gro_ip_csum(skb);
+                       break;
+               case htons(ETH_P_IPV6):
+                       qede_gro_ipv6_csum(skb);
+                       break;
+               default:
+                       DP_ERR(edev,
+                              "Error: FW GRO supports only IPv4/IPv6, not 0x%04x\n",
+                              ntohs(skb->protocol));
+               }
+       }
+#endif
+       skb_record_rx_queue(skb, fp->rss_id);
+       qede_skb_receive(edev, fp, skb, vlan_tag);
+}
+
+static inline void qede_tpa_cont(struct qede_dev *edev,
+                                struct qede_rx_queue *rxq,
+                                struct eth_fast_path_rx_tpa_cont_cqe *cqe)
+{
+       int i;
+
+       for (i = 0; cqe->len_list[i]; i++)
+               qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
+                                  le16_to_cpu(cqe->len_list[i]));
+
+       if (unlikely(i > 1))
+               DP_ERR(edev,
+                      "Strange - TPA cont with more than a single len_list entry\n");
+}
+
+static void qede_tpa_end(struct qede_dev *edev,
+                        struct qede_fastpath *fp,
+                        struct eth_fast_path_rx_tpa_end_cqe *cqe)
+{
+       struct qede_rx_queue *rxq = fp->rxq;
+       struct qede_agg_info *tpa_info;
+       struct sk_buff *skb;
+       int i;
+
+       tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
+       skb = tpa_info->skb;
+
+       for (i = 0; cqe->len_list[i]; i++)
+               qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
+                                  le16_to_cpu(cqe->len_list[i]));
+       if (unlikely(i > 1))
+               DP_ERR(edev,
+                      "Strange - TPA emd with more than a single len_list entry\n");
+
+       if (unlikely(tpa_info->agg_state != QEDE_AGG_STATE_START))
+               goto err;
+
+       /* Sanity */
+       if (unlikely(cqe->num_of_bds != tpa_info->frag_id + 1))
+               DP_ERR(edev,
+                      "Strange - TPA had %02x BDs, but SKB has only %d frags\n",
+                      cqe->num_of_bds, tpa_info->frag_id);
+       if (unlikely(skb->len != le16_to_cpu(cqe->total_packet_len)))
+               DP_ERR(edev,
+                      "Strange - total packet len [cqe] is %4x but SKB has len %04x\n",
+                      le16_to_cpu(cqe->total_packet_len), skb->len);
+
+       memcpy(skb->data,
+              page_address(tpa_info->start_buf.data) +
+               tpa_info->start_cqe.placement_offset +
+               tpa_info->start_buf.page_offset,
+              le16_to_cpu(tpa_info->start_cqe.len_on_first_bd));
+
+       /* Recycle [mapped] start buffer for the next replacement */
+       tpa_info->replace_buf = tpa_info->start_buf;
+       tpa_info->replace_buf_mapping = tpa_info->start_buf_mapping;
+
+       /* Finalize the SKB */
+       skb->protocol = eth_type_trans(skb, edev->ndev);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       /* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
+        * to skb_shinfo(skb)->gso_segs
+        */
+       NAPI_GRO_CB(skb)->count = le16_to_cpu(cqe->num_of_coalesced_segs);
+
+       qede_gro_receive(edev, fp, skb, tpa_info->vlan_tag);
+
+       tpa_info->agg_state = QEDE_AGG_STATE_NONE;
+
+       return;
+err:
+       /* The BD starting the aggregation is still mapped; Re-use it for
+        * future aggregations [as replacement buffer]
+        */
+       memcpy(&tpa_info->replace_buf, &tpa_info->start_buf,
+              sizeof(struct sw_rx_data));
+       tpa_info->replace_buf_mapping = tpa_info->start_buf_mapping;
+       tpa_info->start_buf.data = NULL;
+       tpa_info->agg_state = QEDE_AGG_STATE_NONE;
+       dev_kfree_skb_any(tpa_info->skb);
+       tpa_info->skb = NULL;
+}
+
 static u8 qede_check_csum(u16 flag)
 {
        u16 csum_flag = 0;
@@ -857,9 +1189,10 @@ static int qede_rx_int(struct qede_fastpath *fp, int budget)
                struct sw_rx_data *sw_rx_data;
                union eth_rx_cqe *cqe;
                struct sk_buff *skb;
+               struct page *data;
+               __le16 flags;
                u16 len, pad;
                u32 rx_hash;
-               u8 *data;
 
                /* Get the CQE from the completion ring */
                cqe = (union eth_rx_cqe *)
@@ -873,62 +1206,135 @@ static int qede_rx_int(struct qede_fastpath *fp, int budget)
                        goto next_cqe;
                }
 
+               if (cqe_type != ETH_RX_CQE_TYPE_REGULAR) {
+                       switch (cqe_type) {
+                       case ETH_RX_CQE_TYPE_TPA_START:
+                               qede_tpa_start(edev, rxq,
+                                              &cqe->fast_path_tpa_start);
+                               goto next_cqe;
+                       case ETH_RX_CQE_TYPE_TPA_CONT:
+                               qede_tpa_cont(edev, rxq,
+                                             &cqe->fast_path_tpa_cont);
+                               goto next_cqe;
+                       case ETH_RX_CQE_TYPE_TPA_END:
+                               qede_tpa_end(edev, fp,
+                                            &cqe->fast_path_tpa_end);
+                               goto next_rx_only;
+                       default:
+                               break;
+                       }
+               }
+
                /* Get the data from the SW ring */
                sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
                sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
                data = sw_rx_data->data;
 
                fp_cqe = &cqe->fast_path_regular;
-               len =  le16_to_cpu(fp_cqe->pkt_len);
+               len =  le16_to_cpu(fp_cqe->len_on_first_bd);
                pad = fp_cqe->placement_offset;
+               flags = cqe->fast_path_regular.pars_flags.flags;
 
-               /* For every Rx BD consumed, we allocate a new BD so the BD ring
-                * is always with a fixed size. If allocation fails, we take the
-                * consumed BD and return it to the ring in the PROD position.
-                * The packet that was received on that BD will be dropped (and
-                * not passed to the upper stack).
-                */
-               if (likely(qede_alloc_rx_buffer(edev, rxq) == 0)) {
-                       dma_unmap_single(&edev->pdev->dev,
-                                        dma_unmap_addr(sw_rx_data, mapping),
-                                        rxq->rx_buf_size, DMA_FROM_DEVICE);
-
-                       /* If this is an error packet then drop it */
-                       parse_flag =
-                       le16_to_cpu(cqe->fast_path_regular.pars_flags.flags);
-                       csum_flag = qede_check_csum(parse_flag);
-                       if (csum_flag == QEDE_CSUM_ERROR) {
-                               DP_NOTICE(edev,
-                                         "CQE in CONS = %u has error, flags = %x, dropping incoming packet\n",
-                                         sw_comp_cons, parse_flag);
-                               rxq->rx_hw_errors++;
-                               kfree(data);
-                               goto next_rx;
-                       }
-
-                       skb = build_skb(data, 0);
+               /* If this is an error packet then drop it */
+               parse_flag = le16_to_cpu(flags);
 
-                       if (unlikely(!skb)) {
-                               DP_NOTICE(edev,
-                                         "Build_skb failed, dropping incoming packet\n");
-                               kfree(data);
-                               rxq->rx_alloc_errors++;
-                               goto next_rx;
-                       }
-
-                       skb_reserve(skb, pad);
+               csum_flag = qede_check_csum(parse_flag);
+               if (unlikely(csum_flag == QEDE_CSUM_ERROR)) {
+                       DP_NOTICE(edev,
+                                 "CQE in CONS = %u has error, flags = %x, dropping incoming packet\n",
+                                 sw_comp_cons, parse_flag);
+                       rxq->rx_hw_errors++;
+                       qede_reuse_page(edev, rxq, sw_rx_data);
+                       goto next_rx;
+               }
 
-               } else {
+               skb = netdev_alloc_skb(edev->ndev, QEDE_RX_HDR_SIZE);
+               if (unlikely(!skb)) {
                        DP_NOTICE(edev,
-                                 "New buffer allocation failed, dropping incoming packet and reusing its buffer\n");
-                       qede_reuse_rx_data(rxq);
+                                 "Build_skb failed, dropping incoming packet\n");
+                       qede_reuse_page(edev, rxq, sw_rx_data);
                        rxq->rx_alloc_errors++;
-                       goto next_cqe;
+                       goto next_rx;
                }
 
-               sw_rx_data->data = NULL;
+               /* Copy data into SKB */
+               if (len + pad <= QEDE_RX_HDR_SIZE) {
+                       memcpy(skb_put(skb, len),
+                              page_address(data) + pad +
+                               sw_rx_data->page_offset, len);
+                       qede_reuse_page(edev, rxq, sw_rx_data);
+               } else {
+                       struct skb_frag_struct *frag;
+                       unsigned int pull_len;
+                       unsigned char *va;
+
+                       frag = &skb_shinfo(skb)->frags[0];
 
-               skb_put(skb, len);
+                       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, data,
+                                       pad + sw_rx_data->page_offset,
+                                       len, rxq->rx_buf_seg_size);
+
+                       va = skb_frag_address(frag);
+                       pull_len = eth_get_headlen(va, QEDE_RX_HDR_SIZE);
+
+                       /* Align the pull_len to optimize memcpy */
+                       memcpy(skb->data, va, ALIGN(pull_len, sizeof(long)));
+
+                       skb_frag_size_sub(frag, pull_len);
+                       frag->page_offset += pull_len;
+                       skb->data_len -= pull_len;
+                       skb->tail += pull_len;
+
+                       if (unlikely(qede_realloc_rx_buffer(edev, rxq,
+                                                           sw_rx_data))) {
+                               DP_ERR(edev, "Failed to allocate rx buffer\n");
+                               rxq->rx_alloc_errors++;
+                               goto next_cqe;
+                       }
+               }
+
+               if (fp_cqe->bd_num != 1) {
+                       u16 pkt_len = le16_to_cpu(fp_cqe->pkt_len);
+                       u8 num_frags;
+
+                       pkt_len -= len;
+
+                       for (num_frags = fp_cqe->bd_num - 1; num_frags > 0;
+                            num_frags--) {
+                               u16 cur_size = pkt_len > rxq->rx_buf_size ?
+                                               rxq->rx_buf_size : pkt_len;
+
+                               WARN_ONCE(!cur_size,
+                                         "Still got %d BDs for mapping jumbo, but length became 0\n",
+                                         num_frags);
+
+                               if (unlikely(qede_alloc_rx_buffer(edev, rxq)))
+                                       goto next_cqe;
+
+                               rxq->sw_rx_cons++;
+                               sw_rx_index = rxq->sw_rx_cons & NUM_RX_BDS_MAX;
+                               sw_rx_data = &rxq->sw_rx_ring[sw_rx_index];
+                               qed_chain_consume(&rxq->rx_bd_ring);
+                               dma_unmap_page(&edev->pdev->dev,
+                                              sw_rx_data->mapping,
+                                              PAGE_SIZE, DMA_FROM_DEVICE);
+
+                               skb_fill_page_desc(skb,
+                                                  skb_shinfo(skb)->nr_frags++,
+                                                  sw_rx_data->data, 0,
+                                                  cur_size);
+
+                               skb->truesize += PAGE_SIZE;
+                               skb->data_len += cur_size;
+                               skb->len += cur_size;
+                               pkt_len -= cur_size;
+                       }
+
+                       if (pkt_len)
+                               DP_ERR(edev,
+                                      "Mapped all BDs of jumbo, but still have %d bytes\n",
+                                      pkt_len);
+               }
 
                skb->protocol = eth_type_trans(skb, edev->ndev);
 
@@ -945,9 +1351,9 @@ static int qede_rx_int(struct qede_fastpath *fp, int budget)
                qede_skb_receive(edev, fp, skb, le16_to_cpu(fp_cqe->vlan_tag));
 
                qed_chain_consume(&rxq->rx_bd_ring);
-
 next_rx:
                rxq->sw_rx_cons++;
+next_rx_only:
                rx_pkt++;
 
 next_cqe: /* don't consume bd rx buffer */
@@ -1056,6 +1462,21 @@ static int qede_set_ucast_rx_mac(struct qede_dev *edev,
        return edev->ops->filter_config(edev->cdev, &filter_cmd);
 }
 
+static int qede_set_ucast_rx_vlan(struct qede_dev *edev,
+                                 enum qed_filter_xcast_params_type opcode,
+                                 u16 vid)
+{
+       struct qed_filter_params filter_cmd;
+
+       memset(&filter_cmd, 0, sizeof(filter_cmd));
+       filter_cmd.type = QED_FILTER_TYPE_UCAST;
+       filter_cmd.filter.ucast.type = opcode;
+       filter_cmd.filter.ucast.vlan_valid = 1;
+       filter_cmd.filter.ucast.vlan = vid;
+
+       return edev->ops->filter_config(edev->cdev, &filter_cmd);
+}
+
 void qede_fill_by_demand_stats(struct qede_dev *edev)
 {
        struct qed_eth_stats stats;
@@ -1168,6 +1589,247 @@ static struct rtnl_link_stats64 *qede_get_stats64(
        return stats;
 }
 
+static void qede_config_accept_any_vlan(struct qede_dev *edev, bool action)
+{
+       struct qed_update_vport_params params;
+       int rc;
+
+       /* Proceed only if action actually needs to be performed */
+       if (edev->accept_any_vlan == action)
+               return;
+
+       memset(&params, 0, sizeof(params));
+
+       params.vport_id = 0;
+       params.accept_any_vlan = action;
+       params.update_accept_any_vlan_flg = 1;
+
+       rc = edev->ops->vport_update(edev->cdev, &params);
+       if (rc) {
+               DP_ERR(edev, "Failed to %s accept-any-vlan\n",
+                      action ? "enable" : "disable");
+       } else {
+               DP_INFO(edev, "%s accept-any-vlan\n",
+                       action ? "enabled" : "disabled");
+               edev->accept_any_vlan = action;
+       }
+}
+
+static int qede_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qede_vlan *vlan, *tmp;
+       int rc;
+
+       DP_VERBOSE(edev, NETIF_MSG_IFUP, "Adding vlan 0x%04x\n", vid);
+
+       vlan = kzalloc(sizeof(*vlan), GFP_KERNEL);
+       if (!vlan) {
+               DP_INFO(edev, "Failed to allocate struct for vlan\n");
+               return -ENOMEM;
+       }
+       INIT_LIST_HEAD(&vlan->list);
+       vlan->vid = vid;
+       vlan->configured = false;
+
+       /* Verify vlan isn't already configured */
+       list_for_each_entry(tmp, &edev->vlan_list, list) {
+               if (tmp->vid == vlan->vid) {
+                       DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                                  "vlan already configured\n");
+                       kfree(vlan);
+                       return -EEXIST;
+               }
+       }
+
+       /* If interface is down, cache this VLAN ID and return */
+       if (edev->state != QEDE_STATE_OPEN) {
+               DP_VERBOSE(edev, NETIF_MSG_IFDOWN,
+                          "Interface is down, VLAN %d will be configured when interface is up\n",
+                          vid);
+               if (vid != 0)
+                       edev->non_configured_vlans++;
+               list_add(&vlan->list, &edev->vlan_list);
+
+               return 0;
+       }
+
+       /* Check for the filter limit.
+        * Note - vlan0 has a reserved filter and can be added without
+        * worrying about quota
+        */
+       if ((edev->configured_vlans < edev->dev_info.num_vlan_filters) ||
+           (vlan->vid == 0)) {
+               rc = qede_set_ucast_rx_vlan(edev,
+                                           QED_FILTER_XCAST_TYPE_ADD,
+                                           vlan->vid);
+               if (rc) {
+                       DP_ERR(edev, "Failed to configure VLAN %d\n",
+                              vlan->vid);
+                       kfree(vlan);
+                       return -EINVAL;
+               }
+               vlan->configured = true;
+
+               /* vlan0 filter isn't consuming out of our quota */
+               if (vlan->vid != 0)
+                       edev->configured_vlans++;
+       } else {
+               /* Out of quota; Activate accept-any-VLAN mode */
+               if (!edev->non_configured_vlans)
+                       qede_config_accept_any_vlan(edev, true);
+
+               edev->non_configured_vlans++;
+       }
+
+       list_add(&vlan->list, &edev->vlan_list);
+
+       return 0;
+}
+
+static void qede_del_vlan_from_list(struct qede_dev *edev,
+                                   struct qede_vlan *vlan)
+{
+       /* vlan0 filter isn't consuming out of our quota */
+       if (vlan->vid != 0) {
+               if (vlan->configured)
+                       edev->configured_vlans--;
+               else
+                       edev->non_configured_vlans--;
+       }
+
+       list_del(&vlan->list);
+       kfree(vlan);
+}
+
+static int qede_configure_vlan_filters(struct qede_dev *edev)
+{
+       int rc = 0, real_rc = 0, accept_any_vlan = 0;
+       struct qed_dev_eth_info *dev_info;
+       struct qede_vlan *vlan = NULL;
+
+       if (list_empty(&edev->vlan_list))
+               return 0;
+
+       dev_info = &edev->dev_info;
+
+       /* Configure non-configured vlans */
+       list_for_each_entry(vlan, &edev->vlan_list, list) {
+               if (vlan->configured)
+                       continue;
+
+               /* We have used all our credits, now enable accept_any_vlan */
+               if ((vlan->vid != 0) &&
+                   (edev->configured_vlans == dev_info->num_vlan_filters)) {
+                       accept_any_vlan = 1;
+                       continue;
+               }
+
+               DP_VERBOSE(edev, NETIF_MSG_IFUP, "Adding vlan %d\n", vlan->vid);
+
+               rc = qede_set_ucast_rx_vlan(edev, QED_FILTER_XCAST_TYPE_ADD,
+                                           vlan->vid);
+               if (rc) {
+                       DP_ERR(edev, "Failed to configure VLAN %u\n",
+                              vlan->vid);
+                       real_rc = rc;
+                       continue;
+               }
+
+               vlan->configured = true;
+               /* vlan0 filter doesn't consume our VLAN filter's quota */
+               if (vlan->vid != 0) {
+                       edev->non_configured_vlans--;
+                       edev->configured_vlans++;
+               }
+       }
+
+       /* enable accept_any_vlan mode if we have more VLANs than credits,
+        * or remove accept_any_vlan mode if we've actually removed
+        * a non-configured vlan, and all remaining vlans are truly configured.
+        */
+
+       if (accept_any_vlan)
+               qede_config_accept_any_vlan(edev, true);
+       else if (!edev->non_configured_vlans)
+               qede_config_accept_any_vlan(edev, false);
+
+       return real_rc;
+}
+
+static int qede_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qede_vlan *vlan = NULL;
+       int rc;
+
+       DP_VERBOSE(edev, NETIF_MSG_IFDOWN, "Removing vlan 0x%04x\n", vid);
+
+       /* Find whether entry exists */
+       list_for_each_entry(vlan, &edev->vlan_list, list)
+               if (vlan->vid == vid)
+                       break;
+
+       if (!vlan || (vlan->vid != vid)) {
+               DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                          "Vlan isn't configured\n");
+               return 0;
+       }
+
+       if (edev->state != QEDE_STATE_OPEN) {
+               /* As interface is already down, we don't have a VPORT
+                * instance to remove vlan filter. So just update vlan list
+                */
+               DP_VERBOSE(edev, NETIF_MSG_IFDOWN,
+                          "Interface is down, removing VLAN from list only\n");
+               qede_del_vlan_from_list(edev, vlan);
+               return 0;
+       }
+
+       /* Remove vlan */
+       rc = qede_set_ucast_rx_vlan(edev, QED_FILTER_XCAST_TYPE_DEL, vid);
+       if (rc) {
+               DP_ERR(edev, "Failed to remove VLAN %d\n", vid);
+               return -EINVAL;
+       }
+
+       qede_del_vlan_from_list(edev, vlan);
+
+       /* We have removed a VLAN - try to see if we can
+        * configure non-configured VLAN from the list.
+        */
+       rc = qede_configure_vlan_filters(edev);
+
+       return rc;
+}
+
+static void qede_vlan_mark_nonconfigured(struct qede_dev *edev)
+{
+       struct qede_vlan *vlan = NULL;
+
+       if (list_empty(&edev->vlan_list))
+               return;
+
+       list_for_each_entry(vlan, &edev->vlan_list, list) {
+               if (!vlan->configured)
+                       continue;
+
+               vlan->configured = false;
+
+               /* vlan0 filter isn't consuming out of our quota */
+               if (vlan->vid != 0) {
+                       edev->non_configured_vlans++;
+                       edev->configured_vlans--;
+               }
+
+               DP_VERBOSE(edev, NETIF_MSG_IFDOWN,
+                          "marked vlan %d as non-configured\n",
+                          vlan->vid);
+       }
+
+       edev->accept_any_vlan = false;
+}
+
 static const struct net_device_ops qede_netdev_ops = {
        .ndo_open = qede_open,
        .ndo_stop = qede_close,
@@ -1176,6 +1838,8 @@ static const struct net_device_ops qede_netdev_ops = {
        .ndo_set_mac_address = qede_set_mac_addr,
        .ndo_validate_addr = eth_validate_addr,
        .ndo_change_mtu = qede_change_mtu,
+       .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid,
        .ndo_get_stats64 = qede_get_stats64,
 };
 
@@ -1220,6 +1884,8 @@ static struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev,
 
        edev->num_tc = edev->dev_info.num_tc;
 
+       INIT_LIST_HEAD(&edev->vlan_list);
+
        return edev;
 }
 
@@ -1251,7 +1917,7 @@ static void qede_init_ndev(struct qede_dev *edev)
                              NETIF_F_HIGHDMA;
        ndev->features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM |
                         NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HIGHDMA |
-                        NETIF_F_HW_VLAN_CTAG_TX;
+                        NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_TX;
 
        ndev->hw_features = hw_features;
 
@@ -1566,23 +2232,45 @@ static void qede_free_rx_buffers(struct qede_dev *edev,
 
        for (i = rxq->sw_rx_cons; i != rxq->sw_rx_prod; i++) {
                struct sw_rx_data *rx_buf;
-               u8 *data;
+               struct page *data;
 
                rx_buf = &rxq->sw_rx_ring[i & NUM_RX_BDS_MAX];
                data = rx_buf->data;
 
-               dma_unmap_single(&edev->pdev->dev,
-                                dma_unmap_addr(rx_buf, mapping),
-                                rxq->rx_buf_size, DMA_FROM_DEVICE);
+               dma_unmap_page(&edev->pdev->dev,
+                              rx_buf->mapping,
+                              PAGE_SIZE, DMA_FROM_DEVICE);
 
                rx_buf->data = NULL;
-               kfree(data);
+               __free_page(data);
+       }
+}
+
+static void qede_free_sge_mem(struct qede_dev *edev,
+                             struct qede_rx_queue *rxq) {
+       int i;
+
+       if (edev->gro_disable)
+               return;
+
+       for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) {
+               struct qede_agg_info *tpa_info = &rxq->tpa_info[i];
+               struct sw_rx_data *replace_buf = &tpa_info->replace_buf;
+
+               if (replace_buf) {
+                       dma_unmap_page(&edev->pdev->dev,
+                                      dma_unmap_addr(replace_buf, mapping),
+                                      PAGE_SIZE, DMA_FROM_DEVICE);
+                       __free_page(replace_buf->data);
+               }
        }
 }
 
 static void qede_free_mem_rxq(struct qede_dev *edev,
                              struct qede_rx_queue *rxq)
 {
+       qede_free_sge_mem(edev, rxq);
+
        /* Free rx buffers */
        qede_free_rx_buffers(edev, rxq);
 
@@ -1600,29 +2288,32 @@ static int qede_alloc_rx_buffer(struct qede_dev *edev,
        struct sw_rx_data *sw_rx_data;
        struct eth_rx_bd *rx_bd;
        dma_addr_t mapping;
+       struct page *data;
        u16 rx_buf_size;
-       u8 *data;
 
        rx_buf_size = rxq->rx_buf_size;
 
-       data = kmalloc(rx_buf_size, GFP_ATOMIC);
+       data = alloc_pages(GFP_ATOMIC, 0);
        if (unlikely(!data)) {
-               DP_NOTICE(edev, "Failed to allocate Rx data\n");
+               DP_NOTICE(edev, "Failed to allocate Rx data [page]\n");
                return -ENOMEM;
        }
 
-       mapping = dma_map_single(&edev->pdev->dev, data,
-                                rx_buf_size, DMA_FROM_DEVICE);
+       /* Map the entire page as it would be used
+        * for multiple RX buffer segment size mapping.
+        */
+       mapping = dma_map_page(&edev->pdev->dev, data, 0,
+                              PAGE_SIZE, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
-               kfree(data);
+               __free_page(data);
                DP_NOTICE(edev, "Failed to map Rx buffer\n");
                return -ENOMEM;
        }
 
        sw_rx_data = &rxq->sw_rx_ring[rxq->sw_rx_prod & NUM_RX_BDS_MAX];
+       sw_rx_data->page_offset = 0;
        sw_rx_data->data = data;
-
-       dma_unmap_addr_set(sw_rx_data, mapping, mapping);
+       sw_rx_data->mapping = mapping;
 
        /* Advance PROD and get BD pointer */
        rx_bd = (struct eth_rx_bd *)qed_chain_produce(&rxq->rx_bd_ring);
@@ -1635,6 +2326,53 @@ static int qede_alloc_rx_buffer(struct qede_dev *edev,
        return 0;
 }
 
+static int qede_alloc_sge_mem(struct qede_dev *edev,
+                             struct qede_rx_queue *rxq)
+{
+       dma_addr_t mapping;
+       int i;
+
+       if (edev->gro_disable)
+               return 0;
+
+       if (edev->ndev->mtu > PAGE_SIZE) {
+               edev->gro_disable = 1;
+               return 0;
+       }
+
+       for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) {
+               struct qede_agg_info *tpa_info = &rxq->tpa_info[i];
+               struct sw_rx_data *replace_buf = &tpa_info->replace_buf;
+
+               replace_buf->data = alloc_pages(GFP_ATOMIC, 0);
+               if (unlikely(!replace_buf->data)) {
+                       DP_NOTICE(edev,
+                                 "Failed to allocate TPA skb pool [replacement buffer]\n");
+                       goto err;
+               }
+
+               mapping = dma_map_page(&edev->pdev->dev, replace_buf->data, 0,
+                                      rxq->rx_buf_size, DMA_FROM_DEVICE);
+               if (unlikely(dma_mapping_error(&edev->pdev->dev, mapping))) {
+                       DP_NOTICE(edev,
+                                 "Failed to map TPA replacement buffer\n");
+                       goto err;
+               }
+
+               dma_unmap_addr_set(replace_buf, mapping, mapping);
+               tpa_info->replace_buf.page_offset = 0;
+
+               tpa_info->replace_buf_mapping = mapping;
+               tpa_info->agg_state = QEDE_AGG_STATE_NONE;
+       }
+
+       return 0;
+err:
+       qede_free_sge_mem(edev, rxq);
+       edev->gro_disable = 1;
+       return -ENOMEM;
+}
+
 /* This function allocates all memory needed per Rx queue */
 static int qede_alloc_mem_rxq(struct qede_dev *edev,
                              struct qede_rx_queue *rxq)
@@ -1643,13 +2381,16 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev,
 
        rxq->num_rx_buffers = edev->q_num_rx_buffers;
 
-       rxq->rx_buf_size = NET_IP_ALIGN +
-                          ETH_OVERHEAD +
-                          edev->ndev->mtu +
-                          QEDE_FW_RX_ALIGN_END;
+       rxq->rx_buf_size = NET_IP_ALIGN + ETH_OVERHEAD +
+                          edev->ndev->mtu;
+       if (rxq->rx_buf_size > PAGE_SIZE)
+               rxq->rx_buf_size = PAGE_SIZE;
+
+       /* Segment size to spilt a page in multiple equal parts */
+       rxq->rx_buf_seg_size = roundup_pow_of_two(rxq->rx_buf_size);
 
        /* Allocate the parallel driver ring for Rx buffers */
-       size = sizeof(*rxq->sw_rx_ring) * NUM_RX_BDS_MAX;
+       size = sizeof(*rxq->sw_rx_ring) * RX_RING_SIZE;
        rxq->sw_rx_ring = kzalloc(size, GFP_KERNEL);
        if (!rxq->sw_rx_ring) {
                DP_ERR(edev, "Rx buffers ring allocation failed\n");
@@ -1660,7 +2401,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev,
        rc = edev->ops->common->chain_alloc(edev->cdev,
                                            QED_CHAIN_USE_TO_CONSUME_PRODUCE,
                                            QED_CHAIN_MODE_NEXT_PTR,
-                                           NUM_RX_BDS_MAX,
+                                           RX_RING_SIZE,
                                            sizeof(struct eth_rx_bd),
                                            &rxq->rx_bd_ring);
 
@@ -1671,7 +2412,7 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev,
        rc = edev->ops->common->chain_alloc(edev->cdev,
                                            QED_CHAIN_USE_TO_CONSUME,
                                            QED_CHAIN_MODE_PBL,
-                                           NUM_RX_BDS_MAX,
+                                           RX_RING_SIZE,
                                            sizeof(union eth_rx_cqe),
                                            &rxq->rx_comp_ring);
        if (rc)
@@ -1693,6 +2434,8 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev,
                          num_allocated);
        }
 
+       qede_alloc_sge_mem(edev, rxq);
+
        return 0;
 
 err:
@@ -1855,6 +2598,8 @@ static void qede_init_fp(struct qede_dev *edev)
                snprintf(fp->name, sizeof(fp->name), "%s-fp-%d",
                         edev->ndev->name, rss_id);
        }
+
+       edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO);
 }
 
 static int qede_set_real_num_queues(struct qede_dev *edev)
@@ -2088,11 +2833,12 @@ static int qede_stop_queues(struct qede_dev *edev)
 static int qede_start_queues(struct qede_dev *edev)
 {
        int rc, tc, i;
-       int vport_id = 0, drop_ttl0_flg = 1, vlan_removal_en = 1;
+       int vlan_removal_en = 1;
        struct qed_dev *cdev = edev->cdev;
        struct qed_update_vport_rss_params *rss_params = &edev->rss_params;
        struct qed_update_vport_params vport_update_params;
        struct qed_queue_start_common_params q_params;
+       struct qed_start_vport_params start = {0};
 
        if (!edev->num_rss) {
                DP_ERR(edev,
@@ -2100,10 +2846,13 @@ static int qede_start_queues(struct qede_dev *edev)
                return -EINVAL;
        }
 
-       rc = edev->ops->vport_start(cdev, vport_id,
-                                   edev->ndev->mtu,
-                                   drop_ttl0_flg,
-                                   vlan_removal_en);
+       start.gro_enable = !edev->gro_disable;
+       start.mtu = edev->ndev->mtu;
+       start.vport_id = 0;
+       start.drop_ttl0 = true;
+       start.remove_inner_vlan = vlan_removal_en;
+
+       rc = edev->ops->vport_start(cdev, &start);
 
        if (rc) {
                DP_ERR(edev, "Start V-PORT failed %d\n", rc);
@@ -2112,7 +2861,7 @@ static int qede_start_queues(struct qede_dev *edev)
 
        DP_VERBOSE(edev, NETIF_MSG_IFUP,
                   "Start vport ramrod passed, vport_id = %d, MTU = %d, vlan_removal_en = %d\n",
-                  vport_id, edev->ndev->mtu + 0xe, vlan_removal_en);
+                  start.vport_id, edev->ndev->mtu + 0xe, vlan_removal_en);
 
        for_each_rss(i) {
                struct qede_fastpath *fp = &edev->fp_array[i];
@@ -2177,7 +2926,7 @@ static int qede_start_queues(struct qede_dev *edev)
 
        /* Prepare and send the vport enable */
        memset(&vport_update_params, 0, sizeof(vport_update_params));
-       vport_update_params.vport_id = vport_id;
+       vport_update_params.vport_id = start.vport_id;
        vport_update_params.update_vport_active_flg = 1;
        vport_update_params.vport_active_flg = 1;
 
@@ -2252,6 +3001,7 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode)
 
        DP_INFO(edev, "Stopped Queues\n");
 
+       qede_vlan_mark_nonconfigured(edev);
        edev->ops->fastpath_stop(edev->cdev);
 
        /* Release the interrupts */
@@ -2320,6 +3070,9 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode)
        edev->state = QEDE_STATE_OPEN;
        mutex_unlock(&edev->qede_lock);
 
+       /* Program un-configured VLANs */
+       qede_configure_vlan_filters(edev);
+
        /* Ask for link-up using current configuration */
        memset(&link_params, 0, sizeof(link_params));
        link_params.link_up = true;
@@ -2398,13 +3151,17 @@ static void qede_link_update(void *dev, struct qed_link_output *link)
        }
 
        if (link->link_up) {
-               DP_NOTICE(edev, "Link is up\n");
-               netif_tx_start_all_queues(edev->ndev);
-               netif_carrier_on(edev->ndev);
+               if (!netif_carrier_ok(edev->ndev)) {
+                       DP_NOTICE(edev, "Link is up\n");
+                       netif_tx_start_all_queues(edev->ndev);
+                       netif_carrier_on(edev->ndev);
+               }
        } else {
-               DP_NOTICE(edev, "Link is down\n");
-               netif_tx_disable(edev->ndev);
-               netif_carrier_off(edev->ndev);
+               if (netif_carrier_ok(edev->ndev)) {
+                       DP_NOTICE(edev, "Link is down\n");
+                       netif_tx_disable(edev->ndev);
+                       netif_carrier_off(edev->ndev);
+               }
        }
 }
 
@@ -2580,6 +3337,17 @@ static void qede_config_rx_mode(struct net_device *ndev)
                        goto out;
        }
 
+       /* take care of VLAN mode */
+       if (ndev->flags & IFF_PROMISC) {
+               qede_config_accept_any_vlan(edev, true);
+       } else if (!edev->non_configured_vlans) {
+               /* It's possible that accept_any_vlan mode is set due to a
+                * previous setting of IFF_PROMISC. If vlan credits are
+                * sufficient, disable accept_any_vlan.
+                */
+               qede_config_accept_any_vlan(edev, false);
+       }
+
        rx_mode.filter.accept_flags = accept_flags;
        edev->ops->filter_config(edev->cdev, &rx_mode);
 out:
index 46bbea8e023c0194e408ec9e269456c9456136e2..55007f1e6bbcc77981414e9db1e73d8db8502988 100644 (file)
@@ -566,6 +566,7 @@ struct qlcnic_adapter_stats {
        u64  tx_dma_map_error;
        u64  spurious_intr;
        u64  mac_filter_limit_overrun;
+       u64  mbx_spurious_intr;
 };
 
 /*
@@ -1099,7 +1100,7 @@ struct qlcnic_mailbox {
        unsigned long           status;
        spinlock_t              queue_lock;     /* Mailbox queue lock */
        spinlock_t              aen_lock;       /* Mailbox response/AEN lock */
-       atomic_t                rsp_status;
+       u32                     rsp_status;
        u32                     num_cmds;
 };
 
index 37a731be7d399f6ae14d5c0e1f889599f9fd2d5d..f9640d5ce6baa774d1f980a2c6eb652fc301eab8 100644 (file)
@@ -491,7 +491,7 @@ irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *adapter)
 
 static inline void qlcnic_83xx_notify_mbx_response(struct qlcnic_mailbox *mbx)
 {
-       atomic_set(&mbx->rsp_status, QLC_83XX_MBX_RESPONSE_ARRIVED);
+       mbx->rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        complete(&mbx->completion);
 }
 
@@ -510,7 +510,7 @@ static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
        if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
        } else {
-               if (atomic_read(&mbx->rsp_status) != rsp_status)
+               if (mbx->rsp_status != rsp_status)
                        qlcnic_83xx_notify_mbx_response(mbx);
        }
 out:
@@ -1023,7 +1023,7 @@ static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
                if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                        __qlcnic_83xx_process_aen(adapter);
                } else {
-                       if (atomic_read(&mbx->rsp_status) != rsp_status)
+                       if (mbx->rsp_status != rsp_status)
                                qlcnic_83xx_notify_mbx_response(mbx);
                }
        }
@@ -2338,9 +2338,9 @@ static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
 
 static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
 {
+       u32 mask, resp, event, rsp_status = QLC_83XX_MBX_RESPONSE_ARRIVED;
        struct qlcnic_adapter *adapter = data;
        struct qlcnic_mailbox *mbx;
-       u32 mask, resp, event;
        unsigned long flags;
 
        mbx = adapter->ahw->mailbox;
@@ -2350,10 +2350,14 @@ static irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
                goto out;
 
        event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
-       if (event &  QLCNIC_MBX_ASYNC_EVENT)
+       if (event &  QLCNIC_MBX_ASYNC_EVENT) {
                __qlcnic_83xx_process_aen(adapter);
-       else
-               qlcnic_83xx_notify_mbx_response(mbx);
+       } else {
+               if (mbx->rsp_status != rsp_status)
+                       qlcnic_83xx_notify_mbx_response(mbx);
+               else
+                       adapter->stats.mbx_spurious_intr++;
+       }
 
 out:
        mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
@@ -4050,10 +4054,10 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
        struct qlcnic_adapter *adapter = mbx->adapter;
        const struct qlcnic_mbx_ops *mbx_ops = mbx->ops;
        struct device *dev = &adapter->pdev->dev;
-       atomic_t *rsp_status = &mbx->rsp_status;
        struct list_head *head = &mbx->cmd_q;
        struct qlcnic_hardware_context *ahw;
        struct qlcnic_cmd_args *cmd = NULL;
+       unsigned long flags;
 
        ahw = adapter->ahw;
 
@@ -4063,7 +4067,9 @@ static void qlcnic_83xx_mailbox_worker(struct work_struct *work)
                        return;
                }
 
-               atomic_set(rsp_status, QLC_83XX_MBX_RESPONSE_WAIT);
+               spin_lock_irqsave(&mbx->aen_lock, flags);
+               mbx->rsp_status = QLC_83XX_MBX_RESPONSE_WAIT;
+               spin_unlock_irqrestore(&mbx->aen_lock, flags);
 
                spin_lock(&mbx->queue_lock);
 
index 494e8105adee7834341353ddc81cf65a70a33b9c..0a2318cad34d74a6000f710a375848b1c3f54f45 100644 (file)
@@ -59,7 +59,8 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
         QLC_OFF(stats.mac_filter_limit_overrun)},
        {"spurious intr", QLC_SIZEOF(stats.spurious_intr),
         QLC_OFF(stats.spurious_intr)},
-
+       {"mbx spurious intr", QLC_SIZEOF(stats.mbx_spurious_intr),
+        QLC_OFF(stats.mbx_spurious_intr)},
 };
 
 static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
index 689a4a5c8dcfc30fba2675e17293e98691648dd2..1ef03939d25f478356112fbe376ff79cfd1e8eaa 100644 (file)
@@ -811,7 +811,7 @@ qcaspi_netdev_setup(struct net_device *dev)
        dev->netdev_ops = &qcaspi_netdev_ops;
        qcaspi_set_ethtool_ops(dev);
        dev->watchdog_timeo = QCASPI_TX_TIMEOUT;
-       dev->flags = IFF_MULTICAST;
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->tx_queue_len = 100;
 
        qca = netdev_priv(dev);
index 17d5571d04322f1fd88adde8592e3f6ee1d80e69..94f08f1e841ce98bd29e2c7694035d5a2c11143c 100644 (file)
@@ -1999,7 +1999,8 @@ static int rtl8169_set_speed(struct net_device *dev,
                goto out;
 
        if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
-           (advertising & ADVERTISED_1000baseT_Full)) {
+           (advertising & ADVERTISED_1000baseT_Full) &&
+           !pci_is_pcie(tp->pci_dev)) {
                mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
        }
 out:
@@ -4933,8 +4934,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
                RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
                break;
        case RTL_GIGA_MAC_VER_40:
-               RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
-               break;
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
@@ -4943,8 +4942,6 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_46:
        case RTL_GIGA_MAC_VER_47:
        case RTL_GIGA_MAC_VER_48:
-               RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
-               break;
        case RTL_GIGA_MAC_VER_49:
        case RTL_GIGA_MAC_VER_50:
        case RTL_GIGA_MAC_VER_51:
@@ -6137,28 +6134,28 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
                sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
                sw_cnt_1ms_ini &= 0x0fff;
                data = r8168_mac_ocp_read(tp, 0xd412);
-               data &= 0x0fff;
+               data &= ~0x0fff;
                data |= sw_cnt_1ms_ini;
                r8168_mac_ocp_write(tp, 0xd412, data);
        }
 
        data = r8168_mac_ocp_read(tp, 0xe056);
-       data &= 0xf0;
-       data |= 0x07;
+       data &= ~0xf0;
+       data |= 0x70;
        r8168_mac_ocp_write(tp, 0xe056, data);
 
        data = r8168_mac_ocp_read(tp, 0xe052);
-       data &= 0x8008;
-       data |= 0x6000;
+       data &= ~0x6000;
+       data |= 0x8008;
        r8168_mac_ocp_write(tp, 0xe052, data);
 
        data = r8168_mac_ocp_read(tp, 0xe0d6);
-       data &= 0x01ff;
+       data &= ~0x01ff;
        data |= 0x017f;
        r8168_mac_ocp_write(tp, 0xe0d6, data);
 
        data = r8168_mac_ocp_read(tp, 0xd420);
-       data &= 0x0fff;
+       data &= ~0x0fff;
        data |= 0x047f;
        r8168_mac_ocp_write(tp, 0xd420, data);
 
@@ -7730,10 +7727,13 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
        struct rtl8169_counters *counters = tp->counters;
        unsigned int start;
 
-       if (netif_running(dev))
+       pm_runtime_get_noresume(&pdev->dev);
+
+       if (netif_running(dev) && pm_runtime_active(&pdev->dev))
                rtl8169_rx_missed(dev, ioaddr);
 
        do {
@@ -7761,7 +7761,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
         * Fetch additonal counter values missing in stats collected by driver
         * from tally counters.
         */
-       rtl8169_update_counters(dev);
+       if (pm_runtime_active(&pdev->dev))
+               rtl8169_update_counters(dev);
 
        /*
         * Subtract values fetched during initalization.
@@ -7774,6 +7775,8 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) -
                le16_to_cpu(tp->tc_offset.tx_aborted);
 
+       pm_runtime_put_noidle(&pdev->dev);
+
        return stats;
 }
 
@@ -7853,6 +7856,10 @@ static int rtl8169_runtime_suspend(struct device *device)
 
        rtl8169_net_suspend(dev);
 
+       /* Update counters before going runtime suspend */
+       rtl8169_rx_missed(dev, tp->mmio_addr);
+       rtl8169_update_counters(dev);
+
        return 0;
 }
 
index 270c4c9cac7f01e1afce24f499559ac9d021d15c..4f132cf177cdaa4d5e45868be6318dd284dc745a 100644 (file)
@@ -18,7 +18,7 @@ if NET_VENDOR_RENESAS
 config SH_ETH
        tristate "Renesas SuperH Ethernet support"
        depends on HAS_DMA
-       depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
+       depends on ARCH_RENESAS || SUPERH || COMPILE_TEST
        select CRC32
        select MII
        select MDIO_BITBANG
@@ -32,7 +32,7 @@ config SH_ETH
 config RAVB
        tristate "Renesas Ethernet AVB support"
        depends on HAS_DMA
-       depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on ARCH_RENESAS || COMPILE_TEST
        select CRC32
        select MII
        select MDIO_BITBANG
index c936682aae68df0808eb68c63c25b42b0e3b4dca..8f2c4fb4c7246d6cae26e09c33a31c0573c85b00 100644 (file)
@@ -92,8 +92,6 @@ static void ravb_set_rate(struct net_device *ndev)
        case 1000:              /* 1000BASE */
                ravb_write(ndev, GECMR_SPEED_1000, GECMR);
                break;
-       default:
-               break;
        }
 }
 
@@ -1132,7 +1130,8 @@ static int ravb_set_ringparam(struct net_device *ndev,
        if (netif_running(ndev)) {
                netif_device_detach(ndev);
                /* Stop PTP Clock driver */
-               ravb_ptp_stop(ndev);
+               if (priv->chip_id == RCAR_GEN2)
+                       ravb_ptp_stop(ndev);
                /* Wait for DMA stopping */
                error = ravb_stop_dma(ndev);
                if (error) {
@@ -1163,7 +1162,8 @@ static int ravb_set_ringparam(struct net_device *ndev,
                ravb_emac_init(ndev);
 
                /* Initialise PTP Clock driver */
-               ravb_ptp_init(ndev, priv->pdev);
+               if (priv->chip_id == RCAR_GEN2)
+                       ravb_ptp_init(ndev, priv->pdev);
 
                netif_device_attach(ndev);
        }
@@ -1291,7 +1291,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)
        netif_tx_stop_all_queues(ndev);
 
        /* Stop PTP Clock driver */
-       ravb_ptp_stop(ndev);
+       if (priv->chip_id == RCAR_GEN2)
+               ravb_ptp_stop(ndev);
 
        /* Wait for DMA stopping */
        ravb_stop_dma(ndev);
@@ -1304,7 +1305,8 @@ static void ravb_tx_timeout_work(struct work_struct *work)
        ravb_emac_init(ndev);
 
        /* Initialise PTP Clock driver */
-       ravb_ptp_init(ndev, priv->pdev);
+       if (priv->chip_id == RCAR_GEN2)
+               ravb_ptp_init(ndev, priv->pdev);
 
        netif_tx_start_all_queues(ndev);
 }
@@ -1706,7 +1708,6 @@ static int ravb_set_gti(struct net_device *ndev)
 static int ravb_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
-       const struct of_device_id *match;
        struct ravb_private *priv;
        enum ravb_chip_id chip_id;
        struct net_device *ndev;
@@ -1738,8 +1739,7 @@ static int ravb_probe(struct platform_device *pdev)
        ndev->base_addr = res->start;
        ndev->dma = -1;
 
-       match = of_match_device(of_match_ptr(ravb_match_table), &pdev->dev);
-       chip_id = (enum ravb_chip_id)match->data;
+       chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev);
 
        if (chip_id == RCAR_GEN3)
                irq = platform_get_irq_byname(pdev, "ch22");
@@ -1800,10 +1800,6 @@ static int ravb_probe(struct platform_device *pdev)
                            CCC_GAC | CCC_CSEL_HPB);
        }
 
-       /* Set CSEL value */
-       ravb_write(ndev, (ravb_read(ndev, CCC) & ~CCC_CSEL) | CCC_CSEL_HPB,
-                  CCC);
-
        /* Set GTI value */
        error = ravb_set_gti(ndev);
        if (error)
index 0a150b2289146fe6c996b4ad338b9d6b45f56803..2e9a781640549717eae01701bc20361fb85eb551 100644 (file)
@@ -500,8 +500,6 @@ static void sh_eth_set_rate_gether(struct net_device *ndev)
        case 1000: /* 1000BASE */
                sh_eth_write(ndev, GECMR_1000, GECMR);
                break;
-       default:
-               break;
        }
 }
 
@@ -592,8 +590,6 @@ static void sh_eth_set_rate_r8a777x(struct net_device *ndev)
        case 100:/* 100BASE */
                sh_eth_modify(ndev, ECMR, ECMR_ELB, ECMR_ELB);
                break;
-       default:
-               break;
        }
 }
 
@@ -658,8 +654,6 @@ static void sh_eth_set_rate_sh7724(struct net_device *ndev)
        case 100:/* 100BASE */
                sh_eth_modify(ndev, ECMR, ECMR_RTM, ECMR_RTM);
                break;
-       default:
-               break;
        }
 }
 
@@ -698,8 +692,6 @@ static void sh_eth_set_rate_sh7757(struct net_device *ndev)
        case 100:/* 100BASE */
                sh_eth_write(ndev, 1, RTRATE);
                break;
-       default:
-               break;
        }
 }
 
@@ -767,8 +759,6 @@ static void sh_eth_set_rate_giga(struct net_device *ndev)
        case 1000: /* 1000BASE */
                sh_eth_write(ndev, 0x00000020, GECMR);
                break;
-       default:
-               break;
        }
 }
 
@@ -1137,11 +1127,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
                        break;
                sh_eth_set_receive_align(skb);
 
-               /* RX descriptor */
-               rxdesc = &mdp->rx_ring[i];
                /* The size of the buffer is a multiple of 32 bytes. */
                buf_len = ALIGN(mdp->rx_buf_sz, 32);
-               rxdesc->len = cpu_to_le32(buf_len << 16);
                dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
                                          DMA_FROM_DEVICE);
                if (dma_mapping_error(&ndev->dev, dma_addr)) {
@@ -1149,6 +1136,10 @@ static void sh_eth_ring_format(struct net_device *ndev)
                        break;
                }
                mdp->rx_skbuff[i] = skb;
+
+               /* RX descriptor */
+               rxdesc = &mdp->rx_ring[i];
+               rxdesc->len = cpu_to_le32(buf_len << 16);
                rxdesc->addr = cpu_to_le32(dma_addr);
                rxdesc->status = cpu_to_le32(RD_RACT | RD_RFP);
 
@@ -1164,7 +1155,8 @@ static void sh_eth_ring_format(struct net_device *ndev)
        mdp->dirty_rx = (u32) (i - mdp->num_rx_ring);
 
        /* Mark the last entry as wrapping the ring. */
-       rxdesc->status |= cpu_to_le32(RD_RDLE);
+       if (rxdesc)
+               rxdesc->status |= cpu_to_le32(RD_RDLE);
 
        memset(mdp->tx_ring, 0, tx_ringsize);
 
@@ -2917,8 +2909,6 @@ static const u16 *sh_eth_get_register_offset(int register_type)
        case SH_ETH_REG_FAST_SH3_SH2:
                reg_offset = sh_eth_offset_fast_sh3_sh2;
                break;
-       default:
-               break;
        }
 
        return reg_offset;
@@ -3056,15 +3046,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        mdp->ether_link_active_low = pd->ether_link_active_low;
 
        /* set cpu data */
-       if (id) {
+       if (id)
                mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
-       } else  {
-               const struct of_device_id *match;
+       else
+               mdp->cd = (struct sh_eth_cpu_data *)of_device_get_match_data(&pdev->dev);
 
-               match = of_match_device(of_match_ptr(sh_eth_match_table),
-                                       &pdev->dev);
-               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",
index f85fb12f36f1fc87d0ef776131b9096fc75a8e8f..faa36acee2231ed25f8a0d13365b49559d476c1b 100644 (file)
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_ROCKER) += rocker.o
+rocker-y := rocker_main.o rocker_tlv.o rocker_ofdpa.o
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
deleted file mode 100644 (file)
index 166a7fc..0000000
+++ /dev/null
@@ -1,5495 +0,0 @@
-/*
- * drivers/net/ethernet/rocker/rocker.c - Rocker switch device driver
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
- * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/hashtable.h>
-#include <linux/crc32.h>
-#include <linux/sort.h>
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/skbuff.h>
-#include <linux/socket.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/if_ether.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-#include <linux/bitops.h>
-#include <linux/ctype.h>
-#include <net/switchdev.h>
-#include <net/rtnetlink.h>
-#include <net/ip_fib.h>
-#include <net/netevent.h>
-#include <net/arp.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <generated/utsrelease.h>
-
-#include "rocker.h"
-
-static const char rocker_driver_name[] = "rocker";
-
-static const struct pci_device_id rocker_pci_id_table[] = {
-       {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_ROCKER), 0},
-       {0, }
-};
-
-struct rocker_flow_tbl_key {
-       u32 priority;
-       enum rocker_of_dpa_table_id tbl_id;
-       union {
-               struct {
-                       u32 in_pport;
-                       u32 in_pport_mask;
-                       enum rocker_of_dpa_table_id goto_tbl;
-               } ig_port;
-               struct {
-                       u32 in_pport;
-                       __be16 vlan_id;
-                       __be16 vlan_id_mask;
-                       enum rocker_of_dpa_table_id goto_tbl;
-                       bool untagged;
-                       __be16 new_vlan_id;
-               } vlan;
-               struct {
-                       u32 in_pport;
-                       u32 in_pport_mask;
-                       __be16 eth_type;
-                       u8 eth_dst[ETH_ALEN];
-                       u8 eth_dst_mask[ETH_ALEN];
-                       __be16 vlan_id;
-                       __be16 vlan_id_mask;
-                       enum rocker_of_dpa_table_id goto_tbl;
-                       bool copy_to_cpu;
-               } term_mac;
-               struct {
-                       __be16 eth_type;
-                       __be32 dst4;
-                       __be32 dst4_mask;
-                       enum rocker_of_dpa_table_id goto_tbl;
-                       u32 group_id;
-               } ucast_routing;
-               struct {
-                       u8 eth_dst[ETH_ALEN];
-                       u8 eth_dst_mask[ETH_ALEN];
-                       int has_eth_dst;
-                       int has_eth_dst_mask;
-                       __be16 vlan_id;
-                       u32 tunnel_id;
-                       enum rocker_of_dpa_table_id goto_tbl;
-                       u32 group_id;
-                       bool copy_to_cpu;
-               } bridge;
-               struct {
-                       u32 in_pport;
-                       u32 in_pport_mask;
-                       u8 eth_src[ETH_ALEN];
-                       u8 eth_src_mask[ETH_ALEN];
-                       u8 eth_dst[ETH_ALEN];
-                       u8 eth_dst_mask[ETH_ALEN];
-                       __be16 eth_type;
-                       __be16 vlan_id;
-                       __be16 vlan_id_mask;
-                       u8 ip_proto;
-                       u8 ip_proto_mask;
-                       u8 ip_tos;
-                       u8 ip_tos_mask;
-                       u32 group_id;
-               } acl;
-       };
-};
-
-struct rocker_flow_tbl_entry {
-       struct hlist_node entry;
-       u32 cmd;
-       u64 cookie;
-       struct rocker_flow_tbl_key key;
-       size_t key_len;
-       u32 key_crc32; /* key */
-};
-
-struct rocker_group_tbl_entry {
-       struct hlist_node entry;
-       u32 cmd;
-       u32 group_id; /* key */
-       u16 group_count;
-       u32 *group_ids;
-       union {
-               struct {
-                       u8 pop_vlan;
-               } l2_interface;
-               struct {
-                       u8 eth_src[ETH_ALEN];
-                       u8 eth_dst[ETH_ALEN];
-                       __be16 vlan_id;
-                       u32 group_id;
-               } l2_rewrite;
-               struct {
-                       u8 eth_src[ETH_ALEN];
-                       u8 eth_dst[ETH_ALEN];
-                       __be16 vlan_id;
-                       bool ttl_check;
-                       u32 group_id;
-               } l3_unicast;
-       };
-};
-
-struct rocker_fdb_tbl_entry {
-       struct hlist_node entry;
-       u32 key_crc32; /* key */
-       bool learned;
-       unsigned long touched;
-       struct rocker_fdb_tbl_key {
-               struct rocker_port *rocker_port;
-               u8 addr[ETH_ALEN];
-               __be16 vlan_id;
-       } key;
-};
-
-struct rocker_internal_vlan_tbl_entry {
-       struct hlist_node entry;
-       int ifindex; /* key */
-       u32 ref_count;
-       __be16 vlan_id;
-};
-
-struct rocker_neigh_tbl_entry {
-       struct hlist_node entry;
-       __be32 ip_addr; /* key */
-       struct net_device *dev;
-       u32 ref_count;
-       u32 index;
-       u8 eth_dst[ETH_ALEN];
-       bool ttl_check;
-};
-
-struct rocker_desc_info {
-       char *data; /* mapped */
-       size_t data_size;
-       size_t tlv_size;
-       struct rocker_desc *desc;
-       dma_addr_t mapaddr;
-};
-
-struct rocker_dma_ring_info {
-       size_t size;
-       u32 head;
-       u32 tail;
-       struct rocker_desc *desc; /* mapped */
-       dma_addr_t mapaddr;
-       struct rocker_desc_info *desc_info;
-       unsigned int type;
-};
-
-struct rocker;
-
-enum {
-       ROCKER_CTRL_LINK_LOCAL_MCAST,
-       ROCKER_CTRL_LOCAL_ARP,
-       ROCKER_CTRL_IPV4_MCAST,
-       ROCKER_CTRL_IPV6_MCAST,
-       ROCKER_CTRL_DFLT_BRIDGING,
-       ROCKER_CTRL_DFLT_OVS,
-       ROCKER_CTRL_MAX,
-};
-
-#define ROCKER_INTERNAL_VLAN_ID_BASE   0x0f00
-#define ROCKER_N_INTERNAL_VLANS                255
-#define ROCKER_VLAN_BITMAP_LEN         BITS_TO_LONGS(VLAN_N_VID)
-#define ROCKER_INTERNAL_VLAN_BITMAP_LEN        BITS_TO_LONGS(ROCKER_N_INTERNAL_VLANS)
-
-struct rocker_port {
-       struct net_device *dev;
-       struct net_device *bridge_dev;
-       struct rocker *rocker;
-       unsigned int port_number;
-       u32 pport;
-       __be16 internal_vlan_id;
-       int stp_state;
-       u32 brport_flags;
-       unsigned long ageing_time;
-       bool ctrls[ROCKER_CTRL_MAX];
-       unsigned long vlan_bitmap[ROCKER_VLAN_BITMAP_LEN];
-       struct napi_struct napi_tx;
-       struct napi_struct napi_rx;
-       struct rocker_dma_ring_info tx_ring;
-       struct rocker_dma_ring_info rx_ring;
-};
-
-struct rocker {
-       struct pci_dev *pdev;
-       u8 __iomem *hw_addr;
-       struct msix_entry *msix_entries;
-       unsigned int port_count;
-       struct rocker_port **ports;
-       struct {
-               u64 id;
-       } hw;
-       spinlock_t cmd_ring_lock;               /* for cmd ring accesses */
-       struct rocker_dma_ring_info cmd_ring;
-       struct rocker_dma_ring_info event_ring;
-       DECLARE_HASHTABLE(flow_tbl, 16);
-       spinlock_t flow_tbl_lock;               /* for flow tbl accesses */
-       u64 flow_tbl_next_cookie;
-       DECLARE_HASHTABLE(group_tbl, 16);
-       spinlock_t group_tbl_lock;              /* for group tbl accesses */
-       struct timer_list fdb_cleanup_timer;
-       DECLARE_HASHTABLE(fdb_tbl, 16);
-       spinlock_t fdb_tbl_lock;                /* for fdb tbl accesses */
-       unsigned long internal_vlan_bitmap[ROCKER_INTERNAL_VLAN_BITMAP_LEN];
-       DECLARE_HASHTABLE(internal_vlan_tbl, 8);
-       spinlock_t internal_vlan_tbl_lock;      /* for vlan tbl accesses */
-       DECLARE_HASHTABLE(neigh_tbl, 16);
-       spinlock_t neigh_tbl_lock;              /* for neigh tbl accesses */
-       u32 neigh_tbl_next_index;
-};
-
-static const u8 zero_mac[ETH_ALEN]   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static const u8 ff_mac[ETH_ALEN]     = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-static const u8 ll_mac[ETH_ALEN]     = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-static const u8 ll_mask[ETH_ALEN]    = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
-static const u8 mcast_mac[ETH_ALEN]  = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
-static const u8 ipv4_mcast[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
-static const u8 ipv4_mask[ETH_ALEN]  = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 };
-static const u8 ipv6_mcast[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
-static const u8 ipv6_mask[ETH_ALEN]  = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
-/* Rocker priority levels for flow table entries.  Higher
- * priority match takes precedence over lower priority match.
- */
-
-enum {
-       ROCKER_PRIORITY_UNKNOWN = 0,
-       ROCKER_PRIORITY_IG_PORT = 1,
-       ROCKER_PRIORITY_VLAN = 1,
-       ROCKER_PRIORITY_TERM_MAC_UCAST = 0,
-       ROCKER_PRIORITY_TERM_MAC_MCAST = 1,
-       ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_EXACT = 1,
-       ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_WILD = 2,
-       ROCKER_PRIORITY_BRIDGING_VLAN = 3,
-       ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_EXACT = 1,
-       ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_WILD = 2,
-       ROCKER_PRIORITY_BRIDGING_TENANT = 3,
-       ROCKER_PRIORITY_ACL_CTRL = 3,
-       ROCKER_PRIORITY_ACL_NORMAL = 2,
-       ROCKER_PRIORITY_ACL_DFLT = 1,
-};
-
-static bool rocker_vlan_id_is_internal(__be16 vlan_id)
-{
-       u16 start = ROCKER_INTERNAL_VLAN_ID_BASE;
-       u16 end = 0xffe;
-       u16 _vlan_id = ntohs(vlan_id);
-
-       return (_vlan_id >= start && _vlan_id <= end);
-}
-
-static __be16 rocker_port_vid_to_vlan(const struct rocker_port *rocker_port,
-                                     u16 vid, bool *pop_vlan)
-{
-       __be16 vlan_id;
-
-       if (pop_vlan)
-               *pop_vlan = false;
-       vlan_id = htons(vid);
-       if (!vlan_id) {
-               vlan_id = rocker_port->internal_vlan_id;
-               if (pop_vlan)
-                       *pop_vlan = true;
-       }
-
-       return vlan_id;
-}
-
-static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port,
-                                  __be16 vlan_id)
-{
-       if (rocker_vlan_id_is_internal(vlan_id))
-               return 0;
-
-       return ntohs(vlan_id);
-}
-
-static bool rocker_port_is_bridged(const struct rocker_port *rocker_port)
-{
-       return rocker_port->bridge_dev &&
-              netif_is_bridge_master(rocker_port->bridge_dev);
-}
-
-static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port)
-{
-       return rocker_port->bridge_dev &&
-              netif_is_ovs_master(rocker_port->bridge_dev);
-}
-
-#define ROCKER_OP_FLAG_REMOVE          BIT(0)
-#define ROCKER_OP_FLAG_NOWAIT          BIT(1)
-#define ROCKER_OP_FLAG_LEARNED         BIT(2)
-#define ROCKER_OP_FLAG_REFRESH         BIT(3)
-
-static void *__rocker_port_mem_alloc(struct rocker_port *rocker_port,
-                                    struct switchdev_trans *trans, int flags,
-                                    size_t size)
-{
-       struct switchdev_trans_item *elem = NULL;
-       gfp_t gfp_flags = (flags & ROCKER_OP_FLAG_NOWAIT) ?
-                         GFP_ATOMIC : GFP_KERNEL;
-
-       /* If in transaction prepare phase, allocate the memory
-        * and enqueue it on a transaction.  If in transaction
-        * commit phase, dequeue the memory from the transaction
-        * rather than re-allocating the memory.  The idea is the
-        * driver code paths for prepare and commit are identical
-        * so the memory allocated in the prepare phase is the
-        * memory used in the commit phase.
-        */
-
-       if (!trans) {
-               elem = kzalloc(size + sizeof(*elem), gfp_flags);
-       } else if (switchdev_trans_ph_prepare(trans)) {
-               elem = kzalloc(size + sizeof(*elem), gfp_flags);
-               if (!elem)
-                       return NULL;
-               switchdev_trans_item_enqueue(trans, elem, kfree, elem);
-       } else {
-               elem = switchdev_trans_item_dequeue(trans);
-       }
-
-       return elem ? elem + 1 : NULL;
-}
-
-static void *rocker_port_kzalloc(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags,
-                                size_t size)
-{
-       return __rocker_port_mem_alloc(rocker_port, trans, flags, size);
-}
-
-static void *rocker_port_kcalloc(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags,
-                                size_t n, size_t size)
-{
-       return __rocker_port_mem_alloc(rocker_port, trans, flags, n * size);
-}
-
-static void rocker_port_kfree(struct switchdev_trans *trans, const void *mem)
-{
-       struct switchdev_trans_item *elem;
-
-       /* Frees are ignored if in transaction prepare phase.  The
-        * memory remains on the per-port list until freed in the
-        * commit phase.
-        */
-
-       if (switchdev_trans_ph_prepare(trans))
-               return;
-
-       elem = (struct switchdev_trans_item *) mem - 1;
-       kfree(elem);
-}
-
-struct rocker_wait {
-       wait_queue_head_t wait;
-       bool done;
-       bool nowait;
-};
-
-static void rocker_wait_reset(struct rocker_wait *wait)
-{
-       wait->done = false;
-       wait->nowait = false;
-}
-
-static void rocker_wait_init(struct rocker_wait *wait)
-{
-       init_waitqueue_head(&wait->wait);
-       rocker_wait_reset(wait);
-}
-
-static struct rocker_wait *rocker_wait_create(struct rocker_port *rocker_port,
-                                             struct switchdev_trans *trans,
-                                             int flags)
-{
-       struct rocker_wait *wait;
-
-       wait = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*wait));
-       if (!wait)
-               return NULL;
-       rocker_wait_init(wait);
-       return wait;
-}
-
-static void rocker_wait_destroy(struct switchdev_trans *trans,
-                               struct rocker_wait *wait)
-{
-       rocker_port_kfree(trans, wait);
-}
-
-static bool rocker_wait_event_timeout(struct rocker_wait *wait,
-                                     unsigned long timeout)
-{
-       wait_event_timeout(wait->wait, wait->done, HZ / 10);
-       if (!wait->done)
-               return false;
-       return true;
-}
-
-static void rocker_wait_wake_up(struct rocker_wait *wait)
-{
-       wait->done = true;
-       wake_up(&wait->wait);
-}
-
-static u32 rocker_msix_vector(const struct rocker *rocker, unsigned int vector)
-{
-       return rocker->msix_entries[vector].vector;
-}
-
-static u32 rocker_msix_tx_vector(const struct rocker_port *rocker_port)
-{
-       return rocker_msix_vector(rocker_port->rocker,
-                                 ROCKER_MSIX_VEC_TX(rocker_port->port_number));
-}
-
-static u32 rocker_msix_rx_vector(const struct rocker_port *rocker_port)
-{
-       return rocker_msix_vector(rocker_port->rocker,
-                                 ROCKER_MSIX_VEC_RX(rocker_port->port_number));
-}
-
-#define rocker_write32(rocker, reg, val)       \
-       writel((val), (rocker)->hw_addr + (ROCKER_ ## reg))
-#define rocker_read32(rocker, reg)     \
-       readl((rocker)->hw_addr + (ROCKER_ ## reg))
-#define rocker_write64(rocker, reg, val)       \
-       writeq((val), (rocker)->hw_addr + (ROCKER_ ## reg))
-#define rocker_read64(rocker, reg)     \
-       readq((rocker)->hw_addr + (ROCKER_ ## reg))
-
-/*****************************
- * HW basic testing functions
- *****************************/
-
-static int rocker_reg_test(const struct rocker *rocker)
-{
-       const struct pci_dev *pdev = rocker->pdev;
-       u64 test_reg;
-       u64 rnd;
-
-       rnd = prandom_u32();
-       rnd >>= 1;
-       rocker_write32(rocker, TEST_REG, rnd);
-       test_reg = rocker_read32(rocker, TEST_REG);
-       if (test_reg != rnd * 2) {
-               dev_err(&pdev->dev, "unexpected 32bit register value %08llx, expected %08llx\n",
-                       test_reg, rnd * 2);
-               return -EIO;
-       }
-
-       rnd = prandom_u32();
-       rnd <<= 31;
-       rnd |= prandom_u32();
-       rocker_write64(rocker, TEST_REG64, rnd);
-       test_reg = rocker_read64(rocker, TEST_REG64);
-       if (test_reg != rnd * 2) {
-               dev_err(&pdev->dev, "unexpected 64bit register value %16llx, expected %16llx\n",
-                       test_reg, rnd * 2);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int rocker_dma_test_one(const struct rocker *rocker,
-                              struct rocker_wait *wait, u32 test_type,
-                              dma_addr_t dma_handle, const unsigned char *buf,
-                              const unsigned char *expect, size_t size)
-{
-       const struct pci_dev *pdev = rocker->pdev;
-       int i;
-
-       rocker_wait_reset(wait);
-       rocker_write32(rocker, TEST_DMA_CTRL, test_type);
-
-       if (!rocker_wait_event_timeout(wait, HZ / 10)) {
-               dev_err(&pdev->dev, "no interrupt received within a timeout\n");
-               return -EIO;
-       }
-
-       for (i = 0; i < size; i++) {
-               if (buf[i] != expect[i]) {
-                       dev_err(&pdev->dev, "unexpected memory content %02x at byte %x\n, %02x expected",
-                               buf[i], i, expect[i]);
-                       return -EIO;
-               }
-       }
-       return 0;
-}
-
-#define ROCKER_TEST_DMA_BUF_SIZE (PAGE_SIZE * 4)
-#define ROCKER_TEST_DMA_FILL_PATTERN 0x96
-
-static int rocker_dma_test_offset(const struct rocker *rocker,
-                                 struct rocker_wait *wait, int offset)
-{
-       struct pci_dev *pdev = rocker->pdev;
-       unsigned char *alloc;
-       unsigned char *buf;
-       unsigned char *expect;
-       dma_addr_t dma_handle;
-       int i;
-       int err;
-
-       alloc = kzalloc(ROCKER_TEST_DMA_BUF_SIZE * 2 + offset,
-                       GFP_KERNEL | GFP_DMA);
-       if (!alloc)
-               return -ENOMEM;
-       buf = alloc + offset;
-       expect = buf + ROCKER_TEST_DMA_BUF_SIZE;
-
-       dma_handle = pci_map_single(pdev, buf, ROCKER_TEST_DMA_BUF_SIZE,
-                                   PCI_DMA_BIDIRECTIONAL);
-       if (pci_dma_mapping_error(pdev, dma_handle)) {
-               err = -EIO;
-               goto free_alloc;
-       }
-
-       rocker_write64(rocker, TEST_DMA_ADDR, dma_handle);
-       rocker_write32(rocker, TEST_DMA_SIZE, ROCKER_TEST_DMA_BUF_SIZE);
-
-       memset(expect, ROCKER_TEST_DMA_FILL_PATTERN, ROCKER_TEST_DMA_BUF_SIZE);
-       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_FILL,
-                                 dma_handle, buf, expect,
-                                 ROCKER_TEST_DMA_BUF_SIZE);
-       if (err)
-               goto unmap;
-
-       memset(expect, 0, ROCKER_TEST_DMA_BUF_SIZE);
-       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_CLEAR,
-                                 dma_handle, buf, expect,
-                                 ROCKER_TEST_DMA_BUF_SIZE);
-       if (err)
-               goto unmap;
-
-       prandom_bytes(buf, ROCKER_TEST_DMA_BUF_SIZE);
-       for (i = 0; i < ROCKER_TEST_DMA_BUF_SIZE; i++)
-               expect[i] = ~buf[i];
-       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_INVERT,
-                                 dma_handle, buf, expect,
-                                 ROCKER_TEST_DMA_BUF_SIZE);
-       if (err)
-               goto unmap;
-
-unmap:
-       pci_unmap_single(pdev, dma_handle, ROCKER_TEST_DMA_BUF_SIZE,
-                        PCI_DMA_BIDIRECTIONAL);
-free_alloc:
-       kfree(alloc);
-
-       return err;
-}
-
-static int rocker_dma_test(const struct rocker *rocker,
-                          struct rocker_wait *wait)
-{
-       int i;
-       int err;
-
-       for (i = 0; i < 8; i++) {
-               err = rocker_dma_test_offset(rocker, wait, i);
-               if (err)
-                       return err;
-       }
-       return 0;
-}
-
-static irqreturn_t rocker_test_irq_handler(int irq, void *dev_id)
-{
-       struct rocker_wait *wait = dev_id;
-
-       rocker_wait_wake_up(wait);
-
-       return IRQ_HANDLED;
-}
-
-static int rocker_basic_hw_test(const struct rocker *rocker)
-{
-       const struct pci_dev *pdev = rocker->pdev;
-       struct rocker_wait wait;
-       int err;
-
-       err = rocker_reg_test(rocker);
-       if (err) {
-               dev_err(&pdev->dev, "reg test failed\n");
-               return err;
-       }
-
-       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST),
-                         rocker_test_irq_handler, 0,
-                         rocker_driver_name, &wait);
-       if (err) {
-               dev_err(&pdev->dev, "cannot assign test irq\n");
-               return err;
-       }
-
-       rocker_wait_init(&wait);
-       rocker_write32(rocker, TEST_IRQ, ROCKER_MSIX_VEC_TEST);
-
-       if (!rocker_wait_event_timeout(&wait, HZ / 10)) {
-               dev_err(&pdev->dev, "no interrupt received within a timeout\n");
-               err = -EIO;
-               goto free_irq;
-       }
-
-       err = rocker_dma_test(rocker, &wait);
-       if (err)
-               dev_err(&pdev->dev, "dma test failed\n");
-
-free_irq:
-       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST), &wait);
-       return err;
-}
-
-/******
- * TLV
- ******/
-
-#define ROCKER_TLV_ALIGNTO 8U
-#define ROCKER_TLV_ALIGN(len) \
-       (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1))
-#define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(struct rocker_tlv))
-
-/*  <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) --->
- * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
- * |             Header          | Pad |           Payload           | Pad |
- * |      (struct rocker_tlv)    | ing |                             | ing |
- * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
- *  <--------------------------- tlv->len -------------------------->
- */
-
-static struct rocker_tlv *rocker_tlv_next(const struct rocker_tlv *tlv,
-                                         int *remaining)
-{
-       int totlen = ROCKER_TLV_ALIGN(tlv->len);
-
-       *remaining -= totlen;
-       return (struct rocker_tlv *) ((char *) tlv + totlen);
-}
-
-static int rocker_tlv_ok(const struct rocker_tlv *tlv, int remaining)
-{
-       return remaining >= (int) ROCKER_TLV_HDRLEN &&
-              tlv->len >= ROCKER_TLV_HDRLEN &&
-              tlv->len <= remaining;
-}
-
-#define rocker_tlv_for_each(pos, head, len, rem)       \
-       for (pos = head, rem = len;                     \
-            rocker_tlv_ok(pos, rem);                   \
-            pos = rocker_tlv_next(pos, &(rem)))
-
-#define rocker_tlv_for_each_nested(pos, tlv, rem)      \
-       rocker_tlv_for_each(pos, rocker_tlv_data(tlv),  \
-                           rocker_tlv_len(tlv), rem)
-
-static int rocker_tlv_attr_size(int payload)
-{
-       return ROCKER_TLV_HDRLEN + payload;
-}
-
-static int rocker_tlv_total_size(int payload)
-{
-       return ROCKER_TLV_ALIGN(rocker_tlv_attr_size(payload));
-}
-
-static int rocker_tlv_padlen(int payload)
-{
-       return rocker_tlv_total_size(payload) - rocker_tlv_attr_size(payload);
-}
-
-static int rocker_tlv_type(const struct rocker_tlv *tlv)
-{
-       return tlv->type;
-}
-
-static void *rocker_tlv_data(const struct rocker_tlv *tlv)
-{
-       return (char *) tlv + ROCKER_TLV_HDRLEN;
-}
-
-static int rocker_tlv_len(const struct rocker_tlv *tlv)
-{
-       return tlv->len - ROCKER_TLV_HDRLEN;
-}
-
-static u8 rocker_tlv_get_u8(const struct rocker_tlv *tlv)
-{
-       return *(u8 *) rocker_tlv_data(tlv);
-}
-
-static u16 rocker_tlv_get_u16(const struct rocker_tlv *tlv)
-{
-       return *(u16 *) rocker_tlv_data(tlv);
-}
-
-static __be16 rocker_tlv_get_be16(const struct rocker_tlv *tlv)
-{
-       return *(__be16 *) rocker_tlv_data(tlv);
-}
-
-static u32 rocker_tlv_get_u32(const struct rocker_tlv *tlv)
-{
-       return *(u32 *) rocker_tlv_data(tlv);
-}
-
-static u64 rocker_tlv_get_u64(const struct rocker_tlv *tlv)
-{
-       return *(u64 *) rocker_tlv_data(tlv);
-}
-
-static void rocker_tlv_parse(const struct rocker_tlv **tb, int maxtype,
-                            const char *buf, int buf_len)
-{
-       const struct rocker_tlv *tlv;
-       const struct rocker_tlv *head = (const struct rocker_tlv *) buf;
-       int rem;
-
-       memset(tb, 0, sizeof(struct rocker_tlv *) * (maxtype + 1));
-
-       rocker_tlv_for_each(tlv, head, buf_len, rem) {
-               u32 type = rocker_tlv_type(tlv);
-
-               if (type > 0 && type <= maxtype)
-                       tb[type] = tlv;
-       }
-}
-
-static void rocker_tlv_parse_nested(const struct rocker_tlv **tb, int maxtype,
-                                   const struct rocker_tlv *tlv)
-{
-       rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv),
-                        rocker_tlv_len(tlv));
-}
-
-static void rocker_tlv_parse_desc(const struct rocker_tlv **tb, int maxtype,
-                                 const struct rocker_desc_info *desc_info)
-{
-       rocker_tlv_parse(tb, maxtype, desc_info->data,
-                        desc_info->desc->tlv_size);
-}
-
-static struct rocker_tlv *rocker_tlv_start(struct rocker_desc_info *desc_info)
-{
-       return (struct rocker_tlv *) ((char *) desc_info->data +
-                                              desc_info->tlv_size);
-}
-
-static int rocker_tlv_put(struct rocker_desc_info *desc_info,
-                         int attrtype, int attrlen, const void *data)
-{
-       int tail_room = desc_info->data_size - desc_info->tlv_size;
-       int total_size = rocker_tlv_total_size(attrlen);
-       struct rocker_tlv *tlv;
-
-       if (unlikely(tail_room < total_size))
-               return -EMSGSIZE;
-
-       tlv = rocker_tlv_start(desc_info);
-       desc_info->tlv_size += total_size;
-       tlv->type = attrtype;
-       tlv->len = rocker_tlv_attr_size(attrlen);
-       memcpy(rocker_tlv_data(tlv), data, attrlen);
-       memset((char *) tlv + tlv->len, 0, rocker_tlv_padlen(attrlen));
-       return 0;
-}
-
-static int rocker_tlv_put_u8(struct rocker_desc_info *desc_info,
-                            int attrtype, u8 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &value);
-}
-
-static int rocker_tlv_put_u16(struct rocker_desc_info *desc_info,
-                             int attrtype, u16 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &value);
-}
-
-static int rocker_tlv_put_be16(struct rocker_desc_info *desc_info,
-                              int attrtype, __be16 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &value);
-}
-
-static int rocker_tlv_put_u32(struct rocker_desc_info *desc_info,
-                             int attrtype, u32 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &value);
-}
-
-static int rocker_tlv_put_be32(struct rocker_desc_info *desc_info,
-                              int attrtype, __be32 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &value);
-}
-
-static int rocker_tlv_put_u64(struct rocker_desc_info *desc_info,
-                             int attrtype, u64 value)
-{
-       return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &value);
-}
-
-static struct rocker_tlv *
-rocker_tlv_nest_start(struct rocker_desc_info *desc_info, int attrtype)
-{
-       struct rocker_tlv *start = rocker_tlv_start(desc_info);
-
-       if (rocker_tlv_put(desc_info, attrtype, 0, NULL) < 0)
-               return NULL;
-
-       return start;
-}
-
-static void rocker_tlv_nest_end(struct rocker_desc_info *desc_info,
-                               struct rocker_tlv *start)
-{
-       start->len = (char *) rocker_tlv_start(desc_info) - (char *) start;
-}
-
-static void rocker_tlv_nest_cancel(struct rocker_desc_info *desc_info,
-                                  const struct rocker_tlv *start)
-{
-       desc_info->tlv_size = (const char *) start - desc_info->data;
-}
-
-/******************************************
- * DMA rings and descriptors manipulations
- ******************************************/
-
-static u32 __pos_inc(u32 pos, size_t limit)
-{
-       return ++pos == limit ? 0 : pos;
-}
-
-static int rocker_desc_err(const struct rocker_desc_info *desc_info)
-{
-       int err = desc_info->desc->comp_err & ~ROCKER_DMA_DESC_COMP_ERR_GEN;
-
-       switch (err) {
-       case ROCKER_OK:
-               return 0;
-       case -ROCKER_ENOENT:
-               return -ENOENT;
-       case -ROCKER_ENXIO:
-               return -ENXIO;
-       case -ROCKER_ENOMEM:
-               return -ENOMEM;
-       case -ROCKER_EEXIST:
-               return -EEXIST;
-       case -ROCKER_EINVAL:
-               return -EINVAL;
-       case -ROCKER_EMSGSIZE:
-               return -EMSGSIZE;
-       case -ROCKER_ENOTSUP:
-               return -EOPNOTSUPP;
-       case -ROCKER_ENOBUFS:
-               return -ENOBUFS;
-       }
-
-       return -EINVAL;
-}
-
-static void rocker_desc_gen_clear(const struct rocker_desc_info *desc_info)
-{
-       desc_info->desc->comp_err &= ~ROCKER_DMA_DESC_COMP_ERR_GEN;
-}
-
-static bool rocker_desc_gen(const struct rocker_desc_info *desc_info)
-{
-       u32 comp_err = desc_info->desc->comp_err;
-
-       return comp_err & ROCKER_DMA_DESC_COMP_ERR_GEN ? true : false;
-}
-
-static void *rocker_desc_cookie_ptr_get(const struct rocker_desc_info *desc_info)
-{
-       return (void *)(uintptr_t)desc_info->desc->cookie;
-}
-
-static void rocker_desc_cookie_ptr_set(const struct rocker_desc_info *desc_info,
-                                      void *ptr)
-{
-       desc_info->desc->cookie = (uintptr_t) ptr;
-}
-
-static struct rocker_desc_info *
-rocker_desc_head_get(const struct rocker_dma_ring_info *info)
-{
-       static struct rocker_desc_info *desc_info;
-       u32 head = __pos_inc(info->head, info->size);
-
-       desc_info = &info->desc_info[info->head];
-       if (head == info->tail)
-               return NULL; /* ring full */
-       desc_info->tlv_size = 0;
-       return desc_info;
-}
-
-static void rocker_desc_commit(const struct rocker_desc_info *desc_info)
-{
-       desc_info->desc->buf_size = desc_info->data_size;
-       desc_info->desc->tlv_size = desc_info->tlv_size;
-}
-
-static void rocker_desc_head_set(const struct rocker *rocker,
-                                struct rocker_dma_ring_info *info,
-                                const struct rocker_desc_info *desc_info)
-{
-       u32 head = __pos_inc(info->head, info->size);
-
-       BUG_ON(head == info->tail);
-       rocker_desc_commit(desc_info);
-       info->head = head;
-       rocker_write32(rocker, DMA_DESC_HEAD(info->type), head);
-}
-
-static struct rocker_desc_info *
-rocker_desc_tail_get(struct rocker_dma_ring_info *info)
-{
-       static struct rocker_desc_info *desc_info;
-
-       if (info->tail == info->head)
-               return NULL; /* nothing to be done between head and tail */
-       desc_info = &info->desc_info[info->tail];
-       if (!rocker_desc_gen(desc_info))
-               return NULL; /* gen bit not set, desc is not ready yet */
-       info->tail = __pos_inc(info->tail, info->size);
-       desc_info->tlv_size = desc_info->desc->tlv_size;
-       return desc_info;
-}
-
-static void rocker_dma_ring_credits_set(const struct rocker *rocker,
-                                       const struct rocker_dma_ring_info *info,
-                                       u32 credits)
-{
-       if (credits)
-               rocker_write32(rocker, DMA_DESC_CREDITS(info->type), credits);
-}
-
-static unsigned long rocker_dma_ring_size_fix(size_t size)
-{
-       return max(ROCKER_DMA_SIZE_MIN,
-                  min(roundup_pow_of_two(size), ROCKER_DMA_SIZE_MAX));
-}
-
-static int rocker_dma_ring_create(const struct rocker *rocker,
-                                 unsigned int type,
-                                 size_t size,
-                                 struct rocker_dma_ring_info *info)
-{
-       int i;
-
-       BUG_ON(size != rocker_dma_ring_size_fix(size));
-       info->size = size;
-       info->type = type;
-       info->head = 0;
-       info->tail = 0;
-       info->desc_info = kcalloc(info->size, sizeof(*info->desc_info),
-                                 GFP_KERNEL);
-       if (!info->desc_info)
-               return -ENOMEM;
-
-       info->desc = pci_alloc_consistent(rocker->pdev,
-                                         info->size * sizeof(*info->desc),
-                                         &info->mapaddr);
-       if (!info->desc) {
-               kfree(info->desc_info);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < info->size; i++)
-               info->desc_info[i].desc = &info->desc[i];
-
-       rocker_write32(rocker, DMA_DESC_CTRL(info->type),
-                      ROCKER_DMA_DESC_CTRL_RESET);
-       rocker_write64(rocker, DMA_DESC_ADDR(info->type), info->mapaddr);
-       rocker_write32(rocker, DMA_DESC_SIZE(info->type), info->size);
-
-       return 0;
-}
-
-static void rocker_dma_ring_destroy(const struct rocker *rocker,
-                                   const struct rocker_dma_ring_info *info)
-{
-       rocker_write64(rocker, DMA_DESC_ADDR(info->type), 0);
-
-       pci_free_consistent(rocker->pdev,
-                           info->size * sizeof(struct rocker_desc),
-                           info->desc, info->mapaddr);
-       kfree(info->desc_info);
-}
-
-static void rocker_dma_ring_pass_to_producer(const struct rocker *rocker,
-                                            struct rocker_dma_ring_info *info)
-{
-       int i;
-
-       BUG_ON(info->head || info->tail);
-
-       /* When ring is consumer, we need to advance head for each desc.
-        * That tells hw that the desc is ready to be used by it.
-        */
-       for (i = 0; i < info->size - 1; i++)
-               rocker_desc_head_set(rocker, info, &info->desc_info[i]);
-       rocker_desc_commit(&info->desc_info[i]);
-}
-
-static int rocker_dma_ring_bufs_alloc(const struct rocker *rocker,
-                                     const struct rocker_dma_ring_info *info,
-                                     int direction, size_t buf_size)
-{
-       struct pci_dev *pdev = rocker->pdev;
-       int i;
-       int err;
-
-       for (i = 0; i < info->size; i++) {
-               struct rocker_desc_info *desc_info = &info->desc_info[i];
-               struct rocker_desc *desc = &info->desc[i];
-               dma_addr_t dma_handle;
-               char *buf;
-
-               buf = kzalloc(buf_size, GFP_KERNEL | GFP_DMA);
-               if (!buf) {
-                       err = -ENOMEM;
-                       goto rollback;
-               }
-
-               dma_handle = pci_map_single(pdev, buf, buf_size, direction);
-               if (pci_dma_mapping_error(pdev, dma_handle)) {
-                       kfree(buf);
-                       err = -EIO;
-                       goto rollback;
-               }
-
-               desc_info->data = buf;
-               desc_info->data_size = buf_size;
-               dma_unmap_addr_set(desc_info, mapaddr, dma_handle);
-
-               desc->buf_addr = dma_handle;
-               desc->buf_size = buf_size;
-       }
-       return 0;
-
-rollback:
-       for (i--; i >= 0; i--) {
-               const struct rocker_desc_info *desc_info = &info->desc_info[i];
-
-               pci_unmap_single(pdev, dma_unmap_addr(desc_info, mapaddr),
-                                desc_info->data_size, direction);
-               kfree(desc_info->data);
-       }
-       return err;
-}
-
-static void rocker_dma_ring_bufs_free(const struct rocker *rocker,
-                                     const struct rocker_dma_ring_info *info,
-                                     int direction)
-{
-       struct pci_dev *pdev = rocker->pdev;
-       int i;
-
-       for (i = 0; i < info->size; i++) {
-               const struct rocker_desc_info *desc_info = &info->desc_info[i];
-               struct rocker_desc *desc = &info->desc[i];
-
-               desc->buf_addr = 0;
-               desc->buf_size = 0;
-               pci_unmap_single(pdev, dma_unmap_addr(desc_info, mapaddr),
-                                desc_info->data_size, direction);
-               kfree(desc_info->data);
-       }
-}
-
-static int rocker_dma_rings_init(struct rocker *rocker)
-{
-       const struct pci_dev *pdev = rocker->pdev;
-       int err;
-
-       err = rocker_dma_ring_create(rocker, ROCKER_DMA_CMD,
-                                    ROCKER_DMA_CMD_DEFAULT_SIZE,
-                                    &rocker->cmd_ring);
-       if (err) {
-               dev_err(&pdev->dev, "failed to create command dma ring\n");
-               return err;
-       }
-
-       spin_lock_init(&rocker->cmd_ring_lock);
-
-       err = rocker_dma_ring_bufs_alloc(rocker, &rocker->cmd_ring,
-                                        PCI_DMA_BIDIRECTIONAL, PAGE_SIZE);
-       if (err) {
-               dev_err(&pdev->dev, "failed to alloc command dma ring buffers\n");
-               goto err_dma_cmd_ring_bufs_alloc;
-       }
-
-       err = rocker_dma_ring_create(rocker, ROCKER_DMA_EVENT,
-                                    ROCKER_DMA_EVENT_DEFAULT_SIZE,
-                                    &rocker->event_ring);
-       if (err) {
-               dev_err(&pdev->dev, "failed to create event dma ring\n");
-               goto err_dma_event_ring_create;
-       }
-
-       err = rocker_dma_ring_bufs_alloc(rocker, &rocker->event_ring,
-                                        PCI_DMA_FROMDEVICE, PAGE_SIZE);
-       if (err) {
-               dev_err(&pdev->dev, "failed to alloc event dma ring buffers\n");
-               goto err_dma_event_ring_bufs_alloc;
-       }
-       rocker_dma_ring_pass_to_producer(rocker, &rocker->event_ring);
-       return 0;
-
-err_dma_event_ring_bufs_alloc:
-       rocker_dma_ring_destroy(rocker, &rocker->event_ring);
-err_dma_event_ring_create:
-       rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,
-                                 PCI_DMA_BIDIRECTIONAL);
-err_dma_cmd_ring_bufs_alloc:
-       rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
-       return err;
-}
-
-static void rocker_dma_rings_fini(struct rocker *rocker)
-{
-       rocker_dma_ring_bufs_free(rocker, &rocker->event_ring,
-                                 PCI_DMA_BIDIRECTIONAL);
-       rocker_dma_ring_destroy(rocker, &rocker->event_ring);
-       rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,
-                                 PCI_DMA_BIDIRECTIONAL);
-       rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
-}
-
-static int rocker_dma_rx_ring_skb_map(const struct rocker_port *rocker_port,
-                                     struct rocker_desc_info *desc_info,
-                                     struct sk_buff *skb, size_t buf_len)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       struct pci_dev *pdev = rocker->pdev;
-       dma_addr_t dma_handle;
-
-       dma_handle = pci_map_single(pdev, skb->data, buf_len,
-                                   PCI_DMA_FROMDEVICE);
-       if (pci_dma_mapping_error(pdev, dma_handle))
-               return -EIO;
-       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_RX_FRAG_ADDR, dma_handle))
-               goto tlv_put_failure;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_RX_FRAG_MAX_LEN, buf_len))
-               goto tlv_put_failure;
-       return 0;
-
-tlv_put_failure:
-       pci_unmap_single(pdev, dma_handle, buf_len, PCI_DMA_FROMDEVICE);
-       desc_info->tlv_size = 0;
-       return -EMSGSIZE;
-}
-
-static size_t rocker_port_rx_buf_len(const struct rocker_port *rocker_port)
-{
-       return rocker_port->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
-}
-
-static int rocker_dma_rx_ring_skb_alloc(const struct rocker_port *rocker_port,
-                                       struct rocker_desc_info *desc_info)
-{
-       struct net_device *dev = rocker_port->dev;
-       struct sk_buff *skb;
-       size_t buf_len = rocker_port_rx_buf_len(rocker_port);
-       int err;
-
-       /* Ensure that hw will see tlv_size zero in case of an error.
-        * That tells hw to use another descriptor.
-        */
-       rocker_desc_cookie_ptr_set(desc_info, NULL);
-       desc_info->tlv_size = 0;
-
-       skb = netdev_alloc_skb_ip_align(dev, buf_len);
-       if (!skb)
-               return -ENOMEM;
-       err = rocker_dma_rx_ring_skb_map(rocker_port, desc_info, skb, buf_len);
-       if (err) {
-               dev_kfree_skb_any(skb);
-               return err;
-       }
-       rocker_desc_cookie_ptr_set(desc_info, skb);
-       return 0;
-}
-
-static void rocker_dma_rx_ring_skb_unmap(const struct rocker *rocker,
-                                        const struct rocker_tlv **attrs)
-{
-       struct pci_dev *pdev = rocker->pdev;
-       dma_addr_t dma_handle;
-       size_t len;
-
-       if (!attrs[ROCKER_TLV_RX_FRAG_ADDR] ||
-           !attrs[ROCKER_TLV_RX_FRAG_MAX_LEN])
-               return;
-       dma_handle = rocker_tlv_get_u64(attrs[ROCKER_TLV_RX_FRAG_ADDR]);
-       len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
-       pci_unmap_single(pdev, dma_handle, len, PCI_DMA_FROMDEVICE);
-}
-
-static void rocker_dma_rx_ring_skb_free(const struct rocker *rocker,
-                                       const struct rocker_desc_info *desc_info)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
-       struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
-
-       if (!skb)
-               return;
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);
-       rocker_dma_rx_ring_skb_unmap(rocker, attrs);
-       dev_kfree_skb_any(skb);
-}
-
-static int rocker_dma_rx_ring_skbs_alloc(const struct rocker_port *rocker_port)
-{
-       const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
-       const struct rocker *rocker = rocker_port->rocker;
-       int i;
-       int err;
-
-       for (i = 0; i < rx_ring->size; i++) {
-               err = rocker_dma_rx_ring_skb_alloc(rocker_port,
-                                                  &rx_ring->desc_info[i]);
-               if (err)
-                       goto rollback;
-       }
-       return 0;
-
-rollback:
-       for (i--; i >= 0; i--)
-               rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);
-       return err;
-}
-
-static void rocker_dma_rx_ring_skbs_free(const struct rocker_port *rocker_port)
-{
-       const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
-       const struct rocker *rocker = rocker_port->rocker;
-       int i;
-
-       for (i = 0; i < rx_ring->size; i++)
-               rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);
-}
-
-static int rocker_port_dma_rings_init(struct rocker_port *rocker_port)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       int err;
-
-       err = rocker_dma_ring_create(rocker,
-                                    ROCKER_DMA_TX(rocker_port->port_number),
-                                    ROCKER_DMA_TX_DEFAULT_SIZE,
-                                    &rocker_port->tx_ring);
-       if (err) {
-               netdev_err(rocker_port->dev, "failed to create tx dma ring\n");
-               return err;
-       }
-
-       err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->tx_ring,
-                                        PCI_DMA_TODEVICE,
-                                        ROCKER_DMA_TX_DESC_SIZE);
-       if (err) {
-               netdev_err(rocker_port->dev, "failed to alloc tx dma ring buffers\n");
-               goto err_dma_tx_ring_bufs_alloc;
-       }
-
-       err = rocker_dma_ring_create(rocker,
-                                    ROCKER_DMA_RX(rocker_port->port_number),
-                                    ROCKER_DMA_RX_DEFAULT_SIZE,
-                                    &rocker_port->rx_ring);
-       if (err) {
-               netdev_err(rocker_port->dev, "failed to create rx dma ring\n");
-               goto err_dma_rx_ring_create;
-       }
-
-       err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->rx_ring,
-                                        PCI_DMA_BIDIRECTIONAL,
-                                        ROCKER_DMA_RX_DESC_SIZE);
-       if (err) {
-               netdev_err(rocker_port->dev, "failed to alloc rx dma ring buffers\n");
-               goto err_dma_rx_ring_bufs_alloc;
-       }
-
-       err = rocker_dma_rx_ring_skbs_alloc(rocker_port);
-       if (err) {
-               netdev_err(rocker_port->dev, "failed to alloc rx dma ring skbs\n");
-               goto err_dma_rx_ring_skbs_alloc;
-       }
-       rocker_dma_ring_pass_to_producer(rocker, &rocker_port->rx_ring);
-
-       return 0;
-
-err_dma_rx_ring_skbs_alloc:
-       rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,
-                                 PCI_DMA_BIDIRECTIONAL);
-err_dma_rx_ring_bufs_alloc:
-       rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);
-err_dma_rx_ring_create:
-       rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,
-                                 PCI_DMA_TODEVICE);
-err_dma_tx_ring_bufs_alloc:
-       rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);
-       return err;
-}
-
-static void rocker_port_dma_rings_fini(struct rocker_port *rocker_port)
-{
-       struct rocker *rocker = rocker_port->rocker;
-
-       rocker_dma_rx_ring_skbs_free(rocker_port);
-       rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,
-                                 PCI_DMA_BIDIRECTIONAL);
-       rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);
-       rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,
-                                 PCI_DMA_TODEVICE);
-       rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);
-}
-
-static void rocker_port_set_enable(const struct rocker_port *rocker_port,
-                                  bool enable)
-{
-       u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);
-
-       if (enable)
-               val |= 1ULL << rocker_port->pport;
-       else
-               val &= ~(1ULL << rocker_port->pport);
-       rocker_write64(rocker_port->rocker, PORT_PHYS_ENABLE, val);
-}
-
-/********************************
- * Interrupt handler and helpers
- ********************************/
-
-static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
-{
-       struct rocker *rocker = dev_id;
-       const struct rocker_desc_info *desc_info;
-       struct rocker_wait *wait;
-       u32 credits = 0;
-
-       spin_lock(&rocker->cmd_ring_lock);
-       while ((desc_info = rocker_desc_tail_get(&rocker->cmd_ring))) {
-               wait = rocker_desc_cookie_ptr_get(desc_info);
-               if (wait->nowait) {
-                       rocker_desc_gen_clear(desc_info);
-                       rocker_wait_destroy(NULL, wait);
-               } else {
-                       rocker_wait_wake_up(wait);
-               }
-               credits++;
-       }
-       spin_unlock(&rocker->cmd_ring_lock);
-       rocker_dma_ring_credits_set(rocker, &rocker->cmd_ring, credits);
-
-       return IRQ_HANDLED;
-}
-
-static void rocker_port_link_up(const struct rocker_port *rocker_port)
-{
-       netif_carrier_on(rocker_port->dev);
-       netdev_info(rocker_port->dev, "Link is up\n");
-}
-
-static void rocker_port_link_down(const struct rocker_port *rocker_port)
-{
-       netif_carrier_off(rocker_port->dev);
-       netdev_info(rocker_port->dev, "Link is down\n");
-}
-
-static int rocker_event_link_change(const struct rocker *rocker,
-                                   const struct rocker_tlv *info)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_LINK_CHANGED_MAX + 1];
-       unsigned int port_number;
-       bool link_up;
-       struct rocker_port *rocker_port;
-
-       rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_LINK_CHANGED_MAX, info);
-       if (!attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT] ||
-           !attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP])
-               return -EIO;
-       port_number =
-               rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT]) - 1;
-       link_up = rocker_tlv_get_u8(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP]);
-
-       if (port_number >= rocker->port_count)
-               return -EINVAL;
-
-       rocker_port = rocker->ports[port_number];
-       if (netif_carrier_ok(rocker_port->dev) != link_up) {
-               if (link_up)
-                       rocker_port_link_up(rocker_port);
-               else
-                       rocker_port_link_down(rocker_port);
-       }
-
-       return 0;
-}
-
-static int rocker_port_fdb(struct rocker_port *rocker_port,
-                          struct switchdev_trans *trans,
-                          const unsigned char *addr,
-                          __be16 vlan_id, int flags);
-
-static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
-                                     const struct rocker_tlv *info)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
-       unsigned int port_number;
-       struct rocker_port *rocker_port;
-       const unsigned char *addr;
-       int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_LEARNED;
-       __be16 vlan_id;
-
-       rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
-       if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||
-           !attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC] ||
-           !attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID])
-               return -EIO;
-       port_number =
-               rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT]) - 1;
-       addr = rocker_tlv_data(attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC]);
-       vlan_id = rocker_tlv_get_be16(attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID]);
-
-       if (port_number >= rocker->port_count)
-               return -EINVAL;
-
-       rocker_port = rocker->ports[port_number];
-
-       if (rocker_port->stp_state != BR_STATE_LEARNING &&
-           rocker_port->stp_state != BR_STATE_FORWARDING)
-               return 0;
-
-       return rocker_port_fdb(rocker_port, NULL, addr, vlan_id, flags);
-}
-
-static int rocker_event_process(const struct rocker *rocker,
-                               const struct rocker_desc_info *desc_info)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAX + 1];
-       const struct rocker_tlv *info;
-       u16 type;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_EVENT_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_EVENT_TYPE] ||
-           !attrs[ROCKER_TLV_EVENT_INFO])
-               return -EIO;
-
-       type = rocker_tlv_get_u16(attrs[ROCKER_TLV_EVENT_TYPE]);
-       info = attrs[ROCKER_TLV_EVENT_INFO];
-
-       switch (type) {
-       case ROCKER_TLV_EVENT_TYPE_LINK_CHANGED:
-               return rocker_event_link_change(rocker, info);
-       case ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN:
-               return rocker_event_mac_vlan_seen(rocker, info);
-       }
-
-       return -EOPNOTSUPP;
-}
-
-static irqreturn_t rocker_event_irq_handler(int irq, void *dev_id)
-{
-       struct rocker *rocker = dev_id;
-       const struct pci_dev *pdev = rocker->pdev;
-       const struct rocker_desc_info *desc_info;
-       u32 credits = 0;
-       int err;
-
-       while ((desc_info = rocker_desc_tail_get(&rocker->event_ring))) {
-               err = rocker_desc_err(desc_info);
-               if (err) {
-                       dev_err(&pdev->dev, "event desc received with err %d\n",
-                               err);
-               } else {
-                       err = rocker_event_process(rocker, desc_info);
-                       if (err)
-                               dev_err(&pdev->dev, "event processing failed with err %d\n",
-                                       err);
-               }
-               rocker_desc_gen_clear(desc_info);
-               rocker_desc_head_set(rocker, &rocker->event_ring, desc_info);
-               credits++;
-       }
-       rocker_dma_ring_credits_set(rocker, &rocker->event_ring, credits);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t rocker_tx_irq_handler(int irq, void *dev_id)
-{
-       struct rocker_port *rocker_port = dev_id;
-
-       napi_schedule(&rocker_port->napi_tx);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t rocker_rx_irq_handler(int irq, void *dev_id)
-{
-       struct rocker_port *rocker_port = dev_id;
-
-       napi_schedule(&rocker_port->napi_rx);
-       return IRQ_HANDLED;
-}
-
-/********************
- * Command interface
- ********************/
-
-typedef int (*rocker_cmd_prep_cb_t)(const struct rocker_port *rocker_port,
-                                   struct rocker_desc_info *desc_info,
-                                   void *priv);
-
-typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
-                                   const struct rocker_desc_info *desc_info,
-                                   void *priv);
-
-static int rocker_cmd_exec(struct rocker_port *rocker_port,
-                          struct switchdev_trans *trans, int flags,
-                          rocker_cmd_prep_cb_t prepare, void *prepare_priv,
-                          rocker_cmd_proc_cb_t process, void *process_priv)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_desc_info *desc_info;
-       struct rocker_wait *wait;
-       bool nowait = !!(flags & ROCKER_OP_FLAG_NOWAIT);
-       unsigned long lock_flags;
-       int err;
-
-       wait = rocker_wait_create(rocker_port, trans, flags);
-       if (!wait)
-               return -ENOMEM;
-       wait->nowait = nowait;
-
-       spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags);
-
-       desc_info = rocker_desc_head_get(&rocker->cmd_ring);
-       if (!desc_info) {
-               spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
-               err = -EAGAIN;
-               goto out;
-       }
-
-       err = prepare(rocker_port, desc_info, prepare_priv);
-       if (err) {
-               spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
-               goto out;
-       }
-
-       rocker_desc_cookie_ptr_set(desc_info, wait);
-
-       if (!switchdev_trans_ph_prepare(trans))
-               rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
-
-       spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
-
-       if (nowait)
-               return 0;
-
-       if (!switchdev_trans_ph_prepare(trans))
-               if (!rocker_wait_event_timeout(wait, HZ / 10))
-                       return -EIO;
-
-       err = rocker_desc_err(desc_info);
-       if (err)
-               return err;
-
-       if (process)
-               err = process(rocker_port, desc_info, process_priv);
-
-       rocker_desc_gen_clear(desc_info);
-out:
-       rocker_wait_destroy(trans, wait);
-       return err;
-}
-
-static int
-rocker_cmd_get_port_settings_prep(const struct rocker_port *rocker_port,
-                                 struct rocker_desc_info *desc_info,
-                                 void *priv)
-{
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-       return 0;
-}
-
-static int
-rocker_cmd_get_port_settings_ethtool_proc(const struct rocker_port *rocker_port,
-                                         const struct rocker_desc_info *desc_info,
-                                         void *priv)
-{
-       struct ethtool_cmd *ecmd = priv;
-       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
-       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
-       u32 speed;
-       u8 duplex;
-       u8 autoneg;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_CMD_INFO])
-               return -EIO;
-
-       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
-                               attrs[ROCKER_TLV_CMD_INFO]);
-       if (!info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] ||
-           !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] ||
-           !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG])
-               return -EIO;
-
-       speed = rocker_tlv_get_u32(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
-       duplex = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
-       autoneg = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
-
-       ecmd->transceiver = XCVR_INTERNAL;
-       ecmd->supported = SUPPORTED_TP;
-       ecmd->phy_address = 0xff;
-       ecmd->port = PORT_TP;
-       ethtool_cmd_speed_set(ecmd, speed);
-       ecmd->duplex = duplex ? DUPLEX_FULL : DUPLEX_HALF;
-       ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_get_port_settings_macaddr_proc(const struct rocker_port *rocker_port,
-                                         const struct rocker_desc_info *desc_info,
-                                         void *priv)
-{
-       unsigned char *macaddr = priv;
-       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
-       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
-       const struct rocker_tlv *attr;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_CMD_INFO])
-               return -EIO;
-
-       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
-                               attrs[ROCKER_TLV_CMD_INFO]);
-       attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR];
-       if (!attr)
-               return -EIO;
-
-       if (rocker_tlv_len(attr) != ETH_ALEN)
-               return -EINVAL;
-
-       ether_addr_copy(macaddr, rocker_tlv_data(attr));
-       return 0;
-}
-
-struct port_name {
-       char *buf;
-       size_t len;
-};
-
-static int
-rocker_cmd_get_port_settings_phys_name_proc(const struct rocker_port *rocker_port,
-                                           const struct rocker_desc_info *desc_info,
-                                           void *priv)
-{
-       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
-       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
-       struct port_name *name = priv;
-       const struct rocker_tlv *attr;
-       size_t i, j, len;
-       const char *str;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_CMD_INFO])
-               return -EIO;
-
-       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
-                               attrs[ROCKER_TLV_CMD_INFO]);
-       attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME];
-       if (!attr)
-               return -EIO;
-
-       len = min_t(size_t, rocker_tlv_len(attr), name->len);
-       str = rocker_tlv_data(attr);
-
-       /* make sure name only contains alphanumeric characters */
-       for (i = j = 0; i < len; ++i) {
-               if (isalnum(str[i])) {
-                       name->buf[j] = str[i];
-                       j++;
-               }
-       }
-
-       if (j == 0)
-               return -EIO;
-
-       name->buf[j] = '\0';
-
-       return 0;
-}
-
-static int
-rocker_cmd_set_port_settings_ethtool_prep(const struct rocker_port *rocker_port,
-                                         struct rocker_desc_info *desc_info,
-                                         void *priv)
-{
-       struct ethtool_cmd *ecmd = priv;
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED,
-                              ethtool_cmd_speed(ecmd)))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX,
-                             ecmd->duplex))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG,
-                             ecmd->autoneg))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-       return 0;
-}
-
-static int
-rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port,
-                                         struct rocker_desc_info *desc_info,
-                                         void *priv)
-{
-       const unsigned char *macaddr = priv;
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
-                          ETH_ALEN, macaddr))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-       return 0;
-}
-
-static int
-rocker_cmd_set_port_settings_mtu_prep(const struct rocker_port *rocker_port,
-                                     struct rocker_desc_info *desc_info,
-                                     void *priv)
-{
-       int mtu = *(int *)priv;
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MTU,
-                              mtu))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-       return 0;
-}
-
-static int
-rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,
-                                 struct rocker_desc_info *desc_info,
-                                 void *priv)
-{
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
-                             !!(rocker_port->brport_flags & BR_LEARNING)))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-       return 0;
-}
-
-static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
-                                               struct ethtool_cmd *ecmd)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_get_port_settings_prep, NULL,
-                              rocker_cmd_get_port_settings_ethtool_proc,
-                              ecmd);
-}
-
-static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
-                                               unsigned char *macaddr)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_get_port_settings_prep, NULL,
-                              rocker_cmd_get_port_settings_macaddr_proc,
-                              macaddr);
-}
-
-static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
-                                               struct ethtool_cmd *ecmd)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_set_port_settings_ethtool_prep,
-                              ecmd, NULL, NULL);
-}
-
-static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
-                                               unsigned char *macaddr)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_set_port_settings_macaddr_prep,
-                              macaddr, NULL, NULL);
-}
-
-static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port,
-                                           int mtu)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_set_port_settings_mtu_prep,
-                              &mtu, NULL, NULL);
-}
-
-static int rocker_port_set_learning(struct rocker_port *rocker_port,
-                                   struct switchdev_trans *trans)
-{
-       return rocker_cmd_exec(rocker_port, trans, 0,
-                              rocker_cmd_set_port_learning_prep,
-                              NULL, NULL, NULL);
-}
-
-static int
-rocker_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
-                               const struct rocker_flow_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
-                              entry->key.ig_port.in_pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
-                              entry->key.ig_port.in_pport_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
-                              entry->key.ig_port.goto_tbl))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
-                            const struct rocker_flow_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
-                              entry->key.vlan.in_pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->key.vlan.vlan_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
-                               entry->key.vlan.vlan_id_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
-                              entry->key.vlan.goto_tbl))
-               return -EMSGSIZE;
-       if (entry->key.vlan.untagged &&
-           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_NEW_VLAN_ID,
-                               entry->key.vlan.new_vlan_id))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
-                                const struct rocker_flow_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
-                              entry->key.term_mac.in_pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
-                              entry->key.term_mac.in_pport_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
-                               entry->key.term_mac.eth_type))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
-                          ETH_ALEN, entry->key.term_mac.eth_dst))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
-                          ETH_ALEN, entry->key.term_mac.eth_dst_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->key.term_mac.vlan_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
-                               entry->key.term_mac.vlan_id_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
-                              entry->key.term_mac.goto_tbl))
-               return -EMSGSIZE;
-       if (entry->key.term_mac.copy_to_cpu &&
-           rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
-                             entry->key.term_mac.copy_to_cpu))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
-                                     const struct rocker_flow_tbl_entry *entry)
-{
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
-                               entry->key.ucast_routing.eth_type))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP,
-                               entry->key.ucast_routing.dst4))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP_MASK,
-                               entry->key.ucast_routing.dst4_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
-                              entry->key.ucast_routing.goto_tbl))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
-                              entry->key.ucast_routing.group_id))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
-                              const struct rocker_flow_tbl_entry *entry)
-{
-       if (entry->key.bridge.has_eth_dst &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
-                          ETH_ALEN, entry->key.bridge.eth_dst))
-               return -EMSGSIZE;
-       if (entry->key.bridge.has_eth_dst_mask &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
-                          ETH_ALEN, entry->key.bridge.eth_dst_mask))
-               return -EMSGSIZE;
-       if (entry->key.bridge.vlan_id &&
-           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->key.bridge.vlan_id))
-               return -EMSGSIZE;
-       if (entry->key.bridge.tunnel_id &&
-           rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_TUNNEL_ID,
-                              entry->key.bridge.tunnel_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
-                              entry->key.bridge.goto_tbl))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
-                              entry->key.bridge.group_id))
-               return -EMSGSIZE;
-       if (entry->key.bridge.copy_to_cpu &&
-           rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
-                             entry->key.bridge.copy_to_cpu))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
-                           const struct rocker_flow_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
-                              entry->key.acl.in_pport))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
-                              entry->key.acl.in_pport_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
-                          ETH_ALEN, entry->key.acl.eth_src))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC_MASK,
-                          ETH_ALEN, entry->key.acl.eth_src_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
-                          ETH_ALEN, entry->key.acl.eth_dst))
-               return -EMSGSIZE;
-       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
-                          ETH_ALEN, entry->key.acl.eth_dst_mask))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
-                               entry->key.acl.eth_type))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->key.acl.vlan_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
-                               entry->key.acl.vlan_id_mask))
-               return -EMSGSIZE;
-
-       switch (ntohs(entry->key.acl.eth_type)) {
-       case ETH_P_IP:
-       case ETH_P_IPV6:
-               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_PROTO,
-                                     entry->key.acl.ip_proto))
-                       return -EMSGSIZE;
-               if (rocker_tlv_put_u8(desc_info,
-                                     ROCKER_TLV_OF_DPA_IP_PROTO_MASK,
-                                     entry->key.acl.ip_proto_mask))
-                       return -EMSGSIZE;
-               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_DSCP,
-                                     entry->key.acl.ip_tos & 0x3f))
-                       return -EMSGSIZE;
-               if (rocker_tlv_put_u8(desc_info,
-                                     ROCKER_TLV_OF_DPA_IP_DSCP_MASK,
-                                     entry->key.acl.ip_tos_mask & 0x3f))
-                       return -EMSGSIZE;
-               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_ECN,
-                                     (entry->key.acl.ip_tos & 0xc0) >> 6))
-                       return -EMSGSIZE;
-               if (rocker_tlv_put_u8(desc_info,
-                                     ROCKER_TLV_OF_DPA_IP_ECN_MASK,
-                                     (entry->key.acl.ip_tos_mask & 0xc0) >> 6))
-                       return -EMSGSIZE;
-               break;
-       }
-
-       if (entry->key.acl.group_id != ROCKER_GROUP_NONE &&
-           rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
-                              entry->key.acl.group_id))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int rocker_cmd_flow_tbl_add(const struct rocker_port *rocker_port,
-                                  struct rocker_desc_info *desc_info,
-                                  void *priv)
-{
-       const struct rocker_flow_tbl_entry *entry = priv;
-       struct rocker_tlv *cmd_info;
-       int err = 0;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_TABLE_ID,
-                              entry->key.tbl_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_PRIORITY,
-                              entry->key.priority))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_HARDTIME, 0))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
-                              entry->cookie))
-               return -EMSGSIZE;
-
-       switch (entry->key.tbl_id) {
-       case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
-               err = rocker_cmd_flow_tbl_add_ig_port(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_TABLE_ID_VLAN:
-               err = rocker_cmd_flow_tbl_add_vlan(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
-               err = rocker_cmd_flow_tbl_add_term_mac(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
-               err = rocker_cmd_flow_tbl_add_ucast_routing(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
-               err = rocker_cmd_flow_tbl_add_bridge(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
-               err = rocker_cmd_flow_tbl_add_acl(desc_info, entry);
-               break;
-       default:
-               err = -ENOTSUPP;
-               break;
-       }
-
-       if (err)
-               return err;
-
-       rocker_tlv_nest_end(desc_info, cmd_info);
-
-       return 0;
-}
-
-static int rocker_cmd_flow_tbl_del(const struct rocker_port *rocker_port,
-                                  struct rocker_desc_info *desc_info,
-                                  void *priv)
-{
-       const struct rocker_flow_tbl_entry *entry = priv;
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
-                              entry->cookie))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-
-       return 0;
-}
-
-static int
-rocker_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
-                                     struct rocker_group_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_OUT_PPORT,
-                              ROCKER_GROUP_PORT_GET(entry->group_id)))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_POP_VLAN,
-                             entry->l2_interface.pop_vlan))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
-                                   const struct rocker_group_tbl_entry *entry)
-{
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
-                              entry->l2_rewrite.group_id))
-               return -EMSGSIZE;
-       if (!is_zero_ether_addr(entry->l2_rewrite.eth_src) &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
-                          ETH_ALEN, entry->l2_rewrite.eth_src))
-               return -EMSGSIZE;
-       if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst) &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
-                          ETH_ALEN, entry->l2_rewrite.eth_dst))
-               return -EMSGSIZE;
-       if (entry->l2_rewrite.vlan_id &&
-           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->l2_rewrite.vlan_id))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int
-rocker_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
-                                  const struct rocker_group_tbl_entry *entry)
-{
-       int i;
-       struct rocker_tlv *group_ids;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GROUP_COUNT,
-                              entry->group_count))
-               return -EMSGSIZE;
-
-       group_ids = rocker_tlv_nest_start(desc_info,
-                                         ROCKER_TLV_OF_DPA_GROUP_IDS);
-       if (!group_ids)
-               return -EMSGSIZE;
-
-       for (i = 0; i < entry->group_count; i++)
-               /* Note TLV array is 1-based */
-               if (rocker_tlv_put_u32(desc_info, i + 1, entry->group_ids[i]))
-                       return -EMSGSIZE;
-
-       rocker_tlv_nest_end(desc_info, group_ids);
-
-       return 0;
-}
-
-static int
-rocker_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
-                                   const struct rocker_group_tbl_entry *entry)
-{
-       if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
-                          ETH_ALEN, entry->l3_unicast.eth_src))
-               return -EMSGSIZE;
-       if (!is_zero_ether_addr(entry->l3_unicast.eth_dst) &&
-           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
-                          ETH_ALEN, entry->l3_unicast.eth_dst))
-               return -EMSGSIZE;
-       if (entry->l3_unicast.vlan_id &&
-           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
-                               entry->l3_unicast.vlan_id))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_TTL_CHECK,
-                             entry->l3_unicast.ttl_check))
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
-                              entry->l3_unicast.group_id))
-               return -EMSGSIZE;
-
-       return 0;
-}
-
-static int rocker_cmd_group_tbl_add(const struct rocker_port *rocker_port,
-                                   struct rocker_desc_info *desc_info,
-                                   void *priv)
-{
-       struct rocker_group_tbl_entry *entry = priv;
-       struct rocker_tlv *cmd_info;
-       int err = 0;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
-                              entry->group_id))
-               return -EMSGSIZE;
-
-       switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
-               err = rocker_cmd_group_tbl_add_l2_interface(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
-               err = rocker_cmd_group_tbl_add_l2_rewrite(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
-               err = rocker_cmd_group_tbl_add_group_ids(desc_info, entry);
-               break;
-       case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
-               err = rocker_cmd_group_tbl_add_l3_unicast(desc_info, entry);
-               break;
-       default:
-               err = -ENOTSUPP;
-               break;
-       }
-
-       if (err)
-               return err;
-
-       rocker_tlv_nest_end(desc_info, cmd_info);
-
-       return 0;
-}
-
-static int rocker_cmd_group_tbl_del(const struct rocker_port *rocker_port,
-                                   struct rocker_desc_info *desc_info,
-                                   void *priv)
-{
-       const struct rocker_group_tbl_entry *entry = priv;
-       struct rocker_tlv *cmd_info;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
-               return -EMSGSIZE;
-       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_info)
-               return -EMSGSIZE;
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
-                              entry->group_id))
-               return -EMSGSIZE;
-       rocker_tlv_nest_end(desc_info, cmd_info);
-
-       return 0;
-}
-
-/***************************************************
- * Flow, group, FDB, internal VLAN and neigh tables
- ***************************************************/
-
-static int rocker_init_tbls(struct rocker *rocker)
-{
-       hash_init(rocker->flow_tbl);
-       spin_lock_init(&rocker->flow_tbl_lock);
-
-       hash_init(rocker->group_tbl);
-       spin_lock_init(&rocker->group_tbl_lock);
-
-       hash_init(rocker->fdb_tbl);
-       spin_lock_init(&rocker->fdb_tbl_lock);
-
-       hash_init(rocker->internal_vlan_tbl);
-       spin_lock_init(&rocker->internal_vlan_tbl_lock);
-
-       hash_init(rocker->neigh_tbl);
-       spin_lock_init(&rocker->neigh_tbl_lock);
-
-       return 0;
-}
-
-static void rocker_free_tbls(struct rocker *rocker)
-{
-       unsigned long flags;
-       struct rocker_flow_tbl_entry *flow_entry;
-       struct rocker_group_tbl_entry *group_entry;
-       struct rocker_fdb_tbl_entry *fdb_entry;
-       struct rocker_internal_vlan_tbl_entry *internal_vlan_entry;
-       struct rocker_neigh_tbl_entry *neigh_entry;
-       struct hlist_node *tmp;
-       int bkt;
-
-       spin_lock_irqsave(&rocker->flow_tbl_lock, flags);
-       hash_for_each_safe(rocker->flow_tbl, bkt, tmp, flow_entry, entry)
-               hash_del(&flow_entry->entry);
-       spin_unlock_irqrestore(&rocker->flow_tbl_lock, flags);
-
-       spin_lock_irqsave(&rocker->group_tbl_lock, flags);
-       hash_for_each_safe(rocker->group_tbl, bkt, tmp, group_entry, entry)
-               hash_del(&group_entry->entry);
-       spin_unlock_irqrestore(&rocker->group_tbl_lock, flags);
-
-       spin_lock_irqsave(&rocker->fdb_tbl_lock, flags);
-       hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, fdb_entry, entry)
-               hash_del(&fdb_entry->entry);
-       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, flags);
-
-       spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, flags);
-       hash_for_each_safe(rocker->internal_vlan_tbl, bkt,
-                          tmp, internal_vlan_entry, entry)
-               hash_del(&internal_vlan_entry->entry);
-       spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, flags);
-
-       spin_lock_irqsave(&rocker->neigh_tbl_lock, flags);
-       hash_for_each_safe(rocker->neigh_tbl, bkt, tmp, neigh_entry, entry)
-               hash_del(&neigh_entry->entry);
-       spin_unlock_irqrestore(&rocker->neigh_tbl_lock, flags);
-}
-
-static struct rocker_flow_tbl_entry *
-rocker_flow_tbl_find(const struct rocker *rocker,
-                    const struct rocker_flow_tbl_entry *match)
-{
-       struct rocker_flow_tbl_entry *found;
-       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
-
-       hash_for_each_possible(rocker->flow_tbl, found,
-                              entry, match->key_crc32) {
-               if (memcmp(&found->key, &match->key, key_len) == 0)
-                       return found;
-       }
-
-       return NULL;
-}
-
-static int rocker_flow_tbl_add(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans, int flags,
-                              struct rocker_flow_tbl_entry *match)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_flow_tbl_entry *found;
-       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
-       unsigned long lock_flags;
-
-       match->key_crc32 = crc32(~0, &match->key, key_len);
-
-       spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
-
-       found = rocker_flow_tbl_find(rocker, match);
-
-       if (found) {
-               match->cookie = found->cookie;
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_del(&found->entry);
-               rocker_port_kfree(trans, found);
-               found = match;
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
-       } else {
-               found = match;
-               found->cookie = rocker->flow_tbl_next_cookie++;
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
-       }
-
-       if (!switchdev_trans_ph_prepare(trans))
-               hash_add(rocker->flow_tbl, &found->entry, found->key_crc32);
-
-       spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
-
-       return rocker_cmd_exec(rocker_port, trans, flags,
-                              rocker_cmd_flow_tbl_add, found, NULL, NULL);
-}
-
-static int rocker_flow_tbl_del(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans, int flags,
-                              struct rocker_flow_tbl_entry *match)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_flow_tbl_entry *found;
-       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
-       unsigned long lock_flags;
-       int err = 0;
-
-       match->key_crc32 = crc32(~0, &match->key, key_len);
-
-       spin_lock_irqsave(&rocker->flow_tbl_lock, lock_flags);
-
-       found = rocker_flow_tbl_find(rocker, match);
-
-       if (found) {
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_del(&found->entry);
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
-       }
-
-       spin_unlock_irqrestore(&rocker->flow_tbl_lock, lock_flags);
-
-       rocker_port_kfree(trans, match);
-
-       if (found) {
-               err = rocker_cmd_exec(rocker_port, trans, flags,
-                                     rocker_cmd_flow_tbl_del,
-                                     found, NULL, NULL);
-               rocker_port_kfree(trans, found);
-       }
-
-       return err;
-}
-
-static int rocker_flow_tbl_do(struct rocker_port *rocker_port,
-                             struct switchdev_trans *trans, int flags,
-                             struct rocker_flow_tbl_entry *entry)
-{
-       if (flags & ROCKER_OP_FLAG_REMOVE)
-               return rocker_flow_tbl_del(rocker_port, trans, flags, entry);
-       else
-               return rocker_flow_tbl_add(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_ig_port(struct rocker_port *rocker_port,
-                                  struct switchdev_trans *trans, int flags,
-                                  u32 in_pport, u32 in_pport_mask,
-                                  enum rocker_of_dpa_table_id goto_tbl)
-{
-       struct rocker_flow_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->key.priority = ROCKER_PRIORITY_IG_PORT;
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
-       entry->key.ig_port.in_pport = in_pport;
-       entry->key.ig_port.in_pport_mask = in_pport_mask;
-       entry->key.ig_port.goto_tbl = goto_tbl;
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_vlan(struct rocker_port *rocker_port,
-                               struct switchdev_trans *trans, int flags,
-                               u32 in_pport, __be16 vlan_id,
-                               __be16 vlan_id_mask,
-                               enum rocker_of_dpa_table_id goto_tbl,
-                               bool untagged, __be16 new_vlan_id)
-{
-       struct rocker_flow_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->key.priority = ROCKER_PRIORITY_VLAN;
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
-       entry->key.vlan.in_pport = in_pport;
-       entry->key.vlan.vlan_id = vlan_id;
-       entry->key.vlan.vlan_id_mask = vlan_id_mask;
-       entry->key.vlan.goto_tbl = goto_tbl;
-
-       entry->key.vlan.untagged = untagged;
-       entry->key.vlan.new_vlan_id = new_vlan_id;
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_term_mac(struct rocker_port *rocker_port,
-                                   struct switchdev_trans *trans,
-                                   u32 in_pport, u32 in_pport_mask,
-                                   __be16 eth_type, const u8 *eth_dst,
-                                   const u8 *eth_dst_mask, __be16 vlan_id,
-                                   __be16 vlan_id_mask, bool copy_to_cpu,
-                                   int flags)
-{
-       struct rocker_flow_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       if (is_multicast_ether_addr(eth_dst)) {
-               entry->key.priority = ROCKER_PRIORITY_TERM_MAC_MCAST;
-               entry->key.term_mac.goto_tbl =
-                        ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
-       } else {
-               entry->key.priority = ROCKER_PRIORITY_TERM_MAC_UCAST;
-               entry->key.term_mac.goto_tbl =
-                        ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
-       }
-
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
-       entry->key.term_mac.in_pport = in_pport;
-       entry->key.term_mac.in_pport_mask = in_pport_mask;
-       entry->key.term_mac.eth_type = eth_type;
-       ether_addr_copy(entry->key.term_mac.eth_dst, eth_dst);
-       ether_addr_copy(entry->key.term_mac.eth_dst_mask, eth_dst_mask);
-       entry->key.term_mac.vlan_id = vlan_id;
-       entry->key.term_mac.vlan_id_mask = vlan_id_mask;
-       entry->key.term_mac.copy_to_cpu = copy_to_cpu;
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_bridge(struct rocker_port *rocker_port,
-                                 struct switchdev_trans *trans, int flags,
-                                 const u8 *eth_dst, const u8 *eth_dst_mask,
-                                 __be16 vlan_id, u32 tunnel_id,
-                                 enum rocker_of_dpa_table_id goto_tbl,
-                                 u32 group_id, bool copy_to_cpu)
-{
-       struct rocker_flow_tbl_entry *entry;
-       u32 priority;
-       bool vlan_bridging = !!vlan_id;
-       bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
-       bool wild = false;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
-
-       if (eth_dst) {
-               entry->key.bridge.has_eth_dst = 1;
-               ether_addr_copy(entry->key.bridge.eth_dst, eth_dst);
-       }
-       if (eth_dst_mask) {
-               entry->key.bridge.has_eth_dst_mask = 1;
-               ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
-               if (!ether_addr_equal(eth_dst_mask, ff_mac))
-                       wild = true;
-       }
-
-       priority = ROCKER_PRIORITY_UNKNOWN;
-       if (vlan_bridging && dflt && wild)
-               priority = ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_WILD;
-       else if (vlan_bridging && dflt && !wild)
-               priority = ROCKER_PRIORITY_BRIDGING_VLAN_DFLT_EXACT;
-       else if (vlan_bridging && !dflt)
-               priority = ROCKER_PRIORITY_BRIDGING_VLAN;
-       else if (!vlan_bridging && dflt && wild)
-               priority = ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_WILD;
-       else if (!vlan_bridging && dflt && !wild)
-               priority = ROCKER_PRIORITY_BRIDGING_TENANT_DFLT_EXACT;
-       else if (!vlan_bridging && !dflt)
-               priority = ROCKER_PRIORITY_BRIDGING_TENANT;
-
-       entry->key.priority = priority;
-       entry->key.bridge.vlan_id = vlan_id;
-       entry->key.bridge.tunnel_id = tunnel_id;
-       entry->key.bridge.goto_tbl = goto_tbl;
-       entry->key.bridge.group_id = group_id;
-       entry->key.bridge.copy_to_cpu = copy_to_cpu;
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_ucast4_routing(struct rocker_port *rocker_port,
-                                         struct switchdev_trans *trans,
-                                         __be16 eth_type, __be32 dst,
-                                         __be32 dst_mask, u32 priority,
-                                         enum rocker_of_dpa_table_id goto_tbl,
-                                         u32 group_id, int flags)
-{
-       struct rocker_flow_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
-       entry->key.priority = priority;
-       entry->key.ucast_routing.eth_type = eth_type;
-       entry->key.ucast_routing.dst4 = dst;
-       entry->key.ucast_routing.dst4_mask = dst_mask;
-       entry->key.ucast_routing.goto_tbl = goto_tbl;
-       entry->key.ucast_routing.group_id = group_id;
-       entry->key_len = offsetof(struct rocker_flow_tbl_key,
-                                 ucast_routing.group_id);
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_flow_tbl_acl(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans, int flags,
-                              u32 in_pport, u32 in_pport_mask,
-                              const u8 *eth_src, const u8 *eth_src_mask,
-                              const u8 *eth_dst, const u8 *eth_dst_mask,
-                              __be16 eth_type, __be16 vlan_id,
-                              __be16 vlan_id_mask, u8 ip_proto,
-                              u8 ip_proto_mask, u8 ip_tos, u8 ip_tos_mask,
-                              u32 group_id)
-{
-       u32 priority;
-       struct rocker_flow_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       priority = ROCKER_PRIORITY_ACL_NORMAL;
-       if (eth_dst && eth_dst_mask) {
-               if (ether_addr_equal(eth_dst_mask, mcast_mac))
-                       priority = ROCKER_PRIORITY_ACL_DFLT;
-               else if (is_link_local_ether_addr(eth_dst))
-                       priority = ROCKER_PRIORITY_ACL_CTRL;
-       }
-
-       entry->key.priority = priority;
-       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
-       entry->key.acl.in_pport = in_pport;
-       entry->key.acl.in_pport_mask = in_pport_mask;
-
-       if (eth_src)
-               ether_addr_copy(entry->key.acl.eth_src, eth_src);
-       if (eth_src_mask)
-               ether_addr_copy(entry->key.acl.eth_src_mask, eth_src_mask);
-       if (eth_dst)
-               ether_addr_copy(entry->key.acl.eth_dst, eth_dst);
-       if (eth_dst_mask)
-               ether_addr_copy(entry->key.acl.eth_dst_mask, eth_dst_mask);
-
-       entry->key.acl.eth_type = eth_type;
-       entry->key.acl.vlan_id = vlan_id;
-       entry->key.acl.vlan_id_mask = vlan_id_mask;
-       entry->key.acl.ip_proto = ip_proto;
-       entry->key.acl.ip_proto_mask = ip_proto_mask;
-       entry->key.acl.ip_tos = ip_tos;
-       entry->key.acl.ip_tos_mask = ip_tos_mask;
-       entry->key.acl.group_id = group_id;
-
-       return rocker_flow_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static struct rocker_group_tbl_entry *
-rocker_group_tbl_find(const struct rocker *rocker,
-                     const struct rocker_group_tbl_entry *match)
-{
-       struct rocker_group_tbl_entry *found;
-
-       hash_for_each_possible(rocker->group_tbl, found,
-                              entry, match->group_id) {
-               if (found->group_id == match->group_id)
-                       return found;
-       }
-
-       return NULL;
-}
-
-static void rocker_group_tbl_entry_free(struct switchdev_trans *trans,
-                                       struct rocker_group_tbl_entry *entry)
-{
-       switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
-       case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
-               rocker_port_kfree(trans, entry->group_ids);
-               break;
-       default:
-               break;
-       }
-       rocker_port_kfree(trans, entry);
-}
-
-static int rocker_group_tbl_add(struct rocker_port *rocker_port,
-                               struct switchdev_trans *trans, int flags,
-                               struct rocker_group_tbl_entry *match)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_group_tbl_entry *found;
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
-
-       found = rocker_group_tbl_find(rocker, match);
-
-       if (found) {
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_del(&found->entry);
-               rocker_group_tbl_entry_free(trans, found);
-               found = match;
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
-       } else {
-               found = match;
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
-       }
-
-       if (!switchdev_trans_ph_prepare(trans))
-               hash_add(rocker->group_tbl, &found->entry, found->group_id);
-
-       spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
-
-       return rocker_cmd_exec(rocker_port, trans, flags,
-                              rocker_cmd_group_tbl_add, found, NULL, NULL);
-}
-
-static int rocker_group_tbl_del(struct rocker_port *rocker_port,
-                               struct switchdev_trans *trans, int flags,
-                               struct rocker_group_tbl_entry *match)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_group_tbl_entry *found;
-       unsigned long lock_flags;
-       int err = 0;
-
-       spin_lock_irqsave(&rocker->group_tbl_lock, lock_flags);
-
-       found = rocker_group_tbl_find(rocker, match);
-
-       if (found) {
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_del(&found->entry);
-               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
-       }
-
-       spin_unlock_irqrestore(&rocker->group_tbl_lock, lock_flags);
-
-       rocker_group_tbl_entry_free(trans, match);
-
-       if (found) {
-               err = rocker_cmd_exec(rocker_port, trans, flags,
-                                     rocker_cmd_group_tbl_del,
-                                     found, NULL, NULL);
-               rocker_group_tbl_entry_free(trans, found);
-       }
-
-       return err;
-}
-
-static int rocker_group_tbl_do(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans, int flags,
-                              struct rocker_group_tbl_entry *entry)
-{
-       if (flags & ROCKER_OP_FLAG_REMOVE)
-               return rocker_group_tbl_del(rocker_port, trans, flags, entry);
-       else
-               return rocker_group_tbl_add(rocker_port, trans, flags, entry);
-}
-
-static int rocker_group_l2_interface(struct rocker_port *rocker_port,
-                                    struct switchdev_trans *trans, int flags,
-                                    __be16 vlan_id, u32 out_pport,
-                                    int pop_vlan)
-{
-       struct rocker_group_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
-       entry->l2_interface.pop_vlan = pop_vlan;
-
-       return rocker_group_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_group_l2_fan_out(struct rocker_port *rocker_port,
-                                  struct switchdev_trans *trans,
-                                  int flags, u8 group_count,
-                                  const u32 *group_ids, u32 group_id)
-{
-       struct rocker_group_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->group_id = group_id;
-       entry->group_count = group_count;
-
-       entry->group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
-                                              group_count, sizeof(u32));
-       if (!entry->group_ids) {
-               rocker_port_kfree(trans, entry);
-               return -ENOMEM;
-       }
-       memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
-
-       return rocker_group_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static int rocker_group_l2_flood(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags,
-                                __be16 vlan_id, u8 group_count,
-                                const u32 *group_ids, u32 group_id)
-{
-       return rocker_group_l2_fan_out(rocker_port, trans, flags,
-                                      group_count, group_ids,
-                                      group_id);
-}
-
-static int rocker_group_l3_unicast(struct rocker_port *rocker_port,
-                                  struct switchdev_trans *trans, int flags,
-                                  u32 index, const u8 *src_mac, const u8 *dst_mac,
-                                  __be16 vlan_id, bool ttl_check, u32 pport)
-{
-       struct rocker_group_tbl_entry *entry;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       entry->group_id = ROCKER_GROUP_L3_UNICAST(index);
-       if (src_mac)
-               ether_addr_copy(entry->l3_unicast.eth_src, src_mac);
-       if (dst_mac)
-               ether_addr_copy(entry->l3_unicast.eth_dst, dst_mac);
-       entry->l3_unicast.vlan_id = vlan_id;
-       entry->l3_unicast.ttl_check = ttl_check;
-       entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
-
-       return rocker_group_tbl_do(rocker_port, trans, flags, entry);
-}
-
-static struct rocker_neigh_tbl_entry *
-rocker_neigh_tbl_find(const struct rocker *rocker, __be32 ip_addr)
-{
-       struct rocker_neigh_tbl_entry *found;
-
-       hash_for_each_possible(rocker->neigh_tbl, found,
-                              entry, be32_to_cpu(ip_addr))
-               if (found->ip_addr == ip_addr)
-                       return found;
-
-       return NULL;
-}
-
-static void _rocker_neigh_add(struct rocker *rocker,
-                             struct switchdev_trans *trans,
-                             struct rocker_neigh_tbl_entry *entry)
-{
-       if (!switchdev_trans_ph_commit(trans))
-               entry->index = rocker->neigh_tbl_next_index++;
-       if (switchdev_trans_ph_prepare(trans))
-               return;
-       entry->ref_count++;
-       hash_add(rocker->neigh_tbl, &entry->entry,
-                be32_to_cpu(entry->ip_addr));
-}
-
-static void _rocker_neigh_del(struct switchdev_trans *trans,
-                             struct rocker_neigh_tbl_entry *entry)
-{
-       if (switchdev_trans_ph_prepare(trans))
-               return;
-       if (--entry->ref_count == 0) {
-               hash_del(&entry->entry);
-               rocker_port_kfree(trans, entry);
-       }
-}
-
-static void _rocker_neigh_update(struct rocker_neigh_tbl_entry *entry,
-                                struct switchdev_trans *trans,
-                                const u8 *eth_dst, bool ttl_check)
-{
-       if (eth_dst) {
-               ether_addr_copy(entry->eth_dst, eth_dst);
-               entry->ttl_check = ttl_check;
-       } else if (!switchdev_trans_ph_prepare(trans)) {
-               entry->ref_count++;
-       }
-}
-
-static int rocker_port_ipv4_neigh(struct rocker_port *rocker_port,
-                                 struct switchdev_trans *trans,
-                                 int flags, __be32 ip_addr, const u8 *eth_dst)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_neigh_tbl_entry *entry;
-       struct rocker_neigh_tbl_entry *found;
-       unsigned long lock_flags;
-       __be16 eth_type = htons(ETH_P_IP);
-       enum rocker_of_dpa_table_id goto_tbl =
-               ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
-       u32 group_id;
-       u32 priority = 0;
-       bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
-       bool updating;
-       bool removing;
-       int err = 0;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&rocker->neigh_tbl_lock, lock_flags);
-
-       found = rocker_neigh_tbl_find(rocker, ip_addr);
-
-       updating = found && adding;
-       removing = found && !adding;
-       adding = !found && adding;
-
-       if (adding) {
-               entry->ip_addr = ip_addr;
-               entry->dev = rocker_port->dev;
-               ether_addr_copy(entry->eth_dst, eth_dst);
-               entry->ttl_check = true;
-               _rocker_neigh_add(rocker, trans, entry);
-       } else if (removing) {
-               memcpy(entry, found, sizeof(*entry));
-               _rocker_neigh_del(trans, found);
-       } else if (updating) {
-               _rocker_neigh_update(found, trans, eth_dst, true);
-               memcpy(entry, found, sizeof(*entry));
-       } else {
-               err = -ENOENT;
-       }
-
-       spin_unlock_irqrestore(&rocker->neigh_tbl_lock, lock_flags);
-
-       if (err)
-               goto err_out;
-
-       /* For each active neighbor, we have an L3 unicast group and
-        * a /32 route to the neighbor, which uses the L3 unicast
-        * group.  The L3 unicast group can also be referred to by
-        * other routes' nexthops.
-        */
-
-       err = rocker_group_l3_unicast(rocker_port, trans, flags,
-                                     entry->index,
-                                     rocker_port->dev->dev_addr,
-                                     entry->eth_dst,
-                                     rocker_port->internal_vlan_id,
-                                     entry->ttl_check,
-                                     rocker_port->pport);
-       if (err) {
-               netdev_err(rocker_port->dev,
-                          "Error (%d) L3 unicast group index %d\n",
-                          err, entry->index);
-               goto err_out;
-       }
-
-       if (adding || removing) {
-               group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
-               err = rocker_flow_tbl_ucast4_routing(rocker_port, trans,
-                                                    eth_type, ip_addr,
-                                                    inet_make_mask(32),
-                                                    priority, goto_tbl,
-                                                    group_id, flags);
-
-               if (err)
-                       netdev_err(rocker_port->dev,
-                                  "Error (%d) /32 unicast route %pI4 group 0x%08x\n",
-                                  err, &entry->ip_addr, group_id);
-       }
-
-err_out:
-       if (!adding)
-               rocker_port_kfree(trans, entry);
-
-       return err;
-}
-
-static int rocker_port_ipv4_resolve(struct rocker_port *rocker_port,
-                                   struct switchdev_trans *trans,
-                                   __be32 ip_addr)
-{
-       struct net_device *dev = rocker_port->dev;
-       struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
-       int err = 0;
-
-       if (!n) {
-               n = neigh_create(&arp_tbl, &ip_addr, dev);
-               if (IS_ERR(n))
-                       return IS_ERR(n);
-       }
-
-       /* If the neigh is already resolved, then go ahead and
-        * install the entry, otherwise start the ARP process to
-        * resolve the neigh.
-        */
-
-       if (n->nud_state & NUD_VALID)
-               err = rocker_port_ipv4_neigh(rocker_port, trans, 0,
-                                            ip_addr, n->ha);
-       else
-               neigh_event_send(n, NULL);
-
-       neigh_release(n);
-       return err;
-}
-
-static int rocker_port_ipv4_nh(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans, int flags,
-                              __be32 ip_addr, u32 *index)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_neigh_tbl_entry *entry;
-       struct rocker_neigh_tbl_entry *found;
-       unsigned long lock_flags;
-       bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
-       bool updating;
-       bool removing;
-       bool resolved = true;
-       int err = 0;
-
-       entry = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*entry));
-       if (!entry)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&rocker->neigh_tbl_lock, lock_flags);
-
-       found = rocker_neigh_tbl_find(rocker, ip_addr);
-       if (found)
-               *index = found->index;
-
-       updating = found && adding;
-       removing = found && !adding;
-       adding = !found && adding;
-
-       if (adding) {
-               entry->ip_addr = ip_addr;
-               entry->dev = rocker_port->dev;
-               _rocker_neigh_add(rocker, trans, entry);
-               *index = entry->index;
-               resolved = false;
-       } else if (removing) {
-               _rocker_neigh_del(trans, found);
-       } else if (updating) {
-               _rocker_neigh_update(found, trans, NULL, false);
-               resolved = !is_zero_ether_addr(found->eth_dst);
-       } else {
-               err = -ENOENT;
-       }
-
-       spin_unlock_irqrestore(&rocker->neigh_tbl_lock, lock_flags);
-
-       if (!adding)
-               rocker_port_kfree(trans, entry);
-
-       if (err)
-               return err;
-
-       /* Resolved means neigh ip_addr is resolved to neigh mac. */
-
-       if (!resolved)
-               err = rocker_port_ipv4_resolve(rocker_port, trans, ip_addr);
-
-       return err;
-}
-
-static int rocker_port_vlan_flood_group(struct rocker_port *rocker_port,
-                                       struct switchdev_trans *trans,
-                                       int flags, __be16 vlan_id)
-{
-       struct rocker_port *p;
-       const struct rocker *rocker = rocker_port->rocker;
-       u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
-       u32 *group_ids;
-       u8 group_count = 0;
-       int err = 0;
-       int i;
-
-       group_ids = rocker_port_kcalloc(rocker_port, trans, flags,
-                                       rocker->port_count, sizeof(u32));
-       if (!group_ids)
-               return -ENOMEM;
-
-       /* Adjust the flood group for this VLAN.  The flood group
-        * references an L2 interface group for each port in this
-        * VLAN.
-        */
-
-       for (i = 0; i < rocker->port_count; i++) {
-               p = rocker->ports[i];
-               if (!p)
-                       continue;
-               if (!rocker_port_is_bridged(p))
-                       continue;
-               if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
-                       group_ids[group_count++] =
-                               ROCKER_GROUP_L2_INTERFACE(vlan_id, p->pport);
-               }
-       }
-
-       /* If there are no bridged ports in this VLAN, we're done */
-       if (group_count == 0)
-               goto no_ports_in_vlan;
-
-       err = rocker_group_l2_flood(rocker_port, trans, flags, vlan_id,
-                                   group_count, group_ids, group_id);
-       if (err)
-               netdev_err(rocker_port->dev,
-                          "Error (%d) port VLAN l2 flood group\n", err);
-
-no_ports_in_vlan:
-       rocker_port_kfree(trans, group_ids);
-       return err;
-}
-
-static int rocker_port_vlan_l2_groups(struct rocker_port *rocker_port,
-                                     struct switchdev_trans *trans, int flags,
-                                     __be16 vlan_id, bool pop_vlan)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       struct rocker_port *p;
-       bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
-       u32 out_pport;
-       int ref = 0;
-       int err;
-       int i;
-
-       /* An L2 interface group for this port in this VLAN, but
-        * only when port STP state is LEARNING|FORWARDING.
-        */
-
-       if (rocker_port->stp_state == BR_STATE_LEARNING ||
-           rocker_port->stp_state == BR_STATE_FORWARDING) {
-               out_pport = rocker_port->pport;
-               err = rocker_group_l2_interface(rocker_port, trans, flags,
-                                               vlan_id, out_pport, pop_vlan);
-               if (err) {
-                       netdev_err(rocker_port->dev,
-                                  "Error (%d) port VLAN l2 group for pport %d\n",
-                                  err, out_pport);
-                       return err;
-               }
-       }
-
-       /* An L2 interface group for this VLAN to CPU port.
-        * Add when first port joins this VLAN and destroy when
-        * last port leaves this VLAN.
-        */
-
-       for (i = 0; i < rocker->port_count; i++) {
-               p = rocker->ports[i];
-               if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
-                       ref++;
-       }
-
-       if ((!adding || ref != 1) && (adding || ref != 0))
-               return 0;
-
-       out_pport = 0;
-       err = rocker_group_l2_interface(rocker_port, trans, flags,
-                                       vlan_id, out_pport, pop_vlan);
-       if (err) {
-               netdev_err(rocker_port->dev,
-                          "Error (%d) port VLAN l2 group for CPU port\n", err);
-               return err;
-       }
-
-       return 0;
-}
-
-static struct rocker_ctrl {
-       const u8 *eth_dst;
-       const u8 *eth_dst_mask;
-       __be16 eth_type;
-       bool acl;
-       bool bridge;
-       bool term;
-       bool copy_to_cpu;
-} rocker_ctrls[] = {
-       [ROCKER_CTRL_LINK_LOCAL_MCAST] = {
-               /* pass link local multicast pkts up to CPU for filtering */
-               .eth_dst = ll_mac,
-               .eth_dst_mask = ll_mask,
-               .acl = true,
-       },
-       [ROCKER_CTRL_LOCAL_ARP] = {
-               /* pass local ARP pkts up to CPU */
-               .eth_dst = zero_mac,
-               .eth_dst_mask = zero_mac,
-               .eth_type = htons(ETH_P_ARP),
-               .acl = true,
-       },
-       [ROCKER_CTRL_IPV4_MCAST] = {
-               /* pass IPv4 mcast pkts up to CPU, RFC 1112 */
-               .eth_dst = ipv4_mcast,
-               .eth_dst_mask = ipv4_mask,
-               .eth_type = htons(ETH_P_IP),
-               .term  = true,
-               .copy_to_cpu = true,
-       },
-       [ROCKER_CTRL_IPV6_MCAST] = {
-               /* pass IPv6 mcast pkts up to CPU, RFC 2464 */
-               .eth_dst = ipv6_mcast,
-               .eth_dst_mask = ipv6_mask,
-               .eth_type = htons(ETH_P_IPV6),
-               .term  = true,
-               .copy_to_cpu = true,
-       },
-       [ROCKER_CTRL_DFLT_BRIDGING] = {
-               /* flood any pkts on vlan */
-               .bridge = true,
-               .copy_to_cpu = true,
-       },
-       [ROCKER_CTRL_DFLT_OVS] = {
-               /* pass all pkts up to CPU */
-               .eth_dst = zero_mac,
-               .eth_dst_mask = zero_mac,
-               .acl = true,
-       },
-};
-
-static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port,
-                                    struct switchdev_trans *trans, int flags,
-                                    const struct rocker_ctrl *ctrl, __be16 vlan_id)
-{
-       u32 in_pport = rocker_port->pport;
-       u32 in_pport_mask = 0xffffffff;
-       u32 out_pport = 0;
-       const u8 *eth_src = NULL;
-       const u8 *eth_src_mask = NULL;
-       __be16 vlan_id_mask = htons(0xffff);
-       u8 ip_proto = 0;
-       u8 ip_proto_mask = 0;
-       u8 ip_tos = 0;
-       u8 ip_tos_mask = 0;
-       u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
-       int err;
-
-       err = rocker_flow_tbl_acl(rocker_port, trans, flags,
-                                 in_pport, in_pport_mask,
-                                 eth_src, eth_src_mask,
-                                 ctrl->eth_dst, ctrl->eth_dst_mask,
-                                 ctrl->eth_type,
-                                 vlan_id, vlan_id_mask,
-                                 ip_proto, ip_proto_mask,
-                                 ip_tos, ip_tos_mask,
-                                 group_id);
-
-       if (err)
-               netdev_err(rocker_port->dev, "Error (%d) ctrl ACL\n", err);
-
-       return err;
-}
-
-static int rocker_port_ctrl_vlan_bridge(struct rocker_port *rocker_port,
-                                       struct switchdev_trans *trans,
-                                       int flags,
-                                       const struct rocker_ctrl *ctrl,
-                                       __be16 vlan_id)
-{
-       enum rocker_of_dpa_table_id goto_tbl =
-               ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
-       u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
-       u32 tunnel_id = 0;
-       int err;
-
-       if (!rocker_port_is_bridged(rocker_port))
-               return 0;
-
-       err = rocker_flow_tbl_bridge(rocker_port, trans, flags,
-                                    ctrl->eth_dst, ctrl->eth_dst_mask,
-                                    vlan_id, tunnel_id,
-                                    goto_tbl, group_id, ctrl->copy_to_cpu);
-
-       if (err)
-               netdev_err(rocker_port->dev, "Error (%d) ctrl FLOOD\n", err);
-
-       return err;
-}
-
-static int rocker_port_ctrl_vlan_term(struct rocker_port *rocker_port,
-                                     struct switchdev_trans *trans, int flags,
-                                     const struct rocker_ctrl *ctrl, __be16 vlan_id)
-{
-       u32 in_pport_mask = 0xffffffff;
-       __be16 vlan_id_mask = htons(0xffff);
-       int err;
-
-       if (ntohs(vlan_id) == 0)
-               vlan_id = rocker_port->internal_vlan_id;
-
-       err = rocker_flow_tbl_term_mac(rocker_port, trans,
-                                      rocker_port->pport, in_pport_mask,
-                                      ctrl->eth_type, ctrl->eth_dst,
-                                      ctrl->eth_dst_mask, vlan_id,
-                                      vlan_id_mask, ctrl->copy_to_cpu,
-                                      flags);
-
-       if (err)
-               netdev_err(rocker_port->dev, "Error (%d) ctrl term\n", err);
-
-       return err;
-}
-
-static int rocker_port_ctrl_vlan(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags,
-                                const struct rocker_ctrl *ctrl, __be16 vlan_id)
-{
-       if (ctrl->acl)
-               return rocker_port_ctrl_vlan_acl(rocker_port, trans, flags,
-                                                ctrl, vlan_id);
-       if (ctrl->bridge)
-               return rocker_port_ctrl_vlan_bridge(rocker_port, trans, flags,
-                                                   ctrl, vlan_id);
-
-       if (ctrl->term)
-               return rocker_port_ctrl_vlan_term(rocker_port, trans, flags,
-                                                 ctrl, vlan_id);
-
-       return -EOPNOTSUPP;
-}
-
-static int rocker_port_ctrl_vlan_add(struct rocker_port *rocker_port,
-                                    struct switchdev_trans *trans, int flags,
-                                    __be16 vlan_id)
-{
-       int err = 0;
-       int i;
-
-       for (i = 0; i < ROCKER_CTRL_MAX; i++) {
-               if (rocker_port->ctrls[i]) {
-                       err = rocker_port_ctrl_vlan(rocker_port, trans, flags,
-                                                   &rocker_ctrls[i], vlan_id);
-                       if (err)
-                               return err;
-               }
-       }
-
-       return err;
-}
-
-static int rocker_port_ctrl(struct rocker_port *rocker_port,
-                           struct switchdev_trans *trans, int flags,
-                           const struct rocker_ctrl *ctrl)
-{
-       u16 vid;
-       int err = 0;
-
-       for (vid = 1; vid < VLAN_N_VID; vid++) {
-               if (!test_bit(vid, rocker_port->vlan_bitmap))
-                       continue;
-               err = rocker_port_ctrl_vlan(rocker_port, trans, flags,
-                                           ctrl, htons(vid));
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
-static int rocker_port_vlan(struct rocker_port *rocker_port,
-                           struct switchdev_trans *trans, int flags, u16 vid)
-{
-       enum rocker_of_dpa_table_id goto_tbl =
-               ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
-       u32 in_pport = rocker_port->pport;
-       __be16 vlan_id = htons(vid);
-       __be16 vlan_id_mask = htons(0xffff);
-       __be16 internal_vlan_id;
-       bool untagged;
-       bool adding = !(flags & ROCKER_OP_FLAG_REMOVE);
-       int err;
-
-       internal_vlan_id = rocker_port_vid_to_vlan(rocker_port, vid, &untagged);
-
-       if (adding && test_bit(ntohs(internal_vlan_id),
-                              rocker_port->vlan_bitmap))
-                       return 0; /* already added */
-       else if (!adding && !test_bit(ntohs(internal_vlan_id),
-                                     rocker_port->vlan_bitmap))
-                       return 0; /* already removed */
-
-       change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
-
-       if (adding) {
-               err = rocker_port_ctrl_vlan_add(rocker_port, trans, flags,
-                                               internal_vlan_id);
-               if (err) {
-                       netdev_err(rocker_port->dev,
-                                  "Error (%d) port ctrl vlan add\n", err);
-                       goto err_out;
-               }
-       }
-
-       err = rocker_port_vlan_l2_groups(rocker_port, trans, flags,
-                                        internal_vlan_id, untagged);
-       if (err) {
-               netdev_err(rocker_port->dev,
-                          "Error (%d) port VLAN l2 groups\n", err);
-               goto err_out;
-       }
-
-       err = rocker_port_vlan_flood_group(rocker_port, trans, flags,
-                                          internal_vlan_id);
-       if (err) {
-               netdev_err(rocker_port->dev,
-                          "Error (%d) port VLAN l2 flood group\n", err);
-               goto err_out;
-       }
-
-       err = rocker_flow_tbl_vlan(rocker_port, trans, flags,
-                                  in_pport, vlan_id, vlan_id_mask,
-                                  goto_tbl, untagged, internal_vlan_id);
-       if (err)
-               netdev_err(rocker_port->dev,
-                          "Error (%d) port VLAN table\n", err);
-
-err_out:
-       if (switchdev_trans_ph_prepare(trans))
-               change_bit(ntohs(internal_vlan_id), rocker_port->vlan_bitmap);
-
-       return err;
-}
-
-static int rocker_port_ig_tbl(struct rocker_port *rocker_port,
-                             struct switchdev_trans *trans, int flags)
-{
-       enum rocker_of_dpa_table_id goto_tbl;
-       u32 in_pport;
-       u32 in_pport_mask;
-       int err;
-
-       /* Normal Ethernet Frames.  Matches pkts from any local physical
-        * ports.  Goto VLAN tbl.
-        */
-
-       in_pport = 0;
-       in_pport_mask = 0xffff0000;
-       goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
-
-       err = rocker_flow_tbl_ig_port(rocker_port, trans, flags,
-                                     in_pport, in_pport_mask,
-                                     goto_tbl);
-       if (err)
-               netdev_err(rocker_port->dev,
-                          "Error (%d) ingress port table entry\n", err);
-
-       return err;
-}
-
-struct rocker_fdb_learn_work {
-       struct work_struct work;
-       struct rocker_port *rocker_port;
-       struct switchdev_trans *trans;
-       int flags;
-       u8 addr[ETH_ALEN];
-       u16 vid;
-};
-
-static void rocker_port_fdb_learn_work(struct work_struct *work)
-{
-       const struct rocker_fdb_learn_work *lw =
-               container_of(work, struct rocker_fdb_learn_work, work);
-       bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE);
-       bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED);
-       struct switchdev_notifier_fdb_info info;
-
-       info.addr = lw->addr;
-       info.vid = lw->vid;
-
-       rtnl_lock();
-       if (learned && removing)
-               call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
-                                        lw->rocker_port->dev, &info.info);
-       else if (learned && !removing)
-               call_switchdev_notifiers(SWITCHDEV_FDB_ADD,
-                                        lw->rocker_port->dev, &info.info);
-       rtnl_unlock();
-
-       rocker_port_kfree(lw->trans, work);
-}
-
-static int rocker_port_fdb_learn(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags,
-                                const u8 *addr, __be16 vlan_id)
-{
-       struct rocker_fdb_learn_work *lw;
-       enum rocker_of_dpa_table_id goto_tbl =
-               ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
-       u32 out_pport = rocker_port->pport;
-       u32 tunnel_id = 0;
-       u32 group_id = ROCKER_GROUP_NONE;
-       bool syncing = !!(rocker_port->brport_flags & BR_LEARNING_SYNC);
-       bool copy_to_cpu = false;
-       int err;
-
-       if (rocker_port_is_bridged(rocker_port))
-               group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
-
-       if (!(flags & ROCKER_OP_FLAG_REFRESH)) {
-               err = rocker_flow_tbl_bridge(rocker_port, trans, flags, addr,
-                                            NULL, vlan_id, tunnel_id, goto_tbl,
-                                            group_id, copy_to_cpu);
-               if (err)
-                       return err;
-       }
-
-       if (!syncing)
-               return 0;
-
-       if (!rocker_port_is_bridged(rocker_port))
-               return 0;
-
-       lw = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*lw));
-       if (!lw)
-               return -ENOMEM;
-
-       INIT_WORK(&lw->work, rocker_port_fdb_learn_work);
-
-       lw->rocker_port = rocker_port;
-       lw->trans = trans;
-       lw->flags = flags;
-       ether_addr_copy(lw->addr, addr);
-       lw->vid = rocker_port_vlan_to_vid(rocker_port, vlan_id);
-
-       if (switchdev_trans_ph_prepare(trans))
-               rocker_port_kfree(trans, lw);
-       else
-               schedule_work(&lw->work);
-
-       return 0;
-}
-
-static struct rocker_fdb_tbl_entry *
-rocker_fdb_tbl_find(const struct rocker *rocker,
-                   const struct rocker_fdb_tbl_entry *match)
-{
-       struct rocker_fdb_tbl_entry *found;
-
-       hash_for_each_possible(rocker->fdb_tbl, found, entry, match->key_crc32)
-               if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
-                       return found;
-
-       return NULL;
-}
-
-static int rocker_port_fdb(struct rocker_port *rocker_port,
-                          struct switchdev_trans *trans,
-                          const unsigned char *addr,
-                          __be16 vlan_id, int flags)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_fdb_tbl_entry *fdb;
-       struct rocker_fdb_tbl_entry *found;
-       bool removing = (flags & ROCKER_OP_FLAG_REMOVE);
-       unsigned long lock_flags;
-
-       fdb = rocker_port_kzalloc(rocker_port, trans, flags, sizeof(*fdb));
-       if (!fdb)
-               return -ENOMEM;
-
-       fdb->learned = (flags & ROCKER_OP_FLAG_LEARNED);
-       fdb->touched = jiffies;
-       fdb->key.rocker_port = rocker_port;
-       ether_addr_copy(fdb->key.addr, addr);
-       fdb->key.vlan_id = vlan_id;
-       fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
-
-       spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
-
-       found = rocker_fdb_tbl_find(rocker, fdb);
-
-       if (found) {
-               found->touched = jiffies;
-               if (removing) {
-                       rocker_port_kfree(trans, fdb);
-                       if (!switchdev_trans_ph_prepare(trans))
-                               hash_del(&found->entry);
-               }
-       } else if (!removing) {
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_add(rocker->fdb_tbl, &fdb->entry,
-                                fdb->key_crc32);
-       }
-
-       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
-
-       /* Check if adding and already exists, or removing and can't find */
-       if (!found != !removing) {
-               rocker_port_kfree(trans, fdb);
-               if (!found && removing)
-                       return 0;
-               /* Refreshing existing to update aging timers */
-               flags |= ROCKER_OP_FLAG_REFRESH;
-       }
-
-       return rocker_port_fdb_learn(rocker_port, trans, flags, addr, vlan_id);
-}
-
-static int rocker_port_fdb_flush(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans, int flags)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_fdb_tbl_entry *found;
-       unsigned long lock_flags;
-       struct hlist_node *tmp;
-       int bkt;
-       int err = 0;
-
-       if (rocker_port->stp_state == BR_STATE_LEARNING ||
-           rocker_port->stp_state == BR_STATE_FORWARDING)
-               return 0;
-
-       flags |= ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE;
-
-       spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
-
-       hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
-               if (found->key.rocker_port != rocker_port)
-                       continue;
-               if (!found->learned)
-                       continue;
-               err = rocker_port_fdb_learn(rocker_port, trans, flags,
-                                           found->key.addr,
-                                           found->key.vlan_id);
-               if (err)
-                       goto err_out;
-               if (!switchdev_trans_ph_prepare(trans))
-                       hash_del(&found->entry);
-       }
-
-err_out:
-       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
-
-       return err;
-}
-
-static void rocker_fdb_cleanup(unsigned long data)
-{
-       struct rocker *rocker = (struct rocker *)data;
-       struct rocker_port *rocker_port;
-       struct rocker_fdb_tbl_entry *entry;
-       struct hlist_node *tmp;
-       unsigned long next_timer = jiffies + BR_MIN_AGEING_TIME;
-       unsigned long expires;
-       unsigned long lock_flags;
-       int flags = ROCKER_OP_FLAG_NOWAIT | ROCKER_OP_FLAG_REMOVE |
-                   ROCKER_OP_FLAG_LEARNED;
-       int bkt;
-
-       spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
-
-       hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, entry, entry) {
-               if (!entry->learned)
-                       continue;
-               rocker_port = entry->key.rocker_port;
-               expires = entry->touched + rocker_port->ageing_time;
-               if (time_before_eq(expires, jiffies)) {
-                       rocker_port_fdb_learn(rocker_port, NULL,
-                                             flags, entry->key.addr,
-                                             entry->key.vlan_id);
-                       hash_del(&entry->entry);
-               } else if (time_before(expires, next_timer)) {
-                       next_timer = expires;
-               }
-       }
-
-       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
-
-       mod_timer(&rocker->fdb_cleanup_timer, round_jiffies_up(next_timer));
-}
-
-static int rocker_port_router_mac(struct rocker_port *rocker_port,
-                                 struct switchdev_trans *trans, int flags,
-                                 __be16 vlan_id)
-{
-       u32 in_pport_mask = 0xffffffff;
-       __be16 eth_type;
-       const u8 *dst_mac_mask = ff_mac;
-       __be16 vlan_id_mask = htons(0xffff);
-       bool copy_to_cpu = false;
-       int err;
-
-       if (ntohs(vlan_id) == 0)
-               vlan_id = rocker_port->internal_vlan_id;
-
-       eth_type = htons(ETH_P_IP);
-       err = rocker_flow_tbl_term_mac(rocker_port, trans,
-                                      rocker_port->pport, in_pport_mask,
-                                      eth_type, rocker_port->dev->dev_addr,
-                                      dst_mac_mask, vlan_id, vlan_id_mask,
-                                      copy_to_cpu, flags);
-       if (err)
-               return err;
-
-       eth_type = htons(ETH_P_IPV6);
-       err = rocker_flow_tbl_term_mac(rocker_port, trans,
-                                      rocker_port->pport, in_pport_mask,
-                                      eth_type, rocker_port->dev->dev_addr,
-                                      dst_mac_mask, vlan_id, vlan_id_mask,
-                                      copy_to_cpu, flags);
-
-       return err;
-}
-
-static int rocker_port_fwding(struct rocker_port *rocker_port,
-                             struct switchdev_trans *trans, int flags)
-{
-       bool pop_vlan;
-       u32 out_pport;
-       __be16 vlan_id;
-       u16 vid;
-       int err;
-
-       /* Port will be forwarding-enabled if its STP state is LEARNING
-        * or FORWARDING.  Traffic from CPU can still egress, regardless of
-        * port STP state.  Use L2 interface group on port VLANs as a way
-        * to toggle port forwarding: if forwarding is disabled, L2
-        * interface group will not exist.
-        */
-
-       if (rocker_port->stp_state != BR_STATE_LEARNING &&
-           rocker_port->stp_state != BR_STATE_FORWARDING)
-               flags |= ROCKER_OP_FLAG_REMOVE;
-
-       out_pport = rocker_port->pport;
-       for (vid = 1; vid < VLAN_N_VID; vid++) {
-               if (!test_bit(vid, rocker_port->vlan_bitmap))
-                       continue;
-               vlan_id = htons(vid);
-               pop_vlan = rocker_vlan_id_is_internal(vlan_id);
-               err = rocker_group_l2_interface(rocker_port, trans, flags,
-                                               vlan_id, out_pport, pop_vlan);
-               if (err) {
-                       netdev_err(rocker_port->dev,
-                                  "Error (%d) port VLAN l2 group for pport %d\n",
-                                  err, out_pport);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static int rocker_port_stp_update(struct rocker_port *rocker_port,
-                                 struct switchdev_trans *trans, int flags,
-                                 u8 state)
-{
-       bool want[ROCKER_CTRL_MAX] = { 0, };
-       bool prev_ctrls[ROCKER_CTRL_MAX];
-       u8 uninitialized_var(prev_state);
-       int err;
-       int i;
-
-       if (switchdev_trans_ph_prepare(trans)) {
-               memcpy(prev_ctrls, rocker_port->ctrls, sizeof(prev_ctrls));
-               prev_state = rocker_port->stp_state;
-       }
-
-       if (rocker_port->stp_state == state)
-               return 0;
-
-       rocker_port->stp_state = state;
-
-       switch (state) {
-       case BR_STATE_DISABLED:
-               /* port is completely disabled */
-               break;
-       case BR_STATE_LISTENING:
-       case BR_STATE_BLOCKING:
-               want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true;
-               break;
-       case BR_STATE_LEARNING:
-       case BR_STATE_FORWARDING:
-               if (!rocker_port_is_ovsed(rocker_port))
-                       want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true;
-               want[ROCKER_CTRL_IPV4_MCAST] = true;
-               want[ROCKER_CTRL_IPV6_MCAST] = true;
-               if (rocker_port_is_bridged(rocker_port))
-                       want[ROCKER_CTRL_DFLT_BRIDGING] = true;
-               else if (rocker_port_is_ovsed(rocker_port))
-                       want[ROCKER_CTRL_DFLT_OVS] = true;
-               else
-                       want[ROCKER_CTRL_LOCAL_ARP] = true;
-               break;
-       }
-
-       for (i = 0; i < ROCKER_CTRL_MAX; i++) {
-               if (want[i] != rocker_port->ctrls[i]) {
-                       int ctrl_flags = flags |
-                                        (want[i] ? 0 : ROCKER_OP_FLAG_REMOVE);
-                       err = rocker_port_ctrl(rocker_port, trans, ctrl_flags,
-                                              &rocker_ctrls[i]);
-                       if (err)
-                               goto err_out;
-                       rocker_port->ctrls[i] = want[i];
-               }
-       }
-
-       err = rocker_port_fdb_flush(rocker_port, trans, flags);
-       if (err)
-               goto err_out;
-
-       err = rocker_port_fwding(rocker_port, trans, flags);
-
-err_out:
-       if (switchdev_trans_ph_prepare(trans)) {
-               memcpy(rocker_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
-               rocker_port->stp_state = prev_state;
-       }
-
-       return err;
-}
-
-static int rocker_port_fwd_enable(struct rocker_port *rocker_port,
-                                 struct switchdev_trans *trans, int flags)
-{
-       if (rocker_port_is_bridged(rocker_port))
-               /* bridge STP will enable port */
-               return 0;
-
-       /* port is not bridged, so simulate going to FORWARDING state */
-       return rocker_port_stp_update(rocker_port, trans, flags,
-                                     BR_STATE_FORWARDING);
-}
-
-static int rocker_port_fwd_disable(struct rocker_port *rocker_port,
-                                  struct switchdev_trans *trans, int flags)
-{
-       if (rocker_port_is_bridged(rocker_port))
-               /* bridge STP will disable port */
-               return 0;
-
-       /* port is not bridged, so simulate going to DISABLED state */
-       return rocker_port_stp_update(rocker_port, trans, flags,
-                                     BR_STATE_DISABLED);
-}
-
-static struct rocker_internal_vlan_tbl_entry *
-rocker_internal_vlan_tbl_find(const struct rocker *rocker, int ifindex)
-{
-       struct rocker_internal_vlan_tbl_entry *found;
-
-       hash_for_each_possible(rocker->internal_vlan_tbl, found,
-                              entry, ifindex) {
-               if (found->ifindex == ifindex)
-                       return found;
-       }
-
-       return NULL;
-}
-
-static __be16 rocker_port_internal_vlan_id_get(struct rocker_port *rocker_port,
-                                              int ifindex)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_internal_vlan_tbl_entry *entry;
-       struct rocker_internal_vlan_tbl_entry *found;
-       unsigned long lock_flags;
-       int i;
-
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry)
-               return 0;
-
-       entry->ifindex = ifindex;
-
-       spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, lock_flags);
-
-       found = rocker_internal_vlan_tbl_find(rocker, ifindex);
-       if (found) {
-               kfree(entry);
-               goto found;
-       }
-
-       found = entry;
-       hash_add(rocker->internal_vlan_tbl, &found->entry, found->ifindex);
-
-       for (i = 0; i < ROCKER_N_INTERNAL_VLANS; i++) {
-               if (test_and_set_bit(i, rocker->internal_vlan_bitmap))
-                       continue;
-               found->vlan_id = htons(ROCKER_INTERNAL_VLAN_ID_BASE + i);
-               goto found;
-       }
-
-       netdev_err(rocker_port->dev, "Out of internal VLAN IDs\n");
-
-found:
-       found->ref_count++;
-       spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, lock_flags);
-
-       return found->vlan_id;
-}
-
-static void
-rocker_port_internal_vlan_id_put(const struct rocker_port *rocker_port,
-                                int ifindex)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_internal_vlan_tbl_entry *found;
-       unsigned long lock_flags;
-       unsigned long bit;
-
-       spin_lock_irqsave(&rocker->internal_vlan_tbl_lock, lock_flags);
-
-       found = rocker_internal_vlan_tbl_find(rocker, ifindex);
-       if (!found) {
-               netdev_err(rocker_port->dev,
-                          "ifindex (%d) not found in internal VLAN tbl\n",
-                          ifindex);
-               goto not_found;
-       }
-
-       if (--found->ref_count <= 0) {
-               bit = ntohs(found->vlan_id) - ROCKER_INTERNAL_VLAN_ID_BASE;
-               clear_bit(bit, rocker->internal_vlan_bitmap);
-               hash_del(&found->entry);
-               kfree(found);
-       }
-
-not_found:
-       spin_unlock_irqrestore(&rocker->internal_vlan_tbl_lock, lock_flags);
-}
-
-static int rocker_port_fib_ipv4(struct rocker_port *rocker_port,
-                               struct switchdev_trans *trans, __be32 dst,
-                               int dst_len, const struct fib_info *fi,
-                               u32 tb_id, int flags)
-{
-       const struct fib_nh *nh;
-       __be16 eth_type = htons(ETH_P_IP);
-       __be32 dst_mask = inet_make_mask(dst_len);
-       __be16 internal_vlan_id = rocker_port->internal_vlan_id;
-       u32 priority = fi->fib_priority;
-       enum rocker_of_dpa_table_id goto_tbl =
-               ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
-       u32 group_id;
-       bool nh_on_port;
-       bool has_gw;
-       u32 index;
-       int err;
-
-       /* XXX support ECMP */
-
-       nh = fi->fib_nh;
-       nh_on_port = (fi->fib_dev == rocker_port->dev);
-       has_gw = !!nh->nh_gw;
-
-       if (has_gw && nh_on_port) {
-               err = rocker_port_ipv4_nh(rocker_port, trans, flags,
-                                         nh->nh_gw, &index);
-               if (err)
-                       return err;
-
-               group_id = ROCKER_GROUP_L3_UNICAST(index);
-       } else {
-               /* Send to CPU for processing */
-               group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
-       }
-
-       err = rocker_flow_tbl_ucast4_routing(rocker_port, trans, eth_type, dst,
-                                            dst_mask, priority, goto_tbl,
-                                            group_id, flags);
-       if (err)
-               netdev_err(rocker_port->dev, "Error (%d) IPv4 route %pI4\n",
-                          err, &dst);
-
-       return err;
-}
-
-/*****************
- * Net device ops
- *****************/
-
-static int rocker_port_open(struct net_device *dev)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       int err;
-
-       err = rocker_port_dma_rings_init(rocker_port);
-       if (err)
-               return err;
-
-       err = request_irq(rocker_msix_tx_vector(rocker_port),
-                         rocker_tx_irq_handler, 0,
-                         rocker_driver_name, rocker_port);
-       if (err) {
-               netdev_err(rocker_port->dev, "cannot assign tx irq\n");
-               goto err_request_tx_irq;
-       }
-
-       err = request_irq(rocker_msix_rx_vector(rocker_port),
-                         rocker_rx_irq_handler, 0,
-                         rocker_driver_name, rocker_port);
-       if (err) {
-               netdev_err(rocker_port->dev, "cannot assign rx irq\n");
-               goto err_request_rx_irq;
-       }
-
-       err = rocker_port_fwd_enable(rocker_port, NULL, 0);
-       if (err)
-               goto err_fwd_enable;
-
-       napi_enable(&rocker_port->napi_tx);
-       napi_enable(&rocker_port->napi_rx);
-       if (!dev->proto_down)
-               rocker_port_set_enable(rocker_port, true);
-       netif_start_queue(dev);
-       return 0;
-
-err_fwd_enable:
-       free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
-err_request_rx_irq:
-       free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
-err_request_tx_irq:
-       rocker_port_dma_rings_fini(rocker_port);
-       return err;
-}
-
-static int rocker_port_stop(struct net_device *dev)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-
-       netif_stop_queue(dev);
-       rocker_port_set_enable(rocker_port, false);
-       napi_disable(&rocker_port->napi_rx);
-       napi_disable(&rocker_port->napi_tx);
-       rocker_port_fwd_disable(rocker_port, NULL,
-                               ROCKER_OP_FLAG_NOWAIT);
-       free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
-       free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
-       rocker_port_dma_rings_fini(rocker_port);
-
-       return 0;
-}
-
-static void rocker_tx_desc_frags_unmap(const struct rocker_port *rocker_port,
-                                      const struct rocker_desc_info *desc_info)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       struct pci_dev *pdev = rocker->pdev;
-       const struct rocker_tlv *attrs[ROCKER_TLV_TX_MAX + 1];
-       struct rocker_tlv *attr;
-       int rem;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_TX_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_TX_FRAGS])
-               return;
-       rocker_tlv_for_each_nested(attr, attrs[ROCKER_TLV_TX_FRAGS], rem) {
-               const struct rocker_tlv *frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_MAX + 1];
-               dma_addr_t dma_handle;
-               size_t len;
-
-               if (rocker_tlv_type(attr) != ROCKER_TLV_TX_FRAG)
-                       continue;
-               rocker_tlv_parse_nested(frag_attrs, ROCKER_TLV_TX_FRAG_ATTR_MAX,
-                                       attr);
-               if (!frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
-                   !frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN])
-                       continue;
-               dma_handle = rocker_tlv_get_u64(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
-               len = rocker_tlv_get_u16(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
-               pci_unmap_single(pdev, dma_handle, len, DMA_TO_DEVICE);
-       }
-}
-
-static int rocker_tx_desc_frag_map_put(const struct rocker_port *rocker_port,
-                                      struct rocker_desc_info *desc_info,
-                                      char *buf, size_t buf_len)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       struct pci_dev *pdev = rocker->pdev;
-       dma_addr_t dma_handle;
-       struct rocker_tlv *frag;
-
-       dma_handle = pci_map_single(pdev, buf, buf_len, DMA_TO_DEVICE);
-       if (unlikely(pci_dma_mapping_error(pdev, dma_handle))) {
-               if (net_ratelimit())
-                       netdev_err(rocker_port->dev, "failed to dma map tx frag\n");
-               return -EIO;
-       }
-       frag = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAG);
-       if (!frag)
-               goto unmap_frag;
-       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_TX_FRAG_ATTR_ADDR,
-                              dma_handle))
-               goto nest_cancel;
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_TX_FRAG_ATTR_LEN,
-                              buf_len))
-               goto nest_cancel;
-       rocker_tlv_nest_end(desc_info, frag);
-       return 0;
-
-nest_cancel:
-       rocker_tlv_nest_cancel(desc_info, frag);
-unmap_frag:
-       pci_unmap_single(pdev, dma_handle, buf_len, DMA_TO_DEVICE);
-       return -EMSGSIZE;
-}
-
-static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_desc_info *desc_info;
-       struct rocker_tlv *frags;
-       int i;
-       int err;
-
-       desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
-       if (unlikely(!desc_info)) {
-               if (net_ratelimit())
-                       netdev_err(dev, "tx ring full when queue awake\n");
-               return NETDEV_TX_BUSY;
-       }
-
-       rocker_desc_cookie_ptr_set(desc_info, skb);
-
-       frags = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAGS);
-       if (!frags)
-               goto out;
-       err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
-                                         skb->data, skb_headlen(skb));
-       if (err)
-               goto nest_cancel;
-       if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX) {
-               err = skb_linearize(skb);
-               if (err)
-                       goto unmap_frags;
-       }
-
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-               err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
-                                                 skb_frag_address(frag),
-                                                 skb_frag_size(frag));
-               if (err)
-                       goto unmap_frags;
-       }
-       rocker_tlv_nest_end(desc_info, frags);
-
-       rocker_desc_gen_clear(desc_info);
-       rocker_desc_head_set(rocker, &rocker_port->tx_ring, desc_info);
-
-       desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
-       if (!desc_info)
-               netif_stop_queue(dev);
-
-       return NETDEV_TX_OK;
-
-unmap_frags:
-       rocker_tx_desc_frags_unmap(rocker_port, desc_info);
-nest_cancel:
-       rocker_tlv_nest_cancel(desc_info, frags);
-out:
-       dev_kfree_skb(skb);
-       dev->stats.tx_dropped++;
-
-       return NETDEV_TX_OK;
-}
-
-static int rocker_port_set_mac_address(struct net_device *dev, void *p)
-{
-       struct sockaddr *addr = p;
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       int err;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
-
-       err = rocker_cmd_set_port_settings_macaddr(rocker_port, addr->sa_data);
-       if (err)
-               return err;
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       return 0;
-}
-
-static int rocker_port_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       int running = netif_running(dev);
-       int err;
-
-#define ROCKER_PORT_MIN_MTU    68
-#define ROCKER_PORT_MAX_MTU    9000
-
-       if (new_mtu < ROCKER_PORT_MIN_MTU || new_mtu > ROCKER_PORT_MAX_MTU)
-               return -EINVAL;
-
-       if (running)
-               rocker_port_stop(dev);
-
-       netdev_info(dev, "MTU change from %d to %d\n", dev->mtu, new_mtu);
-       dev->mtu = new_mtu;
-
-       err = rocker_cmd_set_port_settings_mtu(rocker_port, new_mtu);
-       if (err)
-               return err;
-
-       if (running)
-               err = rocker_port_open(dev);
-
-       return err;
-}
-
-static int rocker_port_get_phys_port_name(struct net_device *dev,
-                                         char *buf, size_t len)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       struct port_name name = { .buf = buf, .len = len };
-       int err;
-
-       err = rocker_cmd_exec(rocker_port, NULL, 0,
-                             rocker_cmd_get_port_settings_prep, NULL,
-                             rocker_cmd_get_port_settings_phys_name_proc,
-                             &name);
-
-       return err ? -EOPNOTSUPP : 0;
-}
-
-static int rocker_port_change_proto_down(struct net_device *dev,
-                                        bool proto_down)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-
-       if (rocker_port->dev->flags & IFF_UP)
-               rocker_port_set_enable(rocker_port, !proto_down);
-       rocker_port->dev->proto_down = proto_down;
-       return 0;
-}
-
-static void rocker_port_neigh_destroy(struct neighbour *n)
-{
-       struct rocker_port *rocker_port = netdev_priv(n->dev);
-       int flags = ROCKER_OP_FLAG_REMOVE | ROCKER_OP_FLAG_NOWAIT;
-       __be32 ip_addr = *(__be32 *)n->primary_key;
-
-       rocker_port_ipv4_neigh(rocker_port, NULL,
-                              flags, ip_addr, n->ha);
-}
-
-static const struct net_device_ops rocker_port_netdev_ops = {
-       .ndo_open                       = rocker_port_open,
-       .ndo_stop                       = rocker_port_stop,
-       .ndo_start_xmit                 = rocker_port_xmit,
-       .ndo_set_mac_address            = rocker_port_set_mac_address,
-       .ndo_change_mtu                 = rocker_port_change_mtu,
-       .ndo_bridge_getlink             = switchdev_port_bridge_getlink,
-       .ndo_bridge_setlink             = switchdev_port_bridge_setlink,
-       .ndo_bridge_dellink             = switchdev_port_bridge_dellink,
-       .ndo_fdb_add                    = switchdev_port_fdb_add,
-       .ndo_fdb_del                    = switchdev_port_fdb_del,
-       .ndo_fdb_dump                   = switchdev_port_fdb_dump,
-       .ndo_get_phys_port_name         = rocker_port_get_phys_port_name,
-       .ndo_change_proto_down          = rocker_port_change_proto_down,
-       .ndo_neigh_destroy              = rocker_port_neigh_destroy,
-};
-
-/********************
- * swdev interface
- ********************/
-
-static int rocker_port_attr_get(struct net_device *dev,
-                               struct switchdev_attr *attr)
-{
-       const struct rocker_port *rocker_port = netdev_priv(dev);
-       const struct rocker *rocker = rocker_port->rocker;
-
-       switch (attr->id) {
-       case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
-               attr->u.ppid.id_len = sizeof(rocker->hw.id);
-               memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len);
-               break;
-       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
-               attr->u.brport_flags = rocker_port->brport_flags;
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
-static int rocker_port_brport_flags_set(struct rocker_port *rocker_port,
-                                       struct switchdev_trans *trans,
-                                       unsigned long brport_flags)
-{
-       unsigned long orig_flags;
-       int err = 0;
-
-       orig_flags = rocker_port->brport_flags;
-       rocker_port->brport_flags = brport_flags;
-       if ((orig_flags ^ rocker_port->brport_flags) & BR_LEARNING)
-               err = rocker_port_set_learning(rocker_port, trans);
-
-       if (switchdev_trans_ph_prepare(trans))
-               rocker_port->brport_flags = orig_flags;
-
-       return err;
-}
-
-static int rocker_port_bridge_ageing_time(struct rocker_port *rocker_port,
-                                         struct switchdev_trans *trans,
-                                         u32 ageing_time)
-{
-       if (!switchdev_trans_ph_prepare(trans)) {
-               rocker_port->ageing_time = clock_t_to_jiffies(ageing_time);
-               mod_timer(&rocker_port->rocker->fdb_cleanup_timer, jiffies);
-       }
-
-       return 0;
-}
-
-static int rocker_port_attr_set(struct net_device *dev,
-                               const struct switchdev_attr *attr,
-                               struct switchdev_trans *trans)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       int err = 0;
-
-       switch (attr->id) {
-       case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
-               err = rocker_port_stp_update(rocker_port, trans, 0,
-                                            attr->u.stp_state);
-               break;
-       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
-               err = rocker_port_brport_flags_set(rocker_port, trans,
-                                                  attr->u.brport_flags);
-               break;
-       case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
-               err = rocker_port_bridge_ageing_time(rocker_port, trans,
-                                                    attr->u.ageing_time);
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       return err;
-}
-
-static int rocker_port_vlan_add(struct rocker_port *rocker_port,
-                               struct switchdev_trans *trans,
-                               u16 vid, u16 flags)
-{
-       int err;
-
-       /* XXX deal with flags for PVID and untagged */
-
-       err = rocker_port_vlan(rocker_port, trans, 0, vid);
-       if (err)
-               return err;
-
-       err = rocker_port_router_mac(rocker_port, trans, 0, htons(vid));
-       if (err)
-               rocker_port_vlan(rocker_port, trans,
-                                ROCKER_OP_FLAG_REMOVE, vid);
-
-       return err;
-}
-
-static int rocker_port_vlans_add(struct rocker_port *rocker_port,
-                                struct switchdev_trans *trans,
-                                const struct switchdev_obj_port_vlan *vlan)
-{
-       u16 vid;
-       int err;
-
-       for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
-               err = rocker_port_vlan_add(rocker_port, trans,
-                                          vid, vlan->flags);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int rocker_port_fdb_add(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans,
-                              const struct switchdev_obj_port_fdb *fdb)
-{
-       __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
-       int flags = 0;
-
-       if (!rocker_port_is_bridged(rocker_port))
-               return -EINVAL;
-
-       return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags);
-}
-
-static int rocker_port_obj_add(struct net_device *dev,
-                              const struct switchdev_obj *obj,
-                              struct switchdev_trans *trans)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       const struct switchdev_obj_ipv4_fib *fib4;
-       int err = 0;
-
-       switch (obj->id) {
-       case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = rocker_port_vlans_add(rocker_port, trans,
-                                           SWITCHDEV_OBJ_PORT_VLAN(obj));
-               break;
-       case SWITCHDEV_OBJ_ID_IPV4_FIB:
-               fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
-               err = rocker_port_fib_ipv4(rocker_port, trans,
-                                          htonl(fib4->dst), fib4->dst_len,
-                                          &fib4->fi, fib4->tb_id, 0);
-               break;
-       case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = rocker_port_fdb_add(rocker_port, trans,
-                                         SWITCHDEV_OBJ_PORT_FDB(obj));
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       return err;
-}
-
-static int rocker_port_vlan_del(struct rocker_port *rocker_port,
-                               u16 vid, u16 flags)
-{
-       int err;
-
-       err = rocker_port_router_mac(rocker_port, NULL,
-                                    ROCKER_OP_FLAG_REMOVE, htons(vid));
-       if (err)
-               return err;
-
-       return rocker_port_vlan(rocker_port, NULL,
-                               ROCKER_OP_FLAG_REMOVE, vid);
-}
-
-static int rocker_port_vlans_del(struct rocker_port *rocker_port,
-                                const struct switchdev_obj_port_vlan *vlan)
-{
-       u16 vid;
-       int err;
-
-       for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
-               err = rocker_port_vlan_del(rocker_port, vid, vlan->flags);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int rocker_port_fdb_del(struct rocker_port *rocker_port,
-                              struct switchdev_trans *trans,
-                              const struct switchdev_obj_port_fdb *fdb)
-{
-       __be16 vlan_id = rocker_port_vid_to_vlan(rocker_port, fdb->vid, NULL);
-       int flags = ROCKER_OP_FLAG_REMOVE;
-
-       if (!rocker_port_is_bridged(rocker_port))
-               return -EINVAL;
-
-       return rocker_port_fdb(rocker_port, trans, fdb->addr, vlan_id, flags);
-}
-
-static int rocker_port_obj_del(struct net_device *dev,
-                              const struct switchdev_obj *obj)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       const struct switchdev_obj_ipv4_fib *fib4;
-       int err = 0;
-
-       switch (obj->id) {
-       case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = rocker_port_vlans_del(rocker_port,
-                                           SWITCHDEV_OBJ_PORT_VLAN(obj));
-               break;
-       case SWITCHDEV_OBJ_ID_IPV4_FIB:
-               fib4 = SWITCHDEV_OBJ_IPV4_FIB(obj);
-               err = rocker_port_fib_ipv4(rocker_port, NULL,
-                                          htonl(fib4->dst), fib4->dst_len,
-                                          &fib4->fi, fib4->tb_id,
-                                          ROCKER_OP_FLAG_REMOVE);
-               break;
-       case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = rocker_port_fdb_del(rocker_port, NULL,
-                                         SWITCHDEV_OBJ_PORT_FDB(obj));
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       return err;
-}
-
-static int rocker_port_fdb_dump(const struct rocker_port *rocker_port,
-                               struct switchdev_obj_port_fdb *fdb,
-                               switchdev_obj_dump_cb_t *cb)
-{
-       struct rocker *rocker = rocker_port->rocker;
-       struct rocker_fdb_tbl_entry *found;
-       struct hlist_node *tmp;
-       unsigned long lock_flags;
-       int bkt;
-       int err = 0;
-
-       spin_lock_irqsave(&rocker->fdb_tbl_lock, lock_flags);
-       hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) {
-               if (found->key.rocker_port != rocker_port)
-                       continue;
-               ether_addr_copy(fdb->addr, found->key.addr);
-               fdb->ndm_state = NUD_REACHABLE;
-               fdb->vid = rocker_port_vlan_to_vid(rocker_port,
-                                                  found->key.vlan_id);
-               err = cb(&fdb->obj);
-               if (err)
-                       break;
-       }
-       spin_unlock_irqrestore(&rocker->fdb_tbl_lock, lock_flags);
-
-       return err;
-}
-
-static int rocker_port_vlan_dump(const struct rocker_port *rocker_port,
-                                struct switchdev_obj_port_vlan *vlan,
-                                switchdev_obj_dump_cb_t *cb)
-{
-       u16 vid;
-       int err = 0;
-
-       for (vid = 1; vid < VLAN_N_VID; vid++) {
-               if (!test_bit(vid, rocker_port->vlan_bitmap))
-                       continue;
-               vlan->flags = 0;
-               if (rocker_vlan_id_is_internal(htons(vid)))
-                       vlan->flags |= BRIDGE_VLAN_INFO_PVID;
-               vlan->vid_begin = vlan->vid_end = vid;
-               err = cb(&vlan->obj);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
-static int rocker_port_obj_dump(struct net_device *dev,
-                               struct switchdev_obj *obj,
-                               switchdev_obj_dump_cb_t *cb)
-{
-       const struct rocker_port *rocker_port = netdev_priv(dev);
-       int err = 0;
-
-       switch (obj->id) {
-       case SWITCHDEV_OBJ_ID_PORT_FDB:
-               err = rocker_port_fdb_dump(rocker_port,
-                                          SWITCHDEV_OBJ_PORT_FDB(obj), cb);
-               break;
-       case SWITCHDEV_OBJ_ID_PORT_VLAN:
-               err = rocker_port_vlan_dump(rocker_port,
-                                           SWITCHDEV_OBJ_PORT_VLAN(obj), cb);
-               break;
-       default:
-               err = -EOPNOTSUPP;
-               break;
-       }
-
-       return err;
-}
-
-static const struct switchdev_ops rocker_port_switchdev_ops = {
-       .switchdev_port_attr_get        = rocker_port_attr_get,
-       .switchdev_port_attr_set        = rocker_port_attr_set,
-       .switchdev_port_obj_add         = rocker_port_obj_add,
-       .switchdev_port_obj_del         = rocker_port_obj_del,
-       .switchdev_port_obj_dump        = rocker_port_obj_dump,
-};
-
-/********************
- * ethtool interface
- ********************/
-
-static int rocker_port_get_settings(struct net_device *dev,
-                                   struct ethtool_cmd *ecmd)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-
-       return rocker_cmd_get_port_settings_ethtool(rocker_port, ecmd);
-}
-
-static int rocker_port_set_settings(struct net_device *dev,
-                                   struct ethtool_cmd *ecmd)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-
-       return rocker_cmd_set_port_settings_ethtool(rocker_port, ecmd);
-}
-
-static void rocker_port_get_drvinfo(struct net_device *dev,
-                                   struct ethtool_drvinfo *drvinfo)
-{
-       strlcpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver));
-       strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
-}
-
-static struct rocker_port_stats {
-       char str[ETH_GSTRING_LEN];
-       int type;
-} rocker_port_stats[] = {
-       { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS,    },
-       { "rx_bytes",   ROCKER_TLV_CMD_PORT_STATS_RX_BYTES,   },
-       { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },
-       { "rx_errors",  ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS,  },
-
-       { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS,    },
-       { "tx_bytes",   ROCKER_TLV_CMD_PORT_STATS_TX_BYTES,   },
-       { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },
-       { "tx_errors",  ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS,  },
-};
-
-#define ROCKER_PORT_STATS_LEN  ARRAY_SIZE(rocker_port_stats)
-
-static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
-                                   u8 *data)
-{
-       u8 *p = data;
-       int i;
-
-       switch (stringset) {
-       case ETH_SS_STATS:
-               for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
-                       memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);
-                       p += ETH_GSTRING_LEN;
-               }
-               break;
-       }
-}
-
-static int
-rocker_cmd_get_port_stats_prep(const struct rocker_port *rocker_port,
-                              struct rocker_desc_info *desc_info,
-                              void *priv)
-{
-       struct rocker_tlv *cmd_stats;
-
-       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
-                              ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))
-               return -EMSGSIZE;
-
-       cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
-       if (!cmd_stats)
-               return -EMSGSIZE;
-
-       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_PPORT,
-                              rocker_port->pport))
-               return -EMSGSIZE;
-
-       rocker_tlv_nest_end(desc_info, cmd_stats);
-
-       return 0;
-}
-
-static int
-rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,
-                                      const struct rocker_desc_info *desc_info,
-                                      void *priv)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
-       const struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
-       const struct rocker_tlv *pattr;
-       u32 pport;
-       u64 *data = priv;
-       int i;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
-
-       if (!attrs[ROCKER_TLV_CMD_INFO])
-               return -EIO;
-
-       rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,
-                               attrs[ROCKER_TLV_CMD_INFO]);
-
-       if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT])
-               return -EIO;
-
-       pport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT]);
-       if (pport != rocker_port->pport)
-               return -EIO;
-
-       for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
-               pattr = stats_attrs[rocker_port_stats[i].type];
-               if (!pattr)
-                       continue;
-
-               data[i] = rocker_tlv_get_u64(pattr);
-       }
-
-       return 0;
-}
-
-static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
-                                            void *priv)
-{
-       return rocker_cmd_exec(rocker_port, NULL, 0,
-                              rocker_cmd_get_port_stats_prep, NULL,
-                              rocker_cmd_get_port_stats_ethtool_proc,
-                              priv);
-}
-
-static void rocker_port_get_stats(struct net_device *dev,
-                                 struct ethtool_stats *stats, u64 *data)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-
-       if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
-                       data[i] = 0;
-       }
-}
-
-static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
-{
-       switch (sset) {
-       case ETH_SS_STATS:
-               return ROCKER_PORT_STATS_LEN;
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static const struct ethtool_ops rocker_port_ethtool_ops = {
-       .get_settings           = rocker_port_get_settings,
-       .set_settings           = rocker_port_set_settings,
-       .get_drvinfo            = rocker_port_get_drvinfo,
-       .get_link               = ethtool_op_get_link,
-       .get_strings            = rocker_port_get_strings,
-       .get_ethtool_stats      = rocker_port_get_stats,
-       .get_sset_count         = rocker_port_get_sset_count,
-};
-
-/*****************
- * NAPI interface
- *****************/
-
-static struct rocker_port *rocker_port_napi_tx_get(struct napi_struct *napi)
-{
-       return container_of(napi, struct rocker_port, napi_tx);
-}
-
-static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
-{
-       struct rocker_port *rocker_port = rocker_port_napi_tx_get(napi);
-       const struct rocker *rocker = rocker_port->rocker;
-       const struct rocker_desc_info *desc_info;
-       u32 credits = 0;
-       int err;
-
-       /* Cleanup tx descriptors */
-       while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) {
-               struct sk_buff *skb;
-
-               err = rocker_desc_err(desc_info);
-               if (err && net_ratelimit())
-                       netdev_err(rocker_port->dev, "tx desc received with err %d\n",
-                                  err);
-               rocker_tx_desc_frags_unmap(rocker_port, desc_info);
-
-               skb = rocker_desc_cookie_ptr_get(desc_info);
-               if (err == 0) {
-                       rocker_port->dev->stats.tx_packets++;
-                       rocker_port->dev->stats.tx_bytes += skb->len;
-               } else {
-                       rocker_port->dev->stats.tx_errors++;
-               }
-
-               dev_kfree_skb_any(skb);
-               credits++;
-       }
-
-       if (credits && netif_queue_stopped(rocker_port->dev))
-               netif_wake_queue(rocker_port->dev);
-
-       napi_complete(napi);
-       rocker_dma_ring_credits_set(rocker, &rocker_port->tx_ring, credits);
-
-       return 0;
-}
-
-static int rocker_port_rx_proc(const struct rocker *rocker,
-                              const struct rocker_port *rocker_port,
-                              struct rocker_desc_info *desc_info)
-{
-       const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
-       struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
-       size_t rx_len;
-       u16 rx_flags = 0;
-
-       if (!skb)
-               return -ENOENT;
-
-       rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);
-       if (!attrs[ROCKER_TLV_RX_FRAG_LEN])
-               return -EINVAL;
-       if (attrs[ROCKER_TLV_RX_FLAGS])
-               rx_flags = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FLAGS]);
-
-       rocker_dma_rx_ring_skb_unmap(rocker, attrs);
-
-       rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]);
-       skb_put(skb, rx_len);
-       skb->protocol = eth_type_trans(skb, rocker_port->dev);
-
-       if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD)
-               skb->offload_fwd_mark = rocker_port->dev->offload_fwd_mark;
-
-       rocker_port->dev->stats.rx_packets++;
-       rocker_port->dev->stats.rx_bytes += skb->len;
-
-       netif_receive_skb(skb);
-
-       return rocker_dma_rx_ring_skb_alloc(rocker_port, desc_info);
-}
-
-static struct rocker_port *rocker_port_napi_rx_get(struct napi_struct *napi)
-{
-       return container_of(napi, struct rocker_port, napi_rx);
-}
-
-static int rocker_port_poll_rx(struct napi_struct *napi, int budget)
-{
-       struct rocker_port *rocker_port = rocker_port_napi_rx_get(napi);
-       const struct rocker *rocker = rocker_port->rocker;
-       struct rocker_desc_info *desc_info;
-       u32 credits = 0;
-       int err;
-
-       /* Process rx descriptors */
-       while (credits < budget &&
-              (desc_info = rocker_desc_tail_get(&rocker_port->rx_ring))) {
-               err = rocker_desc_err(desc_info);
-               if (err) {
-                       if (net_ratelimit())
-                               netdev_err(rocker_port->dev, "rx desc received with err %d\n",
-                                          err);
-               } else {
-                       err = rocker_port_rx_proc(rocker, rocker_port,
-                                                 desc_info);
-                       if (err && net_ratelimit())
-                               netdev_err(rocker_port->dev, "rx processing failed with err %d\n",
-                                          err);
-               }
-               if (err)
-                       rocker_port->dev->stats.rx_errors++;
-
-               rocker_desc_gen_clear(desc_info);
-               rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info);
-               credits++;
-       }
-
-       if (credits < budget)
-               napi_complete(napi);
-
-       rocker_dma_ring_credits_set(rocker, &rocker_port->rx_ring, credits);
-
-       return credits;
-}
-
-/*****************
- * PCI driver ops
- *****************/
-
-static void rocker_carrier_init(const struct rocker_port *rocker_port)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       u64 link_status = rocker_read64(rocker, PORT_PHYS_LINK_STATUS);
-       bool link_up;
-
-       link_up = link_status & (1 << rocker_port->pport);
-       if (link_up)
-               netif_carrier_on(rocker_port->dev);
-       else
-               netif_carrier_off(rocker_port->dev);
-}
-
-static void rocker_remove_ports(const struct rocker *rocker)
-{
-       struct rocker_port *rocker_port;
-       int i;
-
-       for (i = 0; i < rocker->port_count; i++) {
-               rocker_port = rocker->ports[i];
-               if (!rocker_port)
-                       continue;
-               rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
-               unregister_netdev(rocker_port->dev);
-               free_netdev(rocker_port->dev);
-       }
-       kfree(rocker->ports);
-}
-
-static void rocker_port_dev_addr_init(struct rocker_port *rocker_port)
-{
-       const struct rocker *rocker = rocker_port->rocker;
-       const struct pci_dev *pdev = rocker->pdev;
-       int err;
-
-       err = rocker_cmd_get_port_settings_macaddr(rocker_port,
-                                                  rocker_port->dev->dev_addr);
-       if (err) {
-               dev_warn(&pdev->dev, "failed to get mac address, using random\n");
-               eth_hw_addr_random(rocker_port->dev);
-       }
-}
-
-static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
-{
-       const struct pci_dev *pdev = rocker->pdev;
-       struct rocker_port *rocker_port;
-       struct net_device *dev;
-       u16 untagged_vid = 0;
-       int err;
-
-       dev = alloc_etherdev(sizeof(struct rocker_port));
-       if (!dev)
-               return -ENOMEM;
-       rocker_port = netdev_priv(dev);
-       rocker_port->dev = dev;
-       rocker_port->rocker = rocker;
-       rocker_port->port_number = port_number;
-       rocker_port->pport = port_number + 1;
-       rocker_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
-       rocker_port->ageing_time = BR_DEFAULT_AGEING_TIME;
-
-       rocker_port_dev_addr_init(rocker_port);
-       dev->netdev_ops = &rocker_port_netdev_ops;
-       dev->ethtool_ops = &rocker_port_ethtool_ops;
-       dev->switchdev_ops = &rocker_port_switchdev_ops;
-       netif_tx_napi_add(dev, &rocker_port->napi_tx, rocker_port_poll_tx,
-                      NAPI_POLL_WEIGHT);
-       netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx,
-                      NAPI_POLL_WEIGHT);
-       rocker_carrier_init(rocker_port);
-
-       dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_SG;
-
-       err = register_netdev(dev);
-       if (err) {
-               dev_err(&pdev->dev, "register_netdev failed\n");
-               goto err_register_netdev;
-       }
-       rocker->ports[port_number] = rocker_port;
-
-       switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false);
-
-       rocker_port_set_learning(rocker_port, NULL);
-
-       err = rocker_port_ig_tbl(rocker_port, NULL, 0);
-       if (err) {
-               netdev_err(rocker_port->dev, "install ig port table failed\n");
-               goto err_port_ig_tbl;
-       }
-
-       rocker_port->internal_vlan_id =
-               rocker_port_internal_vlan_id_get(rocker_port, dev->ifindex);
-
-       err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
-       if (err) {
-               netdev_err(rocker_port->dev, "install untagged VLAN failed\n");
-               goto err_untagged_vlan;
-       }
-
-       return 0;
-
-err_untagged_vlan:
-       rocker_port_ig_tbl(rocker_port, NULL, ROCKER_OP_FLAG_REMOVE);
-err_port_ig_tbl:
-       rocker->ports[port_number] = NULL;
-       unregister_netdev(dev);
-err_register_netdev:
-       free_netdev(dev);
-       return err;
-}
-
-static int rocker_probe_ports(struct rocker *rocker)
-{
-       int i;
-       size_t alloc_size;
-       int err;
-
-       alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
-       rocker->ports = kzalloc(alloc_size, GFP_KERNEL);
-       if (!rocker->ports)
-               return -ENOMEM;
-       for (i = 0; i < rocker->port_count; i++) {
-               err = rocker_probe_port(rocker, i);
-               if (err)
-                       goto remove_ports;
-       }
-       return 0;
-
-remove_ports:
-       rocker_remove_ports(rocker);
-       return err;
-}
-
-static int rocker_msix_init(struct rocker *rocker)
-{
-       struct pci_dev *pdev = rocker->pdev;
-       int msix_entries;
-       int i;
-       int err;
-
-       msix_entries = pci_msix_vec_count(pdev);
-       if (msix_entries < 0)
-               return msix_entries;
-
-       if (msix_entries != ROCKER_MSIX_VEC_COUNT(rocker->port_count))
-               return -EINVAL;
-
-       rocker->msix_entries = kmalloc_array(msix_entries,
-                                            sizeof(struct msix_entry),
-                                            GFP_KERNEL);
-       if (!rocker->msix_entries)
-               return -ENOMEM;
-
-       for (i = 0; i < msix_entries; i++)
-               rocker->msix_entries[i].entry = i;
-
-       err = pci_enable_msix_exact(pdev, rocker->msix_entries, msix_entries);
-       if (err < 0)
-               goto err_enable_msix;
-
-       return 0;
-
-err_enable_msix:
-       kfree(rocker->msix_entries);
-       return err;
-}
-
-static void rocker_msix_fini(const struct rocker *rocker)
-{
-       pci_disable_msix(rocker->pdev);
-       kfree(rocker->msix_entries);
-}
-
-static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-       struct rocker *rocker;
-       int err;
-
-       rocker = kzalloc(sizeof(*rocker), GFP_KERNEL);
-       if (!rocker)
-               return -ENOMEM;
-
-       err = pci_enable_device(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "pci_enable_device failed\n");
-               goto err_pci_enable_device;
-       }
-
-       err = pci_request_regions(pdev, rocker_driver_name);
-       if (err) {
-               dev_err(&pdev->dev, "pci_request_regions failed\n");
-               goto err_pci_request_regions;
-       }
-
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-       if (!err) {
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-               if (err) {
-                       dev_err(&pdev->dev, "pci_set_consistent_dma_mask failed\n");
-                       goto err_pci_set_dma_mask;
-               }
-       } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (err) {
-                       dev_err(&pdev->dev, "pci_set_dma_mask failed\n");
-                       goto err_pci_set_dma_mask;
-               }
-       }
-
-       if (pci_resource_len(pdev, 0) < ROCKER_PCI_BAR0_SIZE) {
-               dev_err(&pdev->dev, "invalid PCI region size\n");
-               err = -EINVAL;
-               goto err_pci_resource_len_check;
-       }
-
-       rocker->hw_addr = ioremap(pci_resource_start(pdev, 0),
-                                 pci_resource_len(pdev, 0));
-       if (!rocker->hw_addr) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               err = -EIO;
-               goto err_ioremap;
-       }
-       pci_set_master(pdev);
-
-       rocker->pdev = pdev;
-       pci_set_drvdata(pdev, rocker);
-
-       rocker->port_count = rocker_read32(rocker, PORT_PHYS_COUNT);
-
-       err = rocker_msix_init(rocker);
-       if (err) {
-               dev_err(&pdev->dev, "MSI-X init failed\n");
-               goto err_msix_init;
-       }
-
-       err = rocker_basic_hw_test(rocker);
-       if (err) {
-               dev_err(&pdev->dev, "basic hw test failed\n");
-               goto err_basic_hw_test;
-       }
-
-       rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
-
-       err = rocker_dma_rings_init(rocker);
-       if (err)
-               goto err_dma_rings_init;
-
-       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD),
-                         rocker_cmd_irq_handler, 0,
-                         rocker_driver_name, rocker);
-       if (err) {
-               dev_err(&pdev->dev, "cannot assign cmd irq\n");
-               goto err_request_cmd_irq;
-       }
-
-       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT),
-                         rocker_event_irq_handler, 0,
-                         rocker_driver_name, rocker);
-       if (err) {
-               dev_err(&pdev->dev, "cannot assign event irq\n");
-               goto err_request_event_irq;
-       }
-
-       rocker->hw.id = rocker_read64(rocker, SWITCH_ID);
-
-       err = rocker_init_tbls(rocker);
-       if (err) {
-               dev_err(&pdev->dev, "cannot init rocker tables\n");
-               goto err_init_tbls;
-       }
-
-       setup_timer(&rocker->fdb_cleanup_timer, rocker_fdb_cleanup,
-                   (unsigned long) rocker);
-       mod_timer(&rocker->fdb_cleanup_timer, jiffies);
-
-       err = rocker_probe_ports(rocker);
-       if (err) {
-               dev_err(&pdev->dev, "failed to probe ports\n");
-               goto err_probe_ports;
-       }
-
-       dev_info(&pdev->dev, "Rocker switch with id %*phN\n",
-                (int)sizeof(rocker->hw.id), &rocker->hw.id);
-
-       return 0;
-
-err_probe_ports:
-       del_timer_sync(&rocker->fdb_cleanup_timer);
-       rocker_free_tbls(rocker);
-err_init_tbls:
-       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
-err_request_event_irq:
-       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
-err_request_cmd_irq:
-       rocker_dma_rings_fini(rocker);
-err_dma_rings_init:
-err_basic_hw_test:
-       rocker_msix_fini(rocker);
-err_msix_init:
-       iounmap(rocker->hw_addr);
-err_ioremap:
-err_pci_resource_len_check:
-err_pci_set_dma_mask:
-       pci_release_regions(pdev);
-err_pci_request_regions:
-       pci_disable_device(pdev);
-err_pci_enable_device:
-       kfree(rocker);
-       return err;
-}
-
-static void rocker_remove(struct pci_dev *pdev)
-{
-       struct rocker *rocker = pci_get_drvdata(pdev);
-
-       del_timer_sync(&rocker->fdb_cleanup_timer);
-       rocker_free_tbls(rocker);
-       rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
-       rocker_remove_ports(rocker);
-       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
-       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
-       rocker_dma_rings_fini(rocker);
-       rocker_msix_fini(rocker);
-       iounmap(rocker->hw_addr);
-       pci_release_regions(rocker->pdev);
-       pci_disable_device(rocker->pdev);
-       kfree(rocker);
-}
-
-static struct pci_driver rocker_pci_driver = {
-       .name           = rocker_driver_name,
-       .id_table       = rocker_pci_id_table,
-       .probe          = rocker_probe,
-       .remove         = rocker_remove,
-};
-
-/************************************
- * Net device notifier event handler
- ************************************/
-
-static bool rocker_port_dev_check(const struct net_device *dev)
-{
-       return dev->netdev_ops == &rocker_port_netdev_ops;
-}
-
-static int rocker_port_bridge_join(struct rocker_port *rocker_port,
-                                  struct net_device *bridge)
-{
-       u16 untagged_vid = 0;
-       int err;
-
-       /* Port is joining bridge, so the internal VLAN for the
-        * port is going to change to the bridge internal VLAN.
-        * Let's remove untagged VLAN (vid=0) from port and
-        * re-add once internal VLAN has changed.
-        */
-
-       err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
-       if (err)
-               return err;
-
-       rocker_port_internal_vlan_id_put(rocker_port,
-                                        rocker_port->dev->ifindex);
-       rocker_port->internal_vlan_id =
-               rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex);
-
-       rocker_port->bridge_dev = bridge;
-       switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true);
-
-       return rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
-}
-
-static int rocker_port_bridge_leave(struct rocker_port *rocker_port)
-{
-       u16 untagged_vid = 0;
-       int err;
-
-       err = rocker_port_vlan_del(rocker_port, untagged_vid, 0);
-       if (err)
-               return err;
-
-       rocker_port_internal_vlan_id_put(rocker_port,
-                                        rocker_port->bridge_dev->ifindex);
-       rocker_port->internal_vlan_id =
-               rocker_port_internal_vlan_id_get(rocker_port,
-                                                rocker_port->dev->ifindex);
-
-       switchdev_port_fwd_mark_set(rocker_port->dev, rocker_port->bridge_dev,
-                                   false);
-       rocker_port->bridge_dev = NULL;
-
-       err = rocker_port_vlan_add(rocker_port, NULL, untagged_vid, 0);
-       if (err)
-               return err;
-
-       if (rocker_port->dev->flags & IFF_UP)
-               err = rocker_port_fwd_enable(rocker_port, NULL, 0);
-
-       return err;
-}
-
-
-static int rocker_port_ovs_changed(struct rocker_port *rocker_port,
-                                  struct net_device *master)
-{
-       int err;
-
-       rocker_port->bridge_dev = master;
-
-       err = rocker_port_fwd_disable(rocker_port, NULL, 0);
-       if (err)
-               return err;
-       err = rocker_port_fwd_enable(rocker_port, NULL, 0);
-
-       return err;
-}
-
-static int rocker_port_master_linked(struct rocker_port *rocker_port,
-                                    struct net_device *master)
-{
-       int err = 0;
-
-       if (netif_is_bridge_master(master))
-               err = rocker_port_bridge_join(rocker_port, master);
-       else if (netif_is_ovs_master(master))
-               err = rocker_port_ovs_changed(rocker_port, master);
-       return err;
-}
-
-static int rocker_port_master_unlinked(struct rocker_port *rocker_port)
-{
-       int err = 0;
-
-       if (rocker_port_is_bridged(rocker_port))
-               err = rocker_port_bridge_leave(rocker_port);
-       else if (rocker_port_is_ovsed(rocker_port))
-               err = rocker_port_ovs_changed(rocker_port, NULL);
-       return err;
-}
-
-static int rocker_netdevice_event(struct notifier_block *unused,
-                                 unsigned long event, void *ptr)
-{
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       struct netdev_notifier_changeupper_info *info;
-       struct rocker_port *rocker_port;
-       int err;
-
-       if (!rocker_port_dev_check(dev))
-               return NOTIFY_DONE;
-
-       switch (event) {
-       case NETDEV_CHANGEUPPER:
-               info = ptr;
-               if (!info->master)
-                       goto out;
-               rocker_port = netdev_priv(dev);
-               if (info->linking) {
-                       err = rocker_port_master_linked(rocker_port,
-                                                       info->upper_dev);
-                       if (err)
-                               netdev_warn(dev, "failed to reflect master linked (err %d)\n",
-                                           err);
-               } else {
-                       err = rocker_port_master_unlinked(rocker_port);
-                       if (err)
-                               netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
-                                           err);
-               }
-               break;
-       }
-out:
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block rocker_netdevice_nb __read_mostly = {
-       .notifier_call = rocker_netdevice_event,
-};
-
-/************************************
- * Net event notifier event handler
- ************************************/
-
-static int rocker_neigh_update(struct net_device *dev, struct neighbour *n)
-{
-       struct rocker_port *rocker_port = netdev_priv(dev);
-       int flags = (n->nud_state & NUD_VALID ? 0 : ROCKER_OP_FLAG_REMOVE) |
-                   ROCKER_OP_FLAG_NOWAIT;
-       __be32 ip_addr = *(__be32 *)n->primary_key;
-
-       return rocker_port_ipv4_neigh(rocker_port, NULL, flags, ip_addr, n->ha);
-}
-
-static int rocker_netevent_event(struct notifier_block *unused,
-                                unsigned long event, void *ptr)
-{
-       struct net_device *dev;
-       struct neighbour *n = ptr;
-       int err;
-
-       switch (event) {
-       case NETEVENT_NEIGH_UPDATE:
-               if (n->tbl != &arp_tbl)
-                       return NOTIFY_DONE;
-               dev = n->dev;
-               if (!rocker_port_dev_check(dev))
-                       return NOTIFY_DONE;
-               err = rocker_neigh_update(dev, n);
-               if (err)
-                       netdev_warn(dev,
-                                   "failed to handle neigh update (err %d)\n",
-                                   err);
-               break;
-       }
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block rocker_netevent_nb __read_mostly = {
-       .notifier_call = rocker_netevent_event,
-};
-
-/***********************
- * Module init and exit
- ***********************/
-
-static int __init rocker_module_init(void)
-{
-       int err;
-
-       register_netdevice_notifier(&rocker_netdevice_nb);
-       register_netevent_notifier(&rocker_netevent_nb);
-       err = pci_register_driver(&rocker_pci_driver);
-       if (err)
-               goto err_pci_register_driver;
-       return 0;
-
-err_pci_register_driver:
-       unregister_netevent_notifier(&rocker_netevent_nb);
-       unregister_netdevice_notifier(&rocker_netdevice_nb);
-       return err;
-}
-
-static void __exit rocker_module_exit(void)
-{
-       unregister_netevent_notifier(&rocker_netevent_nb);
-       unregister_netdevice_notifier(&rocker_netdevice_nb);
-       pci_unregister_driver(&rocker_pci_driver);
-}
-
-module_init(rocker_module_init);
-module_exit(rocker_module_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
-MODULE_AUTHOR("Scott Feldman <sfeldma@gmail.com>");
-MODULE_DESCRIPTION("Rocker switch device driver");
-MODULE_DEVICE_TABLE(pci, rocker_pci_id_table);
index 12490b2f65040e18a49a4782387736da411c19e5..1ab995f7146b3d1028465b7af61cfcb08f3f151a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * drivers/net/ethernet/rocker/rocker.h - Rocker switch device driver
- * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
  * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #ifndef _ROCKER_H
 #define _ROCKER_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
-
-/* Return codes */
-enum {
-       ROCKER_OK = 0,
-       ROCKER_ENOENT = 2,
-       ROCKER_ENXIO = 6,
-       ROCKER_ENOMEM = 12,
-       ROCKER_EEXIST = 17,
-       ROCKER_EINVAL = 22,
-       ROCKER_EMSGSIZE = 90,
-       ROCKER_ENOTSUP = 95,
-       ROCKER_ENOBUFS = 105,
-};
-
-#define ROCKER_FP_PORTS_MAX 62
-
-#define PCI_VENDOR_ID_REDHAT           0x1b36
-#define PCI_DEVICE_ID_REDHAT_ROCKER    0x0006
-
-#define ROCKER_PCI_BAR0_SIZE           0x2000
-
-/* MSI-X vectors */
-enum {
-       ROCKER_MSIX_VEC_CMD,
-       ROCKER_MSIX_VEC_EVENT,
-       ROCKER_MSIX_VEC_TEST,
-       ROCKER_MSIX_VEC_RESERVED0,
-       __ROCKER_MSIX_VEC_TX,
-       __ROCKER_MSIX_VEC_RX,
-#define ROCKER_MSIX_VEC_TX(port) \
-       (__ROCKER_MSIX_VEC_TX + ((port) * 2))
-#define ROCKER_MSIX_VEC_RX(port) \
-       (__ROCKER_MSIX_VEC_RX + ((port) * 2))
-#define ROCKER_MSIX_VEC_COUNT(portcnt) \
-       (ROCKER_MSIX_VEC_RX((portcnt - 1)) + 1)
-};
-
-/* Rocker bogus registers */
-#define ROCKER_BOGUS_REG0              0x0000
-#define ROCKER_BOGUS_REG1              0x0004
-#define ROCKER_BOGUS_REG2              0x0008
-#define ROCKER_BOGUS_REG3              0x000c
-
-/* Rocker test registers */
-#define ROCKER_TEST_REG                        0x0010
-#define ROCKER_TEST_REG64              0x0018  /* 8-byte */
-#define ROCKER_TEST_IRQ                        0x0020
-#define ROCKER_TEST_DMA_ADDR           0x0028  /* 8-byte */
-#define ROCKER_TEST_DMA_SIZE           0x0030
-#define ROCKER_TEST_DMA_CTRL           0x0034
-
-/* Rocker test register ctrl */
-#define ROCKER_TEST_DMA_CTRL_CLEAR     BIT(0)
-#define ROCKER_TEST_DMA_CTRL_FILL      BIT(1)
-#define ROCKER_TEST_DMA_CTRL_INVERT    BIT(2)
-
-/* Rocker DMA ring register offsets */
-#define ROCKER_DMA_DESC_ADDR(x)                (0x1000 + (x) * 32)  /* 8-byte */
-#define ROCKER_DMA_DESC_SIZE(x)                (0x1008 + (x) * 32)
-#define ROCKER_DMA_DESC_HEAD(x)                (0x100c + (x) * 32)
-#define ROCKER_DMA_DESC_TAIL(x)                (0x1010 + (x) * 32)
-#define ROCKER_DMA_DESC_CTRL(x)                (0x1014 + (x) * 32)
-#define ROCKER_DMA_DESC_CREDITS(x)     (0x1018 + (x) * 32)
-#define ROCKER_DMA_DESC_RES1(x)                (0x101c + (x) * 32)
-
-/* Rocker dma ctrl register bits */
-#define ROCKER_DMA_DESC_CTRL_RESET     BIT(0)
-
-/* Rocker DMA ring types */
-enum rocker_dma_type {
-       ROCKER_DMA_CMD,
-       ROCKER_DMA_EVENT,
-       __ROCKER_DMA_TX,
-       __ROCKER_DMA_RX,
-#define ROCKER_DMA_TX(port) (__ROCKER_DMA_TX + (port) * 2)
-#define ROCKER_DMA_RX(port) (__ROCKER_DMA_RX + (port) * 2)
-};
-
-/* Rocker DMA ring size limits and default sizes */
-#define ROCKER_DMA_SIZE_MIN            2ul
-#define ROCKER_DMA_SIZE_MAX            65536ul
-#define ROCKER_DMA_CMD_DEFAULT_SIZE    32ul
-#define ROCKER_DMA_EVENT_DEFAULT_SIZE  32ul
-#define ROCKER_DMA_TX_DEFAULT_SIZE     64ul
-#define ROCKER_DMA_TX_DESC_SIZE                256
-#define ROCKER_DMA_RX_DEFAULT_SIZE     64ul
-#define ROCKER_DMA_RX_DESC_SIZE                256
-
-/* Rocker DMA descriptor struct */
-struct rocker_desc {
-       u64 buf_addr;
-       u64 cookie;
-       u16 buf_size;
-       u16 tlv_size;
-       u16 resv[5];
-       u16 comp_err;
-};
-
-#define ROCKER_DMA_DESC_COMP_ERR_GEN   BIT(15)
-
-/* Rocker DMA TLV struct */
-struct rocker_tlv {
-       u32 type;
-       u16 len;
-};
-
-/* TLVs */
-enum {
-       ROCKER_TLV_CMD_UNSPEC,
-       ROCKER_TLV_CMD_TYPE,    /* u16 */
-       ROCKER_TLV_CMD_INFO,    /* nest */
-
-       __ROCKER_TLV_CMD_MAX,
-       ROCKER_TLV_CMD_MAX = __ROCKER_TLV_CMD_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_CMD_TYPE_UNSPEC,
-       ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS,
-       ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
-       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
-
-       ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS,
-       ROCKER_TLV_CMD_TYPE_GET_PORT_STATS,
-
-       __ROCKER_TLV_CMD_TYPE_MAX,
-       ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_CMD_PORT_SETTINGS_UNSPEC,
-       ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,             /* u32 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_SPEED,             /* u32 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX,            /* u8 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG,           /* u8 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,           /* binary */
-       ROCKER_TLV_CMD_PORT_SETTINGS_MODE,              /* u8 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,          /* u8 */
-       ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,         /* binary */
-       ROCKER_TLV_CMD_PORT_SETTINGS_MTU,               /* u16 */
-
-       __ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
-       ROCKER_TLV_CMD_PORT_SETTINGS_MAX =
-                       __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_CMD_PORT_STATS_UNSPEC,
-       ROCKER_TLV_CMD_PORT_STATS_PPORT,            /* u32 */
-
-       ROCKER_TLV_CMD_PORT_STATS_RX_PKTS,          /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_RX_BYTES,         /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED,       /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS,        /* u64 */
-
-       ROCKER_TLV_CMD_PORT_STATS_TX_PKTS,          /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_TX_BYTES,         /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED,       /* u64 */
-       ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS,        /* u64 */
-
-       __ROCKER_TLV_CMD_PORT_STATS_MAX,
-       ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1,
-};
-
-enum rocker_port_mode {
-       ROCKER_PORT_MODE_OF_DPA,
-};
-
-enum {
-       ROCKER_TLV_EVENT_UNSPEC,
-       ROCKER_TLV_EVENT_TYPE,  /* u16 */
-       ROCKER_TLV_EVENT_INFO,  /* nest */
-
-       __ROCKER_TLV_EVENT_MAX,
-       ROCKER_TLV_EVENT_MAX = __ROCKER_TLV_EVENT_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_EVENT_TYPE_UNSPEC,
-       ROCKER_TLV_EVENT_TYPE_LINK_CHANGED,
-       ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN,
-
-       __ROCKER_TLV_EVENT_TYPE_MAX,
-       ROCKER_TLV_EVENT_TYPE_MAX = __ROCKER_TLV_EVENT_TYPE_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_EVENT_LINK_CHANGED_UNSPEC,
-       ROCKER_TLV_EVENT_LINK_CHANGED_PPORT,    /* u32 */
-       ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,   /* u8 */
-
-       __ROCKER_TLV_EVENT_LINK_CHANGED_MAX,
-       ROCKER_TLV_EVENT_LINK_CHANGED_MAX =
-                       __ROCKER_TLV_EVENT_LINK_CHANGED_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_EVENT_MAC_VLAN_UNSPEC,
-       ROCKER_TLV_EVENT_MAC_VLAN_PPORT,        /* u32 */
-       ROCKER_TLV_EVENT_MAC_VLAN_MAC,          /* binary */
-       ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID,      /* __be16 */
-
-       __ROCKER_TLV_EVENT_MAC_VLAN_MAX,
-       ROCKER_TLV_EVENT_MAC_VLAN_MAX = __ROCKER_TLV_EVENT_MAC_VLAN_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_RX_UNSPEC,
-       ROCKER_TLV_RX_FLAGS,            /* u16, see ROCKER_RX_FLAGS_ */
-       ROCKER_TLV_RX_CSUM,             /* u16 */
-       ROCKER_TLV_RX_FRAG_ADDR,        /* u64 */
-       ROCKER_TLV_RX_FRAG_MAX_LEN,     /* u16 */
-       ROCKER_TLV_RX_FRAG_LEN,         /* u16 */
-
-       __ROCKER_TLV_RX_MAX,
-       ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1,
-};
-
-#define ROCKER_RX_FLAGS_IPV4                   BIT(0)
-#define ROCKER_RX_FLAGS_IPV6                   BIT(1)
-#define ROCKER_RX_FLAGS_CSUM_CALC              BIT(2)
-#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD         BIT(3)
-#define ROCKER_RX_FLAGS_IP_FRAG                        BIT(4)
-#define ROCKER_RX_FLAGS_TCP                    BIT(5)
-#define ROCKER_RX_FLAGS_UDP                    BIT(6)
-#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD      BIT(7)
-#define ROCKER_RX_FLAGS_FWD_OFFLOAD            BIT(8)
-
-enum {
-       ROCKER_TLV_TX_UNSPEC,
-       ROCKER_TLV_TX_OFFLOAD,          /* u8, see ROCKER_TX_OFFLOAD_ */
-       ROCKER_TLV_TX_L3_CSUM_OFF,      /* u16 */
-       ROCKER_TLV_TX_TSO_MSS,          /* u16 */
-       ROCKER_TLV_TX_TSO_HDR_LEN,      /* u16 */
-       ROCKER_TLV_TX_FRAGS,            /* array */
-
-       __ROCKER_TLV_TX_MAX,
-       ROCKER_TLV_TX_MAX = __ROCKER_TLV_TX_MAX - 1,
-};
-
-#define ROCKER_TX_OFFLOAD_NONE         0
-#define ROCKER_TX_OFFLOAD_IP_CSUM      1
-#define ROCKER_TX_OFFLOAD_TCP_UDP_CSUM 2
-#define ROCKER_TX_OFFLOAD_L3_CSUM      3
-#define ROCKER_TX_OFFLOAD_TSO          4
-
-#define ROCKER_TX_FRAGS_MAX            16
-
-enum {
-       ROCKER_TLV_TX_FRAG_UNSPEC,
-       ROCKER_TLV_TX_FRAG,             /* nest */
-
-       __ROCKER_TLV_TX_FRAG_MAX,
-       ROCKER_TLV_TX_FRAG_MAX = __ROCKER_TLV_TX_FRAG_MAX - 1,
-};
-
-enum {
-       ROCKER_TLV_TX_FRAG_ATTR_UNSPEC,
-       ROCKER_TLV_TX_FRAG_ATTR_ADDR,   /* u64 */
-       ROCKER_TLV_TX_FRAG_ATTR_LEN,    /* u16 */
-
-       __ROCKER_TLV_TX_FRAG_ATTR_MAX,
-       ROCKER_TLV_TX_FRAG_ATTR_MAX = __ROCKER_TLV_TX_FRAG_ATTR_MAX - 1,
-};
-
-/* cmd info nested for OF-DPA msgs */
-enum {
-       ROCKER_TLV_OF_DPA_UNSPEC,
-       ROCKER_TLV_OF_DPA_TABLE_ID,             /* u16 */
-       ROCKER_TLV_OF_DPA_PRIORITY,             /* u32 */
-       ROCKER_TLV_OF_DPA_HARDTIME,             /* u32 */
-       ROCKER_TLV_OF_DPA_IDLETIME,             /* u32 */
-       ROCKER_TLV_OF_DPA_COOKIE,               /* u64 */
-       ROCKER_TLV_OF_DPA_IN_PPORT,             /* u32 */
-       ROCKER_TLV_OF_DPA_IN_PPORT_MASK,        /* u32 */
-       ROCKER_TLV_OF_DPA_OUT_PPORT,            /* u32 */
-       ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,        /* u16 */
-       ROCKER_TLV_OF_DPA_GROUP_ID,             /* u32 */
-       ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,       /* u32 */
-       ROCKER_TLV_OF_DPA_GROUP_COUNT,          /* u16 */
-       ROCKER_TLV_OF_DPA_GROUP_IDS,            /* u32 array */
-       ROCKER_TLV_OF_DPA_VLAN_ID,              /* __be16 */
-       ROCKER_TLV_OF_DPA_VLAN_ID_MASK,         /* __be16 */
-       ROCKER_TLV_OF_DPA_VLAN_PCP,             /* __be16 */
-       ROCKER_TLV_OF_DPA_VLAN_PCP_MASK,        /* __be16 */
-       ROCKER_TLV_OF_DPA_VLAN_PCP_ACTION,      /* u8 */
-       ROCKER_TLV_OF_DPA_NEW_VLAN_ID,          /* __be16 */
-       ROCKER_TLV_OF_DPA_NEW_VLAN_PCP,         /* u8 */
-       ROCKER_TLV_OF_DPA_TUNNEL_ID,            /* u32 */
-       ROCKER_TLV_OF_DPA_TUNNEL_LPORT,         /* u32 */
-       ROCKER_TLV_OF_DPA_ETHERTYPE,            /* __be16 */
-       ROCKER_TLV_OF_DPA_DST_MAC,              /* binary */
-       ROCKER_TLV_OF_DPA_DST_MAC_MASK,         /* binary */
-       ROCKER_TLV_OF_DPA_SRC_MAC,              /* binary */
-       ROCKER_TLV_OF_DPA_SRC_MAC_MASK,         /* binary */
-       ROCKER_TLV_OF_DPA_IP_PROTO,             /* u8 */
-       ROCKER_TLV_OF_DPA_IP_PROTO_MASK,        /* u8 */
-       ROCKER_TLV_OF_DPA_IP_DSCP,              /* u8 */
-       ROCKER_TLV_OF_DPA_IP_DSCP_MASK,         /* u8 */
-       ROCKER_TLV_OF_DPA_IP_DSCP_ACTION,       /* u8 */
-       ROCKER_TLV_OF_DPA_NEW_IP_DSCP,          /* u8 */
-       ROCKER_TLV_OF_DPA_IP_ECN,               /* u8 */
-       ROCKER_TLV_OF_DPA_IP_ECN_MASK,          /* u8 */
-       ROCKER_TLV_OF_DPA_DST_IP,               /* __be32 */
-       ROCKER_TLV_OF_DPA_DST_IP_MASK,          /* __be32 */
-       ROCKER_TLV_OF_DPA_SRC_IP,               /* __be32 */
-       ROCKER_TLV_OF_DPA_SRC_IP_MASK,          /* __be32 */
-       ROCKER_TLV_OF_DPA_DST_IPV6,             /* binary */
-       ROCKER_TLV_OF_DPA_DST_IPV6_MASK,        /* binary */
-       ROCKER_TLV_OF_DPA_SRC_IPV6,             /* binary */
-       ROCKER_TLV_OF_DPA_SRC_IPV6_MASK,        /* binary */
-       ROCKER_TLV_OF_DPA_SRC_ARP_IP,           /* __be32 */
-       ROCKER_TLV_OF_DPA_SRC_ARP_IP_MASK,      /* __be32 */
-       ROCKER_TLV_OF_DPA_L4_DST_PORT,          /* __be16 */
-       ROCKER_TLV_OF_DPA_L4_DST_PORT_MASK,     /* __be16 */
-       ROCKER_TLV_OF_DPA_L4_SRC_PORT,          /* __be16 */
-       ROCKER_TLV_OF_DPA_L4_SRC_PORT_MASK,     /* __be16 */
-       ROCKER_TLV_OF_DPA_ICMP_TYPE,            /* u8 */
-       ROCKER_TLV_OF_DPA_ICMP_TYPE_MASK,       /* u8 */
-       ROCKER_TLV_OF_DPA_ICMP_CODE,            /* u8 */
-       ROCKER_TLV_OF_DPA_ICMP_CODE_MASK,       /* u8 */
-       ROCKER_TLV_OF_DPA_IPV6_LABEL,           /* __be32 */
-       ROCKER_TLV_OF_DPA_IPV6_LABEL_MASK,      /* __be32 */
-       ROCKER_TLV_OF_DPA_QUEUE_ID_ACTION,      /* u8 */
-       ROCKER_TLV_OF_DPA_NEW_QUEUE_ID,         /* u8 */
-       ROCKER_TLV_OF_DPA_CLEAR_ACTIONS,        /* u32 */
-       ROCKER_TLV_OF_DPA_POP_VLAN,             /* u8 */
-       ROCKER_TLV_OF_DPA_TTL_CHECK,            /* u8 */
-       ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,      /* u8 */
-
-       __ROCKER_TLV_OF_DPA_MAX,
-       ROCKER_TLV_OF_DPA_MAX = __ROCKER_TLV_OF_DPA_MAX - 1,
-};
-
-/* OF-DPA table IDs */
-
-enum rocker_of_dpa_table_id {
-       ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT = 0,
-       ROCKER_OF_DPA_TABLE_ID_VLAN = 10,
-       ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC = 20,
-       ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING = 30,
-       ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING = 40,
-       ROCKER_OF_DPA_TABLE_ID_BRIDGING = 50,
-       ROCKER_OF_DPA_TABLE_ID_ACL_POLICY = 60,
-};
-
-/* OF-DPA flow stats */
-enum {
-       ROCKER_TLV_OF_DPA_FLOW_STAT_UNSPEC,
-       ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION,   /* u32 */
-       ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS,    /* u64 */
-       ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS,    /* u64 */
-
-       __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX,
-       ROCKER_TLV_OF_DPA_FLOW_STAT_MAX = __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX - 1,
-};
-
-/* OF-DPA group types */
-enum rocker_of_dpa_group_type {
-       ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE = 0,
-       ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE,
-       ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST,
-       ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST,
-       ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD,
-       ROCKER_OF_DPA_GROUP_TYPE_L3_INTERFACE,
-       ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST,
-       ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP,
-       ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY,
-};
-
-/* OF-DPA group L2 overlay types */
-enum rocker_of_dpa_overlay_type {
-       ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_UCAST = 0,
-       ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_MCAST,
-       ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_UCAST,
-       ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_MCAST,
-};
-
-/* OF-DPA group ID encoding */
-#define ROCKER_GROUP_TYPE_SHIFT 28
-#define ROCKER_GROUP_TYPE_MASK 0xf0000000
-#define ROCKER_GROUP_VLAN_SHIFT 16
-#define ROCKER_GROUP_VLAN_MASK 0x0fff0000
-#define ROCKER_GROUP_PORT_SHIFT 0
-#define ROCKER_GROUP_PORT_MASK 0x0000ffff
-#define ROCKER_GROUP_TUNNEL_ID_SHIFT 12
-#define ROCKER_GROUP_TUNNEL_ID_MASK 0x0ffff000
-#define ROCKER_GROUP_SUBTYPE_SHIFT 10
-#define ROCKER_GROUP_SUBTYPE_MASK 0x00000c00
-#define ROCKER_GROUP_INDEX_SHIFT 0
-#define ROCKER_GROUP_INDEX_MASK 0x0000ffff
-#define ROCKER_GROUP_INDEX_LONG_SHIFT 0
-#define ROCKER_GROUP_INDEX_LONG_MASK 0x0fffffff
-
-#define ROCKER_GROUP_TYPE_GET(group_id) \
-       (((group_id) & ROCKER_GROUP_TYPE_MASK) >> ROCKER_GROUP_TYPE_SHIFT)
-#define ROCKER_GROUP_TYPE_SET(type) \
-       (((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK)
-#define ROCKER_GROUP_VLAN_GET(group_id) \
-       (((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT)
-#define ROCKER_GROUP_VLAN_SET(vlan_id) \
-       (((vlan_id) << ROCKER_GROUP_VLAN_SHIFT) & ROCKER_GROUP_VLAN_MASK)
-#define ROCKER_GROUP_PORT_GET(group_id) \
-       (((group_id) & ROCKER_GROUP_PORT_MASK) >> ROCKER_GROUP_PORT_SHIFT)
-#define ROCKER_GROUP_PORT_SET(port) \
-       (((port) << ROCKER_GROUP_PORT_SHIFT) & ROCKER_GROUP_PORT_MASK)
-#define ROCKER_GROUP_INDEX_GET(group_id) \
-       (((group_id) & ROCKER_GROUP_INDEX_MASK) >> ROCKER_GROUP_INDEX_SHIFT)
-#define ROCKER_GROUP_INDEX_SET(index) \
-       (((index) << ROCKER_GROUP_INDEX_SHIFT) & ROCKER_GROUP_INDEX_MASK)
-#define ROCKER_GROUP_INDEX_LONG_GET(group_id) \
-       (((group_id) & ROCKER_GROUP_INDEX_LONG_MASK) >> \
-        ROCKER_GROUP_INDEX_LONG_SHIFT)
-#define ROCKER_GROUP_INDEX_LONG_SET(index) \
-       (((index) << ROCKER_GROUP_INDEX_LONG_SHIFT) & \
-        ROCKER_GROUP_INDEX_LONG_MASK)
-
-#define ROCKER_GROUP_NONE 0
-#define ROCKER_GROUP_L2_INTERFACE(vlan_id, port) \
-       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) |\
-        ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_PORT_SET(port))
-#define ROCKER_GROUP_L2_REWRITE(index) \
-       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE) |\
-        ROCKER_GROUP_INDEX_LONG_SET(index))
-#define ROCKER_GROUP_L2_MCAST(vlan_id, index) \
-       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) |\
-        ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
-#define ROCKER_GROUP_L2_FLOOD(vlan_id, index) \
-       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) |\
-       ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
-#define ROCKER_GROUP_L3_UNICAST(index) \
-       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST) |\
-        ROCKER_GROUP_INDEX_LONG_SET(index))
-
-/* Rocker general purpose registers */
-#define ROCKER_CONTROL                 0x0300
-#define ROCKER_PORT_PHYS_COUNT         0x0304
-#define ROCKER_PORT_PHYS_LINK_STATUS   0x0310 /* 8-byte */
-#define ROCKER_PORT_PHYS_ENABLE                0x0318 /* 8-byte */
-#define ROCKER_SWITCH_ID               0x0320 /* 8-byte */
-
-/* Rocker control bits */
-#define ROCKER_CONTROL_RESET           BIT(0)
+#include <linux/netdevice.h>
+#include <net/neighbour.h>
+#include <net/switchdev.h>
+
+#include "rocker_hw.h"
+
+struct rocker_desc_info {
+       char *data; /* mapped */
+       size_t data_size;
+       size_t tlv_size;
+       struct rocker_desc *desc;
+       dma_addr_t mapaddr;
+};
+
+struct rocker_dma_ring_info {
+       size_t size;
+       u32 head;
+       u32 tail;
+       struct rocker_desc *desc; /* mapped */
+       dma_addr_t mapaddr;
+       struct rocker_desc_info *desc_info;
+       unsigned int type;
+};
+
+struct rocker;
+
+struct rocker_port {
+       struct net_device *dev;
+       struct rocker *rocker;
+       void *wpriv;
+       unsigned int port_number;
+       u32 pport;
+       struct napi_struct napi_tx;
+       struct napi_struct napi_rx;
+       struct rocker_dma_ring_info tx_ring;
+       struct rocker_dma_ring_info rx_ring;
+};
+
+struct rocker_world_ops;
+
+struct rocker {
+       struct pci_dev *pdev;
+       u8 __iomem *hw_addr;
+       struct msix_entry *msix_entries;
+       unsigned int port_count;
+       struct rocker_port **ports;
+       struct {
+               u64 id;
+       } hw;
+       spinlock_t cmd_ring_lock;               /* for cmd ring accesses */
+       struct rocker_dma_ring_info cmd_ring;
+       struct rocker_dma_ring_info event_ring;
+       struct rocker_world_ops *wops;
+       void *wpriv;
+};
+
+typedef int (*rocker_cmd_prep_cb_t)(const struct rocker_port *rocker_port,
+                                   struct rocker_desc_info *desc_info,
+                                   void *priv);
+
+typedef int (*rocker_cmd_proc_cb_t)(const struct rocker_port *rocker_port,
+                                   const struct rocker_desc_info *desc_info,
+                                   void *priv);
+
+int rocker_cmd_exec(struct rocker_port *rocker_port, bool nowait,
+                   rocker_cmd_prep_cb_t prepare, void *prepare_priv,
+                   rocker_cmd_proc_cb_t process, void *process_priv);
+
+int rocker_port_set_learning(struct rocker_port *rocker_port,
+                            bool learning);
+
+struct rocker_world_ops {
+       const char *kind;
+       size_t priv_size;
+       size_t port_priv_size;
+       u8 mode;
+       int (*init)(struct rocker *rocker);
+       void (*fini)(struct rocker *rocker);
+       int (*port_pre_init)(struct rocker_port *rocker_port);
+       int (*port_init)(struct rocker_port *rocker_port);
+       void (*port_fini)(struct rocker_port *rocker_port);
+       void (*port_post_fini)(struct rocker_port *rocker_port);
+       int (*port_open)(struct rocker_port *rocker_port);
+       void (*port_stop)(struct rocker_port *rocker_port);
+       int (*port_attr_stp_state_set)(struct rocker_port *rocker_port,
+                                      u8 state,
+                                      struct switchdev_trans *trans);
+       int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port,
+                                         unsigned long brport_flags,
+                                         struct switchdev_trans *trans);
+       int (*port_attr_bridge_flags_get)(const struct rocker_port *rocker_port,
+                                         unsigned long *p_brport_flags);
+       int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port,
+                                               u32 ageing_time,
+                                               struct switchdev_trans *trans);
+       int (*port_obj_vlan_add)(struct rocker_port *rocker_port,
+                                const struct switchdev_obj_port_vlan *vlan,
+                                struct switchdev_trans *trans);
+       int (*port_obj_vlan_del)(struct rocker_port *rocker_port,
+                                const struct switchdev_obj_port_vlan *vlan);
+       int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port,
+                                 struct switchdev_obj_port_vlan *vlan,
+                                 switchdev_obj_dump_cb_t *cb);
+       int (*port_obj_fib4_add)(struct rocker_port *rocker_port,
+                                const struct switchdev_obj_ipv4_fib *fib4,
+                                struct switchdev_trans *trans);
+       int (*port_obj_fib4_del)(struct rocker_port *rocker_port,
+                                const struct switchdev_obj_ipv4_fib *fib4);
+       int (*port_obj_fdb_add)(struct rocker_port *rocker_port,
+                               const struct switchdev_obj_port_fdb *fdb,
+                               struct switchdev_trans *trans);
+       int (*port_obj_fdb_del)(struct rocker_port *rocker_port,
+                               const struct switchdev_obj_port_fdb *fdb);
+       int (*port_obj_fdb_dump)(const struct rocker_port *rocker_port,
+                                struct switchdev_obj_port_fdb *fdb,
+                                switchdev_obj_dump_cb_t *cb);
+       int (*port_master_linked)(struct rocker_port *rocker_port,
+                                 struct net_device *master);
+       int (*port_master_unlinked)(struct rocker_port *rocker_port,
+                                   struct net_device *master);
+       int (*port_neigh_update)(struct rocker_port *rocker_port,
+                                struct neighbour *n);
+       int (*port_neigh_destroy)(struct rocker_port *rocker_port,
+                                 struct neighbour *n);
+       int (*port_ev_mac_vlan_seen)(struct rocker_port *rocker_port,
+                                    const unsigned char *addr,
+                                    __be16 vlan_id);
+};
+
+extern struct rocker_world_ops rocker_ofdpa_ops;
 
 #endif
diff --git a/drivers/net/ethernet/rocker/rocker_hw.h b/drivers/net/ethernet/rocker/rocker_hw.h
new file mode 100644 (file)
index 0000000..2adfe88
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * drivers/net/ethernet/rocker/rocker_hw.h - Rocker switch device driver
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
+ * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ROCKER_HW_H
+#define _ROCKER_HW_H
+
+#include <linux/types.h>
+
+/* Return codes */
+enum {
+       ROCKER_OK = 0,
+       ROCKER_ENOENT = 2,
+       ROCKER_ENXIO = 6,
+       ROCKER_ENOMEM = 12,
+       ROCKER_EEXIST = 17,
+       ROCKER_EINVAL = 22,
+       ROCKER_EMSGSIZE = 90,
+       ROCKER_ENOTSUP = 95,
+       ROCKER_ENOBUFS = 105,
+};
+
+#define ROCKER_FP_PORTS_MAX 62
+
+#define PCI_VENDOR_ID_REDHAT           0x1b36
+#define PCI_DEVICE_ID_REDHAT_ROCKER    0x0006
+
+#define ROCKER_PCI_BAR0_SIZE           0x2000
+
+/* MSI-X vectors */
+enum {
+       ROCKER_MSIX_VEC_CMD,
+       ROCKER_MSIX_VEC_EVENT,
+       ROCKER_MSIX_VEC_TEST,
+       ROCKER_MSIX_VEC_RESERVED0,
+       __ROCKER_MSIX_VEC_TX,
+       __ROCKER_MSIX_VEC_RX,
+#define ROCKER_MSIX_VEC_TX(port) \
+       (__ROCKER_MSIX_VEC_TX + ((port) * 2))
+#define ROCKER_MSIX_VEC_RX(port) \
+       (__ROCKER_MSIX_VEC_RX + ((port) * 2))
+#define ROCKER_MSIX_VEC_COUNT(portcnt) \
+       (ROCKER_MSIX_VEC_RX((portcnt - 1)) + 1)
+};
+
+/* Rocker bogus registers */
+#define ROCKER_BOGUS_REG0              0x0000
+#define ROCKER_BOGUS_REG1              0x0004
+#define ROCKER_BOGUS_REG2              0x0008
+#define ROCKER_BOGUS_REG3              0x000c
+
+/* Rocker test registers */
+#define ROCKER_TEST_REG                        0x0010
+#define ROCKER_TEST_REG64              0x0018  /* 8-byte */
+#define ROCKER_TEST_IRQ                        0x0020
+#define ROCKER_TEST_DMA_ADDR           0x0028  /* 8-byte */
+#define ROCKER_TEST_DMA_SIZE           0x0030
+#define ROCKER_TEST_DMA_CTRL           0x0034
+
+/* Rocker test register ctrl */
+#define ROCKER_TEST_DMA_CTRL_CLEAR     BIT(0)
+#define ROCKER_TEST_DMA_CTRL_FILL      BIT(1)
+#define ROCKER_TEST_DMA_CTRL_INVERT    BIT(2)
+
+/* Rocker DMA ring register offsets */
+#define ROCKER_DMA_DESC_ADDR(x)                (0x1000 + (x) * 32)  /* 8-byte */
+#define ROCKER_DMA_DESC_SIZE(x)                (0x1008 + (x) * 32)
+#define ROCKER_DMA_DESC_HEAD(x)                (0x100c + (x) * 32)
+#define ROCKER_DMA_DESC_TAIL(x)                (0x1010 + (x) * 32)
+#define ROCKER_DMA_DESC_CTRL(x)                (0x1014 + (x) * 32)
+#define ROCKER_DMA_DESC_CREDITS(x)     (0x1018 + (x) * 32)
+#define ROCKER_DMA_DESC_RES1(x)                (0x101c + (x) * 32)
+
+/* Rocker dma ctrl register bits */
+#define ROCKER_DMA_DESC_CTRL_RESET     BIT(0)
+
+/* Rocker DMA ring types */
+enum rocker_dma_type {
+       ROCKER_DMA_CMD,
+       ROCKER_DMA_EVENT,
+       __ROCKER_DMA_TX,
+       __ROCKER_DMA_RX,
+#define ROCKER_DMA_TX(port) (__ROCKER_DMA_TX + (port) * 2)
+#define ROCKER_DMA_RX(port) (__ROCKER_DMA_RX + (port) * 2)
+};
+
+/* Rocker DMA ring size limits and default sizes */
+#define ROCKER_DMA_SIZE_MIN            2ul
+#define ROCKER_DMA_SIZE_MAX            65536ul
+#define ROCKER_DMA_CMD_DEFAULT_SIZE    32ul
+#define ROCKER_DMA_EVENT_DEFAULT_SIZE  32ul
+#define ROCKER_DMA_TX_DEFAULT_SIZE     64ul
+#define ROCKER_DMA_TX_DESC_SIZE                256
+#define ROCKER_DMA_RX_DEFAULT_SIZE     64ul
+#define ROCKER_DMA_RX_DESC_SIZE                256
+
+/* Rocker DMA descriptor struct */
+struct rocker_desc {
+       u64 buf_addr;
+       u64 cookie;
+       u16 buf_size;
+       u16 tlv_size;
+       u16 resv[5];
+       u16 comp_err;
+};
+
+#define ROCKER_DMA_DESC_COMP_ERR_GEN   BIT(15)
+
+/* Rocker DMA TLV struct */
+struct rocker_tlv {
+       u32 type;
+       u16 len;
+};
+
+/* TLVs */
+enum {
+       ROCKER_TLV_CMD_UNSPEC,
+       ROCKER_TLV_CMD_TYPE,    /* u16 */
+       ROCKER_TLV_CMD_INFO,    /* nest */
+
+       __ROCKER_TLV_CMD_MAX,
+       ROCKER_TLV_CMD_MAX = __ROCKER_TLV_CMD_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_CMD_TYPE_UNSPEC,
+       ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS,
+       ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
+       ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
+
+       ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS,
+       ROCKER_TLV_CMD_TYPE_GET_PORT_STATS,
+
+       __ROCKER_TLV_CMD_TYPE_MAX,
+       ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_CMD_PORT_SETTINGS_UNSPEC,
+       ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,             /* u32 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_SPEED,             /* u32 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX,            /* u8 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG,           /* u8 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,           /* binary */
+       ROCKER_TLV_CMD_PORT_SETTINGS_MODE,              /* u8 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,          /* u8 */
+       ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,         /* binary */
+       ROCKER_TLV_CMD_PORT_SETTINGS_MTU,               /* u16 */
+
+       __ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
+       ROCKER_TLV_CMD_PORT_SETTINGS_MAX =
+                       __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_CMD_PORT_STATS_UNSPEC,
+       ROCKER_TLV_CMD_PORT_STATS_PPORT,            /* u32 */
+
+       ROCKER_TLV_CMD_PORT_STATS_RX_PKTS,          /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_RX_BYTES,         /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED,       /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS,        /* u64 */
+
+       ROCKER_TLV_CMD_PORT_STATS_TX_PKTS,          /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_TX_BYTES,         /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED,       /* u64 */
+       ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS,        /* u64 */
+
+       __ROCKER_TLV_CMD_PORT_STATS_MAX,
+       ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1,
+};
+
+enum rocker_port_mode {
+       ROCKER_PORT_MODE_OF_DPA,
+};
+
+enum {
+       ROCKER_TLV_EVENT_UNSPEC,
+       ROCKER_TLV_EVENT_TYPE,  /* u16 */
+       ROCKER_TLV_EVENT_INFO,  /* nest */
+
+       __ROCKER_TLV_EVENT_MAX,
+       ROCKER_TLV_EVENT_MAX = __ROCKER_TLV_EVENT_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_EVENT_TYPE_UNSPEC,
+       ROCKER_TLV_EVENT_TYPE_LINK_CHANGED,
+       ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN,
+
+       __ROCKER_TLV_EVENT_TYPE_MAX,
+       ROCKER_TLV_EVENT_TYPE_MAX = __ROCKER_TLV_EVENT_TYPE_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_EVENT_LINK_CHANGED_UNSPEC,
+       ROCKER_TLV_EVENT_LINK_CHANGED_PPORT,    /* u32 */
+       ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,   /* u8 */
+
+       __ROCKER_TLV_EVENT_LINK_CHANGED_MAX,
+       ROCKER_TLV_EVENT_LINK_CHANGED_MAX =
+                       __ROCKER_TLV_EVENT_LINK_CHANGED_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_EVENT_MAC_VLAN_UNSPEC,
+       ROCKER_TLV_EVENT_MAC_VLAN_PPORT,        /* u32 */
+       ROCKER_TLV_EVENT_MAC_VLAN_MAC,          /* binary */
+       ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID,      /* __be16 */
+
+       __ROCKER_TLV_EVENT_MAC_VLAN_MAX,
+       ROCKER_TLV_EVENT_MAC_VLAN_MAX = __ROCKER_TLV_EVENT_MAC_VLAN_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_RX_UNSPEC,
+       ROCKER_TLV_RX_FLAGS,            /* u16, see ROCKER_RX_FLAGS_ */
+       ROCKER_TLV_RX_CSUM,             /* u16 */
+       ROCKER_TLV_RX_FRAG_ADDR,        /* u64 */
+       ROCKER_TLV_RX_FRAG_MAX_LEN,     /* u16 */
+       ROCKER_TLV_RX_FRAG_LEN,         /* u16 */
+
+       __ROCKER_TLV_RX_MAX,
+       ROCKER_TLV_RX_MAX = __ROCKER_TLV_RX_MAX - 1,
+};
+
+#define ROCKER_RX_FLAGS_IPV4                   BIT(0)
+#define ROCKER_RX_FLAGS_IPV6                   BIT(1)
+#define ROCKER_RX_FLAGS_CSUM_CALC              BIT(2)
+#define ROCKER_RX_FLAGS_IPV4_CSUM_GOOD         BIT(3)
+#define ROCKER_RX_FLAGS_IP_FRAG                        BIT(4)
+#define ROCKER_RX_FLAGS_TCP                    BIT(5)
+#define ROCKER_RX_FLAGS_UDP                    BIT(6)
+#define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD      BIT(7)
+#define ROCKER_RX_FLAGS_FWD_OFFLOAD            BIT(8)
+
+enum {
+       ROCKER_TLV_TX_UNSPEC,
+       ROCKER_TLV_TX_OFFLOAD,          /* u8, see ROCKER_TX_OFFLOAD_ */
+       ROCKER_TLV_TX_L3_CSUM_OFF,      /* u16 */
+       ROCKER_TLV_TX_TSO_MSS,          /* u16 */
+       ROCKER_TLV_TX_TSO_HDR_LEN,      /* u16 */
+       ROCKER_TLV_TX_FRAGS,            /* array */
+
+       __ROCKER_TLV_TX_MAX,
+       ROCKER_TLV_TX_MAX = __ROCKER_TLV_TX_MAX - 1,
+};
+
+#define ROCKER_TX_OFFLOAD_NONE         0
+#define ROCKER_TX_OFFLOAD_IP_CSUM      1
+#define ROCKER_TX_OFFLOAD_TCP_UDP_CSUM 2
+#define ROCKER_TX_OFFLOAD_L3_CSUM      3
+#define ROCKER_TX_OFFLOAD_TSO          4
+
+#define ROCKER_TX_FRAGS_MAX            16
+
+enum {
+       ROCKER_TLV_TX_FRAG_UNSPEC,
+       ROCKER_TLV_TX_FRAG,             /* nest */
+
+       __ROCKER_TLV_TX_FRAG_MAX,
+       ROCKER_TLV_TX_FRAG_MAX = __ROCKER_TLV_TX_FRAG_MAX - 1,
+};
+
+enum {
+       ROCKER_TLV_TX_FRAG_ATTR_UNSPEC,
+       ROCKER_TLV_TX_FRAG_ATTR_ADDR,   /* u64 */
+       ROCKER_TLV_TX_FRAG_ATTR_LEN,    /* u16 */
+
+       __ROCKER_TLV_TX_FRAG_ATTR_MAX,
+       ROCKER_TLV_TX_FRAG_ATTR_MAX = __ROCKER_TLV_TX_FRAG_ATTR_MAX - 1,
+};
+
+/* cmd info nested for OF-DPA msgs */
+enum {
+       ROCKER_TLV_OF_DPA_UNSPEC,
+       ROCKER_TLV_OF_DPA_TABLE_ID,             /* u16 */
+       ROCKER_TLV_OF_DPA_PRIORITY,             /* u32 */
+       ROCKER_TLV_OF_DPA_HARDTIME,             /* u32 */
+       ROCKER_TLV_OF_DPA_IDLETIME,             /* u32 */
+       ROCKER_TLV_OF_DPA_COOKIE,               /* u64 */
+       ROCKER_TLV_OF_DPA_IN_PPORT,             /* u32 */
+       ROCKER_TLV_OF_DPA_IN_PPORT_MASK,        /* u32 */
+       ROCKER_TLV_OF_DPA_OUT_PPORT,            /* u32 */
+       ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,        /* u16 */
+       ROCKER_TLV_OF_DPA_GROUP_ID,             /* u32 */
+       ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,       /* u32 */
+       ROCKER_TLV_OF_DPA_GROUP_COUNT,          /* u16 */
+       ROCKER_TLV_OF_DPA_GROUP_IDS,            /* u32 array */
+       ROCKER_TLV_OF_DPA_VLAN_ID,              /* __be16 */
+       ROCKER_TLV_OF_DPA_VLAN_ID_MASK,         /* __be16 */
+       ROCKER_TLV_OF_DPA_VLAN_PCP,             /* __be16 */
+       ROCKER_TLV_OF_DPA_VLAN_PCP_MASK,        /* __be16 */
+       ROCKER_TLV_OF_DPA_VLAN_PCP_ACTION,      /* u8 */
+       ROCKER_TLV_OF_DPA_NEW_VLAN_ID,          /* __be16 */
+       ROCKER_TLV_OF_DPA_NEW_VLAN_PCP,         /* u8 */
+       ROCKER_TLV_OF_DPA_TUNNEL_ID,            /* u32 */
+       ROCKER_TLV_OF_DPA_TUNNEL_LPORT,         /* u32 */
+       ROCKER_TLV_OF_DPA_ETHERTYPE,            /* __be16 */
+       ROCKER_TLV_OF_DPA_DST_MAC,              /* binary */
+       ROCKER_TLV_OF_DPA_DST_MAC_MASK,         /* binary */
+       ROCKER_TLV_OF_DPA_SRC_MAC,              /* binary */
+       ROCKER_TLV_OF_DPA_SRC_MAC_MASK,         /* binary */
+       ROCKER_TLV_OF_DPA_IP_PROTO,             /* u8 */
+       ROCKER_TLV_OF_DPA_IP_PROTO_MASK,        /* u8 */
+       ROCKER_TLV_OF_DPA_IP_DSCP,              /* u8 */
+       ROCKER_TLV_OF_DPA_IP_DSCP_MASK,         /* u8 */
+       ROCKER_TLV_OF_DPA_IP_DSCP_ACTION,       /* u8 */
+       ROCKER_TLV_OF_DPA_NEW_IP_DSCP,          /* u8 */
+       ROCKER_TLV_OF_DPA_IP_ECN,               /* u8 */
+       ROCKER_TLV_OF_DPA_IP_ECN_MASK,          /* u8 */
+       ROCKER_TLV_OF_DPA_DST_IP,               /* __be32 */
+       ROCKER_TLV_OF_DPA_DST_IP_MASK,          /* __be32 */
+       ROCKER_TLV_OF_DPA_SRC_IP,               /* __be32 */
+       ROCKER_TLV_OF_DPA_SRC_IP_MASK,          /* __be32 */
+       ROCKER_TLV_OF_DPA_DST_IPV6,             /* binary */
+       ROCKER_TLV_OF_DPA_DST_IPV6_MASK,        /* binary */
+       ROCKER_TLV_OF_DPA_SRC_IPV6,             /* binary */
+       ROCKER_TLV_OF_DPA_SRC_IPV6_MASK,        /* binary */
+       ROCKER_TLV_OF_DPA_SRC_ARP_IP,           /* __be32 */
+       ROCKER_TLV_OF_DPA_SRC_ARP_IP_MASK,      /* __be32 */
+       ROCKER_TLV_OF_DPA_L4_DST_PORT,          /* __be16 */
+       ROCKER_TLV_OF_DPA_L4_DST_PORT_MASK,     /* __be16 */
+       ROCKER_TLV_OF_DPA_L4_SRC_PORT,          /* __be16 */
+       ROCKER_TLV_OF_DPA_L4_SRC_PORT_MASK,     /* __be16 */
+       ROCKER_TLV_OF_DPA_ICMP_TYPE,            /* u8 */
+       ROCKER_TLV_OF_DPA_ICMP_TYPE_MASK,       /* u8 */
+       ROCKER_TLV_OF_DPA_ICMP_CODE,            /* u8 */
+       ROCKER_TLV_OF_DPA_ICMP_CODE_MASK,       /* u8 */
+       ROCKER_TLV_OF_DPA_IPV6_LABEL,           /* __be32 */
+       ROCKER_TLV_OF_DPA_IPV6_LABEL_MASK,      /* __be32 */
+       ROCKER_TLV_OF_DPA_QUEUE_ID_ACTION,      /* u8 */
+       ROCKER_TLV_OF_DPA_NEW_QUEUE_ID,         /* u8 */
+       ROCKER_TLV_OF_DPA_CLEAR_ACTIONS,        /* u32 */
+       ROCKER_TLV_OF_DPA_POP_VLAN,             /* u8 */
+       ROCKER_TLV_OF_DPA_TTL_CHECK,            /* u8 */
+       ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,      /* u8 */
+
+       __ROCKER_TLV_OF_DPA_MAX,
+       ROCKER_TLV_OF_DPA_MAX = __ROCKER_TLV_OF_DPA_MAX - 1,
+};
+
+/* OF-DPA table IDs */
+
+enum rocker_of_dpa_table_id {
+       ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT = 0,
+       ROCKER_OF_DPA_TABLE_ID_VLAN = 10,
+       ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC = 20,
+       ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING = 30,
+       ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING = 40,
+       ROCKER_OF_DPA_TABLE_ID_BRIDGING = 50,
+       ROCKER_OF_DPA_TABLE_ID_ACL_POLICY = 60,
+};
+
+/* OF-DPA flow stats */
+enum {
+       ROCKER_TLV_OF_DPA_FLOW_STAT_UNSPEC,
+       ROCKER_TLV_OF_DPA_FLOW_STAT_DURATION,   /* u32 */
+       ROCKER_TLV_OF_DPA_FLOW_STAT_RX_PKTS,    /* u64 */
+       ROCKER_TLV_OF_DPA_FLOW_STAT_TX_PKTS,    /* u64 */
+
+       __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX,
+       ROCKER_TLV_OF_DPA_FLOW_STAT_MAX = __ROCKER_TLV_OF_DPA_FLOW_STAT_MAX - 1,
+};
+
+/* OF-DPA group types */
+enum rocker_of_dpa_group_type {
+       ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE = 0,
+       ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE,
+       ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST,
+       ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST,
+       ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD,
+       ROCKER_OF_DPA_GROUP_TYPE_L3_INTERFACE,
+       ROCKER_OF_DPA_GROUP_TYPE_L3_MCAST,
+       ROCKER_OF_DPA_GROUP_TYPE_L3_ECMP,
+       ROCKER_OF_DPA_GROUP_TYPE_L2_OVERLAY,
+};
+
+/* OF-DPA group L2 overlay types */
+enum rocker_of_dpa_overlay_type {
+       ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_UCAST = 0,
+       ROCKER_OF_DPA_OVERLAY_TYPE_FLOOD_MCAST,
+       ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_UCAST,
+       ROCKER_OF_DPA_OVERLAY_TYPE_MCAST_MCAST,
+};
+
+/* OF-DPA group ID encoding */
+#define ROCKER_GROUP_TYPE_SHIFT 28
+#define ROCKER_GROUP_TYPE_MASK 0xf0000000
+#define ROCKER_GROUP_VLAN_SHIFT 16
+#define ROCKER_GROUP_VLAN_MASK 0x0fff0000
+#define ROCKER_GROUP_PORT_SHIFT 0
+#define ROCKER_GROUP_PORT_MASK 0x0000ffff
+#define ROCKER_GROUP_TUNNEL_ID_SHIFT 12
+#define ROCKER_GROUP_TUNNEL_ID_MASK 0x0ffff000
+#define ROCKER_GROUP_SUBTYPE_SHIFT 10
+#define ROCKER_GROUP_SUBTYPE_MASK 0x00000c00
+#define ROCKER_GROUP_INDEX_SHIFT 0
+#define ROCKER_GROUP_INDEX_MASK 0x0000ffff
+#define ROCKER_GROUP_INDEX_LONG_SHIFT 0
+#define ROCKER_GROUP_INDEX_LONG_MASK 0x0fffffff
+
+#define ROCKER_GROUP_TYPE_GET(group_id) \
+       (((group_id) & ROCKER_GROUP_TYPE_MASK) >> ROCKER_GROUP_TYPE_SHIFT)
+#define ROCKER_GROUP_TYPE_SET(type) \
+       (((type) << ROCKER_GROUP_TYPE_SHIFT) & ROCKER_GROUP_TYPE_MASK)
+#define ROCKER_GROUP_VLAN_GET(group_id) \
+       (((group_id) & ROCKER_GROUP_VLAN_ID_MASK) >> ROCKER_GROUP_VLAN_ID_SHIFT)
+#define ROCKER_GROUP_VLAN_SET(vlan_id) \
+       (((vlan_id) << ROCKER_GROUP_VLAN_SHIFT) & ROCKER_GROUP_VLAN_MASK)
+#define ROCKER_GROUP_PORT_GET(group_id) \
+       (((group_id) & ROCKER_GROUP_PORT_MASK) >> ROCKER_GROUP_PORT_SHIFT)
+#define ROCKER_GROUP_PORT_SET(port) \
+       (((port) << ROCKER_GROUP_PORT_SHIFT) & ROCKER_GROUP_PORT_MASK)
+#define ROCKER_GROUP_INDEX_GET(group_id) \
+       (((group_id) & ROCKER_GROUP_INDEX_MASK) >> ROCKER_GROUP_INDEX_SHIFT)
+#define ROCKER_GROUP_INDEX_SET(index) \
+       (((index) << ROCKER_GROUP_INDEX_SHIFT) & ROCKER_GROUP_INDEX_MASK)
+#define ROCKER_GROUP_INDEX_LONG_GET(group_id) \
+       (((group_id) & ROCKER_GROUP_INDEX_LONG_MASK) >> \
+        ROCKER_GROUP_INDEX_LONG_SHIFT)
+#define ROCKER_GROUP_INDEX_LONG_SET(index) \
+       (((index) << ROCKER_GROUP_INDEX_LONG_SHIFT) & \
+        ROCKER_GROUP_INDEX_LONG_MASK)
+
+#define ROCKER_GROUP_NONE 0
+#define ROCKER_GROUP_L2_INTERFACE(vlan_id, port) \
+       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE) |\
+        ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_PORT_SET(port))
+#define ROCKER_GROUP_L2_REWRITE(index) \
+       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE) |\
+        ROCKER_GROUP_INDEX_LONG_SET(index))
+#define ROCKER_GROUP_L2_MCAST(vlan_id, index) \
+       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST) |\
+        ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
+#define ROCKER_GROUP_L2_FLOOD(vlan_id, index) \
+       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD) |\
+       ROCKER_GROUP_VLAN_SET(ntohs(vlan_id)) | ROCKER_GROUP_INDEX_SET(index))
+#define ROCKER_GROUP_L3_UNICAST(index) \
+       (ROCKER_GROUP_TYPE_SET(ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST) |\
+        ROCKER_GROUP_INDEX_LONG_SET(index))
+
+/* Rocker general purpose registers */
+#define ROCKER_CONTROL                 0x0300
+#define ROCKER_PORT_PHYS_COUNT         0x0304
+#define ROCKER_PORT_PHYS_LINK_STATUS   0x0310 /* 8-byte */
+#define ROCKER_PORT_PHYS_ENABLE                0x0318 /* 8-byte */
+#define ROCKER_SWITCH_ID               0x0320 /* 8-byte */
+
+/* Rocker control bits */
+#define ROCKER_CONTROL_RESET           BIT(0)
+
+#endif
diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c
new file mode 100644 (file)
index 0000000..28b775e
--- /dev/null
@@ -0,0 +1,2909 @@
+/*
+ * drivers/net/ethernet/rocker/rocker.c - Rocker switch device driver
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
+ * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/sort.h>
+#include <linux/random.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#include <linux/bitops.h>
+#include <linux/ctype.h>
+#include <net/switchdev.h>
+#include <net/rtnetlink.h>
+#include <net/netevent.h>
+#include <net/arp.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <generated/utsrelease.h>
+
+#include "rocker_hw.h"
+#include "rocker.h"
+#include "rocker_tlv.h"
+
+static const char rocker_driver_name[] = "rocker";
+
+static const struct pci_device_id rocker_pci_id_table[] = {
+       {PCI_VDEVICE(REDHAT, PCI_DEVICE_ID_REDHAT_ROCKER), 0},
+       {0, }
+};
+
+struct rocker_wait {
+       wait_queue_head_t wait;
+       bool done;
+       bool nowait;
+};
+
+static void rocker_wait_reset(struct rocker_wait *wait)
+{
+       wait->done = false;
+       wait->nowait = false;
+}
+
+static void rocker_wait_init(struct rocker_wait *wait)
+{
+       init_waitqueue_head(&wait->wait);
+       rocker_wait_reset(wait);
+}
+
+static struct rocker_wait *rocker_wait_create(void)
+{
+       struct rocker_wait *wait;
+
+       wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+       if (!wait)
+               return NULL;
+       return wait;
+}
+
+static void rocker_wait_destroy(struct rocker_wait *wait)
+{
+       kfree(wait);
+}
+
+static bool rocker_wait_event_timeout(struct rocker_wait *wait,
+                                     unsigned long timeout)
+{
+       wait_event_timeout(wait->wait, wait->done, HZ / 10);
+       if (!wait->done)
+               return false;
+       return true;
+}
+
+static void rocker_wait_wake_up(struct rocker_wait *wait)
+{
+       wait->done = true;
+       wake_up(&wait->wait);
+}
+
+static u32 rocker_msix_vector(const struct rocker *rocker, unsigned int vector)
+{
+       return rocker->msix_entries[vector].vector;
+}
+
+static u32 rocker_msix_tx_vector(const struct rocker_port *rocker_port)
+{
+       return rocker_msix_vector(rocker_port->rocker,
+                                 ROCKER_MSIX_VEC_TX(rocker_port->port_number));
+}
+
+static u32 rocker_msix_rx_vector(const struct rocker_port *rocker_port)
+{
+       return rocker_msix_vector(rocker_port->rocker,
+                                 ROCKER_MSIX_VEC_RX(rocker_port->port_number));
+}
+
+#define rocker_write32(rocker, reg, val)       \
+       writel((val), (rocker)->hw_addr + (ROCKER_ ## reg))
+#define rocker_read32(rocker, reg)     \
+       readl((rocker)->hw_addr + (ROCKER_ ## reg))
+#define rocker_write64(rocker, reg, val)       \
+       writeq((val), (rocker)->hw_addr + (ROCKER_ ## reg))
+#define rocker_read64(rocker, reg)     \
+       readq((rocker)->hw_addr + (ROCKER_ ## reg))
+
+/*****************************
+ * HW basic testing functions
+ *****************************/
+
+static int rocker_reg_test(const struct rocker *rocker)
+{
+       const struct pci_dev *pdev = rocker->pdev;
+       u64 test_reg;
+       u64 rnd;
+
+       rnd = prandom_u32();
+       rnd >>= 1;
+       rocker_write32(rocker, TEST_REG, rnd);
+       test_reg = rocker_read32(rocker, TEST_REG);
+       if (test_reg != rnd * 2) {
+               dev_err(&pdev->dev, "unexpected 32bit register value %08llx, expected %08llx\n",
+                       test_reg, rnd * 2);
+               return -EIO;
+       }
+
+       rnd = prandom_u32();
+       rnd <<= 31;
+       rnd |= prandom_u32();
+       rocker_write64(rocker, TEST_REG64, rnd);
+       test_reg = rocker_read64(rocker, TEST_REG64);
+       if (test_reg != rnd * 2) {
+               dev_err(&pdev->dev, "unexpected 64bit register value %16llx, expected %16llx\n",
+                       test_reg, rnd * 2);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int rocker_dma_test_one(const struct rocker *rocker,
+                              struct rocker_wait *wait, u32 test_type,
+                              dma_addr_t dma_handle, const unsigned char *buf,
+                              const unsigned char *expect, size_t size)
+{
+       const struct pci_dev *pdev = rocker->pdev;
+       int i;
+
+       rocker_wait_reset(wait);
+       rocker_write32(rocker, TEST_DMA_CTRL, test_type);
+
+       if (!rocker_wait_event_timeout(wait, HZ / 10)) {
+               dev_err(&pdev->dev, "no interrupt received within a timeout\n");
+               return -EIO;
+       }
+
+       for (i = 0; i < size; i++) {
+               if (buf[i] != expect[i]) {
+                       dev_err(&pdev->dev, "unexpected memory content %02x at byte %x\n, %02x expected",
+                               buf[i], i, expect[i]);
+                       return -EIO;
+               }
+       }
+       return 0;
+}
+
+#define ROCKER_TEST_DMA_BUF_SIZE (PAGE_SIZE * 4)
+#define ROCKER_TEST_DMA_FILL_PATTERN 0x96
+
+static int rocker_dma_test_offset(const struct rocker *rocker,
+                                 struct rocker_wait *wait, int offset)
+{
+       struct pci_dev *pdev = rocker->pdev;
+       unsigned char *alloc;
+       unsigned char *buf;
+       unsigned char *expect;
+       dma_addr_t dma_handle;
+       int i;
+       int err;
+
+       alloc = kzalloc(ROCKER_TEST_DMA_BUF_SIZE * 2 + offset,
+                       GFP_KERNEL | GFP_DMA);
+       if (!alloc)
+               return -ENOMEM;
+       buf = alloc + offset;
+       expect = buf + ROCKER_TEST_DMA_BUF_SIZE;
+
+       dma_handle = pci_map_single(pdev, buf, ROCKER_TEST_DMA_BUF_SIZE,
+                                   PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(pdev, dma_handle)) {
+               err = -EIO;
+               goto free_alloc;
+       }
+
+       rocker_write64(rocker, TEST_DMA_ADDR, dma_handle);
+       rocker_write32(rocker, TEST_DMA_SIZE, ROCKER_TEST_DMA_BUF_SIZE);
+
+       memset(expect, ROCKER_TEST_DMA_FILL_PATTERN, ROCKER_TEST_DMA_BUF_SIZE);
+       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_FILL,
+                                 dma_handle, buf, expect,
+                                 ROCKER_TEST_DMA_BUF_SIZE);
+       if (err)
+               goto unmap;
+
+       memset(expect, 0, ROCKER_TEST_DMA_BUF_SIZE);
+       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_CLEAR,
+                                 dma_handle, buf, expect,
+                                 ROCKER_TEST_DMA_BUF_SIZE);
+       if (err)
+               goto unmap;
+
+       prandom_bytes(buf, ROCKER_TEST_DMA_BUF_SIZE);
+       for (i = 0; i < ROCKER_TEST_DMA_BUF_SIZE; i++)
+               expect[i] = ~buf[i];
+       err = rocker_dma_test_one(rocker, wait, ROCKER_TEST_DMA_CTRL_INVERT,
+                                 dma_handle, buf, expect,
+                                 ROCKER_TEST_DMA_BUF_SIZE);
+       if (err)
+               goto unmap;
+
+unmap:
+       pci_unmap_single(pdev, dma_handle, ROCKER_TEST_DMA_BUF_SIZE,
+                        PCI_DMA_BIDIRECTIONAL);
+free_alloc:
+       kfree(alloc);
+
+       return err;
+}
+
+static int rocker_dma_test(const struct rocker *rocker,
+                          struct rocker_wait *wait)
+{
+       int i;
+       int err;
+
+       for (i = 0; i < 8; i++) {
+               err = rocker_dma_test_offset(rocker, wait, i);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static irqreturn_t rocker_test_irq_handler(int irq, void *dev_id)
+{
+       struct rocker_wait *wait = dev_id;
+
+       rocker_wait_wake_up(wait);
+
+       return IRQ_HANDLED;
+}
+
+static int rocker_basic_hw_test(const struct rocker *rocker)
+{
+       const struct pci_dev *pdev = rocker->pdev;
+       struct rocker_wait wait;
+       int err;
+
+       err = rocker_reg_test(rocker);
+       if (err) {
+               dev_err(&pdev->dev, "reg test failed\n");
+               return err;
+       }
+
+       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST),
+                         rocker_test_irq_handler, 0,
+                         rocker_driver_name, &wait);
+       if (err) {
+               dev_err(&pdev->dev, "cannot assign test irq\n");
+               return err;
+       }
+
+       rocker_wait_init(&wait);
+       rocker_write32(rocker, TEST_IRQ, ROCKER_MSIX_VEC_TEST);
+
+       if (!rocker_wait_event_timeout(&wait, HZ / 10)) {
+               dev_err(&pdev->dev, "no interrupt received within a timeout\n");
+               err = -EIO;
+               goto free_irq;
+       }
+
+       err = rocker_dma_test(rocker, &wait);
+       if (err)
+               dev_err(&pdev->dev, "dma test failed\n");
+
+free_irq:
+       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_TEST), &wait);
+       return err;
+}
+
+/******************************************
+ * DMA rings and descriptors manipulations
+ ******************************************/
+
+static u32 __pos_inc(u32 pos, size_t limit)
+{
+       return ++pos == limit ? 0 : pos;
+}
+
+static int rocker_desc_err(const struct rocker_desc_info *desc_info)
+{
+       int err = desc_info->desc->comp_err & ~ROCKER_DMA_DESC_COMP_ERR_GEN;
+
+       switch (err) {
+       case ROCKER_OK:
+               return 0;
+       case -ROCKER_ENOENT:
+               return -ENOENT;
+       case -ROCKER_ENXIO:
+               return -ENXIO;
+       case -ROCKER_ENOMEM:
+               return -ENOMEM;
+       case -ROCKER_EEXIST:
+               return -EEXIST;
+       case -ROCKER_EINVAL:
+               return -EINVAL;
+       case -ROCKER_EMSGSIZE:
+               return -EMSGSIZE;
+       case -ROCKER_ENOTSUP:
+               return -EOPNOTSUPP;
+       case -ROCKER_ENOBUFS:
+               return -ENOBUFS;
+       }
+
+       return -EINVAL;
+}
+
+static void rocker_desc_gen_clear(const struct rocker_desc_info *desc_info)
+{
+       desc_info->desc->comp_err &= ~ROCKER_DMA_DESC_COMP_ERR_GEN;
+}
+
+static bool rocker_desc_gen(const struct rocker_desc_info *desc_info)
+{
+       u32 comp_err = desc_info->desc->comp_err;
+
+       return comp_err & ROCKER_DMA_DESC_COMP_ERR_GEN ? true : false;
+}
+
+static void *
+rocker_desc_cookie_ptr_get(const struct rocker_desc_info *desc_info)
+{
+       return (void *)(uintptr_t)desc_info->desc->cookie;
+}
+
+static void rocker_desc_cookie_ptr_set(const struct rocker_desc_info *desc_info,
+                                      void *ptr)
+{
+       desc_info->desc->cookie = (uintptr_t) ptr;
+}
+
+static struct rocker_desc_info *
+rocker_desc_head_get(const struct rocker_dma_ring_info *info)
+{
+       static struct rocker_desc_info *desc_info;
+       u32 head = __pos_inc(info->head, info->size);
+
+       desc_info = &info->desc_info[info->head];
+       if (head == info->tail)
+               return NULL; /* ring full */
+       desc_info->tlv_size = 0;
+       return desc_info;
+}
+
+static void rocker_desc_commit(const struct rocker_desc_info *desc_info)
+{
+       desc_info->desc->buf_size = desc_info->data_size;
+       desc_info->desc->tlv_size = desc_info->tlv_size;
+}
+
+static void rocker_desc_head_set(const struct rocker *rocker,
+                                struct rocker_dma_ring_info *info,
+                                const struct rocker_desc_info *desc_info)
+{
+       u32 head = __pos_inc(info->head, info->size);
+
+       BUG_ON(head == info->tail);
+       rocker_desc_commit(desc_info);
+       info->head = head;
+       rocker_write32(rocker, DMA_DESC_HEAD(info->type), head);
+}
+
+static struct rocker_desc_info *
+rocker_desc_tail_get(struct rocker_dma_ring_info *info)
+{
+       static struct rocker_desc_info *desc_info;
+
+       if (info->tail == info->head)
+               return NULL; /* nothing to be done between head and tail */
+       desc_info = &info->desc_info[info->tail];
+       if (!rocker_desc_gen(desc_info))
+               return NULL; /* gen bit not set, desc is not ready yet */
+       info->tail = __pos_inc(info->tail, info->size);
+       desc_info->tlv_size = desc_info->desc->tlv_size;
+       return desc_info;
+}
+
+static void rocker_dma_ring_credits_set(const struct rocker *rocker,
+                                       const struct rocker_dma_ring_info *info,
+                                       u32 credits)
+{
+       if (credits)
+               rocker_write32(rocker, DMA_DESC_CREDITS(info->type), credits);
+}
+
+static unsigned long rocker_dma_ring_size_fix(size_t size)
+{
+       return max(ROCKER_DMA_SIZE_MIN,
+                  min(roundup_pow_of_two(size), ROCKER_DMA_SIZE_MAX));
+}
+
+static int rocker_dma_ring_create(const struct rocker *rocker,
+                                 unsigned int type,
+                                 size_t size,
+                                 struct rocker_dma_ring_info *info)
+{
+       int i;
+
+       BUG_ON(size != rocker_dma_ring_size_fix(size));
+       info->size = size;
+       info->type = type;
+       info->head = 0;
+       info->tail = 0;
+       info->desc_info = kcalloc(info->size, sizeof(*info->desc_info),
+                                 GFP_KERNEL);
+       if (!info->desc_info)
+               return -ENOMEM;
+
+       info->desc = pci_alloc_consistent(rocker->pdev,
+                                         info->size * sizeof(*info->desc),
+                                         &info->mapaddr);
+       if (!info->desc) {
+               kfree(info->desc_info);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < info->size; i++)
+               info->desc_info[i].desc = &info->desc[i];
+
+       rocker_write32(rocker, DMA_DESC_CTRL(info->type),
+                      ROCKER_DMA_DESC_CTRL_RESET);
+       rocker_write64(rocker, DMA_DESC_ADDR(info->type), info->mapaddr);
+       rocker_write32(rocker, DMA_DESC_SIZE(info->type), info->size);
+
+       return 0;
+}
+
+static void rocker_dma_ring_destroy(const struct rocker *rocker,
+                                   const struct rocker_dma_ring_info *info)
+{
+       rocker_write64(rocker, DMA_DESC_ADDR(info->type), 0);
+
+       pci_free_consistent(rocker->pdev,
+                           info->size * sizeof(struct rocker_desc),
+                           info->desc, info->mapaddr);
+       kfree(info->desc_info);
+}
+
+static void rocker_dma_ring_pass_to_producer(const struct rocker *rocker,
+                                            struct rocker_dma_ring_info *info)
+{
+       int i;
+
+       BUG_ON(info->head || info->tail);
+
+       /* When ring is consumer, we need to advance head for each desc.
+        * That tells hw that the desc is ready to be used by it.
+        */
+       for (i = 0; i < info->size - 1; i++)
+               rocker_desc_head_set(rocker, info, &info->desc_info[i]);
+       rocker_desc_commit(&info->desc_info[i]);
+}
+
+static int rocker_dma_ring_bufs_alloc(const struct rocker *rocker,
+                                     const struct rocker_dma_ring_info *info,
+                                     int direction, size_t buf_size)
+{
+       struct pci_dev *pdev = rocker->pdev;
+       int i;
+       int err;
+
+       for (i = 0; i < info->size; i++) {
+               struct rocker_desc_info *desc_info = &info->desc_info[i];
+               struct rocker_desc *desc = &info->desc[i];
+               dma_addr_t dma_handle;
+               char *buf;
+
+               buf = kzalloc(buf_size, GFP_KERNEL | GFP_DMA);
+               if (!buf) {
+                       err = -ENOMEM;
+                       goto rollback;
+               }
+
+               dma_handle = pci_map_single(pdev, buf, buf_size, direction);
+               if (pci_dma_mapping_error(pdev, dma_handle)) {
+                       kfree(buf);
+                       err = -EIO;
+                       goto rollback;
+               }
+
+               desc_info->data = buf;
+               desc_info->data_size = buf_size;
+               dma_unmap_addr_set(desc_info, mapaddr, dma_handle);
+
+               desc->buf_addr = dma_handle;
+               desc->buf_size = buf_size;
+       }
+       return 0;
+
+rollback:
+       for (i--; i >= 0; i--) {
+               const struct rocker_desc_info *desc_info = &info->desc_info[i];
+
+               pci_unmap_single(pdev, dma_unmap_addr(desc_info, mapaddr),
+                                desc_info->data_size, direction);
+               kfree(desc_info->data);
+       }
+       return err;
+}
+
+static void rocker_dma_ring_bufs_free(const struct rocker *rocker,
+                                     const struct rocker_dma_ring_info *info,
+                                     int direction)
+{
+       struct pci_dev *pdev = rocker->pdev;
+       int i;
+
+       for (i = 0; i < info->size; i++) {
+               const struct rocker_desc_info *desc_info = &info->desc_info[i];
+               struct rocker_desc *desc = &info->desc[i];
+
+               desc->buf_addr = 0;
+               desc->buf_size = 0;
+               pci_unmap_single(pdev, dma_unmap_addr(desc_info, mapaddr),
+                                desc_info->data_size, direction);
+               kfree(desc_info->data);
+       }
+}
+
+static int rocker_dma_cmd_ring_wait_alloc(struct rocker_desc_info *desc_info)
+{
+       struct rocker_wait *wait;
+
+       wait = rocker_wait_create();
+       if (!wait)
+               return -ENOMEM;
+       rocker_desc_cookie_ptr_set(desc_info, wait);
+       return 0;
+}
+
+static void
+rocker_dma_cmd_ring_wait_free(const struct rocker_desc_info *desc_info)
+{
+       struct rocker_wait *wait = rocker_desc_cookie_ptr_get(desc_info);
+
+       rocker_wait_destroy(wait);
+}
+
+static int rocker_dma_cmd_ring_waits_alloc(const struct rocker *rocker)
+{
+       const struct rocker_dma_ring_info *cmd_ring = &rocker->cmd_ring;
+       int i;
+       int err;
+
+       for (i = 0; i < cmd_ring->size; i++) {
+               err = rocker_dma_cmd_ring_wait_alloc(&cmd_ring->desc_info[i]);
+               if (err)
+                       goto rollback;
+       }
+       return 0;
+
+rollback:
+       for (i--; i >= 0; i--)
+               rocker_dma_cmd_ring_wait_free(&cmd_ring->desc_info[i]);
+       return err;
+}
+
+static void rocker_dma_cmd_ring_waits_free(const struct rocker *rocker)
+{
+       const struct rocker_dma_ring_info *cmd_ring = &rocker->cmd_ring;
+       int i;
+
+       for (i = 0; i < cmd_ring->size; i++)
+               rocker_dma_cmd_ring_wait_free(&cmd_ring->desc_info[i]);
+}
+
+static int rocker_dma_rings_init(struct rocker *rocker)
+{
+       const struct pci_dev *pdev = rocker->pdev;
+       int err;
+
+       err = rocker_dma_ring_create(rocker, ROCKER_DMA_CMD,
+                                    ROCKER_DMA_CMD_DEFAULT_SIZE,
+                                    &rocker->cmd_ring);
+       if (err) {
+               dev_err(&pdev->dev, "failed to create command dma ring\n");
+               return err;
+       }
+
+       spin_lock_init(&rocker->cmd_ring_lock);
+
+       err = rocker_dma_ring_bufs_alloc(rocker, &rocker->cmd_ring,
+                                        PCI_DMA_BIDIRECTIONAL, PAGE_SIZE);
+       if (err) {
+               dev_err(&pdev->dev, "failed to alloc command dma ring buffers\n");
+               goto err_dma_cmd_ring_bufs_alloc;
+       }
+
+       err = rocker_dma_cmd_ring_waits_alloc(rocker);
+       if (err) {
+               dev_err(&pdev->dev, "failed to alloc command dma ring waits\n");
+               goto err_dma_cmd_ring_waits_alloc;
+       }
+
+       err = rocker_dma_ring_create(rocker, ROCKER_DMA_EVENT,
+                                    ROCKER_DMA_EVENT_DEFAULT_SIZE,
+                                    &rocker->event_ring);
+       if (err) {
+               dev_err(&pdev->dev, "failed to create event dma ring\n");
+               goto err_dma_event_ring_create;
+       }
+
+       err = rocker_dma_ring_bufs_alloc(rocker, &rocker->event_ring,
+                                        PCI_DMA_FROMDEVICE, PAGE_SIZE);
+       if (err) {
+               dev_err(&pdev->dev, "failed to alloc event dma ring buffers\n");
+               goto err_dma_event_ring_bufs_alloc;
+       }
+       rocker_dma_ring_pass_to_producer(rocker, &rocker->event_ring);
+       return 0;
+
+err_dma_event_ring_bufs_alloc:
+       rocker_dma_ring_destroy(rocker, &rocker->event_ring);
+err_dma_event_ring_create:
+       rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,
+                                 PCI_DMA_BIDIRECTIONAL);
+err_dma_cmd_ring_waits_alloc:
+       rocker_dma_cmd_ring_waits_free(rocker);
+err_dma_cmd_ring_bufs_alloc:
+       rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
+       return err;
+}
+
+static void rocker_dma_rings_fini(struct rocker *rocker)
+{
+       rocker_dma_ring_bufs_free(rocker, &rocker->event_ring,
+                                 PCI_DMA_BIDIRECTIONAL);
+       rocker_dma_ring_destroy(rocker, &rocker->event_ring);
+       rocker_dma_cmd_ring_waits_free(rocker);
+       rocker_dma_ring_bufs_free(rocker, &rocker->cmd_ring,
+                                 PCI_DMA_BIDIRECTIONAL);
+       rocker_dma_ring_destroy(rocker, &rocker->cmd_ring);
+}
+
+static int rocker_dma_rx_ring_skb_map(const struct rocker_port *rocker_port,
+                                     struct rocker_desc_info *desc_info,
+                                     struct sk_buff *skb, size_t buf_len)
+{
+       const struct rocker *rocker = rocker_port->rocker;
+       struct pci_dev *pdev = rocker->pdev;
+       dma_addr_t dma_handle;
+
+       dma_handle = pci_map_single(pdev, skb->data, buf_len,
+                                   PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(pdev, dma_handle))
+               return -EIO;
+       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_RX_FRAG_ADDR, dma_handle))
+               goto tlv_put_failure;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_RX_FRAG_MAX_LEN, buf_len))
+               goto tlv_put_failure;
+       return 0;
+
+tlv_put_failure:
+       pci_unmap_single(pdev, dma_handle, buf_len, PCI_DMA_FROMDEVICE);
+       desc_info->tlv_size = 0;
+       return -EMSGSIZE;
+}
+
+static size_t rocker_port_rx_buf_len(const struct rocker_port *rocker_port)
+{
+       return rocker_port->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+}
+
+static int rocker_dma_rx_ring_skb_alloc(const struct rocker_port *rocker_port,
+                                       struct rocker_desc_info *desc_info)
+{
+       struct net_device *dev = rocker_port->dev;
+       struct sk_buff *skb;
+       size_t buf_len = rocker_port_rx_buf_len(rocker_port);
+       int err;
+
+       /* Ensure that hw will see tlv_size zero in case of an error.
+        * That tells hw to use another descriptor.
+        */
+       rocker_desc_cookie_ptr_set(desc_info, NULL);
+       desc_info->tlv_size = 0;
+
+       skb = netdev_alloc_skb_ip_align(dev, buf_len);
+       if (!skb)
+               return -ENOMEM;
+       err = rocker_dma_rx_ring_skb_map(rocker_port, desc_info, skb, buf_len);
+       if (err) {
+               dev_kfree_skb_any(skb);
+               return err;
+       }
+       rocker_desc_cookie_ptr_set(desc_info, skb);
+       return 0;
+}
+
+static void rocker_dma_rx_ring_skb_unmap(const struct rocker *rocker,
+                                        const struct rocker_tlv **attrs)
+{
+       struct pci_dev *pdev = rocker->pdev;
+       dma_addr_t dma_handle;
+       size_t len;
+
+       if (!attrs[ROCKER_TLV_RX_FRAG_ADDR] ||
+           !attrs[ROCKER_TLV_RX_FRAG_MAX_LEN])
+               return;
+       dma_handle = rocker_tlv_get_u64(attrs[ROCKER_TLV_RX_FRAG_ADDR]);
+       len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
+       pci_unmap_single(pdev, dma_handle, len, PCI_DMA_FROMDEVICE);
+}
+
+static void rocker_dma_rx_ring_skb_free(const struct rocker *rocker,
+                                       const struct rocker_desc_info *desc_info)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
+       struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
+
+       if (!skb)
+               return;
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);
+       rocker_dma_rx_ring_skb_unmap(rocker, attrs);
+       dev_kfree_skb_any(skb);
+}
+
+static int rocker_dma_rx_ring_skbs_alloc(const struct rocker_port *rocker_port)
+{
+       const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+       const struct rocker *rocker = rocker_port->rocker;
+       int i;
+       int err;
+
+       for (i = 0; i < rx_ring->size; i++) {
+               err = rocker_dma_rx_ring_skb_alloc(rocker_port,
+                                                  &rx_ring->desc_info[i]);
+               if (err)
+                       goto rollback;
+       }
+       return 0;
+
+rollback:
+       for (i--; i >= 0; i--)
+               rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);
+       return err;
+}
+
+static void rocker_dma_rx_ring_skbs_free(const struct rocker_port *rocker_port)
+{
+       const struct rocker_dma_ring_info *rx_ring = &rocker_port->rx_ring;
+       const struct rocker *rocker = rocker_port->rocker;
+       int i;
+
+       for (i = 0; i < rx_ring->size; i++)
+               rocker_dma_rx_ring_skb_free(rocker, &rx_ring->desc_info[i]);
+}
+
+static int rocker_port_dma_rings_init(struct rocker_port *rocker_port)
+{
+       struct rocker *rocker = rocker_port->rocker;
+       int err;
+
+       err = rocker_dma_ring_create(rocker,
+                                    ROCKER_DMA_TX(rocker_port->port_number),
+                                    ROCKER_DMA_TX_DEFAULT_SIZE,
+                                    &rocker_port->tx_ring);
+       if (err) {
+               netdev_err(rocker_port->dev, "failed to create tx dma ring\n");
+               return err;
+       }
+
+       err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->tx_ring,
+                                        PCI_DMA_TODEVICE,
+                                        ROCKER_DMA_TX_DESC_SIZE);
+       if (err) {
+               netdev_err(rocker_port->dev, "failed to alloc tx dma ring buffers\n");
+               goto err_dma_tx_ring_bufs_alloc;
+       }
+
+       err = rocker_dma_ring_create(rocker,
+                                    ROCKER_DMA_RX(rocker_port->port_number),
+                                    ROCKER_DMA_RX_DEFAULT_SIZE,
+                                    &rocker_port->rx_ring);
+       if (err) {
+               netdev_err(rocker_port->dev, "failed to create rx dma ring\n");
+               goto err_dma_rx_ring_create;
+       }
+
+       err = rocker_dma_ring_bufs_alloc(rocker, &rocker_port->rx_ring,
+                                        PCI_DMA_BIDIRECTIONAL,
+                                        ROCKER_DMA_RX_DESC_SIZE);
+       if (err) {
+               netdev_err(rocker_port->dev, "failed to alloc rx dma ring buffers\n");
+               goto err_dma_rx_ring_bufs_alloc;
+       }
+
+       err = rocker_dma_rx_ring_skbs_alloc(rocker_port);
+       if (err) {
+               netdev_err(rocker_port->dev, "failed to alloc rx dma ring skbs\n");
+               goto err_dma_rx_ring_skbs_alloc;
+       }
+       rocker_dma_ring_pass_to_producer(rocker, &rocker_port->rx_ring);
+
+       return 0;
+
+err_dma_rx_ring_skbs_alloc:
+       rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,
+                                 PCI_DMA_BIDIRECTIONAL);
+err_dma_rx_ring_bufs_alloc:
+       rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);
+err_dma_rx_ring_create:
+       rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,
+                                 PCI_DMA_TODEVICE);
+err_dma_tx_ring_bufs_alloc:
+       rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);
+       return err;
+}
+
+static void rocker_port_dma_rings_fini(struct rocker_port *rocker_port)
+{
+       struct rocker *rocker = rocker_port->rocker;
+
+       rocker_dma_rx_ring_skbs_free(rocker_port);
+       rocker_dma_ring_bufs_free(rocker, &rocker_port->rx_ring,
+                                 PCI_DMA_BIDIRECTIONAL);
+       rocker_dma_ring_destroy(rocker, &rocker_port->rx_ring);
+       rocker_dma_ring_bufs_free(rocker, &rocker_port->tx_ring,
+                                 PCI_DMA_TODEVICE);
+       rocker_dma_ring_destroy(rocker, &rocker_port->tx_ring);
+}
+
+static void rocker_port_set_enable(const struct rocker_port *rocker_port,
+                                  bool enable)
+{
+       u64 val = rocker_read64(rocker_port->rocker, PORT_PHYS_ENABLE);
+
+       if (enable)
+               val |= 1ULL << rocker_port->pport;
+       else
+               val &= ~(1ULL << rocker_port->pport);
+       rocker_write64(rocker_port->rocker, PORT_PHYS_ENABLE, val);
+}
+
+/********************************
+ * Interrupt handler and helpers
+ ********************************/
+
+static irqreturn_t rocker_cmd_irq_handler(int irq, void *dev_id)
+{
+       struct rocker *rocker = dev_id;
+       const struct rocker_desc_info *desc_info;
+       struct rocker_wait *wait;
+       u32 credits = 0;
+
+       spin_lock(&rocker->cmd_ring_lock);
+       while ((desc_info = rocker_desc_tail_get(&rocker->cmd_ring))) {
+               wait = rocker_desc_cookie_ptr_get(desc_info);
+               if (wait->nowait) {
+                       rocker_desc_gen_clear(desc_info);
+               } else {
+                       rocker_wait_wake_up(wait);
+               }
+               credits++;
+       }
+       spin_unlock(&rocker->cmd_ring_lock);
+       rocker_dma_ring_credits_set(rocker, &rocker->cmd_ring, credits);
+
+       return IRQ_HANDLED;
+}
+
+static void rocker_port_link_up(const struct rocker_port *rocker_port)
+{
+       netif_carrier_on(rocker_port->dev);
+       netdev_info(rocker_port->dev, "Link is up\n");
+}
+
+static void rocker_port_link_down(const struct rocker_port *rocker_port)
+{
+       netif_carrier_off(rocker_port->dev);
+       netdev_info(rocker_port->dev, "Link is down\n");
+}
+
+static int rocker_event_link_change(const struct rocker *rocker,
+                                   const struct rocker_tlv *info)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_LINK_CHANGED_MAX + 1];
+       unsigned int port_number;
+       bool link_up;
+       struct rocker_port *rocker_port;
+
+       rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_LINK_CHANGED_MAX, info);
+       if (!attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT] ||
+           !attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP])
+               return -EIO;
+       port_number =
+               rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_PPORT]) - 1;
+       link_up = rocker_tlv_get_u8(attrs[ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP]);
+
+       if (port_number >= rocker->port_count)
+               return -EINVAL;
+
+       rocker_port = rocker->ports[port_number];
+       if (netif_carrier_ok(rocker_port->dev) != link_up) {
+               if (link_up)
+                       rocker_port_link_up(rocker_port);
+               else
+                       rocker_port_link_down(rocker_port);
+       }
+
+       return 0;
+}
+
+static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
+                                             const unsigned char *addr,
+                                             __be16 vlan_id);
+
+static int rocker_event_mac_vlan_seen(const struct rocker *rocker,
+                                     const struct rocker_tlv *info)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAX + 1];
+       unsigned int port_number;
+       struct rocker_port *rocker_port;
+       const unsigned char *addr;
+       __be16 vlan_id;
+
+       rocker_tlv_parse_nested(attrs, ROCKER_TLV_EVENT_MAC_VLAN_MAX, info);
+       if (!attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT] ||
+           !attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC] ||
+           !attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID])
+               return -EIO;
+       port_number =
+               rocker_tlv_get_u32(attrs[ROCKER_TLV_EVENT_MAC_VLAN_PPORT]) - 1;
+       addr = rocker_tlv_data(attrs[ROCKER_TLV_EVENT_MAC_VLAN_MAC]);
+       vlan_id = rocker_tlv_get_be16(attrs[ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID]);
+
+       if (port_number >= rocker->port_count)
+               return -EINVAL;
+
+       rocker_port = rocker->ports[port_number];
+       return rocker_world_port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
+}
+
+static int rocker_event_process(const struct rocker *rocker,
+                               const struct rocker_desc_info *desc_info)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_EVENT_MAX + 1];
+       const struct rocker_tlv *info;
+       u16 type;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_EVENT_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_EVENT_TYPE] ||
+           !attrs[ROCKER_TLV_EVENT_INFO])
+               return -EIO;
+
+       type = rocker_tlv_get_u16(attrs[ROCKER_TLV_EVENT_TYPE]);
+       info = attrs[ROCKER_TLV_EVENT_INFO];
+
+       switch (type) {
+       case ROCKER_TLV_EVENT_TYPE_LINK_CHANGED:
+               return rocker_event_link_change(rocker, info);
+       case ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN:
+               return rocker_event_mac_vlan_seen(rocker, info);
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static irqreturn_t rocker_event_irq_handler(int irq, void *dev_id)
+{
+       struct rocker *rocker = dev_id;
+       const struct pci_dev *pdev = rocker->pdev;
+       const struct rocker_desc_info *desc_info;
+       u32 credits = 0;
+       int err;
+
+       while ((desc_info = rocker_desc_tail_get(&rocker->event_ring))) {
+               err = rocker_desc_err(desc_info);
+               if (err) {
+                       dev_err(&pdev->dev, "event desc received with err %d\n",
+                               err);
+               } else {
+                       err = rocker_event_process(rocker, desc_info);
+                       if (err)
+                               dev_err(&pdev->dev, "event processing failed with err %d\n",
+                                       err);
+               }
+               rocker_desc_gen_clear(desc_info);
+               rocker_desc_head_set(rocker, &rocker->event_ring, desc_info);
+               credits++;
+       }
+       rocker_dma_ring_credits_set(rocker, &rocker->event_ring, credits);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rocker_tx_irq_handler(int irq, void *dev_id)
+{
+       struct rocker_port *rocker_port = dev_id;
+
+       napi_schedule(&rocker_port->napi_tx);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rocker_rx_irq_handler(int irq, void *dev_id)
+{
+       struct rocker_port *rocker_port = dev_id;
+
+       napi_schedule(&rocker_port->napi_rx);
+       return IRQ_HANDLED;
+}
+
+/********************
+ * Command interface
+ ********************/
+
+int rocker_cmd_exec(struct rocker_port *rocker_port, bool nowait,
+                   rocker_cmd_prep_cb_t prepare, void *prepare_priv,
+                   rocker_cmd_proc_cb_t process, void *process_priv)
+{
+       struct rocker *rocker = rocker_port->rocker;
+       struct rocker_desc_info *desc_info;
+       struct rocker_wait *wait;
+       unsigned long lock_flags;
+       int err;
+
+       spin_lock_irqsave(&rocker->cmd_ring_lock, lock_flags);
+
+       desc_info = rocker_desc_head_get(&rocker->cmd_ring);
+       if (!desc_info) {
+               spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
+               return -EAGAIN;
+       }
+
+       wait = rocker_desc_cookie_ptr_get(desc_info);
+       rocker_wait_init(wait);
+       wait->nowait = nowait;
+
+       err = prepare(rocker_port, desc_info, prepare_priv);
+       if (err) {
+               spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
+               return err;
+       }
+
+       rocker_desc_head_set(rocker, &rocker->cmd_ring, desc_info);
+
+       spin_unlock_irqrestore(&rocker->cmd_ring_lock, lock_flags);
+
+       if (nowait)
+               return 0;
+
+       if (!rocker_wait_event_timeout(wait, HZ / 10))
+               return -EIO;
+
+       err = rocker_desc_err(desc_info);
+       if (err)
+               return err;
+
+       if (process)
+               err = process(rocker_port, desc_info, process_priv);
+
+       rocker_desc_gen_clear(desc_info);
+       return err;
+}
+
+static int
+rocker_cmd_get_port_settings_prep(const struct rocker_port *rocker_port,
+                                 struct rocker_desc_info *desc_info,
+                                 void *priv)
+{
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+       return 0;
+}
+
+static int
+rocker_cmd_get_port_settings_ethtool_proc(const struct rocker_port *rocker_port,
+                                         const struct rocker_desc_info *desc_info,
+                                         void *priv)
+{
+       struct ethtool_cmd *ecmd = priv;
+       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+       u32 speed;
+       u8 duplex;
+       u8 autoneg;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_CMD_INFO])
+               return -EIO;
+
+       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
+                               attrs[ROCKER_TLV_CMD_INFO]);
+       if (!info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] ||
+           !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] ||
+           !info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG])
+               return -EIO;
+
+       speed = rocker_tlv_get_u32(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
+       duplex = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
+       autoneg = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
+
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->supported = SUPPORTED_TP;
+       ecmd->phy_address = 0xff;
+       ecmd->port = PORT_TP;
+       ethtool_cmd_speed_set(ecmd, speed);
+       ecmd->duplex = duplex ? DUPLEX_FULL : DUPLEX_HALF;
+       ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+       return 0;
+}
+
+static int
+rocker_cmd_get_port_settings_macaddr_proc(const struct rocker_port *rocker_port,
+                                         const struct rocker_desc_info *desc_info,
+                                         void *priv)
+{
+       unsigned char *macaddr = priv;
+       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+       const struct rocker_tlv *attr;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_CMD_INFO])
+               return -EIO;
+
+       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
+                               attrs[ROCKER_TLV_CMD_INFO]);
+       attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR];
+       if (!attr)
+               return -EIO;
+
+       if (rocker_tlv_len(attr) != ETH_ALEN)
+               return -EINVAL;
+
+       ether_addr_copy(macaddr, rocker_tlv_data(attr));
+       return 0;
+}
+
+static int
+rocker_cmd_get_port_settings_mode_proc(const struct rocker_port *rocker_port,
+                                      const struct rocker_desc_info *desc_info,
+                                      void *priv)
+{
+       u8 *p_mode = priv;
+       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+       const struct rocker_tlv *attr;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_CMD_INFO])
+               return -EIO;
+
+       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
+                               attrs[ROCKER_TLV_CMD_INFO]);
+       attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE];
+       if (!attr)
+               return -EIO;
+
+       *p_mode = rocker_tlv_get_u8(info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
+       return 0;
+}
+
+struct port_name {
+       char *buf;
+       size_t len;
+};
+
+static int
+rocker_cmd_get_port_settings_phys_name_proc(const struct rocker_port *rocker_port,
+                                           const struct rocker_desc_info *desc_info,
+                                           void *priv)
+{
+       const struct rocker_tlv *info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
+       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+       struct port_name *name = priv;
+       const struct rocker_tlv *attr;
+       size_t i, j, len;
+       const char *str;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_CMD_INFO])
+               return -EIO;
+
+       rocker_tlv_parse_nested(info_attrs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
+                               attrs[ROCKER_TLV_CMD_INFO]);
+       attr = info_attrs[ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME];
+       if (!attr)
+               return -EIO;
+
+       len = min_t(size_t, rocker_tlv_len(attr), name->len);
+       str = rocker_tlv_data(attr);
+
+       /* make sure name only contains alphanumeric characters */
+       for (i = j = 0; i < len; ++i) {
+               if (isalnum(str[i])) {
+                       name->buf[j] = str[i];
+                       j++;
+               }
+       }
+
+       if (j == 0)
+               return -EIO;
+
+       name->buf[j] = '\0';
+
+       return 0;
+}
+
+static int
+rocker_cmd_set_port_settings_ethtool_prep(const struct rocker_port *rocker_port,
+                                         struct rocker_desc_info *desc_info,
+                                         void *priv)
+{
+       struct ethtool_cmd *ecmd = priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED,
+                              ethtool_cmd_speed(ecmd)))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX,
+                             ecmd->duplex))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG,
+                             ecmd->autoneg))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+       return 0;
+}
+
+static int
+rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port,
+                                         struct rocker_desc_info *desc_info,
+                                         void *priv)
+{
+       const unsigned char *macaddr = priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
+                          ETH_ALEN, macaddr))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+       return 0;
+}
+
+static int
+rocker_cmd_set_port_settings_mtu_prep(const struct rocker_port *rocker_port,
+                                     struct rocker_desc_info *desc_info,
+                                     void *priv)
+{
+       int mtu = *(int *)priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MTU,
+                              mtu))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+       return 0;
+}
+
+static int
+rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port,
+                                 struct rocker_desc_info *desc_info,
+                                 void *priv)
+{
+       bool learning = *(bool *)priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
+                             learning))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+       return 0;
+}
+
+static int rocker_cmd_get_port_settings_ethtool(struct rocker_port *rocker_port,
+                                               struct ethtool_cmd *ecmd)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_get_port_settings_prep, NULL,
+                              rocker_cmd_get_port_settings_ethtool_proc,
+                              ecmd);
+}
+
+static int rocker_cmd_get_port_settings_macaddr(struct rocker_port *rocker_port,
+                                               unsigned char *macaddr)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_get_port_settings_prep, NULL,
+                              rocker_cmd_get_port_settings_macaddr_proc,
+                              macaddr);
+}
+
+static int rocker_cmd_get_port_settings_mode(struct rocker_port *rocker_port,
+                                            u8 *p_mode)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_get_port_settings_prep, NULL,
+                              rocker_cmd_get_port_settings_mode_proc, p_mode);
+}
+
+static int rocker_cmd_set_port_settings_ethtool(struct rocker_port *rocker_port,
+                                               struct ethtool_cmd *ecmd)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_set_port_settings_ethtool_prep,
+                              ecmd, NULL, NULL);
+}
+
+static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port,
+                                               unsigned char *macaddr)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_set_port_settings_macaddr_prep,
+                              macaddr, NULL, NULL);
+}
+
+static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port,
+                                           int mtu)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_set_port_settings_mtu_prep,
+                              &mtu, NULL, NULL);
+}
+
+int rocker_port_set_learning(struct rocker_port *rocker_port,
+                            bool learning)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_set_port_learning_prep,
+                              &learning, NULL, NULL);
+}
+
+/**********************
+ * Worlds manipulation
+ **********************/
+
+static struct rocker_world_ops *rocker_world_ops[] = {
+       &rocker_ofdpa_ops,
+};
+
+#define ROCKER_WORLD_OPS_LEN ARRAY_SIZE(rocker_world_ops)
+
+static struct rocker_world_ops *rocker_world_ops_find(u8 mode)
+{
+       int i;
+
+       for (i = 0; i < ROCKER_WORLD_OPS_LEN; i++)
+               if (rocker_world_ops[i]->mode == mode)
+                       return rocker_world_ops[i];
+       return NULL;
+}
+
+static int rocker_world_init(struct rocker *rocker, u8 mode)
+{
+       struct rocker_world_ops *wops;
+       int err;
+
+       wops = rocker_world_ops_find(mode);
+       if (!wops) {
+               dev_err(&rocker->pdev->dev, "port mode \"%d\" is not supported\n",
+                       mode);
+               return -EINVAL;
+       }
+       rocker->wops = wops;
+       rocker->wpriv = kzalloc(wops->priv_size, GFP_KERNEL);
+       if (!rocker->wpriv)
+               return -ENOMEM;
+       if (!wops->init)
+               return 0;
+       err = wops->init(rocker);
+       if (err)
+               kfree(rocker->wpriv);
+       return err;
+}
+
+static void rocker_world_fini(struct rocker *rocker)
+{
+       struct rocker_world_ops *wops = rocker->wops;
+
+       if (!wops || !wops->fini)
+               return;
+       wops->fini(rocker);
+       kfree(rocker->wpriv);
+}
+
+static int rocker_world_check_init(struct rocker_port *rocker_port)
+{
+       struct rocker *rocker = rocker_port->rocker;
+       u8 mode;
+       int err;
+
+       err = rocker_cmd_get_port_settings_mode(rocker_port, &mode);
+       if (err) {
+               dev_err(&rocker->pdev->dev, "failed to get port mode\n");
+               return err;
+       }
+       if (rocker->wops) {
+               if (rocker->wops->mode != mode) {
+                       dev_err(&rocker->pdev->dev, "hardware has ports in different worlds, which is not supported\n");
+                       return err;
+               }
+               return 0;
+       }
+       return rocker_world_init(rocker, mode);
+}
+
+static int rocker_world_port_pre_init(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+       int err;
+
+       rocker_port->wpriv = kzalloc(wops->port_priv_size, GFP_KERNEL);
+       if (!rocker_port->wpriv)
+               return -ENOMEM;
+       if (!wops->port_pre_init)
+               return 0;
+       err = wops->port_pre_init(rocker_port);
+       if (err)
+               kfree(rocker_port->wpriv);
+       return 0;
+}
+
+static int rocker_world_port_init(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_init)
+               return 0;
+       return wops->port_init(rocker_port);
+}
+
+static void rocker_world_port_fini(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_fini)
+               return;
+       wops->port_fini(rocker_port);
+}
+
+static void rocker_world_port_post_fini(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_post_fini)
+               return;
+       wops->port_post_fini(rocker_port);
+       kfree(rocker_port->wpriv);
+}
+
+static int rocker_world_port_open(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_open)
+               return 0;
+       return wops->port_open(rocker_port);
+}
+
+static void rocker_world_port_stop(struct rocker_port *rocker_port)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_stop)
+               return;
+       wops->port_stop(rocker_port);
+}
+
+static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port,
+                                               u8 state,
+                                               struct switchdev_trans *trans)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_attr_stp_state_set)
+               return -EOPNOTSUPP;
+       return wops->port_attr_stp_state_set(rocker_port, state, trans);
+}
+
+static int
+rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
+                                       unsigned long brport_flags,
+                                       struct switchdev_trans *trans)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_attr_bridge_flags_set)
+               return -EOPNOTSUPP;
+       return wops->port_attr_bridge_flags_set(rocker_port, brport_flags,
+                                               trans);
+}
+
+static int
+rocker_world_port_attr_bridge_flags_get(const struct rocker_port *rocker_port,
+                                       unsigned long *p_brport_flags)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_attr_bridge_flags_get)
+               return -EOPNOTSUPP;
+       return wops->port_attr_bridge_flags_get(rocker_port, p_brport_flags);
+}
+
+static int
+rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
+                                             u32 ageing_time,
+                                             struct switchdev_trans *trans)
+
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_attr_bridge_ageing_time_set)
+               return -EOPNOTSUPP;
+       return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time,
+                                                     trans);
+}
+
+static int
+rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port,
+                              const struct switchdev_obj_port_vlan *vlan,
+                              struct switchdev_trans *trans)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_vlan_add)
+               return -EOPNOTSUPP;
+       return wops->port_obj_vlan_add(rocker_port, vlan, trans);
+}
+
+static int
+rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port,
+                              const struct switchdev_obj_port_vlan *vlan)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_vlan_del)
+               return -EOPNOTSUPP;
+       return wops->port_obj_vlan_del(rocker_port, vlan);
+}
+
+static int
+rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port,
+                               struct switchdev_obj_port_vlan *vlan,
+                               switchdev_obj_dump_cb_t *cb)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_vlan_dump)
+               return -EOPNOTSUPP;
+       return wops->port_obj_vlan_dump(rocker_port, vlan, cb);
+}
+
+static int
+rocker_world_port_obj_fib4_add(struct rocker_port *rocker_port,
+                              const struct switchdev_obj_ipv4_fib *fib4,
+                              struct switchdev_trans *trans)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_fib4_add)
+               return -EOPNOTSUPP;
+       return wops->port_obj_fib4_add(rocker_port, fib4, trans);
+}
+
+static int
+rocker_world_port_obj_fib4_del(struct rocker_port *rocker_port,
+                              const struct switchdev_obj_ipv4_fib *fib4)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_fib4_del)
+               return -EOPNOTSUPP;
+       return wops->port_obj_fib4_del(rocker_port, fib4);
+}
+
+static int
+rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port,
+                             const struct switchdev_obj_port_fdb *fdb,
+                             struct switchdev_trans *trans)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_fdb_add)
+               return -EOPNOTSUPP;
+       return wops->port_obj_fdb_add(rocker_port, fdb, trans);
+}
+
+static int
+rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port,
+                             const struct switchdev_obj_port_fdb *fdb)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_fdb_del)
+               return -EOPNOTSUPP;
+       return wops->port_obj_fdb_del(rocker_port, fdb);
+}
+
+static int
+rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port,
+                              struct switchdev_obj_port_fdb *fdb,
+                              switchdev_obj_dump_cb_t *cb)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_obj_fdb_dump)
+               return -EOPNOTSUPP;
+       return wops->port_obj_fdb_dump(rocker_port, fdb, cb);
+}
+
+static int rocker_world_port_master_linked(struct rocker_port *rocker_port,
+                                          struct net_device *master)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_master_linked)
+               return -EOPNOTSUPP;
+       return wops->port_master_linked(rocker_port, master);
+}
+
+static int rocker_world_port_master_unlinked(struct rocker_port *rocker_port,
+                                            struct net_device *master)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_master_unlinked)
+               return -EOPNOTSUPP;
+       return wops->port_master_unlinked(rocker_port, master);
+}
+
+static int rocker_world_port_neigh_update(struct rocker_port *rocker_port,
+                                         struct neighbour *n)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_neigh_update)
+               return -EOPNOTSUPP;
+       return wops->port_neigh_update(rocker_port, n);
+}
+
+static int rocker_world_port_neigh_destroy(struct rocker_port *rocker_port,
+                                          struct neighbour *n)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_neigh_destroy)
+               return -EOPNOTSUPP;
+       return wops->port_neigh_destroy(rocker_port, n);
+}
+
+static int rocker_world_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
+                                             const unsigned char *addr,
+                                             __be16 vlan_id)
+{
+       struct rocker_world_ops *wops = rocker_port->rocker->wops;
+
+       if (!wops->port_ev_mac_vlan_seen)
+               return -EOPNOTSUPP;
+       return wops->port_ev_mac_vlan_seen(rocker_port, addr, vlan_id);
+}
+
+/*****************
+ * Net device ops
+ *****************/
+
+static int rocker_port_open(struct net_device *dev)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int err;
+
+       err = rocker_port_dma_rings_init(rocker_port);
+       if (err)
+               return err;
+
+       err = request_irq(rocker_msix_tx_vector(rocker_port),
+                         rocker_tx_irq_handler, 0,
+                         rocker_driver_name, rocker_port);
+       if (err) {
+               netdev_err(rocker_port->dev, "cannot assign tx irq\n");
+               goto err_request_tx_irq;
+       }
+
+       err = request_irq(rocker_msix_rx_vector(rocker_port),
+                         rocker_rx_irq_handler, 0,
+                         rocker_driver_name, rocker_port);
+       if (err) {
+               netdev_err(rocker_port->dev, "cannot assign rx irq\n");
+               goto err_request_rx_irq;
+       }
+
+       err = rocker_world_port_open(rocker_port);
+       if (err) {
+               netdev_err(rocker_port->dev, "cannot open port in world\n");
+               goto err_world_port_open;
+       }
+
+       napi_enable(&rocker_port->napi_tx);
+       napi_enable(&rocker_port->napi_rx);
+       if (!dev->proto_down)
+               rocker_port_set_enable(rocker_port, true);
+       netif_start_queue(dev);
+       return 0;
+
+err_world_port_open:
+       free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
+err_request_rx_irq:
+       free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
+err_request_tx_irq:
+       rocker_port_dma_rings_fini(rocker_port);
+       return err;
+}
+
+static int rocker_port_stop(struct net_device *dev)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       rocker_port_set_enable(rocker_port, false);
+       napi_disable(&rocker_port->napi_rx);
+       napi_disable(&rocker_port->napi_tx);
+       rocker_world_port_stop(rocker_port);
+       free_irq(rocker_msix_rx_vector(rocker_port), rocker_port);
+       free_irq(rocker_msix_tx_vector(rocker_port), rocker_port);
+       rocker_port_dma_rings_fini(rocker_port);
+
+       return 0;
+}
+
+static void rocker_tx_desc_frags_unmap(const struct rocker_port *rocker_port,
+                                      const struct rocker_desc_info *desc_info)
+{
+       const struct rocker *rocker = rocker_port->rocker;
+       struct pci_dev *pdev = rocker->pdev;
+       const struct rocker_tlv *attrs[ROCKER_TLV_TX_MAX + 1];
+       struct rocker_tlv *attr;
+       int rem;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_TX_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_TX_FRAGS])
+               return;
+       rocker_tlv_for_each_nested(attr, attrs[ROCKER_TLV_TX_FRAGS], rem) {
+               const struct rocker_tlv *frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_MAX + 1];
+               dma_addr_t dma_handle;
+               size_t len;
+
+               if (rocker_tlv_type(attr) != ROCKER_TLV_TX_FRAG)
+                       continue;
+               rocker_tlv_parse_nested(frag_attrs, ROCKER_TLV_TX_FRAG_ATTR_MAX,
+                                       attr);
+               if (!frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
+                   !frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN])
+                       continue;
+               dma_handle = rocker_tlv_get_u64(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
+               len = rocker_tlv_get_u16(frag_attrs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
+               pci_unmap_single(pdev, dma_handle, len, DMA_TO_DEVICE);
+       }
+}
+
+static int rocker_tx_desc_frag_map_put(const struct rocker_port *rocker_port,
+                                      struct rocker_desc_info *desc_info,
+                                      char *buf, size_t buf_len)
+{
+       const struct rocker *rocker = rocker_port->rocker;
+       struct pci_dev *pdev = rocker->pdev;
+       dma_addr_t dma_handle;
+       struct rocker_tlv *frag;
+
+       dma_handle = pci_map_single(pdev, buf, buf_len, DMA_TO_DEVICE);
+       if (unlikely(pci_dma_mapping_error(pdev, dma_handle))) {
+               if (net_ratelimit())
+                       netdev_err(rocker_port->dev, "failed to dma map tx frag\n");
+               return -EIO;
+       }
+       frag = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAG);
+       if (!frag)
+               goto unmap_frag;
+       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_TX_FRAG_ATTR_ADDR,
+                              dma_handle))
+               goto nest_cancel;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_TX_FRAG_ATTR_LEN,
+                              buf_len))
+               goto nest_cancel;
+       rocker_tlv_nest_end(desc_info, frag);
+       return 0;
+
+nest_cancel:
+       rocker_tlv_nest_cancel(desc_info, frag);
+unmap_frag:
+       pci_unmap_single(pdev, dma_handle, buf_len, DMA_TO_DEVICE);
+       return -EMSGSIZE;
+}
+
+static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       struct rocker *rocker = rocker_port->rocker;
+       struct rocker_desc_info *desc_info;
+       struct rocker_tlv *frags;
+       int i;
+       int err;
+
+       desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+       if (unlikely(!desc_info)) {
+               if (net_ratelimit())
+                       netdev_err(dev, "tx ring full when queue awake\n");
+               return NETDEV_TX_BUSY;
+       }
+
+       rocker_desc_cookie_ptr_set(desc_info, skb);
+
+       frags = rocker_tlv_nest_start(desc_info, ROCKER_TLV_TX_FRAGS);
+       if (!frags)
+               goto out;
+       err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+                                         skb->data, skb_headlen(skb));
+       if (err)
+               goto nest_cancel;
+       if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX) {
+               err = skb_linearize(skb);
+               if (err)
+                       goto unmap_frags;
+       }
+
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               err = rocker_tx_desc_frag_map_put(rocker_port, desc_info,
+                                                 skb_frag_address(frag),
+                                                 skb_frag_size(frag));
+               if (err)
+                       goto unmap_frags;
+       }
+       rocker_tlv_nest_end(desc_info, frags);
+
+       rocker_desc_gen_clear(desc_info);
+       rocker_desc_head_set(rocker, &rocker_port->tx_ring, desc_info);
+
+       desc_info = rocker_desc_head_get(&rocker_port->tx_ring);
+       if (!desc_info)
+               netif_stop_queue(dev);
+
+       return NETDEV_TX_OK;
+
+unmap_frags:
+       rocker_tx_desc_frags_unmap(rocker_port, desc_info);
+nest_cancel:
+       rocker_tlv_nest_cancel(desc_info, frags);
+out:
+       dev_kfree_skb(skb);
+       dev->stats.tx_dropped++;
+
+       return NETDEV_TX_OK;
+}
+
+static int rocker_port_set_mac_address(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int err;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       err = rocker_cmd_set_port_settings_macaddr(rocker_port, addr->sa_data);
+       if (err)
+               return err;
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       return 0;
+}
+
+static int rocker_port_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int running = netif_running(dev);
+       int err;
+
+#define ROCKER_PORT_MIN_MTU    68
+#define ROCKER_PORT_MAX_MTU    9000
+
+       if (new_mtu < ROCKER_PORT_MIN_MTU || new_mtu > ROCKER_PORT_MAX_MTU)
+               return -EINVAL;
+
+       if (running)
+               rocker_port_stop(dev);
+
+       netdev_info(dev, "MTU change from %d to %d\n", dev->mtu, new_mtu);
+       dev->mtu = new_mtu;
+
+       err = rocker_cmd_set_port_settings_mtu(rocker_port, new_mtu);
+       if (err)
+               return err;
+
+       if (running)
+               err = rocker_port_open(dev);
+
+       return err;
+}
+
+static int rocker_port_get_phys_port_name(struct net_device *dev,
+                                         char *buf, size_t len)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       struct port_name name = { .buf = buf, .len = len };
+       int err;
+
+       err = rocker_cmd_exec(rocker_port, false,
+                             rocker_cmd_get_port_settings_prep, NULL,
+                             rocker_cmd_get_port_settings_phys_name_proc,
+                             &name);
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+static int rocker_port_change_proto_down(struct net_device *dev,
+                                        bool proto_down)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+
+       if (rocker_port->dev->flags & IFF_UP)
+               rocker_port_set_enable(rocker_port, !proto_down);
+       rocker_port->dev->proto_down = proto_down;
+       return 0;
+}
+
+static void rocker_port_neigh_destroy(struct neighbour *n)
+{
+       struct rocker_port *rocker_port = netdev_priv(n->dev);
+       int err;
+
+       err = rocker_world_port_neigh_destroy(rocker_port, n);
+       if (err)
+               netdev_warn(rocker_port->dev, "failed to handle neigh destroy (err %d)\n",
+                           err);
+}
+
+static const struct net_device_ops rocker_port_netdev_ops = {
+       .ndo_open                       = rocker_port_open,
+       .ndo_stop                       = rocker_port_stop,
+       .ndo_start_xmit                 = rocker_port_xmit,
+       .ndo_set_mac_address            = rocker_port_set_mac_address,
+       .ndo_change_mtu                 = rocker_port_change_mtu,
+       .ndo_bridge_getlink             = switchdev_port_bridge_getlink,
+       .ndo_bridge_setlink             = switchdev_port_bridge_setlink,
+       .ndo_bridge_dellink             = switchdev_port_bridge_dellink,
+       .ndo_fdb_add                    = switchdev_port_fdb_add,
+       .ndo_fdb_del                    = switchdev_port_fdb_del,
+       .ndo_fdb_dump                   = switchdev_port_fdb_dump,
+       .ndo_get_phys_port_name         = rocker_port_get_phys_port_name,
+       .ndo_change_proto_down          = rocker_port_change_proto_down,
+       .ndo_neigh_destroy              = rocker_port_neigh_destroy,
+};
+
+/********************
+ * swdev interface
+ ********************/
+
+static int rocker_port_attr_get(struct net_device *dev,
+                               struct switchdev_attr *attr)
+{
+       const struct rocker_port *rocker_port = netdev_priv(dev);
+       const struct rocker *rocker = rocker_port->rocker;
+       int err = 0;
+
+       switch (attr->id) {
+       case SWITCHDEV_ATTR_ID_PORT_PARENT_ID:
+               attr->u.ppid.id_len = sizeof(rocker->hw.id);
+               memcpy(&attr->u.ppid.id, &rocker->hw.id, attr->u.ppid.id_len);
+               break;
+       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+               err = rocker_world_port_attr_bridge_flags_get(rocker_port,
+                                                             &attr->u.brport_flags);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
+static int rocker_port_attr_set(struct net_device *dev,
+                               const struct switchdev_attr *attr,
+                               struct switchdev_trans *trans)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int err = 0;
+
+       switch (attr->id) {
+       case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
+               err = rocker_world_port_attr_stp_state_set(rocker_port,
+                                                          attr->u.stp_state,
+                                                          trans);
+               break;
+       case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
+               err = rocker_world_port_attr_bridge_flags_set(rocker_port,
+                                                             attr->u.brport_flags,
+                                                             trans);
+               break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME:
+               err = rocker_world_port_attr_bridge_ageing_time_set(rocker_port,
+                                                                   attr->u.ageing_time,
+                                                                   trans);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static int rocker_port_obj_add(struct net_device *dev,
+                              const struct switchdev_obj *obj,
+                              struct switchdev_trans *trans)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int err = 0;
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_world_port_obj_vlan_add(rocker_port,
+                                                    SWITCHDEV_OBJ_PORT_VLAN(obj),
+                                                    trans);
+               break;
+       case SWITCHDEV_OBJ_ID_IPV4_FIB:
+               err = rocker_world_port_obj_fib4_add(rocker_port,
+                                                    SWITCHDEV_OBJ_IPV4_FIB(obj),
+                                                    trans);
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_world_port_obj_fdb_add(rocker_port,
+                                                   SWITCHDEV_OBJ_PORT_FDB(obj),
+                                                   trans);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static int rocker_port_obj_del(struct net_device *dev,
+                              const struct switchdev_obj *obj)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+       int err = 0;
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_world_port_obj_vlan_del(rocker_port,
+                                                    SWITCHDEV_OBJ_PORT_VLAN(obj));
+               break;
+       case SWITCHDEV_OBJ_ID_IPV4_FIB:
+               err = rocker_world_port_obj_fib4_del(rocker_port,
+                                                    SWITCHDEV_OBJ_IPV4_FIB(obj));
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_world_port_obj_fdb_del(rocker_port,
+                                                   SWITCHDEV_OBJ_PORT_FDB(obj));
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static int rocker_port_obj_dump(struct net_device *dev,
+                               struct switchdev_obj *obj,
+                               switchdev_obj_dump_cb_t *cb)
+{
+       const struct rocker_port *rocker_port = netdev_priv(dev);
+       int err = 0;
+
+       switch (obj->id) {
+       case SWITCHDEV_OBJ_ID_PORT_FDB:
+               err = rocker_world_port_obj_fdb_dump(rocker_port,
+                                                    SWITCHDEV_OBJ_PORT_FDB(obj),
+                                                    cb);
+               break;
+       case SWITCHDEV_OBJ_ID_PORT_VLAN:
+               err = rocker_world_port_obj_vlan_dump(rocker_port,
+                                                     SWITCHDEV_OBJ_PORT_VLAN(obj),
+                                                     cb);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static const struct switchdev_ops rocker_port_switchdev_ops = {
+       .switchdev_port_attr_get        = rocker_port_attr_get,
+       .switchdev_port_attr_set        = rocker_port_attr_set,
+       .switchdev_port_obj_add         = rocker_port_obj_add,
+       .switchdev_port_obj_del         = rocker_port_obj_del,
+       .switchdev_port_obj_dump        = rocker_port_obj_dump,
+};
+
+/********************
+ * ethtool interface
+ ********************/
+
+static int rocker_port_get_settings(struct net_device *dev,
+                                   struct ethtool_cmd *ecmd)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+
+       return rocker_cmd_get_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static int rocker_port_set_settings(struct net_device *dev,
+                                   struct ethtool_cmd *ecmd)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+
+       return rocker_cmd_set_port_settings_ethtool(rocker_port, ecmd);
+}
+
+static void rocker_port_get_drvinfo(struct net_device *dev,
+                                   struct ethtool_drvinfo *drvinfo)
+{
+       strlcpy(drvinfo->driver, rocker_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+}
+
+static struct rocker_port_stats {
+       char str[ETH_GSTRING_LEN];
+       int type;
+} rocker_port_stats[] = {
+       { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS,    },
+       { "rx_bytes",   ROCKER_TLV_CMD_PORT_STATS_RX_BYTES,   },
+       { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },
+       { "rx_errors",  ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS,  },
+
+       { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS,    },
+       { "tx_bytes",   ROCKER_TLV_CMD_PORT_STATS_TX_BYTES,   },
+       { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },
+       { "tx_errors",  ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS,  },
+};
+
+#define ROCKER_PORT_STATS_LEN  ARRAY_SIZE(rocker_port_stats)
+
+static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
+                                   u8 *data)
+{
+       u8 *p = data;
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
+                       memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static int
+rocker_cmd_get_port_stats_prep(const struct rocker_port *rocker_port,
+                              struct rocker_desc_info *desc_info,
+                              void *priv)
+{
+       struct rocker_tlv *cmd_stats;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+                              ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))
+               return -EMSGSIZE;
+
+       cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_stats)
+               return -EMSGSIZE;
+
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_PPORT,
+                              rocker_port->pport))
+               return -EMSGSIZE;
+
+       rocker_tlv_nest_end(desc_info, cmd_stats);
+
+       return 0;
+}
+
+static int
+rocker_cmd_get_port_stats_ethtool_proc(const struct rocker_port *rocker_port,
+                                      const struct rocker_desc_info *desc_info,
+                                      void *priv)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+       const struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
+       const struct rocker_tlv *pattr;
+       u32 pport;
+       u64 *data = priv;
+       int i;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+
+       if (!attrs[ROCKER_TLV_CMD_INFO])
+               return -EIO;
+
+       rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,
+                               attrs[ROCKER_TLV_CMD_INFO]);
+
+       if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT])
+               return -EIO;
+
+       pport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_PPORT]);
+       if (pport != rocker_port->pport)
+               return -EIO;
+
+       for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
+               pattr = stats_attrs[rocker_port_stats[i].type];
+               if (!pattr)
+                       continue;
+
+               data[i] = rocker_tlv_get_u64(pattr);
+       }
+
+       return 0;
+}
+
+static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
+                                            void *priv)
+{
+       return rocker_cmd_exec(rocker_port, false,
+                              rocker_cmd_get_port_stats_prep, NULL,
+                              rocker_cmd_get_port_stats_ethtool_proc,
+                              priv);
+}
+
+static void rocker_port_get_stats(struct net_device *dev,
+                                 struct ethtool_stats *stats, u64 *data)
+{
+       struct rocker_port *rocker_port = netdev_priv(dev);
+
+       if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
+                       data[i] = 0;
+       }
+}
+
+static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ROCKER_PORT_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static const struct ethtool_ops rocker_port_ethtool_ops = {
+       .get_settings           = rocker_port_get_settings,
+       .set_settings           = rocker_port_set_settings,
+       .get_drvinfo            = rocker_port_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+       .get_strings            = rocker_port_get_strings,
+       .get_ethtool_stats      = rocker_port_get_stats,
+       .get_sset_count         = rocker_port_get_sset_count,
+};
+
+/*****************
+ * NAPI interface
+ *****************/
+
+static struct rocker_port *rocker_port_napi_tx_get(struct napi_struct *napi)
+{
+       return container_of(napi, struct rocker_port, napi_tx);
+}
+
+static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
+{
+       struct rocker_port *rocker_port = rocker_port_napi_tx_get(napi);
+       const struct rocker *rocker = rocker_port->rocker;
+       const struct rocker_desc_info *desc_info;
+       u32 credits = 0;
+       int err;
+
+       /* Cleanup tx descriptors */
+       while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) {
+               struct sk_buff *skb;
+
+               err = rocker_desc_err(desc_info);
+               if (err && net_ratelimit())
+                       netdev_err(rocker_port->dev, "tx desc received with err %d\n",
+                                  err);
+               rocker_tx_desc_frags_unmap(rocker_port, desc_info);
+
+               skb = rocker_desc_cookie_ptr_get(desc_info);
+               if (err == 0) {
+                       rocker_port->dev->stats.tx_packets++;
+                       rocker_port->dev->stats.tx_bytes += skb->len;
+               } else {
+                       rocker_port->dev->stats.tx_errors++;
+               }
+
+               dev_kfree_skb_any(skb);
+               credits++;
+       }
+
+       if (credits && netif_queue_stopped(rocker_port->dev))
+               netif_wake_queue(rocker_port->dev);
+
+       napi_complete(napi);
+       rocker_dma_ring_credits_set(rocker, &rocker_port->tx_ring, credits);
+
+       return 0;
+}
+
+static int rocker_port_rx_proc(const struct rocker *rocker,
+                              const struct rocker_port *rocker_port,
+                              struct rocker_desc_info *desc_info)
+{
+       const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1];
+       struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info);
+       size_t rx_len;
+       u16 rx_flags = 0;
+
+       if (!skb)
+               return -ENOENT;
+
+       rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info);
+       if (!attrs[ROCKER_TLV_RX_FRAG_LEN])
+               return -EINVAL;
+       if (attrs[ROCKER_TLV_RX_FLAGS])
+               rx_flags = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FLAGS]);
+
+       rocker_dma_rx_ring_skb_unmap(rocker, attrs);
+
+       rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]);
+       skb_put(skb, rx_len);
+       skb->protocol = eth_type_trans(skb, rocker_port->dev);
+
+       if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD)
+               skb->offload_fwd_mark = rocker_port->dev->offload_fwd_mark;
+
+       rocker_port->dev->stats.rx_packets++;
+       rocker_port->dev->stats.rx_bytes += skb->len;
+
+       netif_receive_skb(skb);
+
+       return rocker_dma_rx_ring_skb_alloc(rocker_port, desc_info);
+}
+
+static struct rocker_port *rocker_port_napi_rx_get(struct napi_struct *napi)
+{
+       return container_of(napi, struct rocker_port, napi_rx);
+}
+
+static int rocker_port_poll_rx(struct napi_struct *napi, int budget)
+{
+       struct rocker_port *rocker_port = rocker_port_napi_rx_get(napi);
+       const struct rocker *rocker = rocker_port->rocker;
+       struct rocker_desc_info *desc_info;
+       u32 credits = 0;
+       int err;
+
+       /* Process rx descriptors */
+       while (credits < budget &&
+              (desc_info = rocker_desc_tail_get(&rocker_port->rx_ring))) {
+               err = rocker_desc_err(desc_info);
+               if (err) {
+                       if (net_ratelimit())
+                               netdev_err(rocker_port->dev, "rx desc received with err %d\n",
+                                          err);
+               } else {
+                       err = rocker_port_rx_proc(rocker, rocker_port,
+                                                 desc_info);
+                       if (err && net_ratelimit())
+                               netdev_err(rocker_port->dev, "rx processing failed with err %d\n",
+                                          err);
+               }
+               if (err)
+                       rocker_port->dev->stats.rx_errors++;
+
+               rocker_desc_gen_clear(desc_info);
+               rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info);
+               credits++;
+       }
+
+       if (credits < budget)
+               napi_complete(napi);
+
+       rocker_dma_ring_credits_set(rocker, &rocker_port->rx_ring, credits);
+
+       return credits;
+}
+
+/*****************
+ * PCI driver ops
+ *****************/
+
+static void rocker_carrier_init(const struct rocker_port *rocker_port)
+{
+       const struct rocker *rocker = rocker_port->rocker;
+       u64 link_status = rocker_read64(rocker, PORT_PHYS_LINK_STATUS);
+       bool link_up;
+
+       link_up = link_status & (1 << rocker_port->pport);
+       if (link_up)
+               netif_carrier_on(rocker_port->dev);
+       else
+               netif_carrier_off(rocker_port->dev);
+}
+
+static void rocker_remove_ports(struct rocker *rocker)
+{
+       struct rocker_port *rocker_port;
+       int i;
+
+       for (i = 0; i < rocker->port_count; i++) {
+               rocker_port = rocker->ports[i];
+               if (!rocker_port)
+                       continue;
+               rocker_world_port_fini(rocker_port);
+               unregister_netdev(rocker_port->dev);
+               rocker_world_port_post_fini(rocker_port);
+               free_netdev(rocker_port->dev);
+       }
+       rocker_world_fini(rocker);
+       kfree(rocker->ports);
+}
+
+static void rocker_port_dev_addr_init(struct rocker_port *rocker_port)
+{
+       const struct rocker *rocker = rocker_port->rocker;
+       const struct pci_dev *pdev = rocker->pdev;
+       int err;
+
+       err = rocker_cmd_get_port_settings_macaddr(rocker_port,
+                                                  rocker_port->dev->dev_addr);
+       if (err) {
+               dev_warn(&pdev->dev, "failed to get mac address, using random\n");
+               eth_hw_addr_random(rocker_port->dev);
+       }
+}
+
+static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
+{
+       const struct pci_dev *pdev = rocker->pdev;
+       struct rocker_port *rocker_port;
+       struct net_device *dev;
+       int err;
+
+       dev = alloc_etherdev(sizeof(struct rocker_port));
+       if (!dev)
+               return -ENOMEM;
+       rocker_port = netdev_priv(dev);
+       rocker_port->dev = dev;
+       rocker_port->rocker = rocker;
+       rocker_port->port_number = port_number;
+       rocker_port->pport = port_number + 1;
+
+       err = rocker_world_check_init(rocker_port);
+       if (err) {
+               dev_err(&pdev->dev, "world init failed\n");
+               goto err_world_check_init;
+       }
+
+       rocker_port_dev_addr_init(rocker_port);
+       dev->netdev_ops = &rocker_port_netdev_ops;
+       dev->ethtool_ops = &rocker_port_ethtool_ops;
+       dev->switchdev_ops = &rocker_port_switchdev_ops;
+       netif_tx_napi_add(dev, &rocker_port->napi_tx, rocker_port_poll_tx,
+                         NAPI_POLL_WEIGHT);
+       netif_napi_add(dev, &rocker_port->napi_rx, rocker_port_poll_rx,
+                      NAPI_POLL_WEIGHT);
+       rocker_carrier_init(rocker_port);
+
+       dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_SG;
+
+       err = rocker_world_port_pre_init(rocker_port);
+       if (err) {
+               dev_err(&pdev->dev, "port world pre-init failed\n");
+               goto err_world_port_pre_init;
+       }
+       err = register_netdev(dev);
+       if (err) {
+               dev_err(&pdev->dev, "register_netdev failed\n");
+               goto err_register_netdev;
+       }
+       rocker->ports[port_number] = rocker_port;
+
+       err = rocker_world_port_init(rocker_port);
+       if (err) {
+               dev_err(&pdev->dev, "port world init failed\n");
+               goto err_world_port_init;
+       }
+
+       return 0;
+
+err_world_port_init:
+       rocker->ports[port_number] = NULL;
+       unregister_netdev(dev);
+err_register_netdev:
+       rocker_world_port_post_fini(rocker_port);
+err_world_port_pre_init:
+err_world_check_init:
+       free_netdev(dev);
+       return err;
+}
+
+static int rocker_probe_ports(struct rocker *rocker)
+{
+       int i;
+       size_t alloc_size;
+       int err;
+
+       alloc_size = sizeof(struct rocker_port *) * rocker->port_count;
+       rocker->ports = kzalloc(alloc_size, GFP_KERNEL);
+       if (!rocker->ports)
+               return -ENOMEM;
+       for (i = 0; i < rocker->port_count; i++) {
+               err = rocker_probe_port(rocker, i);
+               if (err)
+                       goto remove_ports;
+       }
+       return 0;
+
+remove_ports:
+       rocker_remove_ports(rocker);
+       return err;
+}
+
+static int rocker_msix_init(struct rocker *rocker)
+{
+       struct pci_dev *pdev = rocker->pdev;
+       int msix_entries;
+       int i;
+       int err;
+
+       msix_entries = pci_msix_vec_count(pdev);
+       if (msix_entries < 0)
+               return msix_entries;
+
+       if (msix_entries != ROCKER_MSIX_VEC_COUNT(rocker->port_count))
+               return -EINVAL;
+
+       rocker->msix_entries = kmalloc_array(msix_entries,
+                                            sizeof(struct msix_entry),
+                                            GFP_KERNEL);
+       if (!rocker->msix_entries)
+               return -ENOMEM;
+
+       for (i = 0; i < msix_entries; i++)
+               rocker->msix_entries[i].entry = i;
+
+       err = pci_enable_msix_exact(pdev, rocker->msix_entries, msix_entries);
+       if (err < 0)
+               goto err_enable_msix;
+
+       return 0;
+
+err_enable_msix:
+       kfree(rocker->msix_entries);
+       return err;
+}
+
+static void rocker_msix_fini(const struct rocker *rocker)
+{
+       pci_disable_msix(rocker->pdev);
+       kfree(rocker->msix_entries);
+}
+
+static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct rocker *rocker;
+       int err;
+
+       rocker = kzalloc(sizeof(*rocker), GFP_KERNEL);
+       if (!rocker)
+               return -ENOMEM;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "pci_enable_device failed\n");
+               goto err_pci_enable_device;
+       }
+
+       err = pci_request_regions(pdev, rocker_driver_name);
+       if (err) {
+               dev_err(&pdev->dev, "pci_request_regions failed\n");
+               goto err_pci_request_regions;
+       }
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       if (!err) {
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               if (err) {
+                       dev_err(&pdev->dev, "pci_set_consistent_dma_mask failed\n");
+                       goto err_pci_set_dma_mask;
+               }
+       } else {
+               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               if (err) {
+                       dev_err(&pdev->dev, "pci_set_dma_mask failed\n");
+                       goto err_pci_set_dma_mask;
+               }
+       }
+
+       if (pci_resource_len(pdev, 0) < ROCKER_PCI_BAR0_SIZE) {
+               dev_err(&pdev->dev, "invalid PCI region size\n");
+               err = -EINVAL;
+               goto err_pci_resource_len_check;
+       }
+
+       rocker->hw_addr = ioremap(pci_resource_start(pdev, 0),
+                                 pci_resource_len(pdev, 0));
+       if (!rocker->hw_addr) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               err = -EIO;
+               goto err_ioremap;
+       }
+       pci_set_master(pdev);
+
+       rocker->pdev = pdev;
+       pci_set_drvdata(pdev, rocker);
+
+       rocker->port_count = rocker_read32(rocker, PORT_PHYS_COUNT);
+
+       err = rocker_msix_init(rocker);
+       if (err) {
+               dev_err(&pdev->dev, "MSI-X init failed\n");
+               goto err_msix_init;
+       }
+
+       err = rocker_basic_hw_test(rocker);
+       if (err) {
+               dev_err(&pdev->dev, "basic hw test failed\n");
+               goto err_basic_hw_test;
+       }
+
+       rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
+
+       err = rocker_dma_rings_init(rocker);
+       if (err)
+               goto err_dma_rings_init;
+
+       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD),
+                         rocker_cmd_irq_handler, 0,
+                         rocker_driver_name, rocker);
+       if (err) {
+               dev_err(&pdev->dev, "cannot assign cmd irq\n");
+               goto err_request_cmd_irq;
+       }
+
+       err = request_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT),
+                         rocker_event_irq_handler, 0,
+                         rocker_driver_name, rocker);
+       if (err) {
+               dev_err(&pdev->dev, "cannot assign event irq\n");
+               goto err_request_event_irq;
+       }
+
+       rocker->hw.id = rocker_read64(rocker, SWITCH_ID);
+
+       err = rocker_probe_ports(rocker);
+       if (err) {
+               dev_err(&pdev->dev, "failed to probe ports\n");
+               goto err_probe_ports;
+       }
+
+       dev_info(&pdev->dev, "Rocker switch with id %*phN\n",
+                (int)sizeof(rocker->hw.id), &rocker->hw.id);
+
+       return 0;
+
+err_probe_ports:
+       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
+err_request_event_irq:
+       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
+err_request_cmd_irq:
+       rocker_dma_rings_fini(rocker);
+err_dma_rings_init:
+err_basic_hw_test:
+       rocker_msix_fini(rocker);
+err_msix_init:
+       iounmap(rocker->hw_addr);
+err_ioremap:
+err_pci_resource_len_check:
+err_pci_set_dma_mask:
+       pci_release_regions(pdev);
+err_pci_request_regions:
+       pci_disable_device(pdev);
+err_pci_enable_device:
+       kfree(rocker);
+       return err;
+}
+
+static void rocker_remove(struct pci_dev *pdev)
+{
+       struct rocker *rocker = pci_get_drvdata(pdev);
+
+       rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET);
+       rocker_remove_ports(rocker);
+       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_EVENT), rocker);
+       free_irq(rocker_msix_vector(rocker, ROCKER_MSIX_VEC_CMD), rocker);
+       rocker_dma_rings_fini(rocker);
+       rocker_msix_fini(rocker);
+       iounmap(rocker->hw_addr);
+       pci_release_regions(rocker->pdev);
+       pci_disable_device(rocker->pdev);
+       kfree(rocker);
+}
+
+static struct pci_driver rocker_pci_driver = {
+       .name           = rocker_driver_name,
+       .id_table       = rocker_pci_id_table,
+       .probe          = rocker_probe,
+       .remove         = rocker_remove,
+};
+
+/************************************
+ * Net device notifier event handler
+ ************************************/
+
+static bool rocker_port_dev_check(const struct net_device *dev)
+{
+       return dev->netdev_ops == &rocker_port_netdev_ops;
+}
+
+static int rocker_netdevice_event(struct notifier_block *unused,
+                                 unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct netdev_notifier_changeupper_info *info;
+       struct rocker_port *rocker_port;
+       int err;
+
+       if (!rocker_port_dev_check(dev))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_CHANGEUPPER:
+               info = ptr;
+               if (!info->master)
+                       goto out;
+               rocker_port = netdev_priv(dev);
+               if (info->linking) {
+                       err = rocker_world_port_master_linked(rocker_port,
+                                                             info->upper_dev);
+                       if (err)
+                               netdev_warn(dev, "failed to reflect master linked (err %d)\n",
+                                           err);
+               } else {
+                       err = rocker_world_port_master_unlinked(rocker_port,
+                                                               info->upper_dev);
+                       if (err)
+                               netdev_warn(dev, "failed to reflect master unlinked (err %d)\n",
+                                           err);
+               }
+       }
+out:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rocker_netdevice_nb __read_mostly = {
+       .notifier_call = rocker_netdevice_event,
+};
+
+/************************************
+ * Net event notifier event handler
+ ************************************/
+
+static int rocker_netevent_event(struct notifier_block *unused,
+                                unsigned long event, void *ptr)
+{
+       struct rocker_port *rocker_port;
+       struct net_device *dev;
+       struct neighbour *n = ptr;
+       int err;
+
+       switch (event) {
+       case NETEVENT_NEIGH_UPDATE:
+               if (n->tbl != &arp_tbl)
+                       return NOTIFY_DONE;
+               dev = n->dev;
+               if (!rocker_port_dev_check(dev))
+                       return NOTIFY_DONE;
+               rocker_port = netdev_priv(dev);
+               err = rocker_world_port_neigh_update(rocker_port, n);
+               if (err)
+                       netdev_warn(dev, "failed to handle neigh update (err %d)\n",
+                                   err);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rocker_netevent_nb __read_mostly = {
+       .notifier_call = rocker_netevent_event,
+};
+
+/***********************
+ * Module init and exit
+ ***********************/
+
+static int __init rocker_module_init(void)
+{
+       int err;
+
+       register_netdevice_notifier(&rocker_netdevice_nb);
+       register_netevent_notifier(&rocker_netevent_nb);
+       err = pci_register_driver(&rocker_pci_driver);
+       if (err)
+               goto err_pci_register_driver;
+       return 0;
+
+err_pci_register_driver:
+       unregister_netevent_notifier(&rocker_netevent_nb);
+       unregister_netdevice_notifier(&rocker_netdevice_nb);
+       return err;
+}
+
+static void __exit rocker_module_exit(void)
+{
+       unregister_netevent_notifier(&rocker_netevent_nb);
+       unregister_netdevice_notifier(&rocker_netdevice_nb);
+       pci_unregister_driver(&rocker_pci_driver);
+}
+
+module_init(rocker_module_init);
+module_exit(rocker_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
+MODULE_AUTHOR("Scott Feldman <sfeldma@gmail.com>");
+MODULE_DESCRIPTION("Rocker switch device driver");
+MODULE_DEVICE_TABLE(pci, rocker_pci_id_table);
diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c
new file mode 100644 (file)
index 0000000..0e758bc
--- /dev/null
@@ -0,0 +1,2958 @@
+/*
+ * drivers/net/ethernet/rocker/rocker_ofdpa.c - Rocker switch OF-DPA-like
+ *                                             implementation
+ * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/hashtable.h>
+#include <linux/crc32.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#include <net/neighbour.h>
+#include <net/switchdev.h>
+#include <net/ip_fib.h>
+#include <net/arp.h>
+
+#include "rocker.h"
+#include "rocker_tlv.h"
+
+struct ofdpa_flow_tbl_key {
+       u32 priority;
+       enum rocker_of_dpa_table_id tbl_id;
+       union {
+               struct {
+                       u32 in_pport;
+                       u32 in_pport_mask;
+                       enum rocker_of_dpa_table_id goto_tbl;
+               } ig_port;
+               struct {
+                       u32 in_pport;
+                       __be16 vlan_id;
+                       __be16 vlan_id_mask;
+                       enum rocker_of_dpa_table_id goto_tbl;
+                       bool untagged;
+                       __be16 new_vlan_id;
+               } vlan;
+               struct {
+                       u32 in_pport;
+                       u32 in_pport_mask;
+                       __be16 eth_type;
+                       u8 eth_dst[ETH_ALEN];
+                       u8 eth_dst_mask[ETH_ALEN];
+                       __be16 vlan_id;
+                       __be16 vlan_id_mask;
+                       enum rocker_of_dpa_table_id goto_tbl;
+                       bool copy_to_cpu;
+               } term_mac;
+               struct {
+                       __be16 eth_type;
+                       __be32 dst4;
+                       __be32 dst4_mask;
+                       enum rocker_of_dpa_table_id goto_tbl;
+                       u32 group_id;
+               } ucast_routing;
+               struct {
+                       u8 eth_dst[ETH_ALEN];
+                       u8 eth_dst_mask[ETH_ALEN];
+                       int has_eth_dst;
+                       int has_eth_dst_mask;
+                       __be16 vlan_id;
+                       u32 tunnel_id;
+                       enum rocker_of_dpa_table_id goto_tbl;
+                       u32 group_id;
+                       bool copy_to_cpu;
+               } bridge;
+               struct {
+                       u32 in_pport;
+                       u32 in_pport_mask;
+                       u8 eth_src[ETH_ALEN];
+                       u8 eth_src_mask[ETH_ALEN];
+                       u8 eth_dst[ETH_ALEN];
+                       u8 eth_dst_mask[ETH_ALEN];
+                       __be16 eth_type;
+                       __be16 vlan_id;
+                       __be16 vlan_id_mask;
+                       u8 ip_proto;
+                       u8 ip_proto_mask;
+                       u8 ip_tos;
+                       u8 ip_tos_mask;
+                       u32 group_id;
+               } acl;
+       };
+};
+
+struct ofdpa_flow_tbl_entry {
+       struct hlist_node entry;
+       u32 cmd;
+       u64 cookie;
+       struct ofdpa_flow_tbl_key key;
+       size_t key_len;
+       u32 key_crc32; /* key */
+};
+
+struct ofdpa_group_tbl_entry {
+       struct hlist_node entry;
+       u32 cmd;
+       u32 group_id; /* key */
+       u16 group_count;
+       u32 *group_ids;
+       union {
+               struct {
+                       u8 pop_vlan;
+               } l2_interface;
+               struct {
+                       u8 eth_src[ETH_ALEN];
+                       u8 eth_dst[ETH_ALEN];
+                       __be16 vlan_id;
+                       u32 group_id;
+               } l2_rewrite;
+               struct {
+                       u8 eth_src[ETH_ALEN];
+                       u8 eth_dst[ETH_ALEN];
+                       __be16 vlan_id;
+                       bool ttl_check;
+                       u32 group_id;
+               } l3_unicast;
+       };
+};
+
+struct ofdpa_fdb_tbl_entry {
+       struct hlist_node entry;
+       u32 key_crc32; /* key */
+       bool learned;
+       unsigned long touched;
+       struct ofdpa_fdb_tbl_key {
+               struct ofdpa_port *ofdpa_port;
+               u8 addr[ETH_ALEN];
+               __be16 vlan_id;
+       } key;
+};
+
+struct ofdpa_internal_vlan_tbl_entry {
+       struct hlist_node entry;
+       int ifindex; /* key */
+       u32 ref_count;
+       __be16 vlan_id;
+};
+
+struct ofdpa_neigh_tbl_entry {
+       struct hlist_node entry;
+       __be32 ip_addr; /* key */
+       struct net_device *dev;
+       u32 ref_count;
+       u32 index;
+       u8 eth_dst[ETH_ALEN];
+       bool ttl_check;
+};
+
+enum {
+       OFDPA_CTRL_LINK_LOCAL_MCAST,
+       OFDPA_CTRL_LOCAL_ARP,
+       OFDPA_CTRL_IPV4_MCAST,
+       OFDPA_CTRL_IPV6_MCAST,
+       OFDPA_CTRL_DFLT_BRIDGING,
+       OFDPA_CTRL_DFLT_OVS,
+       OFDPA_CTRL_MAX,
+};
+
+#define OFDPA_INTERNAL_VLAN_ID_BASE    0x0f00
+#define OFDPA_N_INTERNAL_VLANS         255
+#define OFDPA_VLAN_BITMAP_LEN          BITS_TO_LONGS(VLAN_N_VID)
+#define OFDPA_INTERNAL_VLAN_BITMAP_LEN BITS_TO_LONGS(OFDPA_N_INTERNAL_VLANS)
+#define OFDPA_UNTAGGED_VID 0
+
+struct ofdpa {
+       struct rocker *rocker;
+       DECLARE_HASHTABLE(flow_tbl, 16);
+       spinlock_t flow_tbl_lock;               /* for flow tbl accesses */
+       u64 flow_tbl_next_cookie;
+       DECLARE_HASHTABLE(group_tbl, 16);
+       spinlock_t group_tbl_lock;              /* for group tbl accesses */
+       struct timer_list fdb_cleanup_timer;
+       DECLARE_HASHTABLE(fdb_tbl, 16);
+       spinlock_t fdb_tbl_lock;                /* for fdb tbl accesses */
+       unsigned long internal_vlan_bitmap[OFDPA_INTERNAL_VLAN_BITMAP_LEN];
+       DECLARE_HASHTABLE(internal_vlan_tbl, 8);
+       spinlock_t internal_vlan_tbl_lock;      /* for vlan tbl accesses */
+       DECLARE_HASHTABLE(neigh_tbl, 16);
+       spinlock_t neigh_tbl_lock;              /* for neigh tbl accesses */
+       u32 neigh_tbl_next_index;
+       unsigned long ageing_time;
+};
+
+struct ofdpa_port {
+       struct ofdpa *ofdpa;
+       struct rocker_port *rocker_port;
+       struct net_device *dev;
+       u32 pport;
+       struct net_device *bridge_dev;
+       __be16 internal_vlan_id;
+       int stp_state;
+       u32 brport_flags;
+       unsigned long ageing_time;
+       bool ctrls[OFDPA_CTRL_MAX];
+       unsigned long vlan_bitmap[OFDPA_VLAN_BITMAP_LEN];
+};
+
+static const u8 zero_mac[ETH_ALEN]   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ff_mac[ETH_ALEN]     = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+static const u8 ll_mac[ETH_ALEN]     = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+static const u8 ll_mask[ETH_ALEN]    = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 };
+static const u8 mcast_mac[ETH_ALEN]  = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ipv4_mcast[ETH_ALEN] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
+static const u8 ipv4_mask[ETH_ALEN]  = { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 };
+static const u8 ipv6_mcast[ETH_ALEN] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
+static const u8 ipv6_mask[ETH_ALEN]  = { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+/* Rocker priority levels for flow table entries.  Higher
+ * priority match takes precedence over lower priority match.
+ */
+
+enum {
+       OFDPA_PRIORITY_UNKNOWN = 0,
+       OFDPA_PRIORITY_IG_PORT = 1,
+       OFDPA_PRIORITY_VLAN = 1,
+       OFDPA_PRIORITY_TERM_MAC_UCAST = 0,
+       OFDPA_PRIORITY_TERM_MAC_MCAST = 1,
+       OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT = 1,
+       OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD = 2,
+       OFDPA_PRIORITY_BRIDGING_VLAN = 3,
+       OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT = 1,
+       OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD = 2,
+       OFDPA_PRIORITY_BRIDGING_TENANT = 3,
+       OFDPA_PRIORITY_ACL_CTRL = 3,
+       OFDPA_PRIORITY_ACL_NORMAL = 2,
+       OFDPA_PRIORITY_ACL_DFLT = 1,
+};
+
+static bool ofdpa_vlan_id_is_internal(__be16 vlan_id)
+{
+       u16 start = OFDPA_INTERNAL_VLAN_ID_BASE;
+       u16 end = 0xffe;
+       u16 _vlan_id = ntohs(vlan_id);
+
+       return (_vlan_id >= start && _vlan_id <= end);
+}
+
+static __be16 ofdpa_port_vid_to_vlan(const struct ofdpa_port *ofdpa_port,
+                                    u16 vid, bool *pop_vlan)
+{
+       __be16 vlan_id;
+
+       if (pop_vlan)
+               *pop_vlan = false;
+       vlan_id = htons(vid);
+       if (!vlan_id) {
+               vlan_id = ofdpa_port->internal_vlan_id;
+               if (pop_vlan)
+                       *pop_vlan = true;
+       }
+
+       return vlan_id;
+}
+
+static u16 ofdpa_port_vlan_to_vid(const struct ofdpa_port *ofdpa_port,
+                                 __be16 vlan_id)
+{
+       if (ofdpa_vlan_id_is_internal(vlan_id))
+               return 0;
+
+       return ntohs(vlan_id);
+}
+
+static bool ofdpa_port_is_slave(const struct ofdpa_port *ofdpa_port,
+                               const char *kind)
+{
+       return ofdpa_port->bridge_dev &&
+               !strcmp(ofdpa_port->bridge_dev->rtnl_link_ops->kind, kind);
+}
+
+static bool ofdpa_port_is_bridged(const struct ofdpa_port *ofdpa_port)
+{
+       return ofdpa_port_is_slave(ofdpa_port, "bridge");
+}
+
+static bool ofdpa_port_is_ovsed(const struct ofdpa_port *ofdpa_port)
+{
+       return ofdpa_port_is_slave(ofdpa_port, "openvswitch");
+}
+
+#define OFDPA_OP_FLAG_REMOVE           BIT(0)
+#define OFDPA_OP_FLAG_NOWAIT           BIT(1)
+#define OFDPA_OP_FLAG_LEARNED          BIT(2)
+#define OFDPA_OP_FLAG_REFRESH          BIT(3)
+
+static bool ofdpa_flags_nowait(int flags)
+{
+       return flags & OFDPA_OP_FLAG_NOWAIT;
+}
+
+static void *__ofdpa_mem_alloc(struct switchdev_trans *trans, int flags,
+                              size_t size)
+{
+       struct switchdev_trans_item *elem = NULL;
+       gfp_t gfp_flags = (flags & OFDPA_OP_FLAG_NOWAIT) ?
+                         GFP_ATOMIC : GFP_KERNEL;
+
+       /* If in transaction prepare phase, allocate the memory
+        * and enqueue it on a transaction.  If in transaction
+        * commit phase, dequeue the memory from the transaction
+        * rather than re-allocating the memory.  The idea is the
+        * driver code paths for prepare and commit are identical
+        * so the memory allocated in the prepare phase is the
+        * memory used in the commit phase.
+        */
+
+       if (!trans) {
+               elem = kzalloc(size + sizeof(*elem), gfp_flags);
+       } else if (switchdev_trans_ph_prepare(trans)) {
+               elem = kzalloc(size + sizeof(*elem), gfp_flags);
+               if (!elem)
+                       return NULL;
+               switchdev_trans_item_enqueue(trans, elem, kfree, elem);
+       } else {
+               elem = switchdev_trans_item_dequeue(trans);
+       }
+
+       return elem ? elem + 1 : NULL;
+}
+
+static void *ofdpa_kzalloc(struct switchdev_trans *trans, int flags,
+                          size_t size)
+{
+       return __ofdpa_mem_alloc(trans, flags, size);
+}
+
+static void *ofdpa_kcalloc(struct switchdev_trans *trans, int flags,
+                          size_t n, size_t size)
+{
+       return __ofdpa_mem_alloc(trans, flags, n * size);
+}
+
+static void ofdpa_kfree(struct switchdev_trans *trans, const void *mem)
+{
+       struct switchdev_trans_item *elem;
+
+       /* Frees are ignored if in transaction prepare phase.  The
+        * memory remains on the per-port list until freed in the
+        * commit phase.
+        */
+
+       if (switchdev_trans_ph_prepare(trans))
+               return;
+
+       elem = (struct switchdev_trans_item *) mem - 1;
+       kfree(elem);
+}
+
+/*************************************************************
+ * Flow, group, FDB, internal VLAN and neigh command prepares
+ *************************************************************/
+
+static int
+ofdpa_cmd_flow_tbl_add_ig_port(struct rocker_desc_info *desc_info,
+                              const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
+                              entry->key.ig_port.in_pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
+                              entry->key.ig_port.in_pport_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+                              entry->key.ig_port.goto_tbl))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_flow_tbl_add_vlan(struct rocker_desc_info *desc_info,
+                           const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
+                              entry->key.vlan.in_pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->key.vlan.vlan_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+                               entry->key.vlan.vlan_id_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+                              entry->key.vlan.goto_tbl))
+               return -EMSGSIZE;
+       if (entry->key.vlan.untagged &&
+           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_NEW_VLAN_ID,
+                               entry->key.vlan.new_vlan_id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_flow_tbl_add_term_mac(struct rocker_desc_info *desc_info,
+                               const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
+                              entry->key.term_mac.in_pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
+                              entry->key.term_mac.in_pport_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+                               entry->key.term_mac.eth_type))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+                          ETH_ALEN, entry->key.term_mac.eth_dst))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+                          ETH_ALEN, entry->key.term_mac.eth_dst_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->key.term_mac.vlan_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+                               entry->key.term_mac.vlan_id_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+                              entry->key.term_mac.goto_tbl))
+               return -EMSGSIZE;
+       if (entry->key.term_mac.copy_to_cpu &&
+           rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
+                             entry->key.term_mac.copy_to_cpu))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_flow_tbl_add_ucast_routing(struct rocker_desc_info *desc_info,
+                                    const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+                               entry->key.ucast_routing.eth_type))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP,
+                               entry->key.ucast_routing.dst4))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be32(desc_info, ROCKER_TLV_OF_DPA_DST_IP_MASK,
+                               entry->key.ucast_routing.dst4_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+                              entry->key.ucast_routing.goto_tbl))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+                              entry->key.ucast_routing.group_id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_flow_tbl_add_bridge(struct rocker_desc_info *desc_info,
+                             const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (entry->key.bridge.has_eth_dst &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+                          ETH_ALEN, entry->key.bridge.eth_dst))
+               return -EMSGSIZE;
+       if (entry->key.bridge.has_eth_dst_mask &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+                          ETH_ALEN, entry->key.bridge.eth_dst_mask))
+               return -EMSGSIZE;
+       if (entry->key.bridge.vlan_id &&
+           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->key.bridge.vlan_id))
+               return -EMSGSIZE;
+       if (entry->key.bridge.tunnel_id &&
+           rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_TUNNEL_ID,
+                              entry->key.bridge.tunnel_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GOTO_TABLE_ID,
+                              entry->key.bridge.goto_tbl))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+                              entry->key.bridge.group_id))
+               return -EMSGSIZE;
+       if (entry->key.bridge.copy_to_cpu &&
+           rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_COPY_CPU_ACTION,
+                             entry->key.bridge.copy_to_cpu))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_flow_tbl_add_acl(struct rocker_desc_info *desc_info,
+                          const struct ofdpa_flow_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT,
+                              entry->key.acl.in_pport))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_IN_PPORT_MASK,
+                              entry->key.acl.in_pport_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+                          ETH_ALEN, entry->key.acl.eth_src))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC_MASK,
+                          ETH_ALEN, entry->key.acl.eth_src_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+                          ETH_ALEN, entry->key.acl.eth_dst))
+               return -EMSGSIZE;
+       if (rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC_MASK,
+                          ETH_ALEN, entry->key.acl.eth_dst_mask))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_ETHERTYPE,
+                               entry->key.acl.eth_type))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->key.acl.vlan_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID_MASK,
+                               entry->key.acl.vlan_id_mask))
+               return -EMSGSIZE;
+
+       switch (ntohs(entry->key.acl.eth_type)) {
+       case ETH_P_IP:
+       case ETH_P_IPV6:
+               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_PROTO,
+                                     entry->key.acl.ip_proto))
+                       return -EMSGSIZE;
+               if (rocker_tlv_put_u8(desc_info,
+                                     ROCKER_TLV_OF_DPA_IP_PROTO_MASK,
+                                     entry->key.acl.ip_proto_mask))
+                       return -EMSGSIZE;
+               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_DSCP,
+                                     entry->key.acl.ip_tos & 0x3f))
+                       return -EMSGSIZE;
+               if (rocker_tlv_put_u8(desc_info,
+                                     ROCKER_TLV_OF_DPA_IP_DSCP_MASK,
+                                     entry->key.acl.ip_tos_mask & 0x3f))
+                       return -EMSGSIZE;
+               if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_IP_ECN,
+                                     (entry->key.acl.ip_tos & 0xc0) >> 6))
+                       return -EMSGSIZE;
+               if (rocker_tlv_put_u8(desc_info,
+                                     ROCKER_TLV_OF_DPA_IP_ECN_MASK,
+                                     (entry->key.acl.ip_tos_mask & 0xc0) >> 6))
+                       return -EMSGSIZE;
+               break;
+       }
+
+       if (entry->key.acl.group_id != ROCKER_GROUP_NONE &&
+           rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+                              entry->key.acl.group_id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int ofdpa_cmd_flow_tbl_add(const struct rocker_port *rocker_port,
+                                 struct rocker_desc_info *desc_info,
+                                 void *priv)
+{
+       const struct ofdpa_flow_tbl_entry *entry = priv;
+       struct rocker_tlv *cmd_info;
+       int err = 0;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_TABLE_ID,
+                              entry->key.tbl_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_PRIORITY,
+                              entry->key.priority))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_HARDTIME, 0))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
+                              entry->cookie))
+               return -EMSGSIZE;
+
+       switch (entry->key.tbl_id) {
+       case ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT:
+               err = ofdpa_cmd_flow_tbl_add_ig_port(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_TABLE_ID_VLAN:
+               err = ofdpa_cmd_flow_tbl_add_vlan(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC:
+               err = ofdpa_cmd_flow_tbl_add_term_mac(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING:
+               err = ofdpa_cmd_flow_tbl_add_ucast_routing(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_TABLE_ID_BRIDGING:
+               err = ofdpa_cmd_flow_tbl_add_bridge(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_TABLE_ID_ACL_POLICY:
+               err = ofdpa_cmd_flow_tbl_add_acl(desc_info, entry);
+               break;
+       default:
+               err = -ENOTSUPP;
+               break;
+       }
+
+       if (err)
+               return err;
+
+       rocker_tlv_nest_end(desc_info, cmd_info);
+
+       return 0;
+}
+
+static int ofdpa_cmd_flow_tbl_del(const struct rocker_port *rocker_port,
+                                 struct rocker_desc_info *desc_info,
+                                 void *priv)
+{
+       const struct ofdpa_flow_tbl_entry *entry = priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u64(desc_info, ROCKER_TLV_OF_DPA_COOKIE,
+                              entry->cookie))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_group_tbl_add_l2_interface(struct rocker_desc_info *desc_info,
+                                    struct ofdpa_group_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_OUT_PPORT,
+                              ROCKER_GROUP_PORT_GET(entry->group_id)))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_POP_VLAN,
+                             entry->l2_interface.pop_vlan))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_group_tbl_add_l2_rewrite(struct rocker_desc_info *desc_info,
+                                  const struct ofdpa_group_tbl_entry *entry)
+{
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
+                              entry->l2_rewrite.group_id))
+               return -EMSGSIZE;
+       if (!is_zero_ether_addr(entry->l2_rewrite.eth_src) &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+                          ETH_ALEN, entry->l2_rewrite.eth_src))
+               return -EMSGSIZE;
+       if (!is_zero_ether_addr(entry->l2_rewrite.eth_dst) &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+                          ETH_ALEN, entry->l2_rewrite.eth_dst))
+               return -EMSGSIZE;
+       if (entry->l2_rewrite.vlan_id &&
+           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->l2_rewrite.vlan_id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_group_tbl_add_group_ids(struct rocker_desc_info *desc_info,
+                                 const struct ofdpa_group_tbl_entry *entry)
+{
+       int i;
+       struct rocker_tlv *group_ids;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_OF_DPA_GROUP_COUNT,
+                              entry->group_count))
+               return -EMSGSIZE;
+
+       group_ids = rocker_tlv_nest_start(desc_info,
+                                         ROCKER_TLV_OF_DPA_GROUP_IDS);
+       if (!group_ids)
+               return -EMSGSIZE;
+
+       for (i = 0; i < entry->group_count; i++)
+               /* Note TLV array is 1-based */
+               if (rocker_tlv_put_u32(desc_info, i + 1, entry->group_ids[i]))
+                       return -EMSGSIZE;
+
+       rocker_tlv_nest_end(desc_info, group_ids);
+
+       return 0;
+}
+
+static int
+ofdpa_cmd_group_tbl_add_l3_unicast(struct rocker_desc_info *desc_info,
+                                  const struct ofdpa_group_tbl_entry *entry)
+{
+       if (!is_zero_ether_addr(entry->l3_unicast.eth_src) &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_SRC_MAC,
+                          ETH_ALEN, entry->l3_unicast.eth_src))
+               return -EMSGSIZE;
+       if (!is_zero_ether_addr(entry->l3_unicast.eth_dst) &&
+           rocker_tlv_put(desc_info, ROCKER_TLV_OF_DPA_DST_MAC,
+                          ETH_ALEN, entry->l3_unicast.eth_dst))
+               return -EMSGSIZE;
+       if (entry->l3_unicast.vlan_id &&
+           rocker_tlv_put_be16(desc_info, ROCKER_TLV_OF_DPA_VLAN_ID,
+                               entry->l3_unicast.vlan_id))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u8(desc_info, ROCKER_TLV_OF_DPA_TTL_CHECK,
+                             entry->l3_unicast.ttl_check))
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID_LOWER,
+                              entry->l3_unicast.group_id))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int ofdpa_cmd_group_tbl_add(const struct rocker_port *rocker_port,
+                                  struct rocker_desc_info *desc_info,
+                                  void *priv)
+{
+       struct ofdpa_group_tbl_entry *entry = priv;
+       struct rocker_tlv *cmd_info;
+       int err = 0;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+                              entry->group_id))
+               return -EMSGSIZE;
+
+       switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE:
+               err = ofdpa_cmd_group_tbl_add_l2_interface(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE:
+               err = ofdpa_cmd_group_tbl_add_l2_rewrite(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
+               err = ofdpa_cmd_group_tbl_add_group_ids(desc_info, entry);
+               break;
+       case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST:
+               err = ofdpa_cmd_group_tbl_add_l3_unicast(desc_info, entry);
+               break;
+       default:
+               err = -ENOTSUPP;
+               break;
+       }
+
+       if (err)
+               return err;
+
+       rocker_tlv_nest_end(desc_info, cmd_info);
+
+       return 0;
+}
+
+static int ofdpa_cmd_group_tbl_del(const struct rocker_port *rocker_port,
+                                  struct rocker_desc_info *desc_info,
+                                  void *priv)
+{
+       const struct ofdpa_group_tbl_entry *entry = priv;
+       struct rocker_tlv *cmd_info;
+
+       if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, entry->cmd))
+               return -EMSGSIZE;
+       cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+       if (!cmd_info)
+               return -EMSGSIZE;
+       if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_OF_DPA_GROUP_ID,
+                              entry->group_id))
+               return -EMSGSIZE;
+       rocker_tlv_nest_end(desc_info, cmd_info);
+
+       return 0;
+}
+
+/***************************************************
+ * Flow, group, FDB, internal VLAN and neigh tables
+ ***************************************************/
+
+static struct ofdpa_flow_tbl_entry *
+ofdpa_flow_tbl_find(const struct ofdpa *ofdpa,
+                   const struct ofdpa_flow_tbl_entry *match)
+{
+       struct ofdpa_flow_tbl_entry *found;
+       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
+
+       hash_for_each_possible(ofdpa->flow_tbl, found,
+                              entry, match->key_crc32) {
+               if (memcmp(&found->key, &match->key, key_len) == 0)
+                       return found;
+       }
+
+       return NULL;
+}
+
+static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port,
+                             struct switchdev_trans *trans, int flags,
+                             struct ofdpa_flow_tbl_entry *match)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_flow_tbl_entry *found;
+       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
+       unsigned long lock_flags;
+
+       match->key_crc32 = crc32(~0, &match->key, key_len);
+
+       spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
+
+       found = ofdpa_flow_tbl_find(ofdpa, match);
+
+       if (found) {
+               match->cookie = found->cookie;
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_del(&found->entry);
+               ofdpa_kfree(trans, found);
+               found = match;
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD;
+       } else {
+               found = match;
+               found->cookie = ofdpa->flow_tbl_next_cookie++;
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD;
+       }
+
+       if (!switchdev_trans_ph_prepare(trans))
+               hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32);
+
+       spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
+
+       if (!switchdev_trans_ph_prepare(trans))
+               return rocker_cmd_exec(ofdpa_port->rocker_port,
+                                      ofdpa_flags_nowait(flags),
+                                      ofdpa_cmd_flow_tbl_add,
+                                      found, NULL, NULL);
+       return 0;
+}
+
+static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port,
+                             struct switchdev_trans *trans, int flags,
+                             struct ofdpa_flow_tbl_entry *match)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_flow_tbl_entry *found;
+       size_t key_len = match->key_len ? match->key_len : sizeof(found->key);
+       unsigned long lock_flags;
+       int err = 0;
+
+       match->key_crc32 = crc32(~0, &match->key, key_len);
+
+       spin_lock_irqsave(&ofdpa->flow_tbl_lock, lock_flags);
+
+       found = ofdpa_flow_tbl_find(ofdpa, match);
+
+       if (found) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_del(&found->entry);
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL;
+       }
+
+       spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags);
+
+       ofdpa_kfree(trans, match);
+
+       if (found) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       err = rocker_cmd_exec(ofdpa_port->rocker_port,
+                                             ofdpa_flags_nowait(flags),
+                                             ofdpa_cmd_flow_tbl_del,
+                                             found, NULL, NULL);
+               ofdpa_kfree(trans, found);
+       }
+
+       return err;
+}
+
+static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port,
+                            struct switchdev_trans *trans, int flags,
+                            struct ofdpa_flow_tbl_entry *entry)
+{
+       if (flags & OFDPA_OP_FLAG_REMOVE)
+               return ofdpa_flow_tbl_del(ofdpa_port, trans, flags, entry);
+       else
+               return ofdpa_flow_tbl_add(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port,
+                                 struct switchdev_trans *trans, int flags,
+                                 u32 in_pport, u32 in_pport_mask,
+                                 enum rocker_of_dpa_table_id goto_tbl)
+{
+       struct ofdpa_flow_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->key.priority = OFDPA_PRIORITY_IG_PORT;
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_INGRESS_PORT;
+       entry->key.ig_port.in_pport = in_pport;
+       entry->key.ig_port.in_pport_mask = in_pport_mask;
+       entry->key.ig_port.goto_tbl = goto_tbl;
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port,
+                              struct switchdev_trans *trans, int flags,
+                              u32 in_pport, __be16 vlan_id,
+                              __be16 vlan_id_mask,
+                              enum rocker_of_dpa_table_id goto_tbl,
+                              bool untagged, __be16 new_vlan_id)
+{
+       struct ofdpa_flow_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->key.priority = OFDPA_PRIORITY_VLAN;
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_VLAN;
+       entry->key.vlan.in_pport = in_pport;
+       entry->key.vlan.vlan_id = vlan_id;
+       entry->key.vlan.vlan_id_mask = vlan_id_mask;
+       entry->key.vlan.goto_tbl = goto_tbl;
+
+       entry->key.vlan.untagged = untagged;
+       entry->key.vlan.new_vlan_id = new_vlan_id;
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port,
+                                  struct switchdev_trans *trans,
+                                  u32 in_pport, u32 in_pport_mask,
+                                  __be16 eth_type, const u8 *eth_dst,
+                                  const u8 *eth_dst_mask, __be16 vlan_id,
+                                  __be16 vlan_id_mask, bool copy_to_cpu,
+                                  int flags)
+{
+       struct ofdpa_flow_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       if (is_multicast_ether_addr(eth_dst)) {
+               entry->key.priority = OFDPA_PRIORITY_TERM_MAC_MCAST;
+               entry->key.term_mac.goto_tbl =
+                        ROCKER_OF_DPA_TABLE_ID_MULTICAST_ROUTING;
+       } else {
+               entry->key.priority = OFDPA_PRIORITY_TERM_MAC_UCAST;
+               entry->key.term_mac.goto_tbl =
+                        ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
+       }
+
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+       entry->key.term_mac.in_pport = in_pport;
+       entry->key.term_mac.in_pport_mask = in_pport_mask;
+       entry->key.term_mac.eth_type = eth_type;
+       ether_addr_copy(entry->key.term_mac.eth_dst, eth_dst);
+       ether_addr_copy(entry->key.term_mac.eth_dst_mask, eth_dst_mask);
+       entry->key.term_mac.vlan_id = vlan_id;
+       entry->key.term_mac.vlan_id_mask = vlan_id_mask;
+       entry->key.term_mac.copy_to_cpu = copy_to_cpu;
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port,
+                                struct switchdev_trans *trans, int flags,
+                                const u8 *eth_dst, const u8 *eth_dst_mask,
+                                __be16 vlan_id, u32 tunnel_id,
+                                enum rocker_of_dpa_table_id goto_tbl,
+                                u32 group_id, bool copy_to_cpu)
+{
+       struct ofdpa_flow_tbl_entry *entry;
+       u32 priority;
+       bool vlan_bridging = !!vlan_id;
+       bool dflt = !eth_dst || (eth_dst && eth_dst_mask);
+       bool wild = false;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_BRIDGING;
+
+       if (eth_dst) {
+               entry->key.bridge.has_eth_dst = 1;
+               ether_addr_copy(entry->key.bridge.eth_dst, eth_dst);
+       }
+       if (eth_dst_mask) {
+               entry->key.bridge.has_eth_dst_mask = 1;
+               ether_addr_copy(entry->key.bridge.eth_dst_mask, eth_dst_mask);
+               if (!ether_addr_equal(eth_dst_mask, ff_mac))
+                       wild = true;
+       }
+
+       priority = OFDPA_PRIORITY_UNKNOWN;
+       if (vlan_bridging && dflt && wild)
+               priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_WILD;
+       else if (vlan_bridging && dflt && !wild)
+               priority = OFDPA_PRIORITY_BRIDGING_VLAN_DFLT_EXACT;
+       else if (vlan_bridging && !dflt)
+               priority = OFDPA_PRIORITY_BRIDGING_VLAN;
+       else if (!vlan_bridging && dflt && wild)
+               priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_WILD;
+       else if (!vlan_bridging && dflt && !wild)
+               priority = OFDPA_PRIORITY_BRIDGING_TENANT_DFLT_EXACT;
+       else if (!vlan_bridging && !dflt)
+               priority = OFDPA_PRIORITY_BRIDGING_TENANT;
+
+       entry->key.priority = priority;
+       entry->key.bridge.vlan_id = vlan_id;
+       entry->key.bridge.tunnel_id = tunnel_id;
+       entry->key.bridge.goto_tbl = goto_tbl;
+       entry->key.bridge.group_id = group_id;
+       entry->key.bridge.copy_to_cpu = copy_to_cpu;
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port,
+                                        struct switchdev_trans *trans,
+                                        __be16 eth_type, __be32 dst,
+                                        __be32 dst_mask, u32 priority,
+                                        enum rocker_of_dpa_table_id goto_tbl,
+                                        u32 group_id, int flags)
+{
+       struct ofdpa_flow_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_UNICAST_ROUTING;
+       entry->key.priority = priority;
+       entry->key.ucast_routing.eth_type = eth_type;
+       entry->key.ucast_routing.dst4 = dst;
+       entry->key.ucast_routing.dst4_mask = dst_mask;
+       entry->key.ucast_routing.goto_tbl = goto_tbl;
+       entry->key.ucast_routing.group_id = group_id;
+       entry->key_len = offsetof(struct ofdpa_flow_tbl_key,
+                                 ucast_routing.group_id);
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port,
+                             struct switchdev_trans *trans, int flags,
+                             u32 in_pport, u32 in_pport_mask,
+                             const u8 *eth_src, const u8 *eth_src_mask,
+                             const u8 *eth_dst, const u8 *eth_dst_mask,
+                             __be16 eth_type, __be16 vlan_id,
+                             __be16 vlan_id_mask, u8 ip_proto,
+                             u8 ip_proto_mask, u8 ip_tos, u8 ip_tos_mask,
+                             u32 group_id)
+{
+       u32 priority;
+       struct ofdpa_flow_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       priority = OFDPA_PRIORITY_ACL_NORMAL;
+       if (eth_dst && eth_dst_mask) {
+               if (ether_addr_equal(eth_dst_mask, mcast_mac))
+                       priority = OFDPA_PRIORITY_ACL_DFLT;
+               else if (is_link_local_ether_addr(eth_dst))
+                       priority = OFDPA_PRIORITY_ACL_CTRL;
+       }
+
+       entry->key.priority = priority;
+       entry->key.tbl_id = ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+       entry->key.acl.in_pport = in_pport;
+       entry->key.acl.in_pport_mask = in_pport_mask;
+
+       if (eth_src)
+               ether_addr_copy(entry->key.acl.eth_src, eth_src);
+       if (eth_src_mask)
+               ether_addr_copy(entry->key.acl.eth_src_mask, eth_src_mask);
+       if (eth_dst)
+               ether_addr_copy(entry->key.acl.eth_dst, eth_dst);
+       if (eth_dst_mask)
+               ether_addr_copy(entry->key.acl.eth_dst_mask, eth_dst_mask);
+
+       entry->key.acl.eth_type = eth_type;
+       entry->key.acl.vlan_id = vlan_id;
+       entry->key.acl.vlan_id_mask = vlan_id_mask;
+       entry->key.acl.ip_proto = ip_proto;
+       entry->key.acl.ip_proto_mask = ip_proto_mask;
+       entry->key.acl.ip_tos = ip_tos;
+       entry->key.acl.ip_tos_mask = ip_tos_mask;
+       entry->key.acl.group_id = group_id;
+
+       return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static struct ofdpa_group_tbl_entry *
+ofdpa_group_tbl_find(const struct ofdpa *ofdpa,
+                    const struct ofdpa_group_tbl_entry *match)
+{
+       struct ofdpa_group_tbl_entry *found;
+
+       hash_for_each_possible(ofdpa->group_tbl, found,
+                              entry, match->group_id) {
+               if (found->group_id == match->group_id)
+                       return found;
+       }
+
+       return NULL;
+}
+
+static void ofdpa_group_tbl_entry_free(struct switchdev_trans *trans,
+                                      struct ofdpa_group_tbl_entry *entry)
+{
+       switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) {
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD:
+       case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST:
+               ofdpa_kfree(trans, entry->group_ids);
+               break;
+       default:
+               break;
+       }
+       ofdpa_kfree(trans, entry);
+}
+
+static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port,
+                              struct switchdev_trans *trans, int flags,
+                              struct ofdpa_group_tbl_entry *match)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_group_tbl_entry *found;
+       unsigned long lock_flags;
+
+       spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
+
+       found = ofdpa_group_tbl_find(ofdpa, match);
+
+       if (found) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_del(&found->entry);
+               ofdpa_group_tbl_entry_free(trans, found);
+               found = match;
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD;
+       } else {
+               found = match;
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD;
+       }
+
+       if (!switchdev_trans_ph_prepare(trans))
+               hash_add(ofdpa->group_tbl, &found->entry, found->group_id);
+
+       spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
+
+       if (!switchdev_trans_ph_prepare(trans))
+               return rocker_cmd_exec(ofdpa_port->rocker_port,
+                                      ofdpa_flags_nowait(flags),
+                                      ofdpa_cmd_group_tbl_add,
+                                      found, NULL, NULL);
+       return 0;
+}
+
+static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port,
+                              struct switchdev_trans *trans, int flags,
+                              struct ofdpa_group_tbl_entry *match)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_group_tbl_entry *found;
+       unsigned long lock_flags;
+       int err = 0;
+
+       spin_lock_irqsave(&ofdpa->group_tbl_lock, lock_flags);
+
+       found = ofdpa_group_tbl_find(ofdpa, match);
+
+       if (found) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_del(&found->entry);
+               found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL;
+       }
+
+       spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags);
+
+       ofdpa_group_tbl_entry_free(trans, match);
+
+       if (found) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       err = rocker_cmd_exec(ofdpa_port->rocker_port,
+                                             ofdpa_flags_nowait(flags),
+                                             ofdpa_cmd_group_tbl_del,
+                                             found, NULL, NULL);
+               ofdpa_group_tbl_entry_free(trans, found);
+       }
+
+       return err;
+}
+
+static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port,
+                             struct switchdev_trans *trans, int flags,
+                             struct ofdpa_group_tbl_entry *entry)
+{
+       if (flags & OFDPA_OP_FLAG_REMOVE)
+               return ofdpa_group_tbl_del(ofdpa_port, trans, flags, entry);
+       else
+               return ofdpa_group_tbl_add(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port,
+                                   struct switchdev_trans *trans, int flags,
+                                   __be16 vlan_id, u32 out_pport,
+                                   int pop_vlan)
+{
+       struct ofdpa_group_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
+       entry->l2_interface.pop_vlan = pop_vlan;
+
+       return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port,
+                                 struct switchdev_trans *trans,
+                                 int flags, u8 group_count,
+                                 const u32 *group_ids, u32 group_id)
+{
+       struct ofdpa_group_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->group_id = group_id;
+       entry->group_count = group_count;
+
+       entry->group_ids = ofdpa_kcalloc(trans, flags,
+                                        group_count, sizeof(u32));
+       if (!entry->group_ids) {
+               ofdpa_kfree(trans, entry);
+               return -ENOMEM;
+       }
+       memcpy(entry->group_ids, group_ids, group_count * sizeof(u32));
+
+       return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port,
+                               struct switchdev_trans *trans, int flags,
+                               __be16 vlan_id, u8 group_count,
+                               const u32 *group_ids, u32 group_id)
+{
+       return ofdpa_group_l2_fan_out(ofdpa_port, trans, flags,
+                                     group_count, group_ids,
+                                     group_id);
+}
+
+static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port,
+                                 struct switchdev_trans *trans, int flags,
+                                 u32 index, const u8 *src_mac, const u8 *dst_mac,
+                                 __be16 vlan_id, bool ttl_check, u32 pport)
+{
+       struct ofdpa_group_tbl_entry *entry;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       entry->group_id = ROCKER_GROUP_L3_UNICAST(index);
+       if (src_mac)
+               ether_addr_copy(entry->l3_unicast.eth_src, src_mac);
+       if (dst_mac)
+               ether_addr_copy(entry->l3_unicast.eth_dst, dst_mac);
+       entry->l3_unicast.vlan_id = vlan_id;
+       entry->l3_unicast.ttl_check = ttl_check;
+       entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport);
+
+       return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry);
+}
+
+static struct ofdpa_neigh_tbl_entry *
+ofdpa_neigh_tbl_find(const struct ofdpa *ofdpa, __be32 ip_addr)
+{
+       struct ofdpa_neigh_tbl_entry *found;
+
+       hash_for_each_possible(ofdpa->neigh_tbl, found,
+                              entry, be32_to_cpu(ip_addr))
+               if (found->ip_addr == ip_addr)
+                       return found;
+
+       return NULL;
+}
+
+static void ofdpa_neigh_add(struct ofdpa *ofdpa,
+                           struct switchdev_trans *trans,
+                           struct ofdpa_neigh_tbl_entry *entry)
+{
+       if (!switchdev_trans_ph_commit(trans))
+               entry->index = ofdpa->neigh_tbl_next_index++;
+       if (switchdev_trans_ph_prepare(trans))
+               return;
+       entry->ref_count++;
+       hash_add(ofdpa->neigh_tbl, &entry->entry,
+                be32_to_cpu(entry->ip_addr));
+}
+
+static void ofdpa_neigh_del(struct switchdev_trans *trans,
+                           struct ofdpa_neigh_tbl_entry *entry)
+{
+       if (switchdev_trans_ph_prepare(trans))
+               return;
+       if (--entry->ref_count == 0) {
+               hash_del(&entry->entry);
+               ofdpa_kfree(trans, entry);
+       }
+}
+
+static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry,
+                              struct switchdev_trans *trans,
+                              const u8 *eth_dst, bool ttl_check)
+{
+       if (eth_dst) {
+               ether_addr_copy(entry->eth_dst, eth_dst);
+               entry->ttl_check = ttl_check;
+       } else if (!switchdev_trans_ph_prepare(trans)) {
+               entry->ref_count++;
+       }
+}
+
+static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port,
+                                struct switchdev_trans *trans,
+                                int flags, __be32 ip_addr, const u8 *eth_dst)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_neigh_tbl_entry *entry;
+       struct ofdpa_neigh_tbl_entry *found;
+       unsigned long lock_flags;
+       __be16 eth_type = htons(ETH_P_IP);
+       enum rocker_of_dpa_table_id goto_tbl =
+                       ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+       u32 group_id;
+       u32 priority = 0;
+       bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
+       bool updating;
+       bool removing;
+       int err = 0;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
+
+       found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
+
+       updating = found && adding;
+       removing = found && !adding;
+       adding = !found && adding;
+
+       if (adding) {
+               entry->ip_addr = ip_addr;
+               entry->dev = ofdpa_port->dev;
+               ether_addr_copy(entry->eth_dst, eth_dst);
+               entry->ttl_check = true;
+               ofdpa_neigh_add(ofdpa, trans, entry);
+       } else if (removing) {
+               memcpy(entry, found, sizeof(*entry));
+               ofdpa_neigh_del(trans, found);
+       } else if (updating) {
+               ofdpa_neigh_update(found, trans, eth_dst, true);
+               memcpy(entry, found, sizeof(*entry));
+       } else {
+               err = -ENOENT;
+       }
+
+       spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
+
+       if (err)
+               goto err_out;
+
+       /* For each active neighbor, we have an L3 unicast group and
+        * a /32 route to the neighbor, which uses the L3 unicast
+        * group.  The L3 unicast group can also be referred to by
+        * other routes' nexthops.
+        */
+
+       err = ofdpa_group_l3_unicast(ofdpa_port, trans, flags,
+                                    entry->index,
+                                    ofdpa_port->dev->dev_addr,
+                                    entry->eth_dst,
+                                    ofdpa_port->internal_vlan_id,
+                                    entry->ttl_check,
+                                    ofdpa_port->pport);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "Error (%d) L3 unicast group index %d\n",
+                          err, entry->index);
+               goto err_out;
+       }
+
+       if (adding || removing) {
+               group_id = ROCKER_GROUP_L3_UNICAST(entry->index);
+               err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans,
+                                                   eth_type, ip_addr,
+                                                   inet_make_mask(32),
+                                                   priority, goto_tbl,
+                                                   group_id, flags);
+
+               if (err)
+                       netdev_err(ofdpa_port->dev, "Error (%d) /32 unicast route %pI4 group 0x%08x\n",
+                                  err, &entry->ip_addr, group_id);
+       }
+
+err_out:
+       if (!adding)
+               ofdpa_kfree(trans, entry);
+
+       return err;
+}
+
+static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port,
+                                  struct switchdev_trans *trans,
+                                  __be32 ip_addr)
+{
+       struct net_device *dev = ofdpa_port->dev;
+       struct neighbour *n = __ipv4_neigh_lookup(dev, (__force u32)ip_addr);
+       int err = 0;
+
+       if (!n) {
+               n = neigh_create(&arp_tbl, &ip_addr, dev);
+               if (IS_ERR(n))
+                       return PTR_ERR(n);
+       }
+
+       /* If the neigh is already resolved, then go ahead and
+        * install the entry, otherwise start the ARP process to
+        * resolve the neigh.
+        */
+
+       if (n->nud_state & NUD_VALID)
+               err = ofdpa_port_ipv4_neigh(ofdpa_port, trans, 0,
+                                           ip_addr, n->ha);
+       else
+               neigh_event_send(n, NULL);
+
+       neigh_release(n);
+       return err;
+}
+
+static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port,
+                             struct switchdev_trans *trans, int flags,
+                             __be32 ip_addr, u32 *index)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_neigh_tbl_entry *entry;
+       struct ofdpa_neigh_tbl_entry *found;
+       unsigned long lock_flags;
+       bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
+       bool updating;
+       bool removing;
+       bool resolved = true;
+       int err = 0;
+
+       entry = ofdpa_kzalloc(trans, flags, sizeof(*entry));
+       if (!entry)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&ofdpa->neigh_tbl_lock, lock_flags);
+
+       found = ofdpa_neigh_tbl_find(ofdpa, ip_addr);
+       if (found)
+               *index = found->index;
+
+       updating = found && adding;
+       removing = found && !adding;
+       adding = !found && adding;
+
+       if (adding) {
+               entry->ip_addr = ip_addr;
+               entry->dev = ofdpa_port->dev;
+               ofdpa_neigh_add(ofdpa, trans, entry);
+               *index = entry->index;
+               resolved = false;
+       } else if (removing) {
+               ofdpa_neigh_del(trans, found);
+       } else if (updating) {
+               ofdpa_neigh_update(found, trans, NULL, false);
+               resolved = !is_zero_ether_addr(found->eth_dst);
+       } else {
+               err = -ENOENT;
+       }
+
+       spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags);
+
+       if (!adding)
+               ofdpa_kfree(trans, entry);
+
+       if (err)
+               return err;
+
+       /* Resolved means neigh ip_addr is resolved to neigh mac. */
+
+       if (!resolved)
+               err = ofdpa_port_ipv4_resolve(ofdpa_port, trans, ip_addr);
+
+       return err;
+}
+
+static struct ofdpa_port *ofdpa_port_get(const struct ofdpa *ofdpa,
+                                        int port_index)
+{
+       struct rocker_port *rocker_port;
+
+       rocker_port = ofdpa->rocker->ports[port_index];
+       return rocker_port ? rocker_port->wpriv : NULL;
+}
+
+static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port,
+                                      struct switchdev_trans *trans,
+                                      int flags, __be16 vlan_id)
+{
+       struct ofdpa_port *p;
+       const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       unsigned int port_count = ofdpa->rocker->port_count;
+       u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
+       u32 *group_ids;
+       u8 group_count = 0;
+       int err = 0;
+       int i;
+
+       group_ids = ofdpa_kcalloc(trans, flags, port_count, sizeof(u32));
+       if (!group_ids)
+               return -ENOMEM;
+
+       /* Adjust the flood group for this VLAN.  The flood group
+        * references an L2 interface group for each port in this
+        * VLAN.
+        */
+
+       for (i = 0; i < port_count; i++) {
+               p = ofdpa_port_get(ofdpa, i);
+               if (!p)
+                       continue;
+               if (!ofdpa_port_is_bridged(p))
+                       continue;
+               if (test_bit(ntohs(vlan_id), p->vlan_bitmap)) {
+                       group_ids[group_count++] =
+                               ROCKER_GROUP_L2_INTERFACE(vlan_id, p->pport);
+               }
+       }
+
+       /* If there are no bridged ports in this VLAN, we're done */
+       if (group_count == 0)
+               goto no_ports_in_vlan;
+
+       err = ofdpa_group_l2_flood(ofdpa_port, trans, flags, vlan_id,
+                                  group_count, group_ids, group_id);
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
+
+no_ports_in_vlan:
+       ofdpa_kfree(trans, group_ids);
+       return err;
+}
+
+static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port,
+                                    struct switchdev_trans *trans, int flags,
+                                    __be16 vlan_id, bool pop_vlan)
+{
+       const struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       unsigned int port_count = ofdpa->rocker->port_count;
+       struct ofdpa_port *p;
+       bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
+       u32 out_pport;
+       int ref = 0;
+       int err;
+       int i;
+
+       /* An L2 interface group for this port in this VLAN, but
+        * only when port STP state is LEARNING|FORWARDING.
+        */
+
+       if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
+           ofdpa_port->stp_state == BR_STATE_FORWARDING) {
+               out_pport = ofdpa_port->pport;
+               err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
+                                              vlan_id, out_pport, pop_vlan);
+               if (err) {
+                       netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
+                                  err, out_pport);
+                       return err;
+               }
+       }
+
+       /* An L2 interface group for this VLAN to CPU port.
+        * Add when first port joins this VLAN and destroy when
+        * last port leaves this VLAN.
+        */
+
+       for (i = 0; i < port_count; i++) {
+               p = ofdpa_port_get(ofdpa, i);
+               if (p && test_bit(ntohs(vlan_id), p->vlan_bitmap))
+                       ref++;
+       }
+
+       if ((!adding || ref != 1) && (adding || ref != 0))
+               return 0;
+
+       out_pport = 0;
+       err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
+                                      vlan_id, out_pport, pop_vlan);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static struct ofdpa_ctrl {
+       const u8 *eth_dst;
+       const u8 *eth_dst_mask;
+       __be16 eth_type;
+       bool acl;
+       bool bridge;
+       bool term;
+       bool copy_to_cpu;
+} ofdpa_ctrls[] = {
+       [OFDPA_CTRL_LINK_LOCAL_MCAST] = {
+               /* pass link local multicast pkts up to CPU for filtering */
+               .eth_dst = ll_mac,
+               .eth_dst_mask = ll_mask,
+               .acl = true,
+       },
+       [OFDPA_CTRL_LOCAL_ARP] = {
+               /* pass local ARP pkts up to CPU */
+               .eth_dst = zero_mac,
+               .eth_dst_mask = zero_mac,
+               .eth_type = htons(ETH_P_ARP),
+               .acl = true,
+       },
+       [OFDPA_CTRL_IPV4_MCAST] = {
+               /* pass IPv4 mcast pkts up to CPU, RFC 1112 */
+               .eth_dst = ipv4_mcast,
+               .eth_dst_mask = ipv4_mask,
+               .eth_type = htons(ETH_P_IP),
+               .term  = true,
+               .copy_to_cpu = true,
+       },
+       [OFDPA_CTRL_IPV6_MCAST] = {
+               /* pass IPv6 mcast pkts up to CPU, RFC 2464 */
+               .eth_dst = ipv6_mcast,
+               .eth_dst_mask = ipv6_mask,
+               .eth_type = htons(ETH_P_IPV6),
+               .term  = true,
+               .copy_to_cpu = true,
+       },
+       [OFDPA_CTRL_DFLT_BRIDGING] = {
+               /* flood any pkts on vlan */
+               .bridge = true,
+               .copy_to_cpu = true,
+       },
+       [OFDPA_CTRL_DFLT_OVS] = {
+               /* pass all pkts up to CPU */
+               .eth_dst = zero_mac,
+               .eth_dst_mask = zero_mac,
+               .acl = true,
+       },
+};
+
+static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port,
+                                   struct switchdev_trans *trans, int flags,
+                                   const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
+{
+       u32 in_pport = ofdpa_port->pport;
+       u32 in_pport_mask = 0xffffffff;
+       u32 out_pport = 0;
+       const u8 *eth_src = NULL;
+       const u8 *eth_src_mask = NULL;
+       __be16 vlan_id_mask = htons(0xffff);
+       u8 ip_proto = 0;
+       u8 ip_proto_mask = 0;
+       u8 ip_tos = 0;
+       u8 ip_tos_mask = 0;
+       u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
+       int err;
+
+       err = ofdpa_flow_tbl_acl(ofdpa_port, trans, flags,
+                                in_pport, in_pport_mask,
+                                eth_src, eth_src_mask,
+                                ctrl->eth_dst, ctrl->eth_dst_mask,
+                                ctrl->eth_type,
+                                vlan_id, vlan_id_mask,
+                                ip_proto, ip_proto_mask,
+                                ip_tos, ip_tos_mask,
+                                group_id);
+
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) ctrl ACL\n", err);
+
+       return err;
+}
+
+static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port,
+                                      struct switchdev_trans *trans,
+                                      int flags,
+                                      const struct ofdpa_ctrl *ctrl,
+                                      __be16 vlan_id)
+{
+       enum rocker_of_dpa_table_id goto_tbl =
+                       ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+       u32 group_id = ROCKER_GROUP_L2_FLOOD(vlan_id, 0);
+       u32 tunnel_id = 0;
+       int err;
+
+       if (!ofdpa_port_is_bridged(ofdpa_port))
+               return 0;
+
+       err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags,
+                                   ctrl->eth_dst, ctrl->eth_dst_mask,
+                                   vlan_id, tunnel_id,
+                                   goto_tbl, group_id, ctrl->copy_to_cpu);
+
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) ctrl FLOOD\n", err);
+
+       return err;
+}
+
+static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port,
+                                    struct switchdev_trans *trans, int flags,
+                                    const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
+{
+       u32 in_pport_mask = 0xffffffff;
+       __be16 vlan_id_mask = htons(0xffff);
+       int err;
+
+       if (ntohs(vlan_id) == 0)
+               vlan_id = ofdpa_port->internal_vlan_id;
+
+       err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
+                                     ofdpa_port->pport, in_pport_mask,
+                                     ctrl->eth_type, ctrl->eth_dst,
+                                     ctrl->eth_dst_mask, vlan_id,
+                                     vlan_id_mask, ctrl->copy_to_cpu,
+                                     flags);
+
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) ctrl term\n", err);
+
+       return err;
+}
+
+static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port,
+                               struct switchdev_trans *trans, int flags,
+                               const struct ofdpa_ctrl *ctrl, __be16 vlan_id)
+{
+       if (ctrl->acl)
+               return ofdpa_port_ctrl_vlan_acl(ofdpa_port, trans, flags,
+                                               ctrl, vlan_id);
+       if (ctrl->bridge)
+               return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, trans, flags,
+                                                  ctrl, vlan_id);
+
+       if (ctrl->term)
+               return ofdpa_port_ctrl_vlan_term(ofdpa_port, trans, flags,
+                                                ctrl, vlan_id);
+
+       return -EOPNOTSUPP;
+}
+
+static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port,
+                                   struct switchdev_trans *trans, int flags,
+                                   __be16 vlan_id)
+{
+       int err = 0;
+       int i;
+
+       for (i = 0; i < OFDPA_CTRL_MAX; i++) {
+               if (ofdpa_port->ctrls[i]) {
+                       err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags,
+                                                  &ofdpa_ctrls[i], vlan_id);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return err;
+}
+
+static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port,
+                          struct switchdev_trans *trans, int flags,
+                          const struct ofdpa_ctrl *ctrl)
+{
+       u16 vid;
+       int err = 0;
+
+       for (vid = 1; vid < VLAN_N_VID; vid++) {
+               if (!test_bit(vid, ofdpa_port->vlan_bitmap))
+                       continue;
+               err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags,
+                                          ctrl, htons(vid));
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port,
+                          struct switchdev_trans *trans, int flags, u16 vid)
+{
+       enum rocker_of_dpa_table_id goto_tbl =
+                       ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC;
+       u32 in_pport = ofdpa_port->pport;
+       __be16 vlan_id = htons(vid);
+       __be16 vlan_id_mask = htons(0xffff);
+       __be16 internal_vlan_id;
+       bool untagged;
+       bool adding = !(flags & OFDPA_OP_FLAG_REMOVE);
+       int err;
+
+       internal_vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, &untagged);
+
+       if (adding &&
+           test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
+               return 0; /* already added */
+       else if (!adding &&
+                !test_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap))
+               return 0; /* already removed */
+
+       change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
+
+       if (adding) {
+               err = ofdpa_port_ctrl_vlan_add(ofdpa_port, trans, flags,
+                                              internal_vlan_id);
+               if (err) {
+                       netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err);
+                       goto err_out;
+               }
+       }
+
+       err = ofdpa_port_vlan_l2_groups(ofdpa_port, trans, flags,
+                                       internal_vlan_id, untagged);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err);
+               goto err_out;
+       }
+
+       err = ofdpa_port_vlan_flood_group(ofdpa_port, trans, flags,
+                                         internal_vlan_id);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err);
+               goto err_out;
+       }
+
+       err = ofdpa_flow_tbl_vlan(ofdpa_port, trans, flags,
+                                 in_pport, vlan_id, vlan_id_mask,
+                                 goto_tbl, untagged, internal_vlan_id);
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err);
+
+err_out:
+       if (switchdev_trans_ph_prepare(trans))
+               change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap);
+
+       return err;
+}
+
+static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port,
+                            struct switchdev_trans *trans, int flags)
+{
+       enum rocker_of_dpa_table_id goto_tbl;
+       u32 in_pport;
+       u32 in_pport_mask;
+       int err;
+
+       /* Normal Ethernet Frames.  Matches pkts from any local physical
+        * ports.  Goto VLAN tbl.
+        */
+
+       in_pport = 0;
+       in_pport_mask = 0xffff0000;
+       goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN;
+
+       err = ofdpa_flow_tbl_ig_port(ofdpa_port, trans, flags,
+                                    in_pport, in_pport_mask,
+                                    goto_tbl);
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) ingress port table entry\n", err);
+
+       return err;
+}
+
+struct ofdpa_fdb_learn_work {
+       struct work_struct work;
+       struct ofdpa_port *ofdpa_port;
+       struct switchdev_trans *trans;
+       int flags;
+       u8 addr[ETH_ALEN];
+       u16 vid;
+};
+
+static void ofdpa_port_fdb_learn_work(struct work_struct *work)
+{
+       const struct ofdpa_fdb_learn_work *lw =
+               container_of(work, struct ofdpa_fdb_learn_work, work);
+       bool removing = (lw->flags & OFDPA_OP_FLAG_REMOVE);
+       bool learned = (lw->flags & OFDPA_OP_FLAG_LEARNED);
+       struct switchdev_notifier_fdb_info info;
+
+       info.addr = lw->addr;
+       info.vid = lw->vid;
+
+       rtnl_lock();
+       if (learned && removing)
+               call_switchdev_notifiers(SWITCHDEV_FDB_DEL,
+                                        lw->ofdpa_port->dev, &info.info);
+       else if (learned && !removing)
+               call_switchdev_notifiers(SWITCHDEV_FDB_ADD,
+                                        lw->ofdpa_port->dev, &info.info);
+       rtnl_unlock();
+
+       ofdpa_kfree(lw->trans, work);
+}
+
+static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port,
+                               struct switchdev_trans *trans, int flags,
+                               const u8 *addr, __be16 vlan_id)
+{
+       struct ofdpa_fdb_learn_work *lw;
+       enum rocker_of_dpa_table_id goto_tbl =
+                       ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+       u32 out_pport = ofdpa_port->pport;
+       u32 tunnel_id = 0;
+       u32 group_id = ROCKER_GROUP_NONE;
+       bool syncing = !!(ofdpa_port->brport_flags & BR_LEARNING_SYNC);
+       bool copy_to_cpu = false;
+       int err;
+
+       if (ofdpa_port_is_bridged(ofdpa_port))
+               group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport);
+
+       if (!(flags & OFDPA_OP_FLAG_REFRESH)) {
+               err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, addr,
+                                           NULL, vlan_id, tunnel_id, goto_tbl,
+                                           group_id, copy_to_cpu);
+               if (err)
+                       return err;
+       }
+
+       if (!syncing)
+               return 0;
+
+       if (!ofdpa_port_is_bridged(ofdpa_port))
+               return 0;
+
+       lw = ofdpa_kzalloc(trans, flags, sizeof(*lw));
+       if (!lw)
+               return -ENOMEM;
+
+       INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work);
+
+       lw->ofdpa_port = ofdpa_port;
+       lw->trans = trans;
+       lw->flags = flags;
+       ether_addr_copy(lw->addr, addr);
+       lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id);
+
+       if (switchdev_trans_ph_prepare(trans))
+               ofdpa_kfree(trans, lw);
+       else
+               schedule_work(&lw->work);
+
+       return 0;
+}
+
+static struct ofdpa_fdb_tbl_entry *
+ofdpa_fdb_tbl_find(const struct ofdpa *ofdpa,
+                  const struct ofdpa_fdb_tbl_entry *match)
+{
+       struct ofdpa_fdb_tbl_entry *found;
+
+       hash_for_each_possible(ofdpa->fdb_tbl, found, entry, match->key_crc32)
+               if (memcmp(&found->key, &match->key, sizeof(found->key)) == 0)
+                       return found;
+
+       return NULL;
+}
+
+static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port,
+                         struct switchdev_trans *trans,
+                         const unsigned char *addr,
+                         __be16 vlan_id, int flags)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_fdb_tbl_entry *fdb;
+       struct ofdpa_fdb_tbl_entry *found;
+       bool removing = (flags & OFDPA_OP_FLAG_REMOVE);
+       unsigned long lock_flags;
+
+       fdb = ofdpa_kzalloc(trans, flags, sizeof(*fdb));
+       if (!fdb)
+               return -ENOMEM;
+
+       fdb->learned = (flags & OFDPA_OP_FLAG_LEARNED);
+       fdb->touched = jiffies;
+       fdb->key.ofdpa_port = ofdpa_port;
+       ether_addr_copy(fdb->key.addr, addr);
+       fdb->key.vlan_id = vlan_id;
+       fdb->key_crc32 = crc32(~0, &fdb->key, sizeof(fdb->key));
+
+       spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       found = ofdpa_fdb_tbl_find(ofdpa, fdb);
+
+       if (found) {
+               found->touched = jiffies;
+               if (removing) {
+                       ofdpa_kfree(trans, fdb);
+                       if (!switchdev_trans_ph_prepare(trans))
+                               hash_del(&found->entry);
+               }
+       } else if (!removing) {
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_add(ofdpa->fdb_tbl, &fdb->entry,
+                                fdb->key_crc32);
+       }
+
+       spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       /* Check if adding and already exists, or removing and can't find */
+       if (!found != !removing) {
+               ofdpa_kfree(trans, fdb);
+               if (!found && removing)
+                       return 0;
+               /* Refreshing existing to update aging timers */
+               flags |= OFDPA_OP_FLAG_REFRESH;
+       }
+
+       return ofdpa_port_fdb_learn(ofdpa_port, trans, flags, addr, vlan_id);
+}
+
+static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port,
+                               struct switchdev_trans *trans, int flags)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_fdb_tbl_entry *found;
+       unsigned long lock_flags;
+       struct hlist_node *tmp;
+       int bkt;
+       int err = 0;
+
+       if (ofdpa_port->stp_state == BR_STATE_LEARNING ||
+           ofdpa_port->stp_state == BR_STATE_FORWARDING)
+               return 0;
+
+       flags |= OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE;
+
+       spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) {
+               if (found->key.ofdpa_port != ofdpa_port)
+                       continue;
+               if (!found->learned)
+                       continue;
+               err = ofdpa_port_fdb_learn(ofdpa_port, trans, flags,
+                                          found->key.addr,
+                                          found->key.vlan_id);
+               if (err)
+                       goto err_out;
+               if (!switchdev_trans_ph_prepare(trans))
+                       hash_del(&found->entry);
+       }
+
+err_out:
+       spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       return err;
+}
+
+static void ofdpa_fdb_cleanup(unsigned long data)
+{
+       struct ofdpa *ofdpa = (struct ofdpa *)data;
+       struct ofdpa_port *ofdpa_port;
+       struct ofdpa_fdb_tbl_entry *entry;
+       struct hlist_node *tmp;
+       unsigned long next_timer = jiffies + ofdpa->ageing_time;
+       unsigned long expires;
+       unsigned long lock_flags;
+       int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_REMOVE |
+                   OFDPA_OP_FLAG_LEARNED;
+       int bkt;
+
+       spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, entry, entry) {
+               if (!entry->learned)
+                       continue;
+               ofdpa_port = entry->key.ofdpa_port;
+               expires = entry->touched + ofdpa_port->ageing_time;
+               if (time_before_eq(expires, jiffies)) {
+                       ofdpa_port_fdb_learn(ofdpa_port, NULL,
+                                            flags, entry->key.addr,
+                                            entry->key.vlan_id);
+                       hash_del(&entry->entry);
+               } else if (time_before(expires, next_timer)) {
+                       next_timer = expires;
+               }
+       }
+
+       spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       mod_timer(&ofdpa->fdb_cleanup_timer, round_jiffies_up(next_timer));
+}
+
+static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port,
+                                struct switchdev_trans *trans, int flags,
+                                __be16 vlan_id)
+{
+       u32 in_pport_mask = 0xffffffff;
+       __be16 eth_type;
+       const u8 *dst_mac_mask = ff_mac;
+       __be16 vlan_id_mask = htons(0xffff);
+       bool copy_to_cpu = false;
+       int err;
+
+       if (ntohs(vlan_id) == 0)
+               vlan_id = ofdpa_port->internal_vlan_id;
+
+       eth_type = htons(ETH_P_IP);
+       err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
+                                     ofdpa_port->pport, in_pport_mask,
+                                     eth_type, ofdpa_port->dev->dev_addr,
+                                     dst_mac_mask, vlan_id, vlan_id_mask,
+                                     copy_to_cpu, flags);
+       if (err)
+               return err;
+
+       eth_type = htons(ETH_P_IPV6);
+       err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans,
+                                     ofdpa_port->pport, in_pport_mask,
+                                     eth_type, ofdpa_port->dev->dev_addr,
+                                     dst_mac_mask, vlan_id, vlan_id_mask,
+                                     copy_to_cpu, flags);
+
+       return err;
+}
+
+static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port,
+                            struct switchdev_trans *trans, int flags)
+{
+       bool pop_vlan;
+       u32 out_pport;
+       __be16 vlan_id;
+       u16 vid;
+       int err;
+
+       /* Port will be forwarding-enabled if its STP state is LEARNING
+        * or FORWARDING.  Traffic from CPU can still egress, regardless of
+        * port STP state.  Use L2 interface group on port VLANs as a way
+        * to toggle port forwarding: if forwarding is disabled, L2
+        * interface group will not exist.
+        */
+
+       if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
+           ofdpa_port->stp_state != BR_STATE_FORWARDING)
+               flags |= OFDPA_OP_FLAG_REMOVE;
+
+       out_pport = ofdpa_port->pport;
+       for (vid = 1; vid < VLAN_N_VID; vid++) {
+               if (!test_bit(vid, ofdpa_port->vlan_bitmap))
+                       continue;
+               vlan_id = htons(vid);
+               pop_vlan = ofdpa_vlan_id_is_internal(vlan_id);
+               err = ofdpa_group_l2_interface(ofdpa_port, trans, flags,
+                                              vlan_id, out_pport, pop_vlan);
+               if (err) {
+                       netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n",
+                                  err, out_pport);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port,
+                                struct switchdev_trans *trans,
+                                int flags, u8 state)
+{
+       bool want[OFDPA_CTRL_MAX] = { 0, };
+       bool prev_ctrls[OFDPA_CTRL_MAX];
+       u8 uninitialized_var(prev_state);
+       int err;
+       int i;
+
+       if (switchdev_trans_ph_prepare(trans)) {
+               memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls));
+               prev_state = ofdpa_port->stp_state;
+       }
+
+       if (ofdpa_port->stp_state == state)
+               return 0;
+
+       ofdpa_port->stp_state = state;
+
+       switch (state) {
+       case BR_STATE_DISABLED:
+               /* port is completely disabled */
+               break;
+       case BR_STATE_LISTENING:
+       case BR_STATE_BLOCKING:
+               want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
+               break;
+       case BR_STATE_LEARNING:
+       case BR_STATE_FORWARDING:
+               if (!ofdpa_port_is_ovsed(ofdpa_port))
+                       want[OFDPA_CTRL_LINK_LOCAL_MCAST] = true;
+               want[OFDPA_CTRL_IPV4_MCAST] = true;
+               want[OFDPA_CTRL_IPV6_MCAST] = true;
+               if (ofdpa_port_is_bridged(ofdpa_port))
+                       want[OFDPA_CTRL_DFLT_BRIDGING] = true;
+               else if (ofdpa_port_is_ovsed(ofdpa_port))
+                       want[OFDPA_CTRL_DFLT_OVS] = true;
+               else
+                       want[OFDPA_CTRL_LOCAL_ARP] = true;
+               break;
+       }
+
+       for (i = 0; i < OFDPA_CTRL_MAX; i++) {
+               if (want[i] != ofdpa_port->ctrls[i]) {
+                       int ctrl_flags = flags |
+                                        (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE);
+                       err = ofdpa_port_ctrl(ofdpa_port, trans, ctrl_flags,
+                                             &ofdpa_ctrls[i]);
+                       if (err)
+                               goto err_out;
+                       ofdpa_port->ctrls[i] = want[i];
+               }
+       }
+
+       err = ofdpa_port_fdb_flush(ofdpa_port, trans, flags);
+       if (err)
+               goto err_out;
+
+       err = ofdpa_port_fwding(ofdpa_port, trans, flags);
+
+err_out:
+       if (switchdev_trans_ph_prepare(trans)) {
+               memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls));
+               ofdpa_port->stp_state = prev_state;
+       }
+
+       return err;
+}
+
+static int ofdpa_port_fwd_enable(struct ofdpa_port *ofdpa_port, int flags)
+{
+       if (ofdpa_port_is_bridged(ofdpa_port))
+               /* bridge STP will enable port */
+               return 0;
+
+       /* port is not bridged, so simulate going to FORWARDING state */
+       return ofdpa_port_stp_update(ofdpa_port, NULL, flags,
+                                    BR_STATE_FORWARDING);
+}
+
+static int ofdpa_port_fwd_disable(struct ofdpa_port *ofdpa_port, int flags)
+{
+       if (ofdpa_port_is_bridged(ofdpa_port))
+               /* bridge STP will disable port */
+               return 0;
+
+       /* port is not bridged, so simulate going to DISABLED state */
+       return ofdpa_port_stp_update(ofdpa_port, NULL, flags,
+                                    BR_STATE_DISABLED);
+}
+
+static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port,
+                              struct switchdev_trans *trans,
+                              u16 vid, u16 flags)
+{
+       int err;
+
+       /* XXX deal with flags for PVID and untagged */
+
+       err = ofdpa_port_vlan(ofdpa_port, trans, 0, vid);
+       if (err)
+               return err;
+
+       err = ofdpa_port_router_mac(ofdpa_port, trans, 0, htons(vid));
+       if (err)
+               ofdpa_port_vlan(ofdpa_port, trans,
+                               OFDPA_OP_FLAG_REMOVE, vid);
+
+       return err;
+}
+
+static int ofdpa_port_vlan_del(struct ofdpa_port *ofdpa_port,
+                              u16 vid, u16 flags)
+{
+       int err;
+
+       err = ofdpa_port_router_mac(ofdpa_port, NULL,
+                                   OFDPA_OP_FLAG_REMOVE, htons(vid));
+       if (err)
+               return err;
+
+       return ofdpa_port_vlan(ofdpa_port, NULL,
+                              OFDPA_OP_FLAG_REMOVE, vid);
+}
+
+static struct ofdpa_internal_vlan_tbl_entry *
+ofdpa_internal_vlan_tbl_find(const struct ofdpa *ofdpa, int ifindex)
+{
+       struct ofdpa_internal_vlan_tbl_entry *found;
+
+       hash_for_each_possible(ofdpa->internal_vlan_tbl, found,
+                              entry, ifindex) {
+               if (found->ifindex == ifindex)
+                       return found;
+       }
+
+       return NULL;
+}
+
+static __be16 ofdpa_port_internal_vlan_id_get(struct ofdpa_port *ofdpa_port,
+                                             int ifindex)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_internal_vlan_tbl_entry *entry;
+       struct ofdpa_internal_vlan_tbl_entry *found;
+       unsigned long lock_flags;
+       int i;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return 0;
+
+       entry->ifindex = ifindex;
+
+       spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
+
+       found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
+       if (found) {
+               kfree(entry);
+               goto found;
+       }
+
+       found = entry;
+       hash_add(ofdpa->internal_vlan_tbl, &found->entry, found->ifindex);
+
+       for (i = 0; i < OFDPA_N_INTERNAL_VLANS; i++) {
+               if (test_and_set_bit(i, ofdpa->internal_vlan_bitmap))
+                       continue;
+               found->vlan_id = htons(OFDPA_INTERNAL_VLAN_ID_BASE + i);
+               goto found;
+       }
+
+       netdev_err(ofdpa_port->dev, "Out of internal VLAN IDs\n");
+
+found:
+       found->ref_count++;
+       spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
+
+       return found->vlan_id;
+}
+
+static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port,
+                              struct switchdev_trans *trans, __be32 dst,
+                              int dst_len, const struct fib_info *fi,
+                              u32 tb_id, int flags)
+{
+       const struct fib_nh *nh;
+       __be16 eth_type = htons(ETH_P_IP);
+       __be32 dst_mask = inet_make_mask(dst_len);
+       __be16 internal_vlan_id = ofdpa_port->internal_vlan_id;
+       u32 priority = fi->fib_priority;
+       enum rocker_of_dpa_table_id goto_tbl =
+               ROCKER_OF_DPA_TABLE_ID_ACL_POLICY;
+       u32 group_id;
+       bool nh_on_port;
+       bool has_gw;
+       u32 index;
+       int err;
+
+       /* XXX support ECMP */
+
+       nh = fi->fib_nh;
+       nh_on_port = (fi->fib_dev == ofdpa_port->dev);
+       has_gw = !!nh->nh_gw;
+
+       if (has_gw && nh_on_port) {
+               err = ofdpa_port_ipv4_nh(ofdpa_port, trans, flags,
+                                        nh->nh_gw, &index);
+               if (err)
+                       return err;
+
+               group_id = ROCKER_GROUP_L3_UNICAST(index);
+       } else {
+               /* Send to CPU for processing */
+               group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0);
+       }
+
+       err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst,
+                                           dst_mask, priority, goto_tbl,
+                                           group_id, flags);
+       if (err)
+               netdev_err(ofdpa_port->dev, "Error (%d) IPv4 route %pI4\n",
+                          err, &dst);
+
+       return err;
+}
+
+static void
+ofdpa_port_internal_vlan_id_put(const struct ofdpa_port *ofdpa_port,
+                               int ifindex)
+{
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_internal_vlan_tbl_entry *found;
+       unsigned long lock_flags;
+       unsigned long bit;
+
+       spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, lock_flags);
+
+       found = ofdpa_internal_vlan_tbl_find(ofdpa, ifindex);
+       if (!found) {
+               netdev_err(ofdpa_port->dev,
+                          "ifindex (%d) not found in internal VLAN tbl\n",
+                          ifindex);
+               goto not_found;
+       }
+
+       if (--found->ref_count <= 0) {
+               bit = ntohs(found->vlan_id) - OFDPA_INTERNAL_VLAN_ID_BASE;
+               clear_bit(bit, ofdpa->internal_vlan_bitmap);
+               hash_del(&found->entry);
+               kfree(found);
+       }
+
+not_found:
+       spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, lock_flags);
+}
+
+/**********************************
+ * Rocker world ops implementation
+ **********************************/
+
+static int ofdpa_init(struct rocker *rocker)
+{
+       struct ofdpa *ofdpa = rocker->wpriv;
+
+       ofdpa->rocker = rocker;
+
+       hash_init(ofdpa->flow_tbl);
+       spin_lock_init(&ofdpa->flow_tbl_lock);
+
+       hash_init(ofdpa->group_tbl);
+       spin_lock_init(&ofdpa->group_tbl_lock);
+
+       hash_init(ofdpa->fdb_tbl);
+       spin_lock_init(&ofdpa->fdb_tbl_lock);
+
+       hash_init(ofdpa->internal_vlan_tbl);
+       spin_lock_init(&ofdpa->internal_vlan_tbl_lock);
+
+       hash_init(ofdpa->neigh_tbl);
+       spin_lock_init(&ofdpa->neigh_tbl_lock);
+
+       setup_timer(&ofdpa->fdb_cleanup_timer, ofdpa_fdb_cleanup,
+                   (unsigned long) ofdpa);
+       mod_timer(&ofdpa->fdb_cleanup_timer, jiffies);
+
+       ofdpa->ageing_time = BR_DEFAULT_AGEING_TIME;
+
+       return 0;
+}
+
+static void ofdpa_fini(struct rocker *rocker)
+{
+       struct ofdpa *ofdpa = rocker->wpriv;
+
+       unsigned long flags;
+       struct ofdpa_flow_tbl_entry *flow_entry;
+       struct ofdpa_group_tbl_entry *group_entry;
+       struct ofdpa_fdb_tbl_entry *fdb_entry;
+       struct ofdpa_internal_vlan_tbl_entry *internal_vlan_entry;
+       struct ofdpa_neigh_tbl_entry *neigh_entry;
+       struct hlist_node *tmp;
+       int bkt;
+
+       del_timer_sync(&ofdpa->fdb_cleanup_timer);
+
+       spin_lock_irqsave(&ofdpa->flow_tbl_lock, flags);
+       hash_for_each_safe(ofdpa->flow_tbl, bkt, tmp, flow_entry, entry)
+               hash_del(&flow_entry->entry);
+       spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags);
+
+       spin_lock_irqsave(&ofdpa->group_tbl_lock, flags);
+       hash_for_each_safe(ofdpa->group_tbl, bkt, tmp, group_entry, entry)
+               hash_del(&group_entry->entry);
+       spin_unlock_irqrestore(&ofdpa->group_tbl_lock, flags);
+
+       spin_lock_irqsave(&ofdpa->fdb_tbl_lock, flags);
+       hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, fdb_entry, entry)
+               hash_del(&fdb_entry->entry);
+       spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, flags);
+
+       spin_lock_irqsave(&ofdpa->internal_vlan_tbl_lock, flags);
+       hash_for_each_safe(ofdpa->internal_vlan_tbl, bkt,
+                          tmp, internal_vlan_entry, entry)
+               hash_del(&internal_vlan_entry->entry);
+       spin_unlock_irqrestore(&ofdpa->internal_vlan_tbl_lock, flags);
+
+       spin_lock_irqsave(&ofdpa->neigh_tbl_lock, flags);
+       hash_for_each_safe(ofdpa->neigh_tbl, bkt, tmp, neigh_entry, entry)
+               hash_del(&neigh_entry->entry);
+       spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, flags);
+}
+
+static int ofdpa_port_pre_init(struct rocker_port *rocker_port)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       ofdpa_port->ofdpa = rocker_port->rocker->wpriv;
+       ofdpa_port->rocker_port = rocker_port;
+       ofdpa_port->dev = rocker_port->dev;
+       ofdpa_port->pport = rocker_port->pport;
+       ofdpa_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC;
+       ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME;
+       return 0;
+}
+
+static int ofdpa_port_init(struct rocker_port *rocker_port)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int err;
+
+       switchdev_port_fwd_mark_set(ofdpa_port->dev, NULL, false);
+       rocker_port_set_learning(rocker_port,
+                                !!(ofdpa_port->brport_flags & BR_LEARNING));
+
+       err = ofdpa_port_ig_tbl(ofdpa_port, NULL, 0);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "install ig port table failed\n");
+               return err;
+       }
+
+       ofdpa_port->internal_vlan_id =
+               ofdpa_port_internal_vlan_id_get(ofdpa_port,
+                                               ofdpa_port->dev->ifindex);
+
+       err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
+       if (err) {
+               netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n");
+               goto err_untagged_vlan;
+       }
+       return 0;
+
+err_untagged_vlan:
+       ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE);
+       return err;
+}
+
+static void ofdpa_port_fini(struct rocker_port *rocker_port)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE);
+}
+
+static int ofdpa_port_open(struct rocker_port *rocker_port)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       return ofdpa_port_fwd_enable(ofdpa_port, 0);
+}
+
+static void ofdpa_port_stop(struct rocker_port *rocker_port)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       ofdpa_port_fwd_disable(ofdpa_port, OFDPA_OP_FLAG_NOWAIT);
+}
+
+static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port,
+                                        u8 state,
+                                        struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       return ofdpa_port_stp_update(ofdpa_port, trans, 0, state);
+}
+
+static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port,
+                                           unsigned long brport_flags,
+                                           struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       unsigned long orig_flags;
+       int err = 0;
+
+       orig_flags = ofdpa_port->brport_flags;
+       ofdpa_port->brport_flags = brport_flags;
+       if ((orig_flags ^ ofdpa_port->brport_flags) & BR_LEARNING &&
+           !switchdev_trans_ph_prepare(trans))
+               err = rocker_port_set_learning(ofdpa_port->rocker_port,
+                                              !!(ofdpa_port->brport_flags & BR_LEARNING));
+
+       if (switchdev_trans_ph_prepare(trans))
+               ofdpa_port->brport_flags = orig_flags;
+
+       return err;
+}
+
+static int
+ofdpa_port_attr_bridge_flags_get(const struct rocker_port *rocker_port,
+                                unsigned long *p_brport_flags)
+{
+       const struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       *p_brport_flags = ofdpa_port->brport_flags;
+       return 0;
+}
+
+static int
+ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port,
+                                      u32 ageing_time,
+                                      struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+
+       if (!switchdev_trans_ph_prepare(trans)) {
+               ofdpa_port->ageing_time = clock_t_to_jiffies(ageing_time);
+               if (ofdpa_port->ageing_time < ofdpa->ageing_time)
+                       ofdpa->ageing_time = ofdpa_port->ageing_time;
+               mod_timer(&ofdpa_port->ofdpa->fdb_cleanup_timer, jiffies);
+       }
+
+       return 0;
+}
+
+static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port,
+                                  const struct switchdev_obj_port_vlan *vlan,
+                                  struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       u16 vid;
+       int err;
+
+       for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+               err = ofdpa_port_vlan_add(ofdpa_port, trans, vid, vlan->flags);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ofdpa_port_obj_vlan_del(struct rocker_port *rocker_port,
+                                  const struct switchdev_obj_port_vlan *vlan)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       u16 vid;
+       int err;
+
+       for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
+               err = ofdpa_port_vlan_del(ofdpa_port, vid, vlan->flags);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port,
+                                   struct switchdev_obj_port_vlan *vlan,
+                                   switchdev_obj_dump_cb_t *cb)
+{
+       const struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       u16 vid;
+       int err = 0;
+
+       for (vid = 1; vid < VLAN_N_VID; vid++) {
+               if (!test_bit(vid, ofdpa_port->vlan_bitmap))
+                       continue;
+               vlan->flags = 0;
+               if (ofdpa_vlan_id_is_internal(htons(vid)))
+                       vlan->flags |= BRIDGE_VLAN_INFO_PVID;
+               vlan->vid_begin = vlan->vid_end = vid;
+               err = cb(&vlan->obj);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+static int ofdpa_port_obj_fib4_add(struct rocker_port *rocker_port,
+                                  const struct switchdev_obj_ipv4_fib *fib4,
+                                  struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       return ofdpa_port_fib_ipv4(ofdpa_port, trans,
+                                  htonl(fib4->dst), fib4->dst_len,
+                                  &fib4->fi, fib4->tb_id, 0);
+}
+
+static int ofdpa_port_obj_fib4_del(struct rocker_port *rocker_port,
+                                  const struct switchdev_obj_ipv4_fib *fib4)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+
+       return ofdpa_port_fib_ipv4(ofdpa_port, NULL,
+                                  htonl(fib4->dst), fib4->dst_len,
+                                  &fib4->fi, fib4->tb_id,
+                                  OFDPA_OP_FLAG_REMOVE);
+}
+
+static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port,
+                                 const struct switchdev_obj_port_fdb *fdb,
+                                 struct switchdev_trans *trans)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL);
+
+       if (!ofdpa_port_is_bridged(ofdpa_port))
+               return -EINVAL;
+
+       return ofdpa_port_fdb(ofdpa_port, trans, fdb->addr, vlan_id, 0);
+}
+
+static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port,
+                                 const struct switchdev_obj_port_fdb *fdb)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL);
+       int flags = OFDPA_OP_FLAG_REMOVE;
+
+       if (!ofdpa_port_is_bridged(ofdpa_port))
+               return -EINVAL;
+
+       return ofdpa_port_fdb(ofdpa_port, NULL, fdb->addr, vlan_id, flags);
+}
+
+static int ofdpa_port_obj_fdb_dump(const struct rocker_port *rocker_port,
+                                  struct switchdev_obj_port_fdb *fdb,
+                                  switchdev_obj_dump_cb_t *cb)
+{
+       const struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       struct ofdpa *ofdpa = ofdpa_port->ofdpa;
+       struct ofdpa_fdb_tbl_entry *found;
+       struct hlist_node *tmp;
+       unsigned long lock_flags;
+       int bkt;
+       int err = 0;
+
+       spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags);
+       hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) {
+               if (found->key.ofdpa_port != ofdpa_port)
+                       continue;
+               ether_addr_copy(fdb->addr, found->key.addr);
+               fdb->ndm_state = NUD_REACHABLE;
+               fdb->vid = ofdpa_port_vlan_to_vid(ofdpa_port,
+                                                 found->key.vlan_id);
+               err = cb(&fdb->obj);
+               if (err)
+                       break;
+       }
+       spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags);
+
+       return err;
+}
+
+static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
+                                 struct net_device *bridge)
+{
+       int err;
+
+       /* Port is joining bridge, so the internal VLAN for the
+        * port is going to change to the bridge internal VLAN.
+        * Let's remove untagged VLAN (vid=0) from port and
+        * re-add once internal VLAN has changed.
+        */
+
+       err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
+       if (err)
+               return err;
+
+       ofdpa_port_internal_vlan_id_put(ofdpa_port,
+                                       ofdpa_port->dev->ifindex);
+       ofdpa_port->internal_vlan_id =
+               ofdpa_port_internal_vlan_id_get(ofdpa_port, bridge->ifindex);
+
+       ofdpa_port->bridge_dev = bridge;
+       switchdev_port_fwd_mark_set(ofdpa_port->dev, bridge, true);
+
+       return ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
+}
+
+static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
+{
+       int err;
+
+       err = ofdpa_port_vlan_del(ofdpa_port, OFDPA_UNTAGGED_VID, 0);
+       if (err)
+               return err;
+
+       ofdpa_port_internal_vlan_id_put(ofdpa_port,
+                                       ofdpa_port->bridge_dev->ifindex);
+       ofdpa_port->internal_vlan_id =
+               ofdpa_port_internal_vlan_id_get(ofdpa_port,
+                                               ofdpa_port->dev->ifindex);
+
+       switchdev_port_fwd_mark_set(ofdpa_port->dev, ofdpa_port->bridge_dev,
+                                   false);
+       ofdpa_port->bridge_dev = NULL;
+
+       err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
+       if (err)
+               return err;
+
+       if (ofdpa_port->dev->flags & IFF_UP)
+               err = ofdpa_port_fwd_enable(ofdpa_port, 0);
+
+       return err;
+}
+
+static int ofdpa_port_ovs_changed(struct ofdpa_port *ofdpa_port,
+                                 struct net_device *master)
+{
+       int err;
+
+       ofdpa_port->bridge_dev = master;
+
+       err = ofdpa_port_fwd_disable(ofdpa_port, 0);
+       if (err)
+               return err;
+       err = ofdpa_port_fwd_enable(ofdpa_port, 0);
+
+       return err;
+}
+
+static int ofdpa_port_master_linked(struct rocker_port *rocker_port,
+                                   struct net_device *master)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int err = 0;
+
+       if (netif_is_bridge_master(master))
+               err = ofdpa_port_bridge_join(ofdpa_port, master);
+       else if (netif_is_ovs_master(master))
+               err = ofdpa_port_ovs_changed(ofdpa_port, master);
+       return err;
+}
+
+static int ofdpa_port_master_unlinked(struct rocker_port *rocker_port,
+                                     struct net_device *master)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int err = 0;
+
+       if (ofdpa_port_is_bridged(ofdpa_port))
+               err = ofdpa_port_bridge_leave(ofdpa_port);
+       else if (ofdpa_port_is_ovsed(ofdpa_port))
+               err = ofdpa_port_ovs_changed(ofdpa_port, NULL);
+       return err;
+}
+
+static int ofdpa_port_neigh_update(struct rocker_port *rocker_port,
+                                  struct neighbour *n)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int flags = (n->nud_state & NUD_VALID ? 0 : OFDPA_OP_FLAG_REMOVE) |
+                                                   OFDPA_OP_FLAG_NOWAIT;
+       __be32 ip_addr = *(__be32 *) n->primary_key;
+
+       return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha);
+}
+
+static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port,
+                                   struct neighbour *n)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT;
+       __be32 ip_addr = *(__be32 *) n->primary_key;
+
+       return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha);
+}
+
+static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port,
+                                      const unsigned char *addr,
+                                      __be16 vlan_id)
+{
+       struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
+       int flags = OFDPA_OP_FLAG_NOWAIT | OFDPA_OP_FLAG_LEARNED;
+
+       if (ofdpa_port->stp_state != BR_STATE_LEARNING &&
+           ofdpa_port->stp_state != BR_STATE_FORWARDING)
+               return 0;
+
+       return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags);
+}
+
+struct rocker_world_ops rocker_ofdpa_ops = {
+       .kind = "ofdpa",
+       .priv_size = sizeof(struct ofdpa),
+       .port_priv_size = sizeof(struct ofdpa_port),
+       .mode = ROCKER_PORT_MODE_OF_DPA,
+       .init = ofdpa_init,
+       .fini = ofdpa_fini,
+       .port_pre_init = ofdpa_port_pre_init,
+       .port_init = ofdpa_port_init,
+       .port_fini = ofdpa_port_fini,
+       .port_open = ofdpa_port_open,
+       .port_stop = ofdpa_port_stop,
+       .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set,
+       .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set,
+       .port_attr_bridge_flags_get = ofdpa_port_attr_bridge_flags_get,
+       .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set,
+       .port_obj_vlan_add = ofdpa_port_obj_vlan_add,
+       .port_obj_vlan_del = ofdpa_port_obj_vlan_del,
+       .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump,
+       .port_obj_fib4_add = ofdpa_port_obj_fib4_add,
+       .port_obj_fib4_del = ofdpa_port_obj_fib4_del,
+       .port_obj_fdb_add = ofdpa_port_obj_fdb_add,
+       .port_obj_fdb_del = ofdpa_port_obj_fdb_del,
+       .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump,
+       .port_master_linked = ofdpa_port_master_linked,
+       .port_master_unlinked = ofdpa_port_master_unlinked,
+       .port_neigh_update = ofdpa_port_neigh_update,
+       .port_neigh_destroy = ofdpa_port_neigh_destroy,
+       .port_ev_mac_vlan_seen = ofdpa_port_ev_mac_vlan_seen,
+};
diff --git a/drivers/net/ethernet/rocker/rocker_tlv.c b/drivers/net/ethernet/rocker/rocker_tlv.c
new file mode 100644 (file)
index 0000000..8185118
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * drivers/net/ethernet/rocker/rocker_tlv.c - Rocker switch device driver
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
+ * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include "rocker_hw.h"
+#include "rocker_tlv.h"
+
+void rocker_tlv_parse(const struct rocker_tlv **tb, int maxtype,
+                     const char *buf, int buf_len)
+{
+       const struct rocker_tlv *tlv;
+       const struct rocker_tlv *head = (const struct rocker_tlv *) buf;
+       int rem;
+
+       memset(tb, 0, sizeof(struct rocker_tlv *) * (maxtype + 1));
+
+       rocker_tlv_for_each(tlv, head, buf_len, rem) {
+               u32 type = rocker_tlv_type(tlv);
+
+               if (type > 0 && type <= maxtype)
+                       tb[type] = tlv;
+       }
+}
+
+int rocker_tlv_put(struct rocker_desc_info *desc_info,
+                  int attrtype, int attrlen, const void *data)
+{
+       int tail_room = desc_info->data_size - desc_info->tlv_size;
+       int total_size = rocker_tlv_total_size(attrlen);
+       struct rocker_tlv *tlv;
+
+       if (unlikely(tail_room < total_size))
+               return -EMSGSIZE;
+
+       tlv = rocker_tlv_start(desc_info);
+       desc_info->tlv_size += total_size;
+       tlv->type = attrtype;
+       tlv->len = rocker_tlv_attr_size(attrlen);
+       memcpy(rocker_tlv_data(tlv), data, attrlen);
+       memset((char *) tlv + tlv->len, 0, rocker_tlv_padlen(attrlen));
+       return 0;
+}
diff --git a/drivers/net/ethernet/rocker/rocker_tlv.h b/drivers/net/ethernet/rocker/rocker_tlv.h
new file mode 100644 (file)
index 0000000..a63ef82
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * drivers/net/ethernet/rocker/rocker_tlv.h - Rocker switch device driver
+ * Copyright (c) 2014-2016 Jiri Pirko <jiri@mellanox.com>
+ * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ROCKER_TLV_H
+#define _ROCKER_TLV_H
+
+#include <linux/types.h>
+
+#include "rocker_hw.h"
+#include "rocker.h"
+
+#define ROCKER_TLV_ALIGNTO 8U
+#define ROCKER_TLV_ALIGN(len) \
+       (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1))
+#define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(struct rocker_tlv))
+
+/*  <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) --->
+ * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
+ * |             Header          | Pad |           Payload           | Pad |
+ * |      (struct rocker_tlv)    | ing |                             | ing |
+ * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
+ *  <--------------------------- tlv->len -------------------------->
+ */
+
+static inline struct rocker_tlv *rocker_tlv_next(const struct rocker_tlv *tlv,
+                                                int *remaining)
+{
+       int totlen = ROCKER_TLV_ALIGN(tlv->len);
+
+       *remaining -= totlen;
+       return (struct rocker_tlv *) ((char *) tlv + totlen);
+}
+
+static inline int rocker_tlv_ok(const struct rocker_tlv *tlv, int remaining)
+{
+       return remaining >= (int) ROCKER_TLV_HDRLEN &&
+              tlv->len >= ROCKER_TLV_HDRLEN &&
+              tlv->len <= remaining;
+}
+
+#define rocker_tlv_for_each(pos, head, len, rem)       \
+       for (pos = head, rem = len;                     \
+            rocker_tlv_ok(pos, rem);                   \
+            pos = rocker_tlv_next(pos, &(rem)))
+
+#define rocker_tlv_for_each_nested(pos, tlv, rem)      \
+       rocker_tlv_for_each(pos, rocker_tlv_data(tlv),  \
+                           rocker_tlv_len(tlv), rem)
+
+static inline int rocker_tlv_attr_size(int payload)
+{
+       return ROCKER_TLV_HDRLEN + payload;
+}
+
+static inline int rocker_tlv_total_size(int payload)
+{
+       return ROCKER_TLV_ALIGN(rocker_tlv_attr_size(payload));
+}
+
+static inline int rocker_tlv_padlen(int payload)
+{
+       return rocker_tlv_total_size(payload) - rocker_tlv_attr_size(payload);
+}
+
+static inline int rocker_tlv_type(const struct rocker_tlv *tlv)
+{
+       return tlv->type;
+}
+
+static inline void *rocker_tlv_data(const struct rocker_tlv *tlv)
+{
+       return (char *) tlv + ROCKER_TLV_HDRLEN;
+}
+
+static inline int rocker_tlv_len(const struct rocker_tlv *tlv)
+{
+       return tlv->len - ROCKER_TLV_HDRLEN;
+}
+
+static inline u8 rocker_tlv_get_u8(const struct rocker_tlv *tlv)
+{
+       return *(u8 *) rocker_tlv_data(tlv);
+}
+
+static inline u16 rocker_tlv_get_u16(const struct rocker_tlv *tlv)
+{
+       return *(u16 *) rocker_tlv_data(tlv);
+}
+
+static inline __be16 rocker_tlv_get_be16(const struct rocker_tlv *tlv)
+{
+       return *(__be16 *) rocker_tlv_data(tlv);
+}
+
+static inline u32 rocker_tlv_get_u32(const struct rocker_tlv *tlv)
+{
+       return *(u32 *) rocker_tlv_data(tlv);
+}
+
+static inline u64 rocker_tlv_get_u64(const struct rocker_tlv *tlv)
+{
+       return *(u64 *) rocker_tlv_data(tlv);
+}
+
+void rocker_tlv_parse(const struct rocker_tlv **tb, int maxtype,
+                     const char *buf, int buf_len);
+
+static inline void rocker_tlv_parse_nested(const struct rocker_tlv **tb,
+                                          int maxtype,
+                                          const struct rocker_tlv *tlv)
+{
+       rocker_tlv_parse(tb, maxtype, rocker_tlv_data(tlv),
+                        rocker_tlv_len(tlv));
+}
+
+static inline void
+rocker_tlv_parse_desc(const struct rocker_tlv **tb, int maxtype,
+                     const struct rocker_desc_info *desc_info)
+{
+       rocker_tlv_parse(tb, maxtype, desc_info->data,
+                        desc_info->desc->tlv_size);
+}
+
+static inline struct rocker_tlv *
+rocker_tlv_start(struct rocker_desc_info *desc_info)
+{
+       return (struct rocker_tlv *) ((char *) desc_info->data +
+                                              desc_info->tlv_size);
+}
+
+int rocker_tlv_put(struct rocker_desc_info *desc_info,
+                  int attrtype, int attrlen, const void *data);
+
+static inline int rocker_tlv_put_u8(struct rocker_desc_info *desc_info,
+                                   int attrtype, u8 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(u8), &value);
+}
+
+static inline int rocker_tlv_put_u16(struct rocker_desc_info *desc_info,
+                                    int attrtype, u16 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(u16), &value);
+}
+
+static inline int rocker_tlv_put_be16(struct rocker_desc_info *desc_info,
+                                     int attrtype, __be16 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(__be16), &value);
+}
+
+static inline int rocker_tlv_put_u32(struct rocker_desc_info *desc_info,
+                                    int attrtype, u32 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(u32), &value);
+}
+
+static inline int rocker_tlv_put_be32(struct rocker_desc_info *desc_info,
+                                     int attrtype, __be32 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(__be32), &value);
+}
+
+static inline int rocker_tlv_put_u64(struct rocker_desc_info *desc_info,
+                                    int attrtype, u64 value)
+{
+       return rocker_tlv_put(desc_info, attrtype, sizeof(u64), &value);
+}
+
+static inline struct rocker_tlv *
+rocker_tlv_nest_start(struct rocker_desc_info *desc_info, int attrtype)
+{
+       struct rocker_tlv *start = rocker_tlv_start(desc_info);
+
+       if (rocker_tlv_put(desc_info, attrtype, 0, NULL) < 0)
+               return NULL;
+
+       return start;
+}
+
+static inline void rocker_tlv_nest_end(struct rocker_desc_info *desc_info,
+                                      struct rocker_tlv *start)
+{
+       start->len = (char *) rocker_tlv_start(desc_info) - (char *) start;
+}
+
+static inline void rocker_tlv_nest_cancel(struct rocker_desc_info *desc_info,
+                                         const struct rocker_tlv *start)
+{
+       desc_info->tlv_size = (const char *) start - desc_info->data;
+}
+
+#endif
index 10827476bc0b38237b9b6999a31a907cd330cf9e..5e3f93f04e624a6b5f4e7885a625c47922766342 100644 (file)
@@ -32,7 +32,8 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
                                struct net_device *net_dev);
 netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
-int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
+int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto,
+                struct tc_to_netdev *tc);
 unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
 extern unsigned int efx_piobuf_size;
 extern bool efx_separate_tx_channels;
index f7a0ec1bca97d96a4debc2324ad944380726cca6..2337789115579972ae4608445872af0b933b3759 100644 (file)
@@ -562,14 +562,20 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
                                     efx->n_tx_channels : 0));
 }
 
-int efx_setup_tc(struct net_device *net_dev, u8 num_tc)
+int efx_setup_tc(struct net_device *net_dev, u32 handle, __be16 proto,
+                struct tc_to_netdev *ntc)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
-       unsigned tc;
+       unsigned tc, num_tc;
        int rc;
 
+       if (ntc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
+       num_tc = ntc->tc;
+
        if (efx_nic_rev(efx) < EFX_REV_FALCON_B0 || num_tc > EFX_MAX_TX_TC)
                return -EINVAL;
 
index 0e2fc1a844ab2b2453681750368e1cf9d288e779..db7db8ac4ca308a2f5f52e11f052bbd246c824a4 100644 (file)
@@ -2342,8 +2342,8 @@ static int smc_drv_probe(struct platform_device *pdev)
        }
 
        ndev->irq = platform_get_irq(pdev, 0);
-       if (ndev->irq <= 0) {
-               ret = -ENODEV;
+       if (ndev->irq < 0) {
+               ret = ndev->irq;
                goto out_release_io;
        }
        /*
index cf28daba4346f0c288d1718513554b38e4de2176..b3e669af30055e234a8910e95f232ba2c47443d1 100644 (file)
@@ -31,8 +31,7 @@
 static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)p;
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int entry = priv->cur_tx % txsize;
+       unsigned int entry = priv->cur_tx;
        struct dma_desc *desc = priv->dma_tx + entry;
        unsigned int nopaged_len = skb_headlen(skb);
        unsigned int bmax;
@@ -50,11 +49,14 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
        if (dma_mapping_error(priv->device, desc->des2))
                return -1;
        priv->tx_skbuff_dma[entry].buf = desc->des2;
-       priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
+       priv->tx_skbuff_dma[entry].len = bmax;
+       /* do not close the descriptor and do not set own bit */
+       priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
+                                       0, false);
 
        while (len != 0) {
                priv->tx_skbuff[entry] = NULL;
-               entry = (++priv->cur_tx) % txsize;
+               entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
                desc = priv->dma_tx + entry;
 
                if (len > bmax) {
@@ -64,9 +66,10 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        if (dma_mapping_error(priv->device, desc->des2))
                                return -1;
                        priv->tx_skbuff_dma[entry].buf = desc->des2;
+                       priv->tx_skbuff_dma[entry].len = bmax;
                        priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
-                                                       STMMAC_CHAIN_MODE);
-                       priv->hw->desc->set_tx_owner(desc);
+                                                       STMMAC_CHAIN_MODE, 1,
+                                                       false);
                        len -= bmax;
                        i++;
                } else {
@@ -76,12 +79,17 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        if (dma_mapping_error(priv->device, desc->des2))
                                return -1;
                        priv->tx_skbuff_dma[entry].buf = desc->des2;
+                       priv->tx_skbuff_dma[entry].len = len;
+                       /* last descriptor can be set now */
                        priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
-                                                       STMMAC_CHAIN_MODE);
-                       priv->hw->desc->set_tx_owner(desc);
+                                                       STMMAC_CHAIN_MODE, 1,
+                                                       true);
                        len = 0;
                }
        }
+
+       priv->cur_tx = entry;
+
        return entry;
 }
 
@@ -138,23 +146,24 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
                 */
                p->des3 = (unsigned int)(priv->dma_rx_phy +
                                         (((priv->dirty_rx) + 1) %
-                                         priv->dma_rx_size) *
+                                         DMA_RX_SIZE) *
                                         sizeof(struct dma_desc));
 }
 
 static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+       unsigned int entry = priv->dirty_tx;
 
-       if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
+       if (priv->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
+           priv->hwts_tx_en)
                /* NOTE: Device will overwrite des3 with timestamp value if
                 * 1588-2002 time stamping is enabled, hence reinitialize it
                 * to keep explicit chaining in the descriptor.
                 */
-               p->des3 = (unsigned int)(priv->dma_tx_phy +
-                                        (((priv->dirty_tx + 1) %
-                                          priv->dma_tx_size) *
-                                         sizeof(struct dma_desc)));
+               p->des3 = (unsigned int)((priv->dma_tx_phy +
+                                         ((priv->dirty_tx + 1) % DMA_TX_SIZE))
+                                         * sizeof(struct dma_desc));
 }
 
 const struct stmmac_mode_ops chain_mode_ops = {
index 1e19c8fd8b823d0419d537be27a2058727c6d30a..f96d257308b0f5e1c22ab37c0e551fe5d3847b0f 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
+#include <linux/stmmac.h>
 #include <linux/phy.h>
 #include <linux/module.h>
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define        DWMAC_CORE_3_40 0x34
 #define        DWMAC_CORE_3_50 0x35
 
+#define DMA_TX_SIZE 512
+#define DMA_RX_SIZE 512
+#define STMMAC_GET_ENTRY(x, size)      ((x + 1) & (size - 1))
+
 #undef FRAME_FILTER_DEBUG
 /* #define FRAME_FILTER_DEBUG */
 
@@ -95,7 +100,7 @@ struct stmmac_extra_stats {
        unsigned long napi_poll;
        unsigned long tx_normal_irq_n;
        unsigned long tx_clean;
-       unsigned long tx_reset_ic_bit;
+       unsigned long tx_set_ic_bit;
        unsigned long irq_receive_pmt_irq_n;
        /* MMC info */
        unsigned long mmc_tx_irq_n;
@@ -233,10 +238,19 @@ struct stmmac_extra_stats {
 
 /* Rx IPC status */
 enum rx_frame_status {
-       good_frame = 0,
-       discard_frame = 1,
-       csum_none = 2,
-       llc_snap = 4,
+       good_frame = 0x0,
+       discard_frame = 0x1,
+       csum_none = 0x2,
+       llc_snap = 0x4,
+       dma_own = 0x8,
+};
+
+/* Tx status */
+enum tx_frame_status {
+       tx_done = 0x0,
+       tx_not_ls = 0x1,
+       tx_err = 0x2,
+       tx_dma_own = 0x4,
 };
 
 enum dma_irq_status {
@@ -332,17 +346,16 @@ struct stmmac_desc_ops {
 
        /* Invoked by the xmit function to prepare the tx descriptor */
        void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
-                                int csum_flag, int mode);
+                                bool csum_flag, int mode, bool tx_own,
+                                bool ls);
        /* Set/get the owner of the descriptor */
        void (*set_tx_owner) (struct dma_desc *p);
        int (*get_tx_owner) (struct dma_desc *p);
-       /* Invoked by the xmit function to close the tx descriptor */
-       void (*close_tx_desc) (struct dma_desc *p);
        /* Clean the tx descriptor as soon as the tx irq is received */
        void (*release_tx_desc) (struct dma_desc *p, int mode);
        /* Clear interrupt on tx frame completion. When this bit is
         * set an interrupt happens as soon as the frame is transmitted */
-       void (*clear_tx_ic) (struct dma_desc *p);
+       void (*set_tx_ic)(struct dma_desc *p);
        /* Last tx segment reports the transmit status */
        int (*get_tx_ls) (struct dma_desc *p);
        /* Return the transmit status looking at the TDES1 */
@@ -351,7 +364,6 @@ struct stmmac_desc_ops {
        /* Get the buffer size from the descriptor */
        int (*get_tx_len) (struct dma_desc *p);
        /* Handle extra events on specific interrupts hw dependent */
-       int (*get_rx_owner) (struct dma_desc *p);
        void (*set_rx_owner) (struct dma_desc *p);
        /* Get the receive frame size */
        int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
@@ -376,8 +388,11 @@ extern const struct stmmac_desc_ops ndesc_ops;
 /* Specific DMA helpers */
 struct stmmac_dma_ops {
        /* DMA core initialization */
-       int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
-                    int burst_len, u32 dma_tx, u32 dma_rx, int atds);
+       int (*reset)(void __iomem *ioaddr);
+       void (*init)(void __iomem *ioaddr, int pbl, int fb, int mb,
+                    int aal, u32 dma_tx, u32 dma_rx, int atds);
+       /* Configure the AXI Bus Mode Register */
+       void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
        /* Dump DMA registers */
        void (*dump_regs) (void __iomem *ioaddr);
        /* Set tx/rx threshold in the csr6 register
index 799c2929c5365792ecf83682ac4064e24669d023..2e4c171a2b4146f6276855ab14a3ba83e85680ad 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
-  Header File to describe the DMA descriptors.
-  Enhanced descriptors have been in case of DWMAC1000 Cores.
+  Header File to describe the DMA descriptors and related definitions.
+  This is for DWMAC100 and 1000 cores.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #ifndef __DESCS_H__
 #define __DESCS_H__
 
+#include <linux/bitops.h>
+
+/* Normal receive descriptor defines */
+
+/* RDES0 */
+#define        RDES0_PAYLOAD_CSUM_ERR  BIT(0)
+#define        RDES0_CRC_ERROR         BIT(1)
+#define        RDES0_DRIBBLING         BIT(2)
+#define        RDES0_MII_ERROR         BIT(3)
+#define        RDES0_RECEIVE_WATCHDOG  BIT(4)
+#define        RDES0_FRAME_TYPE        BIT(5)
+#define        RDES0_COLLISION         BIT(6)
+#define        RDES0_IPC_CSUM_ERROR    BIT(7)
+#define        RDES0_LAST_DESCRIPTOR   BIT(8)
+#define        RDES0_FIRST_DESCRIPTOR  BIT(9)
+#define        RDES0_VLAN_TAG          BIT(10)
+#define        RDES0_OVERFLOW_ERROR    BIT(11)
+#define        RDES0_LENGTH_ERROR      BIT(12)
+#define        RDES0_SA_FILTER_FAIL    BIT(13)
+#define        RDES0_DESCRIPTOR_ERROR  BIT(14)
+#define        RDES0_ERROR_SUMMARY     BIT(15)
+#define        RDES0_FRAME_LEN_MASK    GENMASK(29, 16)
+#define RDES0_FRAME_LEN_SHIFT  16
+#define        RDES0_DA_FILTER_FAIL    BIT(30)
+#define        RDES0_OWN               BIT(31)
+                       /* RDES1 */
+#define        RDES1_BUFFER1_SIZE_MASK         GENMASK(10, 0)
+#define        RDES1_BUFFER2_SIZE_MASK         GENMASK(21, 11)
+#define        RDES1_BUFFER2_SIZE_SHIFT        11
+#define        RDES1_SECOND_ADDRESS_CHAINED    BIT(24)
+#define        RDES1_END_RING                  BIT(25)
+#define        RDES1_DISABLE_IC                BIT(31)
+
+/* Enhanced receive descriptor defines */
+
+/* RDES0 (similar to normal RDES) */
+#define         ERDES0_RX_MAC_ADDR     BIT(0)
+
+/* RDES1: completely differ from normal desc definitions */
+#define        ERDES1_BUFFER1_SIZE_MASK        GENMASK(12, 0)
+#define        ERDES1_SECOND_ADDRESS_CHAINED   BIT(14)
+#define        ERDES1_END_RING                 BIT(15)
+#define        ERDES1_BUFFER2_SIZE_MASK        GENMASK(28, 16)
+#define ERDES1_BUFFER2_SIZE_SHIFT      16
+#define        ERDES1_DISABLE_IC               BIT(31)
+
+/* Normal transmit descriptor defines */
+/* TDES0 */
+#define        TDES0_DEFERRED                  BIT(0)
+#define        TDES0_UNDERFLOW_ERROR           BIT(1)
+#define        TDES0_EXCESSIVE_DEFERRAL        BIT(2)
+#define        TDES0_COLLISION_COUNT_MASK      GENMASK(6, 3)
+#define        TDES0_VLAN_FRAME                BIT(7)
+#define        TDES0_EXCESSIVE_COLLISIONS      BIT(8)
+#define        TDES0_LATE_COLLISION            BIT(9)
+#define        TDES0_NO_CARRIER                BIT(10)
+#define        TDES0_LOSS_CARRIER              BIT(11)
+#define        TDES0_PAYLOAD_ERROR             BIT(12)
+#define        TDES0_FRAME_FLUSHED             BIT(13)
+#define        TDES0_JABBER_TIMEOUT            BIT(14)
+#define        TDES0_ERROR_SUMMARY             BIT(15)
+#define        TDES0_IP_HEADER_ERROR           BIT(16)
+#define        TDES0_TIME_STAMP_STATUS         BIT(17)
+#define        TDES0_OWN                       BIT(31)
+/* TDES1 */
+#define        TDES1_BUFFER1_SIZE_MASK         GENMASK(10, 0)
+#define        TDES1_BUFFER2_SIZE_MASK         GENMASK(21, 11)
+#define        TDES1_BUFFER2_SIZE_SHIFT        11
+#define        TDES1_TIME_STAMP_ENABLE         BIT(22)
+#define        TDES1_DISABLE_PADDING           BIT(23)
+#define        TDES1_SECOND_ADDRESS_CHAINED    BIT(24)
+#define        TDES1_END_RING                  BIT(25)
+#define        TDES1_CRC_DISABLE               BIT(26)
+#define        TDES1_CHECKSUM_INSERTION_MASK   GENMASK(28, 27)
+#define        TDES1_CHECKSUM_INSERTION_SHIFT  27
+#define        TDES1_FIRST_SEGMENT             BIT(29)
+#define        TDES1_LAST_SEGMENT              BIT(30)
+#define        TDES1_INTERRUPT                 BIT(31)
+
+/* Enhanced transmit descriptor defines */
+/* TDES0 */
+#define        ETDES0_DEFERRED                 BIT(0)
+#define        ETDES0_UNDERFLOW_ERROR          BIT(1)
+#define        ETDES0_EXCESSIVE_DEFERRAL       BIT(2)
+#define        ETDES0_COLLISION_COUNT_MASK     GENMASK(6, 3)
+#define        ETDES0_VLAN_FRAME               BIT(7)
+#define        ETDES0_EXCESSIVE_COLLISIONS     BIT(8)
+#define        ETDES0_LATE_COLLISION           BIT(9)
+#define        ETDES0_NO_CARRIER               BIT(10)
+#define        ETDES0_LOSS_CARRIER             BIT(11)
+#define        ETDES0_PAYLOAD_ERROR            BIT(12)
+#define        ETDES0_FRAME_FLUSHED            BIT(13)
+#define        ETDES0_JABBER_TIMEOUT           BIT(14)
+#define        ETDES0_ERROR_SUMMARY            BIT(15)
+#define        ETDES0_IP_HEADER_ERROR          BIT(16)
+#define        ETDES0_TIME_STAMP_STATUS        BIT(17)
+#define        ETDES0_SECOND_ADDRESS_CHAINED   BIT(20)
+#define        ETDES0_END_RING                 BIT(21)
+#define        ETDES0_CHECKSUM_INSERTION_MASK  GENMASK(23, 22)
+#define        ETDES0_CHECKSUM_INSERTION_SHIFT 22
+#define        ETDES0_TIME_STAMP_ENABLE        BIT(25)
+#define        ETDES0_DISABLE_PADDING          BIT(26)
+#define        ETDES0_CRC_DISABLE              BIT(27)
+#define        ETDES0_FIRST_SEGMENT            BIT(28)
+#define        ETDES0_LAST_SEGMENT             BIT(29)
+#define        ETDES0_INTERRUPT                BIT(30)
+#define        ETDES0_OWN                      BIT(31)
+/* TDES1 */
+#define        ETDES1_BUFFER1_SIZE_MASK        GENMASK(12, 0)
+#define        ETDES1_BUFFER2_SIZE_MASK        GENMASK(28, 16)
+#define        ETDES1_BUFFER2_SIZE_SHIFT       16
+
+/* Extended Receive descriptor definitions */
+#define        ERDES4_IP_PAYLOAD_TYPE_MASK     GENMASK(2, 6)
+#define        ERDES4_IP_HDR_ERR               BIT(3)
+#define        ERDES4_IP_PAYLOAD_ERR           BIT(4)
+#define        ERDES4_IP_CSUM_BYPASSED         BIT(5)
+#define        ERDES4_IPV4_PKT_RCVD            BIT(6)
+#define        ERDES4_IPV6_PKT_RCVD            BIT(7)
+#define        ERDES4_MSG_TYPE_MASK            GENMASK(11, 8)
+#define        ERDES4_PTP_FRAME_TYPE           BIT(12)
+#define        ERDES4_PTP_VER                  BIT(13)
+#define        ERDES4_TIMESTAMP_DROPPED        BIT(14)
+#define        ERDES4_AV_PKT_RCVD              BIT(16)
+#define        ERDES4_AV_TAGGED_PKT_RCVD       BIT(17)
+#define        ERDES4_VLAN_TAG_PRI_VAL_MASK    GENMASK(20, 18)
+#define        ERDES4_L3_FILTER_MATCH          BIT(24)
+#define        ERDES4_L4_FILTER_MATCH          BIT(25)
+#define        ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
+
+/* Extended RDES4 message type definitions */
+#define RDES_EXT_NO_PTP                        0
+#define RDES_EXT_SYNC                  1
+#define RDES_EXT_FOLLOW_UP             2
+#define RDES_EXT_DELAY_REQ             3
+#define RDES_EXT_DELAY_RESP            4
+#define RDES_EXT_PDELAY_REQ            5
+#define RDES_EXT_PDELAY_RESP           6
+#define RDES_EXT_PDELAY_FOLLOW_UP      7
+
 /* Basic descriptor structure for normal and alternate descriptors */
 struct dma_desc {
-       /* Receive descriptor */
-       union {
-               struct {
-                       /* RDES0 */
-                       u32 payload_csum_error:1;
-                       u32 crc_error:1;
-                       u32 dribbling:1;
-                       u32 mii_error:1;
-                       u32 receive_watchdog:1;
-                       u32 frame_type:1;
-                       u32 collision:1;
-                       u32 ipc_csum_error:1;
-                       u32 last_descriptor:1;
-                       u32 first_descriptor:1;
-                       u32 vlan_tag:1;
-                       u32 overflow_error:1;
-                       u32 length_error:1;
-                       u32 sa_filter_fail:1;
-                       u32 descriptor_error:1;
-                       u32 error_summary:1;
-                       u32 frame_length:14;
-                       u32 da_filter_fail:1;
-                       u32 own:1;
-                       /* RDES1 */
-                       u32 buffer1_size:11;
-                       u32 buffer2_size:11;
-                       u32 reserved1:2;
-                       u32 second_address_chained:1;
-                       u32 end_ring:1;
-                       u32 reserved2:5;
-                       u32 disable_ic:1;
-
-               } rx;
-               struct {
-                       /* RDES0 */
-                       u32 rx_mac_addr:1;
-                       u32 crc_error:1;
-                       u32 dribbling:1;
-                       u32 error_gmii:1;
-                       u32 receive_watchdog:1;
-                       u32 frame_type:1;
-                       u32 late_collision:1;
-                       u32 ipc_csum_error:1;
-                       u32 last_descriptor:1;
-                       u32 first_descriptor:1;
-                       u32 vlan_tag:1;
-                       u32 overflow_error:1;
-                       u32 length_error:1;
-                       u32 sa_filter_fail:1;
-                       u32 descriptor_error:1;
-                       u32 error_summary:1;
-                       u32 frame_length:14;
-                       u32 da_filter_fail:1;
-                       u32 own:1;
-                       /* RDES1 */
-                       u32 buffer1_size:13;
-                       u32 reserved1:1;
-                       u32 second_address_chained:1;
-                       u32 end_ring:1;
-                       u32 buffer2_size:13;
-                       u32 reserved2:2;
-                       u32 disable_ic:1;
-               } erx;          /* -- enhanced -- */
-
-               /* Transmit descriptor */
-               struct {
-                       /* TDES0 */
-                       u32 deferred:1;
-                       u32 underflow_error:1;
-                       u32 excessive_deferral:1;
-                       u32 collision_count:4;
-                       u32 vlan_frame:1;
-                       u32 excessive_collisions:1;
-                       u32 late_collision:1;
-                       u32 no_carrier:1;
-                       u32 loss_carrier:1;
-                       u32 payload_error:1;
-                       u32 frame_flushed:1;
-                       u32 jabber_timeout:1;
-                       u32 error_summary:1;
-                       u32 ip_header_error:1;
-                       u32 time_stamp_status:1;
-                       u32 reserved1:13;
-                       u32 own:1;
-                       /* TDES1 */
-                       u32 buffer1_size:11;
-                       u32 buffer2_size:11;
-                       u32 time_stamp_enable:1;
-                       u32 disable_padding:1;
-                       u32 second_address_chained:1;
-                       u32 end_ring:1;
-                       u32 crc_disable:1;
-                       u32 checksum_insertion:2;
-                       u32 first_segment:1;
-                       u32 last_segment:1;
-                       u32 interrupt:1;
-               } tx;
-               struct {
-                       /* TDES0 */
-                       u32 deferred:1;
-                       u32 underflow_error:1;
-                       u32 excessive_deferral:1;
-                       u32 collision_count:4;
-                       u32 vlan_frame:1;
-                       u32 excessive_collisions:1;
-                       u32 late_collision:1;
-                       u32 no_carrier:1;
-                       u32 loss_carrier:1;
-                       u32 payload_error:1;
-                       u32 frame_flushed:1;
-                       u32 jabber_timeout:1;
-                       u32 error_summary:1;
-                       u32 ip_header_error:1;
-                       u32 time_stamp_status:1;
-                       u32 reserved1:2;
-                       u32 second_address_chained:1;
-                       u32 end_ring:1;
-                       u32 checksum_insertion:2;
-                       u32 reserved2:1;
-                       u32 time_stamp_enable:1;
-                       u32 disable_padding:1;
-                       u32 crc_disable:1;
-                       u32 first_segment:1;
-                       u32 last_segment:1;
-                       u32 interrupt:1;
-                       u32 own:1;
-                       /* TDES1 */
-                       u32 buffer1_size:13;
-                       u32 reserved3:3;
-                       u32 buffer2_size:13;
-                       u32 reserved4:3;
-               } etx;          /* -- enhanced -- */
-
-               u64 all_flags;
-       } des01;
+       unsigned int des0;
+       unsigned int des1;
        unsigned int des2;
        unsigned int des3;
 };
 
-/* Extended descriptor structure (supported by new SYNP GMAC generations) */
+/* Extended descriptor structure (e.g. >= databook 3.50a) */
 struct dma_extended_desc {
-       struct dma_desc basic;
-       union {
-               struct {
-                       u32 ip_payload_type:3;
-                       u32 ip_hdr_err:1;
-                       u32 ip_payload_err:1;
-                       u32 ip_csum_bypassed:1;
-                       u32 ipv4_pkt_rcvd:1;
-                       u32 ipv6_pkt_rcvd:1;
-                       u32 msg_type:4;
-                       u32 ptp_frame_type:1;
-                       u32 ptp_ver:1;
-                       u32 timestamp_dropped:1;
-                       u32 reserved:1;
-                       u32 av_pkt_rcvd:1;
-                       u32 av_tagged_pkt_rcvd:1;
-                       u32 vlan_tag_priority_val:3;
-                       u32 reserved3:3;
-                       u32 l3_filter_match:1;
-                       u32 l4_filter_match:1;
-                       u32 l3_l4_filter_no_match:2;
-                       u32 reserved4:4;
-               } erx;
-               struct {
-                       u32 reserved;
-               } etx;
-       } des4;
+       struct dma_desc basic;  /* Basic descriptors */
+       unsigned int des4;      /* Extended Status */
        unsigned int des5;      /* Reserved */
        unsigned int des6;      /* Tx/Rx Timestamp Low */
        unsigned int des7;      /* Tx/Rx Timestamp High */
 };
 
 /* Transmit checksum insertion control */
-enum tdes_csum_insertion {
-       cic_disabled = 0,       /* Checksum Insertion Control */
-       cic_only_ip = 1,        /* Only IP header */
-       /* IP header but pseudoheader is not calculated */
-       cic_no_pseudoheader = 2,
-       cic_full = 3,           /* IP header and pseudoheader */
-};
-
-/* Extended RDES4 definitions */
-#define RDES_EXT_NO_PTP                        0
-#define RDES_EXT_SYNC                  0x1
-#define RDES_EXT_FOLLOW_UP             0x2
-#define RDES_EXT_DELAY_REQ             0x3
-#define RDES_EXT_DELAY_RESP            0x4
-#define RDES_EXT_PDELAY_REQ            0x5
-#define RDES_EXT_PDELAY_RESP           0x6
-#define RDES_EXT_PDELAY_FOLLOW_UP      0x7
+#define        TX_CIC_FULL     3       /* Include IP header and pseudoheader */
 
 #endif /* __DESCS_H__ */
index 6f2cc78c5cf513ddcf8abc6e9094725a1ebfe977..7635a464ce41c536b796665e8ad913c1426299c3 100644 (file)
 /* Enhanced descriptors */
 static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
 {
-       p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
-       if (end)
-               p->des01.erx.end_ring = 1;
-}
+       p->des1 |= ((BUF_SIZE_8KiB - 1) << ERDES1_BUFFER2_SIZE_SHIFT)
+                  & ERDES1_BUFFER2_SIZE_MASK;
 
-static inline void ehn_desc_tx_set_on_ring(struct dma_desc *p, int end)
-{
        if (end)
-               p->des01.etx.end_ring = 1;
+               p->des1 |= ERDES1_END_RING;
 }
 
-static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
+static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
 {
-       p->des01.etx.end_ring = ter;
+       if (end)
+               p->des0 |= ETDES0_END_RING;
+       else
+               p->des0 &= ~ETDES0_END_RING;
 }
 
 static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
 {
        if (unlikely(len > BUF_SIZE_4KiB)) {
-               p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
-               p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+               p->des1 |= (((len - BUF_SIZE_4KiB) << ETDES1_BUFFER2_SIZE_SHIFT)
+                           & ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
+                           & ETDES1_BUFFER1_SIZE_MASK);
        } else
-               p->des01.etx.buffer1_size = len;
+               p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
 }
 
 /* Normal descriptors */
 static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
 {
-       p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
-       if (end)
-               p->des01.rx.end_ring = 1;
-}
+       p->des1 |= ((BUF_SIZE_2KiB - 1) << RDES1_BUFFER2_SIZE_SHIFT)
+                   & RDES1_BUFFER2_SIZE_MASK;
 
-static inline void ndesc_tx_set_on_ring(struct dma_desc *p, int end)
-{
        if (end)
-               p->des01.tx.end_ring = 1;
+               p->des1 |= RDES1_END_RING;
 }
 
-static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
+static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
 {
-       p->des01.tx.end_ring = ter;
+       if (end)
+               p->des1 |= TDES1_END_RING;
+       else
+               p->des1 &= ~TDES1_END_RING;
 }
 
 static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
 {
        if (unlikely(len > BUF_SIZE_2KiB)) {
-               p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
-               p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
+               unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
+                                       & TDES1_BUFFER1_SIZE_MASK;
+               p->des1 |= ((((len - buffer1) << TDES1_BUFFER2_SIZE_SHIFT)
+                           & TDES1_BUFFER2_SIZE_MASK) | buffer1);
        } else
-               p->des01.tx.buffer1_size = len;
+               p->des1 |= (len & TDES1_BUFFER1_SIZE_MASK);
 }
 
 /* Specific functions used for Chain mode */
 
 /* Enhanced descriptors */
-static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p, int end)
-{
-       p->des01.erx.second_address_chained = 1;
-}
-
-static inline void ehn_desc_tx_set_on_chain(struct dma_desc *p, int end)
+static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
 {
-       p->des01.etx.second_address_chained = 1;
+       p->des1 |= ERDES1_SECOND_ADDRESS_CHAINED;
 }
 
-static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
+static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
 {
-       p->des01.etx.second_address_chained = 1;
+       p->des0 |= ETDES0_SECOND_ADDRESS_CHAINED;
 }
 
 static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
 {
-       p->des01.etx.buffer1_size = len;
+       p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
 }
 
 /* Normal descriptors */
 static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
 {
-       p->des01.rx.second_address_chained = 1;
-}
-
-static inline void ndesc_tx_set_on_chain(struct dma_desc *p, int ring_size)
-{
-       p->des01.tx.second_address_chained = 1;
+       p->des1 |= RDES1_SECOND_ADDRESS_CHAINED;
 }
 
-static inline void ndesc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
+static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
 {
-       p->des01.tx.second_address_chained = 1;
+       p->des1 |= TDES1_SECOND_ADDRESS_CHAINED;
 }
 
 static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
 {
-       p->des01.tx.buffer1_size = len;
+       p->des1 |= len & TDES1_BUFFER1_SIZE_MASK;
 }
 #endif /* __DESC_COM_H__ */
index 2ec6aeae349e5f7dd3b4e873d1366037a943cb27..1657acfa70c2980108ad7e84f0548aa65299305e 100644 (file)
@@ -95,7 +95,6 @@
 #define DMA_BUS_MODE_DSL_MASK  0x0000007c      /* Descriptor Skip Length */
 #define DMA_BUS_MODE_DSL_SHIFT 2       /*   (in DWORDS)      */
 #define DMA_BUS_MODE_BAR_BUS   0x00000002      /* Bar-Bus Arbitration */
-#define DMA_BUS_MODE_SFT_RESET 0x00000001      /* Software Reset */
 #define DMA_BUS_MODE_DEFAULT   0x00000000
 
 /* DMA Control register defines */
index 8831a053ac135470358b932464b39d2835d128bb..b0593a4268eeab5abb38f787511196faa3590f66 100644 (file)
@@ -221,7 +221,6 @@ enum inter_frame_gap {
 
 /*--- DMA BLOCK defines ---*/
 /* DMA Bus Mode register defines */
-#define DMA_BUS_MODE_SFT_RESET 0x00000001      /* Software Reset */
 #define DMA_BUS_MODE_DA                0x00000002      /* Arbitration scheme */
 #define DMA_BUS_MODE_DSL_MASK  0x0000007c      /* Descriptor Skip Length */
 #define DMA_BUS_MODE_DSL_SHIFT 2               /*   (in DWORDS)      */
@@ -241,7 +240,7 @@ enum rx_tx_priority_ratio {
 #define DMA_BUS_MODE_RPBL_MASK 0x003e0000      /* Rx-Programmable Burst Len */
 #define DMA_BUS_MODE_RPBL_SHIFT        17
 #define DMA_BUS_MODE_USP       0x00800000
-#define DMA_BUS_MODE_PBL       0x01000000
+#define DMA_BUS_MODE_MAXPBL    0x01000000
 #define DMA_BUS_MODE_AAL       0x02000000
 
 /* DMA CRS Control and Status Register Mapping */
index 0e8937c1184af811490bf232a05a100af06a9373..da32d6037e3e4baacfe2d9ef4723029873d641e7 100644 (file)
 #include "dwmac1000.h"
 #include "dwmac_dma.h"
 
-static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-                             int burst_len, u32 dma_tx, u32 dma_rx, int atds)
+static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
 {
-       u32 value = readl(ioaddr + DMA_BUS_MODE);
-       int limit;
+       u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
+       int i;
 
-       /* DMA SW reset */
-       value |= DMA_BUS_MODE_SFT_RESET;
-       writel(value, ioaddr + DMA_BUS_MODE);
-       limit = 10;
-       while (limit--) {
-               if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
+       pr_info("dwmac1000: Master AXI performs %s burst length\n",
+               !(value & DMA_AXI_UNDEF) ? "fixed" : "any");
+
+       if (axi->axi_lpi_en)
+               value |= DMA_AXI_EN_LPI;
+       if (axi->axi_xit_frm)
+               value |= DMA_AXI_LPI_XIT_FRM;
+
+       value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
+                DMA_AXI_WR_OSR_LMT_SHIFT;
+
+       value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
+                DMA_AXI_RD_OSR_LMT_SHIFT;
+
+       /* Depending on the UNDEF bit the Master AXI will perform any burst
+        * length according to the BLEN programmed (by default all BLEN are
+        * set).
+        */
+       for (i = 0; i < AXI_BLEN; i++) {
+               switch (axi->axi_blen[i]) {
+               case 256:
+                       value |= DMA_AXI_BLEN256;
                        break;
-               mdelay(10);
+               case 128:
+                       value |= DMA_AXI_BLEN128;
+                       break;
+               case 64:
+                       value |= DMA_AXI_BLEN64;
+                       break;
+               case 32:
+                       value |= DMA_AXI_BLEN32;
+                       break;
+               case 16:
+                       value |= DMA_AXI_BLEN16;
+                       break;
+               case 8:
+                       value |= DMA_AXI_BLEN8;
+                       break;
+               case 4:
+                       value |= DMA_AXI_BLEN4;
+                       break;
+               }
        }
-       if (limit < 0)
-               return -EBUSY;
+
+       writel(value, ioaddr + DMA_AXI_BUS_MODE);
+}
+
+static void dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+                              int aal, u32 dma_tx, u32 dma_rx, int atds)
+{
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
 
        /*
-        * Set the DMA PBL (Programmable Burst Length) mode
-        * Before stmmac core 3.50 this mode bit was 4xPBL, and
+        * Set the DMA PBL (Programmable Burst Length) mode.
+        *
+        * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
         * post 3.5 mode bit acts as 8*PBL.
-        * For core rev < 3.5, when the core is set for 4xPBL mode, the
-        * DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats
-        * depending on pbl value.
-        * For core rev > 3.5, when the core is set for 8xPBL mode, the
-        * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
-        * depending on pbl value.
+        *
+        * This configuration doesn't take care about the Separate PBL
+        * so only the bits: 13-8 are programmed with the PBL passed from the
+        * platform.
         */
-       value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
-                                   (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+       value |= DMA_BUS_MODE_MAXPBL;
+       value &= ~DMA_BUS_MODE_PBL_MASK;
+       value |= (pbl << DMA_BUS_MODE_PBL_SHIFT);
 
        /* Set the Fixed burst mode */
        if (fb)
@@ -73,26 +112,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
        if (atds)
                value |= DMA_BUS_MODE_ATDS;
 
-       writel(value, ioaddr + DMA_BUS_MODE);
+       if (aal)
+               value |= DMA_BUS_MODE_AAL;
 
-       /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
-        * for supported bursts.
-        *
-        * Note: This is applicable only for revision GMACv3.61a. For
-        * older version this register is reserved and shall have no
-        * effect.
-        *
-        * Note:
-        *  For Fixed Burst Mode: if we directly write 0xFF to this
-        *  register using the configurations pass from platform code,
-        *  this would ensure that all bursts supported by core are set
-        *  and those which are not supported would remain ineffective.
-        *
-        *  For Non Fixed Burst Mode: provide the maximum value of the
-        *  burst length. Any burst equal or below the provided burst
-        *  length would be allowed to perform.
-        */
-       writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
+       writel(value, ioaddr + DMA_BUS_MODE);
 
        /* Mask interrupts by writing to CSR7 */
        writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
@@ -102,8 +125,6 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
         */
        writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
        writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
-
-       return 0;
 }
 
 static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
@@ -205,7 +226,9 @@ static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
 }
 
 const struct stmmac_dma_ops dwmac1000_dma_ops = {
+       .reset = dwmac_dma_reset,
        .init = dwmac1000_dma_init,
+       .axi = dwmac1000_dma_axi,
        .dump_regs = dwmac1000_dump_dma_regs,
        .dma_mode = dwmac1000_dma_operation_mode,
        .enable_dma_transmission = dwmac_enable_dma_transmission,
index 9d0971c1c2ee852fa726262e071c0d88857d738b..61f54c99a7de9ebf0da2db75b6f509900346ea07 100644 (file)
 #include "dwmac100.h"
 #include "dwmac_dma.h"
 
-static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-                            int burst_len, u32 dma_tx, u32 dma_rx, int atds)
+static void dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+                             int aal, u32 dma_tx, u32 dma_rx, int atds)
 {
-       u32 value = readl(ioaddr + DMA_BUS_MODE);
-       int limit;
-
-       /* DMA SW reset */
-       value |= DMA_BUS_MODE_SFT_RESET;
-       writel(value, ioaddr + DMA_BUS_MODE);
-       limit = 10;
-       while (limit--) {
-               if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
-                       break;
-               mdelay(10);
-       }
-       if (limit < 0)
-               return -EBUSY;
-
        /* Enable Application Access by writing to DMA CSR0 */
        writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
               ioaddr + DMA_BUS_MODE);
@@ -62,8 +47,6 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
         */
        writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
        writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
-
-       return 0;
 }
 
 /* Store and Forward capability is not used at all.
@@ -131,6 +114,7 @@ static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
 }
 
 const struct stmmac_dma_ops dwmac100_dma_ops = {
+       .reset = dwmac_dma_reset,
        .init = dwmac100_dma_init,
        .dump_regs = dwmac100_dump_dma_regs,
        .dma_mode = dwmac100_dma_operation_mode,
index def266da55dbe617e8be83f7a3d630f8230b9c5c..726d9d9aaf83dce9c91ab307791fc594642e389f 100644 (file)
 #define DMA_CONTROL            0x00001018      /* Ctrl (Operational Mode) */
 #define DMA_INTR_ENA           0x0000101c      /* Interrupt Enable */
 #define DMA_MISSED_FRAME_CTR   0x00001020      /* Missed Frame Counter */
+
+/* SW Reset */
+#define DMA_BUS_MODE_SFT_RESET 0x00000001      /* Software Reset */
+
 /* Rx watchdog register */
 #define DMA_RX_WATCHDOG                0x00001024
-/* AXI Bus Mode */
+
+/* AXI Master Bus Mode */
 #define DMA_AXI_BUS_MODE       0x00001028
+
+#define DMA_AXI_EN_LPI         BIT(31)
+#define DMA_AXI_LPI_XIT_FRM    BIT(30)
+#define DMA_AXI_WR_OSR_LMT     GENMASK(23, 20)
+#define DMA_AXI_WR_OSR_LMT_SHIFT       20
+#define DMA_AXI_WR_OSR_LMT_MASK        0xf
+#define DMA_AXI_RD_OSR_LMT     GENMASK(19, 16)
+#define DMA_AXI_RD_OSR_LMT_SHIFT       16
+#define DMA_AXI_RD_OSR_LMT_MASK        0xf
+
+#define DMA_AXI_OSR_MAX                0xf
+#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
+                              (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
+#define        DMA_AXI_1KBBE           BIT(13)
+#define DMA_AXI_AAL            BIT(12)
+#define DMA_AXI_BLEN256                BIT(7)
+#define DMA_AXI_BLEN128                BIT(6)
+#define DMA_AXI_BLEN64         BIT(5)
+#define DMA_AXI_BLEN32         BIT(4)
+#define DMA_AXI_BLEN16         BIT(3)
+#define DMA_AXI_BLEN8          BIT(2)
+#define DMA_AXI_BLEN4          BIT(1)
+#define DMA_BURST_LEN_DEFAULT  (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
+                                DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
+                                DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
+                                DMA_AXI_BLEN4)
+
+#define DMA_AXI_UNDEF          BIT(0)
+
+#define DMA_AXI_BURST_LEN_MASK 0x000000FE
+
 #define DMA_CUR_TX_BUF_ADDR    0x00001050      /* Current Host Tx Buffer */
 #define DMA_CUR_RX_BUF_ADDR    0x00001054      /* Current Host Rx Buffer */
 #define DMA_HW_FEATURE         0x00001058      /* HW Feature Register */
@@ -112,5 +148,6 @@ void dwmac_dma_stop_tx(void __iomem *ioaddr);
 void dwmac_dma_start_rx(void __iomem *ioaddr);
 void dwmac_dma_stop_rx(void __iomem *ioaddr);
 int dwmac_dma_interrupt(void __iomem *ioaddr, struct stmmac_extra_stats *x);
+int dwmac_dma_reset(void __iomem *ioaddr);
 
 #endif /* __DWMAC_DMA_H__ */
index 484e3cf9c414f9427aa96144f80f6650ce0dd651..84e3e84cec7d33dddf13e0fc83e235d1e181cbda 100644 (file)
 
 #define GMAC_HI_REG_AE         0x80000000
 
+int dwmac_dma_reset(void __iomem *ioaddr)
+{
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
+       int limit;
+
+       /* DMA SW reset */
+       value |= DMA_BUS_MODE_SFT_RESET;
+       writel(value, ioaddr + DMA_BUS_MODE);
+       limit = 10;
+       while (limit--) {
+               if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
+                       break;
+               mdelay(10);
+       }
+
+       if (limit < 0)
+               return -EBUSY;
+
+       return 0;
+}
+
 /* CSR1 enables the transmit DMA to check for new descriptor */
 void dwmac_enable_dma_transmission(void __iomem *ioaddr)
 {
index 7d944449f5eff9b16c4d7cf633f0cd4d2eb9b879..cfb018c7c5eb11be4f05ccab998474c442d65a76 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
   This contains the functions to handle the enhanced descriptors.
 
-  Copyright (C) 2007-2009  STMicroelectronics Ltd
+  Copyright (C) 2007-2014  STMicroelectronics Ltd
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
                                  struct dma_desc *p, void __iomem *ioaddr)
 {
-       int ret = 0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
+       unsigned int tdes0 = p->des0;
+       int ret = tx_done;
 
-       if (unlikely(p->des01.etx.error_summary)) {
-               if (unlikely(p->des01.etx.jabber_timeout))
+       /* Get tx owner first */
+       if (unlikely(tdes0 & ETDES0_OWN))
+               return tx_dma_own;
+
+       /* Verify tx error by looking at the last segment. */
+       if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
+               return tx_not_ls;
+
+       if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
+               if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
                        x->tx_jabber++;
 
-               if (unlikely(p->des01.etx.frame_flushed)) {
+               if (unlikely(tdes0 & ETDES0_FRAME_FLUSHED)) {
                        x->tx_frame_flushed++;
                        dwmac_dma_flush_tx_fifo(ioaddr);
                }
 
-               if (unlikely(p->des01.etx.loss_carrier)) {
+               if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
                        x->tx_losscarrier++;
                        stats->tx_carrier_errors++;
                }
-               if (unlikely(p->des01.etx.no_carrier)) {
+               if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
                        x->tx_carrier++;
                        stats->tx_carrier_errors++;
                }
-               if (unlikely(p->des01.etx.late_collision))
-                       stats->collisions += p->des01.etx.collision_count;
-
-               if (unlikely(p->des01.etx.excessive_collisions))
-                       stats->collisions += p->des01.etx.collision_count;
+               if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
+                            (tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
+                       stats->collisions +=
+                               (tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
 
-               if (unlikely(p->des01.etx.excessive_deferral))
+               if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
                        x->tx_deferred++;
 
-               if (unlikely(p->des01.etx.underflow_error)) {
+               if (unlikely(tdes0 & ETDES0_UNDERFLOW_ERROR)) {
                        dwmac_dma_flush_tx_fifo(ioaddr);
                        x->tx_underflow++;
                }
 
-               if (unlikely(p->des01.etx.ip_header_error))
+               if (unlikely(tdes0 & ETDES0_IP_HEADER_ERROR))
                        x->tx_ip_header_error++;
 
-               if (unlikely(p->des01.etx.payload_error)) {
+               if (unlikely(tdes0 & ETDES0_PAYLOAD_ERROR)) {
                        x->tx_payload_error++;
                        dwmac_dma_flush_tx_fifo(ioaddr);
                }
 
-               ret = -1;
+               ret = tx_err;
        }
 
-       if (unlikely(p->des01.etx.deferred))
+       if (unlikely(tdes0 & ETDES0_DEFERRED))
                x->tx_deferred++;
 
 #ifdef STMMAC_VLAN_TAG_USED
-       if (p->des01.etx.vlan_frame)
+       if (tdes0 & ETDES0_VLAN_FRAME)
                x->tx_vlan++;
 #endif
 
@@ -87,7 +95,7 @@ static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
 
 static int enh_desc_get_tx_len(struct dma_desc *p)
 {
-       return p->des01.etx.buffer1_size;
+       return (p->des1 & ETDES1_BUFFER1_SIZE_MASK);
 }
 
 static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
@@ -126,50 +134,55 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
 static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
                                    struct dma_extended_desc *p)
 {
-       if (unlikely(p->basic.des01.erx.rx_mac_addr)) {
-               if (p->des4.erx.ip_hdr_err)
+       unsigned int rdes0 = p->basic.des0;
+       unsigned int rdes4 = p->des4;
+
+       if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
+               int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
+
+               if (rdes4 & ERDES4_IP_HDR_ERR)
                        x->ip_hdr_err++;
-               if (p->des4.erx.ip_payload_err)
+               if (rdes4 & ERDES4_IP_PAYLOAD_ERR)
                        x->ip_payload_err++;
-               if (p->des4.erx.ip_csum_bypassed)
+               if (rdes4 & ERDES4_IP_CSUM_BYPASSED)
                        x->ip_csum_bypassed++;
-               if (p->des4.erx.ipv4_pkt_rcvd)
+               if (rdes4 & ERDES4_IPV4_PKT_RCVD)
                        x->ipv4_pkt_rcvd++;
-               if (p->des4.erx.ipv6_pkt_rcvd)
+               if (rdes4 & ERDES4_IPV6_PKT_RCVD)
                        x->ipv6_pkt_rcvd++;
-               if (p->des4.erx.msg_type == RDES_EXT_SYNC)
+               if (message_type == RDES_EXT_SYNC)
                        x->rx_msg_type_sync++;
-               else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
+               else if (message_type == RDES_EXT_FOLLOW_UP)
                        x->rx_msg_type_follow_up++;
-               else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+               else if (message_type == RDES_EXT_DELAY_REQ)
                        x->rx_msg_type_delay_req++;
-               else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
+               else if (message_type == RDES_EXT_DELAY_RESP)
                        x->rx_msg_type_delay_resp++;
-               else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_REQ)
+               else if (message_type == RDES_EXT_PDELAY_REQ)
                        x->rx_msg_type_pdelay_req++;
-               else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
+               else if (message_type == RDES_EXT_PDELAY_RESP)
                        x->rx_msg_type_pdelay_resp++;
-               else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
+               else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
                        x->rx_msg_type_pdelay_follow_up++;
                else
                        x->rx_msg_type_ext_no_ptp++;
-               if (p->des4.erx.ptp_frame_type)
+               if (rdes4 & ERDES4_PTP_FRAME_TYPE)
                        x->ptp_frame_type++;
-               if (p->des4.erx.ptp_ver)
+               if (rdes4 & ERDES4_PTP_VER)
                        x->ptp_ver++;
-               if (p->des4.erx.timestamp_dropped)
+               if (rdes4 & ERDES4_TIMESTAMP_DROPPED)
                        x->timestamp_dropped++;
-               if (p->des4.erx.av_pkt_rcvd)
+               if (rdes4 & ERDES4_AV_PKT_RCVD)
                        x->av_pkt_rcvd++;
-               if (p->des4.erx.av_tagged_pkt_rcvd)
+               if (rdes4 & ERDES4_AV_TAGGED_PKT_RCVD)
                        x->av_tagged_pkt_rcvd++;
-               if (p->des4.erx.vlan_tag_priority_val)
+               if ((rdes4 & ERDES4_VLAN_TAG_PRI_VAL_MASK) >> 18)
                        x->vlan_tag_priority_val++;
-               if (p->des4.erx.l3_filter_match)
+               if (rdes4 & ERDES4_L3_FILTER_MATCH)
                        x->l3_filter_match++;
-               if (p->des4.erx.l4_filter_match)
+               if (rdes4 & ERDES4_L4_FILTER_MATCH)
                        x->l4_filter_match++;
-               if (p->des4.erx.l3_l4_filter_no_match)
+               if ((rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK) >> 26)
                        x->l3_l4_filter_no_match++;
        }
 }
@@ -177,30 +190,33 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
 static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
                                  struct dma_desc *p)
 {
-       int ret = good_frame;
        struct net_device_stats *stats = (struct net_device_stats *)data;
+       unsigned int rdes0 = p->des0;
+       int ret = good_frame;
+
+       if (unlikely(rdes0 & RDES0_OWN))
+               return dma_own;
 
-       if (unlikely(p->des01.erx.error_summary)) {
-               if (unlikely(p->des01.erx.descriptor_error)) {
+       if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
+               if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
                        x->rx_desc++;
                        stats->rx_length_errors++;
                }
-               if (unlikely(p->des01.erx.overflow_error))
+               if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
                        x->rx_gmac_overflow++;
 
-               if (unlikely(p->des01.erx.ipc_csum_error))
+               if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
                        pr_err("\tIPC Csum Error/Giant frame\n");
 
-               if (unlikely(p->des01.erx.late_collision)) {
+               if (unlikely(rdes0 & RDES0_COLLISION))
                        stats->collisions++;
-               }
-               if (unlikely(p->des01.erx.receive_watchdog))
+               if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
                        x->rx_watchdog++;
 
-               if (unlikely(p->des01.erx.error_gmii))
+               if (unlikely(rdes0 & RDES0_MII_ERROR))  /* GMII */
                        x->rx_mii++;
 
-               if (unlikely(p->des01.erx.crc_error)) {
+               if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
                        x->rx_crc++;
                        stats->rx_crc_errors++;
                }
@@ -211,26 +227,27 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
         * It doesn't match with the information reported into the databook.
         * At any rate, we need to understand if the CSUM hw computation is ok
         * and report this info to the upper layers. */
-       ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
-               p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
+       ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
+                                !!(rdes0 & RDES0_FRAME_TYPE),
+                                !!(rdes0 & ERDES0_RX_MAC_ADDR));
 
-       if (unlikely(p->des01.erx.dribbling))
+       if (unlikely(rdes0 & RDES0_DRIBBLING))
                x->dribbling_bit++;
 
-       if (unlikely(p->des01.erx.sa_filter_fail)) {
+       if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
                x->sa_rx_filter_fail++;
                ret = discard_frame;
        }
-       if (unlikely(p->des01.erx.da_filter_fail)) {
+       if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
                x->da_rx_filter_fail++;
                ret = discard_frame;
        }
-       if (unlikely(p->des01.erx.length_error)) {
+       if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
                x->rx_length++;
                ret = discard_frame;
        }
 #ifdef STMMAC_VLAN_TAG_USED
-       if (p->des01.erx.vlan_tag)
+       if (rdes0 & RDES0_VLAN_TAG)
                x->rx_vlan++;
 #endif
 
@@ -240,110 +257,125 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
 static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
                                  int mode, int end)
 {
-       p->des01.all_flags = 0;
-       p->des01.erx.own = 1;
-       p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
+       p->des0 |= RDES0_OWN;
+       p->des1 |= ((BUF_SIZE_8KiB - 1) & ERDES1_BUFFER1_SIZE_MASK);
 
        if (mode == STMMAC_CHAIN_MODE)
-               ehn_desc_rx_set_on_chain(p, end);
+               ehn_desc_rx_set_on_chain(p);
        else
                ehn_desc_rx_set_on_ring(p, end);
 
        if (disable_rx_ic)
-               p->des01.erx.disable_ic = 1;
+               p->des1 |= ERDES1_DISABLE_IC;
 }
 
 static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
 {
-       p->des01.all_flags = 0;
+       p->des0 &= ~ETDES0_OWN;
        if (mode == STMMAC_CHAIN_MODE)
-               ehn_desc_tx_set_on_chain(p, end);
+               enh_desc_end_tx_desc_on_chain(p);
        else
-               ehn_desc_tx_set_on_ring(p, end);
+               enh_desc_end_tx_desc_on_ring(p, end);
 }
 
 static int enh_desc_get_tx_owner(struct dma_desc *p)
 {
-       return p->des01.etx.own;
-}
-
-static int enh_desc_get_rx_owner(struct dma_desc *p)
-{
-       return p->des01.erx.own;
+       return (p->des0 & ETDES0_OWN) >> 31;
 }
 
 static void enh_desc_set_tx_owner(struct dma_desc *p)
 {
-       p->des01.etx.own = 1;
+       p->des0 |= ETDES0_OWN;
 }
 
 static void enh_desc_set_rx_owner(struct dma_desc *p)
 {
-       p->des01.erx.own = 1;
+       p->des0 |= RDES0_OWN;
 }
 
 static int enh_desc_get_tx_ls(struct dma_desc *p)
 {
-       return p->des01.etx.last_segment;
+       return (p->des0 & ETDES0_LAST_SEGMENT) >> 29;
 }
 
 static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
 {
-       int ter = p->des01.etx.end_ring;
+       int ter = (p->des0 & ETDES0_END_RING) >> 21;
 
        memset(p, 0, offsetof(struct dma_desc, des2));
        if (mode == STMMAC_CHAIN_MODE)
-               enh_desc_end_tx_desc_on_chain(p, ter);
+               enh_desc_end_tx_desc_on_chain(p);
        else
                enh_desc_end_tx_desc_on_ring(p, ter);
 }
 
 static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-                                    int csum_flag, int mode)
+                                    bool csum_flag, int mode, bool tx_own,
+                                    bool ls)
 {
-       p->des01.etx.first_segment = is_fs;
+       unsigned int tdes0 = p->des0;
 
        if (mode == STMMAC_CHAIN_MODE)
                enh_set_tx_desc_len_on_chain(p, len);
        else
                enh_set_tx_desc_len_on_ring(p, len);
 
+       if (is_fs)
+               tdes0 |= ETDES0_FIRST_SEGMENT;
+       else
+               tdes0 &= ~ETDES0_FIRST_SEGMENT;
+
        if (likely(csum_flag))
-               p->des01.etx.checksum_insertion = cic_full;
-}
+               tdes0 |= (TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
+       else
+               tdes0 &= ~(TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
 
-static void enh_desc_clear_tx_ic(struct dma_desc *p)
-{
-       p->des01.etx.interrupt = 0;
+       if (ls)
+               tdes0 |= ETDES0_LAST_SEGMENT;
+
+       /* Finally set the OWN bit. Later the DMA will start! */
+       if (tx_own)
+               tdes0 |= ETDES0_OWN;
+
+       if (is_fs & tx_own)
+               /* When the own bit, for the first frame, has to be set, all
+                * descriptors for the same frame has to be set before, to
+                * avoid race condition.
+                */
+               wmb();
+
+       p->des0 = tdes0;
 }
 
-static void enh_desc_close_tx_desc(struct dma_desc *p)
+static void enh_desc_set_tx_ic(struct dma_desc *p)
 {
-       p->des01.etx.last_segment = 1;
-       p->des01.etx.interrupt = 1;
+       p->des0 |= ETDES0_INTERRUPT;
 }
 
 static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
 {
+       unsigned int csum = 0;
        /* The type-1 checksum offload engines append the checksum at
         * the end of frame and the two bytes of checksum are added in
         * the length.
         * Adjust for that in the framelen for type-1 checksum offload
-        * engines. */
+        * engines.
+        */
        if (rx_coe_type == STMMAC_RX_COE_TYPE1)
-               return p->des01.erx.frame_length - 2;
-       else
-               return p->des01.erx.frame_length;
+               csum = 2;
+
+       return (((p->des0 & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT) -
+               csum);
 }
 
 static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
 {
-       p->des01.etx.time_stamp_enable = 1;
+       p->des0 |= ETDES0_TIME_STAMP_ENABLE;
 }
 
 static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
 {
-       return p->des01.etx.time_stamp_status;
+       return (p->des0 & ETDES0_TIME_STAMP_STATUS) >> 17;
 }
 
 static u64 enh_desc_get_timestamp(void *desc, u32 ats)
@@ -368,7 +400,7 @@ static int enh_desc_get_rx_timestamp_status(void *desc, u32 ats)
 {
        if (ats) {
                struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
-               return p->basic.des01.erx.ipc_csum_error;
+               return (p->basic.des0 & RDES0_IPC_CSUM_ERROR) >> 7;
        } else {
                struct dma_desc *p = (struct dma_desc *)desc;
                if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
@@ -386,11 +418,9 @@ const struct stmmac_desc_ops enh_desc_ops = {
        .init_rx_desc = enh_desc_init_rx_desc,
        .init_tx_desc = enh_desc_init_tx_desc,
        .get_tx_owner = enh_desc_get_tx_owner,
-       .get_rx_owner = enh_desc_get_rx_owner,
        .release_tx_desc = enh_desc_release_tx_desc,
        .prepare_tx_desc = enh_desc_prepare_tx_desc,
-       .clear_tx_ic = enh_desc_clear_tx_ic,
-       .close_tx_desc = enh_desc_close_tx_desc,
+       .set_tx_ic = enh_desc_set_tx_ic,
        .get_tx_ls = enh_desc_get_tx_ls,
        .set_tx_owner = enh_desc_set_tx_owner,
        .set_rx_owner = enh_desc_set_rx_owner,
index 48c3456445b282597b89f73cd39b78d5e5caf982..e13228f115f036ce2bf6c5f38878c5e16640988d 100644 (file)
 static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
                               struct dma_desc *p, void __iomem *ioaddr)
 {
-       int ret = 0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
+       unsigned int tdes0 = p->des0;
+       unsigned int tdes1 = p->des1;
+       int ret = tx_done;
 
-       if (unlikely(p->des01.tx.error_summary)) {
-               if (unlikely(p->des01.tx.underflow_error)) {
+       /* Get tx owner first */
+       if (unlikely(tdes0 & TDES0_OWN))
+               return tx_dma_own;
+
+       /* Verify tx error by looking at the last segment. */
+       if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
+               return tx_not_ls;
+
+       if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
+               if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
                        x->tx_underflow++;
                        stats->tx_fifo_errors++;
                }
-               if (unlikely(p->des01.tx.no_carrier)) {
+               if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
                        x->tx_carrier++;
                        stats->tx_carrier_errors++;
                }
-               if (unlikely(p->des01.tx.loss_carrier)) {
+               if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
                        x->tx_losscarrier++;
                        stats->tx_carrier_errors++;
                }
-               if (unlikely((p->des01.tx.excessive_deferral) ||
-                            (p->des01.tx.excessive_collisions) ||
-                            (p->des01.tx.late_collision)))
-                       stats->collisions += p->des01.tx.collision_count;
-               ret = -1;
+               if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
+                            (tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
+                            (tdes0 & TDES0_LATE_COLLISION))) {
+                       unsigned int collisions;
+
+                       collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
+                       stats->collisions += collisions;
+               }
+               ret = tx_err;
        }
 
-       if (p->des01.etx.vlan_frame)
+       if (tdes0 & TDES0_VLAN_FRAME)
                x->tx_vlan++;
 
-       if (unlikely(p->des01.tx.deferred))
+       if (unlikely(tdes0 & TDES0_DEFERRED))
                x->tx_deferred++;
 
        return ret;
@@ -63,7 +77,7 @@ static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
 
 static int ndesc_get_tx_len(struct dma_desc *p)
 {
-       return p->des01.tx.buffer1_size;
+       return (p->des1 & RDES1_BUFFER1_SIZE_MASK);
 }
 
 /* This function verifies if each incoming frame has some errors
@@ -74,47 +88,51 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
                               struct dma_desc *p)
 {
        int ret = good_frame;
+       unsigned int rdes0 = p->des0;
        struct net_device_stats *stats = (struct net_device_stats *)data;
 
-       if (unlikely(p->des01.rx.last_descriptor == 0)) {
+       if (unlikely(rdes0 & RDES0_OWN))
+               return dma_own;
+
+       if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
                pr_warn("%s: Oversized frame spanned multiple buffers\n",
                        __func__);
                stats->rx_length_errors++;
                return discard_frame;
        }
 
-       if (unlikely(p->des01.rx.error_summary)) {
-               if (unlikely(p->des01.rx.descriptor_error))
+       if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
+               if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
                        x->rx_desc++;
-               if (unlikely(p->des01.rx.sa_filter_fail))
+               if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
                        x->sa_filter_fail++;
-               if (unlikely(p->des01.rx.overflow_error))
+               if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
                        x->overflow_error++;
-               if (unlikely(p->des01.rx.ipc_csum_error))
+               if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
                        x->ipc_csum_error++;
-               if (unlikely(p->des01.rx.collision)) {
+               if (unlikely(rdes0 & RDES0_COLLISION)) {
                        x->rx_collision++;
                        stats->collisions++;
                }
-               if (unlikely(p->des01.rx.crc_error)) {
+               if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
                        x->rx_crc++;
                        stats->rx_crc_errors++;
                }
                ret = discard_frame;
        }
-       if (unlikely(p->des01.rx.dribbling))
+       if (unlikely(rdes0 & RDES0_DRIBBLING))
                x->dribbling_bit++;
 
-       if (unlikely(p->des01.rx.length_error)) {
+       if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
                x->rx_length++;
                ret = discard_frame;
        }
-       if (unlikely(p->des01.rx.mii_error)) {
+       if (unlikely(rdes0 & RDES0_MII_ERROR)) {
                x->rx_mii++;
                ret = discard_frame;
        }
 #ifdef STMMAC_VLAN_TAG_USED
-       if (p->des01.rx.vlan_tag)
+       if (rdes0 & RDES0_VLAN_TAG)
                x->vlan_tag++;
 #endif
        return ret;
@@ -123,9 +141,8 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
 static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
                               int end)
 {
-       p->des01.all_flags = 0;
-       p->des01.rx.own = 1;
-       p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+       p->des0 |= RDES0_OWN;
+       p->des1 |= (BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK;
 
        if (mode == STMMAC_CHAIN_MODE)
                ndesc_rx_set_on_chain(p, end);
@@ -133,99 +150,110 @@ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
                ndesc_rx_set_on_ring(p, end);
 
        if (disable_rx_ic)
-               p->des01.rx.disable_ic = 1;
+               p->des1 |= RDES1_DISABLE_IC;
 }
 
 static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
 {
-       p->des01.all_flags = 0;
+       p->des0 &= ~TDES0_OWN;
        if (mode == STMMAC_CHAIN_MODE)
-               ndesc_tx_set_on_chain(p, end);
+               ndesc_tx_set_on_chain(p);
        else
-               ndesc_tx_set_on_ring(p, end);
+               ndesc_end_tx_desc_on_ring(p, end);
 }
 
 static int ndesc_get_tx_owner(struct dma_desc *p)
 {
-       return p->des01.tx.own;
-}
-
-static int ndesc_get_rx_owner(struct dma_desc *p)
-{
-       return p->des01.rx.own;
+       return (p->des0 & TDES0_OWN) >> 31;
 }
 
 static void ndesc_set_tx_owner(struct dma_desc *p)
 {
-       p->des01.tx.own = 1;
+       p->des0 |= TDES0_OWN;
 }
 
 static void ndesc_set_rx_owner(struct dma_desc *p)
 {
-       p->des01.rx.own = 1;
+       p->des0 |= RDES0_OWN;
 }
 
 static int ndesc_get_tx_ls(struct dma_desc *p)
 {
-       return p->des01.tx.last_segment;
+       return (p->des1 & TDES1_LAST_SEGMENT) >> 30;
 }
 
 static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 {
-       int ter = p->des01.tx.end_ring;
+       int ter = (p->des1 & TDES1_END_RING) >> 25;
 
        memset(p, 0, offsetof(struct dma_desc, des2));
        if (mode == STMMAC_CHAIN_MODE)
-               ndesc_end_tx_desc_on_chain(p, ter);
+               ndesc_tx_set_on_chain(p);
        else
                ndesc_end_tx_desc_on_ring(p, ter);
 }
 
 static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
-                                 int csum_flag, int mode)
+                                 bool csum_flag, int mode, bool tx_own,
+                                 bool ls)
 {
-       p->des01.tx.first_segment = is_fs;
+       unsigned int tdes1 = p->des1;
+
        if (mode == STMMAC_CHAIN_MODE)
                norm_set_tx_desc_len_on_chain(p, len);
        else
                norm_set_tx_desc_len_on_ring(p, len);
 
+       if (is_fs)
+               tdes1 |= TDES1_FIRST_SEGMENT;
+       else
+               tdes1 &= ~TDES1_FIRST_SEGMENT;
+
        if (likely(csum_flag))
-               p->des01.tx.checksum_insertion = cic_full;
-}
+               tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT;
+       else
+               tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT);
 
-static void ndesc_clear_tx_ic(struct dma_desc *p)
-{
-       p->des01.tx.interrupt = 0;
+       if (ls)
+               tdes1 |= TDES1_LAST_SEGMENT;
+
+       if (tx_own)
+               tdes1 |= TDES0_OWN;
+
+       p->des1 = tdes1;
 }
 
-static void ndesc_close_tx_desc(struct dma_desc *p)
+static void ndesc_set_tx_ic(struct dma_desc *p)
 {
-       p->des01.tx.last_segment = 1;
-       p->des01.tx.interrupt = 1;
+       p->des1 |= TDES1_INTERRUPT;
 }
 
 static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
 {
+       unsigned int csum = 0;
+
        /* The type-1 checksum offload engines append the checksum at
         * the end of frame and the two bytes of checksum are added in
         * the length.
         * Adjust for that in the framelen for type-1 checksum offload
-        * engines. */
+        * engines
+        */
        if (rx_coe_type == STMMAC_RX_COE_TYPE1)
-               return p->des01.rx.frame_length - 2;
-       else
-               return p->des01.rx.frame_length;
+               csum = 2;
+
+       return (((p->des0 & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT) -
+               csum);
+
 }
 
 static void ndesc_enable_tx_timestamp(struct dma_desc *p)
 {
-       p->des01.tx.time_stamp_enable = 1;
+       p->des1 |= TDES1_TIME_STAMP_ENABLE;
 }
 
 static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
 {
-       return p->des01.tx.time_stamp_status;
+       return (p->des0 & TDES0_TIME_STAMP_STATUS) >> 17;
 }
 
 static u64 ndesc_get_timestamp(void *desc, u32 ats)
@@ -258,11 +286,9 @@ const struct stmmac_desc_ops ndesc_ops = {
        .init_rx_desc = ndesc_init_rx_desc,
        .init_tx_desc = ndesc_init_tx_desc,
        .get_tx_owner = ndesc_get_tx_owner,
-       .get_rx_owner = ndesc_get_rx_owner,
        .release_tx_desc = ndesc_release_tx_desc,
        .prepare_tx_desc = ndesc_prepare_tx_desc,
-       .clear_tx_ic = ndesc_clear_tx_ic,
-       .close_tx_desc = ndesc_close_tx_desc,
+       .set_tx_ic = ndesc_set_tx_ic,
        .get_tx_ls = ndesc_get_tx_ls,
        .set_tx_owner = ndesc_set_tx_owner,
        .set_rx_owner = ndesc_set_rx_owner,
index 5dd50c6cda5be0280e235152057a329a89fb187c..7723b5d2499a1f8e7111d0e74eb8e5634726b30f 100644 (file)
@@ -31,8 +31,7 @@
 static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)p;
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int entry = priv->cur_tx % txsize;
+       unsigned int entry = priv->cur_tx;
        struct dma_desc *desc;
        unsigned int nopaged_len = skb_headlen(skb);
        unsigned int bmax, len;
@@ -57,12 +56,14 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        return -1;
 
                priv->tx_skbuff_dma[entry].buf = desc->des2;
+               priv->tx_skbuff_dma[entry].len = bmax;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
+
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
-                                               STMMAC_RING_MODE);
-               wmb();
+                                               STMMAC_RING_MODE, 0, false);
                priv->tx_skbuff[entry] = NULL;
-               entry = (++priv->cur_tx) % txsize;
+               entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
 
                if (priv->extend_desc)
                        desc = (struct dma_desc *)(priv->dma_etx + entry);
@@ -74,22 +75,27 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                if (dma_mapping_error(priv->device, desc->des2))
                        return -1;
                priv->tx_skbuff_dma[entry].buf = desc->des2;
+               priv->tx_skbuff_dma[entry].len = len;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
+
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
-                                               STMMAC_RING_MODE);
-               wmb();
-               priv->hw->desc->set_tx_owner(desc);
+                                               STMMAC_RING_MODE, 1, true);
        } else {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            nopaged_len, DMA_TO_DEVICE);
                if (dma_mapping_error(priv->device, desc->des2))
                        return -1;
                priv->tx_skbuff_dma[entry].buf = desc->des2;
+               priv->tx_skbuff_dma[entry].len = nopaged_len;
+               priv->tx_skbuff_dma[entry].is_jumbo = true;
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
-                                               STMMAC_RING_MODE);
+                                               STMMAC_RING_MODE, 0, true);
        }
 
+       priv->cur_tx = entry;
+
        return entry;
 }
 
@@ -120,7 +126,13 @@ static void stmmac_init_desc3(struct dma_desc *p)
 
 static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
 {
-       if (unlikely(p->des3))
+       struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+       unsigned int entry = priv->dirty_tx;
+
+       /* des3 is only used for jumbo frames tx or time stamping */
+       if (unlikely(priv->tx_skbuff_dma[entry].is_jumbo ||
+                    (priv->tx_skbuff_dma[entry].last_segment &&
+                     !priv->extend_desc && priv->hwts_tx_en)))
                p->des3 = 0;
 }
 
index 1f3b33a6c6a8f8bd68f1b2313bc9ea93eb470ed4..8bbab97895fe28dde63645af93d58b112a512ed2 100644 (file)
@@ -24,7 +24,7 @@
 #define __STMMAC_H__
 
 #define STMMAC_RESOURCE_NAME   "stmmaceth"
-#define DRV_MODULE_VERSION     "March_2013"
+#define DRV_MODULE_VERSION     "Oct_2015"
 
 #include <linux/clk.h>
 #include <linux/stmmac.h>
@@ -45,6 +45,9 @@ struct stmmac_resources {
 struct stmmac_tx_info {
        dma_addr_t buf;
        bool map_as_page;
+       unsigned len;
+       bool last_segment;
+       bool is_jumbo;
 };
 
 struct stmmac_priv {
@@ -54,7 +57,6 @@ struct stmmac_priv {
        struct sk_buff **tx_skbuff;
        unsigned int cur_tx;
        unsigned int dirty_tx;
-       unsigned int dma_tx_size;
        u32 tx_count_frames;
        u32 tx_coal_frames;
        u32 tx_coal_timer;
@@ -71,8 +73,9 @@ struct stmmac_priv {
        struct sk_buff **rx_skbuff;
        unsigned int cur_rx;
        unsigned int dirty_rx;
-       unsigned int dma_rx_size;
        unsigned int dma_buf_sz;
+       unsigned int rx_copybreak;
+       unsigned int rx_zeroc_thresh;
        u32 rx_riwt;
        int hwts_rx_en;
        dma_addr_t *rx_skbuff_dma;
index 4c6486cc80fbd13f3aaf2d6c6093ac35b203bdd7..3c7928edfebb42e2ccbdd6161aec813622f2cfad 100644 (file)
@@ -97,7 +97,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
        STMMAC_STAT(napi_poll),
        STMMAC_STAT(tx_normal_irq_n),
        STMMAC_STAT(tx_clean),
-       STMMAC_STAT(tx_reset_ic_bit),
+       STMMAC_STAT(tx_set_ic_bit),
        STMMAC_STAT(irq_receive_pmt_irq_n),
        /* MMC info */
        STMMAC_STAT(mmc_tx_irq_n),
@@ -781,6 +781,43 @@ static int stmmac_get_ts_info(struct net_device *dev,
                return ethtool_op_get_ts_info(dev, info);
 }
 
+static int stmmac_get_tunable(struct net_device *dev,
+                             const struct ethtool_tunable *tuna, void *data)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               *(u32 *)data = priv->rx_copybreak;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int stmmac_set_tunable(struct net_device *dev,
+                             const struct ethtool_tunable *tuna,
+                             const void *data)
+{
+       struct stmmac_priv *priv = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               priv->rx_copybreak = *(u32 *)data;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static const struct ethtool_ops stmmac_ethtool_ops = {
        .begin = stmmac_check_if_running,
        .get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -803,6 +840,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
        .get_ts_info = stmmac_get_ts_info,
        .get_coalesce = stmmac_get_coalesce,
        .set_coalesce = stmmac_set_coalesce,
+       .get_tunable = stmmac_get_tunable,
+       .set_tunable = stmmac_set_tunable,
 };
 
 void stmmac_set_ethtool_ops(struct net_device *netdev)
index c21015b68097a0a6135cba039d9ddfc8e6778683..4c5ce9848ca9aebe4090ecf26adb3a10e307cf3a 100644 (file)
@@ -71,15 +71,8 @@ static int phyaddr = -1;
 module_param(phyaddr, int, S_IRUGO);
 MODULE_PARM_DESC(phyaddr, "Physical device address");
 
-#define DMA_TX_SIZE 256
-static int dma_txsize = DMA_TX_SIZE;
-module_param(dma_txsize, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list");
-
-#define DMA_RX_SIZE 256
-static int dma_rxsize = DMA_RX_SIZE;
-module_param(dma_rxsize, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list");
+#define STMMAC_TX_THRESH       (DMA_TX_SIZE / 4)
+#define STMMAC_RX_THRESH       (DMA_RX_SIZE / 4)
 
 static int flow_ctrl = FLOW_OFF;
 module_param(flow_ctrl, int, S_IRUGO | S_IWUSR);
@@ -99,6 +92,8 @@ static int buf_sz = DEFAULT_BUFSIZE;
 module_param(buf_sz, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(buf_sz, "DMA buffer size");
 
+#define        STMMAC_RX_COPYBREAK     256
+
 static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
                                      NETIF_MSG_LINK | NETIF_MSG_IFUP |
                                      NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
@@ -134,10 +129,6 @@ static void stmmac_verify_args(void)
 {
        if (unlikely(watchdog < 0))
                watchdog = TX_TIMEO;
-       if (unlikely(dma_rxsize < 0))
-               dma_rxsize = DMA_RX_SIZE;
-       if (unlikely(dma_txsize < 0))
-               dma_txsize = DMA_TX_SIZE;
        if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
                buf_sz = DEFAULT_BUFSIZE;
        if (unlikely(flow_ctrl > 1))
@@ -197,12 +188,28 @@ static void print_pkt(unsigned char *buf, int len)
        print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len);
 }
 
-/* minimum number of free TX descriptors required to wake up TX process */
-#define STMMAC_TX_THRESH(x)    (x->dma_tx_size/4)
-
 static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
 {
-       return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
+       unsigned avail;
+
+       if (priv->dirty_tx > priv->cur_tx)
+               avail = priv->dirty_tx - priv->cur_tx - 1;
+       else
+               avail = DMA_TX_SIZE - priv->cur_tx + priv->dirty_tx - 1;
+
+       return avail;
+}
+
+static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv)
+{
+       unsigned dirty;
+
+       if (priv->dirty_rx <= priv->cur_rx)
+               dirty = priv->cur_rx - priv->dirty_rx;
+       else
+               dirty = DMA_RX_SIZE - priv->dirty_rx + priv->cur_rx;
+
+       return dirty;
 }
 
 /**
@@ -862,6 +869,12 @@ static int stmmac_init_phy(struct net_device *dev)
                phy_disconnect(phydev);
                return -ENODEV;
        }
+
+       /* If attached to a switch, there is no reason to poll phy handler */
+       if (priv->plat->phy_bus_name)
+               if (!strcmp(priv->plat->phy_bus_name, "fixed"))
+                       phydev->irq = PHY_IGNORE_INTERRUPT;
+
        pr_debug("stmmac_init_phy:  %s: attached to PHY (UID 0x%x)"
                 " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
 
@@ -906,19 +919,16 @@ static void stmmac_display_ring(void *head, int size, int extend_desc)
 
 static void stmmac_display_rings(struct stmmac_priv *priv)
 {
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int rxsize = priv->dma_rx_size;
-
        if (priv->extend_desc) {
                pr_info("Extended RX descriptor ring:\n");
-               stmmac_display_ring((void *)priv->dma_erx, rxsize, 1);
+               stmmac_display_ring((void *)priv->dma_erx, DMA_RX_SIZE, 1);
                pr_info("Extended TX descriptor ring:\n");
-               stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
+               stmmac_display_ring((void *)priv->dma_etx, DMA_TX_SIZE, 1);
        } else {
                pr_info("RX descriptor ring:\n");
-               stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
+               stmmac_display_ring((void *)priv->dma_rx, DMA_RX_SIZE, 0);
                pr_info("TX descriptor ring:\n");
-               stmmac_display_ring((void *)priv->dma_tx, txsize, 0);
+               stmmac_display_ring((void *)priv->dma_tx, DMA_TX_SIZE, 0);
        }
 }
 
@@ -947,28 +957,26 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
 static void stmmac_clear_descriptors(struct stmmac_priv *priv)
 {
        int i;
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int rxsize = priv->dma_rx_size;
 
        /* Clear the Rx/Tx descriptors */
-       for (i = 0; i < rxsize; i++)
+       for (i = 0; i < DMA_RX_SIZE; i++)
                if (priv->extend_desc)
                        priv->hw->desc->init_rx_desc(&priv->dma_erx[i].basic,
                                                     priv->use_riwt, priv->mode,
-                                                    (i == rxsize - 1));
+                                                    (i == DMA_RX_SIZE - 1));
                else
                        priv->hw->desc->init_rx_desc(&priv->dma_rx[i],
                                                     priv->use_riwt, priv->mode,
-                                                    (i == rxsize - 1));
-       for (i = 0; i < txsize; i++)
+                                                    (i == DMA_RX_SIZE - 1));
+       for (i = 0; i < DMA_TX_SIZE; i++)
                if (priv->extend_desc)
                        priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic,
                                                     priv->mode,
-                                                    (i == txsize - 1));
+                                                    (i == DMA_TX_SIZE - 1));
                else
                        priv->hw->desc->init_tx_desc(&priv->dma_tx[i],
                                                     priv->mode,
-                                                    (i == txsize - 1));
+                                                    (i == DMA_TX_SIZE - 1));
 }
 
 /**
@@ -1031,8 +1039,6 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
 {
        int i;
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int rxsize = priv->dma_rx_size;
        unsigned int bfsize = 0;
        int ret = -ENOMEM;
 
@@ -1044,10 +1050,6 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
 
        priv->dma_buf_sz = bfsize;
 
-       if (netif_msg_probe(priv))
-               pr_debug("%s: txsize %d, rxsize %d, bfsize %d\n", __func__,
-                        txsize, rxsize, bfsize);
-
        if (netif_msg_probe(priv)) {
                pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
                         (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
@@ -1055,7 +1057,7 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
                /* RX INITIALIZATION */
                pr_debug("\tSKB addresses:\nskb\t\tskb data\tdma data\n");
        }
-       for (i = 0; i < rxsize; i++) {
+       for (i = 0; i < DMA_RX_SIZE; i++) {
                struct dma_desc *p;
                if (priv->extend_desc)
                        p = &((priv->dma_erx + i)->basic);
@@ -1072,26 +1074,26 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
                                 (unsigned int)priv->rx_skbuff_dma[i]);
        }
        priv->cur_rx = 0;
-       priv->dirty_rx = (unsigned int)(i - rxsize);
+       priv->dirty_rx = (unsigned int)(i - DMA_RX_SIZE);
        buf_sz = bfsize;
 
        /* Setup the chained descriptor addresses */
        if (priv->mode == STMMAC_CHAIN_MODE) {
                if (priv->extend_desc) {
                        priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
-                                            rxsize, 1);
+                                            DMA_RX_SIZE, 1);
                        priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
-                                            txsize, 1);
+                                            DMA_TX_SIZE, 1);
                } else {
                        priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
-                                            rxsize, 0);
+                                            DMA_RX_SIZE, 0);
                        priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
-                                            txsize, 0);
+                                            DMA_TX_SIZE, 0);
                }
        }
 
        /* TX INITIALIZATION */
-       for (i = 0; i < txsize; i++) {
+       for (i = 0; i < DMA_TX_SIZE; i++) {
                struct dma_desc *p;
                if (priv->extend_desc)
                        p = &((priv->dma_etx + i)->basic);
@@ -1100,6 +1102,8 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
                p->des2 = 0;
                priv->tx_skbuff_dma[i].buf = 0;
                priv->tx_skbuff_dma[i].map_as_page = false;
+               priv->tx_skbuff_dma[i].len = 0;
+               priv->tx_skbuff_dma[i].last_segment = false;
                priv->tx_skbuff[i] = NULL;
        }
 
@@ -1123,7 +1127,7 @@ static void dma_free_rx_skbufs(struct stmmac_priv *priv)
 {
        int i;
 
-       for (i = 0; i < priv->dma_rx_size; i++)
+       for (i = 0; i < DMA_RX_SIZE; i++)
                stmmac_free_rx_buffers(priv, i);
 }
 
@@ -1131,7 +1135,7 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
 {
        int i;
 
-       for (i = 0; i < priv->dma_tx_size; i++) {
+       for (i = 0; i < DMA_TX_SIZE; i++) {
                struct dma_desc *p;
 
                if (priv->extend_desc)
@@ -1143,12 +1147,12 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
                        if (priv->tx_skbuff_dma[i].map_as_page)
                                dma_unmap_page(priv->device,
                                               priv->tx_skbuff_dma[i].buf,
-                                              priv->hw->desc->get_tx_len(p),
+                                              priv->tx_skbuff_dma[i].len,
                                               DMA_TO_DEVICE);
                        else
                                dma_unmap_single(priv->device,
                                                 priv->tx_skbuff_dma[i].buf,
-                                                priv->hw->desc->get_tx_len(p),
+                                                priv->tx_skbuff_dma[i].len,
                                                 DMA_TO_DEVICE);
                }
 
@@ -1171,33 +1175,31 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
  */
 static int alloc_dma_desc_resources(struct stmmac_priv *priv)
 {
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int rxsize = priv->dma_rx_size;
        int ret = -ENOMEM;
 
-       priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
+       priv->rx_skbuff_dma = kmalloc_array(DMA_RX_SIZE, sizeof(dma_addr_t),
                                            GFP_KERNEL);
        if (!priv->rx_skbuff_dma)
                return -ENOMEM;
 
-       priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
+       priv->rx_skbuff = kmalloc_array(DMA_RX_SIZE, sizeof(struct sk_buff *),
                                        GFP_KERNEL);
        if (!priv->rx_skbuff)
                goto err_rx_skbuff;
 
-       priv->tx_skbuff_dma = kmalloc_array(txsize,
+       priv->tx_skbuff_dma = kmalloc_array(DMA_TX_SIZE,
                                            sizeof(*priv->tx_skbuff_dma),
                                            GFP_KERNEL);
        if (!priv->tx_skbuff_dma)
                goto err_tx_skbuff_dma;
 
-       priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
+       priv->tx_skbuff = kmalloc_array(DMA_TX_SIZE, sizeof(struct sk_buff *),
                                        GFP_KERNEL);
        if (!priv->tx_skbuff)
                goto err_tx_skbuff;
 
        if (priv->extend_desc) {
-               priv->dma_erx = dma_zalloc_coherent(priv->device, rxsize *
+               priv->dma_erx = dma_zalloc_coherent(priv->device, DMA_RX_SIZE *
                                                    sizeof(struct
                                                           dma_extended_desc),
                                                    &priv->dma_rx_phy,
@@ -1205,31 +1207,31 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
                if (!priv->dma_erx)
                        goto err_dma;
 
-               priv->dma_etx = dma_zalloc_coherent(priv->device, txsize *
+               priv->dma_etx = dma_zalloc_coherent(priv->device, DMA_TX_SIZE *
                                                    sizeof(struct
                                                           dma_extended_desc),
                                                    &priv->dma_tx_phy,
                                                    GFP_KERNEL);
                if (!priv->dma_etx) {
-                       dma_free_coherent(priv->device, priv->dma_rx_size *
+                       dma_free_coherent(priv->device, DMA_RX_SIZE *
                                          sizeof(struct dma_extended_desc),
                                          priv->dma_erx, priv->dma_rx_phy);
                        goto err_dma;
                }
        } else {
-               priv->dma_rx = dma_zalloc_coherent(priv->device, rxsize *
+               priv->dma_rx = dma_zalloc_coherent(priv->device, DMA_RX_SIZE *
                                                   sizeof(struct dma_desc),
                                                   &priv->dma_rx_phy,
                                                   GFP_KERNEL);
                if (!priv->dma_rx)
                        goto err_dma;
 
-               priv->dma_tx = dma_zalloc_coherent(priv->device, txsize *
+               priv->dma_tx = dma_zalloc_coherent(priv->device, DMA_TX_SIZE *
                                                   sizeof(struct dma_desc),
                                                   &priv->dma_tx_phy,
                                                   GFP_KERNEL);
                if (!priv->dma_tx) {
-                       dma_free_coherent(priv->device, priv->dma_rx_size *
+                       dma_free_coherent(priv->device, DMA_RX_SIZE *
                                          sizeof(struct dma_desc),
                                          priv->dma_rx, priv->dma_rx_phy);
                        goto err_dma;
@@ -1258,16 +1260,16 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
        /* Free DMA regions of consistent memory previously allocated */
        if (!priv->extend_desc) {
                dma_free_coherent(priv->device,
-                                 priv->dma_tx_size * sizeof(struct dma_desc),
+                                 DMA_TX_SIZE * sizeof(struct dma_desc),
                                  priv->dma_tx, priv->dma_tx_phy);
                dma_free_coherent(priv->device,
-                                 priv->dma_rx_size * sizeof(struct dma_desc),
+                                 DMA_RX_SIZE * sizeof(struct dma_desc),
                                  priv->dma_rx, priv->dma_rx_phy);
        } else {
-               dma_free_coherent(priv->device, priv->dma_tx_size *
+               dma_free_coherent(priv->device, DMA_TX_SIZE *
                                  sizeof(struct dma_extended_desc),
                                  priv->dma_etx, priv->dma_tx_phy);
-               dma_free_coherent(priv->device, priv->dma_rx_size *
+               dma_free_coherent(priv->device, DMA_RX_SIZE *
                                  sizeof(struct dma_extended_desc),
                                  priv->dma_erx, priv->dma_rx_phy);
        }
@@ -1312,62 +1314,59 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
  */
 static void stmmac_tx_clean(struct stmmac_priv *priv)
 {
-       unsigned int txsize = priv->dma_tx_size;
        unsigned int bytes_compl = 0, pkts_compl = 0;
+       unsigned int entry = priv->dirty_tx;
 
        spin_lock(&priv->tx_lock);
 
        priv->xstats.tx_clean++;
 
-       while (priv->dirty_tx != priv->cur_tx) {
-               int last;
-               unsigned int entry = priv->dirty_tx % txsize;
+       while (entry != priv->cur_tx) {
                struct sk_buff *skb = priv->tx_skbuff[entry];
                struct dma_desc *p;
+               int status;
 
                if (priv->extend_desc)
                        p = (struct dma_desc *)(priv->dma_etx + entry);
                else
                        p = priv->dma_tx + entry;
 
-               /* Check if the descriptor is owned by the DMA. */
-               if (priv->hw->desc->get_tx_owner(p))
-                       break;
-
-               /* Verify tx error by looking at the last segment. */
-               last = priv->hw->desc->get_tx_ls(p);
-               if (likely(last)) {
-                       int tx_error =
-                           priv->hw->desc->tx_status(&priv->dev->stats,
+               status = priv->hw->desc->tx_status(&priv->dev->stats,
                                                      &priv->xstats, p,
                                                      priv->ioaddr);
-                       if (likely(tx_error == 0)) {
+               /* Check if the descriptor is owned by the DMA */
+               if (unlikely(status & tx_dma_own))
+                       break;
+
+               /* Just consider the last segment and ...*/
+               if (likely(!(status & tx_not_ls))) {
+                       /* ... verify the status error condition */
+                       if (unlikely(status & tx_err)) {
+                               priv->dev->stats.tx_errors++;
+                       } else {
                                priv->dev->stats.tx_packets++;
                                priv->xstats.tx_pkt_n++;
-                       } else
-                               priv->dev->stats.tx_errors++;
-
+                       }
                        stmmac_get_tx_hwtstamp(priv, entry, skb);
                }
-               if (netif_msg_tx_done(priv))
-                       pr_debug("%s: curr %d, dirty %d\n", __func__,
-                                priv->cur_tx, priv->dirty_tx);
 
                if (likely(priv->tx_skbuff_dma[entry].buf)) {
                        if (priv->tx_skbuff_dma[entry].map_as_page)
                                dma_unmap_page(priv->device,
                                               priv->tx_skbuff_dma[entry].buf,
-                                              priv->hw->desc->get_tx_len(p),
+                                              priv->tx_skbuff_dma[entry].len,
                                               DMA_TO_DEVICE);
                        else
                                dma_unmap_single(priv->device,
                                                 priv->tx_skbuff_dma[entry].buf,
-                                                priv->hw->desc->get_tx_len(p),
+                                                priv->tx_skbuff_dma[entry].len,
                                                 DMA_TO_DEVICE);
                        priv->tx_skbuff_dma[entry].buf = 0;
                        priv->tx_skbuff_dma[entry].map_as_page = false;
                }
                priv->hw->mode->clean_desc3(priv, p);
+               priv->tx_skbuff_dma[entry].last_segment = false;
+               priv->tx_skbuff_dma[entry].is_jumbo = false;
 
                if (likely(skb != NULL)) {
                        pkts_compl++;
@@ -1378,16 +1377,17 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
 
                priv->hw->desc->release_tx_desc(p, priv->mode);
 
-               priv->dirty_tx++;
+               entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
        }
+       priv->dirty_tx = entry;
 
        netdev_completed_queue(priv->dev, pkts_compl, bytes_compl);
 
        if (unlikely(netif_queue_stopped(priv->dev) &&
-                    stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
+                    stmmac_tx_avail(priv) > STMMAC_TX_THRESH)) {
                netif_tx_lock(priv->dev);
                if (netif_queue_stopped(priv->dev) &&
-                   stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
+                   stmmac_tx_avail(priv) > STMMAC_TX_THRESH) {
                        if (netif_msg_tx_done(priv))
                                pr_debug("%s: restart transmit\n", __func__);
                        netif_wake_queue(priv->dev);
@@ -1421,20 +1421,19 @@ static inline void stmmac_disable_dma_irq(struct stmmac_priv *priv)
 static void stmmac_tx_err(struct stmmac_priv *priv)
 {
        int i;
-       int txsize = priv->dma_tx_size;
        netif_stop_queue(priv->dev);
 
        priv->hw->dma->stop_tx(priv->ioaddr);
        dma_free_tx_skbufs(priv);
-       for (i = 0; i < txsize; i++)
+       for (i = 0; i < DMA_TX_SIZE; i++)
                if (priv->extend_desc)
                        priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic,
                                                     priv->mode,
-                                                    (i == txsize - 1));
+                                                    (i == DMA_TX_SIZE - 1));
                else
                        priv->hw->desc->init_tx_desc(&priv->dma_tx[i],
                                                     priv->mode,
-                                                    (i == txsize - 1));
+                                                    (i == DMA_TX_SIZE - 1));
        priv->dirty_tx = 0;
        priv->cur_tx = 0;
        netdev_reset_queue(priv->dev);
@@ -1635,23 +1634,35 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
  */
 static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 {
-       int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;
+       int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, aal = 0;
        int mixed_burst = 0;
        int atds = 0;
+       int ret = 0;
 
        if (priv->plat->dma_cfg) {
                pbl = priv->plat->dma_cfg->pbl;
                fixed_burst = priv->plat->dma_cfg->fixed_burst;
                mixed_burst = priv->plat->dma_cfg->mixed_burst;
-               burst_len = priv->plat->dma_cfg->burst_len;
+               aal = priv->plat->dma_cfg->aal;
        }
 
        if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
                atds = 1;
 
-       return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
-                                  burst_len, priv->dma_tx_phy,
-                                  priv->dma_rx_phy, atds);
+       ret = priv->hw->dma->reset(priv->ioaddr);
+       if (ret) {
+               dev_err(priv->device, "Failed to reset the dma\n");
+               return ret;
+       }
+
+       priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
+                           aal, priv->dma_tx_phy, priv->dma_rx_phy, atds);
+
+       if ((priv->synopsys_id >= DWMAC_CORE_3_50) &&
+           (priv->plat->axi && priv->hw->dma->axi))
+               priv->hw->dma->axi(priv->ioaddr, priv->plat->axi);
+
+       return ret;
 }
 
 /**
@@ -1799,10 +1810,8 @@ static int stmmac_open(struct net_device *dev)
        memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
        priv->xstats.threshold = tc;
 
-       /* Create and initialize the TX/RX descriptors chains. */
-       priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
-       priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
+       priv->rx_copybreak = STMMAC_RX_COPYBREAK;
 
        ret = alloc_dma_desc_resources(priv);
        if (ret < 0) {
@@ -1943,13 +1952,12 @@ static int stmmac_release(struct net_device *dev)
 static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned int txsize = priv->dma_tx_size;
-       int entry;
+       unsigned int nopaged_len = skb_headlen(skb);
        int i, csum_insertion = 0, is_jumbo = 0;
        int nfrags = skb_shinfo(skb)->nr_frags;
+       unsigned int entry, first_entry;
        struct dma_desc *desc, *first;
-       unsigned int nopaged_len = skb_headlen(skb);
-       unsigned int enh_desc = priv->plat->enh_desc;
+       unsigned int enh_desc;
 
        spin_lock(&priv->tx_lock);
 
@@ -1966,31 +1974,26 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        if (priv->tx_path_in_lpi_mode)
                stmmac_disable_eee_mode(priv);
 
-       entry = priv->cur_tx % txsize;
+       entry = priv->cur_tx;
+       first_entry = entry;
 
        csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
 
-       if (priv->extend_desc)
+       if (likely(priv->extend_desc))
                desc = (struct dma_desc *)(priv->dma_etx + entry);
        else
                desc = priv->dma_tx + entry;
 
        first = desc;
 
+       priv->tx_skbuff[first_entry] = skb;
+
+       enh_desc = priv->plat->enh_desc;
        /* To program the descriptors according to the size of the frame */
        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);
-               if (dma_mapping_error(priv->device, desc->des2))
-                       goto dma_map_err;
-               priv->tx_skbuff_dma[entry].buf = desc->des2;
-               priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
-                                               csum_insertion, priv->mode);
-       } else {
-               desc = first;
+       if (unlikely(is_jumbo)) {
                entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
                if (unlikely(entry < 0))
                        goto dma_map_err;
@@ -1999,10 +2002,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        for (i = 0; i < nfrags; i++) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
                int len = skb_frag_size(frag);
+               bool last_segment = (i == (nfrags - 1));
 
-               priv->tx_skbuff[entry] = NULL;
-               entry = (++priv->cur_tx) % txsize;
-               if (priv->extend_desc)
+               entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
+
+               if (likely(priv->extend_desc))
                        desc = (struct dma_desc *)(priv->dma_etx + entry);
                else
                        desc = priv->dma_tx + entry;
@@ -2012,53 +2016,37 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
                if (dma_mapping_error(priv->device, desc->des2))
                        goto dma_map_err; /* should reuse desc w/o issues */
 
+               priv->tx_skbuff[entry] = NULL;
                priv->tx_skbuff_dma[entry].buf = desc->des2;
                priv->tx_skbuff_dma[entry].map_as_page = true;
+               priv->tx_skbuff_dma[entry].len = len;
+               priv->tx_skbuff_dma[entry].last_segment = last_segment;
+
+               /* Prepare the descriptor and set the own bit too */
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
-                                               priv->mode);
-               wmb();
-               priv->hw->desc->set_tx_owner(desc);
-               wmb();
+                                               priv->mode, 1, last_segment);
        }
 
-       priv->tx_skbuff[entry] = skb;
-
-       /* Finalize the latest segment. */
-       priv->hw->desc->close_tx_desc(desc);
+       entry = STMMAC_GET_ENTRY(entry, DMA_TX_SIZE);
 
-       wmb();
-       /* According to the coalesce parameter the IC bit for the latest
-        * segment could be reset and the timer re-started to invoke the
-        * stmmac_tx function. This approach takes care about the fragments.
-        */
-       priv->tx_count_frames += nfrags + 1;
-       if (priv->tx_coal_frames > priv->tx_count_frames) {
-               priv->hw->desc->clear_tx_ic(desc);
-               priv->xstats.tx_reset_ic_bit++;
-               mod_timer(&priv->txtimer,
-                         STMMAC_COAL_TIMER(priv->tx_coal_timer));
-       } else
-               priv->tx_count_frames = 0;
-
-       /* To avoid raise condition */
-       priv->hw->desc->set_tx_owner(first);
-       wmb();
-
-       priv->cur_tx++;
+       priv->cur_tx = entry;
 
        if (netif_msg_pktdata(priv)) {
-               pr_debug("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
-                       __func__, (priv->cur_tx % txsize),
-                       (priv->dirty_tx % txsize), entry, first, nfrags);
+               pr_debug("%s: curr=%d dirty=%d f=%d, e=%d, first=%p, nfrags=%d",
+                        __func__, priv->cur_tx, priv->dirty_tx, first_entry,
+                        entry, first, nfrags);
 
                if (priv->extend_desc)
-                       stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
+                       stmmac_display_ring((void *)priv->dma_etx,
+                                           DMA_TX_SIZE, 1);
                else
-                       stmmac_display_ring((void *)priv->dma_tx, txsize, 0);
+                       stmmac_display_ring((void *)priv->dma_tx,
+                                           DMA_TX_SIZE, 0);
 
                pr_debug(">>> frame to be transmitted: ");
                print_pkt(skb->data, skb->len);
        }
+
        if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
                if (netif_msg_hw(priv))
                        pr_debug("%s: stop transmitted packets\n", __func__);
@@ -2067,16 +2055,59 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev->stats.tx_bytes += skb->len;
 
-       if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
-                    priv->hwts_tx_en)) {
-               /* declare that device is doing timestamping */
-               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-               priv->hw->desc->enable_tx_timestamp(first);
+       /* According to the coalesce parameter the IC bit for the latest
+        * segment is reset and the timer re-started to clean the tx status.
+        * This approach takes care about the fragments: desc is the first
+        * element in case of no SG.
+        */
+       priv->tx_count_frames += nfrags + 1;
+       if (likely(priv->tx_coal_frames > priv->tx_count_frames)) {
+               mod_timer(&priv->txtimer,
+                         STMMAC_COAL_TIMER(priv->tx_coal_timer));
+       } else {
+               priv->tx_count_frames = 0;
+               priv->hw->desc->set_tx_ic(desc);
+               priv->xstats.tx_set_ic_bit++;
        }
 
        if (!priv->hwts_tx_en)
                skb_tx_timestamp(skb);
 
+       /* Ready to fill the first descriptor and set the OWN bit w/o any
+        * problems because all the descriptors are actually ready to be
+        * passed to the DMA engine.
+        */
+       if (likely(!is_jumbo)) {
+               bool last_segment = (nfrags == 0);
+
+               first->des2 = dma_map_single(priv->device, skb->data,
+                                            nopaged_len, DMA_TO_DEVICE);
+               if (dma_mapping_error(priv->device, first->des2))
+                       goto dma_map_err;
+
+               priv->tx_skbuff_dma[first_entry].buf = first->des2;
+               priv->tx_skbuff_dma[first_entry].len = nopaged_len;
+               priv->tx_skbuff_dma[first_entry].last_segment = last_segment;
+
+               if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+                            priv->hwts_tx_en)) {
+                       /* declare that device is doing timestamping */
+                       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+                       priv->hw->desc->enable_tx_timestamp(first);
+               }
+
+               /* Prepare the first descriptor setting the OWN bit too */
+               priv->hw->desc->prepare_tx_desc(first, 1, nopaged_len,
+                                               csum_insertion, priv->mode, 1,
+                                               last_segment);
+
+               /* The own bit must be the latest setting done when prepare the
+                * descriptor and then barrier is needed to make sure that
+                * all is coherent before granting the DMA engine.
+                */
+               smp_wmb();
+       }
+
        netdev_sent_queue(dev, skb->len);
        priv->hw->dma->enable_dma_transmission(priv->ioaddr);
 
@@ -2108,6 +2139,14 @@ static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
 }
 
 
+static inline int stmmac_rx_threshold_count(struct stmmac_priv *priv)
+{
+       if (priv->rx_zeroc_thresh < STMMAC_RX_THRESH)
+               return 0;
+
+       return 1;
+}
+
 /**
  * stmmac_rx_refill - refill used skb preallocated buffers
  * @priv: driver private structure
@@ -2116,11 +2155,11 @@ static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
  */
 static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 {
-       unsigned int rxsize = priv->dma_rx_size;
        int bfsize = priv->dma_buf_sz;
+       unsigned int entry = priv->dirty_rx;
+       int dirty = stmmac_rx_dirty(priv);
 
-       for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) {
-               unsigned int entry = priv->dirty_rx % rxsize;
+       while (dirty-- > 0) {
                struct dma_desc *p;
 
                if (priv->extend_desc)
@@ -2132,9 +2171,15 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                        struct sk_buff *skb;
 
                        skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);
-
-                       if (unlikely(skb == NULL))
+                       if (unlikely(!skb)) {
+                               /* so for a while no zero-copy! */
+                               priv->rx_zeroc_thresh = STMMAC_RX_THRESH;
+                               if (unlikely(net_ratelimit()))
+                                       dev_err(priv->device,
+                                               "fail to alloc skb entry %d\n",
+                                               entry);
                                break;
+                       }
 
                        priv->rx_skbuff[entry] = skb;
                        priv->rx_skbuff_dma[entry] =
@@ -2150,13 +2195,20 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 
                        priv->hw->mode->refill_desc3(priv, p);
 
+                       if (priv->rx_zeroc_thresh > 0)
+                               priv->rx_zeroc_thresh--;
+
                        if (netif_msg_rx_status(priv))
                                pr_debug("\trefill entry #%d\n", entry);
                }
+
                wmb();
                priv->hw->desc->set_rx_owner(p);
                wmb();
+
+               entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE);
        }
+       priv->dirty_rx = entry;
 }
 
 /**
@@ -2168,8 +2220,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
  */
 static int stmmac_rx(struct stmmac_priv *priv, int limit)
 {
-       unsigned int rxsize = priv->dma_rx_size;
-       unsigned int entry = priv->cur_rx % rxsize;
+       unsigned int entry = priv->cur_rx;
        unsigned int next_entry;
        unsigned int count = 0;
        int coe = priv->hw->rx_csum;
@@ -2177,9 +2228,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
        if (netif_msg_rx_status(priv)) {
                pr_debug("%s: descriptor ring:\n", __func__);
                if (priv->extend_desc)
-                       stmmac_display_ring((void *)priv->dma_erx, rxsize, 1);
+                       stmmac_display_ring((void *)priv->dma_erx,
+                                           DMA_RX_SIZE, 1);
                else
-                       stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
+                       stmmac_display_ring((void *)priv->dma_rx,
+                                           DMA_RX_SIZE, 0);
        }
        while (count < limit) {
                int status;
@@ -2190,20 +2243,23 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                else
                        p = priv->dma_rx + entry;
 
-               if (priv->hw->desc->get_rx_owner(p))
+               /* read the status of the incoming frame */
+               status = priv->hw->desc->rx_status(&priv->dev->stats,
+                                                  &priv->xstats, p);
+               /* check if managed by the DMA otherwise go ahead */
+               if (unlikely(status & dma_own))
                        break;
 
                count++;
 
-               next_entry = (++priv->cur_rx) % rxsize;
+               priv->cur_rx = STMMAC_GET_ENTRY(priv->cur_rx, DMA_RX_SIZE);
+               next_entry = priv->cur_rx;
+
                if (priv->extend_desc)
                        prefetch(priv->dma_erx + next_entry);
                else
                        prefetch(priv->dma_rx + next_entry);
 
-               /* read the status of the incoming frame */
-               status = priv->hw->desc->rx_status(&priv->dev->stats,
-                                                  &priv->xstats, p);
                if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status))
                        priv->hw->desc->rx_extended_status(&priv->dev->stats,
                                                           &priv->xstats,
@@ -2248,23 +2304,54 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                                        pr_debug("\tframe size %d, COE: %d\n",
                                                 frame_len, status);
                        }
-                       skb = priv->rx_skbuff[entry];
-                       if (unlikely(!skb)) {
-                               pr_err("%s: Inconsistent Rx descriptor chain\n",
-                                      priv->dev->name);
-                               priv->dev->stats.rx_dropped++;
-                               break;
+
+                       if (unlikely((frame_len < priv->rx_copybreak) ||
+                                    stmmac_rx_threshold_count(priv))) {
+                               skb = netdev_alloc_skb_ip_align(priv->dev,
+                                                               frame_len);
+                               if (unlikely(!skb)) {
+                                       if (net_ratelimit())
+                                               dev_warn(priv->device,
+                                                        "packet dropped\n");
+                                       priv->dev->stats.rx_dropped++;
+                                       break;
+                               }
+
+                               dma_sync_single_for_cpu(priv->device,
+                                                       priv->rx_skbuff_dma
+                                                       [entry], frame_len,
+                                                       DMA_FROM_DEVICE);
+                               skb_copy_to_linear_data(skb,
+                                                       priv->
+                                                       rx_skbuff[entry]->data,
+                                                       frame_len);
+
+                               skb_put(skb, frame_len);
+                               dma_sync_single_for_device(priv->device,
+                                                          priv->rx_skbuff_dma
+                                                          [entry], frame_len,
+                                                          DMA_FROM_DEVICE);
+                       } else {
+                               skb = priv->rx_skbuff[entry];
+                               if (unlikely(!skb)) {
+                                       pr_err("%s: Inconsistent Rx chain\n",
+                                              priv->dev->name);
+                                       priv->dev->stats.rx_dropped++;
+                                       break;
+                               }
+                               prefetch(skb->data - NET_IP_ALIGN);
+                               priv->rx_skbuff[entry] = NULL;
+                               priv->rx_zeroc_thresh++;
+
+                               skb_put(skb, frame_len);
+                               dma_unmap_single(priv->device,
+                                                priv->rx_skbuff_dma[entry],
+                                                priv->dma_buf_sz,
+                                                DMA_FROM_DEVICE);
                        }
-                       prefetch(skb->data - NET_IP_ALIGN);
-                       priv->rx_skbuff[entry] = NULL;
 
                        stmmac_get_rx_hwtstamp(priv, entry, skb);
 
-                       skb_put(skb, frame_len);
-                       dma_unmap_single(priv->device,
-                                        priv->rx_skbuff_dma[entry],
-                                        priv->dma_buf_sz, DMA_FROM_DEVICE);
-
                        if (netif_msg_pktdata(priv)) {
                                pr_debug("frame received (%dbytes)", frame_len);
                                print_pkt(skb->data, frame_len);
@@ -2555,19 +2642,17 @@ static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
 {
        struct net_device *dev = seq->private;
        struct stmmac_priv *priv = netdev_priv(dev);
-       unsigned int txsize = priv->dma_tx_size;
-       unsigned int rxsize = priv->dma_rx_size;
 
        if (priv->extend_desc) {
                seq_printf(seq, "Extended RX descriptor ring:\n");
-               sysfs_display_ring((void *)priv->dma_erx, rxsize, 1, seq);
+               sysfs_display_ring((void *)priv->dma_erx, DMA_RX_SIZE, 1, seq);
                seq_printf(seq, "Extended TX descriptor ring:\n");
-               sysfs_display_ring((void *)priv->dma_etx, txsize, 1, seq);
+               sysfs_display_ring((void *)priv->dma_etx, DMA_TX_SIZE, 1, seq);
        } else {
                seq_printf(seq, "RX descriptor ring:\n");
-               sysfs_display_ring((void *)priv->dma_rx, rxsize, 0, seq);
+               sysfs_display_ring((void *)priv->dma_rx, DMA_RX_SIZE, 0, seq);
                seq_printf(seq, "TX descriptor ring:\n");
-               sysfs_display_ring((void *)priv->dma_tx, txsize, 0, seq);
+               sysfs_display_ring((void *)priv->dma_tx, DMA_TX_SIZE, 0, seq);
        }
 
        return 0;
@@ -3137,12 +3222,6 @@ static int __init stmmac_cmdline_opt(char *str)
                } else if (!strncmp(opt, "phyaddr:", 8)) {
                        if (kstrtoint(opt + 8, 0, &phyaddr))
                                goto err;
-               } else if (!strncmp(opt, "dma_txsize:", 11)) {
-                       if (kstrtoint(opt + 11, 0, &dma_txsize))
-                               goto err;
-               } else if (!strncmp(opt, "dma_rxsize:", 11)) {
-                       if (kstrtoint(opt + 11, 0, &dma_rxsize))
-                               goto err;
                } else if (!strncmp(opt, "buf_sz:", 7)) {
                        if (kstrtoint(opt + 7, 0, &buf_sz))
                                goto err;
index 0faf1633603531a709358388b116d596d746e3e9..efb54f356a67c03e36856ed0047f5e3d9b2bf0f1 100644 (file)
@@ -199,21 +199,12 @@ int stmmac_mdio_register(struct net_device *ndev)
        struct stmmac_priv *priv = netdev_priv(ndev);
        struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
        int addr, found;
-       struct device_node *mdio_node = NULL;
-       struct device_node *child_node = NULL;
+       struct device_node *mdio_node = priv->plat->mdio_node;
 
        if (!mdio_bus_data)
                return 0;
 
        if (IS_ENABLED(CONFIG_OF)) {
-               for_each_child_of_node(priv->device->of_node, child_node) {
-                       if (of_device_is_compatible(child_node,
-                                                   "snps,dwmac-mdio")) {
-                               mdio_node = child_node;
-                               break;
-                       }
-               }
-
                if (mdio_node) {
                        netdev_dbg(ndev, "FOUND MDIO subnode\n");
                } else {
index d71a721ea61ce8f973d26ac7353ab210e33e9542..ae4388735b7fb560649da51cf823caf4f1dbdbb6 100644 (file)
@@ -81,7 +81,7 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
        plat->mdio_bus_data->phy_mask = 0;
 
        plat->dma_cfg->pbl = 32;
-       plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
+       /* TODO: AXI */
 
        /* Set default value for multicast hash bins */
        plat->multicast_filter_bins = HASH_TABLE_SIZE;
@@ -115,8 +115,8 @@ static int quark_default_data(struct plat_stmmacenet_data *plat,
        plat->mdio_bus_data->phy_mask = 0;
 
        plat->dma_cfg->pbl = 16;
-       plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
        plat->dma_cfg->fixed_burst = 1;
+       /* AXI (TODO) */
 
        /* Set default value for multicast hash bins */
        plat->multicast_filter_bins = HASH_TABLE_SIZE;
index 6a52fa18cbf2e94958bdfe44c4db258ababcdd02..dcbd2a1601e89a620bb2dc1c77887e374d3fe2ba 100644 (file)
@@ -95,6 +95,42 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries)
        return x;
 }
 
+/**
+ * stmmac_axi_setup - parse DT parameters for programming the AXI register
+ * @pdev: platform device
+ * @priv: driver private struct.
+ * Description:
+ * if required, from device-tree the AXI internal register can be tuned
+ * by using platform parameters.
+ */
+static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
+{
+       struct device_node *np;
+       struct stmmac_axi *axi;
+
+       np = of_parse_phandle(pdev->dev.of_node, "snps,axi-config", 0);
+       if (!np)
+               return NULL;
+
+       axi = kzalloc(sizeof(*axi), GFP_KERNEL);
+       if (!axi)
+               return ERR_PTR(-ENOMEM);
+
+       axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
+       axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
+       axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
+       axi->axi_axi_all = of_property_read_bool(np, "snps,axi_all");
+       axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
+       axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
+       axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
+
+       of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt);
+       of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt);
+       of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
+
+       return axi;
+}
+
 /**
  * stmmac_probe_config_dt - parse device-tree driver parameters
  * @pdev: platform_device structure
@@ -110,6 +146,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
        struct device_node *np = pdev->dev.of_node;
        struct plat_stmmacenet_data *plat;
        struct stmmac_dma_cfg *dma_cfg;
+       struct device_node *child_node = NULL;
 
        plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
        if (!plat)
@@ -140,13 +177,19 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                plat->phy_node = of_node_get(np);
        }
 
+       for_each_child_of_node(np, child_node)
+               if (of_device_is_compatible(child_node, "snps,dwmac-mdio")) {
+                       plat->mdio_node = child_node;
+                       break;
+               }
+
        /* "snps,phy-addr" is not a standard property. Mark it as deprecated
         * and warn of its use. Remove this when phy node support is added.
         */
        if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
                dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
 
-       if ((plat->phy_node && !of_phy_is_fixed_link(np)) || plat->phy_bus_name)
+       if ((plat->phy_node && !of_phy_is_fixed_link(np)) || !plat->mdio_node)
                plat->mdio_bus_data = NULL;
        else
                plat->mdio_bus_data =
@@ -216,13 +259,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                }
                plat->dma_cfg = dma_cfg;
                of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+               dma_cfg->aal = of_property_read_bool(np, "snps,aal");
                dma_cfg->fixed_burst =
                        of_property_read_bool(np, "snps,fixed-burst");
                dma_cfg->mixed_burst =
                        of_property_read_bool(np, "snps,mixed-burst");
-               of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len);
-               if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256)
-                       dma_cfg->burst_len = 0;
        }
        plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
        if (plat->force_thresh_dma_mode) {
@@ -230,6 +271,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
        }
 
+       plat->axi = stmmac_axi_setup(pdev);
+
        return plat;
 }
 #else
index 70814b7386b3119e55ac8be1a92cfdb8c0740c5c..af11ed1e0bcc09b4ed4fa5e94df8945fab4d581e 100644 (file)
 #define DWC_MMC_RXOCTETCOUNT_GB          0x0784
 #define DWC_MMC_RXPACKETCOUNT_GB         0x0780
 
-static int debug = 3;
+static int debug = -1;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "DWC_eth_qos debug level (0=none,...,16=all)");
 
@@ -650,6 +650,11 @@ struct net_local {
        u32 mmc_tx_counters_mask;
 
        struct dwceqos_flowcontrol flowcontrol;
+
+       /* Tracks the intermediate state of phy started but hardware
+        * init not finished yet.
+        */
+       bool phy_defer;
 };
 
 static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask,
@@ -901,6 +906,9 @@ static void dwceqos_adjust_link(struct net_device *ndev)
        struct phy_device *phydev = lp->phy_dev;
        int status_change = 0;
 
+       if (lp->phy_defer)
+               return;
+
        if (phydev->link) {
                if ((lp->speed != phydev->speed) ||
                    (lp->duplex != phydev->duplex)) {
@@ -1113,7 +1121,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)
        /* Allocate DMA descriptors */
        size = DWCEQOS_RX_DCNT * sizeof(struct dwceqos_dma_desc);
        lp->rx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size,
-                       &lp->rx_descs_addr, 0);
+                       &lp->rx_descs_addr, GFP_KERNEL);
        if (!lp->rx_descs)
                goto err_out;
        lp->rx_descs_tail_addr = lp->rx_descs_addr +
@@ -1121,7 +1129,7 @@ static int dwceqos_descriptor_init(struct net_local *lp)
 
        size = DWCEQOS_TX_DCNT * sizeof(struct dwceqos_dma_desc);
        lp->tx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size,
-                       &lp->tx_descs_addr, 0);
+                       &lp->tx_descs_addr, GFP_KERNEL);
        if (!lp->tx_descs)
                goto err_out;
        lp->tx_descs_tail_addr = lp->tx_descs_addr +
@@ -1635,6 +1643,12 @@ static void dwceqos_init_hw(struct net_local *lp)
        regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG);
        dwceqos_write(lp, REG_DWCEQOS_MAC_CFG,
                      regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE);
+
+       lp->phy_defer = false;
+       mutex_lock(&lp->phy_dev->lock);
+       phy_read_status(lp->phy_dev);
+       dwceqos_adjust_link(lp->ndev);
+       mutex_unlock(&lp->phy_dev->lock);
 }
 
 static void dwceqos_tx_reclaim(unsigned long data)
@@ -1880,9 +1894,13 @@ static int dwceqos_open(struct net_device *ndev)
        }
        netdev_reset_queue(ndev);
 
-       napi_enable(&lp->napi);
+       /* The dwceqos reset state machine requires all phy clocks to complete,
+        * hence the unusual init order with phy_start first.
+        */
+       lp->phy_defer = true;
        phy_start(lp->phy_dev);
        dwceqos_init_hw(lp);
+       napi_enable(&lp->napi);
 
        netif_start_queue(ndev);
        tasklet_enable(&lp->tx_bdreclaim_tasklet);
@@ -1915,18 +1933,19 @@ static int dwceqos_stop(struct net_device *ndev)
 {
        struct net_local *lp = netdev_priv(ndev);
 
-       phy_stop(lp->phy_dev);
-
        tasklet_disable(&lp->tx_bdreclaim_tasklet);
-       netif_stop_queue(ndev);
        napi_disable(&lp->napi);
 
-       dwceqos_drain_dma(lp);
+       /* Stop all tx before we drain the tx dma. */
+       netif_tx_lock_bh(lp->ndev);
+       netif_stop_queue(ndev);
+       netif_tx_unlock_bh(lp->ndev);
 
-       netif_tx_lock(lp->ndev);
+       dwceqos_drain_dma(lp);
        dwceqos_reset_hw(lp);
+       phy_stop(lp->phy_dev);
+
        dwceqos_descriptor_free(lp);
-       netif_tx_unlock(lp->ndev);
 
        return 0;
 }
@@ -2178,12 +2197,10 @@ static int dwceqos_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                ((trans.initial_descriptor + trans.nr_descriptors) %
                 DWCEQOS_TX_DCNT));
 
-       dwceqos_tx_finalize(skb, lp, &trans);
-
-       netdev_sent_queue(ndev, skb->len);
-
        spin_lock_bh(&lp->tx_lock);
        lp->tx_free -= trans.nr_descriptors;
+       dwceqos_tx_finalize(skb, lp, &trans);
+       netdev_sent_queue(ndev, skb->len);
        spin_unlock_bh(&lp->tx_lock);
 
        ndev->trans_start = jiffies;
index e9cc61e1ec742090157db6b792b1a6a9168e6635..c3e85acfdc70233a628f939477b208e3dd28121b 100644 (file)
@@ -63,8 +63,12 @@ static void cpsw_gmii_sel_am3352(struct cpsw_phy_sel_priv *priv,
                mode = AM33XX_GMII_SEL_MODE_RGMII;
                break;
 
-       case PHY_INTERFACE_MODE_MII:
        default:
+               dev_warn(priv->dev,
+                        "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
+                       phy_modes(phy_mode));
+               /* fallthrough */
+       case PHY_INTERFACE_MODE_MII:
                mode = AM33XX_GMII_SEL_MODE_MII;
                break;
        };
@@ -106,8 +110,12 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_phy_sel_priv *priv,
                mode = AM33XX_GMII_SEL_MODE_RGMII;
                break;
 
-       case PHY_INTERFACE_MODE_MII:
        default:
+               dev_warn(priv->dev,
+                        "Unsupported PHY mode: \"%s\". Defaulting to MII.\n",
+                       phy_modes(phy_mode));
+               /* fallthrough */
+       case PHY_INTERFACE_MODE_MII:
                mode = AM33XX_GMII_SEL_MODE_MII;
                break;
        };
index c61d66d386346a2eda12b8fab2efaa8760b3fff3..1d0942c531209ea5b581ede060398b33fa7d61a7 100644 (file)
@@ -117,21 +117,17 @@ static void get_pkt_info(dma_addr_t *buff, u32 *buff_len, dma_addr_t *ndesc,
        *ndesc = le32_to_cpu(desc->next_desc);
 }
 
-static void get_pad_info(u32 *pad0, u32 *pad1, u32 *pad2, struct knav_dma_desc *desc)
+static u32 get_sw_data(int index, struct knav_dma_desc *desc)
 {
-       *pad0 = le32_to_cpu(desc->pad[0]);
-       *pad1 = le32_to_cpu(desc->pad[1]);
-       *pad2 = le32_to_cpu(desc->pad[2]);
+       /* No Endian conversion needed as this data is untouched by hw */
+       return desc->sw_data[index];
 }
 
-static void get_pad_ptr(void **padptr, struct knav_dma_desc *desc)
-{
-       u64 pad64;
-
-       pad64 = le32_to_cpu(desc->pad[0]) +
-               ((u64)le32_to_cpu(desc->pad[1]) << 32);
-       *padptr = (void *)(uintptr_t)pad64;
-}
+/* use these macros to get sw data */
+#define GET_SW_DATA0(desc) get_sw_data(0, desc)
+#define GET_SW_DATA1(desc) get_sw_data(1, desc)
+#define GET_SW_DATA2(desc) get_sw_data(2, desc)
+#define GET_SW_DATA3(desc) get_sw_data(3, desc)
 
 static void get_org_pkt_info(dma_addr_t *buff, u32 *buff_len,
                             struct knav_dma_desc *desc)
@@ -163,13 +159,18 @@ static void set_desc_info(u32 desc_info, u32 pkt_info,
        desc->packet_info = cpu_to_le32(pkt_info);
 }
 
-static void set_pad_info(u32 pad0, u32 pad1, u32 pad2, struct knav_dma_desc *desc)
+static void set_sw_data(int index, u32 data, struct knav_dma_desc *desc)
 {
-       desc->pad[0] = cpu_to_le32(pad0);
-       desc->pad[1] = cpu_to_le32(pad1);
-       desc->pad[2] = cpu_to_le32(pad1);
+       /* No Endian conversion needed as this data is untouched by hw */
+       desc->sw_data[index] = data;
 }
 
+/* use these macros to set sw data */
+#define SET_SW_DATA0(data, desc) set_sw_data(0, data, desc)
+#define SET_SW_DATA1(data, desc) set_sw_data(1, data, desc)
+#define SET_SW_DATA2(data, desc) set_sw_data(2, data, desc)
+#define SET_SW_DATA3(data, desc) set_sw_data(3, data, desc)
+
 static void set_org_pkt_info(dma_addr_t buff, u32 buff_len,
                             struct knav_dma_desc *desc)
 {
@@ -581,7 +582,6 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
        dma_addr_t dma_desc, dma_buf;
        unsigned int buf_len, dma_sz = sizeof(*ndesc);
        void *buf_ptr;
-       u32 pad[2];
        u32 tmp;
 
        get_words(&dma_desc, 1, &desc->next_desc);
@@ -593,14 +593,20 @@ static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
                        break;
                }
                get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc);
-               get_pad_ptr(&buf_ptr, ndesc);
+               /* warning!!!! We are retrieving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               buf_ptr = (void *)GET_SW_DATA0(ndesc);
+               buf_len = (int)GET_SW_DATA1(desc);
                dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE);
                __free_page(buf_ptr);
                knav_pool_desc_put(netcp->rx_pool, desc);
        }
-
-       get_pad_info(&pad[0], &pad[1], &buf_len, desc);
-       buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32));
+       /* warning!!!! We are retrieving the virtual ptr in the sw_data
+        * field as a 32bit value. Will not work on 64bit machines
+        */
+       buf_ptr = (void *)GET_SW_DATA0(desc);
+       buf_len = (int)GET_SW_DATA1(desc);
 
        if (buf_ptr)
                netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr);
@@ -639,7 +645,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
        dma_addr_t dma_desc, dma_buff;
        struct netcp_packet p_info;
        struct sk_buff *skb;
-       u32 pad[2];
        void *org_buf_ptr;
 
        dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz);
@@ -653,8 +658,11 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
        }
 
        get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc);
-       get_pad_info(&pad[0], &pad[1], &org_buf_len, desc);
-       org_buf_ptr = (void *)(uintptr_t)(pad[0] + ((u64)pad[1] << 32));
+       /* warning!!!! We are retrieving the virtual ptr in the sw_data
+        * field as a 32bit value. Will not work on 64bit machines
+        */
+       org_buf_ptr = (void *)GET_SW_DATA0(desc);
+       org_buf_len = (int)GET_SW_DATA1(desc);
 
        if (unlikely(!org_buf_ptr)) {
                dev_err(netcp->ndev_dev, "NULL bufptr in desc\n");
@@ -679,7 +687,6 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
        /* Fill in the page fragment list */
        while (dma_desc) {
                struct page *page;
-               void *ptr;
 
                ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);
                if (unlikely(!ndesc)) {
@@ -688,8 +695,10 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
                }
 
                get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc);
-               get_pad_ptr(&ptr, ndesc);
-               page = ptr;
+               /* warning!!!! We are retrieving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               page = (struct page *)GET_SW_DATA0(desc);
 
                if (likely(dma_buff && buf_len && page)) {
                        dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE,
@@ -777,7 +786,10 @@ static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq)
                }
 
                get_org_pkt_info(&dma, &buf_len, desc);
-               get_pad_ptr(&buf_ptr, desc);
+               /* warning!!!! We are retrieving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               buf_ptr = (void *)GET_SW_DATA0(desc);
 
                if (unlikely(!dma)) {
                        dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n");
@@ -829,7 +841,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
        struct page *page;
        dma_addr_t dma;
        void *bufptr;
-       u32 pad[3];
+       u32 sw_data[2];
 
        /* Allocate descriptor */
        hwdesc = knav_pool_desc_get(netcp->rx_pool);
@@ -846,7 +858,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
                                SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
                bufptr = netdev_alloc_frag(primary_buf_len);
-               pad[2] = primary_buf_len;
+               sw_data[1] = primary_buf_len;
 
                if (unlikely(!bufptr)) {
                        dev_warn_ratelimited(netcp->ndev_dev,
@@ -858,9 +870,10 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
                if (unlikely(dma_mapping_error(netcp->dev, dma)))
                        goto fail;
 
-               pad[0] = lower_32_bits((uintptr_t)bufptr);
-               pad[1] = upper_32_bits((uintptr_t)bufptr);
-
+               /* warning!!!! We are saving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               sw_data[0] = (u32)bufptr;
        } else {
                /* Allocate a secondary receive queue entry */
                page = alloc_page(GFP_ATOMIC | GFP_DMA | __GFP_COLD);
@@ -870,9 +883,11 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
                }
                buf_len = PAGE_SIZE;
                dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE);
-               pad[0] = lower_32_bits(dma);
-               pad[1] = upper_32_bits(dma);
-               pad[2] = 0;
+               /* warning!!!! We are saving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               sw_data[0] = (u32)page;
+               sw_data[1] = 0;
        }
 
        desc_info =  KNAV_DMA_DESC_PS_INFO_IN_DESC;
@@ -882,7 +897,8 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
        pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) <<
                    KNAV_DMA_DESC_RETQ_SHIFT;
        set_org_pkt_info(dma, buf_len, hwdesc);
-       set_pad_info(pad[0], pad[1], pad[2], hwdesc);
+       SET_SW_DATA0(sw_data[0], hwdesc);
+       SET_SW_DATA1(sw_data[1], hwdesc);
        set_desc_info(desc_info, pkt_info, hwdesc);
 
        /* Push to FDQs */
@@ -971,7 +987,6 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
                                          unsigned int budget)
 {
        struct knav_dma_desc *desc;
-       void *ptr;
        struct sk_buff *skb;
        unsigned int dma_sz;
        dma_addr_t dma;
@@ -988,8 +1003,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
                        continue;
                }
 
-               get_pad_ptr(&ptr, desc);
-               skb = ptr;
+               /* warning!!!! We are retrieving the virtual ptr in the sw_data
+                * field as a 32bit value. Will not work on 64bit machines
+                */
+               skb = (struct sk_buff *)GET_SW_DATA0(desc);
                netcp_free_tx_desc_chain(netcp, desc, dma_sz);
                if (!skb) {
                        dev_err(netcp->ndev_dev, "No skb in Tx desc\n");
@@ -1194,10 +1211,10 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
        }
 
        set_words(&tmp, 1, &desc->packet_info);
-       tmp = lower_32_bits((uintptr_t)&skb);
-       set_words(&tmp, 1, &desc->pad[0]);
-       tmp = upper_32_bits((uintptr_t)&skb);
-       set_words(&tmp, 1, &desc->pad[1]);
+       /* warning!!!! We are saving the virtual ptr in the sw_data
+        * field as a 32bit value. Will not work on 64bit machines
+        */
+       SET_SW_DATA0((u32)skb, desc);
 
        if (tx_pipe->flags & SWITCH_TO_PORT_IN_TAGINFO) {
                tmp = tx_pipe->switch_to_port;
@@ -1835,22 +1852,26 @@ static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb,
        return 0;
 }
 
-static int netcp_setup_tc(struct net_device *dev, u8 num_tc)
+static int netcp_setup_tc(struct net_device *dev, u32 handle, __be16 proto,
+                         struct tc_to_netdev *tc)
 {
        int i;
 
        /* setup tc must be called under rtnl lock */
        ASSERT_RTNL();
 
+       if (tc->type != TC_SETUP_MQPRIO)
+               return -EINVAL;
+
        /* Sanity-check the number of traffic classes requested */
        if ((dev->real_num_tx_queues <= 1) ||
-           (dev->real_num_tx_queues < num_tc))
+           (dev->real_num_tx_queues < tc->tc))
                return -EINVAL;
 
        /* Configure traffic class to queue mappings */
-       if (num_tc) {
-               netdev_set_num_tc(dev, num_tc);
-               for (i = 0; i < num_tc; i++)
+       if (tc->tc) {
+               netdev_set_num_tc(dev, tc->tc);
+               for (i = 0; i < tc->tc; i++)
                        netdev_set_tc_queue(dev, i, 1, i);
        } else {
                netdev_reset_tc(dev);
index 0b14ac3b8d1189081967aad8bcbbfce30016aeea..192631a345dfe6e9a36b976323e340f0693b6123 100644 (file)
@@ -68,14 +68,16 @@ struct geneve_dev {
        u8                 tos;         /* TOS override */
        union geneve_addr  remote;      /* IP address for link partner */
        struct list_head   next;        /* geneve's per namespace list */
+       __be32             label;       /* IPv6 flowlabel override */
        __be16             dst_port;
        bool               collect_md;
        struct gro_cells   gro_cells;
        u32                flags;
+       struct dst_cache   dst_cache;
 };
 
 /* Geneve device flags */
-#define GENEVE_F_UDP_CSUM              BIT(0)
+#define GENEVE_F_UDP_ZERO_CSUM_TX      BIT(0)
 #define GENEVE_F_UDP_ZERO_CSUM6_TX     BIT(1)
 #define GENEVE_F_UDP_ZERO_CSUM6_RX     BIT(2)
 
@@ -109,6 +111,11 @@ static __be64 vni_to_tunnel_id(const __u8 *vni)
 #endif
 }
 
+static sa_family_t geneve_get_sk_family(struct geneve_sock *gs)
+{
+       return gs->sock->sk->sk_family;
+}
+
 static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
                                        __be32 addr, u8 vni[])
 {
@@ -152,58 +159,60 @@ static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb)
        return (struct genevehdr *)(udp_hdr(skb) + 1);
 }
 
-/* geneve receive/decap routine */
-static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
+static struct geneve_dev *geneve_lookup_skb(struct geneve_sock *gs,
+                                           struct sk_buff *skb)
 {
-       struct genevehdr *gnvh = geneve_hdr(skb);
-       struct metadata_dst *tun_dst = NULL;
-       struct geneve_dev *geneve = NULL;
-       struct pcpu_sw_netstats *stats;
-       struct iphdr *iph = NULL;
+       u8 *vni;
        __be32 addr;
        static u8 zero_vni[3];
-       u8 *vni;
-       int err = 0;
-       sa_family_t sa_family;
 #if IS_ENABLED(CONFIG_IPV6)
-       struct ipv6hdr *ip6h = NULL;
-       struct in6_addr addr6;
        static struct in6_addr zero_addr6;
 #endif
 
-       sa_family = gs->sock->sk->sk_family;
+       if (geneve_get_sk_family(gs) == AF_INET) {
+               struct iphdr *iph;
 
-       if (sa_family == AF_INET) {
                iph = ip_hdr(skb); /* outer IP header... */
 
                if (gs->collect_md) {
                        vni = zero_vni;
                        addr = 0;
                } else {
-                       vni = gnvh->vni;
-
+                       vni = geneve_hdr(skb)->vni;
                        addr = iph->saddr;
                }
 
-               geneve = geneve_lookup(gs, addr, vni);
+               return geneve_lookup(gs, addr, vni);
 #if IS_ENABLED(CONFIG_IPV6)
-       } else if (sa_family == AF_INET6) {
+       } else if (geneve_get_sk_family(gs) == AF_INET6) {
+               struct ipv6hdr *ip6h;
+               struct in6_addr addr6;
+
                ip6h = ipv6_hdr(skb); /* outer IPv6 header... */
 
                if (gs->collect_md) {
                        vni = zero_vni;
                        addr6 = zero_addr6;
                } else {
-                       vni = gnvh->vni;
-
+                       vni = geneve_hdr(skb)->vni;
                        addr6 = ip6h->saddr;
                }
 
-               geneve = geneve6_lookup(gs, addr6, vni);
+               return geneve6_lookup(gs, addr6, vni);
 #endif
        }
-       if (!geneve)
-               goto drop;
+       return NULL;
+}
+
+/* geneve receive/decap routine */
+static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
+                     struct sk_buff *skb)
+{
+       struct genevehdr *gnvh = geneve_hdr(skb);
+       struct metadata_dst *tun_dst = NULL;
+       struct pcpu_sw_netstats *stats;
+       int err = 0;
+       void *oiph;
 
        if (ip_tunnel_collect_metadata() || gs->collect_md) {
                __be16 flags;
@@ -212,7 +221,7 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
                        (gnvh->oam ? TUNNEL_OAM : 0) |
                        (gnvh->critical ? TUNNEL_CRIT_OPT : 0);
 
-               tun_dst = udp_tun_rx_dst(skb, sa_family, flags,
+               tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
                                         vni_to_tunnel_id(gnvh->vni),
                                         gnvh->opt_len * 4);
                if (!tun_dst)
@@ -229,7 +238,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
        }
 
        skb_reset_mac_header(skb);
-       skb_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev)));
        skb->protocol = eth_type_trans(skb, geneve->dev);
        skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
@@ -240,25 +248,27 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb)
        if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
                goto drop;
 
+       oiph = skb_network_header(skb);
        skb_reset_network_header(skb);
 
-       if (iph)
-               err = IP_ECN_decapsulate(iph, skb);
+       if (geneve_get_sk_family(gs) == AF_INET)
+               err = IP_ECN_decapsulate(oiph, skb);
 #if IS_ENABLED(CONFIG_IPV6)
-       if (ip6h)
-               err = IP6_ECN_decapsulate(ip6h, skb);
+       else
+               err = IP6_ECN_decapsulate(oiph, skb);
 #endif
 
        if (unlikely(err)) {
                if (log_ecn_error) {
-                       if (iph)
+                       if (geneve_get_sk_family(gs) == AF_INET)
                                net_info_ratelimited("non-ECT from %pI4 "
                                                     "with TOS=%#x\n",
-                                                    &iph->saddr, iph->tos);
+                                                    &((struct iphdr *)oiph)->saddr,
+                                                    ((struct iphdr *)oiph)->tos);
 #if IS_ENABLED(CONFIG_IPV6)
-                       if (ip6h)
+                       else
                                net_info_ratelimited("non-ECT from %pI6\n",
-                                                    &ip6h->saddr);
+                                                    &((struct ipv6hdr *)oiph)->saddr);
 #endif
                }
                if (err > 1) {
@@ -297,6 +307,13 @@ static int geneve_init(struct net_device *dev)
                return err;
        }
 
+       err = dst_cache_init(&geneve->dst_cache, GFP_KERNEL);
+       if (err) {
+               free_percpu(dev->tstats);
+               gro_cells_destroy(&geneve->gro_cells);
+               return err;
+       }
+
        return 0;
 }
 
@@ -304,6 +321,7 @@ static void geneve_uninit(struct net_device *dev)
 {
        struct geneve_dev *geneve = netdev_priv(dev);
 
+       dst_cache_destroy(&geneve->dst_cache);
        gro_cells_destroy(&geneve->gro_cells);
        free_percpu(dev->tstats);
 }
@@ -312,6 +330,7 @@ static void geneve_uninit(struct net_device *dev)
 static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct genevehdr *geneveh;
+       struct geneve_dev *geneve;
        struct geneve_sock *gs;
        int opts_len;
 
@@ -327,16 +346,21 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        if (unlikely(geneveh->proto_type != htons(ETH_P_TEB)))
                goto error;
 
-       opts_len = geneveh->opt_len * 4;
-       if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
-                                htons(ETH_P_TEB)))
-               goto drop;
-
        gs = rcu_dereference_sk_user_data(sk);
        if (!gs)
                goto drop;
 
-       geneve_rx(gs, skb);
+       geneve = geneve_lookup_skb(gs, skb);
+       if (!geneve)
+               goto drop;
+
+       opts_len = geneveh->opt_len * 4;
+       if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
+                                htons(ETH_P_TEB),
+                                !net_eq(geneve->net, dev_net(geneve->dev))))
+               goto drop;
+
+       geneve_rx(geneve, gs, skb);
        return 0;
 
 drop:
@@ -383,7 +407,7 @@ static void geneve_notify_add_rx_port(struct geneve_sock *gs)
        struct net_device *dev;
        struct sock *sk = gs->sock->sk;
        struct net *net = sock_net(sk);
-       sa_family_t sa_family = sk->sk_family;
+       sa_family_t sa_family = geneve_get_sk_family(gs);
        __be16 port = inet_sk(sk)->inet_sport;
        int err;
 
@@ -439,8 +463,6 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
                        goto out;
        }
 
-       flush = 0;
-
        for (p = *head; p; p = p->next) {
                if (!NAPI_GRO_CB(p)->same_flow)
                        continue;
@@ -457,14 +479,13 @@ static struct sk_buff **geneve_gro_receive(struct sk_buff **head,
 
        rcu_read_lock();
        ptype = gro_find_receive_by_type(type);
-       if (!ptype) {
-               flush = 1;
+       if (!ptype)
                goto out_unlock;
-       }
 
        skb_gro_pull(skb, gh_len);
        skb_gro_postpull_rcsum(skb, gh, gh_len);
        pp = ptype->callbacks.gro_receive(head, skb);
+       flush = 0;
 
 out_unlock:
        rcu_read_unlock();
@@ -544,7 +565,7 @@ static void geneve_notify_del_rx_port(struct geneve_sock *gs)
        struct net_device *dev;
        struct sock *sk = gs->sock->sk;
        struct net *net = sock_net(sk);
-       sa_family_t sa_family = sk->sk_family;
+       sa_family_t sa_family = geneve_get_sk_family(gs);
        __be16 port = inet_sk(sk)->inet_sport;
 
        rcu_read_lock();
@@ -587,7 +608,7 @@ static struct geneve_sock *geneve_find_sock(struct geneve_net *gn,
 
        list_for_each_entry(gs, &gn->sock_list, list) {
                if (inet_sk(gs->sock->sk)->inet_sport == dst_port &&
-                   inet_sk(gs->sock->sk)->sk.sk_family == family) {
+                   geneve_get_sk_family(gs) == family) {
                        return gs;
                }
        }
@@ -680,7 +701,7 @@ static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb,
        struct genevehdr *gnvh;
        int min_headroom;
        int err;
-       bool udp_sum = !!(flags & GENEVE_F_UDP_CSUM);
+       bool udp_sum = !(flags & GENEVE_F_UDP_ZERO_CSUM_TX);
 
        skb_scrub_packet(skb, xnet);
 
@@ -752,7 +773,9 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
                                       struct flowi4 *fl4,
                                       struct ip_tunnel_info *info)
 {
+       bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct geneve_dev *geneve = netdev_priv(dev);
+       struct dst_cache *dst_cache;
        struct rtable *rt = NULL;
        __u8 tos;
 
@@ -764,16 +787,25 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
                fl4->daddr = info->key.u.ipv4.dst;
                fl4->saddr = info->key.u.ipv4.src;
                fl4->flowi4_tos = RT_TOS(info->key.tos);
+               dst_cache = &info->dst_cache;
        } else {
                tos = geneve->tos;
                if (tos == 1) {
                        const struct iphdr *iip = ip_hdr(skb);
 
                        tos = ip_tunnel_get_dsfield(iip, skb);
+                       use_cache = false;
                }
 
                fl4->flowi4_tos = RT_TOS(tos);
                fl4->daddr = geneve->remote.sin.sin_addr.s_addr;
+               dst_cache = &geneve->dst_cache;
+       }
+
+       if (use_cache) {
+               rt = dst_cache_get_ip4(dst_cache, &fl4->saddr);
+               if (rt)
+                       return rt;
        }
 
        rt = ip_route_output_key(geneve->net, fl4);
@@ -786,6 +818,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
                ip_rt_put(rt);
                return ERR_PTR(-ELOOP);
        }
+       if (use_cache)
+               dst_cache_set_ip4(dst_cache, &rt->dst, fl4->saddr);
        return rt;
 }
 
@@ -795,9 +829,11 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
                                           struct flowi6 *fl6,
                                           struct ip_tunnel_info *info)
 {
+       bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct geneve_dev *geneve = netdev_priv(dev);
        struct geneve_sock *gs6 = geneve->sock6;
        struct dst_entry *dst = NULL;
+       struct dst_cache *dst_cache;
        __u8 prio;
 
        memset(fl6, 0, sizeof(*fl6));
@@ -808,16 +844,27 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
                fl6->daddr = info->key.u.ipv6.dst;
                fl6->saddr = info->key.u.ipv6.src;
                fl6->flowi6_tos = RT_TOS(info->key.tos);
+               fl6->flowlabel = info->key.label;
+               dst_cache = &info->dst_cache;
        } else {
                prio = geneve->tos;
                if (prio == 1) {
                        const struct iphdr *iip = ip_hdr(skb);
 
                        prio = ip_tunnel_get_dsfield(iip, skb);
+                       use_cache = false;
                }
 
                fl6->flowi6_tos = RT_TOS(prio);
+               fl6->flowlabel = geneve->label;
                fl6->daddr = geneve->remote.sin6.sin6_addr;
+               dst_cache = &geneve->dst_cache;
+       }
+
+       if (use_cache) {
+               dst = dst_cache_get_ip6(dst_cache, &fl6->saddr);
+               if (dst)
+                       return dst;
        }
 
        if (ipv6_stub->ipv6_dst_lookup(geneve->net, gs6->sock->sk, &dst, fl6)) {
@@ -830,6 +877,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
                return ERR_PTR(-ELOOP);
        }
 
+       if (use_cache)
+               dst_cache_set_ip6(dst_cache, dst, &fl6->saddr);
        return dst;
 }
 #endif
@@ -889,13 +938,13 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                u8 vni[3];
 
                tunnel_id_to_vni(key->tun_id, vni);
-               if (key->tun_flags & TUNNEL_GENEVE_OPT)
+               if (info->options_len)
                        opts = ip_tunnel_info_opts(info);
 
                if (key->tun_flags & TUNNEL_CSUM)
-                       flags |= GENEVE_F_UDP_CSUM;
+                       flags &= ~GENEVE_F_UDP_ZERO_CSUM_TX;
                else
-                       flags &= ~GENEVE_F_UDP_CSUM;
+                       flags |= GENEVE_F_UDP_ZERO_CSUM_TX;
 
                err = geneve_build_skb(rt, skb, key->tun_flags, vni,
                                       info->options_len, opts, flags, xnet);
@@ -921,7 +970,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, fl4.saddr, fl4.daddr,
                            tos, ttl, df, sport, geneve->dst_port,
                            !net_eq(geneve->net, dev_net(geneve->dev)),
-                           !(flags & GENEVE_F_UDP_CSUM));
+                           !!(flags & GENEVE_F_UDP_ZERO_CSUM_TX));
 
        return NETDEV_TX_OK;
 
@@ -949,6 +998,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
        struct flowi6 fl6;
        __u8 prio, ttl;
        __be16 sport;
+       __be32 label;
        bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
        u32 flags = geneve->flags;
 
@@ -976,7 +1026,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                u8 vni[3];
 
                tunnel_id_to_vni(key->tun_id, vni);
-               if (key->tun_flags & TUNNEL_GENEVE_OPT)
+               if (info->options_len)
                        opts = ip_tunnel_info_opts(info);
 
                if (key->tun_flags & TUNNEL_CSUM)
@@ -992,6 +1042,7 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 
                prio = ip_tunnel_ecn_encap(key->tos, iip, skb);
                ttl = key->ttl;
+               label = info->key.label;
        } else {
                err = geneve6_build_skb(dst, skb, 0, geneve->vni,
                                        0, NULL, flags, xnet);
@@ -1003,9 +1054,11 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
                if (!ttl && ipv6_addr_is_multicast(&fl6.daddr))
                        ttl = 1;
                ttl = ttl ? : ip6_dst_hoplimit(dst);
+               label = geneve->label;
        }
+
        udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
-                            &fl6.saddr, &fl6.daddr, prio, ttl,
+                            &fl6.saddr, &fl6.daddr, prio, ttl, label,
                             sport, geneve->dst_port,
                             !!(flags & GENEVE_F_UDP_ZERO_CSUM6_TX));
        return NETDEV_TX_OK;
@@ -1039,6 +1092,34 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
        return geneve_xmit_skb(skb, dev, info);
 }
 
+static int __geneve_change_mtu(struct net_device *dev, int new_mtu, bool strict)
+{
+       /* The max_mtu calculation does not take account of GENEVE
+        * options, to avoid excluding potentially valid
+        * configurations.
+        */
+       int max_mtu = IP_MAX_MTU - GENEVE_BASE_HLEN - sizeof(struct iphdr)
+               - dev->hard_header_len;
+
+       if (new_mtu < 68)
+               return -EINVAL;
+
+       if (new_mtu > max_mtu) {
+               if (strict)
+                       return -EINVAL;
+
+               new_mtu = max_mtu;
+       }
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static int geneve_change_mtu(struct net_device *dev, int new_mtu)
+{
+       return __geneve_change_mtu(dev, new_mtu, true);
+}
+
 static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
        struct ip_tunnel_info *info = skb_tunnel_info(skb);
@@ -1083,7 +1164,7 @@ static const struct net_device_ops geneve_netdev_ops = {
        .ndo_stop               = geneve_stop,
        .ndo_start_xmit         = geneve_xmit,
        .ndo_get_stats64        = ip_tunnel_get_stats64,
-       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_change_mtu         = geneve_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_fill_metadata_dst  = geneve_fill_metadata_dst,
@@ -1150,6 +1231,7 @@ static void geneve_setup(struct net_device *dev)
        dev->hw_features |= NETIF_F_GSO_SOFTWARE;
 
        netif_keep_dst(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
        eth_hw_addr_random(dev);
 }
@@ -1160,6 +1242,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
        [IFLA_GENEVE_REMOTE6]           = { .len = sizeof(struct in6_addr) },
        [IFLA_GENEVE_TTL]               = { .type = NLA_U8 },
        [IFLA_GENEVE_TOS]               = { .type = NLA_U8 },
+       [IFLA_GENEVE_LABEL]             = { .type = NLA_U32 },
        [IFLA_GENEVE_PORT]              = { .type = NLA_U16 },
        [IFLA_GENEVE_COLLECT_METADATA]  = { .type = NLA_FLAG },
        [IFLA_GENEVE_UDP_CSUM]          = { .type = NLA_U8 },
@@ -1217,8 +1300,8 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
 
 static int geneve_configure(struct net *net, struct net_device *dev,
                            union geneve_addr *remote,
-                           __u32 vni, __u8 ttl, __u8 tos, __be16 dst_port,
-                           bool metadata, u32 flags)
+                           __u32 vni, __u8 ttl, __u8 tos, __be32 label,
+                           __be16 dst_port, bool metadata, u32 flags)
 {
        struct geneve_net *gn = net_generic(net, geneve_net_id);
        struct geneve_dev *t, *geneve = netdev_priv(dev);
@@ -1228,7 +1311,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
        if (!remote)
                return -EINVAL;
        if (metadata &&
-           (remote->sa.sa_family != AF_UNSPEC || vni || tos || ttl))
+           (remote->sa.sa_family != AF_UNSPEC || vni || tos || ttl || label))
                return -EINVAL;
 
        geneve->net = net;
@@ -1243,10 +1326,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
            (remote->sa.sa_family == AF_INET6 &&
             ipv6_addr_is_multicast(&remote->sin6.sin6_addr)))
                return -EINVAL;
+       if (label && remote->sa.sa_family != AF_INET6)
+               return -EINVAL;
+
        geneve->remote = *remote;
 
        geneve->ttl = ttl;
        geneve->tos = tos;
+       geneve->label = label;
        geneve->dst_port = dst_port;
        geneve->collect_md = metadata;
        geneve->flags = flags;
@@ -1272,6 +1359,8 @@ static int geneve_configure(struct net *net, struct net_device *dev,
                        return -EPERM;
        }
 
+       dst_cache_reset(&geneve->dst_cache);
+
        err = register_netdevice(dev);
        if (err)
                return err;
@@ -1287,6 +1376,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
        __u8 ttl = 0, tos = 0;
        bool metadata = false;
        union geneve_addr remote = geneve_remote_unspec;
+       __be32 label = 0;
        __u32 vni = 0;
        u32 flags = 0;
 
@@ -1323,6 +1413,10 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
        if (data[IFLA_GENEVE_TOS])
                tos = nla_get_u8(data[IFLA_GENEVE_TOS]);
 
+       if (data[IFLA_GENEVE_LABEL])
+               label = nla_get_be32(data[IFLA_GENEVE_LABEL]) &
+                       IPV6_FLOWLABEL_MASK;
+
        if (data[IFLA_GENEVE_PORT])
                dst_port = nla_get_be16(data[IFLA_GENEVE_PORT]);
 
@@ -1330,8 +1424,8 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
                metadata = true;
 
        if (data[IFLA_GENEVE_UDP_CSUM] &&
-           nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
-               flags |= GENEVE_F_UDP_CSUM;
+           !nla_get_u8(data[IFLA_GENEVE_UDP_CSUM]))
+               flags |= GENEVE_F_UDP_ZERO_CSUM_TX;
 
        if (data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX] &&
            nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
@@ -1341,8 +1435,8 @@ static int geneve_newlink(struct net *net, struct net_device *dev,
            nla_get_u8(data[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
                flags |= GENEVE_F_UDP_ZERO_CSUM6_RX;
 
-       return geneve_configure(net, dev, &remote, vni, ttl, tos, dst_port,
-                               metadata, flags);
+       return geneve_configure(net, dev, &remote, vni, ttl, tos, label,
+                               dst_port, metadata, flags);
 }
 
 static void geneve_dellink(struct net_device *dev, struct list_head *head)
@@ -1359,6 +1453,7 @@ static size_t geneve_get_size(const struct net_device *dev)
                nla_total_size(sizeof(struct in6_addr)) + /* IFLA_GENEVE_REMOTE{6} */
                nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TTL */
                nla_total_size(sizeof(__u8)) +  /* IFLA_GENEVE_TOS */
+               nla_total_size(sizeof(__be32)) +  /* IFLA_GENEVE_LABEL */
                nla_total_size(sizeof(__be16)) +  /* IFLA_GENEVE_PORT */
                nla_total_size(0) +      /* IFLA_GENEVE_COLLECT_METADATA */
                nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_UDP_CSUM */
@@ -1389,7 +1484,8 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
        }
 
        if (nla_put_u8(skb, IFLA_GENEVE_TTL, geneve->ttl) ||
-           nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos))
+           nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos) ||
+           nla_put_be32(skb, IFLA_GENEVE_LABEL, geneve->label))
                goto nla_put_failure;
 
        if (nla_put_be16(skb, IFLA_GENEVE_PORT, geneve->dst_port))
@@ -1401,7 +1497,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
        }
 
        if (nla_put_u8(skb, IFLA_GENEVE_UDP_CSUM,
-                      !!(geneve->flags & GENEVE_F_UDP_CSUM)) ||
+                      !(geneve->flags & GENEVE_F_UDP_ZERO_CSUM_TX)) ||
            nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
                       !!(geneve->flags & GENEVE_F_UDP_ZERO_CSUM6_TX)) ||
            nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
@@ -1441,12 +1537,23 @@ struct net_device *geneve_dev_create_fb(struct net *net, const char *name,
                return dev;
 
        err = geneve_configure(net, dev, &geneve_remote_unspec,
-                              0, 0, 0, htons(dst_port), true, 0);
-       if (err) {
-               free_netdev(dev);
-               return ERR_PTR(err);
-       }
+                              0, 0, 0, 0, htons(dst_port), true,
+                              GENEVE_F_UDP_ZERO_CSUM6_RX);
+       if (err)
+               goto err;
+
+       /* openvswitch users expect packet sizes to be unrestricted,
+        * so set the largest MTU we can.
+        */
+       err = __geneve_change_mtu(dev, IP_MAX_MTU, false);
+       if (err)
+               goto err;
+
        return dev;
+
+ err:
+       free_netdev(dev);
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(geneve_dev_create_fb);
 
index c3d37777061631d1c34fb1b1e05f36986bb5f6cc..e4137c1b3df9451fe78593e42f8a1f2d4ea7d956 100644 (file)
@@ -451,7 +451,7 @@ static const struct net_device_ops scc_netdev_ops = {
 
 static int __init setup_adapter(int card_base, int type, int n)
 {
-       int i, irq, chip;
+       int i, irq, chip, err;
        struct scc_info *info;
        struct net_device *dev;
        struct scc_priv *priv;
@@ -463,14 +463,17 @@ static int __init setup_adapter(int card_base, int type, int n)
 
        /* Initialize what is necessary for write_scc and write_scc_data */
        info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
-       if (!info)
+       if (!info) {
+               err = -ENOMEM;
                goto out;
+       }
 
        info->dev[0] = alloc_netdev(0, "", NET_NAME_UNKNOWN, dev_setup);
        if (!info->dev[0]) {
                printk(KERN_ERR "dmascc: "
                       "could not allocate memory for %s at %#3x\n",
                       hw[type].name, card_base);
+               err = -ENOMEM;
                goto out1;
        }
 
@@ -479,6 +482,7 @@ static int __init setup_adapter(int card_base, int type, int n)
                printk(KERN_ERR "dmascc: "
                       "could not allocate memory for %s at %#3x\n",
                       hw[type].name, card_base);
+               err = -ENOMEM;
                goto out2;
        }
        spin_lock_init(&info->register_lock);
@@ -549,6 +553,7 @@ static int __init setup_adapter(int card_base, int type, int n)
                printk(KERN_ERR
                       "dmascc: could not find irq of %s at %#3x (irq=%d)\n",
                       hw[type].name, card_base, irq);
+               err = -ENODEV;
                goto out3;
        }
 
@@ -585,11 +590,13 @@ static int __init setup_adapter(int card_base, int type, int n)
        if (register_netdev(info->dev[0])) {
                printk(KERN_ERR "dmascc: could not register %s\n",
                       info->dev[0]->name);
+               err = -ENODEV;
                goto out3;
        }
        if (register_netdev(info->dev[1])) {
                printk(KERN_ERR "dmascc: could not register %s\n",
                       info->dev[1]->name);
+               err = -ENODEV;
                goto out4;
        }
 
@@ -612,7 +619,7 @@ static int __init setup_adapter(int card_base, int type, int n)
       out1:
        kfree(info);
       out:
-       return -1;
+       return err;
 }
 
 
index fcb92c0d0eb967e0deba99282152a25c804b73ea..b4c68783dfc390b5711a18e3b75e4f4a1c961cc0 100644 (file)
@@ -658,6 +658,10 @@ struct net_device_context {
 
        struct netvsc_stats __percpu *tx_stats;
        struct netvsc_stats __percpu *rx_stats;
+
+       /* Ethtool settings */
+       u8 duplex;
+       u32 speed;
 };
 
 /* Per netvsc device */
index c72e5b83afdbc9ec509106ed5cb70bbc0539372a..08608499fa17364717626147d8c6ec2a894a25bd 100644 (file)
@@ -550,6 +550,8 @@ do_send:
        packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
                                               skb, packet, &pb);
 
+       /* timestamp packet in software */
+       skb_tx_timestamp(skb);
        ret = netvsc_send(net_device_ctx->device_ctx, packet,
                          rndis_msg, &pb, skb);
 
@@ -797,6 +799,58 @@ static int netvsc_set_channels(struct net_device *net,
        goto do_set;
 }
 
+static bool netvsc_validate_ethtool_ss_cmd(const struct ethtool_cmd *cmd)
+{
+       struct ethtool_cmd diff1 = *cmd;
+       struct ethtool_cmd diff2 = {};
+
+       ethtool_cmd_speed_set(&diff1, 0);
+       diff1.duplex = 0;
+       /* advertising and cmd are usually set */
+       diff1.advertising = 0;
+       diff1.cmd = 0;
+       /* We set port to PORT_OTHER */
+       diff2.port = PORT_OTHER;
+
+       return !memcmp(&diff1, &diff2, sizeof(diff1));
+}
+
+static void netvsc_init_settings(struct net_device *dev)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+
+       ndc->speed = SPEED_UNKNOWN;
+       ndc->duplex = DUPLEX_UNKNOWN;
+}
+
+static int netvsc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+
+       ethtool_cmd_speed_set(cmd, ndc->speed);
+       cmd->duplex = ndc->duplex;
+       cmd->port = PORT_OTHER;
+
+       return 0;
+}
+
+static int netvsc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct net_device_context *ndc = netdev_priv(dev);
+       u32 speed;
+
+       speed = ethtool_cmd_speed(cmd);
+       if (!ethtool_validate_speed(speed) ||
+           !ethtool_validate_duplex(cmd->duplex) ||
+           !netvsc_validate_ethtool_ss_cmd(cmd))
+               return -EINVAL;
+
+       ndc->speed = speed;
+       ndc->duplex = cmd->duplex;
+
+       return 0;
+}
+
 static int netvsc_change_mtu(struct net_device *ndev, int mtu)
 {
        struct net_device_context *ndevctx = netdev_priv(ndev);
@@ -920,6 +974,9 @@ static const struct ethtool_ops ethtool_ops = {
        .get_link       = ethtool_op_get_link,
        .get_channels   = netvsc_get_channels,
        .set_channels   = netvsc_set_channels,
+       .get_ts_info    = ethtool_op_get_ts_info,
+       .get_settings   = netvsc_get_settings,
+       .set_settings   = netvsc_set_settings,
 };
 
 static const struct net_device_ops device_ops = {
@@ -1092,6 +1149,9 @@ static int netvsc_probe(struct hv_device *dev,
        net->ethtool_ops = &ethtool_ops;
        SET_NETDEV_DEV(net, &dev->device);
 
+       /* We always need headroom for rndis header */
+       net->needed_headroom = RNDIS_AND_PPI_SIZE;
+
        /* Notify the netvsc driver of the new device */
        memset(&device_info, 0, sizeof(device_info));
        device_info.ring_size = ring_size;
@@ -1109,6 +1169,8 @@ static int netvsc_probe(struct hv_device *dev,
        netif_set_real_num_tx_queues(net, nvdev->num_chn);
        netif_set_real_num_rx_queues(net, nvdev->num_chn);
 
+       netvsc_init_settings(net);
+
        ret = register_netdev(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
index a37bbda37ffa628cf7752e41a4d68d69f3c9e331..47d07c576a344ae144a78ec5064e7091eadbfa24 100644 (file)
@@ -1175,22 +1175,18 @@ int rndis_filter_device_add(struct hv_device *dev,
        ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn);
 
        /*
-        * Wait for the host to send us the sub-channel offers.
+        * Set the number of sub-channels to be received.
         */
        spin_lock_irqsave(&net_device->sc_lock, flags);
        sc_delta = num_rss_qs - (net_device->num_chn - 1);
        net_device->num_sc_offered -= sc_delta;
        spin_unlock_irqrestore(&net_device->sc_lock, flags);
 
-       while (net_device->num_sc_offered != 0) {
-               t = wait_for_completion_timeout(&net_device->channel_init_wait, 10*HZ);
-               if (t == 0)
-                       WARN(1, "Netvsc: Waiting for sub-channel processing");
-       }
 out:
        if (ret) {
                net_device->max_chn = 1;
                net_device->num_chn = 1;
+               net_device->num_sc_offered = 0;
        }
 
        return 0; /* return 0 because primary channel can be used alone */
@@ -1204,6 +1200,17 @@ void rndis_filter_device_remove(struct hv_device *dev)
 {
        struct netvsc_device *net_dev = hv_get_drvdata(dev);
        struct rndis_device *rndis_dev = net_dev->extension;
+       unsigned long t;
+
+       /* If not all subchannel offers are complete, wait for them until
+        * completion to avoid race.
+        */
+       while (net_dev->num_sc_offered > 0) {
+               t = wait_for_completion_timeout(&net_dev->channel_init_wait,
+                                               10 * HZ);
+               if (t == 0)
+                       WARN(1, "Netvsc: Waiting for sub-channel processing");
+       }
 
        /* Halt and release the rndis device */
        rndis_filter_halt_device(rndis_dev);
index 0fbbba7a0cae38afe5fc6dfa122489c1a3271fdf..cb9e9fe6d77a0b75a8d0f88f523b4f6059830dcc 100644 (file)
@@ -343,16 +343,26 @@ static const struct regmap_config at86rf230_regmap_spi_config = {
 };
 
 static void
-at86rf230_async_error_recover(void *context)
+at86rf230_async_error_recover_complete(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       lp->is_tx = 0;
-       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL);
-       ieee802154_wake_queue(lp->hw);
        if (ctx->free)
                kfree(ctx);
+
+       ieee802154_wake_queue(lp->hw);
+}
+
+static void
+at86rf230_async_error_recover(void *context)
+{
+       struct at86rf230_state_change *ctx = context;
+       struct at86rf230_local *lp = ctx->lp;
+
+       lp->is_tx = 0;
+       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
+                                    at86rf230_async_error_recover_complete);
 }
 
 static inline void
@@ -892,14 +902,12 @@ at86rf230_xmit_start(void *context)
        struct at86rf230_local *lp = ctx->lp;
 
        /* check if we change from off state */
-       if (lp->is_tx_from_off) {
-               lp->is_tx_from_off = false;
+       if (lp->is_tx_from_off)
                at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
                                             at86rf230_write_frame);
-       } else {
+       else
                at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
                                             at86rf230_xmit_tx_on);
-       }
 }
 
 static int
@@ -923,6 +931,7 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
                at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF,
                                             at86rf230_xmit_start);
        } else {
+               lp->is_tx_from_off = false;
                at86rf230_xmit_start(ctx);
        }
 
index 4cdf51638972095644204eebccf46c8c77421ef2..764a2bddfaee390e936fed48eab0487b8ac9766a 100644 (file)
@@ -310,6 +310,7 @@ mrf24j40_short_reg_writeable(struct device *dev, unsigned int reg)
        case REG_TRISGPIO:
        case REG_GPIO:
        case REG_RFCTL:
+       case REG_SECCR2:
        case REG_SLPACK:
        case REG_BBREG0:
        case REG_BBREG1:
index 9542b7bac61afab0f4537d91f8cc004160521f85..695a5dc9ace36c01d50233f6bd5e62e42581d39a 100644 (file)
@@ -84,19 +84,19 @@ struct ipvl_addr {
 #define ip4addr ipu.ip4
        struct hlist_node       hlnode;  /* Hash-table linkage */
        struct list_head        anode;   /* logical-interface linkage */
-       struct rcu_head         rcu;
        ipvl_hdr_type           atype;
+       struct rcu_head         rcu;
 };
 
 struct ipvl_port {
        struct net_device       *dev;
        struct hlist_head       hlhead[IPVLAN_HASH_SIZE];
        struct list_head        ipvlans;
-       struct rcu_head         rcu;
+       u16                     mode;
        struct work_struct      wq;
        struct sk_buff_head     backlog;
        int                     count;
-       u16                     mode;
+       struct rcu_head         rcu;
 };
 
 static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d)
@@ -114,8 +114,6 @@ static inline struct ipvl_port *ipvlan_port_get_rtnl(const struct net_device *d)
        return rtnl_dereference(d->rx_handler_data);
 }
 
-void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev);
-void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval);
 void ipvlan_init_secret(void);
 unsigned int ipvlan_mac_hash(const unsigned char *addr);
 rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb);
@@ -125,7 +123,5 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr);
 struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
                                   const void *iaddr, bool is_v6);
 bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
-struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
-                                       const void *iaddr, bool is_v6);
 void ipvlan_ht_addr_del(struct ipvl_addr *addr);
 #endif /* __IPVLAN_H */
index 8c48bb2a94ea063aa9dd7c4dc662aa772f34930c..d6d0524ee5fd2e19d5c5a2bdb5437f6a2748b8e7 100644 (file)
@@ -53,8 +53,8 @@ static u8 ipvlan_get_v4_hash(const void *iaddr)
               IPVLAN_HASH_MASK;
 }
 
-struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
-                                       const void *iaddr, bool is_v6)
+static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
+                                              const void *iaddr, bool is_v6)
 {
        struct ipvl_addr *addr;
        u8 hash;
@@ -265,20 +265,25 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
        struct sk_buff *skb = *pskb;
 
        len = skb->len + ETH_HLEN;
-       if (unlikely(!(dev->flags & IFF_UP))) {
-               kfree_skb(skb);
-               goto out;
-       }
+       /* Only packets exchanged between two local slaves need to have
+        * device-up check as well as skb-share check.
+        */
+       if (local) {
+               if (unlikely(!(dev->flags & IFF_UP))) {
+                       kfree_skb(skb);
+                       goto out;
+               }
 
-       skb = skb_share_check(skb, GFP_ATOMIC);
-       if (!skb)
-               goto out;
+               skb = skb_share_check(skb, GFP_ATOMIC);
+               if (!skb)
+                       goto out;
 
-       *pskb = skb;
+               *pskb = skb;
+       }
        skb->dev = dev;
-       skb->pkt_type = PACKET_HOST;
 
        if (local) {
+               skb->pkt_type = PACKET_HOST;
                if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS)
                        success = true;
        } else {
@@ -342,7 +347,7 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
        return addr;
 }
 
-static int ipvlan_process_v4_outbound(struct sk_buff *skb)
+static int ipvlan_process_v4_outbound(struct sk_buff *skb, bool xnet)
 {
        const struct iphdr *ip4h = ip_hdr(skb);
        struct net_device *dev = skb->dev;
@@ -365,7 +370,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb)
                ip_rt_put(rt);
                goto err;
        }
-       skb_dst_drop(skb);
+       skb_scrub_packet(skb, xnet);
        skb_dst_set(skb, &rt->dst);
        err = ip_local_out(net, skb->sk, skb);
        if (unlikely(net_xmit_eval(err)))
@@ -380,7 +385,7 @@ out:
        return ret;
 }
 
-static int ipvlan_process_v6_outbound(struct sk_buff *skb)
+static int ipvlan_process_v6_outbound(struct sk_buff *skb, bool xnet)
 {
        const struct ipv6hdr *ip6h = ipv6_hdr(skb);
        struct net_device *dev = skb->dev;
@@ -403,7 +408,7 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb)
                dst_release(dst);
                goto err;
        }
-       skb_dst_drop(skb);
+       skb_scrub_packet(skb, xnet);
        skb_dst_set(skb, dst);
        err = ip6_local_out(net, skb->sk, skb);
        if (unlikely(net_xmit_eval(err)))
@@ -418,8 +423,7 @@ out:
        return ret;
 }
 
-static int ipvlan_process_outbound(struct sk_buff *skb,
-                                  const struct ipvl_dev *ipvlan)
+static int ipvlan_process_outbound(struct sk_buff *skb, bool xnet)
 {
        struct ethhdr *ethh = eth_hdr(skb);
        int ret = NET_XMIT_DROP;
@@ -443,9 +447,9 @@ static int ipvlan_process_outbound(struct sk_buff *skb,
        }
 
        if (skb->protocol == htons(ETH_P_IPV6))
-               ret = ipvlan_process_v6_outbound(skb);
+               ret = ipvlan_process_v6_outbound(skb, xnet);
        else if (skb->protocol == htons(ETH_P_IP))
-               ret = ipvlan_process_v4_outbound(skb);
+               ret = ipvlan_process_v4_outbound(skb, xnet);
        else {
                pr_warn_ratelimited("Dropped outbound packet type=%x\n",
                                    ntohs(skb->protocol));
@@ -481,6 +485,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
        void *lyr3h;
        struct ipvl_addr *addr;
        int addr_type;
+       bool xnet;
 
        lyr3h = ipvlan_get_L3_hdr(skb, &addr_type);
        if (!lyr3h)
@@ -491,8 +496,9 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
                return ipvlan_rcv_frame(addr, &skb, true);
 
 out:
+       xnet = !net_eq(dev_net(skb->dev), dev_net(ipvlan->phy_dev));
        skb->dev = ipvlan->phy_dev;
-       return ipvlan_process_outbound(skb, ipvlan);
+       return ipvlan_process_outbound(skb, xnet);
 }
 
 static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
index 7a3b41468a55180b1bdfe1be5d494d16eef701b9..5802b902576594240f39d12c8db0fee8fe707b4e 100644 (file)
@@ -9,12 +9,12 @@
 
 #include "ipvlan.h"
 
-void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
+static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
 {
        ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj;
 }
 
-void ipvlan_set_port_mode(struct ipvl_port *port, u32 nval)
+static void ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
 {
        struct ipvl_dev *ipvlan;
 
@@ -346,12 +346,12 @@ static const struct header_ops ipvlan_header_ops = {
        .cache_update   = eth_header_cache_update,
 };
 
-static int ipvlan_ethtool_get_settings(struct net_device *dev,
-                                      struct ethtool_cmd *cmd)
+static int ipvlan_ethtool_get_link_ksettings(struct net_device *dev,
+                                            struct ethtool_link_ksettings *cmd)
 {
        const struct ipvl_dev *ipvlan = netdev_priv(dev);
 
-       return __ethtool_get_settings(ipvlan->phy_dev, cmd);
+       return __ethtool_get_link_ksettings(ipvlan->phy_dev, cmd);
 }
 
 static void ipvlan_ethtool_get_drvinfo(struct net_device *dev,
@@ -377,7 +377,7 @@ static void ipvlan_ethtool_set_msglevel(struct net_device *dev, u32 value)
 
 static const struct ethtool_ops ipvlan_ethtool_ops = {
        .get_link       = ethtool_op_get_link,
-       .get_settings   = ipvlan_ethtool_get_settings,
+       .get_link_ksettings     = ipvlan_ethtool_get_link_ksettings,
        .get_drvinfo    = ipvlan_ethtool_get_drvinfo,
        .get_msglevel   = ipvlan_ethtool_get_msglevel,
        .set_msglevel   = ipvlan_ethtool_set_msglevel,
@@ -442,6 +442,7 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
        struct ipvl_port *port;
        struct net_device *phy_dev;
        int err;
+       u16 mode = IPVLAN_MODE_L3;
 
        if (!tb[IFLA_LINK])
                return -EINVAL;
@@ -460,10 +461,10 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
                        return err;
        }
 
-       port = ipvlan_port_get_rtnl(phy_dev);
        if (data && data[IFLA_IPVLAN_MODE])
-               port->mode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
+               mode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
 
+       port = ipvlan_port_get_rtnl(phy_dev);
        ipvlan->phy_dev = phy_dev;
        ipvlan->dev = dev;
        ipvlan->port = port;
@@ -489,6 +490,8 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
                goto ipvlan_destroy_port;
 
        list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
+       ipvlan_set_port_mode(port, mode);
+
        netif_stacked_transfer_operstate(phy_dev, dev);
        return 0;
 
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
new file mode 100644 (file)
index 0000000..84d3e5c
--- /dev/null
@@ -0,0 +1,3297 @@
+/*
+ * drivers/net/macsec.c - MACsec device
+ *
+ * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/module.h>
+#include <crypto/aead.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/genetlink.h>
+#include <net/sock.h>
+
+#include <uapi/linux/if_macsec.h>
+
+typedef u64 __bitwise sci_t;
+
+#define MACSEC_SCI_LEN 8
+
+/* SecTAG length = macsec_eth_header without the optional SCI */
+#define MACSEC_TAG_LEN 6
+
+struct macsec_eth_header {
+       struct ethhdr eth;
+       /* SecTAG */
+       u8  tci_an;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8  short_length:6,
+                 unused:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       u8        unused:2,
+           short_length:6;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+       __be32 packet_number;
+       u8 secure_channel_id[8]; /* optional */
+} __packed;
+
+#define MACSEC_TCI_VERSION 0x80
+#define MACSEC_TCI_ES      0x40 /* end station */
+#define MACSEC_TCI_SC      0x20 /* SCI present */
+#define MACSEC_TCI_SCB     0x10 /* epon */
+#define MACSEC_TCI_E       0x08 /* encryption */
+#define MACSEC_TCI_C       0x04 /* changed text */
+#define MACSEC_AN_MASK     0x03 /* association number */
+#define MACSEC_TCI_CONFID  (MACSEC_TCI_E | MACSEC_TCI_C)
+
+/* minimum secure data length deemed "not short", see IEEE 802.1AE-2006 9.7 */
+#define MIN_NON_SHORT_LEN 48
+
+#define GCM_AES_IV_LEN 12
+#define DEFAULT_ICV_LEN 16
+
+#define MACSEC_NUM_AN 4 /* 2 bits for the association number */
+
+#define for_each_rxsc(secy, sc)                        \
+       for (sc = rcu_dereference_bh(secy->rx_sc);      \
+            sc;                                \
+            sc = rcu_dereference_bh(sc->next))
+#define for_each_rxsc_rtnl(secy, sc)                   \
+       for (sc = rtnl_dereference(secy->rx_sc);        \
+            sc;                                        \
+            sc = rtnl_dereference(sc->next))
+
+struct gcm_iv {
+       union {
+               u8 secure_channel_id[8];
+               sci_t sci;
+       };
+       __be32 pn;
+};
+
+/**
+ * struct macsec_key - SA key
+ * @id: user-provided key identifier
+ * @tfm: crypto struct, key storage
+ */
+struct macsec_key {
+       u64 id;
+       struct crypto_aead *tfm;
+};
+
+struct macsec_rx_sc_stats {
+       __u64 InOctetsValidated;
+       __u64 InOctetsDecrypted;
+       __u64 InPktsUnchecked;
+       __u64 InPktsDelayed;
+       __u64 InPktsOK;
+       __u64 InPktsInvalid;
+       __u64 InPktsLate;
+       __u64 InPktsNotValid;
+       __u64 InPktsNotUsingSA;
+       __u64 InPktsUnusedSA;
+};
+
+struct macsec_rx_sa_stats {
+       __u32 InPktsOK;
+       __u32 InPktsInvalid;
+       __u32 InPktsNotValid;
+       __u32 InPktsNotUsingSA;
+       __u32 InPktsUnusedSA;
+};
+
+struct macsec_tx_sa_stats {
+       __u32 OutPktsProtected;
+       __u32 OutPktsEncrypted;
+};
+
+struct macsec_tx_sc_stats {
+       __u64 OutPktsProtected;
+       __u64 OutPktsEncrypted;
+       __u64 OutOctetsProtected;
+       __u64 OutOctetsEncrypted;
+};
+
+struct macsec_dev_stats {
+       __u64 OutPktsUntagged;
+       __u64 InPktsUntagged;
+       __u64 OutPktsTooLong;
+       __u64 InPktsNoTag;
+       __u64 InPktsBadTag;
+       __u64 InPktsUnknownSCI;
+       __u64 InPktsNoSCI;
+       __u64 InPktsOverrun;
+};
+
+/**
+ * struct macsec_rx_sa - receive secure association
+ * @active:
+ * @next_pn: packet number expected for the next packet
+ * @lock: protects next_pn manipulations
+ * @key: key structure
+ * @stats: per-SA stats
+ */
+struct macsec_rx_sa {
+       struct macsec_key key;
+       spinlock_t lock;
+       u32 next_pn;
+       atomic_t refcnt;
+       bool active;
+       struct macsec_rx_sa_stats __percpu *stats;
+       struct macsec_rx_sc *sc;
+       struct rcu_head rcu;
+};
+
+struct pcpu_rx_sc_stats {
+       struct macsec_rx_sc_stats stats;
+       struct u64_stats_sync syncp;
+};
+
+/**
+ * struct macsec_rx_sc - receive secure channel
+ * @sci: secure channel identifier for this SC
+ * @active: channel is active
+ * @sa: array of secure associations
+ * @stats: per-SC stats
+ */
+struct macsec_rx_sc {
+       struct macsec_rx_sc __rcu *next;
+       sci_t sci;
+       bool active;
+       struct macsec_rx_sa __rcu *sa[MACSEC_NUM_AN];
+       struct pcpu_rx_sc_stats __percpu *stats;
+       atomic_t refcnt;
+       struct rcu_head rcu_head;
+};
+
+/**
+ * struct macsec_tx_sa - transmit secure association
+ * @active:
+ * @next_pn: packet number to use for the next packet
+ * @lock: protects next_pn manipulations
+ * @key: key structure
+ * @stats: per-SA stats
+ */
+struct macsec_tx_sa {
+       struct macsec_key key;
+       spinlock_t lock;
+       u32 next_pn;
+       atomic_t refcnt;
+       bool active;
+       struct macsec_tx_sa_stats __percpu *stats;
+       struct rcu_head rcu;
+};
+
+struct pcpu_tx_sc_stats {
+       struct macsec_tx_sc_stats stats;
+       struct u64_stats_sync syncp;
+};
+
+/**
+ * struct macsec_tx_sc - transmit secure channel
+ * @active:
+ * @encoding_sa: association number of the SA currently in use
+ * @encrypt: encrypt packets on transmit, or authenticate only
+ * @send_sci: always include the SCI in the SecTAG
+ * @end_station:
+ * @scb: single copy broadcast flag
+ * @sa: array of secure associations
+ * @stats: stats for this TXSC
+ */
+struct macsec_tx_sc {
+       bool active;
+       u8 encoding_sa;
+       bool encrypt;
+       bool send_sci;
+       bool end_station;
+       bool scb;
+       struct macsec_tx_sa __rcu *sa[MACSEC_NUM_AN];
+       struct pcpu_tx_sc_stats __percpu *stats;
+};
+
+#define MACSEC_VALIDATE_DEFAULT MACSEC_VALIDATE_STRICT
+
+/**
+ * struct macsec_secy - MACsec Security Entity
+ * @netdev: netdevice for this SecY
+ * @n_rx_sc: number of receive secure channels configured on this SecY
+ * @sci: secure channel identifier used for tx
+ * @key_len: length of keys used by the cipher suite
+ * @icv_len: length of ICV used by the cipher suite
+ * @validate_frames: validation mode
+ * @operational: MAC_Operational flag
+ * @protect_frames: enable protection for this SecY
+ * @replay_protect: enable packet number checks on receive
+ * @replay_window: size of the replay window
+ * @tx_sc: transmit secure channel
+ * @rx_sc: linked list of receive secure channels
+ */
+struct macsec_secy {
+       struct net_device *netdev;
+       unsigned int n_rx_sc;
+       sci_t sci;
+       u16 key_len;
+       u16 icv_len;
+       enum macsec_validation_type validate_frames;
+       bool operational;
+       bool protect_frames;
+       bool replay_protect;
+       u32 replay_window;
+       struct macsec_tx_sc tx_sc;
+       struct macsec_rx_sc __rcu *rx_sc;
+};
+
+struct pcpu_secy_stats {
+       struct macsec_dev_stats stats;
+       struct u64_stats_sync syncp;
+};
+
+/**
+ * struct macsec_dev - private data
+ * @secy: SecY config
+ * @real_dev: pointer to underlying netdevice
+ * @stats: MACsec device stats
+ * @secys: linked list of SecY's on the underlying device
+ */
+struct macsec_dev {
+       struct macsec_secy secy;
+       struct net_device *real_dev;
+       struct pcpu_secy_stats __percpu *stats;
+       struct list_head secys;
+};
+
+/**
+ * struct macsec_rxh_data - rx_handler private argument
+ * @secys: linked list of SecY's on this underlying device
+ */
+struct macsec_rxh_data {
+       struct list_head secys;
+};
+
+static struct macsec_dev *macsec_priv(const struct net_device *dev)
+{
+       return (struct macsec_dev *)netdev_priv(dev);
+}
+
+static struct macsec_rxh_data *macsec_data_rcu(const struct net_device *dev)
+{
+       return rcu_dereference_bh(dev->rx_handler_data);
+}
+
+static struct macsec_rxh_data *macsec_data_rtnl(const struct net_device *dev)
+{
+       return rtnl_dereference(dev->rx_handler_data);
+}
+
+struct macsec_cb {
+       struct aead_request *req;
+       union {
+               struct macsec_tx_sa *tx_sa;
+               struct macsec_rx_sa *rx_sa;
+       };
+       u8 assoc_num;
+       bool valid;
+       bool has_sci;
+};
+
+static struct macsec_rx_sa *macsec_rxsa_get(struct macsec_rx_sa __rcu *ptr)
+{
+       struct macsec_rx_sa *sa = rcu_dereference_bh(ptr);
+
+       if (!sa || !sa->active)
+               return NULL;
+
+       if (!atomic_inc_not_zero(&sa->refcnt))
+               return NULL;
+
+       return sa;
+}
+
+static void free_rx_sc_rcu(struct rcu_head *head)
+{
+       struct macsec_rx_sc *rx_sc = container_of(head, struct macsec_rx_sc, rcu_head);
+
+       free_percpu(rx_sc->stats);
+       kfree(rx_sc);
+}
+
+static struct macsec_rx_sc *macsec_rxsc_get(struct macsec_rx_sc *sc)
+{
+       return atomic_inc_not_zero(&sc->refcnt) ? sc : NULL;
+}
+
+static void macsec_rxsc_put(struct macsec_rx_sc *sc)
+{
+       if (atomic_dec_and_test(&sc->refcnt))
+               call_rcu(&sc->rcu_head, free_rx_sc_rcu);
+}
+
+static void free_rxsa(struct rcu_head *head)
+{
+       struct macsec_rx_sa *sa = container_of(head, struct macsec_rx_sa, rcu);
+
+       crypto_free_aead(sa->key.tfm);
+       free_percpu(sa->stats);
+       macsec_rxsc_put(sa->sc);
+       kfree(sa);
+}
+
+static void macsec_rxsa_put(struct macsec_rx_sa *sa)
+{
+       if (atomic_dec_and_test(&sa->refcnt))
+               call_rcu(&sa->rcu, free_rxsa);
+}
+
+static struct macsec_tx_sa *macsec_txsa_get(struct macsec_tx_sa __rcu *ptr)
+{
+       struct macsec_tx_sa *sa = rcu_dereference_bh(ptr);
+
+       if (!sa || !sa->active)
+               return NULL;
+
+       if (!atomic_inc_not_zero(&sa->refcnt))
+               return NULL;
+
+       return sa;
+}
+
+static void free_txsa(struct rcu_head *head)
+{
+       struct macsec_tx_sa *sa = container_of(head, struct macsec_tx_sa, rcu);
+
+       crypto_free_aead(sa->key.tfm);
+       free_percpu(sa->stats);
+       kfree(sa);
+}
+
+static void macsec_txsa_put(struct macsec_tx_sa *sa)
+{
+       if (atomic_dec_and_test(&sa->refcnt))
+               call_rcu(&sa->rcu, free_txsa);
+}
+
+static struct macsec_cb *macsec_skb_cb(struct sk_buff *skb)
+{
+       BUILD_BUG_ON(sizeof(struct macsec_cb) > sizeof(skb->cb));
+       return (struct macsec_cb *)skb->cb;
+}
+
+#define MACSEC_PORT_ES (htons(0x0001))
+#define MACSEC_PORT_SCB (0x0000)
+#define MACSEC_UNDEF_SCI ((__force sci_t)0xffffffffffffffffULL)
+
+#define DEFAULT_SAK_LEN 16
+#define DEFAULT_SEND_SCI true
+#define DEFAULT_ENCRYPT false
+#define DEFAULT_ENCODING_SA 0
+
+static sci_t make_sci(u8 *addr, __be16 port)
+{
+       sci_t sci;
+
+       memcpy(&sci, addr, ETH_ALEN);
+       memcpy(((char *)&sci) + ETH_ALEN, &port, sizeof(port));
+
+       return sci;
+}
+
+static sci_t macsec_frame_sci(struct macsec_eth_header *hdr, bool sci_present)
+{
+       sci_t sci;
+
+       if (sci_present)
+               memcpy(&sci, hdr->secure_channel_id,
+                      sizeof(hdr->secure_channel_id));
+       else
+               sci = make_sci(hdr->eth.h_source, MACSEC_PORT_ES);
+
+       return sci;
+}
+
+static unsigned int macsec_sectag_len(bool sci_present)
+{
+       return MACSEC_TAG_LEN + (sci_present ? MACSEC_SCI_LEN : 0);
+}
+
+static unsigned int macsec_hdr_len(bool sci_present)
+{
+       return macsec_sectag_len(sci_present) + ETH_HLEN;
+}
+
+static unsigned int macsec_extra_len(bool sci_present)
+{
+       return macsec_sectag_len(sci_present) + sizeof(__be16);
+}
+
+/* Fill SecTAG according to IEEE 802.1AE-2006 10.5.3 */
+static void macsec_fill_sectag(struct macsec_eth_header *h,
+                              const struct macsec_secy *secy, u32 pn)
+{
+       const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+
+       memset(&h->tci_an, 0, macsec_sectag_len(tx_sc->send_sci));
+       h->eth.h_proto = htons(ETH_P_MACSEC);
+
+       if (tx_sc->send_sci ||
+           (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb)) {
+               h->tci_an |= MACSEC_TCI_SC;
+               memcpy(&h->secure_channel_id, &secy->sci,
+                      sizeof(h->secure_channel_id));
+       } else {
+               if (tx_sc->end_station)
+                       h->tci_an |= MACSEC_TCI_ES;
+               if (tx_sc->scb)
+                       h->tci_an |= MACSEC_TCI_SCB;
+       }
+
+       h->packet_number = htonl(pn);
+
+       /* with GCM, C/E clear for !encrypt, both set for encrypt */
+       if (tx_sc->encrypt)
+               h->tci_an |= MACSEC_TCI_CONFID;
+       else if (secy->icv_len != DEFAULT_ICV_LEN)
+               h->tci_an |= MACSEC_TCI_C;
+
+       h->tci_an |= tx_sc->encoding_sa;
+}
+
+static void macsec_set_shortlen(struct macsec_eth_header *h, size_t data_len)
+{
+       if (data_len < MIN_NON_SHORT_LEN)
+               h->short_length = data_len;
+}
+
+/* validate MACsec packet according to IEEE 802.1AE-2006 9.12 */
+static bool macsec_validate_skb(struct sk_buff *skb, u16 icv_len)
+{
+       struct macsec_eth_header *h = (struct macsec_eth_header *)skb->data;
+       int len = skb->len - 2 * ETH_ALEN;
+       int extra_len = macsec_extra_len(!!(h->tci_an & MACSEC_TCI_SC)) + icv_len;
+
+       /* a) It comprises at least 17 octets */
+       if (skb->len <= 16)
+               return false;
+
+       /* b) MACsec EtherType: already checked */
+
+       /* c) V bit is clear */
+       if (h->tci_an & MACSEC_TCI_VERSION)
+               return false;
+
+       /* d) ES or SCB => !SC */
+       if ((h->tci_an & MACSEC_TCI_ES || h->tci_an & MACSEC_TCI_SCB) &&
+           (h->tci_an & MACSEC_TCI_SC))
+               return false;
+
+       /* e) Bits 7 and 8 of octet 4 of the SecTAG are clear */
+       if (h->unused)
+               return false;
+
+       /* rx.pn != 0 (figure 10-5) */
+       if (!h->packet_number)
+               return false;
+
+       /* length check, f) g) h) i) */
+       if (h->short_length)
+               return len == extra_len + h->short_length;
+       return len >= extra_len + MIN_NON_SHORT_LEN;
+}
+
+#define MACSEC_NEEDED_HEADROOM (macsec_extra_len(true))
+#define MACSEC_NEEDED_TAILROOM MACSEC_MAX_ICV_LEN
+
+static void macsec_fill_iv(unsigned char *iv, sci_t sci, u32 pn)
+{
+       struct gcm_iv *gcm_iv = (struct gcm_iv *)iv;
+
+       gcm_iv->sci = sci;
+       gcm_iv->pn = htonl(pn);
+}
+
+static struct macsec_eth_header *macsec_ethhdr(struct sk_buff *skb)
+{
+       return (struct macsec_eth_header *)skb_mac_header(skb);
+}
+
+static u32 tx_sa_update_pn(struct macsec_tx_sa *tx_sa, struct macsec_secy *secy)
+{
+       u32 pn;
+
+       spin_lock_bh(&tx_sa->lock);
+       pn = tx_sa->next_pn;
+
+       tx_sa->next_pn++;
+       if (tx_sa->next_pn == 0) {
+               pr_debug("PN wrapped, transitioning to !oper\n");
+               tx_sa->active = false;
+               if (secy->protect_frames)
+                       secy->operational = false;
+       }
+       spin_unlock_bh(&tx_sa->lock);
+
+       return pn;
+}
+
+static void macsec_encrypt_finish(struct sk_buff *skb, struct net_device *dev)
+{
+       struct macsec_dev *macsec = netdev_priv(dev);
+
+       skb->dev = macsec->real_dev;
+       skb_reset_mac_header(skb);
+       skb->protocol = eth_hdr(skb)->h_proto;
+}
+
+static void macsec_count_tx(struct sk_buff *skb, struct macsec_tx_sc *tx_sc,
+                           struct macsec_tx_sa *tx_sa)
+{
+       struct pcpu_tx_sc_stats *txsc_stats = this_cpu_ptr(tx_sc->stats);
+
+       u64_stats_update_begin(&txsc_stats->syncp);
+       if (tx_sc->encrypt) {
+               txsc_stats->stats.OutOctetsEncrypted += skb->len;
+               txsc_stats->stats.OutPktsEncrypted++;
+               this_cpu_inc(tx_sa->stats->OutPktsEncrypted);
+       } else {
+               txsc_stats->stats.OutOctetsProtected += skb->len;
+               txsc_stats->stats.OutPktsProtected++;
+               this_cpu_inc(tx_sa->stats->OutPktsProtected);
+       }
+       u64_stats_update_end(&txsc_stats->syncp);
+}
+
+static void count_tx(struct net_device *dev, int ret, int len)
+{
+       if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
+               struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
+
+               u64_stats_update_begin(&stats->syncp);
+               stats->tx_packets++;
+               stats->tx_bytes += len;
+               u64_stats_update_end(&stats->syncp);
+       } else {
+               dev->stats.tx_dropped++;
+       }
+}
+
+static void macsec_encrypt_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+       struct net_device *dev = skb->dev;
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct macsec_tx_sa *sa = macsec_skb_cb(skb)->tx_sa;
+       int len, ret;
+
+       aead_request_free(macsec_skb_cb(skb)->req);
+
+       rcu_read_lock_bh();
+       macsec_encrypt_finish(skb, dev);
+       macsec_count_tx(skb, &macsec->secy.tx_sc, macsec_skb_cb(skb)->tx_sa);
+       len = skb->len;
+       ret = dev_queue_xmit(skb);
+       count_tx(dev, ret, len);
+       rcu_read_unlock_bh();
+
+       macsec_txsa_put(sa);
+       dev_put(dev);
+}
+
+static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+                                     struct net_device *dev)
+{
+       int ret;
+       struct scatterlist sg[MAX_SKB_FRAGS + 1];
+       unsigned char iv[GCM_AES_IV_LEN];
+       struct ethhdr *eth;
+       struct macsec_eth_header *hh;
+       size_t unprotected_len;
+       struct aead_request *req;
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+       struct macsec_dev *macsec = macsec_priv(dev);
+       u32 pn;
+
+       secy = &macsec->secy;
+       tx_sc = &secy->tx_sc;
+
+       /* 10.5.1 TX SA assignment */
+       tx_sa = macsec_txsa_get(tx_sc->sa[tx_sc->encoding_sa]);
+       if (!tx_sa) {
+               secy->operational = false;
+               kfree_skb(skb);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (unlikely(skb_headroom(skb) < MACSEC_NEEDED_HEADROOM ||
+                    skb_tailroom(skb) < MACSEC_NEEDED_TAILROOM)) {
+               struct sk_buff *nskb = skb_copy_expand(skb,
+                                                      MACSEC_NEEDED_HEADROOM,
+                                                      MACSEC_NEEDED_TAILROOM,
+                                                      GFP_ATOMIC);
+               if (likely(nskb)) {
+                       consume_skb(skb);
+                       skb = nskb;
+               } else {
+                       macsec_txsa_put(tx_sa);
+                       kfree_skb(skb);
+                       return ERR_PTR(-ENOMEM);
+               }
+       } else {
+               skb = skb_unshare(skb, GFP_ATOMIC);
+               if (!skb) {
+                       macsec_txsa_put(tx_sa);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
+
+       unprotected_len = skb->len;
+       eth = eth_hdr(skb);
+       hh = (struct macsec_eth_header *)skb_push(skb, macsec_extra_len(tx_sc->send_sci));
+       memmove(hh, eth, 2 * ETH_ALEN);
+
+       pn = tx_sa_update_pn(tx_sa, secy);
+       if (pn == 0) {
+               macsec_txsa_put(tx_sa);
+               kfree_skb(skb);
+               return ERR_PTR(-ENOLINK);
+       }
+       macsec_fill_sectag(hh, secy, pn);
+       macsec_set_shortlen(hh, unprotected_len - 2 * ETH_ALEN);
+
+       macsec_fill_iv(iv, secy->sci, pn);
+
+       skb_put(skb, secy->icv_len);
+
+       if (skb->len - ETH_HLEN > macsec_priv(dev)->real_dev->mtu) {
+               struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);
+
+               u64_stats_update_begin(&secy_stats->syncp);
+               secy_stats->stats.OutPktsTooLong++;
+               u64_stats_update_end(&secy_stats->syncp);
+
+               macsec_txsa_put(tx_sa);
+               kfree_skb(skb);
+               return ERR_PTR(-EINVAL);
+       }
+
+       req = aead_request_alloc(tx_sa->key.tfm, GFP_ATOMIC);
+       if (!req) {
+               macsec_txsa_put(tx_sa);
+               kfree_skb(skb);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       sg_init_table(sg, MAX_SKB_FRAGS + 1);
+       skb_to_sgvec(skb, sg, 0, skb->len);
+
+       if (tx_sc->encrypt) {
+               int len = skb->len - macsec_hdr_len(tx_sc->send_sci) -
+                         secy->icv_len;
+               aead_request_set_crypt(req, sg, sg, len, iv);
+               aead_request_set_ad(req, macsec_hdr_len(tx_sc->send_sci));
+       } else {
+               aead_request_set_crypt(req, sg, sg, 0, iv);
+               aead_request_set_ad(req, skb->len - secy->icv_len);
+       }
+
+       macsec_skb_cb(skb)->req = req;
+       macsec_skb_cb(skb)->tx_sa = tx_sa;
+       aead_request_set_callback(req, 0, macsec_encrypt_done, skb);
+
+       dev_hold(skb->dev);
+       ret = crypto_aead_encrypt(req);
+       if (ret == -EINPROGRESS) {
+               return ERR_PTR(ret);
+       } else if (ret != 0) {
+               dev_put(skb->dev);
+               kfree_skb(skb);
+               aead_request_free(req);
+               macsec_txsa_put(tx_sa);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dev_put(skb->dev);
+       aead_request_free(req);
+       macsec_txsa_put(tx_sa);
+
+       return skb;
+}
+
+static bool macsec_post_decrypt(struct sk_buff *skb, struct macsec_secy *secy, u32 pn)
+{
+       struct macsec_rx_sa *rx_sa = macsec_skb_cb(skb)->rx_sa;
+       struct pcpu_rx_sc_stats *rxsc_stats = this_cpu_ptr(rx_sa->sc->stats);
+       struct macsec_eth_header *hdr = macsec_ethhdr(skb);
+       u32 lowest_pn = 0;
+
+       spin_lock(&rx_sa->lock);
+       if (rx_sa->next_pn >= secy->replay_window)
+               lowest_pn = rx_sa->next_pn - secy->replay_window;
+
+       /* Now perform replay protection check again
+        * (see IEEE 802.1AE-2006 figure 10-5)
+        */
+       if (secy->replay_protect && pn < lowest_pn) {
+               spin_unlock(&rx_sa->lock);
+               u64_stats_update_begin(&rxsc_stats->syncp);
+               rxsc_stats->stats.InPktsLate++;
+               u64_stats_update_end(&rxsc_stats->syncp);
+               return false;
+       }
+
+       if (secy->validate_frames != MACSEC_VALIDATE_DISABLED) {
+               u64_stats_update_begin(&rxsc_stats->syncp);
+               if (hdr->tci_an & MACSEC_TCI_E)
+                       rxsc_stats->stats.InOctetsDecrypted += skb->len;
+               else
+                       rxsc_stats->stats.InOctetsValidated += skb->len;
+               u64_stats_update_end(&rxsc_stats->syncp);
+       }
+
+       if (!macsec_skb_cb(skb)->valid) {
+               spin_unlock(&rx_sa->lock);
+
+               /* 10.6.5 */
+               if (hdr->tci_an & MACSEC_TCI_C ||
+                   secy->validate_frames == MACSEC_VALIDATE_STRICT) {
+                       u64_stats_update_begin(&rxsc_stats->syncp);
+                       rxsc_stats->stats.InPktsNotValid++;
+                       u64_stats_update_end(&rxsc_stats->syncp);
+                       return false;
+               }
+
+               u64_stats_update_begin(&rxsc_stats->syncp);
+               if (secy->validate_frames == MACSEC_VALIDATE_CHECK) {
+                       rxsc_stats->stats.InPktsInvalid++;
+                       this_cpu_inc(rx_sa->stats->InPktsInvalid);
+               } else if (pn < lowest_pn) {
+                       rxsc_stats->stats.InPktsDelayed++;
+               } else {
+                       rxsc_stats->stats.InPktsUnchecked++;
+               }
+               u64_stats_update_end(&rxsc_stats->syncp);
+       } else {
+               u64_stats_update_begin(&rxsc_stats->syncp);
+               if (pn < lowest_pn) {
+                       rxsc_stats->stats.InPktsDelayed++;
+               } else {
+                       rxsc_stats->stats.InPktsOK++;
+                       this_cpu_inc(rx_sa->stats->InPktsOK);
+               }
+               u64_stats_update_end(&rxsc_stats->syncp);
+
+               if (pn >= rx_sa->next_pn)
+                       rx_sa->next_pn = pn + 1;
+               spin_unlock(&rx_sa->lock);
+       }
+
+       return true;
+}
+
+static void macsec_reset_skb(struct sk_buff *skb, struct net_device *dev)
+{
+       skb->pkt_type = PACKET_HOST;
+       skb->protocol = eth_type_trans(skb, dev);
+
+       skb_reset_network_header(skb);
+       if (!skb_transport_header_was_set(skb))
+               skb_reset_transport_header(skb);
+       skb_reset_mac_len(skb);
+}
+
+static void macsec_finalize_skb(struct sk_buff *skb, u8 icv_len, u8 hdr_len)
+{
+       memmove(skb->data + hdr_len, skb->data, 2 * ETH_ALEN);
+       skb_pull(skb, hdr_len);
+       pskb_trim_unique(skb, skb->len - icv_len);
+}
+
+static void count_rx(struct net_device *dev, int len)
+{
+       struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
+
+       u64_stats_update_begin(&stats->syncp);
+       stats->rx_packets++;
+       stats->rx_bytes += len;
+       u64_stats_update_end(&stats->syncp);
+}
+
+static void macsec_decrypt_done(struct crypto_async_request *base, int err)
+{
+       struct sk_buff *skb = base->data;
+       struct net_device *dev = skb->dev;
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct macsec_rx_sa *rx_sa = macsec_skb_cb(skb)->rx_sa;
+       int len, ret;
+       u32 pn;
+
+       aead_request_free(macsec_skb_cb(skb)->req);
+
+       rcu_read_lock_bh();
+       pn = ntohl(macsec_ethhdr(skb)->packet_number);
+       if (!macsec_post_decrypt(skb, &macsec->secy, pn)) {
+               rcu_read_unlock_bh();
+               kfree_skb(skb);
+               goto out;
+       }
+
+       macsec_finalize_skb(skb, macsec->secy.icv_len,
+                           macsec_extra_len(macsec_skb_cb(skb)->has_sci));
+       macsec_reset_skb(skb, macsec->secy.netdev);
+
+       len = skb->len;
+       ret = netif_rx(skb);
+       if (ret == NET_RX_SUCCESS)
+               count_rx(dev, len);
+       else
+               macsec->secy.netdev->stats.rx_dropped++;
+
+       rcu_read_unlock_bh();
+
+out:
+       macsec_rxsa_put(rx_sa);
+       dev_put(dev);
+       return;
+}
+
+static struct sk_buff *macsec_decrypt(struct sk_buff *skb,
+                                     struct net_device *dev,
+                                     struct macsec_rx_sa *rx_sa,
+                                     sci_t sci,
+                                     struct macsec_secy *secy)
+{
+       int ret;
+       struct scatterlist sg[MAX_SKB_FRAGS + 1];
+       unsigned char iv[GCM_AES_IV_LEN];
+       struct aead_request *req;
+       struct macsec_eth_header *hdr;
+       u16 icv_len = secy->icv_len;
+
+       macsec_skb_cb(skb)->valid = false;
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       req = aead_request_alloc(rx_sa->key.tfm, GFP_ATOMIC);
+       if (!req) {
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       hdr = (struct macsec_eth_header *)skb->data;
+       macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
+
+       sg_init_table(sg, MAX_SKB_FRAGS + 1);
+       skb_to_sgvec(skb, sg, 0, skb->len);
+
+       if (hdr->tci_an & MACSEC_TCI_E) {
+               /* confidentiality: ethernet + macsec header
+                * authenticated, encrypted payload
+                */
+               int len = skb->len - macsec_hdr_len(macsec_skb_cb(skb)->has_sci);
+
+               aead_request_set_crypt(req, sg, sg, len, iv);
+               aead_request_set_ad(req, macsec_hdr_len(macsec_skb_cb(skb)->has_sci));
+               skb = skb_unshare(skb, GFP_ATOMIC);
+               if (!skb) {
+                       aead_request_free(req);
+                       return NULL;
+               }
+       } else {
+               /* integrity only: all headers + data authenticated */
+               aead_request_set_crypt(req, sg, sg, icv_len, iv);
+               aead_request_set_ad(req, skb->len - icv_len);
+       }
+
+       macsec_skb_cb(skb)->req = req;
+       macsec_skb_cb(skb)->rx_sa = rx_sa;
+       skb->dev = dev;
+       aead_request_set_callback(req, 0, macsec_decrypt_done, skb);
+
+       dev_hold(dev);
+       ret = crypto_aead_decrypt(req);
+       if (ret == -EINPROGRESS) {
+               return NULL;
+       } else if (ret != 0) {
+               /* decryption/authentication failed
+                * 10.6 if validateFrames is disabled, deliver anyway
+                */
+               if (ret != -EBADMSG) {
+                       kfree_skb(skb);
+                       skb = NULL;
+               }
+       } else {
+               macsec_skb_cb(skb)->valid = true;
+       }
+       dev_put(dev);
+
+       aead_request_free(req);
+
+       return skb;
+}
+
+static struct macsec_rx_sc *find_rx_sc(struct macsec_secy *secy, sci_t sci)
+{
+       struct macsec_rx_sc *rx_sc;
+
+       for_each_rxsc(secy, rx_sc) {
+               if (rx_sc->sci == sci)
+                       return rx_sc;
+       }
+
+       return NULL;
+}
+
+static struct macsec_rx_sc *find_rx_sc_rtnl(struct macsec_secy *secy, sci_t sci)
+{
+       struct macsec_rx_sc *rx_sc;
+
+       for_each_rxsc_rtnl(secy, rx_sc) {
+               if (rx_sc->sci == sci)
+                       return rx_sc;
+       }
+
+       return NULL;
+}
+
+static void handle_not_macsec(struct sk_buff *skb)
+{
+       struct macsec_rxh_data *rxd;
+       struct macsec_dev *macsec;
+
+       rcu_read_lock();
+       rxd = macsec_data_rcu(skb->dev);
+
+       /* 10.6 If the management control validateFrames is not
+        * Strict, frames without a SecTAG are received, counted, and
+        * delivered to the Controlled Port
+        */
+       list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
+               struct sk_buff *nskb;
+               int ret;
+               struct pcpu_secy_stats *secy_stats = this_cpu_ptr(macsec->stats);
+
+               if (macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+                       u64_stats_update_begin(&secy_stats->syncp);
+                       secy_stats->stats.InPktsNoTag++;
+                       u64_stats_update_end(&secy_stats->syncp);
+                       continue;
+               }
+
+               /* deliver on this port */
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
+                       break;
+
+               nskb->dev = macsec->secy.netdev;
+
+               ret = netif_rx(nskb);
+               if (ret == NET_RX_SUCCESS) {
+                       u64_stats_update_begin(&secy_stats->syncp);
+                       secy_stats->stats.InPktsUntagged++;
+                       u64_stats_update_end(&secy_stats->syncp);
+               } else {
+                       macsec->secy.netdev->stats.rx_dropped++;
+               }
+       }
+
+       rcu_read_unlock();
+}
+
+static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct net_device *dev = skb->dev;
+       struct macsec_eth_header *hdr;
+       struct macsec_secy *secy = NULL;
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_rx_sa *rx_sa;
+       struct macsec_rxh_data *rxd;
+       struct macsec_dev *macsec;
+       sci_t sci;
+       u32 pn;
+       bool cbit;
+       struct pcpu_rx_sc_stats *rxsc_stats;
+       struct pcpu_secy_stats *secy_stats;
+       bool pulled_sci;
+
+       if (skb_headroom(skb) < ETH_HLEN)
+               goto drop_direct;
+
+       hdr = macsec_ethhdr(skb);
+       if (hdr->eth.h_proto != htons(ETH_P_MACSEC)) {
+               handle_not_macsec(skb);
+
+               /* and deliver to the uncontrolled port */
+               return RX_HANDLER_PASS;
+       }
+
+       skb = skb_unshare(skb, GFP_ATOMIC);
+       if (!skb) {
+               *pskb = NULL;
+               return RX_HANDLER_CONSUMED;
+       }
+
+       pulled_sci = pskb_may_pull(skb, macsec_extra_len(true));
+       if (!pulled_sci) {
+               if (!pskb_may_pull(skb, macsec_extra_len(false)))
+                       goto drop_direct;
+       }
+
+       hdr = macsec_ethhdr(skb);
+
+       /* Frames with a SecTAG that has the TCI E bit set but the C
+        * bit clear are discarded, as this reserved encoding is used
+        * to identify frames with a SecTAG that are not to be
+        * delivered to the Controlled Port.
+        */
+       if ((hdr->tci_an & (MACSEC_TCI_C | MACSEC_TCI_E)) == MACSEC_TCI_E)
+               return RX_HANDLER_PASS;
+
+       /* now, pull the extra length */
+       if (hdr->tci_an & MACSEC_TCI_SC) {
+               if (!pulled_sci)
+                       goto drop_direct;
+       }
+
+       /* ethernet header is part of crypto processing */
+       skb_push(skb, ETH_HLEN);
+
+       macsec_skb_cb(skb)->has_sci = !!(hdr->tci_an & MACSEC_TCI_SC);
+       macsec_skb_cb(skb)->assoc_num = hdr->tci_an & MACSEC_AN_MASK;
+       sci = macsec_frame_sci(hdr, macsec_skb_cb(skb)->has_sci);
+
+       rcu_read_lock();
+       rxd = macsec_data_rcu(skb->dev);
+
+       list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
+               struct macsec_rx_sc *sc = find_rx_sc(&macsec->secy, sci);
+
+               if (sc) {
+                       secy = &macsec->secy;
+                       rx_sc = sc;
+                       break;
+               }
+       }
+
+       if (!secy)
+               goto nosci;
+
+       dev = secy->netdev;
+       macsec = macsec_priv(dev);
+       secy_stats = this_cpu_ptr(macsec->stats);
+       rxsc_stats = this_cpu_ptr(rx_sc->stats);
+
+       if (!macsec_validate_skb(skb, secy->icv_len)) {
+               u64_stats_update_begin(&secy_stats->syncp);
+               secy_stats->stats.InPktsBadTag++;
+               u64_stats_update_end(&secy_stats->syncp);
+               goto drop_nosa;
+       }
+
+       rx_sa = macsec_rxsa_get(rx_sc->sa[macsec_skb_cb(skb)->assoc_num]);
+       if (!rx_sa) {
+               /* 10.6.1 if the SA is not in use */
+
+               /* If validateFrames is Strict or the C bit in the
+                * SecTAG is set, discard
+                */
+               if (hdr->tci_an & MACSEC_TCI_C ||
+                   secy->validate_frames == MACSEC_VALIDATE_STRICT) {
+                       u64_stats_update_begin(&rxsc_stats->syncp);
+                       rxsc_stats->stats.InPktsNotUsingSA++;
+                       u64_stats_update_end(&rxsc_stats->syncp);
+                       goto drop_nosa;
+               }
+
+               /* not Strict, the frame (with the SecTAG and ICV
+                * removed) is delivered to the Controlled Port.
+                */
+               u64_stats_update_begin(&rxsc_stats->syncp);
+               rxsc_stats->stats.InPktsUnusedSA++;
+               u64_stats_update_end(&rxsc_stats->syncp);
+               goto deliver;
+       }
+
+       /* First, PN check to avoid decrypting obviously wrong packets */
+       pn = ntohl(hdr->packet_number);
+       if (secy->replay_protect) {
+               bool late;
+
+               spin_lock(&rx_sa->lock);
+               late = rx_sa->next_pn >= secy->replay_window &&
+                      pn < (rx_sa->next_pn - secy->replay_window);
+               spin_unlock(&rx_sa->lock);
+
+               if (late) {
+                       u64_stats_update_begin(&rxsc_stats->syncp);
+                       rxsc_stats->stats.InPktsLate++;
+                       u64_stats_update_end(&rxsc_stats->syncp);
+                       goto drop;
+               }
+       }
+
+       /* Disabled && !changed text => skip validation */
+       if (hdr->tci_an & MACSEC_TCI_C ||
+           secy->validate_frames != MACSEC_VALIDATE_DISABLED)
+               skb = macsec_decrypt(skb, dev, rx_sa, sci, secy);
+
+       if (!skb) {
+               macsec_rxsa_put(rx_sa);
+               rcu_read_unlock();
+               *pskb = NULL;
+               return RX_HANDLER_CONSUMED;
+       }
+
+       if (!macsec_post_decrypt(skb, secy, pn))
+               goto drop;
+
+deliver:
+       macsec_finalize_skb(skb, secy->icv_len,
+                           macsec_extra_len(macsec_skb_cb(skb)->has_sci));
+       macsec_reset_skb(skb, secy->netdev);
+
+       macsec_rxsa_put(rx_sa);
+       count_rx(dev, skb->len);
+
+       rcu_read_unlock();
+
+       *pskb = skb;
+       return RX_HANDLER_ANOTHER;
+
+drop:
+       macsec_rxsa_put(rx_sa);
+drop_nosa:
+       rcu_read_unlock();
+drop_direct:
+       kfree_skb(skb);
+       *pskb = NULL;
+       return RX_HANDLER_CONSUMED;
+
+nosci:
+       /* 10.6.1 if the SC is not found */
+       cbit = !!(hdr->tci_an & MACSEC_TCI_C);
+       if (!cbit)
+               macsec_finalize_skb(skb, DEFAULT_ICV_LEN,
+                                   macsec_extra_len(macsec_skb_cb(skb)->has_sci));
+
+       list_for_each_entry_rcu(macsec, &rxd->secys, secys) {
+               struct sk_buff *nskb;
+               int ret;
+
+               secy_stats = this_cpu_ptr(macsec->stats);
+
+               /* If validateFrames is Strict or the C bit in the
+                * SecTAG is set, discard
+                */
+               if (cbit ||
+                   macsec->secy.validate_frames == MACSEC_VALIDATE_STRICT) {
+                       u64_stats_update_begin(&secy_stats->syncp);
+                       secy_stats->stats.InPktsNoSCI++;
+                       u64_stats_update_end(&secy_stats->syncp);
+                       continue;
+               }
+
+               /* not strict, the frame (with the SecTAG and ICV
+                * removed) is delivered to the Controlled Port.
+                */
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
+                       break;
+
+               macsec_reset_skb(nskb, macsec->secy.netdev);
+
+               ret = netif_rx(nskb);
+               if (ret == NET_RX_SUCCESS) {
+                       u64_stats_update_begin(&secy_stats->syncp);
+                       secy_stats->stats.InPktsUnknownSCI++;
+                       u64_stats_update_end(&secy_stats->syncp);
+               } else {
+                       macsec->secy.netdev->stats.rx_dropped++;
+               }
+       }
+
+       rcu_read_unlock();
+       *pskb = skb;
+       return RX_HANDLER_PASS;
+}
+
+static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len)
+{
+       struct crypto_aead *tfm;
+       int ret;
+
+       tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (!tfm || IS_ERR(tfm))
+               return NULL;
+
+       ret = crypto_aead_setkey(tfm, key, key_len);
+       if (ret < 0) {
+               crypto_free_aead(tfm);
+               return NULL;
+       }
+
+       ret = crypto_aead_setauthsize(tfm, icv_len);
+       if (ret < 0) {
+               crypto_free_aead(tfm);
+               return NULL;
+       }
+
+       return tfm;
+}
+
+static int init_rx_sa(struct macsec_rx_sa *rx_sa, char *sak, int key_len,
+                     int icv_len)
+{
+       rx_sa->stats = alloc_percpu(struct macsec_rx_sa_stats);
+       if (!rx_sa->stats)
+               return -1;
+
+       rx_sa->key.tfm = macsec_alloc_tfm(sak, key_len, icv_len);
+       if (!rx_sa->key.tfm) {
+               free_percpu(rx_sa->stats);
+               return -1;
+       }
+
+       rx_sa->active = false;
+       rx_sa->next_pn = 1;
+       atomic_set(&rx_sa->refcnt, 1);
+       spin_lock_init(&rx_sa->lock);
+
+       return 0;
+}
+
+static void clear_rx_sa(struct macsec_rx_sa *rx_sa)
+{
+       rx_sa->active = false;
+
+       macsec_rxsa_put(rx_sa);
+}
+
+static void free_rx_sc(struct macsec_rx_sc *rx_sc)
+{
+       int i;
+
+       for (i = 0; i < MACSEC_NUM_AN; i++) {
+               struct macsec_rx_sa *sa = rtnl_dereference(rx_sc->sa[i]);
+
+               RCU_INIT_POINTER(rx_sc->sa[i], NULL);
+               if (sa)
+                       clear_rx_sa(sa);
+       }
+
+       macsec_rxsc_put(rx_sc);
+}
+
+static struct macsec_rx_sc *del_rx_sc(struct macsec_secy *secy, sci_t sci)
+{
+       struct macsec_rx_sc *rx_sc, __rcu **rx_scp;
+
+       for (rx_scp = &secy->rx_sc, rx_sc = rtnl_dereference(*rx_scp);
+            rx_sc;
+            rx_scp = &rx_sc->next, rx_sc = rtnl_dereference(*rx_scp)) {
+               if (rx_sc->sci == sci) {
+                       if (rx_sc->active)
+                               secy->n_rx_sc--;
+                       rcu_assign_pointer(*rx_scp, rx_sc->next);
+                       return rx_sc;
+               }
+       }
+
+       return NULL;
+}
+
+static struct macsec_rx_sc *create_rx_sc(struct net_device *dev, sci_t sci)
+{
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_dev *macsec;
+       struct net_device *real_dev = macsec_priv(dev)->real_dev;
+       struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
+       struct macsec_secy *secy;
+
+       list_for_each_entry(macsec, &rxd->secys, secys) {
+               if (find_rx_sc_rtnl(&macsec->secy, sci))
+                       return ERR_PTR(-EEXIST);
+       }
+
+       rx_sc = kzalloc(sizeof(*rx_sc), GFP_KERNEL);
+       if (!rx_sc)
+               return ERR_PTR(-ENOMEM);
+
+       rx_sc->stats = netdev_alloc_pcpu_stats(struct pcpu_rx_sc_stats);
+       if (!rx_sc->stats) {
+               kfree(rx_sc);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       rx_sc->sci = sci;
+       rx_sc->active = true;
+       atomic_set(&rx_sc->refcnt, 1);
+
+       secy = &macsec_priv(dev)->secy;
+       rcu_assign_pointer(rx_sc->next, secy->rx_sc);
+       rcu_assign_pointer(secy->rx_sc, rx_sc);
+
+       if (rx_sc->active)
+               secy->n_rx_sc++;
+
+       return rx_sc;
+}
+
+static int init_tx_sa(struct macsec_tx_sa *tx_sa, char *sak, int key_len,
+                     int icv_len)
+{
+       tx_sa->stats = alloc_percpu(struct macsec_tx_sa_stats);
+       if (!tx_sa->stats)
+               return -1;
+
+       tx_sa->key.tfm = macsec_alloc_tfm(sak, key_len, icv_len);
+       if (!tx_sa->key.tfm) {
+               free_percpu(tx_sa->stats);
+               return -1;
+       }
+
+       tx_sa->active = false;
+       atomic_set(&tx_sa->refcnt, 1);
+       spin_lock_init(&tx_sa->lock);
+
+       return 0;
+}
+
+static void clear_tx_sa(struct macsec_tx_sa *tx_sa)
+{
+       tx_sa->active = false;
+
+       macsec_txsa_put(tx_sa);
+}
+
+static struct genl_family macsec_fam = {
+       .id             = GENL_ID_GENERATE,
+       .name           = MACSEC_GENL_NAME,
+       .hdrsize        = 0,
+       .version        = MACSEC_GENL_VERSION,
+       .maxattr        = MACSEC_ATTR_MAX,
+       .netnsok        = true,
+};
+
+static struct net_device *get_dev_from_nl(struct net *net,
+                                         struct nlattr **attrs)
+{
+       int ifindex = nla_get_u32(attrs[MACSEC_ATTR_IFINDEX]);
+       struct net_device *dev;
+
+       dev = __dev_get_by_index(net, ifindex);
+       if (!dev)
+               return ERR_PTR(-ENODEV);
+
+       if (!netif_is_macsec(dev))
+               return ERR_PTR(-ENODEV);
+
+       return dev;
+}
+
+static sci_t nla_get_sci(const struct nlattr *nla)
+{
+       return (__force sci_t)nla_get_u64(nla);
+}
+
+static int nla_put_sci(struct sk_buff *skb, int attrtype, sci_t value)
+{
+       return nla_put_u64(skb, attrtype, (__force u64)value);
+}
+
+static struct macsec_tx_sa *get_txsa_from_nl(struct net *net,
+                                            struct nlattr **attrs,
+                                            struct nlattr **tb_sa,
+                                            struct net_device **devp,
+                                            struct macsec_secy **secyp,
+                                            struct macsec_tx_sc **scp,
+                                            u8 *assoc_num)
+{
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+
+       if (!tb_sa[MACSEC_SA_ATTR_AN])
+               return ERR_PTR(-EINVAL);
+
+       *assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);
+
+       dev = get_dev_from_nl(net, attrs);
+       if (IS_ERR(dev))
+               return ERR_CAST(dev);
+
+       if (*assoc_num >= MACSEC_NUM_AN)
+               return ERR_PTR(-EINVAL);
+
+       secy = &macsec_priv(dev)->secy;
+       tx_sc = &secy->tx_sc;
+
+       tx_sa = rtnl_dereference(tx_sc->sa[*assoc_num]);
+       if (!tx_sa)
+               return ERR_PTR(-ENODEV);
+
+       *devp = dev;
+       *scp = tx_sc;
+       *secyp = secy;
+       return tx_sa;
+}
+
+static struct macsec_rx_sc *get_rxsc_from_nl(struct net *net,
+                                            struct nlattr **attrs,
+                                            struct nlattr **tb_rxsc,
+                                            struct net_device **devp,
+                                            struct macsec_secy **secyp)
+{
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       sci_t sci;
+
+       dev = get_dev_from_nl(net, attrs);
+       if (IS_ERR(dev))
+               return ERR_CAST(dev);
+
+       secy = &macsec_priv(dev)->secy;
+
+       if (!tb_rxsc[MACSEC_RXSC_ATTR_SCI])
+               return ERR_PTR(-EINVAL);
+
+       sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]);
+       rx_sc = find_rx_sc_rtnl(secy, sci);
+       if (!rx_sc)
+               return ERR_PTR(-ENODEV);
+
+       *secyp = secy;
+       *devp = dev;
+
+       return rx_sc;
+}
+
+static struct macsec_rx_sa *get_rxsa_from_nl(struct net *net,
+                                            struct nlattr **attrs,
+                                            struct nlattr **tb_rxsc,
+                                            struct nlattr **tb_sa,
+                                            struct net_device **devp,
+                                            struct macsec_secy **secyp,
+                                            struct macsec_rx_sc **scp,
+                                            u8 *assoc_num)
+{
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_rx_sa *rx_sa;
+
+       if (!tb_sa[MACSEC_SA_ATTR_AN])
+               return ERR_PTR(-EINVAL);
+
+       *assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);
+       if (*assoc_num >= MACSEC_NUM_AN)
+               return ERR_PTR(-EINVAL);
+
+       rx_sc = get_rxsc_from_nl(net, attrs, tb_rxsc, devp, secyp);
+       if (IS_ERR(rx_sc))
+               return ERR_CAST(rx_sc);
+
+       rx_sa = rtnl_dereference(rx_sc->sa[*assoc_num]);
+       if (!rx_sa)
+               return ERR_PTR(-ENODEV);
+
+       *scp = rx_sc;
+       return rx_sa;
+}
+
+
+static const struct nla_policy macsec_genl_policy[NUM_MACSEC_ATTR] = {
+       [MACSEC_ATTR_IFINDEX] = { .type = NLA_U32 },
+       [MACSEC_ATTR_RXSC_CONFIG] = { .type = NLA_NESTED },
+       [MACSEC_ATTR_SA_CONFIG] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy macsec_genl_rxsc_policy[NUM_MACSEC_RXSC_ATTR] = {
+       [MACSEC_RXSC_ATTR_SCI] = { .type = NLA_U64 },
+       [MACSEC_RXSC_ATTR_ACTIVE] = { .type = NLA_U8 },
+};
+
+static const struct nla_policy macsec_genl_sa_policy[NUM_MACSEC_SA_ATTR] = {
+       [MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+       [MACSEC_SA_ATTR_ACTIVE] = { .type = NLA_U8 },
+       [MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
+       [MACSEC_SA_ATTR_KEYID] = { .type = NLA_U64 },
+       [MACSEC_SA_ATTR_KEY] = { .type = NLA_BINARY,
+                                .len = MACSEC_MAX_KEY_LEN, },
+};
+
+static int parse_sa_config(struct nlattr **attrs, struct nlattr **tb_sa)
+{
+       if (!attrs[MACSEC_ATTR_SA_CONFIG])
+               return -EINVAL;
+
+       if (nla_parse_nested(tb_sa, MACSEC_SA_ATTR_MAX, attrs[MACSEC_ATTR_SA_CONFIG],
+                            macsec_genl_sa_policy))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int parse_rxsc_config(struct nlattr **attrs, struct nlattr **tb_rxsc)
+{
+       if (!attrs[MACSEC_ATTR_RXSC_CONFIG])
+               return -EINVAL;
+
+       if (nla_parse_nested(tb_rxsc, MACSEC_RXSC_ATTR_MAX, attrs[MACSEC_ATTR_RXSC_CONFIG],
+                            macsec_genl_rxsc_policy))
+               return -EINVAL;
+
+       return 0;
+}
+
+static bool validate_add_rxsa(struct nlattr **attrs)
+{
+       if (!attrs[MACSEC_SA_ATTR_AN] ||
+           !attrs[MACSEC_SA_ATTR_KEY] ||
+           !attrs[MACSEC_SA_ATTR_KEYID])
+               return false;
+
+       if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
+               return false;
+
+       if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
+               return false;
+
+       if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
+               if (nla_get_u8(attrs[MACSEC_SA_ATTR_ACTIVE]) > 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net_device *dev;
+       struct nlattr **attrs = info->attrs;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_rx_sa *rx_sa;
+       unsigned char assoc_num;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       if (!validate_add_rxsa(tb_sa))
+               return -EINVAL;
+
+       rtnl_lock();
+       rx_sc = get_rxsc_from_nl(genl_info_net(info), attrs, tb_rxsc, &dev, &secy);
+       if (IS_ERR(rx_sc) || !macsec_rxsc_get(rx_sc)) {
+               rtnl_unlock();
+               return PTR_ERR(rx_sc);
+       }
+
+       assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);
+
+       if (nla_len(tb_sa[MACSEC_SA_ATTR_KEY]) != secy->key_len) {
+               pr_notice("macsec: nl: add_rxsa: bad key length: %d != %d\n",
+                         nla_len(tb_sa[MACSEC_SA_ATTR_KEY]), secy->key_len);
+               rtnl_unlock();
+               return -EINVAL;
+       }
+
+       rx_sa = rtnl_dereference(rx_sc->sa[assoc_num]);
+       if (rx_sa) {
+               rtnl_unlock();
+               return -EBUSY;
+       }
+
+       rx_sa = kmalloc(sizeof(*rx_sa), GFP_KERNEL);
+       if (init_rx_sa(rx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]), secy->key_len,
+                      secy->icv_len)) {
+               rtnl_unlock();
+               return -ENOMEM;
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_PN]) {
+               spin_lock_bh(&rx_sa->lock);
+               rx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+               spin_unlock_bh(&rx_sa->lock);
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+               rx_sa->active = !!nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+
+       rx_sa->key.id = nla_get_u64(tb_sa[MACSEC_SA_ATTR_KEYID]);
+       rx_sa->sc = rx_sc;
+       rcu_assign_pointer(rx_sc->sa[assoc_num], rx_sa);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static bool validate_add_rxsc(struct nlattr **attrs)
+{
+       if (!attrs[MACSEC_RXSC_ATTR_SCI])
+               return false;
+
+       if (attrs[MACSEC_RXSC_ATTR_ACTIVE]) {
+               if (nla_get_u8(attrs[MACSEC_RXSC_ATTR_ACTIVE]) > 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static int macsec_add_rxsc(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net_device *dev;
+       sci_t sci = MACSEC_UNDEF_SCI;
+       struct nlattr **attrs = info->attrs;
+       struct macsec_rx_sc *rx_sc;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       if (!validate_add_rxsc(tb_rxsc))
+               return -EINVAL;
+
+       rtnl_lock();
+       dev = get_dev_from_nl(genl_info_net(info), attrs);
+       if (IS_ERR(dev)) {
+               rtnl_unlock();
+               return PTR_ERR(dev);
+       }
+
+       sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]);
+
+       rx_sc = create_rx_sc(dev, sci);
+       if (IS_ERR(rx_sc)) {
+               rtnl_unlock();
+               return PTR_ERR(rx_sc);
+       }
+
+       if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE])
+               rx_sc->active = !!nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static bool validate_add_txsa(struct nlattr **attrs)
+{
+       if (!attrs[MACSEC_SA_ATTR_AN] ||
+           !attrs[MACSEC_SA_ATTR_PN] ||
+           !attrs[MACSEC_SA_ATTR_KEY] ||
+           !attrs[MACSEC_SA_ATTR_KEYID])
+               return false;
+
+       if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
+               return false;
+
+       if (nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
+               return false;
+
+       if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
+               if (nla_get_u8(attrs[MACSEC_SA_ATTR_ACTIVE]) > 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net_device *dev;
+       struct nlattr **attrs = info->attrs;
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+       unsigned char assoc_num;
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       if (!validate_add_txsa(tb_sa))
+               return -EINVAL;
+
+       rtnl_lock();
+       dev = get_dev_from_nl(genl_info_net(info), attrs);
+       if (IS_ERR(dev)) {
+               rtnl_unlock();
+               return PTR_ERR(dev);
+       }
+
+       secy = &macsec_priv(dev)->secy;
+       tx_sc = &secy->tx_sc;
+
+       assoc_num = nla_get_u8(tb_sa[MACSEC_SA_ATTR_AN]);
+
+       if (nla_len(tb_sa[MACSEC_SA_ATTR_KEY]) != secy->key_len) {
+               pr_notice("macsec: nl: add_txsa: bad key length: %d != %d\n",
+                         nla_len(tb_sa[MACSEC_SA_ATTR_KEY]), secy->key_len);
+               rtnl_unlock();
+               return -EINVAL;
+       }
+
+       tx_sa = rtnl_dereference(tx_sc->sa[assoc_num]);
+       if (tx_sa) {
+               rtnl_unlock();
+               return -EBUSY;
+       }
+
+       tx_sa = kmalloc(sizeof(*tx_sa), GFP_KERNEL);
+       if (!tx_sa || init_tx_sa(tx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+                                secy->key_len, secy->icv_len)) {
+               rtnl_unlock();
+               return -ENOMEM;
+       }
+
+       tx_sa->key.id = nla_get_u64(tb_sa[MACSEC_SA_ATTR_KEYID]);
+
+       spin_lock_bh(&tx_sa->lock);
+       tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+       spin_unlock_bh(&tx_sa->lock);
+
+       if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+               tx_sa->active = !!nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+
+       if (assoc_num == tx_sc->encoding_sa && tx_sa->active)
+               secy->operational = true;
+
+       rcu_assign_pointer(tx_sc->sa[assoc_num], tx_sa);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int macsec_del_rxsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_rx_sa *rx_sa;
+       u8 assoc_num;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       rtnl_lock();
+       rx_sa = get_rxsa_from_nl(genl_info_net(info), attrs, tb_rxsc, tb_sa,
+                                &dev, &secy, &rx_sc, &assoc_num);
+       if (IS_ERR(rx_sa)) {
+               rtnl_unlock();
+               return PTR_ERR(rx_sa);
+       }
+
+       if (rx_sa->active) {
+               rtnl_unlock();
+               return -EBUSY;
+       }
+
+       RCU_INIT_POINTER(rx_sc->sa[assoc_num], NULL);
+       clear_rx_sa(rx_sa);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int macsec_del_rxsc(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       sci_t sci;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       if (!tb_rxsc[MACSEC_RXSC_ATTR_SCI])
+               return -EINVAL;
+
+       rtnl_lock();
+       dev = get_dev_from_nl(genl_info_net(info), info->attrs);
+       if (IS_ERR(dev)) {
+               rtnl_unlock();
+               return PTR_ERR(dev);
+       }
+
+       secy = &macsec_priv(dev)->secy;
+       sci = nla_get_sci(tb_rxsc[MACSEC_RXSC_ATTR_SCI]);
+
+       rx_sc = del_rx_sc(secy, sci);
+       if (!rx_sc) {
+               rtnl_unlock();
+               return -ENODEV;
+       }
+
+       free_rx_sc(rx_sc);
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int macsec_del_txsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+       u8 assoc_num;
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       rtnl_lock();
+       tx_sa = get_txsa_from_nl(genl_info_net(info), attrs, tb_sa,
+                                &dev, &secy, &tx_sc, &assoc_num);
+       if (IS_ERR(tx_sa)) {
+               rtnl_unlock();
+               return PTR_ERR(tx_sa);
+       }
+
+       if (tx_sa->active) {
+               rtnl_unlock();
+               return -EBUSY;
+       }
+
+       RCU_INIT_POINTER(tx_sc->sa[assoc_num], NULL);
+       clear_tx_sa(tx_sa);
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static bool validate_upd_sa(struct nlattr **attrs)
+{
+       if (!attrs[MACSEC_SA_ATTR_AN] ||
+           attrs[MACSEC_SA_ATTR_KEY] ||
+           attrs[MACSEC_SA_ATTR_KEYID])
+               return false;
+
+       if (nla_get_u8(attrs[MACSEC_SA_ATTR_AN]) >= MACSEC_NUM_AN)
+               return false;
+
+       if (attrs[MACSEC_SA_ATTR_PN] && nla_get_u32(attrs[MACSEC_SA_ATTR_PN]) == 0)
+               return false;
+
+       if (attrs[MACSEC_SA_ATTR_ACTIVE]) {
+               if (nla_get_u8(attrs[MACSEC_SA_ATTR_ACTIVE]) > 1)
+                       return false;
+       }
+
+       return true;
+}
+
+static int macsec_upd_txsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+       u8 assoc_num;
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       if (!validate_upd_sa(tb_sa))
+               return -EINVAL;
+
+       rtnl_lock();
+       tx_sa = get_txsa_from_nl(genl_info_net(info), attrs, tb_sa,
+                                &dev, &secy, &tx_sc, &assoc_num);
+       if (IS_ERR(tx_sa)) {
+               rtnl_unlock();
+               return PTR_ERR(tx_sa);
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_PN]) {
+               spin_lock_bh(&tx_sa->lock);
+               tx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+               spin_unlock_bh(&tx_sa->lock);
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+               tx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+
+       if (assoc_num == tx_sc->encoding_sa)
+               secy->operational = tx_sa->active;
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int macsec_upd_rxsa(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_rx_sa *rx_sa;
+       u8 assoc_num;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+       struct nlattr *tb_sa[MACSEC_SA_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       if (parse_sa_config(attrs, tb_sa))
+               return -EINVAL;
+
+       if (!validate_upd_sa(tb_sa))
+               return -EINVAL;
+
+       rtnl_lock();
+       rx_sa = get_rxsa_from_nl(genl_info_net(info), attrs, tb_rxsc, tb_sa,
+                                &dev, &secy, &rx_sc, &assoc_num);
+       if (IS_ERR(rx_sa)) {
+               rtnl_unlock();
+               return PTR_ERR(rx_sa);
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_PN]) {
+               spin_lock_bh(&rx_sa->lock);
+               rx_sa->next_pn = nla_get_u32(tb_sa[MACSEC_SA_ATTR_PN]);
+               spin_unlock_bh(&rx_sa->lock);
+       }
+
+       if (tb_sa[MACSEC_SA_ATTR_ACTIVE])
+               rx_sa->active = nla_get_u8(tb_sa[MACSEC_SA_ATTR_ACTIVE]);
+
+       rtnl_unlock();
+       return 0;
+}
+
+static int macsec_upd_rxsc(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr **attrs = info->attrs;
+       struct net_device *dev;
+       struct macsec_secy *secy;
+       struct macsec_rx_sc *rx_sc;
+       struct nlattr *tb_rxsc[MACSEC_RXSC_ATTR_MAX + 1];
+
+       if (!attrs[MACSEC_ATTR_IFINDEX])
+               return -EINVAL;
+
+       if (parse_rxsc_config(attrs, tb_rxsc))
+               return -EINVAL;
+
+       if (!validate_add_rxsc(tb_rxsc))
+               return -EINVAL;
+
+       rtnl_lock();
+       rx_sc = get_rxsc_from_nl(genl_info_net(info), attrs, tb_rxsc, &dev, &secy);
+       if (IS_ERR(rx_sc)) {
+               rtnl_unlock();
+               return PTR_ERR(rx_sc);
+       }
+
+       if (tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]) {
+               bool new = !!nla_get_u8(tb_rxsc[MACSEC_RXSC_ATTR_ACTIVE]);
+
+               if (rx_sc->active != new)
+                       secy->n_rx_sc += new ? 1 : -1;
+
+               rx_sc->active = new;
+       }
+
+       rtnl_unlock();
+
+       return 0;
+}
+
+static int copy_tx_sa_stats(struct sk_buff *skb,
+                            struct macsec_tx_sa_stats __percpu *pstats)
+{
+       struct macsec_tx_sa_stats sum = {0, };
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct macsec_tx_sa_stats *stats = per_cpu_ptr(pstats, cpu);
+
+               sum.OutPktsProtected += stats->OutPktsProtected;
+               sum.OutPktsEncrypted += stats->OutPktsEncrypted;
+       }
+
+       if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, sum.OutPktsProtected) ||
+           nla_put_u32(skb, MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, sum.OutPktsEncrypted))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int copy_rx_sa_stats(struct sk_buff *skb,
+                            struct macsec_rx_sa_stats __percpu *pstats)
+{
+       struct macsec_rx_sa_stats sum = {0, };
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct macsec_rx_sa_stats *stats = per_cpu_ptr(pstats, cpu);
+
+               sum.InPktsOK         += stats->InPktsOK;
+               sum.InPktsInvalid    += stats->InPktsInvalid;
+               sum.InPktsNotValid   += stats->InPktsNotValid;
+               sum.InPktsNotUsingSA += stats->InPktsNotUsingSA;
+               sum.InPktsUnusedSA   += stats->InPktsUnusedSA;
+       }
+
+       if (nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_OK, sum.InPktsOK) ||
+           nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID, sum.InPktsInvalid) ||
+           nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID, sum.InPktsNotValid) ||
+           nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA, sum.InPktsNotUsingSA) ||
+           nla_put_u32(skb, MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA, sum.InPktsUnusedSA))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int copy_rx_sc_stats(struct sk_buff *skb,
+                            struct pcpu_rx_sc_stats __percpu *pstats)
+{
+       struct macsec_rx_sc_stats sum = {0, };
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct pcpu_rx_sc_stats *stats;
+               struct macsec_rx_sc_stats tmp;
+               unsigned int start;
+
+               stats = per_cpu_ptr(pstats, cpu);
+               do {
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
+                       memcpy(&tmp, &stats->stats, sizeof(tmp));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+
+               sum.InOctetsValidated += tmp.InOctetsValidated;
+               sum.InOctetsDecrypted += tmp.InOctetsDecrypted;
+               sum.InPktsUnchecked   += tmp.InPktsUnchecked;
+               sum.InPktsDelayed     += tmp.InPktsDelayed;
+               sum.InPktsOK          += tmp.InPktsOK;
+               sum.InPktsInvalid     += tmp.InPktsInvalid;
+               sum.InPktsLate        += tmp.InPktsLate;
+               sum.InPktsNotValid    += tmp.InPktsNotValid;
+               sum.InPktsNotUsingSA  += tmp.InPktsNotUsingSA;
+               sum.InPktsUnusedSA    += tmp.InPktsUnusedSA;
+       }
+
+       if (nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED, sum.InOctetsValidated) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED, sum.InOctetsDecrypted) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED, sum.InPktsUnchecked) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED, sum.InPktsDelayed) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK, sum.InPktsOK) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID, sum.InPktsInvalid) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE, sum.InPktsLate) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID, sum.InPktsNotValid) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA, sum.InPktsNotUsingSA) ||
+           nla_put_u64(skb, MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA, sum.InPktsUnusedSA))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int copy_tx_sc_stats(struct sk_buff *skb,
+                            struct pcpu_tx_sc_stats __percpu *pstats)
+{
+       struct macsec_tx_sc_stats sum = {0, };
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct pcpu_tx_sc_stats *stats;
+               struct macsec_tx_sc_stats tmp;
+               unsigned int start;
+
+               stats = per_cpu_ptr(pstats, cpu);
+               do {
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
+                       memcpy(&tmp, &stats->stats, sizeof(tmp));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+
+               sum.OutPktsProtected   += tmp.OutPktsProtected;
+               sum.OutPktsEncrypted   += tmp.OutPktsEncrypted;
+               sum.OutOctetsProtected += tmp.OutOctetsProtected;
+               sum.OutOctetsEncrypted += tmp.OutOctetsEncrypted;
+       }
+
+       if (nla_put_u64(skb, MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED, sum.OutPktsProtected) ||
+           nla_put_u64(skb, MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED, sum.OutPktsEncrypted) ||
+           nla_put_u64(skb, MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED, sum.OutOctetsProtected) ||
+           nla_put_u64(skb, MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED, sum.OutOctetsEncrypted))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int copy_secy_stats(struct sk_buff *skb,
+                           struct pcpu_secy_stats __percpu *pstats)
+{
+       struct macsec_dev_stats sum = {0, };
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct pcpu_secy_stats *stats;
+               struct macsec_dev_stats tmp;
+               unsigned int start;
+
+               stats = per_cpu_ptr(pstats, cpu);
+               do {
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
+                       memcpy(&tmp, &stats->stats, sizeof(tmp));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+
+               sum.OutPktsUntagged  += tmp.OutPktsUntagged;
+               sum.InPktsUntagged   += tmp.InPktsUntagged;
+               sum.OutPktsTooLong   += tmp.OutPktsTooLong;
+               sum.InPktsNoTag      += tmp.InPktsNoTag;
+               sum.InPktsBadTag     += tmp.InPktsBadTag;
+               sum.InPktsUnknownSCI += tmp.InPktsUnknownSCI;
+               sum.InPktsNoSCI      += tmp.InPktsNoSCI;
+               sum.InPktsOverrun    += tmp.InPktsOverrun;
+       }
+
+       if (nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED, sum.OutPktsUntagged) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED, sum.InPktsUntagged) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG, sum.OutPktsTooLong) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG, sum.InPktsNoTag) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG, sum.InPktsBadTag) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI, sum.InPktsUnknownSCI) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI, sum.InPktsNoSCI) ||
+           nla_put_u64(skb, MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN, sum.InPktsOverrun))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
+static int nla_put_secy(struct macsec_secy *secy, struct sk_buff *skb)
+{
+       struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+       struct nlattr *secy_nest = nla_nest_start(skb, MACSEC_ATTR_SECY);
+
+       if (!secy_nest)
+               return 1;
+
+       if (nla_put_sci(skb, MACSEC_SECY_ATTR_SCI, secy->sci) ||
+           nla_put_u64(skb, MACSEC_SECY_ATTR_CIPHER_SUITE, DEFAULT_CIPHER_ID) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_ICV_LEN, secy->icv_len) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_OPER, secy->operational) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_PROTECT, secy->protect_frames) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_REPLAY, secy->replay_protect) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_VALIDATE, secy->validate_frames) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_ENCRYPT, tx_sc->encrypt) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_INC_SCI, tx_sc->send_sci) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_ES, tx_sc->end_station) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_SCB, tx_sc->scb) ||
+           nla_put_u8(skb, MACSEC_SECY_ATTR_ENCODING_SA, tx_sc->encoding_sa))
+               goto cancel;
+
+       if (secy->replay_protect) {
+               if (nla_put_u32(skb, MACSEC_SECY_ATTR_WINDOW, secy->replay_window))
+                       goto cancel;
+       }
+
+       nla_nest_end(skb, secy_nest);
+       return 0;
+
+cancel:
+       nla_nest_cancel(skb, secy_nest);
+       return 1;
+}
+
+static int dump_secy(struct macsec_secy *secy, struct net_device *dev,
+                    struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct macsec_rx_sc *rx_sc;
+       struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+       struct nlattr *txsa_list, *rxsc_list;
+       int i, j;
+       void *hdr;
+       struct nlattr *attr;
+
+       hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+                         &macsec_fam, NLM_F_MULTI, MACSEC_CMD_GET_TXSC);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       rtnl_lock();
+
+       if (nla_put_u32(skb, MACSEC_ATTR_IFINDEX, dev->ifindex))
+               goto nla_put_failure;
+
+       if (nla_put_secy(secy, skb))
+               goto nla_put_failure;
+
+       attr = nla_nest_start(skb, MACSEC_ATTR_TXSC_STATS);
+       if (!attr)
+               goto nla_put_failure;
+       if (copy_tx_sc_stats(skb, tx_sc->stats)) {
+               nla_nest_cancel(skb, attr);
+               goto nla_put_failure;
+       }
+       nla_nest_end(skb, attr);
+
+       attr = nla_nest_start(skb, MACSEC_ATTR_SECY_STATS);
+       if (!attr)
+               goto nla_put_failure;
+       if (copy_secy_stats(skb, macsec_priv(dev)->stats)) {
+               nla_nest_cancel(skb, attr);
+               goto nla_put_failure;
+       }
+       nla_nest_end(skb, attr);
+
+       txsa_list = nla_nest_start(skb, MACSEC_ATTR_TXSA_LIST);
+       if (!txsa_list)
+               goto nla_put_failure;
+       for (i = 0, j = 1; i < MACSEC_NUM_AN; i++) {
+               struct macsec_tx_sa *tx_sa = rtnl_dereference(tx_sc->sa[i]);
+               struct nlattr *txsa_nest;
+
+               if (!tx_sa)
+                       continue;
+
+               txsa_nest = nla_nest_start(skb, j++);
+               if (!txsa_nest) {
+                       nla_nest_cancel(skb, txsa_list);
+                       goto nla_put_failure;
+               }
+
+               if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+                   nla_put_u32(skb, MACSEC_SA_ATTR_PN, tx_sa->next_pn) ||
+                   nla_put_u64(skb, MACSEC_SA_ATTR_KEYID, tx_sa->key.id) ||
+                   nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, tx_sa->active)) {
+                       nla_nest_cancel(skb, txsa_nest);
+                       nla_nest_cancel(skb, txsa_list);
+                       goto nla_put_failure;
+               }
+
+               attr = nla_nest_start(skb, MACSEC_SA_ATTR_STATS);
+               if (!attr) {
+                       nla_nest_cancel(skb, txsa_nest);
+                       nla_nest_cancel(skb, txsa_list);
+                       goto nla_put_failure;
+               }
+               if (copy_tx_sa_stats(skb, tx_sa->stats)) {
+                       nla_nest_cancel(skb, attr);
+                       nla_nest_cancel(skb, txsa_nest);
+                       nla_nest_cancel(skb, txsa_list);
+                       goto nla_put_failure;
+               }
+               nla_nest_end(skb, attr);
+
+               nla_nest_end(skb, txsa_nest);
+       }
+       nla_nest_end(skb, txsa_list);
+
+       rxsc_list = nla_nest_start(skb, MACSEC_ATTR_RXSC_LIST);
+       if (!rxsc_list)
+               goto nla_put_failure;
+
+       j = 1;
+       for_each_rxsc_rtnl(secy, rx_sc) {
+               int k;
+               struct nlattr *rxsa_list;
+               struct nlattr *rxsc_nest = nla_nest_start(skb, j++);
+
+               if (!rxsc_nest) {
+                       nla_nest_cancel(skb, rxsc_list);
+                       goto nla_put_failure;
+               }
+
+               if (nla_put_u8(skb, MACSEC_RXSC_ATTR_ACTIVE, rx_sc->active) ||
+                   nla_put_sci(skb, MACSEC_RXSC_ATTR_SCI, rx_sc->sci)) {
+                       nla_nest_cancel(skb, rxsc_nest);
+                       nla_nest_cancel(skb, rxsc_list);
+                       goto nla_put_failure;
+               }
+
+               attr = nla_nest_start(skb, MACSEC_RXSC_ATTR_STATS);
+               if (!attr) {
+                       nla_nest_cancel(skb, rxsc_nest);
+                       nla_nest_cancel(skb, rxsc_list);
+                       goto nla_put_failure;
+               }
+               if (copy_rx_sc_stats(skb, rx_sc->stats)) {
+                       nla_nest_cancel(skb, attr);
+                       nla_nest_cancel(skb, rxsc_nest);
+                       nla_nest_cancel(skb, rxsc_list);
+                       goto nla_put_failure;
+               }
+               nla_nest_end(skb, attr);
+
+               rxsa_list = nla_nest_start(skb, MACSEC_RXSC_ATTR_SA_LIST);
+               if (!rxsa_list) {
+                       nla_nest_cancel(skb, rxsc_nest);
+                       nla_nest_cancel(skb, rxsc_list);
+                       goto nla_put_failure;
+               }
+
+               for (i = 0, k = 1; i < MACSEC_NUM_AN; i++) {
+                       struct macsec_rx_sa *rx_sa = rtnl_dereference(rx_sc->sa[i]);
+                       struct nlattr *rxsa_nest;
+
+                       if (!rx_sa)
+                               continue;
+
+                       rxsa_nest = nla_nest_start(skb, k++);
+                       if (!rxsa_nest) {
+                               nla_nest_cancel(skb, rxsa_list);
+                               nla_nest_cancel(skb, rxsc_nest);
+                               nla_nest_cancel(skb, rxsc_list);
+                               goto nla_put_failure;
+                       }
+
+                       attr = nla_nest_start(skb, MACSEC_SA_ATTR_STATS);
+                       if (!attr) {
+                               nla_nest_cancel(skb, rxsa_list);
+                               nla_nest_cancel(skb, rxsc_nest);
+                               nla_nest_cancel(skb, rxsc_list);
+                               goto nla_put_failure;
+                       }
+                       if (copy_rx_sa_stats(skb, rx_sa->stats)) {
+                               nla_nest_cancel(skb, attr);
+                               nla_nest_cancel(skb, rxsa_list);
+                               nla_nest_cancel(skb, rxsc_nest);
+                               nla_nest_cancel(skb, rxsc_list);
+                               goto nla_put_failure;
+                       }
+                       nla_nest_end(skb, attr);
+
+                       if (nla_put_u8(skb, MACSEC_SA_ATTR_AN, i) ||
+                           nla_put_u32(skb, MACSEC_SA_ATTR_PN, rx_sa->next_pn) ||
+                           nla_put_u64(skb, MACSEC_SA_ATTR_KEYID, rx_sa->key.id) ||
+                           nla_put_u8(skb, MACSEC_SA_ATTR_ACTIVE, rx_sa->active)) {
+                               nla_nest_cancel(skb, rxsa_nest);
+                               nla_nest_cancel(skb, rxsc_nest);
+                               nla_nest_cancel(skb, rxsc_list);
+                               goto nla_put_failure;
+                       }
+                       nla_nest_end(skb, rxsa_nest);
+               }
+
+               nla_nest_end(skb, rxsa_list);
+               nla_nest_end(skb, rxsc_nest);
+       }
+
+       nla_nest_end(skb, rxsc_list);
+
+       rtnl_unlock();
+
+       genlmsg_end(skb, hdr);
+
+       return 0;
+
+nla_put_failure:
+       rtnl_unlock();
+       genlmsg_cancel(skb, hdr);
+       return -EMSGSIZE;
+}
+
+static int macsec_dump_txsc(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       struct net_device *dev;
+       int dev_idx, d;
+
+       dev_idx = cb->args[0];
+
+       d = 0;
+       for_each_netdev(net, dev) {
+               struct macsec_secy *secy;
+
+               if (d < dev_idx)
+                       goto next;
+
+               if (!netif_is_macsec(dev))
+                       goto next;
+
+               secy = &macsec_priv(dev)->secy;
+               if (dump_secy(secy, dev, skb, cb) < 0)
+                       goto done;
+next:
+               d++;
+       }
+
+done:
+       cb->args[0] = d;
+       return skb->len;
+}
+
+static const struct genl_ops macsec_genl_ops[] = {
+       {
+               .cmd = MACSEC_CMD_GET_TXSC,
+               .dumpit = macsec_dump_txsc,
+               .policy = macsec_genl_policy,
+       },
+       {
+               .cmd = MACSEC_CMD_ADD_RXSC,
+               .doit = macsec_add_rxsc,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_DEL_RXSC,
+               .doit = macsec_del_rxsc,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_UPD_RXSC,
+               .doit = macsec_upd_rxsc,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_ADD_TXSA,
+               .doit = macsec_add_txsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_DEL_TXSA,
+               .doit = macsec_del_txsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_UPD_TXSA,
+               .doit = macsec_upd_txsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_ADD_RXSA,
+               .doit = macsec_add_rxsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_DEL_RXSA,
+               .doit = macsec_del_rxsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = MACSEC_CMD_UPD_RXSA,
+               .doit = macsec_upd_rxsa,
+               .policy = macsec_genl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
+                                    struct net_device *dev)
+{
+       struct macsec_dev *macsec = netdev_priv(dev);
+       struct macsec_secy *secy = &macsec->secy;
+       struct pcpu_secy_stats *secy_stats;
+       int ret, len;
+
+       /* 10.5 */
+       if (!secy->protect_frames) {
+               secy_stats = this_cpu_ptr(macsec->stats);
+               u64_stats_update_begin(&secy_stats->syncp);
+               secy_stats->stats.OutPktsUntagged++;
+               u64_stats_update_end(&secy_stats->syncp);
+               len = skb->len;
+               ret = dev_queue_xmit(skb);
+               count_tx(dev, ret, len);
+               return ret;
+       }
+
+       if (!secy->operational) {
+               kfree_skb(skb);
+               dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
+
+       skb = macsec_encrypt(skb, dev);
+       if (IS_ERR(skb)) {
+               if (PTR_ERR(skb) != -EINPROGRESS)
+                       dev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
+
+       macsec_count_tx(skb, &macsec->secy.tx_sc, macsec_skb_cb(skb)->tx_sa);
+
+       macsec_encrypt_finish(skb, dev);
+       len = skb->len;
+       ret = dev_queue_xmit(skb);
+       count_tx(dev, ret, len);
+       return ret;
+}
+
+#define MACSEC_FEATURES \
+       (NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST)
+static int macsec_dev_init(struct net_device *dev)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+       if (!dev->tstats)
+               return -ENOMEM;
+
+       dev->features = real_dev->features & MACSEC_FEATURES;
+       dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
+
+       dev->needed_headroom = real_dev->needed_headroom +
+                              MACSEC_NEEDED_HEADROOM;
+       dev->needed_tailroom = real_dev->needed_tailroom +
+                              MACSEC_NEEDED_TAILROOM;
+
+       if (is_zero_ether_addr(dev->dev_addr))
+               eth_hw_addr_inherit(dev, real_dev);
+       if (is_zero_ether_addr(dev->broadcast))
+               memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
+
+       return 0;
+}
+
+static void macsec_dev_uninit(struct net_device *dev)
+{
+       free_percpu(dev->tstats);
+}
+
+static netdev_features_t macsec_fix_features(struct net_device *dev,
+                                            netdev_features_t features)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+
+       features &= real_dev->features & MACSEC_FEATURES;
+       features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
+
+       return features;
+}
+
+static int macsec_dev_open(struct net_device *dev)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+       int err;
+
+       if (!(real_dev->flags & IFF_UP))
+               return -ENETDOWN;
+
+       err = dev_uc_add(real_dev, dev->dev_addr);
+       if (err < 0)
+               return err;
+
+       if (dev->flags & IFF_ALLMULTI) {
+               err = dev_set_allmulti(real_dev, 1);
+               if (err < 0)
+                       goto del_unicast;
+       }
+
+       if (dev->flags & IFF_PROMISC) {
+               err = dev_set_promiscuity(real_dev, 1);
+               if (err < 0)
+                       goto clear_allmulti;
+       }
+
+       if (netif_carrier_ok(real_dev))
+               netif_carrier_on(dev);
+
+       return 0;
+clear_allmulti:
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(real_dev, -1);
+del_unicast:
+       dev_uc_del(real_dev, dev->dev_addr);
+       netif_carrier_off(dev);
+       return err;
+}
+
+static int macsec_dev_stop(struct net_device *dev)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+
+       netif_carrier_off(dev);
+
+       dev_mc_unsync(real_dev, dev);
+       dev_uc_unsync(real_dev, dev);
+
+       if (dev->flags & IFF_ALLMULTI)
+               dev_set_allmulti(real_dev, -1);
+
+       if (dev->flags & IFF_PROMISC)
+               dev_set_promiscuity(real_dev, -1);
+
+       dev_uc_del(real_dev, dev->dev_addr);
+
+       return 0;
+}
+
+static void macsec_dev_change_rx_flags(struct net_device *dev, int change)
+{
+       struct net_device *real_dev = macsec_priv(dev)->real_dev;
+
+       if (!(dev->flags & IFF_UP))
+               return;
+
+       if (change & IFF_ALLMULTI)
+               dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+
+       if (change & IFF_PROMISC)
+               dev_set_promiscuity(real_dev,
+                                   dev->flags & IFF_PROMISC ? 1 : -1);
+}
+
+static void macsec_dev_set_rx_mode(struct net_device *dev)
+{
+       struct net_device *real_dev = macsec_priv(dev)->real_dev;
+
+       dev_mc_sync(real_dev, dev);
+       dev_uc_sync(real_dev, dev);
+}
+
+static int macsec_set_mac_address(struct net_device *dev, void *p)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+       struct sockaddr *addr = p;
+       int err;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (!(dev->flags & IFF_UP))
+               goto out;
+
+       err = dev_uc_add(real_dev, addr->sa_data);
+       if (err < 0)
+               return err;
+
+       dev_uc_del(real_dev, dev->dev_addr);
+
+out:
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+       return 0;
+}
+
+static int macsec_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       unsigned int extra = macsec->secy.icv_len + macsec_extra_len(true);
+
+       if (macsec->real_dev->mtu - extra < new_mtu)
+               return -ERANGE;
+
+       dev->mtu = new_mtu;
+
+       return 0;
+}
+
+static struct rtnl_link_stats64 *macsec_get_stats64(struct net_device *dev,
+                                                   struct rtnl_link_stats64 *s)
+{
+       int cpu;
+
+       if (!dev->tstats)
+               return s;
+
+       for_each_possible_cpu(cpu) {
+               struct pcpu_sw_netstats *stats;
+               struct pcpu_sw_netstats tmp;
+               int start;
+
+               stats = per_cpu_ptr(dev->tstats, cpu);
+               do {
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
+                       tmp.rx_packets = stats->rx_packets;
+                       tmp.rx_bytes   = stats->rx_bytes;
+                       tmp.tx_packets = stats->tx_packets;
+                       tmp.tx_bytes   = stats->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+
+               s->rx_packets += tmp.rx_packets;
+               s->rx_bytes   += tmp.rx_bytes;
+               s->tx_packets += tmp.tx_packets;
+               s->tx_bytes   += tmp.tx_bytes;
+       }
+
+       s->rx_dropped = dev->stats.rx_dropped;
+       s->tx_dropped = dev->stats.tx_dropped;
+
+       return s;
+}
+
+static int macsec_get_iflink(const struct net_device *dev)
+{
+       return macsec_priv(dev)->real_dev->ifindex;
+}
+
+static const struct net_device_ops macsec_netdev_ops = {
+       .ndo_init               = macsec_dev_init,
+       .ndo_uninit             = macsec_dev_uninit,
+       .ndo_open               = macsec_dev_open,
+       .ndo_stop               = macsec_dev_stop,
+       .ndo_fix_features       = macsec_fix_features,
+       .ndo_change_mtu         = macsec_change_mtu,
+       .ndo_set_rx_mode        = macsec_dev_set_rx_mode,
+       .ndo_change_rx_flags    = macsec_dev_change_rx_flags,
+       .ndo_set_mac_address    = macsec_set_mac_address,
+       .ndo_start_xmit         = macsec_start_xmit,
+       .ndo_get_stats64        = macsec_get_stats64,
+       .ndo_get_iflink         = macsec_get_iflink,
+};
+
+static const struct device_type macsec_type = {
+       .name = "macsec",
+};
+
+static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = {
+       [IFLA_MACSEC_SCI] = { .type = NLA_U64 },
+       [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
+       [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
+       [IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
+       [IFLA_MACSEC_ENCODING_SA] = { .type = NLA_U8 },
+       [IFLA_MACSEC_ENCRYPT] = { .type = NLA_U8 },
+       [IFLA_MACSEC_PROTECT] = { .type = NLA_U8 },
+       [IFLA_MACSEC_INC_SCI] = { .type = NLA_U8 },
+       [IFLA_MACSEC_ES] = { .type = NLA_U8 },
+       [IFLA_MACSEC_SCB] = { .type = NLA_U8 },
+       [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
+       [IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
+};
+
+static void macsec_free_netdev(struct net_device *dev)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+
+       free_percpu(macsec->stats);
+       free_percpu(macsec->secy.tx_sc.stats);
+
+       dev_put(real_dev);
+       free_netdev(dev);
+}
+
+static void macsec_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+       dev->tx_queue_len = 0;
+       dev->netdev_ops = &macsec_netdev_ops;
+       dev->destructor = macsec_free_netdev;
+
+       eth_zero_addr(dev->broadcast);
+}
+
+static void macsec_changelink_common(struct net_device *dev,
+                                    struct nlattr *data[])
+{
+       struct macsec_secy *secy;
+       struct macsec_tx_sc *tx_sc;
+
+       secy = &macsec_priv(dev)->secy;
+       tx_sc = &secy->tx_sc;
+
+       if (data[IFLA_MACSEC_ENCODING_SA]) {
+               struct macsec_tx_sa *tx_sa;
+
+               tx_sc->encoding_sa = nla_get_u8(data[IFLA_MACSEC_ENCODING_SA]);
+               tx_sa = rtnl_dereference(tx_sc->sa[tx_sc->encoding_sa]);
+
+               secy->operational = tx_sa && tx_sa->active;
+       }
+
+       if (data[IFLA_MACSEC_WINDOW])
+               secy->replay_window = nla_get_u32(data[IFLA_MACSEC_WINDOW]);
+
+       if (data[IFLA_MACSEC_ENCRYPT])
+               tx_sc->encrypt = !!nla_get_u8(data[IFLA_MACSEC_ENCRYPT]);
+
+       if (data[IFLA_MACSEC_PROTECT])
+               secy->protect_frames = !!nla_get_u8(data[IFLA_MACSEC_PROTECT]);
+
+       if (data[IFLA_MACSEC_INC_SCI])
+               tx_sc->send_sci = !!nla_get_u8(data[IFLA_MACSEC_INC_SCI]);
+
+       if (data[IFLA_MACSEC_ES])
+               tx_sc->end_station = !!nla_get_u8(data[IFLA_MACSEC_ES]);
+
+       if (data[IFLA_MACSEC_SCB])
+               tx_sc->scb = !!nla_get_u8(data[IFLA_MACSEC_SCB]);
+
+       if (data[IFLA_MACSEC_REPLAY_PROTECT])
+               secy->replay_protect = !!nla_get_u8(data[IFLA_MACSEC_REPLAY_PROTECT]);
+
+       if (data[IFLA_MACSEC_VALIDATION])
+               secy->validate_frames = nla_get_u8(data[IFLA_MACSEC_VALIDATION]);
+}
+
+static int macsec_changelink(struct net_device *dev, struct nlattr *tb[],
+                            struct nlattr *data[])
+{
+       if (!data)
+               return 0;
+
+       if (data[IFLA_MACSEC_CIPHER_SUITE] ||
+           data[IFLA_MACSEC_ICV_LEN] ||
+           data[IFLA_MACSEC_SCI] ||
+           data[IFLA_MACSEC_PORT])
+               return -EINVAL;
+
+       macsec_changelink_common(dev, data);
+
+       return 0;
+}
+
+static void macsec_del_dev(struct macsec_dev *macsec)
+{
+       int i;
+
+       while (macsec->secy.rx_sc) {
+               struct macsec_rx_sc *rx_sc = rtnl_dereference(macsec->secy.rx_sc);
+
+               rcu_assign_pointer(macsec->secy.rx_sc, rx_sc->next);
+               free_rx_sc(rx_sc);
+       }
+
+       for (i = 0; i < MACSEC_NUM_AN; i++) {
+               struct macsec_tx_sa *sa = rtnl_dereference(macsec->secy.tx_sc.sa[i]);
+
+               if (sa) {
+                       RCU_INIT_POINTER(macsec->secy.tx_sc.sa[i], NULL);
+                       clear_tx_sa(sa);
+               }
+       }
+}
+
+static void macsec_dellink(struct net_device *dev, struct list_head *head)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev = macsec->real_dev;
+       struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
+
+       unregister_netdevice_queue(dev, head);
+       list_del_rcu(&macsec->secys);
+       if (list_empty(&rxd->secys))
+               netdev_rx_handler_unregister(real_dev);
+
+       macsec_del_dev(macsec);
+}
+
+static int register_macsec_dev(struct net_device *real_dev,
+                              struct net_device *dev)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct macsec_rxh_data *rxd = macsec_data_rtnl(real_dev);
+
+       if (!rxd) {
+               int err;
+
+               rxd = kmalloc(sizeof(*rxd), GFP_KERNEL);
+               if (!rxd)
+                       return -ENOMEM;
+
+               INIT_LIST_HEAD(&rxd->secys);
+
+               err = netdev_rx_handler_register(real_dev, macsec_handle_frame,
+                                                rxd);
+               if (err < 0)
+                       return err;
+       }
+
+       list_add_tail_rcu(&macsec->secys, &rxd->secys);
+       return 0;
+}
+
+static bool sci_exists(struct net_device *dev, sci_t sci)
+{
+       struct macsec_rxh_data *rxd = macsec_data_rtnl(dev);
+       struct macsec_dev *macsec;
+
+       list_for_each_entry(macsec, &rxd->secys, secys) {
+               if (macsec->secy.sci == sci)
+                       return true;
+       }
+
+       return false;
+}
+
+static sci_t dev_to_sci(struct net_device *dev, __be16 port)
+{
+       return make_sci(dev->dev_addr, port);
+}
+
+static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct macsec_secy *secy = &macsec->secy;
+
+       macsec->stats = netdev_alloc_pcpu_stats(struct pcpu_secy_stats);
+       if (!macsec->stats)
+               return -ENOMEM;
+
+       secy->tx_sc.stats = netdev_alloc_pcpu_stats(struct pcpu_tx_sc_stats);
+       if (!secy->tx_sc.stats) {
+               free_percpu(macsec->stats);
+               return -ENOMEM;
+       }
+
+       if (sci == MACSEC_UNDEF_SCI)
+               sci = dev_to_sci(dev, MACSEC_PORT_ES);
+
+       secy->netdev = dev;
+       secy->operational = true;
+       secy->key_len = DEFAULT_SAK_LEN;
+       secy->icv_len = icv_len;
+       secy->validate_frames = MACSEC_VALIDATE_DEFAULT;
+       secy->protect_frames = true;
+       secy->replay_protect = false;
+
+       secy->sci = sci;
+       secy->tx_sc.active = true;
+       secy->tx_sc.encoding_sa = DEFAULT_ENCODING_SA;
+       secy->tx_sc.encrypt = DEFAULT_ENCRYPT;
+       secy->tx_sc.send_sci = DEFAULT_SEND_SCI;
+       secy->tx_sc.end_station = false;
+       secy->tx_sc.scb = false;
+
+       return 0;
+}
+
+static int macsec_newlink(struct net *net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[])
+{
+       struct macsec_dev *macsec = macsec_priv(dev);
+       struct net_device *real_dev;
+       int err;
+       sci_t sci;
+       u8 icv_len = DEFAULT_ICV_LEN;
+       rx_handler_func_t *rx_handler;
+
+       if (!tb[IFLA_LINK])
+               return -EINVAL;
+       real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
+       if (!real_dev)
+               return -ENODEV;
+
+       dev->priv_flags |= IFF_MACSEC;
+
+       macsec->real_dev = real_dev;
+
+       if (data && data[IFLA_MACSEC_ICV_LEN])
+               icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
+       dev->mtu = real_dev->mtu - icv_len - macsec_extra_len(true);
+
+       rx_handler = rtnl_dereference(real_dev->rx_handler);
+       if (rx_handler && rx_handler != macsec_handle_frame)
+               return -EBUSY;
+
+       err = register_netdevice(dev);
+       if (err < 0)
+               return err;
+
+       /* need to be already registered so that ->init has run and
+        * the MAC addr is set
+        */
+       if (data && data[IFLA_MACSEC_SCI])
+               sci = nla_get_sci(data[IFLA_MACSEC_SCI]);
+       else if (data && data[IFLA_MACSEC_PORT])
+               sci = dev_to_sci(dev, nla_get_be16(data[IFLA_MACSEC_PORT]));
+       else
+               sci = dev_to_sci(dev, MACSEC_PORT_ES);
+
+       if (rx_handler && sci_exists(real_dev, sci)) {
+               err = -EBUSY;
+               goto unregister;
+       }
+
+       err = macsec_add_dev(dev, sci, icv_len);
+       if (err)
+               goto unregister;
+
+       if (data)
+               macsec_changelink_common(dev, data);
+
+       err = register_macsec_dev(real_dev, dev);
+       if (err < 0)
+               goto del_dev;
+
+       dev_hold(real_dev);
+
+       return 0;
+
+del_dev:
+       macsec_del_dev(macsec);
+unregister:
+       unregister_netdevice(dev);
+       return err;
+}
+
+static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[])
+{
+       u64 csid = DEFAULT_CIPHER_ID;
+       u8 icv_len = DEFAULT_ICV_LEN;
+       int flag;
+       bool es, scb, sci;
+
+       if (!data)
+               return 0;
+
+       if (data[IFLA_MACSEC_CIPHER_SUITE])
+               csid = nla_get_u64(data[IFLA_MACSEC_CIPHER_SUITE]);
+
+       if (data[IFLA_MACSEC_ICV_LEN])
+               icv_len = nla_get_u8(data[IFLA_MACSEC_ICV_LEN]);
+
+       switch (csid) {
+       case DEFAULT_CIPHER_ID:
+       case DEFAULT_CIPHER_ALT:
+               if (icv_len < MACSEC_MIN_ICV_LEN ||
+                   icv_len > MACSEC_MAX_ICV_LEN)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (data[IFLA_MACSEC_ENCODING_SA]) {
+               if (nla_get_u8(data[IFLA_MACSEC_ENCODING_SA]) >= MACSEC_NUM_AN)
+                       return -EINVAL;
+       }
+
+       for (flag = IFLA_MACSEC_ENCODING_SA + 1;
+            flag < IFLA_MACSEC_VALIDATION;
+            flag++) {
+               if (data[flag]) {
+                       if (nla_get_u8(data[flag]) > 1)
+                               return -EINVAL;
+               }
+       }
+
+       es  = data[IFLA_MACSEC_ES] ? nla_get_u8(data[IFLA_MACSEC_ES]) : false;
+       sci = data[IFLA_MACSEC_INC_SCI] ? nla_get_u8(data[IFLA_MACSEC_INC_SCI]) : false;
+       scb = data[IFLA_MACSEC_SCB] ? nla_get_u8(data[IFLA_MACSEC_SCB]) : false;
+
+       if ((sci && (scb || es)) || (scb && es))
+               return -EINVAL;
+
+       if (data[IFLA_MACSEC_VALIDATION] &&
+           nla_get_u8(data[IFLA_MACSEC_VALIDATION]) > MACSEC_VALIDATE_MAX)
+               return -EINVAL;
+
+       if ((data[IFLA_MACSEC_PROTECT] &&
+            nla_get_u8(data[IFLA_MACSEC_PROTECT])) &&
+           !data[IFLA_MACSEC_WINDOW])
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct net *macsec_get_link_net(const struct net_device *dev)
+{
+       return dev_net(macsec_priv(dev)->real_dev);
+}
+
+static size_t macsec_get_size(const struct net_device *dev)
+{
+       return 0 +
+               nla_total_size(8) + /* SCI */
+               nla_total_size(1) + /* ICV_LEN */
+               nla_total_size(8) + /* CIPHER_SUITE */
+               nla_total_size(4) + /* WINDOW */
+               nla_total_size(1) + /* ENCODING_SA */
+               nla_total_size(1) + /* ENCRYPT */
+               nla_total_size(1) + /* PROTECT */
+               nla_total_size(1) + /* INC_SCI */
+               nla_total_size(1) + /* ES */
+               nla_total_size(1) + /* SCB */
+               nla_total_size(1) + /* REPLAY_PROTECT */
+               nla_total_size(1) + /* VALIDATION */
+               0;
+}
+
+static int macsec_fill_info(struct sk_buff *skb,
+                           const struct net_device *dev)
+{
+       struct macsec_secy *secy = &macsec_priv(dev)->secy;
+       struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+
+       if (nla_put_sci(skb, IFLA_MACSEC_SCI, secy->sci) ||
+           nla_put_u8(skb, IFLA_MACSEC_ICV_LEN, secy->icv_len) ||
+           nla_put_u64(skb, IFLA_MACSEC_CIPHER_SUITE, DEFAULT_CIPHER_ID) ||
+           nla_put_u8(skb, IFLA_MACSEC_ENCODING_SA, tx_sc->encoding_sa) ||
+           nla_put_u8(skb, IFLA_MACSEC_ENCRYPT, tx_sc->encrypt) ||
+           nla_put_u8(skb, IFLA_MACSEC_PROTECT, secy->protect_frames) ||
+           nla_put_u8(skb, IFLA_MACSEC_INC_SCI, tx_sc->send_sci) ||
+           nla_put_u8(skb, IFLA_MACSEC_ES, tx_sc->end_station) ||
+           nla_put_u8(skb, IFLA_MACSEC_SCB, tx_sc->scb) ||
+           nla_put_u8(skb, IFLA_MACSEC_REPLAY_PROTECT, secy->replay_protect) ||
+           nla_put_u8(skb, IFLA_MACSEC_VALIDATION, secy->validate_frames) ||
+           0)
+               goto nla_put_failure;
+
+       if (secy->replay_protect) {
+               if (nla_put_u32(skb, IFLA_MACSEC_WINDOW, secy->replay_window))
+                       goto nla_put_failure;
+       }
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static struct rtnl_link_ops macsec_link_ops __read_mostly = {
+       .kind           = "macsec",
+       .priv_size      = sizeof(struct macsec_dev),
+       .maxtype        = IFLA_MACSEC_MAX,
+       .policy         = macsec_rtnl_policy,
+       .setup          = macsec_setup,
+       .validate       = macsec_validate_attr,
+       .newlink        = macsec_newlink,
+       .changelink     = macsec_changelink,
+       .dellink        = macsec_dellink,
+       .get_size       = macsec_get_size,
+       .fill_info      = macsec_fill_info,
+       .get_link_net   = macsec_get_link_net,
+};
+
+static bool is_macsec_master(struct net_device *dev)
+{
+       return rcu_access_pointer(dev->rx_handler) == macsec_handle_frame;
+}
+
+static int macsec_notify(struct notifier_block *this, unsigned long event,
+                        void *ptr)
+{
+       struct net_device *real_dev = netdev_notifier_info_to_dev(ptr);
+       LIST_HEAD(head);
+
+       if (!is_macsec_master(real_dev))
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UNREGISTER: {
+               struct macsec_dev *m, *n;
+               struct macsec_rxh_data *rxd;
+
+               rxd = macsec_data_rtnl(real_dev);
+               list_for_each_entry_safe(m, n, &rxd->secys, secys) {
+                       macsec_dellink(m->secy.netdev, &head);
+               }
+               unregister_netdevice_many(&head);
+               break;
+       }
+       case NETDEV_CHANGEMTU: {
+               struct macsec_dev *m;
+               struct macsec_rxh_data *rxd;
+
+               rxd = macsec_data_rtnl(real_dev);
+               list_for_each_entry(m, &rxd->secys, secys) {
+                       struct net_device *dev = m->secy.netdev;
+                       unsigned int mtu = real_dev->mtu - (m->secy.icv_len +
+                                                           macsec_extra_len(true));
+
+                       if (dev->mtu > mtu)
+                               dev_set_mtu(dev, mtu);
+               }
+       }
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block macsec_notifier = {
+       .notifier_call = macsec_notify,
+};
+
+static int __init macsec_init(void)
+{
+       int err;
+
+       pr_info("MACsec IEEE 802.1AE\n");
+       err = register_netdevice_notifier(&macsec_notifier);
+       if (err)
+               return err;
+
+       err = rtnl_link_register(&macsec_link_ops);
+       if (err)
+               goto notifier;
+
+       err = genl_register_family_with_ops(&macsec_fam, macsec_genl_ops);
+       if (err)
+               goto rtnl;
+
+       return 0;
+
+rtnl:
+       rtnl_link_unregister(&macsec_link_ops);
+notifier:
+       unregister_netdevice_notifier(&macsec_notifier);
+       return err;
+}
+
+static void __exit macsec_exit(void)
+{
+       genl_unregister_family(&macsec_fam);
+       rtnl_link_unregister(&macsec_link_ops);
+       unregister_netdevice_notifier(&macsec_notifier);
+}
+
+module_init(macsec_init);
+module_exit(macsec_exit);
+
+MODULE_ALIAS_RTNL_LINK("macsec");
+
+MODULE_DESCRIPTION("MACsec IEEE 802.1AE");
+MODULE_LICENSE("GPL v2");
index 94e688805dd262317327a446d8e2e460a668d75a..6e953e3a460a7f23d038ae2424b17930d325056a 100644 (file)
@@ -940,12 +940,12 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
        strlcpy(drvinfo->version, "0.1", sizeof(drvinfo->version));
 }
 
-static int macvlan_ethtool_get_settings(struct net_device *dev,
-                                       struct ethtool_cmd *cmd)
+static int macvlan_ethtool_get_link_ksettings(struct net_device *dev,
+                                             struct ethtool_link_ksettings *cmd)
 {
        const struct macvlan_dev *vlan = netdev_priv(dev);
 
-       return __ethtool_get_settings(vlan->lowerdev, cmd);
+       return __ethtool_get_link_ksettings(vlan->lowerdev, cmd);
 }
 
 static netdev_features_t macvlan_fix_features(struct net_device *dev,
@@ -1020,7 +1020,7 @@ static int macvlan_dev_get_iflink(const struct net_device *dev)
 
 static const struct ethtool_ops macvlan_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
-       .get_settings           = macvlan_ethtool_get_settings,
+       .get_link_ksettings     = macvlan_ethtool_get_link_ksettings,
        .get_drvinfo            = macvlan_ethtool_get_drvinfo,
 };
 
@@ -1069,7 +1069,7 @@ EXPORT_SYMBOL_GPL(macvlan_common_setup);
 static void macvlan_setup(struct net_device *dev)
 {
        macvlan_common_setup(dev);
-       dev->tx_queue_len       = 0;
+       dev->priv_flags |= IFF_NO_QUEUE;
 }
 
 static int macvlan_port_create(struct net_device *dev)
index d636d051fac8317ca6d94dd1bdf9c34cac4a5b4b..95394edd1ed528fc9cf94fb39aadeaa28c47fb26 100644 (file)
@@ -760,6 +760,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                        macvtap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
                if (copylen > good_linear)
                        copylen = good_linear;
+               else if (copylen < ETH_HLEN)
+                       copylen = ETH_HLEN;
                linear = copylen;
                i = *from;
                iov_iter_advance(&i, copylen);
@@ -769,10 +771,11 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
 
        if (!zerocopy) {
                copylen = len;
-               if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > good_linear)
+               linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+               if (linear > good_linear)
                        linear = good_linear;
-               else
-                       linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
+               else if (linear < ETH_HLEN)
+                       linear = ETH_HLEN;
        }
 
        skb = macvtap_alloc_skb(&q->sk, MACVTAP_RESERVE, copylen,
index 2174ec937b4dc8c9356be98db399bd4b265f07be..1e901c7cfaac730ba385b4dde83d77614d5f4173 100644 (file)
@@ -52,6 +52,9 @@
 #define AT803X_DEBUG_REG_5                     0x05
 #define AT803X_DEBUG_TX_CLK_DLY_EN             BIT(8)
 
+#define AT803X_REG_CHIP_CONFIG                 0x1f
+#define AT803X_BT_BX_REG_SEL                   0x8000
+
 #define ATH8030_PHY_ID 0x004dd076
 #define ATH8031_PHY_ID 0x004dd074
 #define ATH8035_PHY_ID 0x004dd072
@@ -206,6 +209,7 @@ static int at803x_suspend(struct phy_device *phydev)
 {
        int value;
        int wol_enabled;
+       int ccr;
 
        mutex_lock(&phydev->lock);
 
@@ -221,6 +225,16 @@ static int at803x_suspend(struct phy_device *phydev)
 
        phy_write(phydev, MII_BMCR, value);
 
+       if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
+               goto done;
+
+       /* also power-down SGMII interface */
+       ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
+       phy_write(phydev, MII_BMCR, phy_read(phydev, MII_BMCR) | BMCR_PDOWN);
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
+
+done:
        mutex_unlock(&phydev->lock);
 
        return 0;
@@ -229,6 +243,7 @@ static int at803x_suspend(struct phy_device *phydev)
 static int at803x_resume(struct phy_device *phydev)
 {
        int value;
+       int ccr;
 
        mutex_lock(&phydev->lock);
 
@@ -236,6 +251,17 @@ static int at803x_resume(struct phy_device *phydev)
        value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
        phy_write(phydev, MII_BMCR, value);
 
+       if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
+               goto done;
+
+       /* also power-up SGMII interface */
+       ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
+       value = phy_read(phydev, MII_BMCR) & ~(BMCR_PDOWN | BMCR_ISOLATE);
+       phy_write(phydev, MII_BMCR, value);
+       phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
+
+done:
        mutex_unlock(&phydev->lock);
 
        return 0;
index bf241a3ec5e56ceb9d9f85aed73bab90f1559781..b881a7b1e4f6dbc9cbbcbdac2ed16a3a6ace4fa5 100644 (file)
@@ -24,7 +24,7 @@
 #define MII_BCM7XXX_100TX_FALSE_CAR    0x13
 #define MII_BCM7XXX_100TX_DISC         0x14
 #define MII_BCM7XXX_AUX_MODE           0x1d
-#define  MII_BCM7XX_64CLK_MDIO         BIT(12)
+#define  MII_BCM7XXX_64CLK_MDIO                BIT(12)
 #define MII_BCM7XXX_TEST               0x1f
 #define  MII_BCM7XXX_SHD_MODE_2                BIT(2)
 
@@ -247,13 +247,9 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
        int ret;
 
        /* Enable 64 clock MDIO */
-       phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
+       phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XXX_64CLK_MDIO);
        phy_read(phydev, MII_BCM7XXX_AUX_MODE);
 
-       /* Workaround only required for 100Mbits/sec capable PHYs */
-       if (phydev->supported & PHY_GBIT_FEATURES)
-               return 0;
-
        /* set shadow mode 2 */
        ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
                        MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
@@ -270,7 +266,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
        phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
 
        /* reset shadow mode 2 */
-       ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
+       ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, 0, MII_BCM7XXX_SHD_MODE_2);
        if (ret < 0)
                return ret;
 
@@ -307,11 +303,6 @@ static int bcm7xxx_suspend(struct phy_device *phydev)
        return 0;
 }
 
-static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
-{
-       return 0;
-}
-
 #define BCM7XXX_28NM_GPHY(_oui, _name)                                 \
 {                                                                      \
        .phy_id         = (_oui),                                       \
@@ -326,6 +317,21 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
        .resume         = bcm7xxx_28nm_resume,                          \
 }
 
+#define BCM7XXX_40NM_EPHY(_oui, _name)                                 \
+{                                                                      \
+       .phy_id         = (_oui),                                       \
+       .phy_id_mask    = 0xfffffff0,                                   \
+       .name           = _name,                                        \
+       .features       = PHY_BASIC_FEATURES |                          \
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,       \
+       .flags          = PHY_IS_INTERNAL,                              \
+       .config_init    = bcm7xxx_config_init,                          \
+       .config_aneg    = genphy_config_aneg,                           \
+       .read_status    = genphy_read_status,                           \
+       .suspend        = bcm7xxx_suspend,                              \
+       .resume         = bcm7xxx_config_init,                          \
+}
+
 static struct phy_driver bcm7xxx_driver[] = {
        BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
        BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
@@ -333,67 +339,10 @@ static struct phy_driver bcm7xxx_driver[] = {
        BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
        BCM7XXX_28NM_GPHY(PHY_ID_BCM7439_2, "Broadcom BCM7439 (2)"),
        BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
-{
-       .phy_id         = PHY_ID_BCM7425,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7425",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_config_init,
-}, {
-       .phy_id         = PHY_ID_BCM7429,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7429",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_config_init,
-}, {
-       .phy_id         = PHY_ID_BCM7435,
-       .phy_id_mask    = 0xfffffff0,
-       .name           = "Broadcom BCM7435",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_config_init,
-}, {
-       .phy_id         = PHY_BCM_OUI_4,
-       .phy_id_mask    = 0xffff0000,
-       .name           = "Broadcom BCM7XXX 40nm",
-       .features       = PHY_GBIT_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_config_init,
-}, {
-       .phy_id         = PHY_BCM_OUI_5,
-       .phy_id_mask    = 0xffffff00,
-       .name           = "Broadcom BCM7XXX 65nm",
-       .features       = PHY_BASIC_FEATURES |
-                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
-       .flags          = PHY_IS_INTERNAL,
-       .config_init    = bcm7xxx_dummy_config_init,
-       .config_aneg    = genphy_config_aneg,
-       .read_status    = genphy_read_status,
-       .suspend        = bcm7xxx_suspend,
-       .resume         = bcm7xxx_config_init,
-} };
+       BCM7XXX_40NM_EPHY(PHY_ID_BCM7425, "Broadcom BCM7425"),
+       BCM7XXX_40NM_EPHY(PHY_ID_BCM7429, "Broadcom BCM7429"),
+       BCM7XXX_40NM_EPHY(PHY_ID_BCM7435, "Broadcom BCM7435"),
+};
 
 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
        { PHY_ID_BCM7250, 0xfffffff0, },
@@ -404,8 +353,6 @@ static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
        { PHY_ID_BCM7439, 0xfffffff0, },
        { PHY_ID_BCM7435, 0xfffffff0, },
        { PHY_ID_BCM7445, 0xfffffff0, },
-       { PHY_BCM_OUI_4, 0xffff0000 },
-       { PHY_BCM_OUI_5, 0xffffff00 },
        { }
 };
 
index 556904f572d6258f5c4fe9c4c7ba184e28ba2ff8..03d54c4adc881fc2d65de40a399096687c5b4444 100644 (file)
@@ -103,7 +103,7 @@ MODULE_DEVICE_TABLE(mdio, dp83848_tbl);
 
 static struct phy_driver dp83848_driver[] = {
        DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"),
-       DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"),
+       DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"),
        DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"),
 };
 module_phy_driver(dp83848_driver);
index e3eb96443c97ad0bc6e03ad0784a119d35b89ee7..280e8795b46367af40d717d9b16d56f748d6f585 100644 (file)
 #define MII_88E3016_DISABLE_SCRAMBLER  0x0200
 #define MII_88E3016_AUTO_MDIX_CROSSOVER        0x0030
 
+#define MII_88E1510_GEN_CTRL_REG_1             0x14
+#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK   0x7
+#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII  0x1     /* SGMII to copper */
+#define MII_88E1510_GEN_CTRL_REG_1_RESET       0x8000  /* Soft reset */
+
 MODULE_DESCRIPTION("Marvell PHY driver");
 MODULE_AUTHOR("Andy Fleming");
 MODULE_LICENSE("GPL");
@@ -446,6 +451,12 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
        if (err < 0)
                return err;
 
+       return 0;
+}
+
+static int marvell_config_init(struct phy_device *phydev)
+{
+       /* Set registers from marvell,reg-init DT property */
        return marvell_of_reg_init(phydev);
 }
 
@@ -495,7 +506,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
 
        mdelay(500);
 
-       return 0;
+       return marvell_config_init(phydev);
 }
 
 static int m88e3016_config_init(struct phy_device *phydev)
@@ -514,7 +525,7 @@ static int m88e3016_config_init(struct phy_device *phydev)
        if (reg < 0)
                return reg;
 
-       return 0;
+       return marvell_config_init(phydev);
 }
 
 static int m88e1111_config_init(struct phy_device *phydev)
@@ -625,6 +636,41 @@ static int m88e1111_config_init(struct phy_device *phydev)
        return phy_write(phydev, MII_BMCR, BMCR_RESET);
 }
 
+static int m88e1510_config_init(struct phy_device *phydev)
+{
+       int err;
+       int temp;
+
+       /* SGMII-to-Copper mode initialization */
+       if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+               /* Select page 18 */
+               err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
+               if (err < 0)
+                       return err;
+
+               /* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
+               temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
+               temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
+               temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
+               err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+               if (err < 0)
+                       return err;
+
+               /* PHY reset is necessary after changing MODE[2:0] */
+               temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
+               err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+               if (err < 0)
+                       return err;
+
+               /* Reset page selection */
+               err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
+               if (err < 0)
+                       return err;
+       }
+
+       return marvell_config_init(phydev);
+}
+
 static int m88e1118_config_aneg(struct phy_device *phydev)
 {
        int err;
@@ -1025,8 +1071,8 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
 {
        struct marvell_hw_stat stat = marvell_hw_stats[i];
        struct marvell_priv *priv = phydev->priv;
-       int err, oldpage;
-       u64 val;
+       int err, oldpage, val;
+       u64 ret;
 
        oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
        err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
@@ -1036,16 +1082,16 @@ static u64 marvell_get_stat(struct phy_device *phydev, int i)
 
        val = phy_read(phydev, stat.reg);
        if (val < 0) {
-               val = UINT64_MAX;
+               ret = UINT64_MAX;
        } else {
                val = val & ((1 << stat.bits) - 1);
                priv->stats[i] += val;
-               val = priv->stats[i];
+               ret = priv->stats[i];
        }
 
        phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
 
-       return val;
+       return ret;
 }
 
 static void marvell_get_stats(struct phy_device *phydev,
@@ -1078,6 +1124,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .probe = marvell_probe,
                .flags = PHY_HAS_INTERRUPT,
+               .config_init = &marvell_config_init,
                .config_aneg = &marvell_config_aneg,
                .read_status = &genphy_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
@@ -1149,6 +1196,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
                .probe = marvell_probe,
+               .config_init = &marvell_config_init,
                .config_aneg = &m88e1121_config_aneg,
                .read_status = &marvell_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
@@ -1167,6 +1215,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
                .probe = marvell_probe,
+               .config_init = &marvell_config_init,
                .config_aneg = &m88e1318_config_aneg,
                .read_status = &marvell_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
@@ -1259,6 +1308,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
                .probe = marvell_probe,
+               .config_init = &m88e1510_config_init,
                .config_aneg = &m88e1510_config_aneg,
                .read_status = &marvell_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
@@ -1277,6 +1327,7 @@ static struct phy_driver marvell_drivers[] = {
                .features = PHY_GBIT_FEATURES,
                .flags = PHY_HAS_INTERRUPT,
                .probe = marvell_probe,
+               .config_init = &marvell_config_init,
                .config_aneg = &m88e1510_config_aneg,
                .read_status = &marvell_read_status,
                .ack_interrupt = &marvell_ack_interrupt,
index 03833dbfca67d1ab53ca1af42398e7ea9dd04f01..4516c8a4fd82b3d73a7393f2fd3b09d25d4263bc 100644 (file)
@@ -297,6 +297,17 @@ static int kszphy_config_init(struct phy_device *phydev)
        if (priv->led_mode >= 0)
                kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode);
 
+       if (phy_interrupt_is_valid(phydev)) {
+               int ctl = phy_read(phydev, MII_BMCR);
+
+               if (ctl < 0)
+                       return ctl;
+
+               ret = phy_write(phydev, MII_BMCR, ctl & ~BMCR_ANENABLE);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -612,18 +623,19 @@ static u64 kszphy_get_stat(struct phy_device *phydev, int i)
 {
        struct kszphy_hw_stat stat = kszphy_hw_stats[i];
        struct kszphy_priv *priv = phydev->priv;
-       u64 val;
+       int val;
+       u64 ret;
 
        val = phy_read(phydev, stat.reg);
        if (val < 0) {
-               val = UINT64_MAX;
+               ret = UINT64_MAX;
        } else {
                val = val & ((1 << stat.bits) - 1);
                priv->stats[i] += val;
-               val = priv->stats[i];
+               ret = priv->stats[i];
        }
 
-       return val;
+       return ret;
 }
 
 static void kszphy_get_stats(struct phy_device *phydev,
@@ -635,6 +647,21 @@ static void kszphy_get_stats(struct phy_device *phydev,
                data[i] = kszphy_get_stat(phydev, i);
 }
 
+static int kszphy_resume(struct phy_device *phydev)
+{
+       int value;
+
+       mutex_lock(&phydev->lock);
+
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+       kszphy_config_intr(phydev);
+       mutex_unlock(&phydev->lock);
+
+       return 0;
+}
+
 static int kszphy_probe(struct phy_device *phydev)
 {
        const struct kszphy_type *type = phydev->drv->driver_data;
@@ -844,7 +871,7 @@ static struct phy_driver ksphy_driver[] = {
        .get_strings    = kszphy_get_strings,
        .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
-       .resume         = genphy_resume,
+       .resume         = kszphy_resume,
 }, {
        .phy_id         = PHY_ID_KSZ8061,
        .name           = "Micrel KSZ8061",
index bad3f005faee433608f1e059cf6f07f8cbae6093..e551f3a89cfd0212e381ec274c59f558eb07d2b0 100644 (file)
@@ -1410,7 +1410,7 @@ int genphy_config_init(struct phy_device *phydev)
 
        features = (SUPPORTED_TP | SUPPORTED_MII
                        | SUPPORTED_AUI | SUPPORTED_FIBRE |
-                       SUPPORTED_BNC);
+                       SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause);
 
        /* Do we support autonegotiation? */
        val = phy_read(phydev, MII_BMSR);
index 5e7340f6b37cf162ef7d0c12902c220231f6a938..b5d50d45872893ffcbdef86f8317d0512b2e2a32 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
-#include <linux/gpio.h>
 #include <linux/of_gpio.h>
 
 #include <linux/spi/spi.h>
index fc8ad001bc949e894e7659301af65565a5a21046..931836e09a6b62f3b34de3f6490e655bf05ce1eb 100644 (file)
@@ -443,9 +443,14 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
                         * network traffic (demand mode).
                         */
                        struct ppp *ppp = PF_TO_PPP(pf);
+
+                       ppp_recv_lock(ppp);
                        if (ppp->n_channels == 0 &&
-                           (ppp->flags & SC_LOOP_TRAFFIC) == 0)
+                           (ppp->flags & SC_LOOP_TRAFFIC) == 0) {
+                               ppp_recv_unlock(ppp);
                                break;
+                       }
+                       ppp_recv_unlock(ppp);
                }
                ret = -EAGAIN;
                if (file->f_flags & O_NONBLOCK)
@@ -532,9 +537,12 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait)
        else if (pf->kind == INTERFACE) {
                /* see comment in ppp_read */
                struct ppp *ppp = PF_TO_PPP(pf);
+
+               ppp_recv_lock(ppp);
                if (ppp->n_channels == 0 &&
                    (ppp->flags & SC_LOOP_TRAFFIC) == 0)
                        mask |= POLLIN | POLLRDNORM;
+               ppp_recv_unlock(ppp);
        }
 
        return mask;
@@ -2429,13 +2437,15 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
        unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
 
        err = -EFAULT;
-       if (copy_from_user(&data, (void __user *) arg, sizeof(data)) ||
-           (data.length <= CCP_MAX_OPTION_LENGTH &&
-            copy_from_user(ccp_option, (void __user *) data.ptr, data.length)))
+       if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
+               goto out;
+       if (data.length > CCP_MAX_OPTION_LENGTH)
+               goto out;
+       if (copy_from_user(ccp_option, (void __user *) data.ptr, data.length))
                goto out;
+
        err = -EINVAL;
-       if (data.length > CCP_MAX_OPTION_LENGTH ||
-           ccp_option[1] < 2 || ccp_option[1] > data.length)
+       if (data.length < 2 || ccp_option[1] < 2 || ccp_option[1] > data.length)
                goto out;
 
        cp = try_then_request_module(
@@ -2808,6 +2818,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
 
 out2:
        mutex_unlock(&pn->all_ppp_mutex);
+       rtnl_unlock();
        free_netdev(dev);
 out1:
        *retp = ret;
index f3c63022eb3c582b46841e381e67af478c03f629..4ddae8118c8566e4de07a16b136af13597fe4f3e 100644 (file)
@@ -395,6 +395,8 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb)
 
                if (!__pppoe_xmit(sk_pppox(relay_po), skb))
                        goto abort_put;
+
+               sock_put(sk_pppox(relay_po));
        } else {
                if (sock_queue_rcv_skb(sk, skb))
                        goto abort_kfree;
index 00558e1395847d51bccd4a35050c9ae1bb79f52a..2769835f48ca862cd4afb618e90204eb37d70bd7 100644 (file)
@@ -2813,12 +2813,12 @@ static void __team_port_change_send(struct team_port *port, bool linkup)
        port->state.linkup = linkup;
        team_refresh_port_linkup(port);
        if (linkup) {
-               struct ethtool_cmd ecmd;
+               struct ethtool_link_ksettings ecmd;
 
-               err = __ethtool_get_settings(port->dev, &ecmd);
+               err = __ethtool_get_link_ksettings(port->dev, &ecmd);
                if (!err) {
-                       port->state.speed = ethtool_cmd_speed(&ecmd);
-                       port->state.duplex = ecmd.duplex;
+                       port->state.speed = ecmd.base.speed;
+                       port->state.duplex = ecmd.base.duplex;
                        goto send_event;
                }
        }
index 88bb8cc3555b8c8197d7993a2a9c338ddab8e8b1..afdf950617c36e0bc5042da9cf0e57a0cb0cd88d 100644 (file)
@@ -187,6 +187,7 @@ struct tun_struct {
 #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
                          NETIF_F_TSO6|NETIF_F_UFO)
 
+       int                     align;
        int                     vnet_hdr_sz;
        int                     sndbuf;
        struct tap_filter       txflt;
@@ -934,6 +935,17 @@ static void tun_poll_controller(struct net_device *dev)
        return;
 }
 #endif
+
+static void tun_set_headroom(struct net_device *dev, int new_hr)
+{
+       struct tun_struct *tun = netdev_priv(dev);
+
+       if (new_hr < NET_SKB_PAD)
+               new_hr = NET_SKB_PAD;
+
+       tun->align = new_hr;
+}
+
 static const struct net_device_ops tun_netdev_ops = {
        .ndo_uninit             = tun_net_uninit,
        .ndo_open               = tun_net_open,
@@ -945,6 +957,7 @@ static const struct net_device_ops tun_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = tun_poll_controller,
 #endif
+       .ndo_set_rx_headroom    = tun_set_headroom,
 };
 
 static const struct net_device_ops tap_netdev_ops = {
@@ -962,6 +975,7 @@ static const struct net_device_ops tap_netdev_ops = {
        .ndo_poll_controller    = tun_poll_controller,
 #endif
        .ndo_features_check     = passthru_features_check,
+       .ndo_set_rx_headroom    = tun_set_headroom,
 };
 
 static void tun_flow_init(struct tun_struct *tun)
@@ -1086,7 +1100,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
        struct sk_buff *skb;
        size_t total_len = iov_iter_count(from);
-       size_t len = total_len, align = NET_SKB_PAD, linear;
+       size_t len = total_len, align = tun->align, linear;
        struct virtio_net_hdr gso = { 0 };
        int good_linear;
        int copylen;
@@ -1694,6 +1708,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->txflt.count = 0;
                tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
+               tun->align = NET_SKB_PAD;
                tun->filter_attached = false;
                tun->sndbuf = tfile->socket.sk->sk_sndbuf;
 
index 7f83504dfa69bba2c8db612d1d25196fa5b72d91..cdde59089f729fc3578e4aea56796df237c0cee2 100644 (file)
@@ -395,6 +395,10 @@ config USB_NET_RNDIS_HOST
          The protocol specification is incomplete, and is controlled by
          (and for) Microsoft; it isn't an "Open" ecosystem or market.
 
+config USB_NET_CDC_SUBSET_ENABLE
+       tristate
+       depends on USB_NET_CDC_SUBSET
+
 config USB_NET_CDC_SUBSET
        tristate "Simple USB Network Links (CDC Ethernet subset)"
        depends on USB_USBNET
@@ -413,6 +417,7 @@ config USB_NET_CDC_SUBSET
 config USB_ALI_M5632
        bool "ALi M5632 based 'USB 2.0 Data Link' cables"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          based on this design, which supports USB 2.0 high speed.
@@ -420,6 +425,7 @@ config USB_ALI_M5632
 config USB_AN2720
        bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          based on this design.  Note that AnchorChips is now a
@@ -428,6 +434,7 @@ config USB_AN2720
 config USB_BELKIN
        bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        default y
        help
          Choose this option if you're using a host-to-host cable
@@ -437,6 +444,7 @@ config USB_BELKIN
 config USB_ARMLINUX
        bool "Embedded ARM Linux links (iPaq, ...)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        default y
        help
          Choose this option to support the "usb-eth" networking driver
@@ -454,6 +462,7 @@ config USB_ARMLINUX
 config USB_EPSON2888
        bool "Epson 2888 based firmware (DEVELOPMENT)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option to support the usb networking links used
          by some sample firmware from Epson.
@@ -461,6 +470,7 @@ config USB_EPSON2888
 config USB_KC2190
        bool "KT Technology KC2190 based cables (InstaNet)"
        depends on USB_NET_CDC_SUBSET
+       select USB_NET_CDC_SUBSET_ENABLE
        help
          Choose this option if you're using a host-to-host cable
          with one of these chips.
index b5f04068dbe4859fb9581304c8bd893addaaeb1d..37fb46aee341a77bf734ea55999fd70c9b8eac3a 100644 (file)
@@ -23,7 +23,7 @@ obj-$(CONFIG_USB_NET_GL620A)  += gl620a.o
 obj-$(CONFIG_USB_NET_NET1080)  += net1080.o
 obj-$(CONFIG_USB_NET_PLUSB)    += plusb.o
 obj-$(CONFIG_USB_NET_RNDIS_HOST)       += rndis_host.o
-obj-$(CONFIG_USB_NET_CDC_SUBSET)       += cdc_subset.o
+obj-$(CONFIG_USB_NET_CDC_SUBSET_ENABLE)        += cdc_subset.o
 obj-$(CONFIG_USB_NET_ZAURUS)   += zaurus.o
 obj-$(CONFIG_USB_NET_MCS7830)  += mcs7830.o
 obj-$(CONFIG_USB_USBNET)       += usbnet.o
index 224e7d82de6d2552121a2af643ea57d927e5b05b..cf77f2dffa698fa8399f5ae7b04162be8a1b34fe 100644 (file)
@@ -134,7 +134,6 @@ static void ax88172a_remove_mdio(struct usbnet *dev)
 
        netdev_info(dev->net, "deregistering mdio bus %s\n", priv->mdio->id);
        mdiobus_unregister(priv->mdio);
-       kfree(priv->mdio->irq);
        mdiobus_free(priv->mdio);
 }
 
index dc0212c3cc28cc36267d62cfebe726f51fe0c910..86ba30ba35e8fcf45f9eba287334da04b54203e2 100644 (file)
@@ -837,7 +837,11 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
-       /* reset data interface */
+       /* Reset data interface. Some devices will not reset properly
+        * unless they are configured first.  Toggle the altsetting to
+        * force a reset
+        */
+       usb_set_interface(dev->udev, iface_no, data_altsetting);
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp) {
                dev_dbg(&intf->dev, "set interface failed\n");
@@ -984,8 +988,6 @@ EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
 
 static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 {
-       int ret;
-
        /* MBIM backwards compatible function? */
        if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
                return -ENODEV;
@@ -994,16 +996,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
         * Additionally, generic NCM devices are assumed to accept arbitrarily
         * placed NDP.
         */
-       ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
-
-       /*
-        * We should get an event when network connection is "connected" or
-        * "disconnected". Set network connection in "disconnected" state
-        * (carrier is OFF) during attach, so the IP network stack does not
-        * start IPv6 negotiation and more.
-        */
-       usbnet_link_change(dev, 0, 0);
-       return ret;
+       return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
 }
 
 static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
@@ -1586,7 +1579,8 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
 
 static const struct driver_info cdc_ncm_info = {
        .description = "CDC NCM",
-       .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+       .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
+                       | FLAG_LINK_INTR,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .manage_power = usbnet_manage_power,
@@ -1599,7 +1593,7 @@ static const struct driver_info cdc_ncm_info = {
 static const struct driver_info wwan_info = {
        .description = "Mobile Broadband Network Device",
        .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-                       | FLAG_WWAN,
+                       | FLAG_LINK_INTR | FLAG_WWAN,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .manage_power = usbnet_manage_power,
@@ -1612,7 +1606,7 @@ static const struct driver_info wwan_info = {
 static const struct driver_info wwan_noarp_info = {
        .description = "Mobile Broadband Network Device (NO ARP)",
        .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
-                       | FLAG_WWAN | FLAG_NOARP,
+                       | FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .manage_power = usbnet_manage_power,
index 1c299b8a162d7243c5ae94b96618c3763083e91e..705c180163c5c2d240ff3eade515c5c156efb230 100644 (file)
@@ -36,7 +36,7 @@
 #define DRIVER_AUTHOR  "WOOJUNG HUH <woojung.huh@microchip.com>"
 #define DRIVER_DESC    "LAN78XX USB 3.0 Gigabit Ethernet Devices"
 #define DRIVER_NAME    "lan78xx"
-#define DRIVER_VERSION "1.0.2"
+#define DRIVER_VERSION "1.0.3"
 
 #define TX_TIMEOUT_JIFFIES             (5 * HZ)
 #define THROTTLE_JIFFIES               (HZ / 8)
@@ -278,8 +278,12 @@ struct lan78xx_net {
        int                     link_on;
        u8                      mdix_ctrl;
 
-       u32                     devid;
+       u32                     chipid;
+       u32                     chiprev;
        struct mii_bus          *mdiobus;
+
+       int                     fc_autoneg;
+       u8                      fc_request_control;
 };
 
 /* use ethtool to change the level for any given device */
@@ -471,7 +475,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,
         */
        ret = lan78xx_read_reg(dev, HW_CFG, &val);
        saved = val;
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
+       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
                val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
                ret = lan78xx_write_reg(dev, HW_CFG, val);
        }
@@ -505,7 +509,7 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,
 
        retval = 0;
 exit:
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
+       if (dev->chipid == ID_REV_CHIP_ID_7800_)
                ret = lan78xx_write_reg(dev, HW_CFG, saved);
 
        return retval;
@@ -539,7 +543,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,
         */
        ret = lan78xx_read_reg(dev, HW_CFG, &val);
        saved = val;
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
+       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
                val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
                ret = lan78xx_write_reg(dev, HW_CFG, val);
        }
@@ -587,7 +591,7 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,
 
        retval = 0;
 exit:
-       if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
+       if (dev->chipid == ID_REV_CHIP_ID_7800_)
                ret = lan78xx_write_reg(dev, HW_CFG, saved);
 
        return retval;
@@ -901,11 +905,15 @@ static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex,
 {
        u32 flow = 0, fct_flow = 0;
        int ret;
+       u8 cap;
 
-       u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+       if (dev->fc_autoneg)
+               cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
+       else
+               cap = dev->fc_request_control;
 
        if (cap & FLOW_CTRL_TX)
-               flow = (FLOW_CR_TX_FCEN_ | 0xFFFF);
+               flow |= (FLOW_CR_TX_FCEN_ | 0xFFFF);
 
        if (cap & FLOW_CTRL_RX)
                flow |= FLOW_CR_RX_FCEN_;
@@ -1385,6 +1393,62 @@ static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
        return ret;
 }
 
+static void lan78xx_get_pause(struct net_device *net,
+                             struct ethtool_pauseparam *pause)
+{
+       struct lan78xx_net *dev = netdev_priv(net);
+       struct phy_device *phydev = net->phydev;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+
+       phy_ethtool_gset(phydev, &ecmd);
+
+       pause->autoneg = dev->fc_autoneg;
+
+       if (dev->fc_request_control & FLOW_CTRL_TX)
+               pause->tx_pause = 1;
+
+       if (dev->fc_request_control & FLOW_CTRL_RX)
+               pause->rx_pause = 1;
+}
+
+static int lan78xx_set_pause(struct net_device *net,
+                            struct ethtool_pauseparam *pause)
+{
+       struct lan78xx_net *dev = netdev_priv(net);
+       struct phy_device *phydev = net->phydev;
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+       int ret;
+
+       phy_ethtool_gset(phydev, &ecmd);
+
+       if (pause->autoneg && !ecmd.autoneg) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       dev->fc_request_control = 0;
+       if (pause->rx_pause)
+               dev->fc_request_control |= FLOW_CTRL_RX;
+
+       if (pause->tx_pause)
+               dev->fc_request_control |= FLOW_CTRL_TX;
+
+       if (ecmd.autoneg) {
+               u32 mii_adv;
+
+               ecmd.advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+               mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
+               ecmd.advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+               phy_ethtool_sset(phydev, &ecmd);
+       }
+
+       dev->fc_autoneg = pause->autoneg;
+
+       ret = 0;
+exit:
+       return ret;
+}
+
 static const struct ethtool_ops lan78xx_ethtool_ops = {
        .get_link       = lan78xx_get_link,
        .nway_reset     = lan78xx_nway_reset,
@@ -1403,6 +1467,8 @@ static const struct ethtool_ops lan78xx_ethtool_ops = {
        .set_wol        = lan78xx_set_wol,
        .get_eee        = lan78xx_get_eee,
        .set_eee        = lan78xx_set_eee,
+       .get_pauseparam = lan78xx_get_pause,
+       .set_pauseparam = lan78xx_set_pause,
 };
 
 static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -1555,9 +1621,9 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
        snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
                 dev->udev->bus->busnum, dev->udev->devnum);
 
-       switch (dev->devid & ID_REV_CHIP_ID_MASK_) {
-       case 0x78000000:
-       case 0x78500000:
+       switch (dev->chipid) {
+       case ID_REV_CHIP_ID_7800_:
+       case ID_REV_CHIP_ID_7850_:
                /* set to internal PHY id */
                dev->mdiobus->phy_mask = ~(1 << 1);
                break;
@@ -1590,6 +1656,7 @@ static void lan78xx_link_status_change(struct net_device *net)
 static int lan78xx_phy_init(struct lan78xx_net *dev)
 {
        int ret;
+       u32 mii_adv;
        struct phy_device *phydev = dev->net->phydev;
 
        phydev = phy_find_first(dev->mdiobus);
@@ -1622,14 +1689,17 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
 
        /* MAC doesn't support 1000T Half */
        phydev->supported &= ~SUPPORTED_1000baseT_Half;
-       phydev->supported |= (SUPPORTED_10baseT_Half |
-                             SUPPORTED_10baseT_Full |
-                             SUPPORTED_100baseT_Half |
-                             SUPPORTED_100baseT_Full |
-                             SUPPORTED_1000baseT_Full |
-                             SUPPORTED_Pause | SUPPORTED_Asym_Pause);
+
+       /* support both flow controls */
+       dev->fc_request_control = (FLOW_CTRL_RX | FLOW_CTRL_TX);
+       phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+       mii_adv = (u32)mii_advertise_flowctrl(dev->fc_request_control);
+       phydev->advertising |= mii_adv_to_ethtool_adv_t(mii_adv);
+
        genphy_config_aneg(phydev);
 
+       dev->fc_autoneg = phydev->autoneg;
+
        phy_start(phydev);
 
        netif_dbg(dev, ifup, dev->net, "phy initialised successfully");
@@ -1918,7 +1988,8 @@ static int lan78xx_reset(struct lan78xx_net *dev)
 
        /* save DEVID for later usage */
        ret = lan78xx_read_reg(dev, ID_REV, &buf);
-       dev->devid = buf;
+       dev->chipid = (buf & ID_REV_CHIP_ID_MASK_) >> 16;
+       dev->chiprev = buf & ID_REV_CHIP_REV_MASK_;
 
        /* Respond to the IN token with a NAK */
        ret = lan78xx_read_reg(dev, USB_CFG0, &buf);
index a93fb653e7c52f415bd0aae99f7cd2619c8cf47b..40927906109aa66de5e7be422d356d3ab371de20 100644 (file)
 #define ID_REV_CHIP_ID_MASK_           (0xFFFF0000)
 #define ID_REV_CHIP_REV_MASK_          (0x0000FFFF)
 #define ID_REV_CHIP_ID_7800_           (0x7800)
+#define ID_REV_CHIP_ID_7850_           (0x7850)
 
 #define FPGA_REV                       (0x04)
 #define FPGA_REV_MINOR_MASK_           (0x0000FF00)
index 23e9880791fcd3c05997e0af13d6806a75b0dffb..a3a4ccf7cf5272530ac8addf182c479feffd47fc 100644 (file)
@@ -637,6 +637,7 @@ static const struct usb_device_id products[] = {
 
        /* 3. Combined interface devices matching on interface number */
        {QMI_FIXED_INTF(0x0408, 0xea42, 4)},    /* Yota / Megafon M100-1 */
+       {QMI_FIXED_INTF(0x05c6, 0x6001, 3)},    /* 4G LTE usb-modem U901 */
        {QMI_FIXED_INTF(0x05c6, 0x7000, 0)},
        {QMI_FIXED_INTF(0x05c6, 0x7001, 1)},
        {QMI_FIXED_INTF(0x05c6, 0x7002, 1)},
@@ -860,8 +861,10 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x9056, 8)},    /* Sierra Wireless Modem */
        {QMI_FIXED_INTF(0x1199, 0x9057, 8)},
        {QMI_FIXED_INTF(0x1199, 0x9061, 8)},    /* Sierra Wireless Modem */
-       {QMI_FIXED_INTF(0x1199, 0x9071, 8)},    /* Sierra Wireless MC74xx/EM74xx */
-       {QMI_FIXED_INTF(0x1199, 0x9071, 10)},   /* Sierra Wireless MC74xx/EM74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9071, 8)},    /* Sierra Wireless MC74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9071, 10)},   /* Sierra Wireless MC74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9079, 8)},    /* Sierra Wireless EM74xx */
+       {QMI_FIXED_INTF(0x1199, 0x9079, 10)},   /* Sierra Wireless EM74xx */
        {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
        {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)},    /* Alcatel L800MA */
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
@@ -884,6 +887,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81a8, 8)},    /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81a9, 8)},    /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
        {QMI_FIXED_INTF(0x413c, 0x81b1, 8)},    /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x413c, 0x81b3, 8)},    /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
        {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
        {QMI_FIXED_INTF(0x22de, 0x9061, 3)},    /* WeTelecom WPD-600N */
        {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},    /* SIMCom 7230E */
index 0b0ba7ef14e4e9054adeb1251c29cddba08c5187..10798128c03fc64881c5a437df3510f016461b7c 100644 (file)
@@ -1769,6 +1769,13 @@ out3:
        if (info->unbind)
                info->unbind (dev, udev);
 out1:
+       /* subdrivers must undo all they did in bind() if they
+        * fail it, but we may fail later and a deferred kevent
+        * may trigger an error resubmitting itself and, worse,
+        * schedule a timer. So we kill it all just in case.
+        */
+       cancel_work_sync(&dev->kevent);
+       del_timer_sync(&dev->delay);
        free_netdev(net);
 out:
        return status;
index ba21d072be31c95827833f9e5014f20cfa43bb8b..4f30a6ae50d029f8ce0bb8105490b13489a5f090 100644 (file)
@@ -35,6 +35,7 @@ struct pcpu_vstats {
 struct veth_priv {
        struct net_device __rcu *peer;
        atomic64_t              dropped;
+       unsigned                requested_headroom;
 };
 
 /*
@@ -271,6 +272,29 @@ static int veth_get_iflink(const struct net_device *dev)
        return iflink;
 }
 
+static void veth_set_rx_headroom(struct net_device *dev, int new_hr)
+{
+       struct veth_priv *peer_priv, *priv = netdev_priv(dev);
+       struct net_device *peer;
+
+       if (new_hr < 0)
+               new_hr = 0;
+
+       rcu_read_lock();
+       peer = rcu_dereference(priv->peer);
+       if (unlikely(!peer))
+               goto out;
+
+       peer_priv = netdev_priv(peer);
+       priv->requested_headroom = new_hr;
+       new_hr = max(priv->requested_headroom, peer_priv->requested_headroom);
+       dev->needed_headroom = new_hr;
+       peer->needed_headroom = new_hr;
+
+out:
+       rcu_read_unlock();
+}
+
 static const struct net_device_ops veth_netdev_ops = {
        .ndo_init            = veth_dev_init,
        .ndo_open            = veth_open,
@@ -285,6 +309,7 @@ static const struct net_device_ops veth_netdev_ops = {
 #endif
        .ndo_get_iflink         = veth_get_iflink,
        .ndo_features_check     = passthru_features_check,
+       .ndo_set_rx_headroom    = veth_set_rx_headroom,
 };
 
 #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO |    \
@@ -301,6 +326,7 @@ static void veth_setup(struct net_device *dev)
        dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
        dev->priv_flags |= IFF_NO_QUEUE;
+       dev->priv_flags |= IFF_PHONY_HEADROOM;
 
        dev->netdev_ops = &veth_netdev_ops;
        dev->ethtool_ops = &veth_ethtool_ops;
index 221a53025fd023077adbc64f0e53a6246373032e..72ba8ae7f09a6a5a7a8b14303731997f966c9fea 100644 (file)
@@ -377,7 +377,7 @@ union Vmxnet3_GenericDesc {
 #define VMXNET3_TX_RING_MAX_SIZE   4096
 #define VMXNET3_TC_RING_MAX_SIZE   4096
 #define VMXNET3_RX_RING_MAX_SIZE   4096
-#define VMXNET3_RX_RING2_MAX_SIZE  2048
+#define VMXNET3_RX_RING2_MAX_SIZE  4096
 #define VMXNET3_RC_RING_MAX_SIZE   8192
 
 /* a list of reasons for queue stop */
index 0cbf520cea778fc703c9657ab2d085eee522634b..fc895d0e85d9cafced5d7e9d1166e8bc0de833bd 100644 (file)
@@ -814,7 +814,7 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
 
 
 /*
- *    parse and copy relevant protocol headers:
+ *    parse relevant protocol headers:
  *      For a tso pkt, relevant headers are L2/3/4 including options
  *      For a pkt requesting csum offloading, they are L2/3 and may include L4
  *      if it's a TCP/UDP pkt
@@ -827,15 +827,14 @@ vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
  * Other effects:
  *    1. related *ctx fields are updated.
  *    2. ctx->copy_size is # of bytes copied
- *    3. the portion copied is guaranteed to be in the linear part
+ *    3. the portion to be copied is guaranteed to be in the linear part
  *
  */
 static int
-vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
-                          struct vmxnet3_tx_ctx *ctx,
-                          struct vmxnet3_adapter *adapter)
+vmxnet3_parse_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+                 struct vmxnet3_tx_ctx *ctx,
+                 struct vmxnet3_adapter *adapter)
 {
-       struct Vmxnet3_TxDataDesc *tdd;
        u8 protocol = 0;
 
        if (ctx->mss) { /* TSO */
@@ -892,16 +891,34 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                return 0;
        }
 
+       return 1;
+err:
+       return -1;
+}
+
+/*
+ *    copy relevant protocol headers to the transmit ring:
+ *      For a tso pkt, relevant headers are L2/3/4 including options
+ *      For a pkt requesting csum offloading, they are L2/3 and may include L4
+ *      if it's a TCP/UDP pkt
+ *
+ *
+ *    Note that this requires that vmxnet3_parse_hdr be called first to set the
+ *      appropriate bits in ctx first
+ */
+static void
+vmxnet3_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+                struct vmxnet3_tx_ctx *ctx,
+                struct vmxnet3_adapter *adapter)
+{
+       struct Vmxnet3_TxDataDesc *tdd;
+
        tdd = tq->data_ring.base + tq->tx_ring.next2fill;
 
        memcpy(tdd->data, skb->data, ctx->copy_size);
        netdev_dbg(adapter->netdev,
                "copy %u bytes to dataRing[%u]\n",
                ctx->copy_size, tq->tx_ring.next2fill);
-       return 1;
-
-err:
-       return -1;
 }
 
 
@@ -998,22 +1015,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                }
        }
 
-       spin_lock_irqsave(&tq->tx_lock, flags);
-
-       if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
-               tq->stats.tx_ring_full++;
-               netdev_dbg(adapter->netdev,
-                       "tx queue stopped on %s, next2comp %u"
-                       " next2fill %u\n", adapter->netdev->name,
-                       tq->tx_ring.next2comp, tq->tx_ring.next2fill);
-
-               vmxnet3_tq_stop(tq, adapter);
-               spin_unlock_irqrestore(&tq->tx_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-
-
-       ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter);
+       ret = vmxnet3_parse_hdr(skb, tq, &ctx, adapter);
        if (ret >= 0) {
                BUG_ON(ret <= 0 && ctx.copy_size != 0);
                /* hdrs parsed, check against other limits */
@@ -1033,9 +1035,26 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                }
        } else {
                tq->stats.drop_hdr_inspect_err++;
-               goto unlock_drop_pkt;
+               goto drop_pkt;
        }
 
+       spin_lock_irqsave(&tq->tx_lock, flags);
+
+       if (count > vmxnet3_cmd_ring_desc_avail(&tq->tx_ring)) {
+               tq->stats.tx_ring_full++;
+               netdev_dbg(adapter->netdev,
+                       "tx queue stopped on %s, next2comp %u"
+                       " next2fill %u\n", adapter->netdev->name,
+                       tq->tx_ring.next2comp, tq->tx_ring.next2fill);
+
+               vmxnet3_tq_stop(tq, adapter);
+               spin_unlock_irqrestore(&tq->tx_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+
+       vmxnet3_copy_hdr(skb, tq, &ctx, adapter);
+
        /* fill tx descs related to addr & len */
        if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))
                goto unlock_drop_pkt;
index bdb8a6c0f8aa2c62e22edc64d3900530477b6fa8..729c344e677499b6f737aa622d6925c07d647a17 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.4.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.4.6.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01040500
+#define VMXNET3_DRIVER_VERSION_NUM      0x01040600
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
index 9ce088bb28ab9b6206737984dbe21e7093b28709..9a9fabb900c19e5f7dc483a63f1b71fcd1a96e5a 100644 (file)
@@ -103,20 +103,23 @@ static struct dst_ops vrf_dst_ops = {
 #if IS_ENABLED(CONFIG_IPV6)
 static bool check_ipv6_frame(const struct sk_buff *skb)
 {
-       const struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb->data;
-       size_t hlen = sizeof(*ipv6h);
+       const struct ipv6hdr *ipv6h;
+       struct ipv6hdr _ipv6h;
        bool rc = true;
 
-       if (skb->len < hlen)
+       ipv6h = skb_header_pointer(skb, 0, sizeof(_ipv6h), &_ipv6h);
+       if (!ipv6h)
                goto out;
 
        if (ipv6h->nexthdr == NEXTHDR_ICMP) {
                const struct icmp6hdr *icmph;
+               struct icmp6hdr _icmph;
 
-               if (skb->len < hlen + sizeof(*icmph))
+               icmph = skb_header_pointer(skb, sizeof(_ipv6h),
+                                          sizeof(_icmph), &_icmph);
+               if (!icmph)
                        goto out;
 
-               icmph = (struct icmp6hdr *)(skb->data + sizeof(*ipv6h));
                switch (icmph->icmp6_type) {
                case NDISC_ROUTER_SOLICITATION:
                case NDISC_ROUTER_ADVERTISEMENT:
index 0a23c64379d6ab405e840055c7d1d4bcb6d4a2e1..800106a7246cb165d46b4e25316cbfbc41996cef 100644 (file)
@@ -197,9 +197,9 @@ static int vxlan_nla_put_addr(struct sk_buff *skb, int attr,
 #endif
 
 /* Virtual Network hash table head */
-static inline struct hlist_head *vni_head(struct vxlan_sock *vs, u32 id)
+static inline struct hlist_head *vni_head(struct vxlan_sock *vs, __be32 vni)
 {
-       return &vs->vni_list[hash_32(id, VNI_HASH_BITS)];
+       return &vs->vni_list[hash_32((__force u32)vni, VNI_HASH_BITS)];
 }
 
 /* Socket hash table head */
@@ -242,12 +242,16 @@ static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
        return NULL;
 }
 
-static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)
+static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, __be32 vni)
 {
        struct vxlan_dev *vxlan;
 
-       hlist_for_each_entry_rcu(vxlan, vni_head(vs, id), hlist) {
-               if (vxlan->default_dst.remote_vni == id)
+       /* For flow based devices, map all packets to VNI 0 */
+       if (vs->flags & VXLAN_F_COLLECT_METADATA)
+               vni = 0;
+
+       hlist_for_each_entry_rcu(vxlan, vni_head(vs, vni), hlist) {
+               if (vxlan->default_dst.remote_vni == vni)
                        return vxlan;
        }
 
@@ -255,7 +259,7 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)
 }
 
 /* Look up VNI in a per net namespace table */
-static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id,
+static struct vxlan_dev *vxlan_find_vni(struct net *net, __be32 vni,
                                        sa_family_t family, __be16 port,
                                        u32 flags)
 {
@@ -265,7 +269,7 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id,
        if (!vs)
                return NULL;
 
-       return vxlan_vs_find_vni(vs, id);
+       return vxlan_vs_find_vni(vs, vni);
 }
 
 /* Fill in neighbour message in skbuff. */
@@ -315,7 +319,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
            nla_put_be16(skb, NDA_PORT, rdst->remote_port))
                goto nla_put_failure;
        if (rdst->remote_vni != vxlan->default_dst.remote_vni &&
-           nla_put_u32(skb, NDA_VNI, rdst->remote_vni))
+           nla_put_u32(skb, NDA_VNI, be32_to_cpu(rdst->remote_vni)))
                goto nla_put_failure;
        if (rdst->remote_ifindex &&
            nla_put_u32(skb, NDA_IFINDEX, rdst->remote_ifindex))
@@ -383,7 +387,7 @@ static void vxlan_ip_miss(struct net_device *dev, union vxlan_addr *ipa)
        };
        struct vxlan_rdst remote = {
                .remote_ip = *ipa, /* goes to NDA_DST */
-               .remote_vni = VXLAN_N_VID,
+               .remote_vni = cpu_to_be32(VXLAN_N_VID),
        };
 
        vxlan_fdb_notify(vxlan, &f, &remote, RTM_GETNEIGH);
@@ -452,7 +456,7 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
 /* caller should hold vxlan->hash_lock */
 static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
                                              union vxlan_addr *ip, __be16 port,
-                                             __u32 vni, __u32 ifindex)
+                                             __be32 vni, __u32 ifindex)
 {
        struct vxlan_rdst *rd;
 
@@ -469,7 +473,8 @@ static struct vxlan_rdst *vxlan_fdb_find_rdst(struct vxlan_fdb *f,
 
 /* Replace destination of unicast mac */
 static int vxlan_fdb_replace(struct vxlan_fdb *f,
-                            union vxlan_addr *ip, __be16 port, __u32 vni, __u32 ifindex)
+                            union vxlan_addr *ip, __be16 port, __be32 vni,
+                            __u32 ifindex)
 {
        struct vxlan_rdst *rd;
 
@@ -480,6 +485,8 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
        rd = list_first_entry_or_null(&f->remotes, struct vxlan_rdst, list);
        if (!rd)
                return 0;
+
+       dst_cache_reset(&rd->dst_cache);
        rd->remote_ip = *ip;
        rd->remote_port = port;
        rd->remote_vni = vni;
@@ -489,7 +496,7 @@ static int vxlan_fdb_replace(struct vxlan_fdb *f,
 
 /* Add/update destinations for multicast */
 static int vxlan_fdb_append(struct vxlan_fdb *f,
-                           union vxlan_addr *ip, __be16 port, __u32 vni,
+                           union vxlan_addr *ip, __be16 port, __be32 vni,
                            __u32 ifindex, struct vxlan_rdst **rdp)
 {
        struct vxlan_rdst *rd;
@@ -501,6 +508,12 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
        rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
        if (rd == NULL)
                return -ENOBUFS;
+
+       if (dst_cache_init(&rd->dst_cache, GFP_ATOMIC)) {
+               kfree(rd);
+               return -ENOBUFS;
+       }
+
        rd->remote_ip = *ip;
        rd->remote_port = port;
        rd->remote_vni = vni;
@@ -515,7 +528,8 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
 static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
                                          unsigned int off,
                                          struct vxlanhdr *vh, size_t hdrlen,
-                                         u32 data, struct gro_remcsum *grc,
+                                         __be32 vni_field,
+                                         struct gro_remcsum *grc,
                                          bool nopartial)
 {
        size_t start, offset;
@@ -526,10 +540,8 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
        if (!NAPI_GRO_CB(skb)->csum_valid)
                return NULL;
 
-       start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
-       offset = start + ((data & VXLAN_RCO_UDP) ?
-                         offsetof(struct udphdr, check) :
-                         offsetof(struct tcphdr, check));
+       start = vxlan_rco_start(vni_field);
+       offset = start + vxlan_rco_offset(vni_field);
 
        vh = skb_gro_remcsum_process(skb, (void *)vh, off, hdrlen,
                                     start, offset, grc, nopartial);
@@ -549,7 +561,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
        int flush = 1;
        struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock,
                                             udp_offloads);
-       u32 flags;
+       __be32 flags;
        struct gro_remcsum grc;
 
        skb_gro_remcsum_init(&grc);
@@ -565,11 +577,11 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
 
        skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
 
-       flags = ntohl(vh->vx_flags);
+       flags = vh->vx_flags;
 
        if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
                vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
-                                      ntohl(vh->vx_vni), &grc,
+                                      vh->vx_vni, &grc,
                                       !!(vs->flags &
                                          VXLAN_F_REMCSUM_NOPARTIAL));
 
@@ -579,8 +591,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
 
        skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
 
-       flush = 0;
-
        for (p = *head; p; p = p->next) {
                if (!NAPI_GRO_CB(p)->same_flow)
                        continue;
@@ -594,6 +604,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
        }
 
        pp = eth_gro_receive(head, skb);
+       flush = 0;
 
 out:
        skb_gro_remcsum_cleanup(skb, &grc);
@@ -660,7 +671,7 @@ static void vxlan_notify_del_rx_port(struct vxlan_sock *vs)
 static int vxlan_fdb_create(struct vxlan_dev *vxlan,
                            const u8 *mac, union vxlan_addr *ip,
                            __u16 state, __u16 flags,
-                           __be16 port, __u32 vni, __u32 ifindex,
+                           __be16 port, __be32 vni, __u32 ifindex,
                            __u8 ndm_flags)
 {
        struct vxlan_rdst *rd = NULL;
@@ -749,8 +760,10 @@ static void vxlan_fdb_free(struct rcu_head *head)
        struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
        struct vxlan_rdst *rd, *nd;
 
-       list_for_each_entry_safe(rd, nd, &f->remotes, list)
+       list_for_each_entry_safe(rd, nd, &f->remotes, list) {
+               dst_cache_destroy(&rd->dst_cache);
                kfree(rd);
+       }
        kfree(f);
 }
 
@@ -767,7 +780,8 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
 }
 
 static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
-                          union vxlan_addr *ip, __be16 *port, u32 *vni, u32 *ifindex)
+                          union vxlan_addr *ip, __be16 *port, __be32 *vni,
+                          u32 *ifindex)
 {
        struct net *net = dev_net(vxlan->dev);
        int err;
@@ -800,7 +814,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
        if (tb[NDA_VNI]) {
                if (nla_len(tb[NDA_VNI]) != sizeof(u32))
                        return -EINVAL;
-               *vni = nla_get_u32(tb[NDA_VNI]);
+               *vni = cpu_to_be32(nla_get_u32(tb[NDA_VNI]));
        } else {
                *vni = vxlan->default_dst.remote_vni;
        }
@@ -830,7 +844,8 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        /* struct net *net = dev_net(vxlan->dev); */
        union vxlan_addr ip;
        __be16 port;
-       u32 vni, ifindex;
+       __be32 vni;
+       u32 ifindex;
        int err;
 
        if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_REACHABLE))) {
@@ -867,7 +882,8 @@ static int vxlan_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
        struct vxlan_rdst *rd = NULL;
        union vxlan_addr ip;
        __be16 port;
-       u32 vni, ifindex;
+       __be32 vni;
+       u32 ifindex;
        int err;
 
        err = vxlan_fdb_parse(tb, vxlan, &ip, &port, &vni, &ifindex);
@@ -931,8 +947,10 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
                                                     cb->nlh->nlmsg_seq,
                                                     RTM_NEWNEIGH,
                                                     NLM_F_MULTI, rd);
-                               if (err < 0)
+                               if (err < 0) {
+                                       cb->args[1] = err;
                                        goto out;
+                               }
 skip:
                                ++idx;
                        }
@@ -1122,177 +1140,168 @@ static int vxlan_igmp_leave(struct vxlan_dev *vxlan)
        return ret;
 }
 
-static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
-                                     size_t hdrlen, u32 data, bool nopartial)
+static bool vxlan_remcsum(struct vxlanhdr *unparsed,
+                         struct sk_buff *skb, u32 vxflags)
 {
        size_t start, offset, plen;
 
-       if (skb->remcsum_offload)
-               return vh;
+       if (!(unparsed->vx_flags & VXLAN_HF_RCO) || skb->remcsum_offload)
+               goto out;
 
-       start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
-       offset = start + ((data & VXLAN_RCO_UDP) ?
-                         offsetof(struct udphdr, check) :
-                         offsetof(struct tcphdr, check));
+       start = vxlan_rco_start(unparsed->vx_vni);
+       offset = start + vxlan_rco_offset(unparsed->vx_vni);
 
-       plen = hdrlen + offset + sizeof(u16);
+       plen = sizeof(struct vxlanhdr) + offset + sizeof(u16);
 
        if (!pskb_may_pull(skb, plen))
-               return NULL;
+               return false;
+
+       skb_remcsum_process(skb, (void *)(vxlan_hdr(skb) + 1), start, offset,
+                           !!(vxflags & VXLAN_F_REMCSUM_NOPARTIAL));
+out:
+       unparsed->vx_flags &= ~VXLAN_HF_RCO;
+       unparsed->vx_vni &= VXLAN_VNI_MASK;
+       return true;
+}
+
+static void vxlan_parse_gbp_hdr(struct vxlanhdr *unparsed,
+                               struct sk_buff *skb, u32 vxflags,
+                               struct vxlan_metadata *md)
+{
+       struct vxlanhdr_gbp *gbp = (struct vxlanhdr_gbp *)unparsed;
+       struct metadata_dst *tun_dst;
 
-       vh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
+       if (!(unparsed->vx_flags & VXLAN_HF_GBP))
+               goto out;
 
-       skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset,
-                           nopartial);
+       md->gbp = ntohs(gbp->policy_id);
 
-       return vh;
+       tun_dst = (struct metadata_dst *)skb_dst(skb);
+       if (tun_dst) {
+               tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
+               tun_dst->u.tun_info.options_len = sizeof(*md);
+       }
+       if (gbp->dont_learn)
+               md->gbp |= VXLAN_GBP_DONT_LEARN;
+
+       if (gbp->policy_applied)
+               md->gbp |= VXLAN_GBP_POLICY_APPLIED;
+
+       /* In flow-based mode, GBP is carried in dst_metadata */
+       if (!(vxflags & VXLAN_F_COLLECT_METADATA))
+               skb->mark = md->gbp;
+out:
+       unparsed->vx_flags &= ~VXLAN_GBP_USED_BITS;
 }
 
-static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
-                     struct vxlan_metadata *md, u32 vni,
-                     struct metadata_dst *tun_dst)
+static bool vxlan_set_mac(struct vxlan_dev *vxlan,
+                         struct vxlan_sock *vs,
+                         struct sk_buff *skb)
 {
-       struct iphdr *oip = NULL;
-       struct ipv6hdr *oip6 = NULL;
-       struct vxlan_dev *vxlan;
-       struct pcpu_sw_netstats *stats;
        union vxlan_addr saddr;
-       int err = 0;
-
-       /* For flow based devices, map all packets to VNI 0 */
-       if (vs->flags & VXLAN_F_COLLECT_METADATA)
-               vni = 0;
-
-       /* Is this VNI defined? */
-       vxlan = vxlan_vs_find_vni(vs, vni);
-       if (!vxlan)
-               goto drop;
 
        skb_reset_mac_header(skb);
-       skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev)));
        skb->protocol = eth_type_trans(skb, vxlan->dev);
        skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
        /* Ignore packet loops (and multicast echo) */
        if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr))
-               goto drop;
+               return false;
 
-       /* Get data from the outer IP header */
+       /* Get address from the outer IP header */
        if (vxlan_get_sk_family(vs) == AF_INET) {
-               oip = ip_hdr(skb);
-               saddr.sin.sin_addr.s_addr = oip->saddr;
+               saddr.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
                saddr.sa.sa_family = AF_INET;
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
-               oip6 = ipv6_hdr(skb);
-               saddr.sin6.sin6_addr = oip6->saddr;
+               saddr.sin6.sin6_addr = ipv6_hdr(skb)->saddr;
                saddr.sa.sa_family = AF_INET6;
 #endif
        }
 
-       if (tun_dst) {
-               skb_dst_set(skb, (struct dst_entry *)tun_dst);
-               tun_dst = NULL;
-       }
-
        if ((vxlan->flags & VXLAN_F_LEARN) &&
            vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source))
-               goto drop;
-
-       skb_reset_network_header(skb);
-       /* In flow-based mode, GBP is carried in dst_metadata */
-       if (!(vs->flags & VXLAN_F_COLLECT_METADATA))
-               skb->mark = md->gbp;
-
-       if (oip6)
-               err = IP6_ECN_decapsulate(oip6, skb);
-       if (oip)
-               err = IP_ECN_decapsulate(oip, skb);
-
-       if (unlikely(err)) {
-               if (log_ecn_error) {
-                       if (oip6)
-                               net_info_ratelimited("non-ECT from %pI6\n",
-                                                    &oip6->saddr);
-                       if (oip)
-                               net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
-                                                    &oip->saddr, oip->tos);
-               }
-               if (err > 1) {
-                       ++vxlan->dev->stats.rx_frame_errors;
-                       ++vxlan->dev->stats.rx_errors;
-                       goto drop;
-               }
-       }
+               return false;
 
-       stats = this_cpu_ptr(vxlan->dev->tstats);
-       u64_stats_update_begin(&stats->syncp);
-       stats->rx_packets++;
-       stats->rx_bytes += skb->len;
-       u64_stats_update_end(&stats->syncp);
+       return true;
+}
 
-       gro_cells_receive(&vxlan->gro_cells, skb);
+static bool vxlan_ecn_decapsulate(struct vxlan_sock *vs, void *oiph,
+                                 struct sk_buff *skb)
+{
+       int err = 0;
 
-       return;
-drop:
-       if (tun_dst)
-               dst_release((struct dst_entry *)tun_dst);
+       if (vxlan_get_sk_family(vs) == AF_INET)
+               err = IP_ECN_decapsulate(oiph, skb);
+#if IS_ENABLED(CONFIG_IPV6)
+       else
+               err = IP6_ECN_decapsulate(oiph, skb);
+#endif
 
-       /* Consume bad packet */
-       kfree_skb(skb);
+       if (unlikely(err) && log_ecn_error) {
+               if (vxlan_get_sk_family(vs) == AF_INET)
+                       net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
+                                            &((struct iphdr *)oiph)->saddr,
+                                            ((struct iphdr *)oiph)->tos);
+               else
+                       net_info_ratelimited("non-ECT from %pI6\n",
+                                            &((struct ipv6hdr *)oiph)->saddr);
+       }
+       return err <= 1;
 }
 
 /* Callback from net/ipv4/udp.c to receive packets */
-static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
+static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 {
-       struct metadata_dst *tun_dst = NULL;
+       struct pcpu_sw_netstats *stats;
+       struct vxlan_dev *vxlan;
        struct vxlan_sock *vs;
-       struct vxlanhdr *vxh;
-       u32 flags, vni;
+       struct vxlanhdr unparsed;
        struct vxlan_metadata _md;
        struct vxlan_metadata *md = &_md;
+       void *oiph;
 
        /* Need Vxlan and inner Ethernet header to be present */
        if (!pskb_may_pull(skb, VXLAN_HLEN))
-               goto error;
+               return 1;
 
-       vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
-       flags = ntohl(vxh->vx_flags);
-       vni = ntohl(vxh->vx_vni);
-
-       if (flags & VXLAN_HF_VNI) {
-               flags &= ~VXLAN_HF_VNI;
-       } else {
-               /* VNI flag always required to be set */
-               goto bad_flags;
+       unparsed = *vxlan_hdr(skb);
+       /* VNI flag always required to be set */
+       if (!(unparsed.vx_flags & VXLAN_HF_VNI)) {
+               netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
+                          ntohl(vxlan_hdr(skb)->vx_flags),
+                          ntohl(vxlan_hdr(skb)->vx_vni));
+               /* Return non vxlan pkt */
+               return 1;
        }
-
-       if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
-               goto drop;
-       vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
+       unparsed.vx_flags &= ~VXLAN_HF_VNI;
+       unparsed.vx_vni &= ~VXLAN_VNI_MASK;
 
        vs = rcu_dereference_sk_user_data(sk);
        if (!vs)
                goto drop;
 
-       if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
-               vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni,
-                                   !!(vs->flags & VXLAN_F_REMCSUM_NOPARTIAL));
-               if (!vxh)
-                       goto drop;
+       vxlan = vxlan_vs_find_vni(vs, vxlan_vni(vxlan_hdr(skb)->vx_vni));
+       if (!vxlan)
+               goto drop;
 
-               flags &= ~VXLAN_HF_RCO;
-               vni &= VXLAN_VNI_MASK;
-       }
+       if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB),
+                                !net_eq(vxlan->net, dev_net(vxlan->dev))))
+               goto drop;
 
        if (vxlan_collect_metadata(vs)) {
+               __be32 vni = vxlan_vni(vxlan_hdr(skb)->vx_vni);
+               struct metadata_dst *tun_dst;
+
                tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), TUNNEL_KEY,
-                                        cpu_to_be64(vni >> 8), sizeof(*md));
+                                        vxlan_vni_to_tun_id(vni), sizeof(*md));
 
                if (!tun_dst)
                        goto drop;
 
                md = ip_tunnel_info_opts(&tun_dst->u.tun_info);
+
+               skb_dst_set(skb, (struct dst_entry *)tun_dst);
        } else {
                memset(md, 0, sizeof(*md));
        }
@@ -1300,25 +1309,13 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        /* For backwards compatibility, only allow reserved fields to be
         * used by VXLAN extensions if explicitly requested.
         */
-       if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
-               struct vxlanhdr_gbp *gbp;
-
-               gbp = (struct vxlanhdr_gbp *)vxh;
-               md->gbp = ntohs(gbp->policy_id);
-
-               if (tun_dst)
-                       tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT;
-
-               if (gbp->dont_learn)
-                       md->gbp |= VXLAN_GBP_DONT_LEARN;
-
-               if (gbp->policy_applied)
-                       md->gbp |= VXLAN_GBP_POLICY_APPLIED;
-
-               flags &= ~VXLAN_GBP_USED_BITS;
-       }
+       if (vs->flags & VXLAN_F_REMCSUM_RX)
+               if (!vxlan_remcsum(&unparsed, skb, vs->flags))
+                       goto drop;
+       if (vs->flags & VXLAN_F_GBP)
+               vxlan_parse_gbp_hdr(&unparsed, skb, vs->flags, md);
 
-       if (flags || vni & ~VXLAN_VNI_MASK) {
+       if (unparsed.vx_flags || unparsed.vx_vni) {
                /* If there are any unprocessed flags remaining treat
                 * this as a malformed packet. This behavior diverges from
                 * VXLAN RFC (RFC7348) which stipulates that bits in reserved
@@ -1327,28 +1324,34 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                 * is more robust and provides a little more security in
                 * adding extensions to VXLAN.
                 */
+               goto drop;
+       }
+
+       if (!vxlan_set_mac(vxlan, vs, skb))
+               goto drop;
+
+       oiph = skb_network_header(skb);
+       skb_reset_network_header(skb);
 
-               goto bad_flags;
+       if (!vxlan_ecn_decapsulate(vs, oiph, skb)) {
+               ++vxlan->dev->stats.rx_frame_errors;
+               ++vxlan->dev->stats.rx_errors;
+               goto drop;
        }
 
-       vxlan_rcv(vs, skb, md, vni >> 8, tun_dst);
+       stats = this_cpu_ptr(vxlan->dev->tstats);
+       u64_stats_update_begin(&stats->syncp);
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+       u64_stats_update_end(&stats->syncp);
+
+       gro_cells_receive(&vxlan->gro_cells, skb);
        return 0;
 
 drop:
        /* Consume bad packet */
        kfree_skb(skb);
        return 0;
-
-bad_flags:
-       netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
-                  ntohl(vxh->vx_flags), ntohl(vxh->vx_vni));
-
-error:
-       if (tun_dst)
-               dst_release((struct dst_entry *)tun_dst);
-
-       /* Return non vxlan pkt */
-       return 1;
 }
 
 static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
@@ -1459,7 +1462,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
        reply->dev = dev;
        skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
        skb_push(reply, sizeof(struct ethhdr));
-       skb_set_mac_header(reply, 0);
+       skb_reset_mac_header(reply);
 
        ns = (struct nd_msg *)skb_transport_header(request);
 
@@ -1479,7 +1482,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
        reply->protocol = htons(ETH_P_IPV6);
 
        skb_pull(reply, sizeof(struct ethhdr));
-       skb_set_network_header(reply, 0);
+       skb_reset_network_header(reply);
        skb_put(reply, sizeof(struct ipv6hdr));
 
        /* IPv6 header */
@@ -1494,7 +1497,7 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request,
        pip6->saddr = *(struct in6_addr *)n->primary_key;
 
        skb_pull(reply, sizeof(struct ipv6hdr));
-       skb_set_transport_header(reply, 0);
+       skb_reset_transport_header(reply);
 
        na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
 
@@ -1673,7 +1676,7 @@ static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
                return;
 
        gbp = (struct vxlanhdr_gbp *)vxh;
-       vxh->vx_flags |= htonl(VXLAN_HF_GBP);
+       vxh->vx_flags |= VXLAN_HF_GBP;
 
        if (md->gbp & VXLAN_GBP_DONT_LEARN)
                gbp->dont_learn = 1;
@@ -1693,7 +1696,6 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
        int min_headroom;
        int err;
        int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
-       u16 hdrlen = sizeof(struct vxlanhdr);
 
        if ((vxflags & VXLAN_F_REMCSUM_TX) &&
            skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -1726,18 +1728,15 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
                return PTR_ERR(skb);
 
        vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
-       vxh->vx_flags = htonl(VXLAN_HF_VNI);
-       vxh->vx_vni = vni;
+       vxh->vx_flags = VXLAN_HF_VNI;
+       vxh->vx_vni = vxlan_vni_field(vni);
 
        if (type & SKB_GSO_TUNNEL_REMCSUM) {
-               u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
-                          VXLAN_RCO_SHIFT;
+               unsigned int start;
 
-               if (skb->csum_offset == offsetof(struct udphdr, check))
-                       data |= VXLAN_RCO_UDP;
-
-               vxh->vx_vni |= htonl(data);
-               vxh->vx_flags |= htonl(VXLAN_HF_RCO);
+               start = skb_checksum_start_offset(skb) - sizeof(struct vxlanhdr);
+               vxh->vx_vni |= vxlan_compute_rco(start, skb->csum_offset);
+               vxh->vx_flags |= VXLAN_HF_RCO;
 
                if (!skb_is_gso(skb)) {
                        skb->ip_summed = CHECKSUM_NONE;
@@ -1754,11 +1753,22 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst,
 
 static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
                                      struct sk_buff *skb, int oif, u8 tos,
-                                     __be32 daddr, __be32 *saddr)
+                                     __be32 daddr, __be32 *saddr,
+                                     struct dst_cache *dst_cache,
+                                     const struct ip_tunnel_info *info)
 {
+       bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct rtable *rt = NULL;
        struct flowi4 fl4;
 
+       if (tos && !info)
+               use_cache = false;
+       if (use_cache) {
+               rt = dst_cache_get_ip4(dst_cache, saddr);
+               if (rt)
+                       return rt;
+       }
+
        memset(&fl4, 0, sizeof(fl4));
        fl4.flowi4_oif = oif;
        fl4.flowi4_tos = RT_TOS(tos);
@@ -1768,25 +1778,42 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan,
        fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr;
 
        rt = ip_route_output_key(vxlan->net, &fl4);
-       if (!IS_ERR(rt))
+       if (!IS_ERR(rt)) {
                *saddr = fl4.saddr;
+               if (use_cache)
+                       dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
+       }
        return rt;
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
 static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
-                                         struct sk_buff *skb, int oif,
+                                         struct sk_buff *skb, int oif, u8 tos,
+                                         __be32 label,
                                          const struct in6_addr *daddr,
-                                         struct in6_addr *saddr)
+                                         struct in6_addr *saddr,
+                                         struct dst_cache *dst_cache,
+                                         const struct ip_tunnel_info *info)
 {
+       bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
        struct dst_entry *ndst;
        struct flowi6 fl6;
        int err;
 
+       if (tos && !info)
+               use_cache = false;
+       if (use_cache) {
+               ndst = dst_cache_get_ip6(dst_cache, saddr);
+               if (ndst)
+                       return ndst;
+       }
+
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_oif = oif;
+       fl6.flowi6_tos = RT_TOS(tos);
        fl6.daddr = *daddr;
        fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr;
+       fl6.flowlabel = label;
        fl6.flowi6_mark = skb->mark;
        fl6.flowi6_proto = IPPROTO_UDP;
 
@@ -1797,6 +1824,8 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
                return ERR_PTR(err);
 
        *saddr = fl6.saddr;
+       if (use_cache)
+               dst_cache_set_ip6(dst_cache, ndst, saddr);
        return ndst;
 }
 #endif
@@ -1849,6 +1878,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
 static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                           struct vxlan_rdst *rdst, bool did_rsc)
 {
+       struct dst_cache *dst_cache;
        struct ip_tunnel_info *info;
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct sock *sk;
@@ -1859,7 +1889,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        struct vxlan_metadata _md;
        struct vxlan_metadata *md = &_md;
        __be16 src_port = 0, dst_port;
-       u32 vni;
+       __be32 vni, label;
        __be16 df = 0;
        __u8 tos, ttl;
        int err;
@@ -1873,6 +1903,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port;
                vni = rdst->remote_vni;
                dst = &rdst->remote_ip;
+               dst_cache = &rdst->dst_cache;
        } else {
                if (!info) {
                        WARN_ONCE(1, "%s: Missing encapsulation instructions\n",
@@ -1880,13 +1911,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                        goto drop;
                }
                dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port;
-               vni = be64_to_cpu(info->key.tun_id);
+               vni = vxlan_tun_id_to_vni(info->key.tun_id);
                remote_ip.sa.sa_family = ip_tunnel_info_af(info);
                if (remote_ip.sa.sa_family == AF_INET)
                        remote_ip.sin.sin_addr.s_addr = info->key.u.ipv4.dst;
                else
                        remote_ip.sin6.sin6_addr = info->key.u.ipv6.dst;
                dst = &remote_ip;
+               dst_cache = &info->dst_cache;
        }
 
        if (vxlan_addr_any(dst)) {
@@ -1908,12 +1940,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
        if (tos == 1)
                tos = ip_tunnel_get_dsfield(old_iph, skb);
 
+       label = vxlan->cfg.label;
        src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
                                     vxlan->cfg.port_max, true);
 
        if (info) {
                ttl = info->key.ttl;
                tos = info->key.tos;
+               label = info->key.label;
                udp_sum = !!(info->key.tun_flags & TUNNEL_CSUM);
 
                if (info->options_len)
@@ -1929,16 +1963,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                        goto drop;
                sk = vxlan->vn4_sock->sock->sk;
 
-               if (info) {
-                       if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
-                               df = htons(IP_DF);
-               } else {
-                       udp_sum = !!(flags & VXLAN_F_UDP_CSUM);
-               }
-
                rt = vxlan_get_route(vxlan, skb,
                                     rdst ? rdst->remote_ifindex : 0, tos,
-                                    dst->sin.sin_addr.s_addr, &saddr);
+                                    dst->sin.sin_addr.s_addr, &saddr,
+                                    dst_cache, info);
                if (IS_ERR(rt)) {
                        netdev_dbg(dev, "no route to %pI4\n",
                                   &dst->sin.sin_addr.s_addr);
@@ -1968,10 +1996,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                        return;
                }
 
+               if (!info)
+                       udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM_TX);
+               else if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)
+                       df = htons(IP_DF);
+
                tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
                ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
                err = vxlan_build_skb(skb, &rt->dst, sizeof(struct iphdr),
-                                     htonl(vni << 8), md, flags, udp_sum);
+                                     vni, md, flags, udp_sum);
                if (err < 0)
                        goto xmit_tx_error;
 
@@ -1989,8 +2022,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                sk = vxlan->vn6_sock->sock->sk;
 
                ndst = vxlan6_get_route(vxlan, skb,
-                                       rdst ? rdst->remote_ifindex : 0,
-                                       &dst->sin6.sin6_addr, &saddr);
+                                       rdst ? rdst->remote_ifindex : 0, tos,
+                                       label, &dst->sin6.sin6_addr, &saddr,
+                                       dst_cache, info);
                if (IS_ERR(ndst)) {
                        netdev_dbg(dev, "no route to %pI6\n",
                                   &dst->sin6.sin6_addr);
@@ -2025,17 +2059,18 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                if (!info)
                        udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
 
+               tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
                ttl = ttl ? : ip6_dst_hoplimit(ndst);
                skb_scrub_packet(skb, xnet);
                err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr),
-                                     htonl(vni << 8), md, flags, udp_sum);
+                                     vni, md, flags, udp_sum);
                if (err < 0) {
                        dst_release(ndst);
                        return;
                }
                udp_tunnel6_xmit_skb(ndst, sk, skb, dev,
-                                    &saddr, &dst->sin6.sin6_addr,
-                                    0, ttl, src_port, dst_port, !udp_sum);
+                                    &saddr, &dst->sin6.sin6_addr, tos, ttl,
+                                    label, src_port, dst_port, !udp_sum);
 #endif
        }
 
@@ -2095,9 +2130,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
        }
 
-       if (vxlan->flags & VXLAN_F_COLLECT_METADATA &&
-           info && info->mode & IP_TUNNEL_INFO_TX) {
-               vxlan_xmit_one(skb, dev, NULL, false);
+       if (vxlan->flags & VXLAN_F_COLLECT_METADATA) {
+               if (info && info->mode & IP_TUNNEL_INFO_TX)
+                       vxlan_xmit_one(skb, dev, NULL, false);
+               else
+                       kfree_skb(skb);
                return NETDEV_TX_OK;
        }
 
@@ -2185,7 +2222,7 @@ static void vxlan_cleanup(unsigned long arg)
 static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
 {
        struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
-       __u32 vni = vxlan->default_dst.remote_vni;
+       __be32 vni = vxlan->default_dst.remote_vni;
 
        spin_lock(&vn->sock_lock);
        hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni));
@@ -2291,29 +2328,43 @@ static void vxlan_set_multicast_list(struct net_device *dev)
 {
 }
 
-static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
+static int __vxlan_change_mtu(struct net_device *dev,
+                             struct net_device *lowerdev,
+                             struct vxlan_rdst *dst, int new_mtu, bool strict)
 {
-       struct vxlan_dev *vxlan = netdev_priv(dev);
-       struct vxlan_rdst *dst = &vxlan->default_dst;
-       struct net_device *lowerdev;
-       int max_mtu;
+       int max_mtu = IP_MAX_MTU;
 
-       lowerdev = __dev_get_by_index(vxlan->net, dst->remote_ifindex);
-       if (lowerdev == NULL)
-               return eth_change_mtu(dev, new_mtu);
+       if (lowerdev)
+               max_mtu = lowerdev->mtu;
 
        if (dst->remote_ip.sa.sa_family == AF_INET6)
-               max_mtu = lowerdev->mtu - VXLAN6_HEADROOM;
+               max_mtu -= VXLAN6_HEADROOM;
        else
-               max_mtu = lowerdev->mtu - VXLAN_HEADROOM;
+               max_mtu -= VXLAN_HEADROOM;
 
-       if (new_mtu < 68 || new_mtu > max_mtu)
+       if (new_mtu < 68)
                return -EINVAL;
 
+       if (new_mtu > max_mtu) {
+               if (strict)
+                       return -EINVAL;
+
+               new_mtu = max_mtu;
+       }
+
        dev->mtu = new_mtu;
        return 0;
 }
 
+static int vxlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct vxlan_dev *vxlan = netdev_priv(dev);
+       struct vxlan_rdst *dst = &vxlan->default_dst;
+       struct net_device *lowerdev = __dev_get_by_index(vxlan->net,
+                                                        dst->remote_ifindex);
+       return __vxlan_change_mtu(dev, lowerdev, dst, new_mtu, true);
+}
+
 static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
@@ -2331,7 +2382,7 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
                        return -EINVAL;
                rt = vxlan_get_route(vxlan, skb, 0, info->key.tos,
                                     info->key.u.ipv4.dst,
-                                    &info->key.u.ipv4.src);
+                                    &info->key.u.ipv4.src, NULL, info);
                if (IS_ERR(rt))
                        return PTR_ERR(rt);
                ip_rt_put(rt);
@@ -2341,9 +2392,9 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 
                if (!vxlan->vn6_sock)
                        return -EINVAL;
-               ndst = vxlan6_get_route(vxlan, skb, 0,
-                                       &info->key.u.ipv6.dst,
-                                       &info->key.u.ipv6.src);
+               ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos,
+                                       info->key.label, &info->key.u.ipv6.dst,
+                                       &info->key.u.ipv6.src, NULL, info);
                if (IS_ERR(ndst))
                        return PTR_ERR(ndst);
                dst_release(ndst);
@@ -2428,6 +2479,7 @@ static void vxlan_setup(struct net_device *dev)
        dev->hw_features |= NETIF_F_GSO_SOFTWARE;
        dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
        netif_keep_dst(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
        dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
 
        INIT_LIST_HEAD(&vxlan->next);
@@ -2456,6 +2508,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
        [IFLA_VXLAN_LOCAL6]     = { .len = sizeof(struct in6_addr) },
        [IFLA_VXLAN_TOS]        = { .type = NLA_U8 },
        [IFLA_VXLAN_TTL]        = { .type = NLA_U8 },
+       [IFLA_VXLAN_LABEL]      = { .type = NLA_U32 },
        [IFLA_VXLAN_LEARNING]   = { .type = NLA_U8 },
        [IFLA_VXLAN_AGEING]     = { .type = NLA_U32 },
        [IFLA_VXLAN_LIMIT]      = { .type = NLA_U32 },
@@ -2603,7 +2656,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, bool ipv6,
        /* Mark socket as an encapsulation socket. */
        tunnel_cfg.sk_user_data = vs;
        tunnel_cfg.encap_type = 1;
-       tunnel_cfg.encap_rcv = vxlan_udp_encap_recv;
+       tunnel_cfg.encap_rcv = vxlan_rcv;
        tunnel_cfg.encap_destroy = NULL;
 
        setup_udp_tunnel_sock(net, sock, &tunnel_cfg);
@@ -2670,6 +2723,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
        int err;
        bool use_ipv6 = false;
        __be16 default_port = vxlan->cfg.dst_port;
+       struct net_device *lowerdev = NULL;
 
        vxlan->net = src_net;
 
@@ -2689,10 +2743,13 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
                vxlan->flags |= VXLAN_F_IPV6;
        }
 
-       if (conf->remote_ifindex) {
-               struct net_device *lowerdev
-                        = __dev_get_by_index(src_net, conf->remote_ifindex);
+       if (conf->label && !use_ipv6) {
+               pr_info("label only supported in use with IPv6\n");
+               return -EINVAL;
+       }
 
+       if (conf->remote_ifindex) {
+               lowerdev = __dev_get_by_index(src_net, conf->remote_ifindex);
                dst->remote_ifindex = conf->remote_ifindex;
 
                if (!lowerdev) {
@@ -2716,6 +2773,12 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev,
                needed_headroom = lowerdev->hard_header_len;
        }
 
+       if (conf->mtu) {
+               err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false);
+               if (err)
+                       return err;
+       }
+
        if (use_ipv6 || conf->flags & VXLAN_F_COLLECT_METADATA)
                needed_headroom += VXLAN6_HEADROOM;
        else
@@ -2800,7 +2863,7 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
        memset(&conf, 0, sizeof(conf));
 
        if (data[IFLA_VXLAN_ID])
-               conf.vni = nla_get_u32(data[IFLA_VXLAN_ID]);
+               conf.vni = cpu_to_be32(nla_get_u32(data[IFLA_VXLAN_ID]));
 
        if (data[IFLA_VXLAN_GROUP]) {
                conf.remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]);
@@ -2833,6 +2896,10 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
        if (data[IFLA_VXLAN_TTL])
                conf.ttl = nla_get_u8(data[IFLA_VXLAN_TTL]);
 
+       if (data[IFLA_VXLAN_LABEL])
+               conf.label = nla_get_be32(data[IFLA_VXLAN_LABEL]) &
+                            IPV6_FLOWLABEL_MASK;
+
        if (!data[IFLA_VXLAN_LEARNING] || nla_get_u8(data[IFLA_VXLAN_LEARNING]))
                conf.flags |= VXLAN_F_LEARN;
 
@@ -2868,8 +2935,9 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
        if (data[IFLA_VXLAN_PORT])
                conf.dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]);
 
-       if (data[IFLA_VXLAN_UDP_CSUM] && nla_get_u8(data[IFLA_VXLAN_UDP_CSUM]))
-               conf.flags |= VXLAN_F_UDP_CSUM;
+       if (data[IFLA_VXLAN_UDP_CSUM] &&
+           !nla_get_u8(data[IFLA_VXLAN_UDP_CSUM]))
+               conf.flags |= VXLAN_F_UDP_ZERO_CSUM_TX;
 
        if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] &&
            nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
@@ -2904,7 +2972,7 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev,
                break;
 
        case -EEXIST:
-               pr_info("duplicate VNI %u\n", conf.vni);
+               pr_info("duplicate VNI %u\n", be32_to_cpu(conf.vni));
                break;
        }
 
@@ -2935,6 +3003,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
                nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_LOCAL{6} */
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_TTL */
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_TOS */
+               nla_total_size(sizeof(__be32)) + /* IFLA_VXLAN_LABEL */
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_LEARNING */
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_PROXY */
                nla_total_size(sizeof(__u8)) +  /* IFLA_VXLAN_RSC */
@@ -2962,7 +3031,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
                .high = htons(vxlan->cfg.port_max),
        };
 
-       if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni))
+       if (nla_put_u32(skb, IFLA_VXLAN_ID, be32_to_cpu(dst->remote_vni)))
                goto nla_put_failure;
 
        if (!vxlan_addr_any(&dst->remote_ip)) {
@@ -2998,6 +3067,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
        if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) ||
            nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) ||
+           nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) ||
            nla_put_u8(skb, IFLA_VXLAN_LEARNING,
                        !!(vxlan->flags & VXLAN_F_LEARN)) ||
            nla_put_u8(skb, IFLA_VXLAN_PROXY,
@@ -3013,7 +3083,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
            nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) ||
            nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) ||
            nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM,
-                       !!(vxlan->flags & VXLAN_F_UDP_CSUM)) ||
+                       !(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) ||
            nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
                        !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ||
            nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
index 7a72407208b161772ba66dc284c7701ea5a85f59..6292259804634e0c6251e23dd8eb7213f16211fb 100644 (file)
@@ -1626,7 +1626,7 @@ try:
                if (state & Xpr) {
                        void __iomem *scc_addr;
                        unsigned long ring;
-                       int i;
+                       unsigned int i;
 
                        /*
                         * - the busy condition happens (sometimes);
index 317bc79cc8b9b22eace33116de7504c216b60a39..bb33b242ab48d66cd354c5626c8fb0de81be125e 100644 (file)
@@ -826,7 +826,7 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* lmc_trace(dev, "lmc_init_one in"); */
 
-       err = pci_enable_device(pdev);
+       err = pcim_enable_device(pdev);
        if (err) {
                printk(KERN_ERR "lmc: pci enable failed: %d\n", err);
                return err;
@@ -835,23 +835,20 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        err = pci_request_regions(pdev, "lmc");
        if (err) {
                printk(KERN_ERR "lmc: pci_request_region failed\n");
-               goto err_req_io;
+               return err;
        }
 
        /*
         * Allocate our own device structure
         */
-       sc = kzalloc(sizeof(lmc_softc_t), GFP_KERNEL);
-       if (!sc) {
-               err = -ENOMEM;
-               goto err_kzalloc;
-       }
+       sc = devm_kzalloc(&pdev->dev, sizeof(lmc_softc_t), GFP_KERNEL);
+       if (!sc)
+               return -ENOMEM;
 
        dev = alloc_hdlcdev(sc);
        if (!dev) {
                printk(KERN_ERR "lmc:alloc_netdev for device failed\n");
-               err = -ENOMEM;
-               goto err_hdlcdev;
+               return -ENOMEM;
        }
 
 
@@ -888,7 +885,7 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err) {
                printk(KERN_ERR "%s: register_netdev failed.\n", dev->name);
                free_netdev(dev);
-               goto err_hdlcdev;
+               return err;
        }
 
     sc->lmc_cardtype = LMC_CARDTYPE_UNKNOWN;
@@ -971,14 +968,6 @@ static int lmc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
     lmc_trace(dev, "lmc_init_one out");
     return 0;
-
-err_hdlcdev:
-       kfree(sc);
-err_kzalloc:
-       pci_release_regions(pdev);
-err_req_io:
-       pci_disable_device(pdev);
-       return err;
 }
 
 /*
@@ -992,8 +981,6 @@ static void lmc_remove_one(struct pci_dev *pdev)
                printk(KERN_DEBUG "%s: removing...\n", dev->name);
                unregister_hdlc_device(dev);
                free_netdev(dev);
-               pci_release_regions(pdev);
-               pci_disable_device(pdev);
        }
 }
 
index 03aa35f999a10c508e9e8090fd34e5519b15fe19..db1ca629cbd6d9c57d2fdd472c45c62fe1c5638f 100644 (file)
@@ -15,6 +15,12 @@ config ATH10K_PCI
        ---help---
          This module adds support for PCIE bus
 
+config ATH10K_AHB
+       bool "Atheros ath10k AHB support"
+       depends on ATH10K_PCI && OF && RESET_CONTROLLER
+       ---help---
+         This module adds support for AHB bus
+
 config ATH10K_DEBUG
        bool "Atheros ath10k debugging"
        depends on ATH10K
index c04fb00e7930219f909939b9ea36140ad3101fb8..930fadd940d86ad05e5dc473b30aee410789114b 100644 (file)
@@ -25,5 +25,7 @@ obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
 ath10k_pci-y += pci.o \
                ce.o
 
+ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
+
 # for tracing framework to find trace.h
 CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c
new file mode 100644 (file)
index 0000000..bd62bc1
--- /dev/null
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include "core.h"
+#include "debug.h"
+#include "pci.h"
+#include "ahb.h"
+
+static const struct of_device_id ath10k_ahb_of_match[] = {
+       /* TODO: enable this entry once everything in place.
+        * { .compatible = "qcom,ipq4019-wifi",
+        *   .data = (void *)ATH10K_HW_QCA4019 },
+        */
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match);
+
+static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar)
+{
+       return &((struct ath10k_pci *)ar->drv_priv)->ahb[0];
+}
+
+static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       iowrite32(value, ar_ahb->mem + offset);
+}
+
+static u32 ath10k_ahb_read32(struct ath10k *ar, u32 offset)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       return ioread32(ar_ahb->mem + offset);
+}
+
+static u32 ath10k_ahb_gcc_read32(struct ath10k *ar, u32 offset)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       return ioread32(ar_ahb->gcc_mem + offset);
+}
+
+static void ath10k_ahb_tcsr_write32(struct ath10k *ar, u32 offset, u32 value)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       iowrite32(value, ar_ahb->tcsr_mem + offset);
+}
+
+static u32 ath10k_ahb_tcsr_read32(struct ath10k *ar, u32 offset)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       return ioread32(ar_ahb->tcsr_mem + offset);
+}
+
+static u32 ath10k_ahb_soc_read32(struct ath10k *ar, u32 addr)
+{
+       return ath10k_ahb_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
+}
+
+static int ath10k_ahb_get_num_banks(struct ath10k *ar)
+{
+       if (ar->hw_rev == ATH10K_HW_QCA4019)
+               return 1;
+
+       ath10k_warn(ar, "unknown number of banks, assuming 1\n");
+       return 1;
+}
+
+static int ath10k_ahb_clock_init(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       struct device *dev;
+       int ret;
+
+       dev = &ar_ahb->pdev->dev;
+
+       ar_ahb->cmd_clk = clk_get(dev, "wifi_wcss_cmd");
+       if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) {
+               ath10k_err(ar, "failed to get cmd clk: %ld\n",
+                          PTR_ERR(ar_ahb->cmd_clk));
+               ret = ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV;
+               goto out;
+       }
+
+       ar_ahb->ref_clk = clk_get(dev, "wifi_wcss_ref");
+       if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) {
+               ath10k_err(ar, "failed to get ref clk: %ld\n",
+                          PTR_ERR(ar_ahb->ref_clk));
+               ret = ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV;
+               goto err_cmd_clk_put;
+       }
+
+       ar_ahb->rtc_clk = clk_get(dev, "wifi_wcss_rtc");
+       if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
+               ath10k_err(ar, "failed to get rtc clk: %ld\n",
+                          PTR_ERR(ar_ahb->rtc_clk));
+               ret = ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV;
+               goto err_ref_clk_put;
+       }
+
+       return 0;
+
+err_ref_clk_put:
+       clk_put(ar_ahb->ref_clk);
+
+err_cmd_clk_put:
+       clk_put(ar_ahb->cmd_clk);
+
+out:
+       return ret;
+}
+
+static void ath10k_ahb_clock_deinit(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk))
+               clk_put(ar_ahb->cmd_clk);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->ref_clk))
+               clk_put(ar_ahb->ref_clk);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk))
+               clk_put(ar_ahb->rtc_clk);
+
+       ar_ahb->cmd_clk = NULL;
+       ar_ahb->ref_clk = NULL;
+       ar_ahb->rtc_clk = NULL;
+}
+
+static int ath10k_ahb_clock_enable(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       struct device *dev;
+       int ret;
+
+       dev = &ar_ahb->pdev->dev;
+
+       if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) ||
+           IS_ERR_OR_NULL(ar_ahb->ref_clk) ||
+           IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
+               ath10k_err(ar, "clock(s) is/are not initialized\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       ret = clk_prepare_enable(ar_ahb->cmd_clk);
+       if (ret) {
+               ath10k_err(ar, "failed to enable cmd clk: %d\n", ret);
+               goto out;
+       }
+
+       ret = clk_prepare_enable(ar_ahb->ref_clk);
+       if (ret) {
+               ath10k_err(ar, "failed to enable ref clk: %d\n", ret);
+               goto err_cmd_clk_disable;
+       }
+
+       ret = clk_prepare_enable(ar_ahb->rtc_clk);
+       if (ret) {
+               ath10k_err(ar, "failed to enable rtc clk: %d\n", ret);
+               goto err_ref_clk_disable;
+       }
+
+       return 0;
+
+err_ref_clk_disable:
+       clk_disable_unprepare(ar_ahb->ref_clk);
+
+err_cmd_clk_disable:
+       clk_disable_unprepare(ar_ahb->cmd_clk);
+
+out:
+       return ret;
+}
+
+static void ath10k_ahb_clock_disable(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk))
+               clk_disable_unprepare(ar_ahb->cmd_clk);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->ref_clk))
+               clk_disable_unprepare(ar_ahb->ref_clk);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk))
+               clk_disable_unprepare(ar_ahb->rtc_clk);
+}
+
+static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       struct device *dev;
+       int ret;
+
+       dev = &ar_ahb->pdev->dev;
+
+       ar_ahb->core_cold_rst = reset_control_get(dev, "wifi_core_cold");
+       if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) {
+               ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n",
+                          PTR_ERR(ar_ahb->core_cold_rst));
+               ret = ar_ahb->core_cold_rst ?
+                       PTR_ERR(ar_ahb->core_cold_rst) : -ENODEV;
+               goto out;
+       }
+
+       ar_ahb->radio_cold_rst = reset_control_get(dev, "wifi_radio_cold");
+       if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) {
+               ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n",
+                          PTR_ERR(ar_ahb->radio_cold_rst));
+               ret = ar_ahb->radio_cold_rst ?
+                       PTR_ERR(ar_ahb->radio_cold_rst) : -ENODEV;
+               goto err_core_cold_rst_put;
+       }
+
+       ar_ahb->radio_warm_rst = reset_control_get(dev, "wifi_radio_warm");
+       if (IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) {
+               ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n",
+                          PTR_ERR(ar_ahb->radio_warm_rst));
+               ret = ar_ahb->radio_warm_rst ?
+                       PTR_ERR(ar_ahb->radio_warm_rst) : -ENODEV;
+               goto err_radio_cold_rst_put;
+       }
+
+       ar_ahb->radio_srif_rst = reset_control_get(dev, "wifi_radio_srif");
+       if (IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) {
+               ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n",
+                          PTR_ERR(ar_ahb->radio_srif_rst));
+               ret = ar_ahb->radio_srif_rst ?
+                       PTR_ERR(ar_ahb->radio_srif_rst) : -ENODEV;
+               goto err_radio_warm_rst_put;
+       }
+
+       ar_ahb->cpu_init_rst = reset_control_get(dev, "wifi_cpu_init");
+       if (IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
+               ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n",
+                          PTR_ERR(ar_ahb->cpu_init_rst));
+               ret = ar_ahb->cpu_init_rst ?
+                       PTR_ERR(ar_ahb->cpu_init_rst) : -ENODEV;
+               goto err_radio_srif_rst_put;
+       }
+
+       return 0;
+
+err_radio_srif_rst_put:
+       reset_control_put(ar_ahb->radio_srif_rst);
+
+err_radio_warm_rst_put:
+       reset_control_put(ar_ahb->radio_warm_rst);
+
+err_radio_cold_rst_put:
+       reset_control_put(ar_ahb->radio_cold_rst);
+
+err_core_cold_rst_put:
+       reset_control_put(ar_ahb->core_cold_rst);
+
+out:
+       return ret;
+}
+
+static void ath10k_ahb_rst_ctrl_deinit(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->core_cold_rst))
+               reset_control_put(ar_ahb->core_cold_rst);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->radio_cold_rst))
+               reset_control_put(ar_ahb->radio_cold_rst);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->radio_warm_rst))
+               reset_control_put(ar_ahb->radio_warm_rst);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->radio_srif_rst))
+               reset_control_put(ar_ahb->radio_srif_rst);
+
+       if (!IS_ERR_OR_NULL(ar_ahb->cpu_init_rst))
+               reset_control_put(ar_ahb->cpu_init_rst);
+
+       ar_ahb->core_cold_rst = NULL;
+       ar_ahb->radio_cold_rst = NULL;
+       ar_ahb->radio_warm_rst = NULL;
+       ar_ahb->radio_srif_rst = NULL;
+       ar_ahb->cpu_init_rst = NULL;
+}
+
+static int ath10k_ahb_release_reset(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       int ret;
+
+       if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
+               ath10k_err(ar, "rst ctrl(s) is/are not initialized\n");
+               return -EINVAL;
+       }
+
+       ret = reset_control_deassert(ar_ahb->radio_cold_rst);
+       if (ret) {
+               ath10k_err(ar, "failed to deassert radio cold rst: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_control_deassert(ar_ahb->radio_warm_rst);
+       if (ret) {
+               ath10k_err(ar, "failed to deassert radio warm rst: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_control_deassert(ar_ahb->radio_srif_rst);
+       if (ret) {
+               ath10k_err(ar, "failed to deassert radio srif rst: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_control_deassert(ar_ahb->cpu_init_rst);
+       if (ret) {
+               ath10k_err(ar, "failed to deassert cpu init rst: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ath10k_ahb_halt_axi_bus(struct ath10k *ar, u32 haltreq_reg,
+                                   u32 haltack_reg)
+{
+       unsigned long timeout;
+       u32 val;
+
+       /* Issue halt axi bus request */
+       val = ath10k_ahb_tcsr_read32(ar, haltreq_reg);
+       val |= AHB_AXI_BUS_HALT_REQ;
+       ath10k_ahb_tcsr_write32(ar, haltreq_reg, val);
+
+       /* Wait for axi bus halted ack */
+       timeout = jiffies + msecs_to_jiffies(ATH10K_AHB_AXI_BUS_HALT_TIMEOUT);
+       do {
+               val = ath10k_ahb_tcsr_read32(ar, haltack_reg);
+               if (val & AHB_AXI_BUS_HALT_ACK)
+                       break;
+
+               mdelay(1);
+       } while (time_before(jiffies, timeout));
+
+       if (!(val & AHB_AXI_BUS_HALT_ACK)) {
+               ath10k_err(ar, "failed to halt axi bus: %d\n", val);
+               return;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_AHB, "axi bus halted\n");
+}
+
+static void ath10k_ahb_halt_chip(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       u32 core_id, glb_cfg_reg, haltreq_reg, haltack_reg;
+       u32 val;
+       int ret;
+
+       if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) ||
+           IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
+               ath10k_err(ar, "rst ctrl(s) is/are not initialized\n");
+               return;
+       }
+
+       core_id = ath10k_ahb_read32(ar, ATH10K_AHB_WLAN_CORE_ID_REG);
+
+       switch (core_id) {
+       case 0:
+               glb_cfg_reg = ATH10K_AHB_TCSR_WIFI0_GLB_CFG;
+               haltreq_reg = ATH10K_AHB_TCSR_WCSS0_HALTREQ;
+               haltack_reg = ATH10K_AHB_TCSR_WCSS0_HALTACK;
+               break;
+       case 1:
+               glb_cfg_reg = ATH10K_AHB_TCSR_WIFI1_GLB_CFG;
+               haltreq_reg = ATH10K_AHB_TCSR_WCSS1_HALTREQ;
+               haltack_reg = ATH10K_AHB_TCSR_WCSS1_HALTACK;
+               break;
+       default:
+               ath10k_err(ar, "invalid core id %d found, skipping reset sequence\n",
+                          core_id);
+               return;
+       }
+
+       ath10k_ahb_halt_axi_bus(ar, haltreq_reg, haltack_reg);
+
+       val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg);
+       val |= TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK;
+       ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val);
+
+       ret = reset_control_assert(ar_ahb->core_cold_rst);
+       if (ret)
+               ath10k_err(ar, "failed to assert core cold rst: %d\n", ret);
+       msleep(1);
+
+       ret = reset_control_assert(ar_ahb->radio_cold_rst);
+       if (ret)
+               ath10k_err(ar, "failed to assert radio cold rst: %d\n", ret);
+       msleep(1);
+
+       ret = reset_control_assert(ar_ahb->radio_warm_rst);
+       if (ret)
+               ath10k_err(ar, "failed to assert radio warm rst: %d\n", ret);
+       msleep(1);
+
+       ret = reset_control_assert(ar_ahb->radio_srif_rst);
+       if (ret)
+               ath10k_err(ar, "failed to assert radio srif rst: %d\n", ret);
+       msleep(1);
+
+       ret = reset_control_assert(ar_ahb->cpu_init_rst);
+       if (ret)
+               ath10k_err(ar, "failed to assert cpu init rst: %d\n", ret);
+       msleep(10);
+
+       /* Clear halt req and core clock disable req before
+        * deasserting wifi core reset.
+        */
+       val = ath10k_ahb_tcsr_read32(ar, haltreq_reg);
+       val &= ~AHB_AXI_BUS_HALT_REQ;
+       ath10k_ahb_tcsr_write32(ar, haltreq_reg, val);
+
+       val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg);
+       val &= ~TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK;
+       ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val);
+
+       ret = reset_control_deassert(ar_ahb->core_cold_rst);
+       if (ret)
+               ath10k_err(ar, "failed to deassert core cold rst: %d\n", ret);
+
+       ath10k_dbg(ar, ATH10K_DBG_AHB, "core %d reset done\n", core_id);
+}
+
+static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg)
+{
+       struct ath10k *ar = arg;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       if (!ath10k_pci_irq_pending(ar))
+               return IRQ_NONE;
+
+       ath10k_pci_disable_and_clear_legacy_irq(ar);
+       tasklet_schedule(&ar_pci->intr_tq);
+
+       return IRQ_HANDLED;
+}
+
+static int ath10k_ahb_request_irq_legacy(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       int ret;
+
+       ret = request_irq(ar_ahb->irq,
+                         ath10k_ahb_interrupt_handler,
+                         IRQF_SHARED, "ath10k_ahb", ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
+                           ar_ahb->irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ath10k_ahb_release_irq_legacy(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       free_irq(ar_ahb->irq, ar);
+}
+
+static void ath10k_ahb_irq_disable(struct ath10k *ar)
+{
+       ath10k_ce_disable_interrupts(ar);
+       ath10k_pci_disable_and_clear_legacy_irq(ar);
+}
+
+static int ath10k_ahb_resource_init(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       struct platform_device *pdev;
+       struct device *dev;
+       struct resource *res;
+       int ret;
+
+       pdev = ar_ahb->pdev;
+       dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ath10k_err(ar, "failed to get memory resource\n");
+               ret = -ENXIO;
+               goto out;
+       }
+
+       ar_ahb->mem = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ar_ahb->mem)) {
+               ath10k_err(ar, "mem ioremap error\n");
+               ret = PTR_ERR(ar_ahb->mem);
+               goto out;
+       }
+
+       ar_ahb->mem_len = resource_size(res);
+
+       ar_ahb->gcc_mem = ioremap_nocache(ATH10K_GCC_REG_BASE,
+                                         ATH10K_GCC_REG_SIZE);
+       if (!ar_ahb->gcc_mem) {
+               ath10k_err(ar, "gcc mem ioremap error\n");
+               ret = -ENOMEM;
+               goto err_mem_unmap;
+       }
+
+       ar_ahb->tcsr_mem = ioremap_nocache(ATH10K_TCSR_REG_BASE,
+                                          ATH10K_TCSR_REG_SIZE);
+       if (!ar_ahb->tcsr_mem) {
+               ath10k_err(ar, "tcsr mem ioremap error\n");
+               ret = -ENOMEM;
+               goto err_gcc_mem_unmap;
+       }
+
+       ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               ath10k_err(ar, "failed to set 32-bit dma mask: %d\n", ret);
+               goto err_tcsr_mem_unmap;
+       }
+
+       ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               ath10k_err(ar, "failed to set 32-bit consistent dma: %d\n",
+                          ret);
+               goto err_tcsr_mem_unmap;
+       }
+
+       ret = ath10k_ahb_clock_init(ar);
+       if (ret)
+               goto err_tcsr_mem_unmap;
+
+       ret = ath10k_ahb_rst_ctrl_init(ar);
+       if (ret)
+               goto err_clock_deinit;
+
+       ar_ahb->irq = platform_get_irq_byname(pdev, "legacy");
+       if (ar_ahb->irq < 0) {
+               ath10k_err(ar, "failed to get irq number: %d\n", ar_ahb->irq);
+               goto err_clock_deinit;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "irq: %d\n", ar_ahb->irq);
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "mem: 0x%p mem_len: %lu gcc mem: 0x%p tcsr_mem: 0x%p\n",
+                  ar_ahb->mem, ar_ahb->mem_len,
+                  ar_ahb->gcc_mem, ar_ahb->tcsr_mem);
+       return 0;
+
+err_clock_deinit:
+       ath10k_ahb_clock_deinit(ar);
+
+err_tcsr_mem_unmap:
+       iounmap(ar_ahb->tcsr_mem);
+
+err_gcc_mem_unmap:
+       ar_ahb->tcsr_mem = NULL;
+       iounmap(ar_ahb->gcc_mem);
+
+err_mem_unmap:
+       ar_ahb->gcc_mem = NULL;
+       devm_iounmap(&pdev->dev, ar_ahb->mem);
+
+out:
+       ar_ahb->mem = NULL;
+       return ret;
+}
+
+static void ath10k_ahb_resource_deinit(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+       struct device *dev;
+
+       dev = &ar_ahb->pdev->dev;
+
+       if (ar_ahb->mem)
+               devm_iounmap(dev, ar_ahb->mem);
+
+       if (ar_ahb->gcc_mem)
+               iounmap(ar_ahb->gcc_mem);
+
+       if (ar_ahb->tcsr_mem)
+               iounmap(ar_ahb->tcsr_mem);
+
+       ar_ahb->mem = NULL;
+       ar_ahb->gcc_mem = NULL;
+       ar_ahb->tcsr_mem = NULL;
+
+       ath10k_ahb_clock_deinit(ar);
+       ath10k_ahb_rst_ctrl_deinit(ar);
+}
+
+static int ath10k_ahb_prepare_device(struct ath10k *ar)
+{
+       u32 val;
+       int ret;
+
+       ret = ath10k_ahb_clock_enable(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to enable clocks\n");
+               return ret;
+       }
+
+       /* Clock for the target is supplied from outside of target (ie,
+        * external clock module controlled by the host). Target needs
+        * to know what frequency target cpu is configured which is needed
+        * for target internal use. Read target cpu frequency info from
+        * gcc register and write into target's scratch register where
+        * target expects this information.
+        */
+       val = ath10k_ahb_gcc_read32(ar, ATH10K_AHB_GCC_FEPLL_PLL_DIV);
+       ath10k_ahb_write32(ar, ATH10K_AHB_WIFI_SCRATCH_5_REG, val);
+
+       ret = ath10k_ahb_release_reset(ar);
+       if (ret)
+               goto err_clk_disable;
+
+       ath10k_ahb_irq_disable(ar);
+
+       ath10k_ahb_write32(ar, FW_INDICATOR_ADDRESS, FW_IND_HOST_READY);
+
+       ret = ath10k_pci_wait_for_target_init(ar);
+       if (ret)
+               goto err_halt_chip;
+
+       return 0;
+
+err_halt_chip:
+       ath10k_ahb_halt_chip(ar);
+
+err_clk_disable:
+       ath10k_ahb_clock_disable(ar);
+
+       return ret;
+}
+
+static int ath10k_ahb_chip_reset(struct ath10k *ar)
+{
+       int ret;
+
+       ath10k_ahb_halt_chip(ar);
+       ath10k_ahb_clock_disable(ar);
+
+       ret = ath10k_ahb_prepare_device(ar);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int ath10k_ahb_wake_target_cpu(struct ath10k *ar)
+{
+       u32 addr, val;
+
+       addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS;
+       val = ath10k_ahb_read32(ar, addr);
+       val |= ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK;
+       ath10k_ahb_write32(ar, addr, val);
+
+       return 0;
+}
+
+static int ath10k_ahb_hif_start(struct ath10k *ar)
+{
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n");
+
+       ath10k_ce_enable_interrupts(ar);
+       ath10k_pci_enable_legacy_irq(ar);
+
+       ath10k_pci_rx_post(ar);
+
+       return 0;
+}
+
+static void ath10k_ahb_hif_stop(struct ath10k *ar)
+{
+       struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif stop\n");
+
+       ath10k_ahb_irq_disable(ar);
+       synchronize_irq(ar_ahb->irq);
+
+       ath10k_pci_flush(ar);
+}
+
+static int ath10k_ahb_hif_power_up(struct ath10k *ar)
+{
+       int ret;
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif power up\n");
+
+       ret = ath10k_ahb_chip_reset(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to reset chip: %d\n", ret);
+               goto out;
+       }
+
+       ret = ath10k_pci_init_pipes(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to initialize CE: %d\n", ret);
+               goto out;
+       }
+
+       ret = ath10k_pci_init_config(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to setup init config: %d\n", ret);
+               goto err_ce_deinit;
+       }
+
+       ret = ath10k_ahb_wake_target_cpu(ar);
+       if (ret) {
+               ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
+               goto err_ce_deinit;
+       }
+
+       return 0;
+
+err_ce_deinit:
+       ath10k_pci_ce_deinit(ar);
+out:
+       return ret;
+}
+
+static const struct ath10k_hif_ops ath10k_ahb_hif_ops = {
+       .tx_sg                  = ath10k_pci_hif_tx_sg,
+       .diag_read              = ath10k_pci_hif_diag_read,
+       .diag_write             = ath10k_pci_diag_write_mem,
+       .exchange_bmi_msg       = ath10k_pci_hif_exchange_bmi_msg,
+       .start                  = ath10k_ahb_hif_start,
+       .stop                   = ath10k_ahb_hif_stop,
+       .map_service_to_pipe    = ath10k_pci_hif_map_service_to_pipe,
+       .get_default_pipe       = ath10k_pci_hif_get_default_pipe,
+       .send_complete_check    = ath10k_pci_hif_send_complete_check,
+       .get_free_queue_number  = ath10k_pci_hif_get_free_queue_number,
+       .power_up               = ath10k_ahb_hif_power_up,
+       .power_down             = ath10k_pci_hif_power_down,
+       .read32                 = ath10k_ahb_read32,
+       .write32                = ath10k_ahb_write32,
+};
+
+static const struct ath10k_bus_ops ath10k_ahb_bus_ops = {
+       .read32         = ath10k_ahb_read32,
+       .write32        = ath10k_ahb_write32,
+       .get_num_banks  = ath10k_ahb_get_num_banks,
+};
+
+static int ath10k_ahb_probe(struct platform_device *pdev)
+{
+       struct ath10k *ar;
+       struct ath10k_ahb *ar_ahb;
+       struct ath10k_pci *ar_pci;
+       const struct of_device_id *of_id;
+       enum ath10k_hw_rev hw_rev;
+       size_t size;
+       int ret;
+       u32 chip_id;
+
+       of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
+       if (!of_id) {
+               dev_err(&pdev->dev, "failed to find matching device tree id\n");
+               return -EINVAL;
+       }
+
+       hw_rev = (enum ath10k_hw_rev)of_id->data;
+
+       size = sizeof(*ar_pci) + sizeof(*ar_ahb);
+       ar = ath10k_core_create(size, &pdev->dev, ATH10K_BUS_AHB,
+                               hw_rev, &ath10k_ahb_hif_ops);
+       if (!ar) {
+               dev_err(&pdev->dev, "failed to allocate core\n");
+               return -ENOMEM;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "ahb probe\n");
+
+       ar_pci = ath10k_pci_priv(ar);
+       ar_ahb = ath10k_ahb_priv(ar);
+
+       ar_ahb->pdev = pdev;
+       platform_set_drvdata(pdev, ar);
+
+       ret = ath10k_ahb_resource_init(ar);
+       if (ret)
+               goto err_core_destroy;
+
+       ar->dev_id = 0;
+       ar_pci->mem = ar_ahb->mem;
+       ar_pci->mem_len = ar_ahb->mem_len;
+       ar_pci->ar = ar;
+       ar_pci->bus_ops = &ath10k_ahb_bus_ops;
+
+       ret = ath10k_pci_setup_resource(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to setup resource: %d\n", ret);
+               goto err_resource_deinit;
+       }
+
+       ath10k_pci_init_irq_tasklets(ar);
+
+       ret = ath10k_ahb_request_irq_legacy(ar);
+       if (ret)
+               goto err_free_pipes;
+
+       ret = ath10k_ahb_prepare_device(ar);
+       if (ret)
+               goto err_free_irq;
+
+       ath10k_pci_ce_deinit(ar);
+
+       chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+       if (chip_id == 0xffffffff) {
+               ath10k_err(ar, "failed to get chip id\n");
+               goto err_halt_device;
+       }
+
+       ret = ath10k_core_register(ar, chip_id);
+       if (ret) {
+               ath10k_err(ar, "failed to register driver core: %d\n", ret);
+               goto err_halt_device;
+       }
+
+       return 0;
+
+err_halt_device:
+       ath10k_ahb_halt_chip(ar);
+       ath10k_ahb_clock_disable(ar);
+
+err_free_irq:
+       ath10k_ahb_release_irq_legacy(ar);
+
+err_free_pipes:
+       ath10k_pci_free_pipes(ar);
+
+err_resource_deinit:
+       ath10k_ahb_resource_deinit(ar);
+
+err_core_destroy:
+       ath10k_core_destroy(ar);
+       platform_set_drvdata(pdev, NULL);
+
+       return ret;
+}
+
+static int ath10k_ahb_remove(struct platform_device *pdev)
+{
+       struct ath10k *ar = platform_get_drvdata(pdev);
+       struct ath10k_ahb *ar_ahb;
+
+       if (!ar)
+               return -EINVAL;
+
+       ar_ahb = ath10k_ahb_priv(ar);
+
+       if (!ar_ahb)
+               return -EINVAL;
+
+       ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n");
+
+       ath10k_core_unregister(ar);
+       ath10k_ahb_irq_disable(ar);
+       ath10k_ahb_release_irq_legacy(ar);
+       ath10k_pci_release_resource(ar);
+       ath10k_ahb_halt_chip(ar);
+       ath10k_ahb_clock_disable(ar);
+       ath10k_ahb_resource_deinit(ar);
+       ath10k_core_destroy(ar);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ath10k_ahb_driver = {
+       .driver         = {
+               .name   = "ath10k_ahb",
+               .of_match_table = ath10k_ahb_of_match,
+       },
+       .probe  = ath10k_ahb_probe,
+       .remove = ath10k_ahb_remove,
+};
+
+int ath10k_ahb_init(void)
+{
+       int ret;
+
+       printk(KERN_ERR "AHB support is still work in progress\n");
+
+       ret = platform_driver_register(&ath10k_ahb_driver);
+       if (ret)
+               printk(KERN_ERR "failed to register ath10k ahb driver: %d\n",
+                      ret);
+       return ret;
+}
+
+void ath10k_ahb_exit(void)
+{
+       platform_driver_unregister(&ath10k_ahb_driver);
+}
diff --git a/drivers/net/wireless/ath/ath10k/ahb.h b/drivers/net/wireless/ath/ath10k/ahb.h
new file mode 100644 (file)
index 0000000..d43e375
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _AHB_H_
+#define _AHB_H_
+
+#include <linux/platform_device.h>
+
+struct ath10k_ahb {
+       struct platform_device *pdev;
+       void __iomem *mem;
+       unsigned long mem_len;
+       void __iomem *gcc_mem;
+       void __iomem *tcsr_mem;
+
+       int irq;
+
+       struct clk *cmd_clk;
+       struct clk *ref_clk;
+       struct clk *rtc_clk;
+
+       struct reset_control *core_cold_rst;
+       struct reset_control *radio_cold_rst;
+       struct reset_control *radio_warm_rst;
+       struct reset_control *radio_srif_rst;
+       struct reset_control *cpu_init_rst;
+};
+
+#ifdef CONFIG_ATH10K_AHB
+
+#define ATH10K_GCC_REG_BASE                  0x1800000
+#define ATH10K_GCC_REG_SIZE                  0x60000
+
+#define ATH10K_TCSR_REG_BASE                 0x1900000
+#define ATH10K_TCSR_REG_SIZE                 0x80000
+
+#define ATH10K_AHB_GCC_FEPLL_PLL_DIV         0x2f020
+#define ATH10K_AHB_WIFI_SCRATCH_5_REG        0x4f014
+
+#define ATH10K_AHB_WLAN_CORE_ID_REG          0x82030
+
+#define ATH10K_AHB_TCSR_WIFI0_GLB_CFG        0x49000
+#define ATH10K_AHB_TCSR_WIFI1_GLB_CFG        0x49004
+#define TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK  BIT(25)
+
+#define ATH10K_AHB_TCSR_WCSS0_HALTREQ        0x52000
+#define ATH10K_AHB_TCSR_WCSS1_HALTREQ        0x52010
+#define ATH10K_AHB_TCSR_WCSS0_HALTACK        0x52004
+#define ATH10K_AHB_TCSR_WCSS1_HALTACK        0x52014
+
+#define ATH10K_AHB_AXI_BUS_HALT_TIMEOUT      10 /* msec */
+#define AHB_AXI_BUS_HALT_REQ                 1
+#define AHB_AXI_BUS_HALT_ACK                 1
+
+#define ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK   1
+
+int ath10k_ahb_init(void);
+void ath10k_ahb_exit(void);
+
+#else /* CONFIG_ATH10K_AHB */
+
+static inline int ath10k_ahb_init(void)
+{
+       return 0;
+}
+
+static inline void ath10k_ahb_exit(void)
+{
+}
+
+#endif /* CONFIG_ATH10K_AHB */
+
+#endif /* _AHB_H_ */
index b41eb3f4ee5661c99afb0f99e5b168524e790be9..c84c2d30ef1f3f8c127eaca4baafee0d748f07d6 100644 (file)
@@ -156,6 +156,11 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .channel_counters_freq_hz = 150000,
                .max_probe_resp_desc_thres = 24,
                .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
+               .num_msdu_desc = 1424,
+               .qcache_active_peers = 50,
+               .tx_chain_mask = 0xf,
+               .rx_chain_mask = 0xf,
+               .max_spatial_stream = 4,
                .fw = {
                        .dir = QCA99X0_HW_2_0_FW_DIR,
                        .fw = QCA99X0_HW_2_0_FW_FILE,
@@ -201,6 +206,31 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                        .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
                },
        },
+       {
+               .id = QCA4019_HW_1_0_DEV_VERSION,
+               .dev_id = 0,
+               .name = "qca4019 hw1.0",
+               .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
+               .uart_pin = 7,
+               .otp_exe_param = 0x0010000,
+               .continuous_frag_desc = true,
+               .channel_counters_freq_hz = 125000,
+               .max_probe_resp_desc_thres = 24,
+               .hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
+               .num_msdu_desc = 2500,
+               .qcache_active_peers = 35,
+               .tx_chain_mask = 0x3,
+               .rx_chain_mask = 0x3,
+               .max_spatial_stream = 2,
+               .fw = {
+                       .dir = QCA4019_HW_1_0_FW_DIR,
+                       .fw = QCA4019_HW_1_0_FW_FILE,
+                       .otp = QCA4019_HW_1_0_OTP_FILE,
+                       .board = QCA4019_HW_1_0_BOARD_DATA_FILE,
+                       .board_size = QCA4019_BOARD_DATA_SZ,
+                       .board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
+               },
+       },
 };
 
 static const char *const ath10k_core_fw_feature_str[] = {
@@ -217,6 +247,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
        [ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
        [ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
        [ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
+       [ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
@@ -1478,8 +1509,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
        case ATH10K_FW_WMI_OP_VERSION_10_1:
        case ATH10K_FW_WMI_OP_VERSION_10_2:
        case ATH10K_FW_WMI_OP_VERSION_10_2_4:
-               ar->max_num_peers = TARGET_10X_NUM_PEERS;
-               ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+               if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
+                       ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
+                       ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;
+               } else {
+                       ar->max_num_peers = TARGET_10X_NUM_PEERS;
+                       ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+               }
                ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
                ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
                ar->fw_stats_req_mask = WMI_STAT_PEER;
@@ -1502,9 +1538,9 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
                ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
                ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
                ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
-               ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;
+               ar->htt.max_num_pending_tx = ar->hw_params.num_msdu_desc;
                ar->fw_stats_req_mask = WMI_STAT_PEER;
-               ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM;
+               ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
                break;
        case ATH10K_FW_WMI_OP_VERSION_UNSET:
        case ATH10K_FW_WMI_OP_VERSION_MAX:
@@ -1979,6 +2015,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
                ar->regs = &qca99x0_regs;
                ar->hw_values = &qca99x0_values;
                break;
+       case ATH10K_HW_QCA4019:
+               ar->regs = &qca4019_regs;
+               ar->hw_values = &qca4019_values;
+               break;
        default:
                ath10k_err(ar, "unsupported core hardware revision %d\n",
                           hw_rev);
index 7840cf3ef7a64399640129f700f6bdba42a776e8..a62b62a6226687e4f1ee09b8ba721588b79cbb9f 100644 (file)
@@ -69,6 +69,7 @@ struct ath10k;
 
 enum ath10k_bus {
        ATH10K_BUS_PCI,
+       ATH10K_BUS_AHB,
 };
 
 static inline const char *ath10k_bus_str(enum ath10k_bus bus)
@@ -76,6 +77,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
        switch (bus) {
        case ATH10K_BUS_PCI:
                return "pci";
+       case ATH10K_BUS_AHB:
+               return "ahb";
        }
 
        return "unknown";
@@ -159,6 +162,7 @@ struct ath10k_fw_stats_peer {
        u32 peer_rssi;
        u32 peer_tx_rate;
        u32 peer_rx_rate; /* 10x only */
+       u32 rx_duration;
 };
 
 struct ath10k_fw_stats_vdev {
@@ -315,6 +319,7 @@ struct ath10k_sta {
 #ifdef CONFIG_MAC80211_DEBUGFS
        /* protected by conf_mutex */
        bool aggr_mode;
+       u64 rx_duration;
 #endif
 };
 
@@ -510,6 +515,15 @@ enum ath10k_fw_features {
        /* Firmware supports management frame protection */
        ATH10K_FW_FEATURE_MFP_SUPPORT = 12,
 
+       /* Firmware supports pull-push model where host shares it's software
+        * queue state with firmware and firmware generates fetch requests
+        * telling host which queues to dequeue tx from.
+        *
+        * Primary function of this is improved MU-MIMO performance with
+        * multiple clients.
+        */
+       ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
+
        /* keep last */
        ATH10K_FW_FEATURE_COUNT,
 };
@@ -666,6 +680,12 @@ struct ath10k {
                /* The padding bytes's location is different on various chips */
                enum ath10k_hw_4addr_pad hw_4addr_pad;
 
+               u32 num_msdu_desc;
+               u32 qcache_active_peers;
+               u32 tx_chain_mask;
+               u32 rx_chain_mask;
+               u32 max_spatial_stream;
+
                struct ath10k_hw_params_fw {
                        const char *dir;
                        const char *fw;
index 2bdf5408b0d91e0a8dfba4bbc6e242590c429b8f..076d29b53ddff67a5b687dc6b722632db20d111c 100644 (file)
@@ -276,7 +276,7 @@ static const struct file_operations fops_wmi_services = {
        .llseek = default_llseek,
 };
 
-static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
+static void ath10k_fw_stats_pdevs_free(struct list_head *head)
 {
        struct ath10k_fw_stats_pdev *i, *tmp;
 
@@ -286,7 +286,7 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
        }
 }
 
-static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
+static void ath10k_fw_stats_vdevs_free(struct list_head *head)
 {
        struct ath10k_fw_stats_vdev *i, *tmp;
 
@@ -296,7 +296,7 @@ static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
        }
 }
 
-static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
+static void ath10k_fw_stats_peers_free(struct list_head *head)
 {
        struct ath10k_fw_stats_peer *i, *tmp;
 
@@ -310,16 +310,16 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
 {
        spin_lock_bh(&ar->data_lock);
        ar->debug.fw_stats_done = false;
-       ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
-       ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
-       ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
+       ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+       ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
+       ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
        spin_unlock_bh(&ar->data_lock);
 }
 
 void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
 {
        struct ath10k_fw_stats stats = {};
-       bool is_start, is_started, is_end;
+       bool is_start, is_started, is_end, peer_stats_svc;
        size_t num_peers;
        size_t num_vdevs;
        int ret;
@@ -347,8 +347,14 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
         *     delivered which is treated as end-of-data and is itself discarded
         */
 
+       peer_stats_svc = test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map);
+       if (peer_stats_svc)
+               ath10k_sta_update_rx_duration(ar, &stats.peers);
+
        if (ar->debug.fw_stats_done) {
-               ath10k_warn(ar, "received unsolicited stats update event\n");
+               if (!peer_stats_svc)
+                       ath10k_warn(ar, "received unsolicited stats update event\n");
+
                goto free;
        }
 
@@ -372,11 +378,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
                        /* Although this is unlikely impose a sane limit to
                         * prevent firmware from DoS-ing the host.
                         */
+                       ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
                        ath10k_warn(ar, "dropping fw peer stats\n");
                        goto free;
                }
 
                if (num_vdevs >= BITS_PER_LONG) {
+                       ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
                        ath10k_warn(ar, "dropping fw vdev stats\n");
                        goto free;
                }
@@ -391,9 +399,9 @@ free:
        /* In some cases lists have been spliced and cleared. Free up
         * resources if that is not the case.
         */
-       ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
-       ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
-       ath10k_debug_fw_stats_peers_free(&stats.peers);
+       ath10k_fw_stats_pdevs_free(&stats.pdevs);
+       ath10k_fw_stats_vdevs_free(&stats.vdevs);
+       ath10k_fw_stats_peers_free(&stats.peers);
 
        spin_unlock_bh(&ar->data_lock);
 }
@@ -2106,6 +2114,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
        struct ath10k *ar = file->private_data;
        char buf[32];
        size_t buf_size;
+       int ret = 0;
        bool val;
 
        buf_size = min(count, (sizeof(buf) - 1));
@@ -2119,6 +2128,12 @@ static ssize_t ath10k_write_btcoex(struct file *file,
 
        mutex_lock(&ar->conf_mutex);
 
+       if (ar->state != ATH10K_STATE_ON &&
+           ar->state != ATH10K_STATE_RESTARTED) {
+               ret = -ENETDOWN;
+               goto exit;
+       }
+
        if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val))
                goto exit;
 
@@ -2127,17 +2142,15 @@ static ssize_t ath10k_write_btcoex(struct file *file,
        else
                clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
 
-       if (ar->state != ATH10K_STATE_ON)
-               goto exit;
-
        ath10k_info(ar, "restarting firmware due to btcoex change");
 
        queue_work(ar->workqueue, &ar->restart_work);
+       ret = count;
 
 exit:
        mutex_unlock(&ar->conf_mutex);
 
-       return count;
+       return ret;
 }
 
 static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
@@ -2176,9 +2189,6 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
 
        mutex_lock(&ar->conf_mutex);
 
-       if (len > buf_len)
-               len = buf_len;
-
        len += scnprintf(buf + len, buf_len - len,
                         "firmware-N.bin\t\t%08x\n",
                         crc32_le(0, ar->firmware->data, ar->firmware->size));
index 814719cf4f226251d3c60389d78af1e05c36bba7..6206edd7c49f0a6a0ff85f09c608118f38923729 100644 (file)
@@ -37,6 +37,7 @@ enum ath10k_debug_mask {
        ATH10K_DBG_TESTMODE     = 0x00001000,
        ATH10K_DBG_WMI_PRINT    = 0x00002000,
        ATH10K_DBG_PCI_PS       = 0x00004000,
+       ATH10K_DBG_AHB          = 0x00008000,
        ATH10K_DBG_ANY          = 0xffffffff,
 };
 
@@ -153,6 +154,12 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, struct dentry *dir);
+void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer);
+#else
+static inline void ath10k_sta_update_rx_duration(struct ath10k *ar,
+                                                struct list_head *peer)
+{
+}
 #endif /* CONFIG_MAC80211_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
index 95b5c49374e0cd04dc5bafc4f089375792f5f38e..67ef75b60567e95476e5d8344903f36694a740e2 100644 (file)
 #include "wmi-ops.h"
 #include "debug.h"
 
+void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
+{      struct ieee80211_sta *sta;
+       struct ath10k_fw_stats_peer *peer;
+       struct ath10k_sta *arsta;
+
+       rcu_read_lock();
+       list_for_each_entry(peer, head, list) {
+               sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
+                                                  NULL);
+               if (!sta)
+                       continue;
+               arsta = (struct ath10k_sta *)sta->drv_priv;
+               arsta->rx_duration += (u64)peer->rx_duration;
+       }
+       rcu_read_unlock();
+}
+
 static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
                                             char __user *user_buf,
                                             size_t count, loff_t *ppos)
@@ -232,6 +249,28 @@ static const struct file_operations fops_delba = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath10k_dbg_sta_read_rx_duration(struct file *file,
+                                              char __user *user_buf,
+                                              size_t count, loff_t *ppos)
+{
+       struct ieee80211_sta *sta = file->private_data;
+       struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+       char buf[100];
+       int len = 0;
+
+       len = scnprintf(buf, sizeof(buf),
+                       "%llu usecs\n", arsta->rx_duration);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_rx_duration = {
+       .read = ath10k_dbg_sta_read_rx_duration,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, struct dentry *dir)
 {
@@ -240,4 +279,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
        debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
        debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
+       debugfs_create_file("rx_duration", S_IRUGO, dir, sta,
+                           &fops_rx_duration);
 }
index 3e6ba63dfdffe118b8d6e62a4fb086c376f1e3a5..7561f22f10f9c92266e4e73d6826f465acd0f361 100644 (file)
@@ -131,12 +131,12 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = {
        [HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
        [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] =
                                HTT_T2H_MSG_TYPE_TX_FETCH_IND,
-       [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] =
-                               HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
+       [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM] =
+                               HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
        [HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] =
                                HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
-       [HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] =
-                               HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
+       [HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
+                               HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
 };
 
 int ath10k_htt_connect(struct ath10k_htt *htt)
index 47ca048feaf02e097199c4affcd28081c24b879d..13391ea4422d3f5acf0adf3d0e10ed35a3b535b1 100644 (file)
@@ -52,6 +52,7 @@ enum htt_h2t_msg_type { /* host-to-target */
        /* This command is used for sending management frames in HTT < 3.0.
         * HTT >= 3.0 uses TX_FRM for everything. */
        HTT_H2T_MSG_TYPE_MGMT_TX            = 7,
+       HTT_H2T_MSG_TYPE_TX_FETCH_RESP      = 11,
 
        HTT_H2T_NUM_MSGS /* keep this last */
 };
@@ -413,10 +414,10 @@ enum htt_10_4_t2h_msg_type {
        HTT_10_4_T2H_MSG_TYPE_EN_STATS               = 0x14,
        HTT_10_4_T2H_MSG_TYPE_AGGR_CONF              = 0x15,
        HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND           = 0x16,
-       HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF          = 0x17,
+       HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM       = 0x17,
        HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD         = 0x18,
        /* 0x19 to 0x2f are reserved */
-       HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND     = 0x30,
+       HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND     = 0x30,
        /* keep this last */
        HTT_10_4_T2H_NUM_MSGS
 };
@@ -449,8 +450,8 @@ enum htt_t2h_msg_type {
        HTT_T2H_MSG_TYPE_TEST,
        HTT_T2H_MSG_TYPE_EN_STATS,
        HTT_T2H_MSG_TYPE_TX_FETCH_IND,
-       HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
-       HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
+       HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
+       HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
        /* keep this last */
        HTT_T2H_NUM_MSGS
 };
@@ -1306,9 +1307,43 @@ struct htt_frag_desc_bank_id {
  * so we use a conservatively safe value for now */
 #define HTT_FRAG_DESC_BANK_MAX 4
 
-#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03
-#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB  0
-#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP         (1 << 2)
+#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK               0x03
+#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB                        0
+#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP                       BIT(2)
+#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID              BIT(3)
+#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_MASK    BIT(4)
+#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_LSB     4
+
+enum htt_q_depth_type {
+       HTT_Q_DEPTH_TYPE_BYTES = 0,
+       HTT_Q_DEPTH_TYPE_MSDUS = 1,
+};
+
+#define HTT_TX_Q_STATE_NUM_PEERS               (TARGET_10_4_NUM_QCACHE_PEERS_MAX + \
+                                                TARGET_10_4_NUM_VDEVS)
+#define HTT_TX_Q_STATE_NUM_TIDS                        8
+#define HTT_TX_Q_STATE_ENTRY_SIZE              1
+#define HTT_TX_Q_STATE_ENTRY_MULTIPLIER                0
+
+/**
+ * htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config
+ *
+ * Defines host q state format and behavior. See htt_q_state.
+ *
+ * @record_size: Defines the size of each host q entry in bytes. In practice
+ *     however firmware (at least 10.4.3-00191) ignores this host
+ *     configuration value and uses hardcoded value of 1.
+ * @record_multiplier: This is valid only when q depth type is MSDUs. It
+ *     defines the exponent for the power of 2 multiplication.
+ */
+struct htt_q_state_conf {
+       __le32 paddr;
+       __le16 num_peers;
+       __le16 num_tids;
+       u8 record_size;
+       u8 record_multiplier;
+       u8 pad[2];
+} __packed;
 
 struct htt_frag_desc_bank_cfg {
        u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
@@ -1316,6 +1351,114 @@ struct htt_frag_desc_bank_cfg {
        u8 desc_size;
        __le32 bank_base_addrs[HTT_FRAG_DESC_BANK_MAX];
        struct htt_frag_desc_bank_id bank_id[HTT_FRAG_DESC_BANK_MAX];
+       struct htt_q_state_conf q_state;
+} __packed;
+
+#define HTT_TX_Q_STATE_ENTRY_COEFFICIENT       128
+#define HTT_TX_Q_STATE_ENTRY_FACTOR_MASK       0x3f
+#define HTT_TX_Q_STATE_ENTRY_FACTOR_LSB                0
+#define HTT_TX_Q_STATE_ENTRY_EXP_MASK          0xc0
+#define HTT_TX_Q_STATE_ENTRY_EXP_LSB           6
+
+/**
+ * htt_q_state - shared between host and firmware via DMA
+ *
+ * This structure is used for the host to expose it's software queue state to
+ * firmware so that its rate control can schedule fetch requests for optimized
+ * performance. This is most notably used for MU-MIMO aggregation when multiple
+ * MU clients are connected.
+ *
+ * @count: Each element defines the host queue depth. When q depth type was
+ *     configured as HTT_Q_DEPTH_TYPE_BYTES then each entry is defined as:
+ *     FACTOR * 128 * 8^EXP (see HTT_TX_Q_STATE_ENTRY_FACTOR_MASK and
+ *     HTT_TX_Q_STATE_ENTRY_EXP_MASK). When q depth type was configured as
+ *     HTT_Q_DEPTH_TYPE_MSDUS the number of packets is scaled by 2 **
+ *     record_multiplier (see htt_q_state_conf).
+ * @map: Used by firmware to quickly check which host queues are not empty. It
+ *     is a bitmap simply saying.
+ * @seq: Used by firmware to quickly check if the host queues were updated
+ *     since it last checked.
+ *
+ * FIXME: Is the q_state map[] size calculation really correct?
+ */
+struct htt_q_state {
+       u8 count[HTT_TX_Q_STATE_NUM_TIDS][HTT_TX_Q_STATE_NUM_PEERS];
+       u32 map[HTT_TX_Q_STATE_NUM_TIDS][(HTT_TX_Q_STATE_NUM_PEERS + 31) / 32];
+       __le32 seq;
+} __packed;
+
+#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_MASK  0x0fff
+#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_LSB   0
+#define HTT_TX_FETCH_RECORD_INFO_TID_MASK      0xf000
+#define HTT_TX_FETCH_RECORD_INFO_TID_LSB       12
+
+struct htt_tx_fetch_record {
+       __le16 info; /* HTT_TX_FETCH_IND_RECORD_INFO_ */
+       __le16 num_msdus;
+       __le32 num_bytes;
+} __packed;
+
+struct htt_tx_fetch_ind {
+       u8 pad0;
+       __le16 fetch_seq_num;
+       __le32 token;
+       __le16 num_resp_ids;
+       __le16 num_records;
+       struct htt_tx_fetch_record records[0];
+       __le32 resp_ids[0]; /* ath10k_htt_get_tx_fetch_ind_resp_ids() */
+} __packed;
+
+static inline void *
+ath10k_htt_get_tx_fetch_ind_resp_ids(struct htt_tx_fetch_ind *ind)
+{
+       return (void *)&ind->records[le16_to_cpu(ind->num_records)];
+}
+
+struct htt_tx_fetch_resp {
+       u8 pad0;
+       __le16 resp_id;
+       __le16 fetch_seq_num;
+       __le16 num_records;
+       __le32 token;
+       struct htt_tx_fetch_record records[0];
+} __packed;
+
+struct htt_tx_fetch_confirm {
+       u8 pad0;
+       __le16 num_resp_ids;
+       __le32 resp_ids[0];
+} __packed;
+
+enum htt_tx_mode_switch_mode {
+       HTT_TX_MODE_SWITCH_PUSH = 0,
+       HTT_TX_MODE_SWITCH_PUSH_PULL = 1,
+};
+
+#define HTT_TX_MODE_SWITCH_IND_INFO0_ENABLE            BIT(0)
+#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_MASK  0xfffe
+#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_LSB   1
+
+#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_MASK         0x0003
+#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_LSB          0
+#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_MASK    0xfffc
+#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_LSB     2
+
+#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_MASK   0x0fff
+#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_LSB    0
+#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_MASK       0xf000
+#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_LSB                12
+
+struct htt_tx_mode_switch_record {
+       __le16 info0; /* HTT_TX_MODE_SWITCH_RECORD_INFO0_ */
+       __le16 num_max_msdus;
+} __packed;
+
+struct htt_tx_mode_switch_ind {
+       u8 pad0;
+       __le16 info0; /* HTT_TX_MODE_SWITCH_IND_INFO0_ */
+       __le16 info1; /* HTT_TX_MODE_SWITCH_IND_INFO1_ */
+       u8 pad1[2];
+       struct htt_tx_mode_switch_record records[0];
 } __packed;
 
 union htt_rx_pn_t {
@@ -1340,6 +1483,7 @@ struct htt_cmd {
                struct htt_oob_sync_req oob_sync_req;
                struct htt_aggr_conf aggr_conf;
                struct htt_frag_desc_bank_cfg frag_desc_bank_cfg;
+               struct htt_tx_fetch_resp tx_fetch_resp;
        };
 } __packed;
 
@@ -1364,6 +1508,9 @@ struct htt_resp {
                struct htt_rx_pn_ind rx_pn_ind;
                struct htt_rx_offload_ind rx_offload_ind;
                struct htt_rx_in_ord_ind rx_in_ord_ind;
+               struct htt_tx_fetch_ind tx_fetch_ind;
+               struct htt_tx_fetch_confirm tx_fetch_confirm;
+               struct htt_tx_mode_switch_ind tx_mode_switch_ind;
        };
 } __packed;
 
@@ -1518,6 +1665,14 @@ struct ath10k_htt {
                dma_addr_t paddr;
                struct ath10k_htt_txbuf *vaddr;
        } txbuf;
+
+       struct {
+               struct htt_q_state *vaddr;
+               dma_addr_t paddr;
+               u16 num_peers;
+               u16 num_tids;
+               enum htt_q_depth_type type;
+       } tx_q_state;
 };
 
 #define RX_HTT_HDR_STATUS_LEN 64
index 91afa3ae414cb039e198949a651c09d1294d20c3..ae9b686a4e912298723d32a022af479d5854c5f4 100644 (file)
@@ -2011,9 +2011,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        }
        case HTT_T2H_MSG_TYPE_RX_IND:
-               spin_lock_bh(&htt->rx_ring.lock);
-               __skb_queue_tail(&htt->rx_compl_q, skb);
-               spin_unlock_bh(&htt->rx_ring.lock);
+               skb_queue_tail(&htt->rx_compl_q, skb);
                tasklet_schedule(&htt->txrx_compl_task);
                return;
        case HTT_T2H_MSG_TYPE_PEER_MAP: {
@@ -2111,9 +2109,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        }
        case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
-               spin_lock_bh(&htt->rx_ring.lock);
-               __skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
-               spin_unlock_bh(&htt->rx_ring.lock);
+               skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
                tasklet_schedule(&htt->txrx_compl_task);
                return;
        }
@@ -2123,10 +2119,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        case HTT_T2H_MSG_TYPE_AGGR_CONF:
                break;
-       case HTT_T2H_MSG_TYPE_EN_STATS:
        case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
-       case HTT_T2H_MSG_TYPE_TX_FETCH_CONF:
-       case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND:
+       case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
+       case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
+               /* TODO: Implement pull-push logic */
+               break;
+       case HTT_T2H_MSG_TYPE_EN_STATS:
        default:
                ath10k_warn(ar, "htt event (%d) not handled\n",
                            resp->hdr.msg_type);
@@ -2143,11 +2141,7 @@ EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler);
 void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       struct ath10k_pktlog_10_4_hdr *hdr =
-               (struct ath10k_pktlog_10_4_hdr *)skb->data;
-
-       trace_ath10k_htt_pktlog(ar, hdr->payload,
-                               sizeof(*hdr) + __le16_to_cpu(hdr->size));
+       trace_ath10k_htt_pktlog(ar, skb->data, skb->len);
        dev_kfree_skb_any(skb);
 }
 EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
@@ -2156,24 +2150,46 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
 {
        struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
        struct ath10k *ar = htt->ar;
+       struct sk_buff_head tx_q;
+       struct sk_buff_head rx_q;
+       struct sk_buff_head rx_ind_q;
        struct htt_resp *resp;
        struct sk_buff *skb;
+       unsigned long flags;
+
+       __skb_queue_head_init(&tx_q);
+       __skb_queue_head_init(&rx_q);
+       __skb_queue_head_init(&rx_ind_q);
 
-       while ((skb = skb_dequeue(&htt->tx_compl_q))) {
+       spin_lock_irqsave(&htt->tx_compl_q.lock, flags);
+       skb_queue_splice_init(&htt->tx_compl_q, &tx_q);
+       spin_unlock_irqrestore(&htt->tx_compl_q.lock, flags);
+
+       spin_lock_irqsave(&htt->rx_compl_q.lock, flags);
+       skb_queue_splice_init(&htt->rx_compl_q, &rx_q);
+       spin_unlock_irqrestore(&htt->rx_compl_q.lock, flags);
+
+       spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags);
+       skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q);
+       spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags);
+
+       while ((skb = __skb_dequeue(&tx_q))) {
                ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
                dev_kfree_skb_any(skb);
        }
 
-       spin_lock_bh(&htt->rx_ring.lock);
-       while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
+       while ((skb = __skb_dequeue(&rx_q))) {
                resp = (struct htt_resp *)skb->data;
+               spin_lock_bh(&htt->rx_ring.lock);
                ath10k_htt_rx_handler(htt, &resp->rx_ind);
+               spin_unlock_bh(&htt->rx_ring.lock);
                dev_kfree_skb_any(skb);
        }
 
-       while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
+       while ((skb = __skb_dequeue(&rx_ind_q))) {
+               spin_lock_bh(&htt->rx_ring.lock);
                ath10k_htt_rx_in_ord_ind(ar, skb);
+               spin_unlock_bh(&htt->rx_ring.lock);
                dev_kfree_skb_any(skb);
        }
-       spin_unlock_bh(&htt->rx_ring.lock);
 }
index b3adadb5f8243b616191d53ccf0c5995197f6587..95acb727c068f242f1324a39f04c540291071126 100644 (file)
@@ -97,6 +97,85 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
        idr_remove(&htt->pending_tx, msdu_id);
 }
 
+static void ath10k_htt_tx_free_cont_frag_desc(struct ath10k_htt *htt)
+{
+       size_t size;
+
+       if (!htt->frag_desc.vaddr)
+               return;
+
+       size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
+
+       dma_free_coherent(htt->ar->dev,
+                         size,
+                         htt->frag_desc.vaddr,
+                         htt->frag_desc.paddr);
+}
+
+static int ath10k_htt_tx_alloc_cont_frag_desc(struct ath10k_htt *htt)
+{
+       struct ath10k *ar = htt->ar;
+       size_t size;
+
+       if (!ar->hw_params.continuous_frag_desc)
+               return 0;
+
+       size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
+       htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size,
+                                                 &htt->frag_desc.paddr,
+                                                 GFP_KERNEL);
+       if (!htt->frag_desc.vaddr) {
+               ath10k_err(ar, "failed to alloc fragment desc memory\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt)
+{
+       struct ath10k *ar = htt->ar;
+       size_t size;
+
+       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+               return;
+
+       size = sizeof(*htt->tx_q_state.vaddr);
+
+       dma_unmap_single(ar->dev, htt->tx_q_state.paddr, size, DMA_TO_DEVICE);
+       kfree(htt->tx_q_state.vaddr);
+}
+
+static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt)
+{
+       struct ath10k *ar = htt->ar;
+       size_t size;
+       int ret;
+
+       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+               return 0;
+
+       htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS;
+       htt->tx_q_state.num_tids = HTT_TX_Q_STATE_NUM_TIDS;
+       htt->tx_q_state.type = HTT_Q_DEPTH_TYPE_BYTES;
+
+       size = sizeof(*htt->tx_q_state.vaddr);
+       htt->tx_q_state.vaddr = kzalloc(size, GFP_KERNEL);
+       if (!htt->tx_q_state.vaddr)
+               return -ENOMEM;
+
+       htt->tx_q_state.paddr = dma_map_single(ar->dev, htt->tx_q_state.vaddr,
+                                              size, DMA_TO_DEVICE);
+       ret = dma_mapping_error(ar->dev, htt->tx_q_state.paddr);
+       if (ret) {
+               ath10k_warn(ar, "failed to dma map tx_q_state: %d\n", ret);
+               kfree(htt->tx_q_state.vaddr);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
 {
        struct ath10k *ar = htt->ar;
@@ -118,29 +197,32 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
                goto free_idr_pending_tx;
        }
 
-       if (!ar->hw_params.continuous_frag_desc)
-               goto skip_frag_desc_alloc;
-
-       size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
-       htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size,
-                                                 &htt->frag_desc.paddr,
-                                                 GFP_KERNEL);
-       if (!htt->frag_desc.vaddr) {
-               ath10k_warn(ar, "failed to alloc fragment desc memory\n");
-               ret = -ENOMEM;
+       ret = ath10k_htt_tx_alloc_cont_frag_desc(htt);
+       if (ret) {
+               ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret);
                goto free_txbuf;
        }
 
-skip_frag_desc_alloc:
+       ret = ath10k_htt_tx_alloc_txq(htt);
+       if (ret) {
+               ath10k_err(ar, "failed to alloc txq: %d\n", ret);
+               goto free_frag_desc;
+       }
+
        return 0;
 
+free_frag_desc:
+       ath10k_htt_tx_free_cont_frag_desc(htt);
+
 free_txbuf:
        size = htt->max_num_pending_tx *
                          sizeof(struct ath10k_htt_txbuf);
        dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
                          htt->txbuf.paddr);
+
 free_idr_pending_tx:
        idr_destroy(&htt->pending_tx);
+
        return ret;
 }
 
@@ -174,12 +256,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
                                  htt->txbuf.paddr);
        }
 
-       if (htt->frag_desc.vaddr) {
-               size = htt->max_num_pending_tx *
-                                 sizeof(struct htt_msdu_ext_desc);
-               dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr,
-                                 htt->frag_desc.paddr);
-       }
+       ath10k_htt_tx_free_txq(htt);
+       ath10k_htt_tx_free_cont_frag_desc(htt);
 }
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
@@ -268,7 +346,9 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
        struct ath10k *ar = htt->ar;
        struct sk_buff *skb;
        struct htt_cmd *cmd;
+       struct htt_frag_desc_bank_cfg *cfg;
        int ret, size;
+       u8 info;
 
        if (!ar->hw_params.continuous_frag_desc)
                return 0;
@@ -286,14 +366,30 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
        skb_put(skb, size);
        cmd = (struct htt_cmd *)skb->data;
        cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG;
-       cmd->frag_desc_bank_cfg.info = 0;
-       cmd->frag_desc_bank_cfg.num_banks = 1;
-       cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc);
-       cmd->frag_desc_bank_cfg.bank_base_addrs[0] =
-                               __cpu_to_le32(htt->frag_desc.paddr);
-       cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0;
-       cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id =
-                               __cpu_to_le16(htt->max_num_pending_tx - 1);
+
+       info = 0;
+       info |= SM(htt->tx_q_state.type,
+                  HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE);
+
+       if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+               info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID;
+
+       cfg = &cmd->frag_desc_bank_cfg;
+       cfg->info = info;
+       cfg->num_banks = 1;
+       cfg->desc_size = sizeof(struct htt_msdu_ext_desc);
+       cfg->bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr);
+       cfg->bank_id[0].bank_min_id = 0;
+       cfg->bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx -
+                                                   1);
+
+       cfg->q_state.paddr = cpu_to_le32(htt->tx_q_state.paddr);
+       cfg->q_state.num_peers = cpu_to_le16(htt->tx_q_state.num_peers);
+       cfg->q_state.num_tids = cpu_to_le16(htt->tx_q_state.num_tids);
+       cfg->q_state.record_size = HTT_TX_Q_STATE_ENTRY_SIZE;
+       cfg->q_state.record_multiplier = HTT_TX_Q_STATE_ENTRY_MULTIPLIER;
+
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt frag desc bank cmd\n");
 
        ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
        if (ret) {
index 7b84d08a5154e7b2f14b79824665836d7c777100..f544d48518c3fedbcb22ba4a0e56742b797e5170 100644 (file)
@@ -109,6 +109,38 @@ const struct ath10k_hw_regs qca99x0_regs = {
        .pcie_intr_clr_address                  = 0x00000010,
 };
 
+const struct ath10k_hw_regs qca4019_regs = {
+       .rtc_soc_base_address                   = 0x00080000,
+       .soc_core_base_address                  = 0x00082000,
+       .ce_wrapper_base_address                = 0x0004d000,
+       .ce0_base_address                       = 0x0004a000,
+       .ce1_base_address                       = 0x0004a400,
+       .ce2_base_address                       = 0x0004a800,
+       .ce3_base_address                       = 0x0004ac00,
+       .ce4_base_address                       = 0x0004b000,
+       .ce5_base_address                       = 0x0004b400,
+       .ce6_base_address                       = 0x0004b800,
+       .ce7_base_address                       = 0x0004bc00,
+       /* qca4019 supports upto 12 copy engines. Since base address
+        * of ce8 to ce11 are not directly referred in the code,
+        * no need have them in separate members in this table.
+        *      Copy Engine             Address
+        *      CE8                     0x0004c000
+        *      CE9                     0x0004c400
+        *      CE10                    0x0004c800
+        *      CE11                    0x0004cc00
+        */
+       .soc_reset_control_si0_rst_mask         = 0x00000001,
+       .soc_reset_control_ce_rst_mask          = 0x00000100,
+       .soc_chip_id_address                    = 0x000000ec,
+       .fw_indicator_address                   = 0x0004f00c,
+       .ce_wrap_intr_sum_host_msi_lsb          = 0x0000000c,
+       .ce_wrap_intr_sum_host_msi_mask         = 0x00fff000,
+       .pcie_intr_fw_mask                      = 0x00100000,
+       .pcie_intr_ce_mask_all                  = 0x000fff00,
+       .pcie_intr_clr_address                  = 0x00000010,
+};
+
 const struct ath10k_hw_values qca988x_values = {
        .rtc_state_val_on               = 3,
        .ce_count                       = 8,
@@ -136,6 +168,13 @@ const struct ath10k_hw_values qca99x0_values = {
        .ce_desc_meta_data_lsb          = 4,
 };
 
+const struct ath10k_hw_values qca4019_values = {
+       .ce_count                       = 12,
+       .num_target_ce_config_wlan      = 10,
+       .ce_desc_meta_data_mask         = 0xFFF0,
+       .ce_desc_meta_data_lsb          = 4,
+};
+
 void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
                                u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
 {
index 0678831e867111fd1f15249e1f735724e64e2509..f0cfbc745c97dea91d368e5de4ef72bdb00702e2 100644 (file)
@@ -106,6 +106,14 @@ enum qca9377_chip_id_rev {
 #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
 #define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
 
+/* QCA4019 1.0 definitions */
+#define QCA4019_HW_1_0_DEV_VERSION     0x01000000
+#define QCA4019_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA4019/hw1.0"
+#define QCA4019_HW_1_0_FW_FILE         "firmware.bin"
+#define QCA4019_HW_1_0_OTP_FILE        "otp.bin"
+#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
+#define QCA4019_HW_1_0_PATCH_LOAD_ADDR  0x1234
+
 #define ATH10K_FW_API2_FILE            "firmware-2.bin"
 #define ATH10K_FW_API3_FILE            "firmware-3.bin"
 
@@ -200,6 +208,7 @@ enum ath10k_hw_rev {
        ATH10K_HW_QCA6174,
        ATH10K_HW_QCA99X0,
        ATH10K_HW_QCA9377,
+       ATH10K_HW_QCA4019,
 };
 
 struct ath10k_hw_regs {
@@ -232,6 +241,7 @@ struct ath10k_hw_regs {
 extern const struct ath10k_hw_regs qca988x_regs;
 extern const struct ath10k_hw_regs qca6174_regs;
 extern const struct ath10k_hw_regs qca99x0_regs;
+extern const struct ath10k_hw_regs qca4019_regs;
 
 struct ath10k_hw_values {
        u32 rtc_state_val_on;
@@ -245,6 +255,7 @@ struct ath10k_hw_values {
 extern const struct ath10k_hw_values qca988x_values;
 extern const struct ath10k_hw_values qca6174_values;
 extern const struct ath10k_hw_values qca99x0_values;
+extern const struct ath10k_hw_values qca4019_values;
 
 void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
                                u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
@@ -253,6 +264,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
 #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
 #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
 #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
+#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
 
 /* Known pecularities:
  *  - raw appears in nwifi decap, raw and nwifi appear in ethernet decap
@@ -363,14 +375,19 @@ enum ath10k_hw_4addr_pad {
 #define TARGET_10X_MAC_AGGR_DELIM              0
 #define TARGET_10X_AST_SKID_LIMIT              128
 #define TARGET_10X_NUM_STATIONS                        128
+#define TARGET_10X_TX_STATS_NUM_STATIONS       118
 #define TARGET_10X_NUM_PEERS                   ((TARGET_10X_NUM_STATIONS) + \
                                                 (TARGET_10X_NUM_VDEVS))
+#define TARGET_10X_TX_STATS_NUM_PEERS          ((TARGET_10X_TX_STATS_NUM_STATIONS) + \
+                                                (TARGET_10X_NUM_VDEVS))
 #define TARGET_10X_NUM_OFFLOAD_PEERS           0
 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS    0
 #define TARGET_10X_NUM_PEER_KEYS               2
 #define TARGET_10X_NUM_TIDS_MAX                        256
 #define TARGET_10X_NUM_TIDS                    min((TARGET_10X_NUM_TIDS_MAX), \
                                                    (TARGET_10X_NUM_PEERS) * 2)
+#define TARGET_10X_TX_STATS_NUM_TIDS           min((TARGET_10X_NUM_TIDS_MAX), \
+                                                   (TARGET_10X_TX_STATS_NUM_PEERS) * 2)
 #define TARGET_10X_TX_CHAIN_MASK               (BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_CHAIN_MASK               (BIT(0) | BIT(1) | BIT(2))
 #define TARGET_10X_RX_TIMEOUT_LO_PRI           100
@@ -414,16 +431,11 @@ enum ath10k_hw_4addr_pad {
 #define TARGET_10_4_ACTIVE_PEERS               0
 
 #define TARGET_10_4_NUM_QCACHE_PEERS_MAX       512
-#define TARGET_10_4_QCACHE_ACTIVE_PEERS                50
 #define TARGET_10_4_NUM_OFFLOAD_PEERS          0
 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS  0
 #define TARGET_10_4_NUM_PEER_KEYS              2
 #define TARGET_10_4_TGT_NUM_TIDS               ((TARGET_10_4_NUM_PEERS) * 2)
 #define TARGET_10_4_AST_SKID_LIMIT             32
-#define TARGET_10_4_TX_CHAIN_MASK              (BIT(0) | BIT(1) | \
-                                                BIT(2) | BIT(3))
-#define TARGET_10_4_RX_CHAIN_MASK              (BIT(0) | BIT(1) | \
-                                                BIT(2) | BIT(3))
 
 /* 100 ms for video, best-effort, and background */
 #define TARGET_10_4_RX_TIMEOUT_LO_PRI          100
@@ -449,7 +461,6 @@ enum ath10k_hw_4addr_pad {
 #define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
 #define TARGET_10_4_VOW_CONFIG                 0
 #define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV       3
-#define TARGET_10_4_NUM_MSDU_DESC              (1024 + 400)
 #define TARGET_10_4_11AC_TX_MAX_FRAGS          2
 #define TARGET_10_4_MAX_PEER_EXT_STATS         16
 #define TARGET_10_4_SMART_ANT_CAP              0
@@ -601,6 +612,7 @@ enum ath10k_hw_4addr_pad {
 #define FW_INDICATOR_ADDRESS                   ar->regs->fw_indicator_address
 #define FW_IND_EVENT_PENDING                   1
 #define FW_IND_INITIALIZED                     2
+#define FW_IND_HOST_READY                      0x80000000
 
 /* HOST_REG interrupt from firmware */
 #define PCIE_INTR_FIRMWARE_MASK                        ar->regs->pcie_intr_fw_mask
index 6146a293601a7fea098a353aeb11fc803f5523a4..78999c9de23b350a7cc871ee446792a2825b77f2 100644 (file)
@@ -1358,10 +1358,7 @@ static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
        const u8 *p2p_ie;
        int ret;
 
-       if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
-               return 0;
-
-       if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
+       if (arvif->vif->type != NL80211_IFTYPE_AP || !arvif->vif->p2p)
                return 0;
 
        mgmt = (void *)bcn->data;
@@ -3259,8 +3256,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 
        /* This is case only for P2P_GO */
-       if (arvif->vdev_type != WMI_VDEV_TYPE_AP ||
-           arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
+       if (vif->type != NL80211_IFTYPE_AP || !vif->p2p)
                return;
 
        if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
@@ -3988,7 +3984,7 @@ static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
 static int ath10k_start(struct ieee80211_hw *hw)
 {
        struct ath10k *ar = hw->priv;
-       u32 burst_enable;
+       u32 param;
        int ret = 0;
 
        /*
@@ -4031,13 +4027,15 @@ static int ath10k_start(struct ieee80211_hw *hw)
                goto err_power_down;
        }
 
-       ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
+       param = ar->wmi.pdev_param->pmf_qos;
+       ret = ath10k_wmi_pdev_set_param(ar, param, 1);
        if (ret) {
                ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
                goto err_core_stop;
        }
 
-       ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
+       param = ar->wmi.pdev_param->dynamic_bw;
+       ret = ath10k_wmi_pdev_set_param(ar, param, 1);
        if (ret) {
                ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
                goto err_core_stop;
@@ -4053,8 +4051,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
        }
 
        if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) {
-               burst_enable = ar->wmi.pdev_param->burst_enable;
-               ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0);
+               param = ar->wmi.pdev_param->burst_enable;
+               ret = ath10k_wmi_pdev_set_param(ar, param, 0);
                if (ret) {
                        ath10k_warn(ar, "failed to disable burst: %d\n", ret);
                        goto err_core_stop;
@@ -4072,8 +4070,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
         * this problem.
         */
 
-       ret = ath10k_wmi_pdev_set_param(ar,
-                                       ar->wmi.pdev_param->arp_ac_override, 0);
+       param = ar->wmi.pdev_param->arp_ac_override;
+       ret = ath10k_wmi_pdev_set_param(ar, param, 0);
        if (ret) {
                ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
                            ret);
@@ -4092,8 +4090,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
                }
        }
 
-       ret = ath10k_wmi_pdev_set_param(ar,
-                                       ar->wmi.pdev_param->ani_enable, 1);
+       param = ar->wmi.pdev_param->ani_enable;
+       ret = ath10k_wmi_pdev_set_param(ar, param, 1);
        if (ret) {
                ath10k_warn(ar, "failed to enable ani by default: %d\n",
                            ret);
@@ -4102,6 +4100,18 @@ static int ath10k_start(struct ieee80211_hw *hw)
 
        ar->ani_enabled = true;
 
+       if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
+               param = ar->wmi.pdev_param->peer_stats_update_period;
+               ret = ath10k_wmi_pdev_set_param(ar, param,
+                                               PEER_DEFAULT_STATS_UPDATE_PERIOD);
+               if (ret) {
+                       ath10k_warn(ar,
+                                   "failed to set peer stats period : %d\n",
+                                   ret);
+                       goto err_core_stop;
+               }
+       }
+
        ar->num_started_vdevs = 0;
        ath10k_regd_update(ar);
 
@@ -4349,25 +4359,29 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                   bit, ar->free_vdev_map);
 
        arvif->vdev_id = bit;
-       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
+       arvif->vdev_subtype =
+               ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE);
 
        switch (vif->type) {
        case NL80211_IFTYPE_P2P_DEVICE:
                arvif->vdev_type = WMI_VDEV_TYPE_STA;
-               arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
+               arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
+                                       (ar, WMI_VDEV_SUBTYPE_P2P_DEVICE);
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case NL80211_IFTYPE_STATION:
                arvif->vdev_type = WMI_VDEV_TYPE_STA;
                if (vif->p2p)
-                       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
+                       arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
+                                       (ar, WMI_VDEV_SUBTYPE_P2P_CLIENT);
                break;
        case NL80211_IFTYPE_ADHOC:
                arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
                break;
        case NL80211_IFTYPE_MESH_POINT:
-               if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
-                       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
+               if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) {
+                       arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
+                                               (ar, WMI_VDEV_SUBTYPE_MESH_11S);
                } else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
                        ret = -EINVAL;
                        ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
@@ -4379,7 +4393,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                arvif->vdev_type = WMI_VDEV_TYPE_AP;
 
                if (vif->p2p)
-                       arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
+                       arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
+                                               (ar, WMI_VDEV_SUBTYPE_P2P_GO);
                break;
        case NL80211_IFTYPE_MONITOR:
                arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
@@ -6366,12 +6381,13 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 static int ath10k_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
-                              enum ieee80211_ampdu_mlme_action action,
-                              struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                              u8 buf_size, bool amsdu)
+                              struct ieee80211_ampdu_params *params)
 {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
 
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
                   arvif->vdev_id, sta->addr, tid, action);
index ee925c618535f464a213b59d35a0a4c8688da59f..b3cff1d3364aad85151b4abd54d05bee0d2e02a3 100644 (file)
@@ -94,7 +94,6 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
 static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
 static int ath10k_pci_cold_reset(struct ath10k *ar);
 static int ath10k_pci_safe_chip_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);
 static int ath10k_pci_request_irq(struct ath10k *ar);
@@ -620,7 +619,7 @@ static void ath10k_pci_sleep_sync(struct ath10k *ar)
        spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
 }
 
-void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
+static void ath10k_bus_pci_write32(struct ath10k *ar, u32 offset, u32 value)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret;
@@ -642,7 +641,7 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
        ath10k_pci_sleep(ar);
 }
 
-u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
+static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        u32 val;
@@ -667,6 +666,20 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
        return val;
 }
 
+inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       ar_pci->bus_ops->write32(ar, offset, value);
+}
+
+inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       return ar_pci->bus_ops->read32(ar, offset);
+}
+
 u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
 {
        return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
@@ -687,7 +700,7 @@ void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
        ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
 }
 
-static bool ath10k_pci_irq_pending(struct ath10k *ar)
+bool ath10k_pci_irq_pending(struct ath10k *ar)
 {
        u32 cause;
 
@@ -700,7 +713,7 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar)
        return false;
 }
 
-static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
+void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
 {
        /* IMPORTANT: INTR_CLR register has to be set after
         * INTR_ENABLE is set to 0, otherwise interrupt can not be
@@ -716,7 +729,7 @@ static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
                                PCIE_INTR_ENABLE_ADDRESS);
 }
 
-static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
+void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
 {
        ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
                           PCIE_INTR_ENABLE_ADDRESS,
@@ -809,7 +822,7 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
        }
 }
 
-static void ath10k_pci_rx_post(struct ath10k *ar)
+void ath10k_pci_rx_post(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int i;
@@ -818,7 +831,7 @@ static void ath10k_pci_rx_post(struct ath10k *ar)
                ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
 }
 
-static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
+void ath10k_pci_rx_replenish_retry(unsigned long ptr)
 {
        struct ath10k *ar = (void *)ptr;
 
@@ -838,6 +851,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
                       0x7ff) << 21;
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA4019:
                val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
                break;
        }
@@ -1007,8 +1021,8 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
 #define ath10k_pci_diag_read_hi(ar, dest, src, len)            \
        __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
 
-static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
-                                    const void *data, int nbytes)
+int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
+                             const void *data, int nbytes)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ret = 0;
@@ -1263,8 +1277,8 @@ static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
        ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
 }
 
-static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
-                               struct ath10k_hif_sg_item *items, int n_items)
+int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+                        struct ath10k_hif_sg_item *items, int n_items)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
@@ -1332,13 +1346,13 @@ err:
        return err;
 }
 
-static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
-                                   size_t buf_len)
+int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+                            size_t buf_len)
 {
        return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
 }
 
-static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
+u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
@@ -1406,8 +1420,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
        queue_work(ar->workqueue, &ar->restart_work);
 }
 
-static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
-                                              int force)
+void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
+                                       int force)
 {
        ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
 
@@ -1432,7 +1446,7 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
        ath10k_ce_per_engine_service(ar, pipe);
 }
 
-static void ath10k_pci_kill_tasklet(struct ath10k *ar)
+void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int i;
@@ -1446,8 +1460,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
        del_timer_sync(&ar_pci->rx_post_retry);
 }
 
-static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
-                                             u8 *ul_pipe, u8 *dl_pipe)
+int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
+                                      u8 *ul_pipe, u8 *dl_pipe)
 {
        const struct service_to_pipe *entry;
        bool ul_set = false, dl_set = false;
@@ -1491,8 +1505,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
        return 0;
 }
 
-static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
-                                           u8 *ul_pipe, u8 *dl_pipe)
+void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
+                                    u8 *ul_pipe, u8 *dl_pipe)
 {
        ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
 
@@ -1516,6 +1530,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
                                   CORE_CTRL_ADDRESS, val);
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA4019:
                /* TODO: Find appropriate register configuration for QCA99X0
                 *  to mask irq/MSI.
                 */
@@ -1538,6 +1553,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
                                   CORE_CTRL_ADDRESS, val);
                break;
        case ATH10K_HW_QCA99X0:
+       case ATH10K_HW_QCA4019:
                /* TODO: Find appropriate register configuration for QCA99X0
                 *  to unmask irq/MSI.
                 */
@@ -1668,7 +1684,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
        }
 }
 
-static void ath10k_pci_ce_deinit(struct ath10k *ar)
+void ath10k_pci_ce_deinit(struct ath10k *ar)
 {
        int i;
 
@@ -1676,7 +1692,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
                ath10k_ce_deinit_pipe(ar, i);
 }
 
-static void ath10k_pci_flush(struct ath10k *ar)
+void ath10k_pci_flush(struct ath10k *ar)
 {
        ath10k_pci_kill_tasklet(ar);
        ath10k_pci_buffer_cleanup(ar);
@@ -1711,9 +1727,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
        spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
 }
 
-static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
-                                          void *req, u32 req_len,
-                                          void *resp, u32 *resp_len)
+int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
+                                   void *req, u32 req_len,
+                                   void *resp, u32 *resp_len)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
@@ -1756,7 +1772,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
                                            DMA_FROM_DEVICE);
                ret = dma_mapping_error(ar->dev, resp_paddr);
                if (ret) {
-                       ret = EIO;
+                       ret = -EIO;
                        goto err_req;
                }
 
@@ -1907,7 +1923,14 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
        return 1;
 }
 
-static int ath10k_pci_init_config(struct ath10k *ar)
+static int ath10k_bus_get_num_banks(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       return ar_pci->bus_ops->get_num_banks(ar);
+}
+
+int ath10k_pci_init_config(struct ath10k *ar)
 {
        u32 interconnect_targ_addr;
        u32 pcie_state_targ_addr = 0;
@@ -2018,7 +2041,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
        /* first bank is switched to IRAM */
        ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
                         HI_EARLY_ALLOC_MAGIC_MASK);
-       ealloc_value |= ((ath10k_pci_get_num_banks(ar) <<
+       ealloc_value |= ((ath10k_bus_get_num_banks(ar) <<
                          HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
                         HI_EARLY_ALLOC_IRAM_BANKS_MASK);
 
@@ -2071,7 +2094,7 @@ static void ath10k_pci_override_ce_config(struct ath10k *ar)
        target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
 }
 
-static int ath10k_pci_alloc_pipes(struct ath10k *ar)
+int ath10k_pci_alloc_pipes(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_pci_pipe *pipe;
@@ -2102,7 +2125,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)
        return 0;
 }
 
-static void ath10k_pci_free_pipes(struct ath10k *ar)
+void ath10k_pci_free_pipes(struct ath10k *ar)
 {
        int i;
 
@@ -2110,7 +2133,7 @@ static void ath10k_pci_free_pipes(struct ath10k *ar)
                ath10k_ce_free_pipe(ar, i);
 }
 
-static int ath10k_pci_init_pipes(struct ath10k *ar)
+int ath10k_pci_init_pipes(struct ath10k *ar)
 {
        int i, ret;
 
@@ -2453,7 +2476,7 @@ err_sleep:
        return ret;
 }
 
-static void ath10k_pci_hif_power_down(struct ath10k *ar)
+void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
 
@@ -2722,7 +2745,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar)
                free_irq(ar_pci->pdev->irq + i, ar);
 }
 
-static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
+void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int i;
@@ -2808,7 +2831,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
        return 0;
 }
 
-static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
+int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        unsigned long timeout;
@@ -2989,6 +3012,43 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
        return false;
 }
 
+int ath10k_pci_setup_resource(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int ret;
+
+       spin_lock_init(&ar_pci->ce_lock);
+       spin_lock_init(&ar_pci->ps_lock);
+
+       setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
+                   (unsigned long)ar);
+
+       if (QCA_REV_6174(ar))
+               ath10k_pci_override_ce_config(ar);
+
+       ret = ath10k_pci_alloc_pipes(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
+                          ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void ath10k_pci_release_resource(struct ath10k *ar)
+{
+       ath10k_pci_kill_tasklet(ar);
+       ath10k_pci_ce_deinit(ar);
+       ath10k_pci_free_pipes(ar);
+}
+
+static const struct ath10k_bus_ops ath10k_pci_bus_ops = {
+       .read32         = ath10k_bus_pci_read32,
+       .write32        = ath10k_bus_pci_write32,
+       .get_num_banks  = ath10k_pci_get_num_banks,
+};
+
 static int ath10k_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *pci_dev)
 {
@@ -3039,40 +3099,32 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        ar_pci->ar = ar;
        ar->dev_id = pci_dev->device;
        ar_pci->pci_ps = pci_ps;
+       ar_pci->bus_ops = &ath10k_pci_bus_ops;
 
        ar->id.vendor = pdev->vendor;
        ar->id.device = pdev->device;
        ar->id.subsystem_vendor = pdev->subsystem_vendor;
        ar->id.subsystem_device = pdev->subsystem_device;
 
-       spin_lock_init(&ar_pci->ce_lock);
-       spin_lock_init(&ar_pci->ps_lock);
-
-       setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
-                   (unsigned long)ar);
        setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
                    (unsigned long)ar);
 
-       ret = ath10k_pci_claim(ar);
+       ret = ath10k_pci_setup_resource(ar);
        if (ret) {
-               ath10k_err(ar, "failed to claim device: %d\n", ret);
+               ath10k_err(ar, "failed to setup resource: %d\n", ret);
                goto err_core_destroy;
        }
 
-       if (QCA_REV_6174(ar))
-               ath10k_pci_override_ce_config(ar);
-
-       ret = ath10k_pci_alloc_pipes(ar);
+       ret = ath10k_pci_claim(ar);
        if (ret) {
-               ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
-                          ret);
-               goto err_sleep;
+               ath10k_err(ar, "failed to claim device: %d\n", ret);
+               goto err_free_pipes;
        }
 
        ret = ath10k_pci_force_wake(ar);
        if (ret) {
                ath10k_warn(ar, "failed to wake up device : %d\n", ret);
-               goto err_free_pipes;
+               goto err_sleep;
        }
 
        ath10k_pci_ce_deinit(ar);
@@ -3081,7 +3133,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        ret = ath10k_pci_init_irq(ar);
        if (ret) {
                ath10k_err(ar, "failed to init irqs: %d\n", ret);
-               goto err_free_pipes;
+               goto err_sleep;
        }
 
        ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
@@ -3127,13 +3179,13 @@ err_free_irq:
 err_deinit_irq:
        ath10k_pci_deinit_irq(ar);
 
-err_free_pipes:
-       ath10k_pci_free_pipes(ar);
-
 err_sleep:
        ath10k_pci_sleep_sync(ar);
        ath10k_pci_release(ar);
 
+err_free_pipes:
+       ath10k_pci_free_pipes(ar);
+
 err_core_destroy:
        ath10k_core_destroy(ar);
 
@@ -3157,10 +3209,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
 
        ath10k_core_unregister(ar);
        ath10k_pci_free_irq(ar);
-       ath10k_pci_kill_tasklet(ar);
        ath10k_pci_deinit_irq(ar);
-       ath10k_pci_ce_deinit(ar);
-       ath10k_pci_free_pipes(ar);
+       ath10k_pci_release_resource(ar);
        ath10k_pci_sleep_sync(ar);
        ath10k_pci_release(ar);
        ath10k_core_destroy(ar);
@@ -3184,6 +3234,10 @@ static int __init ath10k_pci_init(void)
                printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
                       ret);
 
+       ret = ath10k_ahb_init();
+       if (ret)
+               printk(KERN_ERR "ahb init failed: %d\n", ret);
+
        return ret;
 }
 module_init(ath10k_pci_init);
@@ -3191,6 +3245,7 @@ module_init(ath10k_pci_init);
 static void __exit ath10k_pci_exit(void)
 {
        pci_unregister_driver(&ath10k_pci_driver);
+       ath10k_ahb_exit();
 }
 
 module_exit(ath10k_pci_exit);
index f91bf333cb75e7cfb0fb974ccf5a80217876b3d9..249c73a6980088408afaed9530d68701dcd2fa06 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "hw.h"
 #include "ce.h"
+#include "ahb.h"
 
 /*
  * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
@@ -157,6 +158,12 @@ struct ath10k_pci_supp_chip {
        u32 rev_id;
 };
 
+struct ath10k_bus_ops {
+       u32 (*read32)(struct ath10k *ar, u32 offset);
+       void (*write32)(struct ath10k *ar, u32 offset, u32 value);
+       int (*get_num_banks)(struct ath10k *ar);
+};
+
 struct ath10k_pci {
        struct pci_dev *pdev;
        struct device *dev;
@@ -225,6 +232,14 @@ struct ath10k_pci {
         * on MMIO read/write.
         */
        bool pci_ps;
+
+       const struct ath10k_bus_ops *bus_ops;
+
+       /* Keep this entry in the last, memory for struct ath10k_ahb is
+        * allocated (ahb support enabled case) in the continuation of
+        * this struct.
+        */
+       struct ath10k_ahb ahb[0];
 };
 
 static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
@@ -253,6 +268,40 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
 u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
 u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr);
 
+int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+                        struct ath10k_hif_sg_item *items, int n_items);
+int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+                            size_t buf_len);
+int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
+                             const void *data, int nbytes);
+int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, void *req, u32 req_len,
+                                   void *resp, u32 *resp_len);
+int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
+                                      u8 *ul_pipe, u8 *dl_pipe);
+void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, u8 *ul_pipe,
+                                    u8 *dl_pipe);
+void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
+                                       int force);
+u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe);
+void ath10k_pci_hif_power_down(struct ath10k *ar);
+int ath10k_pci_alloc_pipes(struct ath10k *ar);
+void ath10k_pci_free_pipes(struct ath10k *ar);
+void ath10k_pci_free_pipes(struct ath10k *ar);
+void ath10k_pci_rx_replenish_retry(unsigned long ptr);
+void ath10k_pci_ce_deinit(struct ath10k *ar);
+void ath10k_pci_init_irq_tasklets(struct ath10k *ar);
+void ath10k_pci_kill_tasklet(struct ath10k *ar);
+int ath10k_pci_init_pipes(struct ath10k *ar);
+int ath10k_pci_init_config(struct ath10k *ar);
+void ath10k_pci_rx_post(struct ath10k *ar);
+void ath10k_pci_flush(struct ath10k *ar);
+void ath10k_pci_enable_legacy_irq(struct ath10k *ar);
+bool ath10k_pci_irq_pending(struct ath10k *ar);
+void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar);
+int ath10k_pci_wait_for_target_init(struct ath10k *ar);
+int ath10k_pci_setup_resource(struct ath10k *ar);
+void ath10k_pci_release_resource(struct ath10k *ar);
+
 /* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too
  * frequently. To avoid this put SoC to sleep after a very conservative grace
  * period. Adjust with great care.
index 05a421bc322ae03a3adffaac03c732b10fadca00..361f143b019c1a1c1c0c7c53cb7d442bd5dce772 100644 (file)
@@ -456,4 +456,7 @@ Fw Mode/SubMode Mask
 #define QCA99X0_BOARD_DATA_SZ    12288
 #define QCA99X0_BOARD_EXT_DATA_SZ 0
 
+#define QCA4019_BOARD_DATA_SZ    12064
+#define QCA4019_BOARD_EXT_DATA_SZ 0
+
 #endif /* __TARGADDRS_H__ */
index 71bdb368813de3af8ba8c062d49a27000392cf98..e0d00cef0bd8d27dc0ee9d964d4343f542efce41 100644 (file)
@@ -250,6 +250,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
        TP_STRUCT__entry(
                __string(device, dev_name(ar->dev))
                __string(driver, dev_driver_string(ar->dev))
+               __field(u8, hw_type);
                __field(size_t, buf_len)
                __dynamic_array(u8, buf, buf_len)
        ),
@@ -257,14 +258,16 @@ TRACE_EVENT(ath10k_wmi_dbglog,
        TP_fast_assign(
                __assign_str(device, dev_name(ar->dev));
                __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->hw_type = ar->hw_rev;
                __entry->buf_len = buf_len;
                memcpy(__get_dynamic_array(buf), buf, buf_len);
        ),
 
        TP_printk(
-               "%s %s len %zu",
+               "%s %s %d len %zu",
                __get_str(driver),
                __get_str(device),
+               __entry->hw_type,
                __entry->buf_len
        )
 );
@@ -277,6 +280,7 @@ TRACE_EVENT(ath10k_htt_pktlog,
        TP_STRUCT__entry(
                __string(device, dev_name(ar->dev))
                __string(driver, dev_driver_string(ar->dev))
+               __field(u8, hw_type);
                __field(u16, buf_len)
                __dynamic_array(u8, pktlog, buf_len)
        ),
@@ -284,14 +288,16 @@ TRACE_EVENT(ath10k_htt_pktlog,
        TP_fast_assign(
                __assign_str(device, dev_name(ar->dev));
                __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->hw_type = ar->hw_rev;
                __entry->buf_len = buf_len;
                memcpy(__get_dynamic_array(pktlog), buf, buf_len);
        ),
 
        TP_printk(
-               "%s %s size %hu",
+               "%s %s %d size %hu",
                __get_str(driver),
                __get_str(device),
+               __entry->hw_type,
                __entry->buf_len
         )
 );
@@ -440,6 +446,7 @@ TRACE_EVENT(ath10k_htt_rx_desc,
        TP_STRUCT__entry(
                __string(device, dev_name(ar->dev))
                __string(driver, dev_driver_string(ar->dev))
+               __field(u8, hw_type);
                __field(u16, len)
                __dynamic_array(u8, rxdesc, len)
        ),
@@ -447,14 +454,16 @@ TRACE_EVENT(ath10k_htt_rx_desc,
        TP_fast_assign(
                __assign_str(device, dev_name(ar->dev));
                __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->hw_type = ar->hw_rev;
                __entry->len = len;
                memcpy(__get_dynamic_array(rxdesc), data, len);
        ),
 
        TP_printk(
-               "%s %s rxdesc len %d",
+               "%s %s %d rxdesc len %d",
                __get_str(driver),
                __get_str(device),
+               __entry->hw_type,
                __entry->len
         )
 );
index 8f4f6a892581c2ac7e976e08138e37740d0b0a33..32ab34edceb54927fa4f668ac7c37ec4f728226a 100644 (file)
@@ -186,6 +186,8 @@ struct wmi_ops {
                                                        u8 enable,
                                                        u32 detect_level,
                                                        u32 detect_margin);
+       int (*get_vdev_subtype)(struct ath10k *ar,
+                               enum wmi_vdev_subtype subtype);
 };
 
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1327,4 +1329,13 @@ ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
                                   ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid);
 }
 
+static inline int
+ath10k_wmi_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype)
+{
+       if (!ar->wmi.ops->get_vdev_subtype)
+               return -EOPNOTSUPP;
+
+       return ar->wmi.ops->get_vdev_subtype(ar, subtype);
+}
+
 #endif
index 3b3a27b859f36fa4eae088465b44a4641bb26e40..108593202052fb86fe43060ec6f19ef113417d0f 100644 (file)
@@ -3483,6 +3483,7 @@ static const struct wmi_ops wmi_tlv_ops = {
        .gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
        .gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
        .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
+       .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
 };
 
 static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
index a7c3d299639b272d7cd85fc0feaab2248a451a00..70261387d1a5733a6069e9274222d49ec9a8cb99 100644 (file)
@@ -2862,11 +2862,20 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
        /* fw doesn't implement vdev stats */
 
        for (i = 0; i < num_peer_stats; i++) {
-               const struct wmi_10_2_4_peer_stats *src;
+               const struct wmi_10_2_4_ext_peer_stats *src;
                struct ath10k_fw_stats_peer *dst;
+               int stats_len;
+               bool ext_peer_stats_support;
+
+               ext_peer_stats_support = test_bit(WMI_SERVICE_PEER_STATS,
+                                                 ar->wmi.svc_map);
+               if (ext_peer_stats_support)
+                       stats_len = sizeof(struct wmi_10_2_4_ext_peer_stats);
+               else
+                       stats_len = sizeof(struct wmi_10_2_4_peer_stats);
 
                src = (void *)skb->data;
-               if (!skb_pull(skb, sizeof(*src)))
+               if (!skb_pull(skb, stats_len))
                        return -EPROTO;
 
                dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
@@ -2876,6 +2885,9 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
                ath10k_wmi_pull_peer_stats(&src->common.old, dst);
 
                dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
+
+               if (ext_peer_stats_support)
+                       dst->rx_duration = __le32_to_cpu(src->rx_duration);
                /* FIXME: expose 10.2 specific values */
 
                list_add_tail(&dst->list, &stats->peers);
@@ -3184,7 +3196,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
                                  struct sk_buff *bcn,
                                  const struct wmi_p2p_noa_info *noa)
 {
-       if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
+       if (!arvif->vif->p2p)
                return;
 
        ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
@@ -3244,6 +3256,50 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
        return 0;
 }
 
+static int ath10k_wmi_10_2_4_op_pull_swba_ev(struct ath10k *ar,
+                                            struct sk_buff *skb,
+                                            struct wmi_swba_ev_arg *arg)
+{
+       struct wmi_10_2_4_host_swba_event *ev = (void *)skb->data;
+       u32 map;
+       size_t i;
+
+       if (skb->len < sizeof(*ev))
+               return -EPROTO;
+
+       skb_pull(skb, sizeof(*ev));
+       arg->vdev_map = ev->vdev_map;
+
+       for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) {
+               if (!(map & BIT(0)))
+                       continue;
+
+               /* If this happens there were some changes in firmware and
+                * ath10k should update the max size of tim_info array.
+                */
+               if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
+                       break;
+
+               if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) >
+                    sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) {
+                       ath10k_warn(ar, "refusing to parse invalid swba structure\n");
+                       return -EPROTO;
+               }
+
+               arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len;
+               arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast;
+               arg->tim_info[i].tim_bitmap =
+                               ev->bcn_info[i].tim_info.tim_bitmap;
+               arg->tim_info[i].tim_changed =
+                               ev->bcn_info[i].tim_info.tim_changed;
+               arg->tim_info[i].tim_num_ps_pending =
+                               ev->bcn_info[i].tim_info.tim_num_ps_pending;
+               i++;
+       }
+
+       return 0;
+}
+
 static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar,
                                           struct sk_buff *skb,
                                           struct wmi_swba_ev_arg *arg)
@@ -4562,9 +4618,9 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
 
        if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
                ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX +
-                                   TARGET_10_4_NUM_VDEVS;
-               ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS +
-                                      TARGET_10_4_NUM_VDEVS;
+                                   ar->max_num_vdevs;
+               ar->num_active_peers = ar->hw_params.qcache_active_peers +
+                                      ar->max_num_vdevs;
                ar->num_tids = ar->num_active_peers * 2;
                ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX;
        }
@@ -5460,9 +5516,15 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
        u32 len, val, features;
 
        config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
-       config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
        config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
-       config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+       if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
+               config.num_peers = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_PEERS);
+               config.num_tids = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_TIDS);
+       } else {
+               config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+               config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+       }
+
        config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
        config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
        config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
@@ -5517,6 +5579,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
            test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
                features |= WMI_10_2_COEX_GPIO;
 
+       if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
+               features |= WMI_10_2_PEER_STATS;
+
        cmd->resource_config.feature_mask = __cpu_to_le32(features);
 
        memcpy(&cmd->resource_config.common, &config, sizeof(config));
@@ -5543,8 +5608,8 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar)
                        __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS);
        config.num_peer_keys  = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS);
        config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT);
-       config.tx_chain_mask  = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK);
-       config.rx_chain_mask  = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK);
+       config.tx_chain_mask  = __cpu_to_le32(ar->hw_params.tx_chain_mask);
+       config.rx_chain_mask  = __cpu_to_le32(ar->hw_params.rx_chain_mask);
 
        config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
        config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
@@ -5575,7 +5640,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar)
        config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG);
        config.gtk_offload_max_vdev =
                        __cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV);
-       config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC);
+       config.num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx);
        config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS);
        config.max_peer_ext_stats =
                        __cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS);
@@ -7126,6 +7191,9 @@ ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer,
                        "Peer TX rate", peer->peer_tx_rate);
        len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
                        "Peer RX rate", peer->peer_rx_rate);
+       len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
+                       "Peer RX duration", peer->rx_duration);
+
        len += scnprintf(buf + len, buf_len - len, "\n");
        *length = len;
 }
@@ -7351,6 +7419,71 @@ unlock:
                buf[len] = 0;
 }
 
+int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
+                                  enum wmi_vdev_subtype subtype)
+{
+       switch (subtype) {
+       case WMI_VDEV_SUBTYPE_NONE:
+               return WMI_VDEV_SUBTYPE_LEGACY_NONE;
+       case WMI_VDEV_SUBTYPE_P2P_DEVICE:
+               return WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV;
+       case WMI_VDEV_SUBTYPE_P2P_CLIENT:
+               return WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI;
+       case WMI_VDEV_SUBTYPE_P2P_GO:
+               return WMI_VDEV_SUBTYPE_LEGACY_P2P_GO;
+       case WMI_VDEV_SUBTYPE_PROXY_STA:
+               return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA;
+       case WMI_VDEV_SUBTYPE_MESH_11S:
+       case WMI_VDEV_SUBTYPE_MESH_NON_11S:
+               return -ENOTSUPP;
+       }
+       return -ENOTSUPP;
+}
+
+static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar,
+                                                enum wmi_vdev_subtype subtype)
+{
+       switch (subtype) {
+       case WMI_VDEV_SUBTYPE_NONE:
+               return WMI_VDEV_SUBTYPE_10_2_4_NONE;
+       case WMI_VDEV_SUBTYPE_P2P_DEVICE:
+               return WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV;
+       case WMI_VDEV_SUBTYPE_P2P_CLIENT:
+               return WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI;
+       case WMI_VDEV_SUBTYPE_P2P_GO:
+               return WMI_VDEV_SUBTYPE_10_2_4_P2P_GO;
+       case WMI_VDEV_SUBTYPE_PROXY_STA:
+               return WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA;
+       case WMI_VDEV_SUBTYPE_MESH_11S:
+               return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S;
+       case WMI_VDEV_SUBTYPE_MESH_NON_11S:
+               return -ENOTSUPP;
+       }
+       return -ENOTSUPP;
+}
+
+static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar,
+                                              enum wmi_vdev_subtype subtype)
+{
+       switch (subtype) {
+       case WMI_VDEV_SUBTYPE_NONE:
+               return WMI_VDEV_SUBTYPE_10_4_NONE;
+       case WMI_VDEV_SUBTYPE_P2P_DEVICE:
+               return WMI_VDEV_SUBTYPE_10_4_P2P_DEV;
+       case WMI_VDEV_SUBTYPE_P2P_CLIENT:
+               return WMI_VDEV_SUBTYPE_10_4_P2P_CLI;
+       case WMI_VDEV_SUBTYPE_P2P_GO:
+               return WMI_VDEV_SUBTYPE_10_4_P2P_GO;
+       case WMI_VDEV_SUBTYPE_PROXY_STA:
+               return WMI_VDEV_SUBTYPE_10_4_PROXY_STA;
+       case WMI_VDEV_SUBTYPE_MESH_11S:
+               return WMI_VDEV_SUBTYPE_10_4_MESH_11S;
+       case WMI_VDEV_SUBTYPE_MESH_NON_11S:
+               return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S;
+       }
+       return -ENOTSUPP;
+}
+
 static const struct wmi_ops wmi_ops = {
        .rx = ath10k_wmi_op_rx,
        .map_svc = wmi_main_svc_map,
@@ -7410,6 +7543,7 @@ static const struct wmi_ops wmi_ops = {
        .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
        .gen_delba_send = ath10k_wmi_op_gen_delba_send,
        .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
+       .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
        /* .gen_bcn_tmpl not implemented */
        /* .gen_prb_tmpl not implemented */
        /* .gen_p2p_go_bcn_ie not implemented */
@@ -7477,6 +7611,7 @@ static const struct wmi_ops wmi_10_1_ops = {
        .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
        .gen_delba_send = ath10k_wmi_op_gen_delba_send,
        .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
+       .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
        /* .gen_bcn_tmpl not implemented */
        /* .gen_prb_tmpl not implemented */
        /* .gen_p2p_go_bcn_ie not implemented */
@@ -7545,6 +7680,7 @@ static const struct wmi_ops wmi_10_2_ops = {
        .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
        .gen_delba_send = ath10k_wmi_op_gen_delba_send,
        .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
+       .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
        /* .gen_pdev_enable_adaptive_cca not implemented */
 };
 
@@ -7566,7 +7702,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
        .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
        .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
        .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
-       .pull_swba = ath10k_wmi_op_pull_swba_ev,
+       .pull_swba = ath10k_wmi_10_2_4_op_pull_swba_ev,
        .pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,
        .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
        .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
@@ -7611,6 +7747,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
        .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
        .gen_pdev_enable_adaptive_cca =
                ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
+       .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
        /* .gen_bcn_tmpl not implemented */
        /* .gen_prb_tmpl not implemented */
        /* .gen_p2p_go_bcn_ie not implemented */
@@ -7677,6 +7814,7 @@ static const struct wmi_ops wmi_10_4_ops = {
        /* shared with 10.2 */
        .gen_request_stats = ath10k_wmi_op_gen_request_stats,
        .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
+       .get_vdev_subtype = ath10k_wmi_10_4_op_get_vdev_subtype,
 };
 
 int ath10k_wmi_attach(struct ath10k *ar)
index d85ad7855d20acfef9f0d3587c5ab8bfd56519ce..4d3cbc44fcd27851ec46a7178e42d04f69ed3701 100644 (file)
@@ -176,7 +176,10 @@ enum wmi_service {
        WMI_SERVICE_AUX_CHAN_LOAD_INTF,
        WMI_SERVICE_BSS_CHANNEL_INFO_64,
        WMI_SERVICE_EXT_RES_CFG_SUPPORT,
-       WMI_SERVICE_MESH,
+       WMI_SERVICE_MESH_11S,
+       WMI_SERVICE_MESH_NON_11S,
+       WMI_SERVICE_PEER_STATS,
+       WMI_SERVICE_RESTRT_CHNL_SUPPORT,
 
        /* keep last */
        WMI_SERVICE_MAX,
@@ -213,6 +216,7 @@ enum wmi_10x_service {
        WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
        WMI_10X_SERVICE_MESH,
        WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
+       WMI_10X_SERVICE_PEER_STATS,
 };
 
 enum wmi_main_service {
@@ -294,7 +298,10 @@ enum wmi_10_4_service {
        WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF,
        WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
        WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
-       WMI_10_4_SERVICE_MESH,
+       WMI_10_4_SERVICE_MESH_NON_11S,
+       WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
+       WMI_10_4_SERVICE_PEER_STATS,
+       WMI_10_4_SERVICE_MESH_11S,
 };
 
 static inline char *wmi_service_name(int service_id)
@@ -385,7 +392,10 @@ static inline char *wmi_service_name(int service_id)
        SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
        SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
        SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT);
-       SVCSTR(WMI_SERVICE_MESH);
+       SVCSTR(WMI_SERVICE_MESH_11S);
+       SVCSTR(WMI_SERVICE_MESH_NON_11S);
+       SVCSTR(WMI_SERVICE_PEER_STATS);
+       SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT);
        default:
                return NULL;
        }
@@ -460,9 +470,11 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
        SVCMAP(WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
               WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
        SVCMAP(WMI_10X_SERVICE_MESH,
-              WMI_SERVICE_MESH, len);
+              WMI_SERVICE_MESH_11S, len);
        SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
               WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
+       SVCMAP(WMI_10X_SERVICE_PEER_STATS,
+              WMI_SERVICE_PEER_STATS, len);
 }
 
 static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
@@ -623,8 +635,14 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
               WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
        SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
               WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
-       SVCMAP(WMI_10_4_SERVICE_MESH,
-              WMI_SERVICE_MESH, len);
+       SVCMAP(WMI_10_4_SERVICE_MESH_NON_11S,
+              WMI_SERVICE_MESH_NON_11S, len);
+       SVCMAP(WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
+              WMI_SERVICE_RESTRT_CHNL_SUPPORT, len);
+       SVCMAP(WMI_10_4_SERVICE_PEER_STATS,
+              WMI_SERVICE_PEER_STATS, len);
+       SVCMAP(WMI_10_4_SERVICE_MESH_11S,
+              WMI_SERVICE_MESH_11S, len);
 }
 
 #undef SVCMAP
@@ -1800,7 +1818,6 @@ enum wmi_channel_change_cause {
 #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
 
 #define WMI_MAX_SPATIAL_STREAM        3 /* default max ss */
-#define WMI_10_4_MAX_SPATIAL_STREAM   4
 
 /* HT Capabilities*/
 #define WMI_HT_CAP_ENABLED                0x0001   /* HT Enabled/ disabled */
@@ -2417,6 +2434,7 @@ enum wmi_10_2_feature_mask {
        WMI_10_2_RX_BATCH_MODE = BIT(0),
        WMI_10_2_ATF_CONFIG    = BIT(1),
        WMI_10_2_COEX_GPIO     = BIT(3),
+       WMI_10_2_PEER_STATS    = BIT(7),
 };
 
 struct wmi_resource_config_10_2 {
@@ -4227,7 +4245,13 @@ struct wmi_10_2_peer_stats {
 
 struct wmi_10_2_4_peer_stats {
        struct wmi_10_2_peer_stats common;
-       __le32 unknown_value; /* FIXME: what is this word? */
+       __le32 peer_rssi_changed;
+} __packed;
+
+struct wmi_10_2_4_ext_peer_stats {
+       struct wmi_10_2_peer_stats common;
+       __le32 peer_rssi_changed;
+       __le32 rx_duration;
 } __packed;
 
 struct wmi_10_4_peer_stats {
@@ -4270,12 +4294,40 @@ enum wmi_vdev_type {
 };
 
 enum wmi_vdev_subtype {
-       WMI_VDEV_SUBTYPE_NONE       = 0,
-       WMI_VDEV_SUBTYPE_P2P_DEVICE = 1,
-       WMI_VDEV_SUBTYPE_P2P_CLIENT = 2,
-       WMI_VDEV_SUBTYPE_P2P_GO     = 3,
-       WMI_VDEV_SUBTYPE_PROXY_STA      = 4,
-       WMI_VDEV_SUBTYPE_MESH           = 5,
+       WMI_VDEV_SUBTYPE_NONE,
+       WMI_VDEV_SUBTYPE_P2P_DEVICE,
+       WMI_VDEV_SUBTYPE_P2P_CLIENT,
+       WMI_VDEV_SUBTYPE_P2P_GO,
+       WMI_VDEV_SUBTYPE_PROXY_STA,
+       WMI_VDEV_SUBTYPE_MESH_11S,
+       WMI_VDEV_SUBTYPE_MESH_NON_11S,
+};
+
+enum wmi_vdev_subtype_legacy {
+       WMI_VDEV_SUBTYPE_LEGACY_NONE      = 0,
+       WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV   = 1,
+       WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI   = 2,
+       WMI_VDEV_SUBTYPE_LEGACY_P2P_GO    = 3,
+       WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA = 4,
+};
+
+enum wmi_vdev_subtype_10_2_4 {
+       WMI_VDEV_SUBTYPE_10_2_4_NONE      = 0,
+       WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV   = 1,
+       WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI   = 2,
+       WMI_VDEV_SUBTYPE_10_2_4_P2P_GO    = 3,
+       WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA = 4,
+       WMI_VDEV_SUBTYPE_10_2_4_MESH_11S  = 5,
+};
+
+enum wmi_vdev_subtype_10_4 {
+       WMI_VDEV_SUBTYPE_10_4_NONE         = 0,
+       WMI_VDEV_SUBTYPE_10_4_P2P_DEV      = 1,
+       WMI_VDEV_SUBTYPE_10_4_P2P_CLI      = 2,
+       WMI_VDEV_SUBTYPE_10_4_P2P_GO       = 3,
+       WMI_VDEV_SUBTYPE_10_4_PROXY_STA    = 4,
+       WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S = 5,
+       WMI_VDEV_SUBTYPE_10_4_MESH_11S     = 6,
 };
 
 /* values for vdev_subtype */
@@ -5442,6 +5494,16 @@ struct wmi_host_swba_event {
        struct wmi_bcn_info bcn_info[0];
 } __packed;
 
+struct wmi_10_2_4_bcn_info {
+       struct wmi_tim_info tim_info;
+       /* The 10.2.4 FW doesn't have p2p NOA info */
+} __packed;
+
+struct wmi_10_2_4_host_swba_event {
+       __le32 vdev_map;
+       struct wmi_10_2_4_bcn_info bcn_info[0];
+} __packed;
+
 /* 16 words = 512 client + 1 word = for guard */
 #define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17
 
@@ -6436,5 +6498,7 @@ size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head);
 void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
                                      struct ath10k_fw_stats *fw_stats,
                                      char *buf);
+int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
+                                  enum wmi_vdev_subtype subtype);
 
 #endif /* _WMI_H_ */
index 25e45e4d1a605ba69092f9c76af4dcf3ebfae056..815efe9fd208fab95984b04bd84b088e6407576f 100644 (file)
@@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
 
 static void ath9k_ani_restart(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
-
-       if (!ah->curchan)
-               return;
+       struct ar5416AniState *aniState = &ah->ani;
 
-       aniState = &ah->ani;
        aniState->listenTime = 0;
 
        ENABLE_REGWRITE_BUFFER(ah);
@@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
 
 static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
-
-       if (!ah->curchan)
-               return;
-
-       aniState = &ah->ani;
+       struct ar5416AniState *aniState = &ah->ani;
 
        if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
                ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
@@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
 
 static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
-
-       if (!ah->curchan)
-               return;
-
-       aniState = &ah->ani;
+       struct ar5416AniState *aniState = &ah->ani;
 
        if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
                ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
@@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
  */
 static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 {
-       struct ar5416AniState *aniState;
-
-       aniState = &ah->ani;
+       struct ar5416AniState *aniState = &ah->ani;
 
        /* lower OFDM noise immunity */
        if (aniState->ofdmNoiseImmunityLevel > 0 &&
@@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
        struct ath_common *common = ath9k_hw_common(ah);
        int ofdm_nil, cck_nil;
 
-       if (!ah->curchan)
+       if (!chan)
                return;
 
        BUG_ON(aniState == NULL);
@@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 
 void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-       struct ar5416AniState *aniState;
+       struct ar5416AniState *aniState = &ah->ani;
        struct ath_common *common = ath9k_hw_common(ah);
        u32 ofdmPhyErrRate, cckPhyErrRate;
 
-       if (!ah->curchan)
-               return;
-
-       aniState = &ah->ani;
        if (!ath9k_hw_ani_read_counters(ah))
                return;
 
@@ -450,7 +430,9 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
                } else if (cckPhyErrRate > ah->config.cck_trig_high) {
                        ath9k_hw_ani_cck_err_trigger(ah);
                        aniState->ofdmsTurn = true;
-               }
+               } else
+                       return;
+                       
                ath9k_ani_restart(ah);
        }
 }
index 1db119d777839a3644a5ae44a997798892442cb8..547cd46da260f79159b4ceeddbb99fe62e3605c7 100644 (file)
@@ -53,19 +53,19 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
        return true;
 }
 
-static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram,
+static int16_t ar9003_aic_find_valid(bool *cal_sram_valid,
                                     bool dir, u8 index)
 {
        int16_t i;
 
        if (dir) {
                for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
-                       if (cal_sram[i].valid)
+                       if (cal_sram_valid[i])
                                break;
                }
        } else {
                for (i = index - 1; i >= 0; i--) {
-                       if (cal_sram[i].valid)
+                       if (cal_sram_valid[i])
                                break;
                }
        }
@@ -264,7 +264,7 @@ static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
 static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
 {
        struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
-       struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL];
+       bool cal_sram_valid[ATH_AIC_MAX_BT_CHANNEL];
        struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL];
        u32 dir_path_gain_idx, quad_path_gain_idx, value;
        u32 fixed_com_att_db;
@@ -272,33 +272,34 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
        int16_t i;
        bool ret = true;
 
-       memset(&cal_sram, 0, sizeof(cal_sram));
+       memset(&cal_sram_valid, 0, sizeof(cal_sram_valid));
        memset(&aic_sram, 0, sizeof(aic_sram));
 
        for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
+               struct ath_aic_sram_info sram;
                value = aic->aic_sram[i];
 
-               cal_sram[i].valid =
+               cal_sram_valid[i] = sram.valid =
                        MS(value, AR_PHY_AIC_SRAM_VALID);
-               cal_sram[i].rot_quad_att_db =
+               sram.rot_quad_att_db =
                        MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB);
-               cal_sram[i].vga_quad_sign =
+               sram.vga_quad_sign =
                        MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN);
-               cal_sram[i].rot_dir_att_db =
+               sram.rot_dir_att_db =
                        MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB);
-               cal_sram[i].vga_dir_sign =
+               sram.vga_dir_sign =
                        MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN);
-               cal_sram[i].com_att_6db =
+               sram.com_att_6db =
                        MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB);
 
-               if (cal_sram[i].valid) {
-                       dir_path_gain_idx = cal_sram[i].rot_dir_att_db +
-                               com_att_db_table[cal_sram[i].com_att_6db];
-                       quad_path_gain_idx = cal_sram[i].rot_quad_att_db +
-                               com_att_db_table[cal_sram[i].com_att_6db];
+               if (sram.valid) {
+                       dir_path_gain_idx = sram.rot_dir_att_db +
+                               com_att_db_table[sram.com_att_6db];
+                       quad_path_gain_idx = sram.rot_quad_att_db +
+                               com_att_db_table[sram.com_att_6db];
 
-                       dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1;
-                       quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1;
+                       dir_path_sign = (sram.vga_dir_sign) ? 1 : -1;
+                       quad_path_sign = (sram.vga_quad_sign) ? 1 : -1;
 
                        aic_sram[i].dir_path_gain_lin = dir_path_sign *
                                aic_lin_table[dir_path_gain_idx];
@@ -310,16 +311,16 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
        for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
                int16_t start_idx, end_idx;
 
-               if (cal_sram[i].valid)
+               if (cal_sram_valid[i])
                        continue;
 
-               start_idx = ar9003_aic_find_valid(cal_sram, 0, i);
-               end_idx = ar9003_aic_find_valid(cal_sram, 1, i);
+               start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i);
+               end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i);
 
                if (start_idx < 0) {
                        /* extrapolation */
                        start_idx = end_idx;
-                       end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx);
+                       end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx);
 
                        if (end_idx < 0) {
                                ret = false;
@@ -342,7 +343,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
 
                if (end_idx < 0) {
                        /* extrapolation */
-                       end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx);
+                       end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx);
 
                        if (end_idx < 0) {
                                ret = false;
@@ -378,19 +379,21 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
        }
 
        /* From dir/quad_path_gain_lin to sram. */
-       i = ar9003_aic_find_valid(cal_sram, 1, 0);
+       i = ar9003_aic_find_valid(cal_sram_valid, 1, 0);
        if (i < 0) {
                i = 0;
                ret = false;
        }
-       fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db];
+       fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i],
+                                           AR_PHY_AIC_SRAM_COM_ATT_6DB)];
 
        for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
                int16_t rot_dir_path_att_db, rot_quad_path_att_db;
+               struct ath_aic_sram_info sram;
 
-               aic_sram[i].sram.vga_dir_sign =
+               sram.vga_dir_sign =
                        (aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0;
-               aic_sram[i].sram.vga_quad_sign=
+               sram.vga_quad_sign =
                        (aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
 
                rot_dir_path_att_db =
@@ -400,33 +403,31 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
                        ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) -
                        fixed_com_att_db;
 
-               aic_sram[i].sram.com_att_6db =
+               sram.com_att_6db =
                        ar9003_aic_find_index(1, fixed_com_att_db);
 
-               aic_sram[i].sram.valid = 1;
+               sram.valid = 1;
 
-               aic_sram[i].sram.rot_dir_att_db =
+               sram.rot_dir_att_db =
                        min(max(rot_dir_path_att_db,
                                (int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
                            ATH_AIC_MAX_ROT_DIR_ATT_DB);
-               aic_sram[i].sram.rot_quad_att_db =
+               sram.rot_quad_att_db =
                        min(max(rot_quad_path_att_db,
                                (int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
                            ATH_AIC_MAX_ROT_QUAD_ATT_DB);
-       }
 
-       for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
-               aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign,
+               aic->aic_sram[i] = (SM(sram.vga_dir_sign,
                                       AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
-                                   SM(aic_sram[i].sram.vga_quad_sign,
+                                   SM(sram.vga_quad_sign,
                                       AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) |
-                                   SM(aic_sram[i].sram.com_att_6db,
+                                   SM(sram.com_att_6db,
                                       AR_PHY_AIC_SRAM_COM_ATT_6DB) |
-                                   SM(aic_sram[i].sram.valid,
+                                   SM(sram.valid,
                                       AR_PHY_AIC_SRAM_VALID) |
-                                   SM(aic_sram[i].sram.rot_dir_att_db,
+                                   SM(sram.rot_dir_att_db,
                                       AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) |
-                                   SM(aic_sram[i].sram.rot_quad_att_db,
+                                   SM(sram.rot_quad_att_db,
                                       AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB));
        }
 
index 86f40644be4309ae1efa3d64d9b5e9362a61719b..9512c63799f203652896e36ce9f59b0759c905ca 100644 (file)
@@ -50,7 +50,6 @@ struct ath_aic_sram_info {
 struct ath_aic_out_info {
        int16_t dir_path_gain_lin;
        int16_t quad_path_gain_lin;
-       struct ath_aic_sram_info sram;
 };
 
 u8 ar9003_aic_calibration(struct ath_hw *ah);
index 8b4561e8ce1aacf0ff2523cad1069d67bf2ca15f..54ed2f72d35eb27c4a8998a83463afcaae0c8cc1 100644 (file)
@@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
                          AR9300_PAPRD_SCALE_1);
        else {
                if (chan->channel >= 5700)
-               return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
-                         AR9300_PAPRD_SCALE_1);
+                       return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
+                                 AR9300_PAPRD_SCALE_1);
                else if (chan->channel >= 5400)
                        return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
-                                  AR9300_PAPRD_SCALE_2);
+                                 AR9300_PAPRD_SCALE_2);
                else
                        return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
                                  AR9300_PAPRD_SCALE_1);
index 8b238c15916df3281189b015a7df6a9034263161..2fe12b0de5b4f2a47af17caf7417d0ce48793728 100644 (file)
@@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
        else if (AR_SREV_9340(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9340Modes_low_ob_db_tx_gain_table_1p0);
+       else if (AR_SREV_9531_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              qca953x_1p1_modes_no_xpa_low_power_tx_gain_table);
        else if (AR_SREV_9485_11_OR_LATER(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9485Modes_low_ob_db_tx_gain_1_1);
index 201425e7f9cb94f031ad47d6d2366543b870d985..06c1ca6e829053efbd2d8c8620649792324f394d 100644 (file)
@@ -976,9 +976,14 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        /*
         * JAPAN regulatory.
         */
-       if (chan->channel == 2484)
+       if (chan->channel == 2484) {
                ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
 
+               if (AR_SREV_9531(ah))
+                       REG_RMW_FIELD(ah, AR_PHY_FCAL_2_0,
+                                     AR_PHY_FLC_PWR_THRESH, 0);
+       }
+
        ah->modes_index = modesIndex;
        ar9003_hw_override_ini(ah);
        ar9003_hw_set_channel_regs(ah, chan);
@@ -2071,7 +2076,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
  *             to be disabled.
  *
  * 0x04000409: Packet stuck on receive.
- *             Full chip reset is required for all chips except AR9340.
+ *             Full chip reset is required for all chips except
+ *            AR9340, AR9531 and AR9561.
  */
 
 /*
@@ -2100,7 +2106,7 @@ bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
        case 0x04000b09:
                return true;
        case 0x04000409:
-               if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
+               if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah))
                        return false;
                else
                        return true;
index c5f8bc4b5595ecda04fcb7b130f68180c6d74791..566da789f97ebe7117453b32c1374b22b8f5b977 100644 (file)
 #define AR_PHY_ADDAC_PARA_CTL    (AR_SM_BASE + 0x150)
 #define AR_PHY_XPA_CFG           (AR_SM_BASE + 0x158)
 
+#define AR_PHY_FLC_PWR_THRESH          7
+#define AR_PHY_FLC_PWR_THRESH_S                0
+
 #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW  3
 #define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S    0
 
index 6fc0d07e5ec6cbd0b324e4d3e96b4875e70ed4d3..c0b90daa3e3d8646f2e064e0f9bbe561d1f5a7d7 100644 (file)
@@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = {
        {0x00016448, 0x6c927a70},
 };
 
+static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xfff55592},
+       {0x0000a2e0, 0xfff99924},
+       {0x0000a2e4, 0xfffe1e00},
+       {0x0000a2e8, 0xffffe000},
+       {0x0000a410, 0x000050d6},
+       {0x0000a500, 0x00000069},
+       {0x0000a504, 0x0400006b},
+       {0x0000a508, 0x0800006d},
+       {0x0000a50c, 0x0c000269},
+       {0x0000a510, 0x1000026b},
+       {0x0000a514, 0x1400026d},
+       {0x0000a518, 0x18000669},
+       {0x0000a51c, 0x1c00066b},
+       {0x0000a520, 0x1d000a68},
+       {0x0000a524, 0x21000a6a},
+       {0x0000a528, 0x25000a6c},
+       {0x0000a52c, 0x29000a6e},
+       {0x0000a530, 0x2d0012a9},
+       {0x0000a534, 0x310012ab},
+       {0x0000a538, 0x350012ad},
+       {0x0000a53c, 0x39001b0a},
+       {0x0000a540, 0x3d001b0c},
+       {0x0000a544, 0x41001b0e},
+       {0x0000a548, 0x43001bae},
+       {0x0000a54c, 0x45001914},
+       {0x0000a550, 0x47001916},
+       {0x0000a554, 0x49001b96},
+       {0x0000a558, 0x49001b96},
+       {0x0000a55c, 0x49001b96},
+       {0x0000a560, 0x49001b96},
+       {0x0000a564, 0x49001b96},
+       {0x0000a568, 0x49001b96},
+       {0x0000a56c, 0x49001b96},
+       {0x0000a570, 0x49001b96},
+       {0x0000a574, 0x49001b96},
+       {0x0000a578, 0x49001b96},
+       {0x0000a57c, 0x49001b96},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00000000},
+       {0x0000a610, 0x00000000},
+       {0x0000a614, 0x00000000},
+       {0x0000a618, 0x00804201},
+       {0x0000a61c, 0x01408201},
+       {0x0000a620, 0x01408502},
+       {0x0000a624, 0x01408502},
+       {0x0000a628, 0x01408502},
+       {0x0000a62c, 0x01408502},
+       {0x0000a630, 0x01408502},
+       {0x0000a634, 0x01408502},
+       {0x0000a638, 0x01408502},
+       {0x0000a63c, 0x01408502},
+       {0x0000b2dc, 0xfff55592},
+       {0x0000b2e0, 0xfff99924},
+       {0x0000b2e4, 0xfffe1e00},
+       {0x0000b2e8, 0xffffe000},
+       {0x00016044, 0x044922db},
+       {0x00016048, 0x6c927a70},
+       {0x00016444, 0x044922db},
+       {0x00016448, 0x6c927a70},
+};
+
 static const u32 qca953x_2p0_baseband_core[][2] = {
        /* Addr      allmodes  */
        {0x00009800, 0xafe68e30},
index 3e2e24e4843fdbf94ef4d4484a4f05ef1f3bb21a..37f6d66d16715932771ef24a74a70382e11270ec 100644 (file)
@@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
        u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
        struct ath_common *common = ath9k_hw_common(ah);
        s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
+       u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
 
        if (ah->caldata)
                h = ah->caldata->nfCalHist;
@@ -263,6 +264,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                }
        }
 
+       /*
+        * stop NF cal if ongoing to ensure NF load completes immediately
+        * (or after end rx/tx frame if ongoing)
+        */
+       if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
+               REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+               REG_RMW_BUFFER_FLUSH(ah);
+               ENABLE_REG_RMW_BUFFER(ah);
+       }
+
        /*
         * Load software filtered NF value into baseband internal minCCApwr
         * variable.
@@ -276,17 +287,32 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 
        /*
         * Wait for load to complete, should be fast, a few 10s of us.
-        * The max delay was changed from an original 250us to 10000us
-        * since 250us often results in NF load timeout and causes deaf
-        * condition during stress testing 12/12/2009
+        * The max delay was changed from an original 250us to 22.2 msec.
+        * This would increase timeout to the longest possible frame
+        * (11n max length 22.1 msec)
         */
-       for (j = 0; j < 10000; j++) {
+       for (j = 0; j < 22200; j++) {
                if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-                    AR_PHY_AGC_CONTROL_NF) == 0)
+                             AR_PHY_AGC_CONTROL_NF) == 0)
                        break;
                udelay(10);
        }
 
+       /*
+        * Restart NF so it can continue.
+        */
+       if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
+               ENABLE_REG_RMW_BUFFER(ah);
+               if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
+                       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                                   AR_PHY_AGC_CONTROL_ENABLE_NF);
+               if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
+                       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+               REG_RMW_BUFFER_FLUSH(ah);
+       }
+
        /*
         * We timed out waiting for the noisefloor to load, probably due to an
         * in-progress rx. Simply return here and allow the load plenty of time
@@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
         * here, the baseband nf cal will just be capped by our present
         * noisefloor until the next calibration timer.
         */
-       if (j == 10000) {
+       if (j == 22200) {
                ath_dbg(common, ANY,
                        "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
                        REG_READ(ah, AR_PHY_AGC_CONTROL));
index 50e614b915f1b1b5b19835ddbe3fd156a6c15d5d..319cb5f25f58d83fbdaab226698c8f021a3e897b 100644 (file)
@@ -226,7 +226,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
        }
 }
 
-static const u32 chanctx_event_delta(struct ath_softc *sc)
+static u32 chanctx_event_delta(struct ath_softc *sc)
 {
        u64 ms;
        struct timespec ts, *old;
@@ -1454,7 +1454,7 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
        if (!sc->p2p_ps_timer)
                return;
 
-       if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+       if (vif->type != NL80211_IFTYPE_STATION)
                return;
 
        sc->p2p_ps_vif = avp;
index 165dd202c3654412db8dc79745d12fd48b78d29a..8cbf4904db7b282b1f73dea228179e75b230cc25 100644 (file)
@@ -55,6 +55,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
          .driver_info = AR9280_USB },  /* Buffalo WLI-UV-AG300P */
        { USB_DEVICE(0x04da, 0x3904),
          .driver_info = AR9280_USB },
+       { USB_DEVICE(0x0930, 0x0a08),
+         .driver_info = AR9280_USB },  /* Toshiba WLM-20U2 and GN-1080 */
 
        { USB_DEVICE(0x0cf3, 0x20ff),
          .driver_info = STORAGE_DEVICE },
index fe1fd1a5ae1502a2c5d2947d1a40ff3ee6193d76..639294a9e34df6b2461b4c4c8052af75cbf2b258 100644 (file)
@@ -1657,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
 
 static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
-                                 enum ieee80211_ampdu_mlme_action action,
-                                 struct ieee80211_sta *sta,
-                                 u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
+                                 struct ieee80211_ampdu_params *params)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath9k_htc_sta *ista;
        int ret = 0;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
 
        mutex_lock(&priv->mutex);
        ath9k_htc_ps_wakeup(priv);
index 257f46ed4a040a5354a1542a2c039af3101fe72f..e7a31016f370ade654f6e4fcd05e3adc4595a13e 100644 (file)
@@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_check_gpm_offset(ah);
 
+       /* DMA HALT added to resolve ar9300 and ar9580 bus error during
+        * RTC_RC reg read
+        */
+       if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
+               REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
+               ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
+                             20 * AH_WAIT_TIMEOUT);
+               REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
+       }
+
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
        REGWRITE_BUFFER_FLUSH(ah);
index ab7a1ac378495d5e6da98909259321d46b1f738f..d4e0ac946c3a076838b62cb1d8cabbf346bffcd6 100644 (file)
@@ -751,14 +751,6 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
 
 #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
 
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
-       { .max = 1,     .types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
-                                BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
-                                BIT(NL80211_IFTYPE_ADHOC) },
-};
-
 static const struct ieee80211_iface_combination if_comb[] = {
        {
                .limits = if_limits,
@@ -766,6 +758,11 @@ static const struct ieee80211_iface_combination if_comb[] = {
                .max_interfaces = 2048,
                .num_different_channels = 1,
                .beacon_int_infra_match = true,
+#ifdef CONFIG_ATH9K_DFS_CERTIFIED
+               .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+                                       BIT(NL80211_CHAN_WIDTH_20) |
+                                       BIT(NL80211_CHAN_WIDTH_40),
+#endif
        },
        {
                .limits = wds_limits,
@@ -774,18 +771,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
                .num_different_channels = 1,
                .beacon_int_infra_match = true,
        },
-#ifdef CONFIG_ATH9K_DFS_CERTIFIED
-       {
-               .limits = if_dfs_limits,
-               .n_limits = ARRAY_SIZE(if_dfs_limits),
-               .max_interfaces = 1,
-               .num_different_channels = 1,
-               .beacon_int_infra_match = true,
-               .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
-                                       BIT(NL80211_CHAN_WIDTH_20) |
-                                       BIT(NL80211_CHAN_WIDTH_40),
-       }
-#endif
 };
 
 #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
index c1b33fdcca0875a20cd2be3b54b21e46c37b725c..3aed43a63f946d0fa2d218b15f4621be2ad49977 100644 (file)
@@ -978,7 +978,7 @@ static void ath9k_update_bssid_mask(struct ath_softc *sc,
                if (ctx->nvifs_assigned != 1)
                        continue;
 
-               if (!avp->vif->p2p || !iter_data->has_hw_macaddr)
+               if (!iter_data->has_hw_macaddr)
                        continue;
 
                ether_addr_copy(common->curbssid, avp->bssid);
@@ -1255,6 +1255,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
        sc->cur_chan->nvifs++;
 
+       if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled())
+               vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE;
+
        if (ath9k_uses_beacons(vif->type))
                ath9k_beacon_assign_slot(sc, vif);
 
@@ -1864,14 +1867,16 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
 static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
-                             enum ieee80211_ampdu_mlme_action action,
-                             struct ieee80211_sta *sta,
-                             u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
+                             struct ieee80211_ampdu_params *params)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        bool flush = false;
        int ret = 0;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
 
        mutex_lock(&sc->mutex);
 
index caba54ddad25c3dc4d7abd932e48602c4c885b94..c8d35febaf0f7e7ffb2bdc462f2987ab5f1a3896 100644 (file)
 #define AR_CFG_SWRG          0x00000010
 #define AR_CFG_AP_ADHOC_INDICATION 0x00000020
 #define AR_CFG_PHOK          0x00000100
-#define AR_CFG_CLK_GATE_DIS  0x00000400
 #define AR_CFG_EEBS          0x00000200
+#define AR_CFG_CLK_GATE_DIS  0x00000400
+#define AR_CFG_HALT_REQ             0x00000800
+#define AR_CFG_HALT_ACK             0x00001000
 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH         0x00060000
 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S       17
 
index 9111d4ffc1b3851309af860a7b2e3e8175a2fb3e..ea1d80f9a50efb3a8d4c59113c6782479b90d8aa 100644 (file)
@@ -56,6 +56,7 @@ enum carl9170_cmd_oids {
        CARL9170_CMD_RX_FILTER          = 0x07,
        CARL9170_CMD_WOL                = 0x08,
        CARL9170_CMD_TALLY              = 0x09,
+       CARL9170_CMD_WREGB              = 0x0a,
 
        /* CAM */
        CARL9170_CMD_EKEY               = 0x10,
@@ -123,6 +124,12 @@ struct carl9170_write_reg {
        } regs[0] __packed;
 } __packed;
 
+struct carl9170_write_reg_byte {
+       __le32  addr;
+       __le32  count;
+       u8      val[0];
+} __packed;
+
 #define        CARL9170FW_PHY_HT_ENABLE                0x4
 #define        CARL9170FW_PHY_HT_DYN2040               0x8
 #define        CARL9170FW_PHY_HT_EXT_CHAN_OFF          0x3
@@ -226,6 +233,7 @@ struct carl9170_cmd {
                struct carl9170_u32_list        echo;
                struct carl9170_reg_list        rreg;
                struct carl9170_write_reg       wreg;
+               struct carl9170_write_reg_byte  wregb;
                struct carl9170_rf_init         rf_init;
                struct carl9170_psm             psm;
                struct carl9170_wol_cmd         wol;
index 66848d47c88e993c2c04d328699e94249c5bad61..0533f79cb99810168bc87c32c1a17f87b87ae932 100644 (file)
@@ -81,6 +81,12 @@ enum carl9170fw_feature_list {
        /* Firmware will pass BA when BARs are queued */
        CARL9170FW_RX_BA_FILTER,
 
+       /* Firmware has support to write a byte at a time */
+       CARL9170FW_HAS_WREGB_CMD,
+
+       /* Pattern generator */
+       CARL9170FW_PATTERN_GENERATOR,
+
        /* KEEP LAST */
        __CARL9170FW_FEATURE_NUM
 };
index 0db874abde500750f7365ed6a9c254b297d03025..08e0ae9c5836dc38d7d4f2d9f5abe71d8af86a66 100644 (file)
 #define        AR9170_MC_REG_BASE                      0x1d1000
 
 #define        AR9170_MC_REG_FLASH_WAIT_STATE          (AR9170_MC_REG_BASE + 0x000)
-#define        AR9170_MC_REG_SEEPROM_WP0               (AR9170_MC_REG_BASE + 0x400)
-#define        AR9170_MC_REG_SEEPROM_WP1               (AR9170_MC_REG_BASE + 0x404)
-#define        AR9170_MC_REG_SEEPROM_WP2               (AR9170_MC_REG_BASE + 0x408)
+
+#define AR9170_SPI_REG_BASE                    (AR9170_MC_REG_BASE + 0x200)
+#define AR9170_SPI_REG_CONTROL0                        (AR9170_SPI_REG_BASE + 0x000)
+#define                AR9170_SPI_CONTROL0_BUSY                BIT(0)
+#define                AR9170_SPI_CONTROL0_CMD_GO              BIT(1)
+#define                AR9170_SPI_CONTROL0_PAGE_WR             BIT(2)
+#define                AR9170_SPI_CONTROL0_SEQ_RD              BIT(3)
+#define                AR9170_SPI_CONTROL0_CMD_ABORT           BIT(4)
+#define                AR9170_SPI_CONTROL0_CMD_LEN_S           8
+#define                AR9170_SPI_CONTROL0_CMD_LEN             0x00000f00
+#define                AR9170_SPI_CONTROL0_RD_LEN_S            12
+#define                AR9170_SPI_CONTROL0_RD_LEN              0x00007000
+
+#define        AR9170_SPI_REG_CONTROL1                 (AR9170_SPI_REG_BASE + 0x004)
+#define                AR9170_SPI_CONTROL1_SCK_RATE            BIT(0)
+#define                AR9170_SPI_CONTROL1_DRIVE_SDO           BIT(1)
+#define                AR9170_SPI_CONTROL1_MODE_SEL_S          2
+#define                AR9170_SPI_CONTROL1_MODE_SEL            0x000000c0
+#define                AR9170_SPI_CONTROL1_WRITE_PROTECT       BIT(4)
+
+#define AR9170_SPI_REG_COMMAND_PORT0           (AR9170_SPI_REG_BASE + 0x008)
+#define                AR9170_SPI_COMMAND_PORT0_CMD0_S         0
+#define                AR9170_SPI_COMMAND_PORT0_CMD0           0x000000ff
+#define                AR9170_SPI_COMMAND_PORT0_CMD1_S         8
+#define                AR9170_SPI_COMMAND_PORT0_CMD1           0x0000ff00
+#define                AR9170_SPI_COMMAND_PORT0_CMD2_S         16
+#define                AR9170_SPI_COMMAND_PORT0_CMD2           0x00ff0000
+#define                AR9170_SPI_COMMAND_PORT0_CMD3_S         24
+#define                AR9170_SPI_COMMAND_PORT0_CMD3           0xff000000
+
+#define AR9170_SPI_REG_COMMAND_PORT1           (AR9170_SPI_REG_BASE + 0x00C)
+#define                AR9170_SPI_COMMAND_PORT1_CMD4_S         0
+#define                AR9170_SPI_COMMAND_PORT1_CMD4           0x000000ff
+#define                AR9170_SPI_COMMAND_PORT1_CMD5_S         8
+#define                AR9170_SPI_COMMAND_PORT1_CMD5           0x0000ff00
+#define                AR9170_SPI_COMMAND_PORT1_CMD6_S         16
+#define                AR9170_SPI_COMMAND_PORT1_CMD6           0x00ff0000
+#define                AR9170_SPI_COMMAND_PORT1_CMD7_S         24
+#define                AR9170_SPI_COMMAND_PORT1_CMD7           0xff000000
+
+#define AR9170_SPI_REG_DATA_PORT               (AR9170_SPI_REG_BASE + 0x010)
+#define AR9170_SPI_REG_PAGE_WRITE_LEN          (AR9170_SPI_REG_BASE + 0x014)
+
+#define AR9170_EEPROM_REG_BASE                 (AR9170_MC_REG_BASE + 0x400)
+#define        AR9170_EEPROM_REG_WP_MAGIC1             (AR9170_EEPROM_REG_BASE + 0x000)
+#define                AR9170_EEPROM_WP_MAGIC1                 0x12345678
+
+#define        AR9170_EEPROM_REG_WP_MAGIC2             (AR9170_EEPROM_REG_BASE + 0x004)
+#define                AR9170_EEPROM_WP_MAGIC2                 0x55aa00ff
+
+#define        AR9170_EEPROM_REG_WP_MAGIC3             (AR9170_EEPROM_REG_BASE + 0x008)
+#define                AR9170_EEPROM_WP_MAGIC3                 0x13579ace
+
+#define        AR9170_EEPROM_REG_CLOCK_DIV             (AR9170_EEPROM_REG_BASE + 0x00C)
+#define                AR9170_EEPROM_CLOCK_DIV_FAC_S           0
+#define                AR9170_EEPROM_CLOCK_DIV_FAC             0x000001ff
+#define                AR9170_EEPROM_CLOCK_DIV_FAC_39KHZ       0xff
+#define                AR9170_EEPROM_CLOCK_DIV_FAC_78KHZ       0x7f
+#define                AR9170_EEPROM_CLOCK_DIV_FAC_312KHZ      0x1f
+#define                AR9170_EEPROM_CLOCK_DIV_FAC_10MHZ       0x0
+#define        AR9170_EEPROM_CLOCK_DIV_SOFT_RST                BIT(9)
+
+#define AR9170_EEPROM_REG_MODE                 (AR9170_EEPROM_REG_BASE + 0x010)
+#define        AR9170_EEPROM_MODE_EEPROM_SIZE_16K_PLUS         BIT(31)
+
+#define AR9170_EEPROM_REG_WRITE_PROTECT                (AR9170_EEPROM_REG_BASE + 0x014)
+#define                AR9170_EEPROM_WRITE_PROTECT_WP_STATUS   BIT(0)
+#define                AR9170_EEPROM_WRITE_PROTECT_WP_SET      BIT(8)
 
 /* Interrupt Controller */
 #define        AR9170_MAX_INT_SRC                      9
 #define        AR9170_USB_REG_EP10_MAP                 (AR9170_USB_REG_BASE + 0x039)
 
 #define        AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH      (AR9170_USB_REG_BASE + 0x03f)
+#define                AR9170_USB_EP_IN_STALL                  0x8
 #define                AR9170_USB_EP_IN_TOGGLE                 0x10
 
 #define        AR9170_USB_REG_EP_IN_MAX_SIZE_LOW       (AR9170_USB_REG_BASE + 0x03e)
 
 #define        AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH     (AR9170_USB_REG_BASE + 0x05f)
+#define                AR9170_USB_EP_OUT_STALL                 0x8
 #define                AR9170_USB_EP_OUT_TOGGLE                0x10
 
 #define        AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW      (AR9170_USB_REG_BASE + 0x05e)
index 19d3d64416bf66825eb113590474b4e4a68f8ec2..4d1527a2e292a2ba2d29907554625cf0fbb980f4 100644 (file)
@@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work)
 
 static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
-                                   enum ieee80211_ampdu_mlme_action action,
-                                   struct ieee80211_sta *sta,
-                                   u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
+                                   struct ieee80211_ampdu_params *params)
 {
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
        struct ar9170 *ar = hw->priv;
        struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
        struct carl9170_sta_tid *tid_info;
index 2282847d4bb898fa2f09f858f9530b9ae6191300..a0410fe8c03a1f93758273cd36845701f1daf292 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __CARL9170_SHARED_VERSION_H
 #define __CARL9170_SHARED_VERSION_H
-#define CARL9170FW_VERSION_YEAR 12
-#define CARL9170FW_VERSION_MONTH 12
+#define CARL9170FW_VERSION_YEAR 16
+#define CARL9170FW_VERSION_MONTH 2
 #define CARL9170FW_VERSION_DAY 15
-#define CARL9170FW_VERSION_GIT "1.9.7"
+#define CARL9170FW_VERSION_GIT "1.9.9"
 #endif /* __CARL9170_SHARED_VERSION_H */
index 7c169abdbafee95ccfe8f461e670fbb8ab5ca5eb..a27279c2c6950913c0b1f14fd4cacdd3bc650428 100644 (file)
@@ -857,12 +857,14 @@ static int wcn36xx_resume(struct ieee80211_hw *hw)
 
 static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
-                   enum ieee80211_ampdu_mlme_action action,
-                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                   u8 buf_size, bool amsdu)
+                   struct ieee80211_ampdu_params *params)
 {
        struct wcn36xx *wcn = hw->priv;
        struct wcn36xx_sta *sta_priv = NULL;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
                    action, tid);
index 20d07ef679e89d467170abae532819f36f283821..11f1bb8dfebebf95a089b015702bb9bcf72072c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -422,6 +422,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
        if (sme->privacy && !rsn_eid)
                wil_info(wil, "WSC connection\n");
 
+       if (sme->pbss) {
+               wil_err(wil, "connect - PBSS not yet supported\n");
+               return -EOPNOTSUPP;
+       }
+
        bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
                               sme->ssid, sme->ssid_len,
                               IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
@@ -535,7 +540,18 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
 
        wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
 
-       rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+       if (!(test_bit(wil_status_fwconnecting, wil->status) ||
+             test_bit(wil_status_fwconnected, wil->status))) {
+               wil_err(wil, "%s: Disconnect was called while disconnected\n",
+                       __func__);
+               return 0;
+       }
+
+       rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
+                     WMI_DISCONNECT_EVENTID, NULL, 0,
+                     WIL6210_DISCONNECT_TO_MS);
+       if (rc)
+               wil_err(wil, "%s: disconnect error %d\n", __func__, rc);
 
        return rc;
 }
@@ -696,6 +712,79 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
        return rc;
 }
 
+/**
+ * find a specific IE in a list of IEs
+ * return a pointer to the beginning of IE in the list
+ * or NULL if not found
+ */
+static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie,
+                                      u16 ie_len)
+{
+       struct ieee80211_vendor_ie *vie;
+       u32 oui;
+
+       /* IE tag at offset 0, length at offset 1 */
+       if (ie_len < 2 || 2 + ie[1] > ie_len)
+               return NULL;
+
+       if (ie[0] != WLAN_EID_VENDOR_SPECIFIC)
+               return cfg80211_find_ie(ie[0], ies, ies_len);
+
+       /* make sure there is room for 3 bytes OUI + 1 byte OUI type */
+       if (ie[1] < 4)
+               return NULL;
+       vie = (struct ieee80211_vendor_ie *)ie;
+       oui = vie->oui[0] << 16 | vie->oui[1] << 8 | vie->oui[2];
+       return cfg80211_find_vendor_ie(oui, vie->oui_type, ies,
+                                      ies_len);
+}
+
+/**
+ * merge the IEs in two lists into a single list.
+ * do not include IEs from the second list which exist in the first list.
+ * add only vendor specific IEs from second list to keep
+ * the merged list sorted (since vendor-specific IE has the
+ * highest tag number)
+ * caller must free the allocated memory for merged IEs
+ */
+static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
+                                        const u8 *ies2, u16 ies2_len,
+                                        u8 **merged_ies, u16 *merged_len)
+{
+       u8 *buf, *dpos;
+       const u8 *spos;
+
+       if (ies1_len == 0 && ies2_len == 0) {
+               *merged_ies = NULL;
+               *merged_len = 0;
+               return 0;
+       }
+
+       buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       memcpy(buf, ies1, ies1_len);
+       dpos = buf + ies1_len;
+       spos = ies2;
+       while (spos + 1 < ies2 + ies2_len) {
+               /* IE tag at offset 0, length at offset 1 */
+               u16 ielen = 2 + spos[1];
+
+               if (spos + ielen > ies2 + ies2_len)
+                       break;
+               if (spos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+                   !_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) {
+                       memcpy(dpos, spos, ielen);
+                       dpos += ielen;
+               }
+               spos += ielen;
+       }
+
+       *merged_ies = buf;
+       *merged_len = dpos - buf;
+       return 0;
+}
+
 static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
 {
        print_hex_dump_bytes("head     ", DUMP_PREFIX_OFFSET,
@@ -712,49 +801,49 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
                             b->assocresp_ies, b->assocresp_ies_len);
 }
 
-static int wil_fix_bcon(struct wil6210_priv *wil,
-                       struct cfg80211_beacon_data *bcon)
-{
-       struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
-       size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
-
-       if (bcon->probe_resp_len <= hlen)
-               return 0;
-
-/* always use IE's from full probe frame, they has more info
- * notable RSN
- */
-       bcon->proberesp_ies = f->u.probe_resp.variable;
-       bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
-       if (!bcon->assocresp_ies) {
-               bcon->assocresp_ies = bcon->proberesp_ies;
-               bcon->assocresp_ies_len = bcon->proberesp_ies_len;
-       }
-
-       return 1;
-}
-
 /* internal functions for device reset and starting AP */
 static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
                                 struct cfg80211_beacon_data *bcon)
 {
        int rc;
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       u16 len = 0, proberesp_len = 0;
+       u8 *ies = NULL, *proberesp = NULL;
+
+       if (bcon->probe_resp) {
+               struct ieee80211_mgmt *f =
+                       (struct ieee80211_mgmt *)bcon->probe_resp;
+               size_t hlen = offsetof(struct ieee80211_mgmt,
+                                      u.probe_resp.variable);
+               proberesp = f->u.probe_resp.variable;
+               proberesp_len = bcon->probe_resp_len - hlen;
+       }
+       rc = _wil_cfg80211_merge_extra_ies(proberesp,
+                                          proberesp_len,
+                                          bcon->proberesp_ies,
+                                          bcon->proberesp_ies_len,
+                                          &ies, &len);
 
-       rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
-                       bcon->proberesp_ies);
        if (rc)
-               return rc;
+               goto out;
+
+       rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies);
+       if (rc)
+               goto out;
 
-       rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
-                       bcon->assocresp_ies);
+       if (bcon->assocresp_ies)
+               rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
+                               bcon->assocresp_ies_len, bcon->assocresp_ies);
+       else
+               rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies);
 #if 0 /* to use beacon IE's, remove this #if 0 */
        if (rc)
-               return rc;
+               goto out;
 
        rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
 #endif
-
+out:
+       kfree(ies);
        return rc;
 }
 
@@ -823,14 +912,9 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
        wil_dbg_misc(wil, "%s()\n", __func__);
        wil_print_bcon_data(bcon);
 
-       if (wil_fix_bcon(wil, bcon)) {
-               wil_dbg_misc(wil, "Fixed bcon\n");
-               wil_print_bcon_data(bcon);
-       }
-
-       if (bcon->proberesp_ies &&
-           cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies,
-                            bcon->proberesp_ies_len))
+       if (bcon->tail &&
+           cfg80211_find_ie(WLAN_EID_RSN, bcon->tail,
+                            bcon->tail_len))
                privacy = 1;
 
        /* in case privacy has changed, need to restart the AP */
@@ -870,6 +954,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       if (info->pbss) {
+               wil_err(wil, "AP: PBSS not yet supported\n");
+               return -EOPNOTSUPP;
+       }
+
        switch (info->hidden_ssid) {
        case NL80211_HIDDEN_SSID_NOT_IN_USE:
                hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
@@ -900,11 +989,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
        wil_print_bcon_data(bcon);
        wil_print_crypto(wil, crypto);
 
-       if (wil_fix_bcon(wil, bcon)) {
-               wil_dbg_misc(wil, "Fixed bcon\n");
-               wil_print_bcon_data(bcon);
-       }
-
        rc = _wil_cfg80211_start_ap(wiphy, ndev,
                                    info->ssid, info->ssid_len, info->privacy,
                                    info->beacon_interval, channel->hw_value,
index a1d10b85989f7bfec11be8a7352b5a58247daacb..3bbe73b6d05a9caebe7d867d792501c70336cbbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -68,13 +68,13 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
                seq_puts(s, "???\n");
        }
 
-       if (vring->va && (vring->size < 1025)) {
+       if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
                uint i;
 
                for (i = 0; i < vring->size; i++) {
                        volatile struct vring_tx_desc *d = &vring->va[i].tx;
 
-                       if ((i % 64) == 0 && (i != 0))
+                       if ((i % 128) == 0 && (i != 0))
                                seq_puts(s, "\n");
                        seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
                                        _s : (vring->ctx[i].skb ? _h : 'h'));
index b39f0bfc591e9f9a120d72e658a0aaa6eee5066c..78ba6e04c9445f35a3700d9bcd4a21ce1b42b557 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -23,9 +23,6 @@
 #include "wmi.h"
 #include "boot_loader.h"
 
-#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
-#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
-
 bool debug_fw; /* = false; */
 module_param(debug_fw, bool, S_IRUGO);
 MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
@@ -155,7 +152,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
 
        if (sta->status != wil_sta_unused) {
                if (!from_event)
-                       wmi_disconnect_sta(wil, sta->addr, reason_code);
+                       wmi_disconnect_sta(wil, sta->addr, reason_code, true);
 
                switch (wdev->iftype) {
                case NL80211_IFTYPE_AP:
@@ -195,8 +192,8 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
        struct wireless_dev *wdev = wil->wdev;
 
        might_sleep();
-       wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
-                    reason_code, from_event ? "+" : "-");
+       wil_info(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
+                reason_code, from_event ? "+" : "-");
 
        /* Cases are:
         * - disconnect single STA, still connected
@@ -258,13 +255,16 @@ static void wil_disconnect_worker(struct work_struct *work)
 static void wil_connect_timer_fn(ulong x)
 {
        struct wil6210_priv *wil = (void *)x;
+       bool q;
 
-       wil_dbg_misc(wil, "Connect timeout\n");
+       wil_err(wil, "Connect timeout detected, disconnect station\n");
 
        /* reschedule to thread context - disconnect won't
-        * run from atomic context
+        * run from atomic context.
+        * queue on wmi_wq to prevent race with connect event.
         */
-       schedule_work(&wil->disconnect_worker);
+       q = queue_work(wil->wmi_wq, &wil->disconnect_worker);
+       wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
 }
 
 static void wil_scan_timer_fn(ulong x)
@@ -369,6 +369,32 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
        return -EINVAL;
 }
 
+int wil_tx_init(struct wil6210_priv *wil, int cid)
+{
+       int rc = -EINVAL, ringid;
+
+       if (cid < 0) {
+               wil_err(wil, "No connection pending\n");
+               goto out;
+       }
+       ringid = wil_find_free_vring(wil);
+       if (ringid < 0) {
+               wil_err(wil, "No free vring found\n");
+               goto out;
+       }
+
+       wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
+                   cid, ringid);
+
+       rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
+       if (rc)
+               wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n",
+                       cid, ringid);
+
+out:
+       return rc;
+}
+
 int wil_bcast_init(struct wil6210_priv *wil)
 {
        int ri = wil->bcast_vring, rc;
@@ -399,41 +425,6 @@ void wil_bcast_fini(struct wil6210_priv *wil)
        wil_vring_fini_tx(wil, ri);
 }
 
-static void wil_connect_worker(struct work_struct *work)
-{
-       int rc, cid, ringid;
-       struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
-                                               connect_worker);
-       struct net_device *ndev = wil_to_ndev(wil);
-
-       mutex_lock(&wil->mutex);
-
-       cid = wil->pending_connect_cid;
-       if (cid < 0) {
-               wil_err(wil, "No connection pending\n");
-               goto out;
-       }
-       ringid = wil_find_free_vring(wil);
-       if (ringid < 0) {
-               wil_err(wil, "No free vring found\n");
-               goto out;
-       }
-
-       wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
-                   cid, ringid);
-
-       rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
-       wil->pending_connect_cid = -1;
-       if (rc == 0) {
-               wil->sta[cid].status = wil_sta_connected;
-               netif_tx_wake_all_queues(ndev);
-       } else {
-               wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true);
-       }
-out:
-       mutex_unlock(&wil->mutex);
-}
-
 int wil_priv_init(struct wil6210_priv *wil)
 {
        uint i;
@@ -444,6 +435,9 @@ int wil_priv_init(struct wil6210_priv *wil)
        for (i = 0; i < WIL6210_MAX_CID; i++)
                spin_lock_init(&wil->sta[i].tid_rx_lock);
 
+       for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
+               spin_lock_init(&wil->vring_tx_data[i].lock);
+
        mutex_init(&wil->mutex);
        mutex_init(&wil->wmi_mutex);
        mutex_init(&wil->back_rx_mutex);
@@ -453,12 +447,10 @@ int wil_priv_init(struct wil6210_priv *wil)
        init_completion(&wil->wmi_ready);
        init_completion(&wil->wmi_call);
 
-       wil->pending_connect_cid = -1;
        wil->bcast_vring = -1;
        setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
        setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
 
-       INIT_WORK(&wil->connect_worker, wil_connect_worker);
        INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
        INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
        INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
@@ -844,7 +836,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
        }
 
        /* init after reset */
-       wil->pending_connect_cid = -1;
        wil->ap_isolate = 0;
        reinit_completion(&wil->wmi_ready);
        reinit_completion(&wil->wmi_call);
@@ -948,8 +939,7 @@ int wil_up(struct wil6210_priv *wil)
 
 int __wil_down(struct wil6210_priv *wil)
 {
-       int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
-                       WAIT_FOR_DISCONNECT_INTERVAL_MS;
+       int rc;
 
        WARN_ON(!mutex_is_locked(&wil->mutex));
 
@@ -973,22 +963,16 @@ int __wil_down(struct wil6210_priv *wil)
        }
 
        if (test_bit(wil_status_fwconnected, wil->status) ||
-           test_bit(wil_status_fwconnecting, wil->status))
-               wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+           test_bit(wil_status_fwconnecting, wil->status)) {
 
-       /* make sure wil is idle (not connected) */
-       mutex_unlock(&wil->mutex);
-       while (iter--) {
-               int idle = !test_bit(wil_status_fwconnected, wil->status) &&
-                          !test_bit(wil_status_fwconnecting, wil->status);
-               if (idle)
-                       break;
-               msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
+               mutex_unlock(&wil->mutex);
+               rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
+                             WMI_DISCONNECT_EVENTID, NULL, 0,
+                             WIL6210_DISCONNECT_TO_MS);
+               mutex_lock(&wil->mutex);
+               if (rc)
+                       wil_err(wil, "timeout waiting for disconnect\n");
        }
-       mutex_lock(&wil->mutex);
-
-       if (iter < 0)
-               wil_err(wil, "timeout waiting for idle FW/HW\n");
 
        wil_reset(wil, false);
 
index 56aaa2d4fb0ecb7f44e76ed1f28043d231a79719..ecc3c1bdae4b535ed1018676eb820fd372f85082 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -108,8 +108,9 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
        /* always process ALL Tx complete, regardless budget - it is fast */
        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
                struct vring *vring = &wil->vring_tx[i];
+               struct vring_tx_data *txdata = &wil->vring_tx_data[i];
 
-               if (!vring->va)
+               if (!vring->va || !txdata->enabled)
                        continue;
 
                tx_done += wil_tx_complete(wil, i);
index 7887e6cfd817ee4c00184566ac9255eb2f2a0b50..6af20903cf89fac32bd3f96d14d8b4ed5923d60a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -717,6 +717,21 @@ void wil_rx_fini(struct wil6210_priv *wil)
                wil_vring_free(wil, vring, 0);
 }
 
+static inline void wil_tx_data_init(struct vring_tx_data *txdata)
+{
+       spin_lock_bh(&txdata->lock);
+       txdata->dot1x_open = 0;
+       txdata->enabled = 0;
+       txdata->idle = 0;
+       txdata->last_idle = 0;
+       txdata->begin = 0;
+       txdata->agg_wsize = 0;
+       txdata->agg_timeout = 0;
+       txdata->agg_amsdu = 0;
+       txdata->addba_in_progress = false;
+       spin_unlock_bh(&txdata->lock);
+}
+
 int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
                      int cid, int tid)
 {
@@ -758,8 +773,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
                goto out;
        }
 
-       memset(txdata, 0, sizeof(*txdata));
-       spin_lock_init(&txdata->lock);
+       wil_tx_data_init(txdata);
        vring->size = size;
        rc = wil_vring_alloc(wil, vring);
        if (rc)
@@ -791,9 +805,14 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
 
        return 0;
  out_free:
+       spin_lock_bh(&txdata->lock);
        txdata->dot1x_open = false;
        txdata->enabled = 0;
+       spin_unlock_bh(&txdata->lock);
        wil_vring_free(wil, vring, 1);
+       wil->vring2cid_tid[id][0] = WIL6210_MAX_CID;
+       wil->vring2cid_tid[id][1] = 0;
+
  out:
 
        return rc;
@@ -831,8 +850,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
                goto out;
        }
 
-       memset(txdata, 0, sizeof(*txdata));
-       spin_lock_init(&txdata->lock);
+       wil_tx_data_init(txdata);
        vring->size = size;
        rc = wil_vring_alloc(wil, vring);
        if (rc)
@@ -862,8 +880,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
 
        return 0;
  out_free:
+       spin_lock_bh(&txdata->lock);
        txdata->enabled = 0;
        txdata->dot1x_open = false;
+       spin_unlock_bh(&txdata->lock);
        wil_vring_free(wil, vring, 1);
  out:
 
@@ -891,7 +911,6 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
                napi_synchronize(&wil->napi_tx);
 
        wil_vring_free(wil, vring, 1);
-       memset(txdata, 0, sizeof(*txdata));
 }
 
 static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
@@ -911,10 +930,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
                        continue;
                if (wil->vring2cid_tid[i][0] == cid) {
                        struct vring *v = &wil->vring_tx[i];
+                       struct vring_tx_data *txdata = &wil->vring_tx_data[i];
 
                        wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
                                     __func__, eth->h_dest, i);
-                       if (v->va) {
+                       if (v->va && txdata->enabled) {
                                return v;
                        } else {
                                wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
@@ -935,6 +955,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
        struct vring *v;
        int i;
        u8 cid;
+       struct vring_tx_data *txdata;
 
        /* In the STA mode, it is expected to have only 1 VRING
         * for the AP we connected to.
@@ -942,7 +963,8 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
         */
        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
                v = &wil->vring_tx[i];
-               if (!v->va)
+               txdata = &wil->vring_tx_data[i];
+               if (!v->va || !txdata->enabled)
                        continue;
 
                cid = wil->vring2cid_tid[i][0];
@@ -978,12 +1000,14 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
                                         struct sk_buff *skb)
 {
        struct vring *v;
+       struct vring_tx_data *txdata;
        int i = wil->bcast_vring;
 
        if (i < 0)
                return NULL;
        v = &wil->vring_tx[i];
-       if (!v->va)
+       txdata = &wil->vring_tx_data[i];
+       if (!v->va || !txdata->enabled)
                return NULL;
        if (!wil->vring_tx_data[i].dot1x_open &&
            (skb->protocol != cpu_to_be16(ETH_P_PAE)))
@@ -1010,11 +1034,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
        u8 cid;
        struct ethhdr *eth = (void *)skb->data;
        char *src = eth->h_source;
+       struct vring_tx_data *txdata;
 
        /* find 1-st vring eligible for data */
        for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
                v = &wil->vring_tx[i];
-               if (!v->va)
+               txdata = &wil->vring_tx_data[i];
+               if (!v->va || !txdata->enabled)
                        continue;
 
                cid = wil->vring2cid_tid[i][0];
index 235e205ce2bc0f6eeba985c348308af5dbb29374..8427d68b6fa8e875a2ae13cbdcaf5b3b187b19e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -51,7 +51,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 
 #define WIL_TX_Q_LEN_DEFAULT           (4000)
 #define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
-#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
+#define WIL_TX_RING_SIZE_ORDER_DEFAULT (12)
 #define WIL_BCAST_RING_SIZE_ORDER_DEFAULT      (7)
 #define WIL_BCAST_MCS0_LIMIT           (1024) /* limit for MCS0 frame size */
 /* limit ring size in range [32..32k] */
@@ -92,6 +92,7 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
 #define WIL6210_FW_RECOVERY_RETRIES    (5) /* try to recover this many times */
 #define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000)
 #define WIL6210_SCAN_TO                msecs_to_jiffies(10000)
+#define WIL6210_DISCONNECT_TO_MS (2000)
 #define WIL6210_RX_HIGH_TRSH_INIT              (0)
 #define WIL6210_RX_HIGH_TRSH_DEFAULT \
                                (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
@@ -581,12 +582,10 @@ struct wil6210_priv {
        struct workqueue_struct *wmi_wq; /* for deferred calls */
        struct work_struct wmi_event_worker;
        struct workqueue_struct *wq_service;
-       struct work_struct connect_worker;
        struct work_struct disconnect_worker;
        struct work_struct fw_error_worker;     /* for FW error recovery */
        struct timer_list connect_timer;
        struct timer_list scan_timer; /* detect scan timeout */
-       int pending_connect_cid;
        struct list_head pending_wmi_ev;
        /*
         * protect pending_wmi_ev
@@ -756,7 +755,8 @@ 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 wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
+                      bool full_disconnect);
 int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
 int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
 int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
@@ -807,6 +807,7 @@ void wil_rx_fini(struct wil6210_priv *wil);
 int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
                      int cid, int tid);
 void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
+int wil_tx_init(struct wil6210_priv *wil, int cid);
 int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
 int wil_bcast_init(struct wil6210_priv *wil);
 void wil_bcast_fini(struct wil6210_priv *wil);
index e3ea74cdd4aaee066c3d5f034265e63024e7cd6b..493e721c4fa715ba23ac86e153fe4626d389e9fb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -426,6 +426,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
        const size_t assoc_req_ie_offset = sizeof(u16) * 2;
        /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
        const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
+       int rc;
 
        if (len < sizeof(*evt)) {
                wil_err(wil, "Connect event too short : %d bytes\n", len);
@@ -445,8 +446,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
        }
 
        ch = evt->channel + 1;
-       wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
-                   evt->bssid, ch, evt->cid);
+       wil_info(wil, "Connect %pM channel [%d] cid %d\n",
+                evt->bssid, ch, evt->cid);
        wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
                         evt->assoc_info, len - sizeof(*evt), true);
 
@@ -468,20 +469,67 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
                assoc_resp_ielen = 0;
        }
 
+       mutex_lock(&wil->mutex);
+       if (test_bit(wil_status_resetting, wil->status) ||
+           !test_bit(wil_status_fwready, wil->status)) {
+               wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
+                       evt->cid);
+               mutex_unlock(&wil->mutex);
+               /* no need for cleanup, wil_reset will do that */
+               return;
+       }
+
        if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
            (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
                if (!test_bit(wil_status_fwconnecting, wil->status)) {
                        wil_err(wil, "Not in connecting state\n");
+                       mutex_unlock(&wil->mutex);
                        return;
                }
                del_timer_sync(&wil->connect_timer);
-               cfg80211_connect_result(ndev, evt->bssid,
-                                       assoc_req_ie, assoc_req_ielen,
-                                       assoc_resp_ie, assoc_resp_ielen,
-                                       WLAN_STATUS_SUCCESS, GFP_KERNEL);
+       }
+
+       /* FIXME FW can transmit only ucast frames to peer */
+       /* FIXME real ring_id instead of hard coded 0 */
+       ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
+       wil->sta[evt->cid].status = wil_sta_conn_pending;
 
+       rc = wil_tx_init(wil, evt->cid);
+       if (rc) {
+               wil_err(wil, "%s: config tx vring failed for CID %d, rc (%d)\n",
+                       __func__, evt->cid, rc);
+               wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
+                                  WLAN_REASON_UNSPECIFIED, false);
+       } else {
+               wil_info(wil, "%s: successful connection to CID %d\n",
+                        __func__, evt->cid);
+       }
+
+       if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
+           (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+               if (rc) {
+                       netif_tx_stop_all_queues(ndev);
+                       netif_carrier_off(ndev);
+                       wil_err(wil,
+                               "%s: cfg80211_connect_result with failure\n",
+                               __func__);
+                       cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
+                                               NULL, 0,
+                                               WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                               GFP_KERNEL);
+                       goto out;
+               } else {
+                       cfg80211_connect_result(ndev, evt->bssid,
+                                               assoc_req_ie, assoc_req_ielen,
+                                               assoc_resp_ie, assoc_resp_ielen,
+                                               WLAN_STATUS_SUCCESS,
+                                               GFP_KERNEL);
+               }
        } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
                   (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
+               if (rc)
+                       goto out;
+
                memset(&sinfo, 0, sizeof(sinfo));
 
                sinfo.generation = wil->sinfo_gen++;
@@ -492,17 +540,21 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
                }
 
                cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
+       } else {
+               wil_err(wil, "%s: unhandled iftype %d for CID %d\n",
+                       __func__, wdev->iftype, evt->cid);
+               goto out;
        }
-       clear_bit(wil_status_fwconnecting, wil->status);
-       set_bit(wil_status_fwconnected, wil->status);
 
-       /* FIXME FW can transmit only ucast frames to peer */
-       /* FIXME real ring_id instead of hard coded 0 */
-       ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
-       wil->sta[evt->cid].status = wil_sta_conn_pending;
+       wil->sta[evt->cid].status = wil_sta_connected;
+       set_bit(wil_status_fwconnected, wil->status);
+       netif_tx_wake_all_queues(ndev);
 
-       wil->pending_connect_cid = evt->cid;
-       queue_work(wil->wq_service, &wil->connect_worker);
+out:
+       if (rc)
+               wil->sta[evt->cid].status = wil_sta_unused;
+       clear_bit(wil_status_fwconnecting, wil->status);
+       mutex_unlock(&wil->mutex);
 }
 
 static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -511,8 +563,8 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
        struct wmi_disconnect_event *evt = d;
        u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
 
-       wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
-                   evt->bssid, reason_code, evt->disconnect_reason);
+       wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
+                evt->bssid, reason_code, evt->disconnect_reason);
 
        wil->sinfo_gen++;
 
@@ -727,6 +779,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
        void __iomem *src;
        ulong flags;
        unsigned n;
+       unsigned int num_immed_reply = 0;
 
        if (!test_bit(wil_status_mbox_ready, wil->status)) {
                wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
@@ -736,6 +789,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
        for (n = 0;; n++) {
                u16 len;
                bool q;
+               bool immed_reply = false;
 
                r->head = wil_r(wil, RGF_MBOX +
                                offsetof(struct wil6210_mbox_ctl, rx.head));
@@ -784,6 +838,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
                        struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
                        u16 id = le16_to_cpu(wmi->id);
                        u32 tstamp = le32_to_cpu(wmi->timestamp);
+                       spin_lock_irqsave(&wil->wmi_ev_lock, flags);
+                       if (wil->reply_id && wil->reply_id == id) {
+                               if (wil->reply_buf) {
+                                       memcpy(wil->reply_buf, wmi,
+                                              min(len, wil->reply_size));
+                                       immed_reply = true;
+                               }
+                       }
+                       spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
 
                        wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
                                    id, wmi->mid, tstamp);
@@ -799,15 +862,24 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
                wil_w(wil, RGF_MBOX +
                      offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
 
-               /* add to the pending list */
-               spin_lock_irqsave(&wil->wmi_ev_lock, flags);
-               list_add_tail(&evt->list, &wil->pending_wmi_ev);
-               spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
-               q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
-               wil_dbg_wmi(wil, "queue_work -> %d\n", q);
+               if (immed_reply) {
+                       wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
+                                   __func__, wil->reply_id);
+                       kfree(evt);
+                       num_immed_reply++;
+                       complete(&wil->wmi_call);
+               } else {
+                       /* add to the pending list */
+                       spin_lock_irqsave(&wil->wmi_ev_lock, flags);
+                       list_add_tail(&evt->list, &wil->pending_wmi_ev);
+                       spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
+                       q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
+                       wil_dbg_wmi(wil, "queue_work -> %d\n", q);
+               }
        }
        /* normally, 1 event per IRQ should be processed */
-       wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n);
+       wil_dbg_wmi(wil, "%s -> %d events queued, %d completed\n", __func__,
+                   n - num_immed_reply, num_immed_reply);
 }
 
 int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
@@ -818,13 +890,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
 
        mutex_lock(&wil->wmi_mutex);
 
+       spin_lock(&wil->wmi_ev_lock);
+       wil->reply_id = reply_id;
+       wil->reply_buf = reply;
+       wil->reply_size = reply_size;
+       spin_unlock(&wil->wmi_ev_lock);
+
        rc = __wmi_send(wil, cmdid, buf, len);
        if (rc)
                goto out;
 
-       wil->reply_id = reply_id;
-       wil->reply_buf = reply;
-       wil->reply_size = reply_size;
        remain = wait_for_completion_timeout(&wil->wmi_call,
                                             msecs_to_jiffies(to_msec));
        if (0 == remain) {
@@ -837,10 +912,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
                            cmdid, reply_id,
                            to_msec - jiffies_to_msecs(remain));
        }
+
+out:
+       spin_lock(&wil->wmi_ev_lock);
        wil->reply_id = 0;
        wil->reply_buf = NULL;
        wil->reply_size = 0;
- out:
+       spin_unlock(&wil->wmi_ev_lock);
+
        mutex_unlock(&wil->wmi_mutex);
 
        return rc;
@@ -1184,7 +1263,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
        return 0;
 }
 
-int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
+int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
+                      bool full_disconnect)
 {
        int rc;
        u16 reason_code;
@@ -1208,19 +1288,20 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
                return rc;
        }
 
-       /* call event handler manually after processing wmi_call,
-        * to avoid deadlock - disconnect event handler acquires wil->mutex
-        * while it is already held here
-        */
-       reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
-
-       wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
-                   reply.evt.bssid, reason_code,
-                   reply.evt.disconnect_reason);
+       if (full_disconnect) {
+               /* call event handler manually after processing wmi_call,
+                * to avoid deadlock - disconnect event handler acquires
+                * wil->mutex while it is already held here
+                */
+               reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
 
-       wil->sinfo_gen++;
-       wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
+               wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
+                           reply.evt.bssid, reason_code,
+                           reply.evt.disconnect_reason);
 
+               wil->sinfo_gen++;
+               wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
+       }
        return 0;
 }
 
@@ -1348,14 +1429,11 @@ static void wmi_event_handle(struct wil6210_priv *wil,
                            id, wil->reply_id);
                /* check if someone waits for this event */
                if (wil->reply_id && wil->reply_id == id) {
-                       if (wil->reply_buf) {
-                               memcpy(wil->reply_buf, wmi,
-                                      min(len, wil->reply_size));
-                       } else {
-                               wmi_evt_call_handler(wil, id, evt_data,
-                                                    len - sizeof(*wmi));
-                       }
-                       wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
+                       WARN_ON(wil->reply_buf);
+                       wmi_evt_call_handler(wil, id, evt_data,
+                                            len - sizeof(*wmi));
+                       wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
+                                   __func__, id);
                        complete(&wil->wmi_call);
                        return;
                }
index dab25136214a4b181910562f9c99b10cff23da25..1efb1d66e0b7471499a4ff4386c8fa37f1df8bc0 100644 (file)
@@ -2481,9 +2481,7 @@ static int at76_probe(struct usb_interface *interface,
                        dev_err(&interface->dev,
                                "error %d downloading internal firmware\n",
                                ret);
-                       goto exit;
                }
-               usb_put_dev(udev);
                goto exit;
        }
 
index ec013fbd6a81cda4a0cce04a74b469c1f3cda532..72380af9dc523e56055eecccd5402de62972412e 100644 (file)
@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
        case B43_BUS_BCMA:
                bcma_cc = &dev->dev->bdev->bus->drv_cc;
 
-               bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
-               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
-               bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
-               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+               bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+               bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
                break;
 #endif
 #ifdef CONFIG_B43_SSB
@@ -4375,12 +4375,10 @@ redo:
        /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       if (b43_bus_host_is_sdio(dev->dev)) {
+       if (b43_bus_host_is_sdio(dev->dev))
                b43_sdio_free_irq(dev);
-       } else {
-               synchronize_irq(dev->dev->irq);
+       else
                free_irq(dev->dev->irq, dev);
-       }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (!dev)
index b98db8a0a069bdf71e3c09dcf873aa6905700823..da0cdd3138802d6bf1925c5249cbb8e08e083cba 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/brcmfmac-sdio.h>
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
 #include <linux/errno.h>
@@ -46,7 +44,6 @@
 #include "bus.h"
 #include "debug.h"
 #include "sdio.h"
-#include "of.h"
 #include "core.h"
 #include "common.h"
 
@@ -106,18 +103,18 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
 
 int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 {
+       struct brcmfmac_sdio_pd *pdata;
        int ret = 0;
        u8 data;
        u32 addr, gpiocontrol;
        unsigned long flags;
 
-       if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
+       pdata = &sdiodev->settings->bus.sdio;
+       if (pdata->oob_irq_supported) {
                brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
-                         sdiodev->pdata->oob_irq_nr);
-               ret = request_irq(sdiodev->pdata->oob_irq_nr,
-                                 brcmf_sdiod_oob_irqhandler,
-                                 sdiodev->pdata->oob_irq_flags,
-                                 "brcmf_oob_intr",
+                         pdata->oob_irq_nr);
+               ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
+                                 pdata->oob_irq_flags, "brcmf_oob_intr",
                                  &sdiodev->func[1]->dev);
                if (ret != 0) {
                        brcmf_err("request_irq failed %d\n", ret);
@@ -129,7 +126,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
                sdiodev->irq_en = true;
                spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
 
-               ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
+               ret = enable_irq_wake(pdata->oob_irq_nr);
                if (ret != 0) {
                        brcmf_err("enable_irq_wake failed %d\n", ret);
                        return ret;
@@ -158,7 +155,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 
                /* redirect, configure and enable io for interrupt signal */
                data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
-               if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
+               if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
                        data |= SDIO_SEPINT_ACT_HI;
                brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
 
@@ -176,9 +173,12 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
 
 int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 {
+       struct brcmfmac_sdio_pd *pdata;
+
        brcmf_dbg(SDIO, "Entering\n");
 
-       if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
+       pdata = &sdiodev->settings->bus.sdio;
+       if (pdata->oob_irq_supported) {
                sdio_claim_host(sdiodev->func[1]);
                brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
                brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
@@ -187,11 +187,10 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
                if (sdiodev->oob_irq_requested) {
                        sdiodev->oob_irq_requested = false;
                        if (sdiodev->irq_wake) {
-                               disable_irq_wake(sdiodev->pdata->oob_irq_nr);
+                               disable_irq_wake(pdata->oob_irq_nr);
                                sdiodev->irq_wake = false;
                        }
-                       free_irq(sdiodev->pdata->oob_irq_nr,
-                                &sdiodev->func[1]->dev);
+                       free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
                        sdiodev->irq_en = false;
                }
        } else {
@@ -523,7 +522,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
        target_list = pktlist;
        /* for host with broken sg support, prepare a page aligned list */
        __skb_queue_head_init(&local_list);
-       if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
+       if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
                req_sz = 0;
                skb_queue_walk(pktlist, pkt_next)
                        req_sz += pkt_next->len;
@@ -630,7 +629,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
                }
        }
 
-       if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
+       if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
                local_pkt_next = local_list.next;
                orig_offset = 0;
                skb_queue_walk(pktlist, pkt_next) {
@@ -901,7 +900,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
                return;
 
        nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
-                     sdiodev->bus_if->drvr->settings->sdiod_txglomsz);
+                     sdiodev->settings->bus.sdio.txglomsz);
        nents += (nents >> 4) + 1;
 
        WARN_ON(nents > sdiodev->max_segment_count);
@@ -913,7 +912,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
                sdiodev->sg_support = false;
        }
 
-       sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz;
+       sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -1103,8 +1102,6 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
 };
 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
 
-static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
-
 
 static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
                                                  int val)
@@ -1167,20 +1164,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        dev_set_drvdata(&func->dev, bus_if);
        dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
        sdiodev->dev = &sdiodev->func[1]->dev;
-       sdiodev->pdata = brcmfmac_sdio_pdata;
-
-       if (!sdiodev->pdata)
-               brcmf_of_probe(sdiodev);
-
-#ifdef CONFIG_PM_SLEEP
-       /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
-        * is true or when platform data OOB irq is true).
-        */
-       if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
-           ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
-            (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
-               bus_if->wowl_supported = true;
-#endif
 
        brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
 
@@ -1263,8 +1246,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
 
        sdio_flags = MMC_PM_KEEP_POWER;
        if (sdiodev->wowl_enabled) {
-               if (sdiodev->pdata->oob_irq_supported)
-                       enable_irq_wake(sdiodev->pdata->oob_irq_nr);
+               if (sdiodev->settings->bus.sdio.oob_irq_supported)
+                       enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
                else
                        sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
        }
@@ -1296,7 +1279,7 @@ static const struct dev_pm_ops brcmf_sdio_pm_ops = {
 static struct sdio_driver brcmf_sdmmc_driver = {
        .probe = brcmf_ops_sdio_probe,
        .remove = brcmf_ops_sdio_remove,
-       .name = BRCMFMAC_SDIO_PDATA_NAME,
+       .name = KBUILD_MODNAME,
        .id_table = brcmf_sdmmc_ids,
        .drv = {
                .owner = THIS_MODULE,
@@ -1306,37 +1289,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
        },
 };
 
-static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)
-{
-       brcmf_dbg(SDIO, "Enter\n");
-
-       brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
-
-       if (brcmfmac_sdio_pdata->power_on)
-               brcmfmac_sdio_pdata->power_on();
-
-       return 0;
-}
-
-static int brcmf_sdio_pd_remove(struct platform_device *pdev)
-{
-       brcmf_dbg(SDIO, "Enter\n");
-
-       if (brcmfmac_sdio_pdata->power_off)
-               brcmfmac_sdio_pdata->power_off();
-
-       sdio_unregister_driver(&brcmf_sdmmc_driver);
-
-       return 0;
-}
-
-static struct platform_driver brcmf_sdio_pd = {
-       .remove         = brcmf_sdio_pd_remove,
-       .driver         = {
-               .name   = BRCMFMAC_SDIO_PDATA_NAME,
-       }
-};
-
 void brcmf_sdio_register(void)
 {
        int ret;
@@ -1350,19 +1302,6 @@ void brcmf_sdio_exit(void)
 {
        brcmf_dbg(SDIO, "Enter\n");
 
-       if (brcmfmac_sdio_pdata)
-               platform_driver_unregister(&brcmf_sdio_pd);
-       else
-               sdio_unregister_driver(&brcmf_sdmmc_driver);
+       sdio_unregister_driver(&brcmf_sdmmc_driver);
 }
 
-void __init brcmf_sdio_init(void)
-{
-       int ret;
-
-       brcmf_dbg(SDIO, "Enter\n");
-
-       ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
-       if (ret == -ENODEV)
-               brcmf_dbg(SDIO, "No platform data available.\n");
-}
index 36093f93bfbe1c057b978474058abf7880f52beb..8e02a478e889602a61fa4f07ad260d20bea9182b 100644 (file)
@@ -43,6 +43,8 @@ enum brcmf_bus_protocol_type {
        BRCMF_PROTO_MSGBUF
 };
 
+struct brcmf_mp_device;
+
 struct brcmf_bus_dcmd {
        char *name;
        char *param;
@@ -217,7 +219,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
 void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
-int brcmf_attach(struct device *dev);
+int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
 /* Indication from bus module regarding removal/absence of dongle */
 void brcmf_detach(struct device *dev);
 /* Indication from bus module that dongle should be reset */
index 7b01e4ddb315b70ca0432371ecdb695808c2a4ac..d5c2a27573b45cdfcbb72bf32dedc1dcd0af82da 100644 (file)
 #define RSN_AKM_NONE                   0       /* None (IBSS) */
 #define RSN_AKM_UNSPECIFIED            1       /* Over 802.1x */
 #define RSN_AKM_PSK                    2       /* Pre-shared Key */
+#define RSN_AKM_SHA256_1X              5       /* SHA256, 802.1X */
+#define RSN_AKM_SHA256_PSK             6       /* SHA256, Pre-shared Key */
 #define RSN_CAP_LEN                    2       /* Length of RSN capabilities */
-#define RSN_CAP_PTK_REPLAY_CNTR_MASK   0x000C
+#define RSN_CAP_PTK_REPLAY_CNTR_MASK   (BIT(2) | BIT(3))
+#define RSN_CAP_MFPR_MASK              BIT(6)
+#define RSN_CAP_MFPC_MASK              BIT(7)
+#define RSN_PMKID_COUNT_LEN            2
 
 #define VNDR_IE_CMD_LEN                        4       /* length of the set command
                                                 * string :"add", "del" (+ NUL)
@@ -211,12 +216,19 @@ static const struct ieee80211_regdomain brcmf_regdom = {
                REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
 };
 
-static const u32 __wl_cipher_suites[] = {
+/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
+ * are supported. A pointer to this array and the number of entries is passed
+ * on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
+ * So the cipher suite AES_CMAC has to be the last one in the array, and when
+ * device does not support MFP then the number of suites will be decreased by 1
+ */
+static const u32 brcmf_cipher_suites[] = {
        WLAN_CIPHER_SUITE_WEP40,
        WLAN_CIPHER_SUITE_WEP104,
        WLAN_CIPHER_SUITE_TKIP,
        WLAN_CIPHER_SUITE_CCMP,
-       WLAN_CIPHER_SUITE_AES_CMAC,
+       /* Keep as last entry: */
+       WLAN_CIPHER_SUITE_AES_CMAC
 };
 
 /* Vendor specific ie. id = 221, oui and type defines exact ie */
@@ -247,7 +259,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
        brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
                  ch->chan->center_freq, ch->center_freq1, ch->width);
        ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
-       primary_offset = ch->center_freq1 - ch->chan->center_freq;
+       primary_offset = ch->chan->center_freq - ch->center_freq1;
        switch (ch->width) {
        case NL80211_CHAN_WIDTH_20:
        case NL80211_CHAN_WIDTH_20_NOHT:
@@ -256,24 +268,21 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
                break;
        case NL80211_CHAN_WIDTH_40:
                ch_inf.bw = BRCMU_CHAN_BW_40;
-               if (primary_offset < 0)
+               if (primary_offset > 0)
                        ch_inf.sb = BRCMU_CHAN_SB_U;
                else
                        ch_inf.sb = BRCMU_CHAN_SB_L;
                break;
        case NL80211_CHAN_WIDTH_80:
                ch_inf.bw = BRCMU_CHAN_BW_80;
-               if (primary_offset < 0) {
-                       if (primary_offset < -CH_10MHZ_APART)
-                               ch_inf.sb = BRCMU_CHAN_SB_UU;
-                       else
-                               ch_inf.sb = BRCMU_CHAN_SB_UL;
-               } else {
-                       if (primary_offset > CH_10MHZ_APART)
-                               ch_inf.sb = BRCMU_CHAN_SB_LL;
-                       else
-                               ch_inf.sb = BRCMU_CHAN_SB_LU;
-               }
+               if (primary_offset == -30)
+                       ch_inf.sb = BRCMU_CHAN_SB_LL;
+               else if (primary_offset == -10)
+                       ch_inf.sb = BRCMU_CHAN_SB_LU;
+               else if (primary_offset == 10)
+                       ch_inf.sb = BRCMU_CHAN_SB_UL;
+               else
+                       ch_inf.sb = BRCMU_CHAN_SB_UU;
                break;
        case NL80211_CHAN_WIDTH_80P80:
        case NL80211_CHAN_WIDTH_160:
@@ -459,7 +468,7 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
 }
 
 static s32
-brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
+brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
 {
        s32 err;
        u32 mode;
@@ -487,6 +496,15 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
                                  enable, mode);
        }
 
+       err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
+       if (err) {
+               brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
+                         enable, err);
+               err = 0;
+       } else
+               brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
+                         enable, mode);
+
        return err;
 }
 
@@ -567,8 +585,8 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
        }
 
        /* wait for firmware event */
-       err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
-                                                   BRCMF_VIF_EVENT_TIMEOUT);
+       err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
+                                           BRCMF_VIF_EVENT_TIMEOUT);
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
        if (!err) {
                brcmf_err("timeout occurred\n");
@@ -1128,7 +1146,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
 
        /* Arm scan timeout timer */
        mod_timer(&cfg->escan_timeout, jiffies +
-                       WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
+                       BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
 
        return 0;
 
@@ -1527,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
 
 static s32
 brcmf_set_wsec_mode(struct net_device *ndev,
-                    struct cfg80211_connect_params *sme, bool mfp)
+                   struct cfg80211_connect_params *sme)
 {
        struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
        struct brcmf_cfg80211_security *sec;
@@ -1586,10 +1604,7 @@ brcmf_set_wsec_mode(struct net_device *ndev,
            sme->privacy)
                pval = AES_ENABLED;
 
-       if (mfp)
-               wsec = pval | gval | MFP_CAPABLE;
-       else
-               wsec = pval | gval;
+       wsec = pval | gval;
        err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
        if (err) {
                brcmf_err("error (%d)\n", err);
@@ -1606,56 +1621,100 @@ brcmf_set_wsec_mode(struct net_device *ndev,
 static s32
 brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
 {
-       struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
-       struct brcmf_cfg80211_security *sec;
-       s32 val = 0;
-       s32 err = 0;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       s32 val;
+       s32 err;
+       const struct brcmf_tlv *rsn_ie;
+       const u8 *ie;
+       u32 ie_len;
+       u32 offset;
+       u16 rsn_cap;
+       u32 mfp;
+       u16 count;
 
-       if (sme->crypto.n_akm_suites) {
-               err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
-                                              "wpa_auth", &val);
-               if (err) {
-                       brcmf_err("could not get wpa_auth (%d)\n", err);
-                       return err;
+       if (!sme->crypto.n_akm_suites)
+               return 0;
+
+       err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
+       if (err) {
+               brcmf_err("could not get wpa_auth (%d)\n", err);
+               return err;
+       }
+       if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+               switch (sme->crypto.akm_suites[0]) {
+               case WLAN_AKM_SUITE_8021X:
+                       val = WPA_AUTH_UNSPECIFIED;
+                       break;
+               case WLAN_AKM_SUITE_PSK:
+                       val = WPA_AUTH_PSK;
+                       break;
+               default:
+                       brcmf_err("invalid cipher group (%d)\n",
+                                 sme->crypto.cipher_group);
+                       return -EINVAL;
                }
-               if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
-                       switch (sme->crypto.akm_suites[0]) {
-                       case WLAN_AKM_SUITE_8021X:
-                               val = WPA_AUTH_UNSPECIFIED;
-                               break;
-                       case WLAN_AKM_SUITE_PSK:
-                               val = WPA_AUTH_PSK;
-                               break;
-                       default:
-                               brcmf_err("invalid cipher group (%d)\n",
-                                         sme->crypto.cipher_group);
-                               return -EINVAL;
-                       }
-               } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
-                       switch (sme->crypto.akm_suites[0]) {
-                       case WLAN_AKM_SUITE_8021X:
-                               val = WPA2_AUTH_UNSPECIFIED;
-                               break;
-                       case WLAN_AKM_SUITE_PSK:
-                               val = WPA2_AUTH_PSK;
-                               break;
-                       default:
-                               brcmf_err("invalid cipher group (%d)\n",
-                                         sme->crypto.cipher_group);
-                               return -EINVAL;
-                       }
+       } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+               switch (sme->crypto.akm_suites[0]) {
+               case WLAN_AKM_SUITE_8021X:
+                       val = WPA2_AUTH_UNSPECIFIED;
+                       break;
+               case WLAN_AKM_SUITE_8021X_SHA256:
+                       val = WPA2_AUTH_1X_SHA256;
+                       break;
+               case WLAN_AKM_SUITE_PSK_SHA256:
+                       val = WPA2_AUTH_PSK_SHA256;
+                       break;
+               case WLAN_AKM_SUITE_PSK:
+                       val = WPA2_AUTH_PSK;
+                       break;
+               default:
+                       brcmf_err("invalid cipher group (%d)\n",
+                                 sme->crypto.cipher_group);
+                       return -EINVAL;
                }
+       }
 
-               brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
-               err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
-                                              "wpa_auth", val);
-               if (err) {
-                       brcmf_err("could not set wpa_auth (%d)\n", err);
-                       return err;
-               }
+       if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
+               goto skip_mfp_config;
+       /* The MFP mode (1 or 2) needs to be determined, parse IEs. The
+        * IE will not be verified, just a quick search for MFP config
+        */
+       rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
+                                 WLAN_EID_RSN);
+       if (!rsn_ie)
+               goto skip_mfp_config;
+       ie = (const u8 *)rsn_ie;
+       ie_len = rsn_ie->len + TLV_HDR_LEN;
+       /* Skip unicast suite */
+       offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
+       if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
+               goto skip_mfp_config;
+       /* Skip multicast suite */
+       count = ie[offset] + (ie[offset + 1] << 8);
+       offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
+       if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
+               goto skip_mfp_config;
+       /* Skip auth key management suite(s) */
+       count = ie[offset] + (ie[offset + 1] << 8);
+       offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
+       if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
+               goto skip_mfp_config;
+       /* Ready to read capabilities */
+       mfp = BRCMF_MFP_NONE;
+       rsn_cap = ie[offset] + (ie[offset + 1] << 8);
+       if (rsn_cap & RSN_CAP_MFPR_MASK)
+               mfp = BRCMF_MFP_REQUIRED;
+       else if (rsn_cap & RSN_CAP_MFPC_MASK)
+               mfp = BRCMF_MFP_CAPABLE;
+       brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
+
+skip_mfp_config:
+       brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
+       err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
+       if (err) {
+               brcmf_err("could not set wpa_auth (%d)\n", err);
+               return err;
        }
-       sec = &profile->sec;
-       sec->wpa_auth = sme->crypto.akm_suites[0];
 
        return err;
 }
@@ -1821,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                goto done;
        }
 
-       err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
+       err = brcmf_set_wsec_mode(ndev, sme);
        if (err) {
                brcmf_err("wl_set_set_cipher failed (%d)\n", err);
                goto done;
@@ -2067,98 +2126,54 @@ done:
 }
 
 static s32
-brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
-             u8 key_idx, const u8 *mac_addr, struct key_params *params)
+brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+                      u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_wsec_key key;
-       s32 err = 0;
-       u8 keybuf[8];
+       struct brcmf_wsec_key *key;
+       s32 err;
 
-       memset(&key, 0, sizeof(key));
-       key.index = (u32) key_idx;
-       /* Instead of bcast for ea address for default wep keys,
-                driver needs it to be Null */
-       if (!is_multicast_ether_addr(mac_addr))
-               memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
-       key.len = (u32) params->key_len;
-       /* check for key index change */
-       if (key.len == 0) {
-               /* key delete */
-               err = send_key_to_dongle(ifp, &key);
-               if (err)
-                       brcmf_err("key delete error (%d)\n", err);
-       } else {
-               if (key.len > sizeof(key.data)) {
-                       brcmf_err("Invalid key length (%d)\n", key.len);
-                       return -EINVAL;
-               }
+       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(CONN, "key index (%d)\n", key_idx);
 
-               brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
-               memcpy(key.data, params->key, key.len);
+       if (!check_vif_up(ifp->vif))
+               return -EIO;
 
-               if (!brcmf_is_apmode(ifp->vif) &&
-                   (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
-                       brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
-                       memcpy(keybuf, &key.data[24], sizeof(keybuf));
-                       memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
-                       memcpy(&key.data[16], keybuf, sizeof(keybuf));
-               }
+       if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
+               /* we ignore this key index in this case */
+               return -EINVAL;
+       }
 
-               /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
-               if (params->seq && params->seq_len == 6) {
-                       /* rx iv */
-                       u8 *ivptr;
-                       ivptr = (u8 *) params->seq;
-                       key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
-                           (ivptr[3] << 8) | ivptr[2];
-                       key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
-                       key.iv_initialized = true;
-               }
+       key = &ifp->vif->profile.key[key_idx];
 
-               switch (params->cipher) {
-               case WLAN_CIPHER_SUITE_WEP40:
-                       key.algo = CRYPTO_ALGO_WEP1;
-                       brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
-                       break;
-               case WLAN_CIPHER_SUITE_WEP104:
-                       key.algo = CRYPTO_ALGO_WEP128;
-                       brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
-                       break;
-               case WLAN_CIPHER_SUITE_TKIP:
-                       key.algo = CRYPTO_ALGO_TKIP;
-                       brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
-                       break;
-               case WLAN_CIPHER_SUITE_AES_CMAC:
-                       key.algo = CRYPTO_ALGO_AES_CCM;
-                       brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
-                       break;
-               case WLAN_CIPHER_SUITE_CCMP:
-                       key.algo = CRYPTO_ALGO_AES_CCM;
-                       brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
-                       break;
-               default:
-                       brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
-                       return -EINVAL;
-               }
-               err = send_key_to_dongle(ifp, &key);
-               if (err)
-                       brcmf_err("wsec_key error (%d)\n", err);
+       if (key->algo == CRYPTO_ALGO_OFF) {
+               brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
+               return -EINVAL;
        }
+
+       memset(key, 0, sizeof(*key));
+       key->index = (u32)key_idx;
+       key->flags = BRCMF_PRIMARY_KEY;
+
+       /* Clear the key/index */
+       err = send_key_to_dongle(ifp, key);
+
+       brcmf_dbg(TRACE, "Exit\n");
        return err;
 }
 
 static s32
 brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
-                   u8 key_idx, bool pairwise, const u8 *mac_addr,
-                   struct key_params *params)
+                      u8 key_idx, bool pairwise, const u8 *mac_addr,
+                      struct key_params *params)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_wsec_key *key;
        s32 val;
        s32 wsec;
-       s32 err = 0;
+       s32 err;
        u8 keybuf[8];
+       bool ext_key;
 
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_dbg(CONN, "key index (%d)\n", key_idx);
@@ -2171,27 +2186,32 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                return -EINVAL;
        }
 
-       if (mac_addr &&
-               (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
-               (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
-               brcmf_dbg(TRACE, "Exit");
-               return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
-       }
-
-       key = &ifp->vif->profile.key[key_idx];
-       memset(key, 0, sizeof(*key));
+       if (params->key_len == 0)
+               return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
+                                             mac_addr);
 
        if (params->key_len > sizeof(key->data)) {
                brcmf_err("Too long key length (%u)\n", params->key_len);
-               err = -EINVAL;
-               goto done;
+               return -EINVAL;
+       }
+
+       ext_key = false;
+       if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+           (params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
+               brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
+               ext_key = true;
        }
+
+       key = &ifp->vif->profile.key[key_idx];
+       memset(key, 0, sizeof(*key));
+       if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
+               memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
        key->len = params->key_len;
        key->index = key_idx;
-
        memcpy(key->data, params->key, key->len);
+       if (!ext_key)
+               key->flags = BRCMF_PRIMARY_KEY;
 
-       key->flags = BRCMF_PRIMARY_KEY;
        switch (params->cipher) {
        case WLAN_CIPHER_SUITE_WEP40:
                key->algo = CRYPTO_ALGO_WEP1;
@@ -2231,7 +2251,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        err = send_key_to_dongle(ifp, key);
-       if (err)
+       if (ext_key || err)
                goto done;
 
        err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
@@ -2252,41 +2272,10 @@ done:
 }
 
 static s32
-brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
-                   u8 key_idx, bool pairwise, const u8 *mac_addr)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_wsec_key key;
-       s32 err = 0;
-
-       brcmf_dbg(TRACE, "Enter\n");
-       if (!check_vif_up(ifp->vif))
-               return -EIO;
-
-       if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
-               /* we ignore this key index in this case */
-               return -EINVAL;
-       }
-
-       memset(&key, 0, sizeof(key));
-
-       key.index = (u32) key_idx;
-       key.flags = BRCMF_PRIMARY_KEY;
-       key.algo = CRYPTO_ALGO_OFF;
-
-       brcmf_dbg(CONN, "key index (%d)\n", key_idx);
-
-       /* Set the new key/index */
-       err = send_key_to_dongle(ifp, &key);
-
-       brcmf_dbg(TRACE, "Exit\n");
-       return err;
-}
-
-static s32
-brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
-                   u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
-                   void (*callback) (void *cookie, struct key_params * params))
+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
+                      bool pairwise, const u8 *mac_addr, void *cookie,
+                      void (*callback)(void *cookie,
+                                       struct key_params *params))
 {
        struct key_params params;
        struct brcmf_if *ifp = netdev_priv(ndev);
@@ -2338,8 +2327,15 @@ done:
 
 static s32
 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
-                                   struct net_device *ndev, u8 key_idx)
+                                      struct net_device *ndev, u8 key_idx)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+
+       brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
+
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
+               return 0;
+
        brcmf_dbg(INFO, "Not supported\n");
 
        return -EOPNOTSUPP;
@@ -3023,7 +3019,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
 
                list = (struct brcmf_scan_results *)
                                cfg->escan_info.escan_buf;
-               if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
+               if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
                        brcmf_err("Buffer is too small: ignoring\n");
                        goto exit;
                }
@@ -3036,8 +3032,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
                                                          bss_info_le))
                                goto exit;
                }
-               memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
-                       bss_info_le, bi_length);
+               memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
+                      bi_length);
                list->version = le32_to_cpu(bss_info_le->version);
                list->buflen += bi_length;
                list->count++;
@@ -3095,6 +3091,11 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
 
        brcmf_dbg(SCAN, "Enter\n");
 
+       if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
+               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+               return 0;
+       }
+
        if (e->event_code == BRCMF_E_PFN_NET_LOST) {
                brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
                return 0;
@@ -3418,6 +3419,11 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
 
        brcmf_dbg(SCAN, "Enter\n");
 
+       if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
+               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+               return 0;
+       }
+
        pfn_result = (struct brcmf_pno_scanresults_le *)data;
 
        if (e->event_code == BRCMF_E_PFN_NET_LOST) {
@@ -3510,6 +3516,10 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
                        else
                                wakeup_data.net_detect = cfg->wowl.nd_info;
                }
+               if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
+                       brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
+                       wakeup_data.gtk_rekey_failure = true;
+               }
        } else {
                wakeup = NULL;
        }
@@ -3536,7 +3546,8 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
                brcmf_report_wowl_wakeind(wiphy, ifp);
                brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
                brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
-               brcmf_configure_arp_offload(ifp, true);
+               if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
+                       brcmf_configure_arp_nd_offload(ifp, true);
                brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
                                      cfg->wowl.pre_pmmode);
                cfg->wowl.active = false;
@@ -3560,7 +3571,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
 
        brcmf_dbg(TRACE, "Suspend, wowl config.\n");
 
-       brcmf_configure_arp_offload(ifp, false);
+       if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
+               brcmf_configure_arp_nd_offload(ifp, false);
        brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
        brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
 
@@ -3591,6 +3603,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
                brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
                                    brcmf_wowl_nd_results);
        }
+       if (wowl->gtk_rekey_failure)
+               wowl_config |= BRCMF_WOWL_GTK_FAILURE;
        if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
                wowl_config |= BRCMF_WOWL_UNASSOC;
 
@@ -3821,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
        u32 auth = 0; /* d11 open authentication */
        u16 count;
        s32 err = 0;
-       s32 len = 0;
+       s32 len;
        u32 i;
        u32 wsec;
        u32 pval = 0;
@@ -3831,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
        u8 *data;
        u16 rsn_cap;
        u32 wme_bss_disable;
+       u32 mfp;
 
        brcmf_dbg(TRACE, "Enter\n");
        if (wpa_ie == NULL)
@@ -3945,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
                        is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
                                    (wpa_auth |= WPA_AUTH_PSK);
                        break;
+               case RSN_AKM_SHA256_PSK:
+                       brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
+                       wpa_auth |= WPA2_AUTH_PSK_SHA256;
+                       break;
+               case RSN_AKM_SHA256_1X:
+                       brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
+                       wpa_auth |= WPA2_AUTH_1X_SHA256;
+                       break;
                default:
                        brcmf_err("Ivalid key mgmt info\n");
                }
                offset++;
        }
 
+       mfp = BRCMF_MFP_NONE;
        if (is_rsn_ie) {
                wme_bss_disable = 1;
                if ((offset + RSN_CAP_LEN) <= len) {
                        rsn_cap = data[offset] + (data[offset + 1] << 8);
                        if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
                                wme_bss_disable = 0;
+                       if (rsn_cap & RSN_CAP_MFPR_MASK) {
+                               brcmf_dbg(TRACE, "MFP Required\n");
+                               mfp = BRCMF_MFP_REQUIRED;
+                               /* Firmware only supports mfp required in
+                                * combination with WPA2_AUTH_PSK_SHA256 or
+                                * WPA2_AUTH_1X_SHA256.
+                                */
+                               if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
+                                                 WPA2_AUTH_1X_SHA256))) {
+                                       err = -EINVAL;
+                                       goto exit;
+                               }
+                               /* Firmware has requirement that WPA2_AUTH_PSK/
+                                * WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
+                                * is to be included in the rsn ie.
+                                */
+                               if (wpa_auth & WPA2_AUTH_PSK_SHA256)
+                                       wpa_auth |= WPA2_AUTH_PSK;
+                               else if (wpa_auth & WPA2_AUTH_1X_SHA256)
+                                       wpa_auth |= WPA2_AUTH_UNSPECIFIED;
+                       } else if (rsn_cap & RSN_CAP_MFPC_MASK) {
+                               brcmf_dbg(TRACE, "MFP Capable\n");
+                               mfp = BRCMF_MFP_CAPABLE;
+                       }
                }
+               offset += RSN_CAP_LEN;
                /* set wme_bss_disable to sync RSN Capabilities */
                err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
                                               wme_bss_disable);
@@ -3965,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
                        brcmf_err("wme_bss_disable error %d\n", err);
                        goto exit;
                }
+
+               /* Skip PMKID cnt as it is know to be 0 for AP. */
+               offset += RSN_PMKID_COUNT_LEN;
+
+               /* See if there is BIP wpa suite left for MFP */
+               if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
+                   ((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
+                       err = brcmf_fil_bsscfg_data_set(ifp, "bip",
+                                                       &data[offset],
+                                                       WPA_IE_MIN_OUI_LEN);
+                       if (err < 0) {
+                               brcmf_err("bip error %d\n", err);
+                               goto exit;
+                       }
+               }
        }
        /* FOR WPS , set SES_OW_ENABLED */
        wsec = (pval | gval | SES_OW_ENABLED);
@@ -3981,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
                brcmf_err("wsec error %d\n", err);
                goto exit;
        }
+       /* Configure MFP, this needs to go after wsec otherwise the wsec command
+        * will overwrite the values set by MFP
+        */
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
+               err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
+               if (err < 0) {
+                       brcmf_err("mfp error %d\n", err);
+                       goto exit;
+               }
+       }
        /* set upper-layer auth */
        err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
        if (err < 0) {
@@ -4329,7 +4403,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 
        if (!mbss) {
                brcmf_set_mpc(ifp, 0);
-               brcmf_configure_arp_offload(ifp, false);
+               brcmf_configure_arp_nd_offload(ifp, false);
        }
 
        /* find the RSN_IE */
@@ -4475,7 +4549,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
 exit:
        if ((err) && (!mbss)) {
                brcmf_set_mpc(ifp, 1);
-               brcmf_configure_arp_offload(ifp, true);
+               brcmf_configure_arp_nd_offload(ifp, true);
        }
        return err;
 }
@@ -4533,7 +4607,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
                        brcmf_err("bss_enable config failed %d\n", err);
        }
        brcmf_set_mpc(ifp, 1);
-       brcmf_configure_arp_offload(ifp, true);
+       brcmf_configure_arp_nd_offload(ifp, true);
        clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
        brcmf_net_setcarrier(ifp, false);
 
@@ -4858,7 +4932,32 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
        return ret;
 }
 
-static struct cfg80211_ops wl_cfg80211_ops = {
+#ifdef CONFIG_PM
+static int
+brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
+                             struct cfg80211_gtk_rekey_data *gtk)
+{
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_gtk_keyinfo_le gtk_le;
+       int ret;
+
+       brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
+
+       memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
+       memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
+       memcpy(gtk_le.replay_counter, gtk->replay_ctr,
+              sizeof(gtk_le.replay_counter));
+
+       ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
+                                      sizeof(gtk_le));
+       if (ret < 0)
+               brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
+
+       return ret;
+}
+#endif
+
+static struct cfg80211_ops brcmf_cfg80211_ops = {
        .add_virtual_intf = brcmf_cfg80211_add_iface,
        .del_virtual_intf = brcmf_cfg80211_del_iface,
        .change_virtual_intf = brcmf_cfg80211_change_iface,
@@ -5405,14 +5504,14 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
 {
        kfree(cfg->conf);
        cfg->conf = NULL;
-       kfree(cfg->escan_ioctl_buf);
-       cfg->escan_ioctl_buf = NULL;
        kfree(cfg->extra_buf);
        cfg->extra_buf = NULL;
        kfree(cfg->wowl.nd);
        cfg->wowl.nd = NULL;
        kfree(cfg->wowl.nd_info);
        cfg->wowl.nd_info = NULL;
+       kfree(cfg->escan_info.escan_buf);
+       cfg->escan_info.escan_buf = NULL;
 }
 
 static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -5420,9 +5519,6 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
        cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
        if (!cfg->conf)
                goto init_priv_mem_out;
-       cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
-       if (!cfg->escan_ioctl_buf)
-               goto init_priv_mem_out;
        cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
        if (!cfg->extra_buf)
                goto init_priv_mem_out;
@@ -5434,6 +5530,9 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
                                    GFP_KERNEL);
        if (!cfg->wowl.nd_info)
                goto init_priv_mem_out;
+       cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
+       if (!cfg->escan_info.escan_buf)
+               goto init_priv_mem_out;
 
        return 0;
 
@@ -6123,19 +6222,18 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
 {
 #ifdef CONFIG_PM
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       s32 err;
-       u32 wowl_cap;
 
        if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
-               err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
-               if (!err) {
-                       if (wowl_cap & BRCMF_WOWL_PFN_FOUND) {
-                               brcmf_wowlan_support.flags |=
-                                                       WIPHY_WOWLAN_NET_DETECT;
-                               init_waitqueue_head(&cfg->wowl.nd_data_wait);
-                       }
+               if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
+                       brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
+                       init_waitqueue_head(&cfg->wowl.nd_data_wait);
                }
        }
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
+               brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
+               brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+       }
+
        wiphy->wowlan = &brcmf_wowlan_support;
 #endif
 }
@@ -6177,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
        wiphy->n_addresses = i;
 
        wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-       wiphy->cipher_suites = __wl_cipher_suites;
-       wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+       wiphy->cipher_suites = brcmf_cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
+       if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
+               wiphy->n_cipher_suites--;
        wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
                        WIPHY_FLAG_OFFCHAN_TX |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@@ -6280,7 +6380,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
        if (err)
                goto default_conf_out;
 
-       brcmf_configure_arp_offload(ifp, true);
+       brcmf_configure_arp_nd_offload(ifp, true);
 
        cfg->dongle_up = true;
 default_conf_out:
@@ -6398,8 +6498,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
 
        return armed;
 }
-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
-                                         u8 action, ulong timeout)
+
+int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
+                                 u8 action, ulong timeout)
 {
        struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
 
@@ -6407,28 +6508,85 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
                                  vif_event_equals(event, action), timeout);
 }
 
+static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
+                                       struct brcmf_fil_country_le *ccreq)
+{
+       struct brcmfmac_pd_cc *country_codes;
+       struct brcmfmac_pd_cc_entry *cc;
+       s32 found_index;
+       int i;
+
+       country_codes = drvr->settings->country_codes;
+       if (!country_codes) {
+               brcmf_dbg(TRACE, "No country codes configured for device\n");
+               return -EINVAL;
+       }
+
+       if ((alpha2[0] == ccreq->country_abbrev[0]) &&
+           (alpha2[1] == ccreq->country_abbrev[1])) {
+               brcmf_dbg(TRACE, "Country code already set\n");
+               return -EAGAIN;
+       }
+
+       found_index = -1;
+       for (i = 0; i < country_codes->table_size; i++) {
+               cc = &country_codes->table[i];
+               if ((cc->iso3166[0] == '\0') && (found_index == -1))
+                       found_index = i;
+               if ((cc->iso3166[0] == alpha2[0]) &&
+                   (cc->iso3166[1] == alpha2[1])) {
+                       found_index = i;
+                       break;
+               }
+       }
+       if (found_index == -1) {
+               brcmf_dbg(TRACE, "No country code match found\n");
+               return -EINVAL;
+       }
+       memset(ccreq, 0, sizeof(*ccreq));
+       ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
+       memcpy(ccreq->ccode, country_codes->table[found_index].cc,
+              BRCMF_COUNTRY_BUF_SZ);
+       ccreq->country_abbrev[0] = alpha2[0];
+       ccreq->country_abbrev[1] = alpha2[1];
+       ccreq->country_abbrev[2] = 0;
+
+       return 0;
+}
+
 static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
                                        struct regulatory_request *req)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct brcmf_fil_country_le ccreq;
+       s32 err;
        int i;
 
-       brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
-                 req->alpha2[0], req->alpha2[1]);
-
        /* ignore non-ISO3166 country codes */
        for (i = 0; i < sizeof(req->alpha2); i++)
                if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
-                       brcmf_err("not a ISO3166 code\n");
+                       brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
+                                 req->alpha2[0], req->alpha2[1]);
                        return;
                }
-       memset(&ccreq, 0, sizeof(ccreq));
-       ccreq.rev = cpu_to_le32(-1);
-       memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
-       if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
-               brcmf_err("firmware rejected country setting\n");
+
+       brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
+                 req->alpha2[0], req->alpha2[1]);
+
+       err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
+       if (err) {
+               brcmf_err("Country code iovar returned err = %d\n", err);
+               return;
+       }
+
+       err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
+       if (err)
+               return;
+
+       err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
+       if (err) {
+               brcmf_err("Firmware rejected country setting\n");
                return;
        }
        brcmf_setup_wiphybands(wiphy);
@@ -6464,6 +6622,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
        struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
        struct brcmf_cfg80211_info *cfg;
        struct wiphy *wiphy;
+       struct cfg80211_ops *ops;
        struct brcmf_cfg80211_vif *vif;
        struct brcmf_if *ifp;
        s32 err = 0;
@@ -6475,8 +6634,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
                return NULL;
        }
 
+       ops = kzalloc(sizeof(*ops), GFP_KERNEL);
+       if (!ops)
+               return NULL;
+
+       memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
        ifp = netdev_priv(ndev);
-       wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
+#ifdef CONFIG_PM
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
+               ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
+#endif
+       wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
        if (!wiphy) {
                brcmf_err("Could not allocate wiphy device\n");
                return NULL;
@@ -6486,6 +6654,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
 
        cfg = wiphy_priv(wiphy);
        cfg->wiphy = wiphy;
+       cfg->ops = ops;
        cfg->pub = drvr;
        init_vif_event(&cfg->vif_event);
        INIT_LIST_HEAD(&cfg->vif_list);
@@ -6596,7 +6765,8 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
        if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
                wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
 #ifdef CONFIG_PM
-               if (wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
+               if (wiphy->wowlan &&
+                   wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
                        wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
 #endif
        }
@@ -6611,6 +6781,7 @@ priv_out:
        ifp->vif = NULL;
 wiphy_out:
        brcmf_free_wiphy(wiphy);
+       kfree(ops);
        return NULL;
 }
 
@@ -6621,6 +6792,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 
        brcmf_btcoex_detach(cfg);
        wiphy_unregister(cfg->wiphy);
+       kfree(cfg->ops);
        wl_deinit_priv(cfg);
        brcmf_free_wiphy(cfg->wiphy);
 }
index 40efb539ac26b233cb3888f23dd2083ffdd2dd60..95e35bcc16ce0018d957e395e5df12f421334e6d 100644 (file)
 #define WL_ROAM_TRIGGER_LEVEL          -75
 #define WL_ROAM_DELTA                  20
 
-#define WL_ESCAN_BUF_SIZE              (1024 * 64)
-#define WL_ESCAN_TIMER_INTERVAL_MS     10000 /* E-Scan timeout */
+/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
+ * problematic on some systems and should be avoided.
+ */
+#define BRCMF_ESCAN_BUF_SIZE           65000
+#define BRCMF_ESCAN_TIMER_INTERVAL_MS  10000   /* E-Scan timeout */
 
 #define WL_ESCAN_ACTION_START          1
 #define WL_ESCAN_ACTION_CONTINUE       2
@@ -69,7 +72,7 @@
 
 #define BRCMF_VNDR_IE_P2PAF_SHIFT      12
 
-#define BRCMF_MAX_DEFAULT_KEYS         4
+#define BRCMF_MAX_DEFAULT_KEYS         6
 
 /* beacon loss timeout defaults */
 #define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON      2
@@ -104,7 +107,6 @@ struct brcmf_cfg80211_security {
        u32 auth_type;
        u32 cipher_pairwise;
        u32 cipher_group;
-       u32 wpa_auth;
 };
 
 /**
@@ -205,7 +207,7 @@ enum wl_escan_state {
 
 struct escan_info {
        u32 escan_state;
-       u8 escan_buf[WL_ESCAN_BUF_SIZE];
+       u8 *escan_buf;
        struct wiphy *wiphy;
        struct brcmf_if *ifp;
        s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
@@ -253,6 +255,7 @@ struct brcmf_cfg80211_wowl {
  * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
  *
  * @wiphy: wiphy object for cfg80211 interface.
+ * @ops: pointer to copy of ops as registered with wiphy object.
  * @conf: dongle configuration.
  * @p2p: peer-to-peer specific information.
  * @btcoex: Bluetooth coexistence information.
@@ -278,7 +281,6 @@ struct brcmf_cfg80211_wowl {
  * @escan_info: escan information.
  * @escan_timeout: Timer for catch scan timeout.
  * @escan_timeout_work: scan timeout worker.
- * @escan_ioctl_buf: dongle command buffer for escan commands.
  * @vif_list: linked list of vif instances.
  * @vif_cnt: number of vif instances.
  * @vif_event: vif event signalling.
@@ -286,6 +288,7 @@ struct brcmf_cfg80211_wowl {
  */
 struct brcmf_cfg80211_info {
        struct wiphy *wiphy;
+       struct cfg80211_ops *ops;
        struct brcmf_cfg80211_conf *conf;
        struct brcmf_p2p_info p2p;
        struct brcmf_btcoex_info *btcoex;
@@ -309,7 +312,6 @@ struct brcmf_cfg80211_info {
        struct escan_info escan_info;
        struct timer_list escan_timeout;
        struct work_struct escan_timeout_work;
-       u8 *escan_ioctl_buf;
        struct list_head vif_list;
        struct brcmf_cfg80211_vif_event vif_event;
        struct completion vif_disabled;
@@ -402,8 +404,8 @@ bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
 void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
                                  struct brcmf_cfg80211_vif *vif);
 bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
-int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
-                                         u8 action, ulong timeout);
+int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
+                                 u8 action, ulong timeout);
 s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                                struct brcmf_if *ifp, bool aborted,
                                bool fw_abort);
index 82e4382eb177c98733f79b79f6dc6e78af3066d7..0e8f2a079907d7c9deb8cef9eaafa61877eaf1b3 100644 (file)
@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
                                *eromaddr -= 4;
                                return -EFAULT;
                        }
-               } while (desc != DMP_DESC_ADDRESS);
+               } while (desc != DMP_DESC_ADDRESS &&
+                        desc != DMP_DESC_COMPONENT);
+
+               /* stop if we crossed current component border */
+               if (desc == DMP_DESC_COMPONENT) {
+                       *eromaddr -= 4;
+                       return 0;
+               }
 
                /* skip upper 32-bit address descriptor */
                if (val & DMP_DESC_ADDRSIZE_GT32)
@@ -876,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
                rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
 
                /* need core with ports */
-               if (nmw + nsw == 0)
+               if (nmw + nsw == 0 &&
+                   id != BCMA_CORE_PMU)
                        continue;
 
                /* try to obtain register address info */
@@ -1006,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
 {
        struct brcmf_chip *pub;
        struct brcmf_core_priv *cc;
+       struct brcmf_core *pmu;
        u32 base;
        u32 val;
        int ret = 0;
@@ -1017,11 +1026,15 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
        /* get chipcommon capabilites */
        pub->cc_caps = chip->ops->read32(chip->ctx,
                                         CORE_CC_REG(base, capabilities));
+       pub->cc_caps_ext = chip->ops->read32(chip->ctx,
+                                            CORE_CC_REG(base,
+                                                        capabilities_ext));
 
        /* get pmu caps & rev */
+       pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */
        if (pub->cc_caps & CC_CAP_PMU) {
                val = chip->ops->read32(chip->ctx,
-                                       CORE_CC_REG(base, pmucapabilities));
+                                       CORE_CC_REG(pmu->base, pmucapabilities));
                pub->pmurev = val & PCAP_REV_MASK;
                pub->pmucaps = val;
        }
@@ -1120,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub)
        return &cc->pub;
 }
 
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
+{
+       struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub);
+       struct brcmf_core *pmu;
+
+       /* See if there is separated PMU core available */
+       if (cc->rev >= 35 &&
+           pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
+               pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU);
+               if (pmu)
+                       return pmu;
+       }
+
+       /* Fallback to ChipCommon core for older hardware */
+       return cc;
+}
+
 bool brcmf_chip_iscoreup(struct brcmf_core *pub)
 {
        struct brcmf_core_priv *core;
@@ -1290,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
 {
        u32 base, addr, reg, pmu_cc3_mask = ~0;
        struct brcmf_chip_priv *chip;
+       struct brcmf_core *pmu = brcmf_chip_get_pmu(pub);
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -1309,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
        case BRCM_CC_4335_CHIP_ID:
        case BRCM_CC_4339_CHIP_ID:
                /* read PMU chipcontrol register 3 */
-               addr = CORE_CC_REG(base, chipcontrol_addr);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
                chip->ops->write32(chip->ctx, addr, 3);
-               addr = CORE_CC_REG(base, chipcontrol_data);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_data);
                reg = chip->ops->read32(chip->ctx, addr);
                return (reg & pmu_cc3_mask) != 0;
        case BRCM_CC_43430_CHIP_ID:
@@ -1319,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
                reg = chip->ops->read32(chip->ctx, addr);
                return reg != 0;
        default:
-               addr = CORE_CC_REG(base, pmucapabilities_ext);
+               addr = CORE_CC_REG(pmu->base, pmucapabilities_ext);
                reg = chip->ops->read32(chip->ctx, addr);
                if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
                        return false;
 
-               addr = CORE_CC_REG(base, retention_ctl);
+               addr = CORE_CC_REG(pmu->base, retention_ctl);
                reg = chip->ops->read32(chip->ctx, addr);
                return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
                               PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
index f6b5feea23d20508abf4fc0e6670adf51b966d33..dd0ec3eba6a98505e92005789bcbed7fa53dedb1 100644 (file)
@@ -27,6 +27,7 @@
  * @chip: chip identifier.
  * @chiprev: chip revision.
  * @cc_caps: chipcommon core capabilities.
+ * @cc_caps_ext: chipcommon core extended capabilities.
  * @pmucaps: PMU capabilities.
  * @pmurev: PMU revision.
  * @rambase: RAM base address (only applicable for ARM CR4 chips).
@@ -38,6 +39,7 @@ struct brcmf_chip {
        u32 chip;
        u32 chiprev;
        u32 cc_caps;
+       u32 cc_caps_ext;
        u32 pmucaps;
        u32 pmurev;
        u32 rambase;
@@ -83,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx,
 void brcmf_chip_detach(struct brcmf_chip *chip);
 struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
 struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
 bool brcmf_chip_iscoreup(struct brcmf_core *core);
 void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
 void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
index cfee477a6eb1f4b3f4ce5af01d3d19d37d768fb6..9e909e3c2f0c0fdae44398ce967c1de015b5bfe6 100644 (file)
 #include "fwil_types.h"
 #include "tracepoint.h"
 #include "common.h"
+#include "of.h"
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
+MODULE_LICENSE("Dual BSD/GPL");
 
 const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
@@ -75,6 +80,7 @@ module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
 MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
 #endif
 
+static struct brcmfmac_platform_data *brcmfmac_pdata;
 struct brcmf_mp_global_t brcmf_mp_global;
 
 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
@@ -221,33 +227,147 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
 }
 #endif
 
-void brcmf_mp_attach(void)
+static void brcmf_mp_attach(void)
 {
+       /* If module param firmware path is set then this will always be used,
+        * if not set then if available use the platform data version. To make
+        * sure it gets initialized at all, always copy the module param version
+        */
        strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
                BRCMF_FW_ALTPATH_LEN);
+       if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
+           (brcmf_mp_global.firmware_path[0] == '\0')) {
+               strlcpy(brcmf_mp_global.firmware_path,
+                       brcmfmac_pdata->fw_alternative_path,
+                       BRCMF_FW_ALTPATH_LEN);
+       }
 }
 
-int brcmf_mp_device_attach(struct brcmf_pub *drvr)
+struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
+                                              enum brcmf_bus_type bus_type,
+                                              u32 chip, u32 chiprev)
 {
-       drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
-       if (!drvr->settings) {
-               brcmf_err("Failed to alloca storage space for settings\n");
-               return -ENOMEM;
-       }
-
-       drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz;
-       drvr->settings->p2p_enable = !!brcmf_p2p_enable;
-       drvr->settings->feature_disable = brcmf_feature_disable;
-       drvr->settings->fcmode = brcmf_fcmode;
-       drvr->settings->roamoff = !!brcmf_roamoff;
+       struct brcmf_mp_device *settings;
+       struct brcmfmac_pd_device *device_pd;
+       bool found;
+       int i;
+
+       brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
+                 chiprev);
+       settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
+       if (!settings)
+               return NULL;
+
+       /* start by using the module paramaters */
+       settings->p2p_enable = !!brcmf_p2p_enable;
+       settings->feature_disable = brcmf_feature_disable;
+       settings->fcmode = brcmf_fcmode;
+       settings->roamoff = !!brcmf_roamoff;
 #ifdef DEBUG
-       drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
+       settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
 #endif
+
+       if (bus_type == BRCMF_BUSTYPE_SDIO)
+               settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
+
+       /* See if there is any device specific platform data configured */
+       found = false;
+       if (brcmfmac_pdata) {
+               for (i = 0; i < brcmfmac_pdata->device_count; i++) {
+                       device_pd = &brcmfmac_pdata->devices[i];
+                       if ((device_pd->bus_type == bus_type) &&
+                           (device_pd->id == chip) &&
+                           ((device_pd->rev == chiprev) ||
+                            (device_pd->rev == -1))) {
+                               brcmf_dbg(INFO, "Platform data for device found\n");
+                               settings->country_codes =
+                                               device_pd->country_codes;
+                               if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
+                                       memcpy(&settings->bus.sdio,
+                                              &device_pd->bus.sdio,
+                                              sizeof(settings->bus.sdio));
+                               found = true;
+                               break;
+                       }
+               }
+       }
+       if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) {
+               /* No platform data for this device. In case of SDIO try OF
+                * (Open Firwmare) Device Tree.
+                */
+               brcmf_of_probe(dev, &settings->bus.sdio);
+       }
+       return settings;
+}
+
+void brcmf_release_module_param(struct brcmf_mp_device *module_param)
+{
+       kfree(module_param);
+}
+
+static int __init brcmf_common_pd_probe(struct platform_device *pdev)
+{
+       brcmf_dbg(INFO, "Enter\n");
+
+       brcmfmac_pdata = dev_get_platdata(&pdev->dev);
+
+       if (brcmfmac_pdata->power_on)
+               brcmfmac_pdata->power_on();
+
+       return 0;
+}
+
+static int brcmf_common_pd_remove(struct platform_device *pdev)
+{
+       brcmf_dbg(INFO, "Enter\n");
+
+       if (brcmfmac_pdata->power_off)
+               brcmfmac_pdata->power_off();
+
        return 0;
 }
 
-void brcmf_mp_device_detach(struct brcmf_pub *drvr)
+static struct platform_driver brcmf_pd = {
+       .remove         = brcmf_common_pd_remove,
+       .driver         = {
+               .name   = BRCMFMAC_PDATA_NAME,
+       }
+};
+
+static int __init brcmfmac_module_init(void)
+{
+       int err;
+
+       /* Initialize debug system first */
+       brcmf_debugfs_init();
+
+       /* Get the platform data (if available) for our devices */
+       err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
+       if (err == -ENODEV)
+               brcmf_dbg(INFO, "No platform data available.\n");
+
+       /* Initialize global module paramaters */
+       brcmf_mp_attach();
+
+       /* Continue the initialization by registering the different busses */
+       err = brcmf_core_init();
+       if (err) {
+               brcmf_debugfs_exit();
+               if (brcmfmac_pdata)
+                       platform_driver_unregister(&brcmf_pd);
+       }
+
+       return err;
+}
+
+static void __exit brcmfmac_module_exit(void)
 {
-       kfree(drvr->settings);
+       brcmf_core_exit();
+       if (brcmfmac_pdata)
+               platform_driver_unregister(&brcmf_pd);
+       brcmf_debugfs_exit();
 }
 
+module_init(brcmfmac_module_init);
+module_exit(brcmfmac_module_exit);
+
index 3b0a63b98e998682c9654895c2f8ff6667e97bf0..bd095abca39340cc75490673755a07593dc66d93 100644 (file)
 #ifndef BRCMFMAC_COMMON_H
 #define BRCMFMAC_COMMON_H
 
+#include <linux/platform_device.h>
+#include <linux/platform_data/brcmfmac.h>
+#include "fwil_types.h"
+
 extern const u8 ALLFFMAC[ETH_ALEN];
 
 #define BRCMF_FW_ALTPATH_LEN                   256
@@ -41,37 +45,30 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
 /**
  * struct brcmf_mp_device - Device module paramaters.
  *
- * @sdiod_txglomsz: SDIO txglom size.
- * @joinboost_5g_rssi: 5g rssi booost for preferred join selection.
  * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant).
  * @feature_disable: Feature_disable bitmask.
  * @fcmode: FWS flow control.
  * @roamoff: Firmware roaming off?
+ * @ignore_probe_fail: Ignore probe failure.
+ * @country_codes: If available, pointer to struct for translating country codes
+ * @bus: Bus specific platform data. Only SDIO at the mmoment.
  */
 struct brcmf_mp_device {
-       int     sdiod_txglomsz;
-       int     joinboost_5g_rssi;
-       bool    p2p_enable;
-       int     feature_disable;
-       int     fcmode;
-       bool    roamoff;
-       bool    ignore_probe_fail;
+       bool            p2p_enable;
+       unsigned int    feature_disable;
+       int             fcmode;
+       bool            roamoff;
+       bool            ignore_probe_fail;
+       struct brcmfmac_pd_cc *country_codes;
+       union {
+               struct brcmfmac_sdio_pd sdio;
+       } bus;
 };
 
-void brcmf_mp_attach(void);
-int brcmf_mp_device_attach(struct brcmf_pub *drvr);
-void brcmf_mp_device_detach(struct brcmf_pub *drvr);
-#ifdef DEBUG
-static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
-{
-       return drvr->settings->ignore_probe_fail;
-}
-#else
-static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
-{
-       return false;
-}
-#endif
+struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
+                                              enum brcmf_bus_type bus_type,
+                                              u32 chip, u32 chiprev);
+void brcmf_release_module_param(struct brcmf_mp_device *module_param);
 
 /* Sets dongle media info (drv_version, mac address). */
 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
index ed9998b69709ace269c103c14605b4c18d45f472..ff825cd7739e29e946cb1120aeaf06b1ecfbbcdb 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/inetdevice.h>
 #include <net/cfg80211.h>
 #include <net/rtnetlink.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
 #include "pcie.h"
 #include "common.h"
 
-MODULE_AUTHOR("Broadcom Corporation");
-MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
-MODULE_LICENSE("Dual BSD/GPL");
-
-#define MAX_WAIT_FOR_8021X_TX                  msecs_to_jiffies(50)
+#define MAX_WAIT_FOR_8021X_TX                  msecs_to_jiffies(950)
 
 /* AMPDU rx reordering definitions */
 #define BRCMF_RXREORDER_FLOWID_OFFSET          0
@@ -172,6 +170,35 @@ _brcmf_set_mac_address(struct work_struct *work)
        }
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+static void _brcmf_update_ndtable(struct work_struct *work)
+{
+       struct brcmf_if *ifp;
+       int i, ret;
+
+       ifp = container_of(work, struct brcmf_if, ndoffload_work);
+
+       /* clear the table in firmware */
+       ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
+       if (ret) {
+               brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
+               return;
+       }
+
+       for (i = 0; i < ifp->ipv6addr_idx; i++) {
+               ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
+                                              &ifp->ipv6_addr_tbl[i],
+                                              sizeof(struct in6_addr));
+               if (ret)
+                       brcmf_err("add nd ip err %d\n", ret);
+       }
+}
+#else
+static void _brcmf_update_ndtable(struct work_struct *work)
+{
+}
+#endif
+
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
@@ -685,6 +712,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 
        INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
        INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+       INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
 
        if (rtnl_locked)
                err = register_netdevice(ndev);
@@ -884,6 +912,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
                if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
                        cancel_work_sync(&ifp->setmacaddr_work);
                        cancel_work_sync(&ifp->multicast_work);
+                       cancel_work_sync(&ifp->ndoffload_work);
                }
                brcmf_net_detach(ifp->ndev);
        } else {
@@ -1006,14 +1035,14 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
                                return NOTIFY_OK;
                        }
                        for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
-                               if (addr_table[i] != 0) {
-                                       brcmf_fil_iovar_data_set(ifp,
-                                               "arp_hostip", &addr_table[i],
-                                               sizeof(addr_table[i]));
-                                       if (ret)
-                                               brcmf_err("add arp ip err %d\n",
-                                                         ret);
-                               }
+                               if (addr_table[i] == 0)
+                                       continue;
+                               ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
+                                                              &addr_table[i],
+                                                              sizeof(addr_table[i]));
+                               if (ret)
+                                       brcmf_err("add arp ip err %d\n",
+                                                 ret);
                        }
                }
                break;
@@ -1025,7 +1054,57 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
 }
 #endif
 
-int brcmf_attach(struct device *dev)
+#if IS_ENABLED(CONFIG_IPV6)
+static int brcmf_inet6addr_changed(struct notifier_block *nb,
+                                  unsigned long action, void *data)
+{
+       struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
+                                             inet6addr_notifier);
+       struct inet6_ifaddr *ifa = data;
+       struct brcmf_if *ifp;
+       int i;
+       struct in6_addr *table;
+
+       /* Only handle primary interface */
+       ifp = drvr->iflist[0];
+       if (!ifp)
+               return NOTIFY_DONE;
+       if (ifp->ndev != ifa->idev->dev)
+               return NOTIFY_DONE;
+
+       table = ifp->ipv6_addr_tbl;
+       for (i = 0; i < NDOL_MAX_ENTRIES; i++)
+               if (ipv6_addr_equal(&ifa->addr, &table[i]))
+                       break;
+
+       switch (action) {
+       case NETDEV_UP:
+               if (i == NDOL_MAX_ENTRIES) {
+                       if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
+                               table[ifp->ipv6addr_idx++] = ifa->addr;
+                       } else {
+                               for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
+                                       table[i] = table[i + 1];
+                               table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
+                       }
+               }
+               break;
+       case NETDEV_DOWN:
+               if (i < NDOL_MAX_ENTRIES)
+                       for (; i < ifp->ipv6addr_idx; i++)
+                               table[i] = table[i + 1];
+               break;
+       default:
+               break;
+       }
+
+       schedule_work(&ifp->ndoffload_work);
+
+       return NOTIFY_OK;
+}
+#endif
+
+int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
 {
        struct brcmf_pub *drvr = NULL;
        int ret = 0;
@@ -1047,10 +1126,7 @@ int brcmf_attach(struct device *dev)
        drvr->hdrlen = 0;
        drvr->bus_if = dev_get_drvdata(dev);
        drvr->bus_if->drvr = drvr;
-
-       /* Initialize device specific settings */
-       if (brcmf_mp_device_attach(drvr))
-               goto fail;
+       drvr->settings = settings;
 
        /* attach debug facilities */
        brcmf_debug_attach(drvr);
@@ -1164,30 +1240,41 @@ int brcmf_bus_start(struct device *dev)
 #ifdef CONFIG_INET
        drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
        ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
+       if (ret)
+               goto fail;
+
+#if IS_ENABLED(CONFIG_IPV6)
+       drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
+       ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
+       if (ret) {
+               unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
+               goto fail;
+       }
 #endif
+#endif /* CONFIG_INET */
+
+       return 0;
 
 fail:
-       if (ret < 0) {
-               brcmf_err("failed: %d\n", ret);
-               if (drvr->config) {
-                       brcmf_cfg80211_detach(drvr->config);
-                       drvr->config = NULL;
-               }
-               if (drvr->fws) {
-                       brcmf_fws_del_interface(ifp);
-                       brcmf_fws_deinit(drvr);
-               }
-               if (ifp)
-                       brcmf_net_detach(ifp->ndev);
-               if (p2p_ifp)
-                       brcmf_net_detach(p2p_ifp->ndev);
-               drvr->iflist[0] = NULL;
-               drvr->iflist[1] = NULL;
-               if (brcmf_ignoring_probe_fail(drvr))
-                       ret = 0;
-               return ret;
+       brcmf_err("failed: %d\n", ret);
+       if (drvr->config) {
+               brcmf_cfg80211_detach(drvr->config);
+               drvr->config = NULL;
        }
-       return 0;
+       if (drvr->fws) {
+               brcmf_fws_del_interface(ifp);
+               brcmf_fws_deinit(drvr);
+       }
+       if (ifp)
+               brcmf_net_detach(ifp->ndev);
+       if (p2p_ifp)
+               brcmf_net_detach(p2p_ifp->ndev);
+       drvr->iflist[0] = NULL;
+       drvr->iflist[1] = NULL;
+       if (drvr->settings->ignore_probe_fail)
+               ret = 0;
+
+       return ret;
 }
 
 void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
@@ -1237,6 +1324,10 @@ void brcmf_detach(struct device *dev)
        unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
 #endif
 
+#if IS_ENABLED(CONFIG_IPV6)
+       unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
+#endif
+
        /* stop firmware event handling */
        brcmf_fweh_detach(drvr);
        if (drvr->config)
@@ -1256,8 +1347,6 @@ void brcmf_detach(struct device *dev)
 
        brcmf_proto_detach(drvr);
 
-       brcmf_mp_device_detach(drvr);
-
        brcmf_debug_detach(drvr);
        bus_if->drvr = NULL;
        kfree(drvr);
@@ -1324,19 +1413,15 @@ static void brcmf_driver_register(struct work_struct *work)
 }
 static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
 
-static int __init brcmfmac_module_init(void)
+int __init brcmf_core_init(void)
 {
-       brcmf_debugfs_init();
-#ifdef CONFIG_BRCMFMAC_SDIO
-       brcmf_sdio_init();
-#endif
        if (!schedule_work(&brcmf_driver_work))
                return -EBUSY;
 
        return 0;
 }
 
-static void __exit brcmfmac_module_exit(void)
+void __exit brcmf_core_exit(void)
 {
        cancel_work_sync(&brcmf_driver_work);
 
@@ -1349,8 +1434,5 @@ static void __exit brcmfmac_module_exit(void)
 #ifdef CONFIG_BRCMFMAC_PCIE
        brcmf_pcie_exit();
 #endif
-       brcmf_debugfs_exit();
 }
 
-module_init(brcmfmac_module_init);
-module_exit(brcmfmac_module_exit);
index 8f39435f976fb7eb6a798adb0ed1ae7f61080827..7bdb6fef99c3fba9fb3b2970683fd80df0482678 100644 (file)
@@ -48,6 +48,8 @@
  */
 #define BRCMF_DRIVER_FIRMWARE_VERSION_LEN      32
 
+#define NDOL_MAX_ENTRIES       8
+
 /**
  * struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
  *
@@ -143,6 +145,7 @@ struct brcmf_pub {
 #endif
 
        struct notifier_block inetaddr_notifier;
+       struct notifier_block inet6addr_notifier;
        struct brcmf_mp_device *settings;
 };
 
@@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason {
  * @stats: interface specific network statistics.
  * @setmacaddr_work: worker object for setting mac address.
  * @multicast_work: worker object for multicast provisioning.
+ * @ndoffload_work: worker object for neighbor discovery offload configuration.
  * @fws_desc: interface specific firmware-signalling descriptor.
  * @ifidx: interface index in device firmware.
  * @bsscfgidx: index of bss associated with this interface.
@@ -191,6 +195,7 @@ struct brcmf_if {
        struct net_device_stats stats;
        struct work_struct setmacaddr_work;
        struct work_struct multicast_work;
+       struct work_struct ndoffload_work;
        struct brcmf_fws_mac_descriptor *fws_desc;
        int ifidx;
        s32 bsscfgidx;
@@ -199,6 +204,8 @@ struct brcmf_if {
        spinlock_t netif_stop_lock;
        atomic_t pend_8021x_cnt;
        wait_queue_head_t pend_8021x_wait;
+       struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
+       u8 ipv6addr_idx;
 };
 
 struct brcmf_skb_reorder_data {
@@ -220,5 +227,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+int __init brcmf_core_init(void);
+void __exit brcmf_core_exit(void);
 
 #endif /* BRCMFMAC_CORE_H */
index 1ffa95f1b8d2b325df79f79e655b777df49162e3..62985f2c08538c1cbccb0a128df425c4b9eb20e5 100644 (file)
@@ -136,6 +136,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
 {
        struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
        struct brcmf_pno_macaddr_le pfn_mac;
+       u32 wowl_cap;
        s32 err;
 
        brcmf_feat_firmware_capabilities(ifp);
@@ -143,11 +144,24 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
        if (drvr->bus_if->wowl_supported)
                brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
+       if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
+               err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
+               if (!err) {
+                       ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
+                       if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
+                               ifp->drvr->feat_flags |=
+                                       BIT(BRCMF_FEAT_WOWL_ND);
+                       if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
+                               ifp->drvr->feat_flags |=
+                                       BIT(BRCMF_FEAT_WOWL_GTK);
+               }
+       }
        /* MBSS does not work for 43362 */
        if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID)
                ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
        brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
+       brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
 
        pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
        err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
index 2e2479d413379b0b980433fd27b1a9b43950b503..db4733a95e28fe99217b50b88de8b9b986446bfa 100644 (file)
  * RSDB: Real Simultaneous Dual Band
  * TDLS: Tunneled Direct Link Setup
  * SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan.
+ * WOWL_ND: WOWL net detect (PNO)
+ * WOWL_GTK: (WOWL) GTK rekeying offload
+ * WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
+ * MFP: 802.11w Management Frame Protection.
  */
 #define BRCMF_FEAT_LIST \
        BRCMF_FEAT_DEF(MBSS) \
        BRCMF_FEAT_DEF(P2P) \
        BRCMF_FEAT_DEF(RSDB) \
        BRCMF_FEAT_DEF(TDLS) \
-       BRCMF_FEAT_DEF(SCAN_RANDOM_MAC)
+       BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
+       BRCMF_FEAT_DEF(WOWL_ND) \
+       BRCMF_FEAT_DEF(WOWL_GTK) \
+       BRCMF_FEAT_DEF(WOWL_ARP_ND) \
+       BRCMF_FEAT_DEF(MFP)
 
 /*
  * Quirks:
index 1365c12b78fc39632f2e30c99092092e7a0256a8..7269056d0044d82727f57cf2b05d60f5f93118a7 100644 (file)
@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
        c = nvp->data[nvp->pos];
        if (c == '\n')
                return COMMENT;
-       if (is_whitespace(c))
+       if (is_whitespace(c) || c == '\0')
                goto proceed;
        if (c == '#')
                return COMMENT;
index 2ca783fa50cfc71b5556ddf731186af4704a3e63..7e269f9aa6070004b4185ad4549802e14a6019da 100644 (file)
@@ -32,7 +32,7 @@
 #define BRCMF_FLOWRING_LOW             (BRCMF_FLOWRING_HIGH - 256)
 #define BRCMF_FLOWRING_INVALID_IFIDX   0xff
 
-#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
+#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
 #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
 
 static const u8 brcmf_flowring_prio2fifo[] = {
@@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
                          u8 prio, u8 ifidx)
 {
        struct brcmf_flowring_hash *hash;
-       u8 hash_idx;
+       u16 hash_idx;
        u32 i;
        bool found;
        bool sta;
@@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
        }
        hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
                          BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
+       hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
        found = false;
        hash = flow->hash;
        for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
@@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
                        break;
                }
                hash_idx++;
+               hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
        }
        if (found)
                return hash[hash_idx].flowid;
@@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
 {
        struct brcmf_flowring_ring *ring;
        struct brcmf_flowring_hash *hash;
-       u8 hash_idx;
+       u16 hash_idx;
        u32 i;
        bool found;
        u8 fifo;
@@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
        }
        hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
                          BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
+       hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
        found = false;
        hash = flow->hash;
        for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
@@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
                        break;
                }
                hash_idx++;
+               hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
        }
        if (found) {
                for (i = 0; i < flow->nrofrings; i++) {
@@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
 }
 
 
-u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
 
@@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
 }
 
 
-static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
+static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
                                 bool blocked)
 {
        struct brcmf_flowring_ring *ring;
@@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
 }
 
 
-void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
-       u8 hash_idx;
+       u16 hash_idx;
        struct sk_buff *skb;
 
        ring = flow->rings[flowid];
@@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
 }
 
 
-u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
                           struct sk_buff *skb)
 {
        struct brcmf_flowring_ring *ring;
@@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
 }
 
 
-struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
        struct sk_buff *skb;
@@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
 }
 
 
-void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
                             struct sk_buff *skb)
 {
        struct brcmf_flowring_ring *ring;
@@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
 }
 
 
-u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
 
@@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
 }
 
 
-void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
 
@@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
 }
 
 
-u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
 {
        struct brcmf_flowring_ring *ring;
-       u8 hash_idx;
+       u16 hash_idx;
 
        ring = flow->rings[flowid];
        hash_idx = ring->hash_id;
@@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_flowring *flow)
        struct brcmf_pub *drvr = bus_if->drvr;
        struct brcmf_flowring_tdls_entry *search;
        struct brcmf_flowring_tdls_entry *remove;
-       u8 flowid;
+       u16 flowid;
 
        for (flowid = 0; flowid < flow->nrofrings; flowid++) {
                if (flow->rings[flowid])
@@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
        struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
        struct brcmf_pub *drvr = bus_if->drvr;
        u32 i;
-       u8 flowid;
+       u16 flowid;
 
        if (flow->addr_mode[ifidx] != addr_mode) {
                for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
@@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
        struct brcmf_flowring_tdls_entry *prev;
        struct brcmf_flowring_tdls_entry *search;
        u32 i;
-       u8 flowid;
+       u16 flowid;
        bool sta;
 
        sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);
index 95fd1c9675d172467a2f6c2c53fea0e5de2bbb06..068e68d94999bb6425a4ef0f9b2e19bc5895c149 100644 (file)
@@ -16,7 +16,7 @@
 #define BRCMFMAC_FLOWRING_H
 
 
-#define BRCMF_FLOWRING_HASHSIZE                256
+#define BRCMF_FLOWRING_HASHSIZE                512             /* has to be 2^x */
 #define BRCMF_FLOWRING_INVALID_ID      0xFFFFFFFF
 
 
@@ -24,7 +24,7 @@ struct brcmf_flowring_hash {
        u8 mac[ETH_ALEN];
        u8 fifo;
        u8 ifidx;
-       u8 flowid;
+       u16 flowid;
 };
 
 enum ring_status {
@@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
                          u8 prio, u8 ifidx);
 u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
                          u8 prio, u8 ifidx);
-void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
-void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
-u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
-u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid);
+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid);
+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid);
+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
                           struct sk_buff *skb);
-struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
-void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid);
+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
                             struct sk_buff *skb);
-u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
-u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid);
+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid);
 struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
 void brcmf_flowring_detach(struct brcmf_flowring *flow);
 void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
index 7b26fb1b437cdd1e28fd4164acbffccfb0331611..d414fbbcc81400630a881c8205ea3e410c627469 100644 (file)
 #include "fweh.h"
 #include "fwil.h"
 
-/**
- * struct brcm_ethhdr - broadcom specific ether header.
- *
- * @subtype: subtype for this packet.
- * @length: TODO: length of appended data.
- * @version: version indication.
- * @oui: OUI of this packet.
- * @usr_subtype: subtype for this OUI.
- */
-struct brcm_ethhdr {
-       __be16 subtype;
-       __be16 length;
-       u8 version;
-       u8 oui[3];
-       __be16 usr_subtype;
-} __packed;
-
-struct brcmf_event_msg_be {
-       __be16 version;
-       __be16 flags;
-       __be32 event_type;
-       __be32 status;
-       __be32 reason;
-       __be32 auth_type;
-       __be32 datalen;
-       u8 addr[ETH_ALEN];
-       char ifname[IFNAMSIZ];
-       u8 ifidx;
-       u8 bsscfgidx;
-} __packed;
-
-/**
- * struct brcmf_event - contents of broadcom event packet.
- *
- * @eth: standard ether header.
- * @hdr: broadcom specific ether header.
- * @msg: common part of the actual event message.
- */
-struct brcmf_event {
-       struct ethhdr eth;
-       struct brcm_ethhdr hdr;
-       struct brcmf_event_msg_be msg;
-} __packed;
-
 /**
  * struct brcmf_fweh_queue_item - event item on event queue.
  *
@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
        u8 ifidx;
        u8 ifaddr[ETH_ALEN];
        struct brcmf_event_msg_be emsg;
+       u32 datalen;
        u8 data[0];
 };
 
@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
                brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
                                   min_t(u32, emsg.datalen, 64),
                                   "event payload, len=%d\n", emsg.datalen);
+               if (emsg.datalen > event->datalen) {
+                       brcmf_err("event invalid length header=%d, msg=%d\n",
+                                 event->datalen, emsg.datalen);
+                       goto event_free;
+               }
 
                /* special handling of interface event */
                if (event->code == BRCMF_E_IF) {
@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
  * dispatch the event to a registered handler (using worker).
  */
 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-                             struct brcmf_event *event_packet)
+                             struct brcmf_event *event_packet,
+                             u32 packet_len)
 {
        enum brcmf_fweh_event_code code;
        struct brcmf_fweh_info *fweh = &drvr->fweh;
@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
        if (code != BRCMF_E_IF && !fweh->evt_handler[code])
                return;
 
+       if (datalen > BRCMF_DCMD_MAXLEN)
+               return;
+
        if (in_interrupt())
                alloc_flag = GFP_ATOMIC;
 
@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
        /* use memcpy to get aligned event message */
        memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
        memcpy(event->data, data, datalen);
+       event->datalen = datalen;
        memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
 
        brcmf_fweh_queue_event(fweh, event);
index 5e39e2a9e388a22c26e391b979067aa078e14eed..26ff5a9648f3517ac72209fbe1ff6b140e26b01b 100644 (file)
@@ -27,7 +27,6 @@
 struct brcmf_pub;
 struct brcmf_if;
 struct brcmf_cfg80211_info;
-struct brcmf_event;
 
 /* list of firmware events */
 #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
@@ -180,12 +179,54 @@ enum brcmf_fweh_event_code {
 /**
  * definitions for event packet validation.
  */
-#define BRCMF_EVENT_OUI_OFFSET         19
-#define BRCM_OUI                       "\x00\x10\x18"
-#define DOT11_OUI_LEN                  3
-#define BCMILCP_BCM_SUBTYPE_EVENT      1
+#define BRCM_OUI                               "\x00\x10\x18"
+#define BCMILCP_BCM_SUBTYPE_EVENT              1
 
 
+/**
+ * struct brcm_ethhdr - broadcom specific ether header.
+ *
+ * @subtype: subtype for this packet.
+ * @length: TODO: length of appended data.
+ * @version: version indication.
+ * @oui: OUI of this packet.
+ * @usr_subtype: subtype for this OUI.
+ */
+struct brcm_ethhdr {
+       __be16 subtype;
+       __be16 length;
+       u8 version;
+       u8 oui[3];
+       __be16 usr_subtype;
+} __packed;
+
+struct brcmf_event_msg_be {
+       __be16 version;
+       __be16 flags;
+       __be32 event_type;
+       __be32 status;
+       __be32 reason;
+       __be32 auth_type;
+       __be32 datalen;
+       u8 addr[ETH_ALEN];
+       char ifname[IFNAMSIZ];
+       u8 ifidx;
+       u8 bsscfgidx;
+} __packed;
+
+/**
+ * struct brcmf_event - contents of broadcom event packet.
+ *
+ * @eth: standard ether header.
+ * @hdr: broadcom specific ether header.
+ * @msg: common part of the actual event message.
+ */
+struct brcmf_event {
+       struct ethhdr eth;
+       struct brcm_ethhdr hdr;
+       struct brcmf_event_msg_be msg;
+} __packed;
+
 /**
  * struct brcmf_event_msg - firmware event message.
  *
@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
                           enum brcmf_fweh_event_code code);
 int brcmf_fweh_activate_events(struct brcmf_if *ifp);
 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
-                             struct brcmf_event *event_packet);
+                             struct brcmf_event *event_packet,
+                             u32 packet_len);
 void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
 
 static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
                                          struct sk_buff *skb)
 {
        struct brcmf_event *event_packet;
-       u8 *data;
        u16 usr_stype;
 
        /* only process events when protocol matches */
        if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
                return;
 
+       if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
+               return;
+
        /* check for BRCM oui match */
        event_packet = (struct brcmf_event *)skb_mac_header(skb);
-       data = (u8 *)event_packet;
-       data += BRCMF_EVENT_OUI_OFFSET;
-       if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
+       if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
+                  sizeof(event_packet->hdr.oui)))
                return;
 
        /* final match on usr_subtype */
-       data += DOT11_OUI_LEN;
-       usr_stype = get_unaligned_be16(data);
+       usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
        if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
                return;
 
-       brcmf_fweh_process_event(drvr, event_packet);
+       brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
 }
 
 #endif /* FWEH_H_ */
index 1afc2ad83b6c77fe4306fd98bab3cf655a4185a2..a4118c0ef6ca7fb8dab86ee53c1c4291d8c1acc7 100644 (file)
 /* Wakeup if received matched secured pattern: */
 #define BRCMF_WOWL_SECURE              (1 << 25)
 /* Wakeup on finding preferred network */
-#define BRCMF_WOWL_PFN_FOUND           (1 << 26)
+#define BRCMF_WOWL_PFN_FOUND           (1 << 27)
+/* Wakeup on receiving pairwise key EAP packets: */
+#define WIPHY_WOWL_EAP_PK              (1 << 28)
 /* Link Down indication in WoWL mode: */
 #define BRCMF_WOWL_LINKDOWN            (1 << 31)
 
 #define BRCMF_PFN_MAC_OUI_ONLY         BIT(0)
 #define BRCMF_PFN_SET_MAC_UNASSOC      BIT(1)
 
+#define BRCMF_MCSSET_LEN               16
+
+#define BRCMF_RSN_KCK_LENGTH           16
+#define BRCMF_RSN_KEK_LENGTH           16
+#define BRCMF_RSN_REPLAY_LEN           8
+
+#define BRCMF_MFP_NONE                 0
+#define BRCMF_MFP_CAPABLE              1
+#define BRCMF_MFP_REQUIRED             2
+
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
        BRCMF_JOIN_PREF_RSSI = 1,
@@ -279,7 +291,7 @@ struct brcmf_bss_info_le {
        __le32 reserved32[1];   /* Reserved for expansion of BSS properties */
        u8 flags;               /* flags */
        u8 reserved[3]; /* Reserved for expansion of BSS properties */
-       u8 basic_mcs[MCSSET_LEN];       /* 802.11N BSS required MCS set */
+       u8 basic_mcs[BRCMF_MCSSET_LEN]; /* 802.11N BSS required MCS set */
 
        __le16 ie_offset;       /* offset at which IEs start, from beginning */
        __le32 ie_length;       /* byte length of Information Elements */
@@ -787,4 +799,17 @@ struct brcmf_pktcnt_le {
        __le32 rx_ocast_good_pkt;
 };
 
+/**
+ * struct brcmf_gtk_keyinfo_le - GTP rekey data
+ *
+ * @kck: key confirmation key.
+ * @kek: key encryption key.
+ * @replay_counter: replay counter.
+ */
+struct brcmf_gtk_keyinfo_le {
+       u8 kck[BRCMF_RSN_KCK_LENGTH];
+       u8 kek[BRCMF_RSN_KEK_LENGTH];
+       u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
+};
+
 #endif /* FWIL_TYPES_H_ */
index c2bdb91746cf8eb0fded26afff5e1b22273e73d6..922966734a7f3e8f48e4576b0e6066bc5b3c6fea 100644 (file)
@@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,
 }
 
 
-static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
+static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
 {
        struct brcmf_flowring *flow = msgbuf->flow;
        struct brcmf_commonring *commonring;
@@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
 }
 
 
-void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)
+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
 {
        struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
        struct msgbuf_tx_flowring_delete_req *delete;
@@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
        u32 count;
 
        if_msgbuf = drvr->bus_if->msgbuf;
+
+       if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) {
+               brcmf_err("driver not configured for this many flowrings %d\n",
+                         if_msgbuf->nrof_flowrings);
+               if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;
+       }
+
        msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);
        if (!msgbuf)
                goto fail;
index 3d513e407e3d5db610792a6bea0d1d843cd15a63..ee6906a3c3f6627a5fce11b2d8c77b48fe135604 100644 (file)
@@ -33,7 +33,7 @@
 
 
 int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
-void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);
 int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
 void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
 #else
index 03f35e0c52ca5469f49a7d43a39edac648563c10..425c41dc0a59bd5167eb429f37395273d06d2403 100644 (file)
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
-#include <linux/mmc/card.h>
-#include <linux/platform_data/brcmfmac-sdio.h>
-#include <linux/mmc/sdio_func.h>
 
 #include <defs.h>
 #include "debug.h"
-#include "sdio.h"
+#include "core.h"
+#include "common.h"
+#include "of.h"
 
-void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
+void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
 {
-       struct device *dev = sdiodev->dev;
        struct device_node *np = dev->of_node;
        int irq;
        u32 irqf;
@@ -35,12 +33,8 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
        if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
                return;
 
-       sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL);
-       if (!sdiodev->pdata)
-               return;
-
        if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
-               sdiodev->pdata->drive_strength = val;
+               sdio->drive_strength = val;
 
        /* make sure there are interrupts defined in the node */
        if (!of_find_property(np, "interrupts", NULL))
@@ -53,7 +47,7 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
        }
        irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
 
-       sdiodev->pdata->oob_irq_supported = true;
-       sdiodev->pdata->oob_irq_nr = irq;
-       sdiodev->pdata->oob_irq_flags = irqf;
+       sdio->oob_irq_supported = true;
+       sdio->oob_irq_nr = irq;
+       sdio->oob_irq_flags = irqf;
 }
index 5f7c3550deda4c038a8d02822f13eaf17a30691e..a9d94c15d0f5ef422fdbad2656db1fd3064d0e6c 100644 (file)
@@ -14,9 +14,9 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #ifdef CONFIG_OF
-void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev);
+void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio);
 #else
-static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
+static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
 {
 }
 #endif /* CONFIG_OF */
index 821b6494f9d11031708153998c1767a88c0b298c..b5a49e564f25567fcc218a114302bd5c7ad5318b 100644 (file)
@@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
        u16 mgmt_type;
        u8 action;
 
+       if (e->datalen < sizeof(*rxframe)) {
+               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+               return 0;
+       }
+
        ch.chspec = be16_to_cpu(rxframe->chanspec);
        cfg->d11inf.decchspec(&ch);
        /* Check if wpa_supplicant has registered for this frame */
@@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
        brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
                  e->reason);
 
+       if (e->datalen < sizeof(*rxframe)) {
+               brcmf_dbg(SCAN, "Event data to small. Ignore\n");
+               return 0;
+       }
+
        ch.chspec = be16_to_cpu(rxframe->chanspec);
        cfg->d11inf.decchspec(&ch);
 
@@ -1988,8 +1998,8 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
                brcmf_cfg80211_arm_vif_event(cfg, NULL);
                return err;
        }
-       err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
-                                                   BRCMF_VIF_EVENT_TIMEOUT);
+       err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE,
+                                           BRCMF_VIF_EVENT_TIMEOUT);
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
        if (!err)  {
                brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
@@ -2090,8 +2100,8 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        }
 
        /* wait for firmware event */
-       err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
-                                                   BRCMF_VIF_EVENT_TIMEOUT);
+       err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD,
+                                           BRCMF_VIF_EVENT_TIMEOUT);
        brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
        brcmf_fweh_p2pdev_setup(pri_ifp, false);
        if (!err) {
@@ -2180,8 +2190,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
        }
 
        /* wait for firmware event */
-       err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
-                                                   BRCMF_VIF_EVENT_TIMEOUT);
+       err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
+                                           BRCMF_VIF_EVENT_TIMEOUT);
        brcmf_cfg80211_arm_vif_event(cfg, NULL);
        if (!err) {
                brcmf_err("timeout occurred\n");
@@ -2272,8 +2282,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
        }
        if (!err) {
                /* wait for firmware event */
-               err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
-                                                       BRCMF_VIF_EVENT_TIMEOUT);
+               err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
+                                                   BRCMF_VIF_EVENT_TIMEOUT);
                if (!err)
                        err = -EIO;
                else
index 0480b70e3eb84b5b5e627dc022a9589455f85b4d..52fef5e1d615b68053806b8219cd0aa673d3f989 100644 (file)
@@ -37,6 +37,8 @@
 #include "pcie.h"
 #include "firmware.h"
 #include "chip.h"
+#include "core.h"
+#include "common.h"
 
 
 enum brcmf_pcie_state {
@@ -53,6 +55,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt");
 BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt");
 BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt");
 BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt");
+BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt");
 BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt");
 
 static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
@@ -66,13 +69,13 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
        BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
        BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
        BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B),
-       BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B),
+       BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
+       BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
        BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
 };
 
 #define BRCMF_PCIE_FW_UP_TIMEOUT               2000 /* msec */
 
-#define BRCMF_PCIE_TCM_MAP_SIZE                        (4096 * 1024)
 #define BRCMF_PCIE_REG_MAP_SIZE                        (32 * 1024)
 
 /* backplane addres space accessed by BAR0 */
@@ -99,9 +102,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
 #define BRCMF_PCIE_PCIE2REG_CONFIGDATA         0x124
 #define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX                0x140
 
-#define BRCMF_PCIE_GENREV1                     1
-#define BRCMF_PCIE_GENREV2                     2
-
 #define BRCMF_PCIE2_INTA                       0x01
 #define BRCMF_PCIE2_INTB                       0x02
 
@@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
 #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG      0x4F4
 #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB  3
 
+/* Magic number at a magic location to find RAM size */
+#define BRCMF_RAMSIZE_MAGIC                    0x534d4152      /* SMAR */
+#define BRCMF_RAMSIZE_OFFSET                   0x6c
+
 
 struct brcmf_pcie_console {
        u32 base_addr;
@@ -248,14 +252,11 @@ struct brcmf_pciedev_info {
        char nvram_name[BRCMF_FW_NAME_LEN];
        void __iomem *regs;
        void __iomem *tcm;
-       u32 tcm_size;
        u32 ram_base;
        u32 ram_size;
        struct brcmf_chip *ci;
        u32 coreid;
-       u32 generic_corerev;
        struct brcmf_pcie_shared_info shared;
-       void (*ringbell)(struct brcmf_pciedev_info *devinfo);
        wait_queue_head_t mbdata_resp_wait;
        bool mbdata_completed;
        bool irq_allocated;
@@ -267,6 +268,7 @@ struct brcmf_pciedev_info {
        u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
        void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
                          u16 value);
+       struct brcmf_mp_device *settings;
 };
 
 struct brcmf_pcie_ringbuf {
@@ -742,68 +744,22 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo)
 }
 
 
-static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo)
-{
-       u32 reg_value;
-
-       brcmf_dbg(PCIE, "RING !\n");
-       reg_value = brcmf_pcie_read_reg32(devinfo,
-                                         BRCMF_PCIE_PCIE2REG_MAILBOXINT);
-       reg_value |= BRCMF_PCIE2_INTB;
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
-                              reg_value);
-}
-
-
-static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo)
-{
-       brcmf_dbg(PCIE, "RING !\n");
-       /* Any arbitrary value will do, lets use 1 */
-       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
-}
-
-
 static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
 {
-       if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
-               pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
-                                      0);
-       else
-               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
-                                      0);
+       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
 }
 
 
 static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
 {
-       if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
-               pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
-                                      BRCMF_PCIE_INT_DEF);
-       else
-               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
-                                      BRCMF_PCIE_MB_INT_D2H_DB |
-                                      BRCMF_PCIE_MB_INT_FN0_0 |
-                                      BRCMF_PCIE_MB_INT_FN0_1);
-}
-
-
-static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg)
-{
-       struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
-       u32 status;
-
-       status = 0;
-       pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-       if (status) {
-               brcmf_pcie_intr_disable(devinfo);
-               brcmf_dbg(PCIE, "Enter\n");
-               return IRQ_WAKE_THREAD;
-       }
-       return IRQ_NONE;
+       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
+                              BRCMF_PCIE_MB_INT_D2H_DB |
+                              BRCMF_PCIE_MB_INT_FN0_0 |
+                              BRCMF_PCIE_MB_INT_FN0_1);
 }
 
 
-static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg)
+static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg)
 {
        struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
 
@@ -816,29 +772,7 @@ static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg)
 }
 
 
-static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg)
-{
-       struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
-       const struct pci_dev *pdev = devinfo->pdev;
-       u32 status;
-
-       devinfo->in_irq = true;
-       status = 0;
-       pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-       brcmf_dbg(PCIE, "Enter %x\n", status);
-       if (status) {
-               pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
-               if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
-                       brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev);
-       }
-       if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
-               brcmf_pcie_intr_enable(devinfo);
-       devinfo->in_irq = false;
-       return IRQ_HANDLED;
-}
-
-
-static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg)
+static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
 {
        struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
        u32 status;
@@ -875,28 +809,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo)
        brcmf_pcie_intr_disable(devinfo);
 
        brcmf_dbg(PCIE, "Enter\n");
-       /* is it a v1 or v2 implementation */
+
        pci_enable_msi(pdev);
-       if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
-               if (request_threaded_irq(pdev->irq,
-                                        brcmf_pcie_quick_check_isr_v1,
-                                        brcmf_pcie_isr_thread_v1,
-                                        IRQF_SHARED, "brcmf_pcie_intr",
-                                        devinfo)) {
-                       pci_disable_msi(pdev);
-                       brcmf_err("Failed to request IRQ %d\n", pdev->irq);
-                       return -EIO;
-               }
-       } else {
-               if (request_threaded_irq(pdev->irq,
-                                        brcmf_pcie_quick_check_isr_v2,
-                                        brcmf_pcie_isr_thread_v2,
-                                        IRQF_SHARED, "brcmf_pcie_intr",
-                                        devinfo)) {
-                       pci_disable_msi(pdev);
-                       brcmf_err("Failed to request IRQ %d\n", pdev->irq);
-                       return -EIO;
-               }
+       if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr,
+                                brcmf_pcie_isr_thread, IRQF_SHARED,
+                                "brcmf_pcie_intr", devinfo)) {
+               pci_disable_msi(pdev);
+               brcmf_err("Failed to request IRQ %d\n", pdev->irq);
+               return -EIO;
        }
        devinfo->irq_allocated = true;
        return 0;
@@ -927,16 +847,9 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
        if (devinfo->in_irq)
                brcmf_err("Still in IRQ (processing) !!!\n");
 
-       if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
-               status = 0;
-               pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
-               pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
-       } else {
-               status = brcmf_pcie_read_reg32(devinfo,
-                                              BRCMF_PCIE_PCIE2REG_MAILBOXINT);
-               brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
-                                      status);
-       }
+       status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
+       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status);
+
        devinfo->irq_allocated = false;
 }
 
@@ -985,7 +898,9 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx)
        if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
                return -EIO;
 
-       devinfo->ringbell(devinfo);
+       brcmf_dbg(PCIE, "RING !\n");
+       /* Any arbitrary value will do, lets use 1 */
+       brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
 
        return 0;
 }
@@ -1412,6 +1327,28 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 };
 
 
+static void
+brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data,
+                         u32 data_len)
+{
+       __le32 *field;
+       u32 newsize;
+
+       if (data_len < BRCMF_RAMSIZE_OFFSET + 8)
+               return;
+
+       field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET];
+       if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC)
+               return;
+       field++;
+       newsize = le32_to_cpup(field);
+
+       brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n",
+                 newsize);
+       devinfo->ci->ramsize = newsize;
+}
+
+
 static int
 brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
                               u32 sharedram_addr)
@@ -1477,9 +1414,6 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
        u32 address;
        u32 resetintr;
 
-       devinfo->ringbell = brcmf_pcie_ringbell_v2;
-       devinfo->generic_corerev = BRCMF_PCIE_GENREV2;
-
        brcmf_dbg(PCIE, "Halt ARM.\n");
        err = brcmf_pcie_enter_download_state(devinfo);
        if (err)
@@ -1566,8 +1500,7 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo)
        }
 
        devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE);
-       devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE);
-       devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE;
+       devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size);
 
        if (!devinfo->regs || !devinfo->tcm) {
                brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs,
@@ -1576,8 +1509,9 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo)
        }
        brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n",
                  devinfo->regs, (unsigned long long)bar0_addr);
-       brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n",
-                 devinfo->tcm, (unsigned long long)bar1_addr);
+       brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n",
+                 devinfo->tcm, (unsigned long long)bar1_addr,
+                 (unsigned int)bar1_size);
 
        return 0;
 }
@@ -1594,16 +1528,16 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo)
 }
 
 
-static int brcmf_pcie_attach_bus(struct device *dev)
+static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo)
 {
        int ret;
 
        /* Attach to the common driver interface */
-       ret = brcmf_attach(dev);
+       ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings);
        if (ret) {
                brcmf_err("brcmf_attach failed\n");
        } else {
-               ret = brcmf_bus_start(dev);
+               ret = brcmf_bus_start(&devinfo->pdev->dev);
                if (ret)
                        brcmf_err("dongle is not responding\n");
        }
@@ -1694,6 +1628,13 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
 
        brcmf_pcie_attach(devinfo);
 
+       /* Some of the firmwares have the size of the memory of the device
+        * defined inside the firmware. This is because part of the memory in
+        * the device is shared and the devision is determined by FW. Parse
+        * the firmware and adjust the chip memory size now.
+        */
+       brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
+
        ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
        if (ret)
                goto fail;
@@ -1734,7 +1675,7 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
        init_waitqueue_head(&devinfo->mbdata_resp_wait);
 
        brcmf_pcie_intr_enable(devinfo);
-       if (brcmf_pcie_attach_bus(bus->dev) == 0)
+       if (brcmf_pcie_attach_bus(devinfo) == 0)
                return;
 
        brcmf_pcie_bus_console_read(devinfo);
@@ -1778,6 +1719,15 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto fail;
        }
 
+       devinfo->settings = brcmf_get_module_param(&devinfo->pdev->dev,
+                                                  BRCMF_BUSTYPE_PCIE,
+                                                  devinfo->ci->chip,
+                                                  devinfo->ci->chiprev);
+       if (!devinfo->settings) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (!bus) {
                ret = -ENOMEM;
@@ -1822,6 +1772,8 @@ fail:
        brcmf_pcie_release_resource(devinfo);
        if (devinfo->ci)
                brcmf_chip_detach(devinfo->ci);
+       if (devinfo->settings)
+               brcmf_release_module_param(devinfo->settings);
        kfree(pcie_bus_dev);
        kfree(devinfo);
        return ret;
@@ -1861,6 +1813,8 @@ brcmf_pcie_remove(struct pci_dev *pdev)
 
        if (devinfo->ci)
                brcmf_chip_detach(devinfo->ci);
+       if (devinfo->settings)
+               brcmf_release_module_param(devinfo->settings);
 
        kfree(devinfo);
        dev_set_drvdata(&pdev->dev, NULL);
@@ -1951,6 +1905,9 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
 
 #define BRCMF_PCIE_DEVICE(dev_id)      { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \
+       BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
+       subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
 
 static struct pci_device_id brcmf_pcie_devid_table[] = {
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
@@ -1966,6 +1923,7 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
+       BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
index a14d9d9da094224b0c8c6d326547a5001c29d925..43fd3f402ebad89f89f7d5f8afdce9613d87b5de 100644 (file)
@@ -33,8 +33,6 @@
 #include <linux/bcma/bcma.h>
 #include <linux/debugfs.h>
 #include <linux/vmalloc.h>
-#include <linux/platform_data/brcmfmac-sdio.h>
-#include <linux/moduleparam.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
 #include "sdio.h"
 #include "chip.h"
 #include "firmware.h"
+#include "core.h"
+#include "common.h"
 
-#define DCMD_RESP_TIMEOUT      msecs_to_jiffies(2000)
-#define CTL_DONE_TIMEOUT       msecs_to_jiffies(2000)
+#define DCMD_RESP_TIMEOUT      msecs_to_jiffies(2500)
+#define CTL_DONE_TIMEOUT       msecs_to_jiffies(2500)
 
 #ifdef DEBUG
 
@@ -2442,15 +2442,17 @@ static void brcmf_sdio_bus_stop(struct device *dev)
 
 static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
 {
+       struct brcmf_sdio_dev *sdiodev;
        unsigned long flags;
 
-       if (bus->sdiodev->oob_irq_requested) {
-               spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
-               if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
-                       enable_irq(bus->sdiodev->pdata->oob_irq_nr);
-                       bus->sdiodev->irq_en = true;
+       sdiodev = bus->sdiodev;
+       if (sdiodev->oob_irq_requested) {
+               spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
+               if (!sdiodev->irq_en && !atomic_read(&bus->ipend)) {
+                       enable_irq(sdiodev->settings->bus.sdio.oob_irq_nr);
+                       sdiodev->irq_en = true;
                }
-               spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
+               spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
        }
 }
 
@@ -3394,9 +3396,7 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
                                           sizeof(u32));
        } else {
                /* otherwise, set txglomalign */
-               value = 4;
-               if (sdiodev->pdata)
-                       value = sdiodev->pdata->sd_sgentry_align;
+               value = sdiodev->settings->bus.sdio.sd_sgentry_align;
                /* SDIO ADMA requires at least 32 bit alignment */
                value = max_t(u32, value, 4);
                err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
        const struct sdiod_drive_str *str_tab = NULL;
        u32 str_mask;
        u32 str_shift;
-       u32 base;
        u32 i;
        u32 drivestrength_sel = 0;
        u32 cc_data_temp;
@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
        }
 
        if (str_tab != NULL) {
+               struct brcmf_core *pmu = brcmf_chip_get_pmu(ci);
+
                for (i = 0; str_tab[i].strength != 0; i++) {
                        if (drivestrength >= str_tab[i].strength) {
                                drivestrength_sel = str_tab[i].sel;
                                break;
                        }
                }
-               base = brcmf_chip_get_chipcommon(ci)->base;
-               addr = CORE_CC_REG(base, chipcontrol_addr);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
                brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
                cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
                cc_data_temp &= ~str_mask;
@@ -3775,26 +3775,28 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
 static bool
 brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 {
+       struct brcmf_sdio_dev *sdiodev;
        u8 clkctl = 0;
        int err = 0;
        int reg_addr;
        u32 reg_val;
        u32 drivestrength;
 
-       sdio_claim_host(bus->sdiodev->func[1]);
+       sdiodev = bus->sdiodev;
+       sdio_claim_host(sdiodev->func[1]);
 
        pr_debug("F1 signature read @0x18000000=0x%4x\n",
-                brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
+                brcmf_sdiod_regrl(sdiodev, SI_ENUM_BASE, NULL));
 
        /*
         * Force PLL off until brcmf_chip_attach()
         * programs PLL control regs
         */
 
-       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+       brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
                          BRCMF_INIT_CLKCTL1, &err);
        if (!err)
-               clkctl = brcmf_sdiod_regrb(bus->sdiodev,
+               clkctl = brcmf_sdiod_regrb(sdiodev,
                                           SBSDIO_FUNC1_CHIPCLKCSR, &err);
 
        if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
@@ -3803,51 +3805,81 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
                goto fail;
        }
 
-       bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
+       bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops);
        if (IS_ERR(bus->ci)) {
                brcmf_err("brcmf_chip_attach failed!\n");
                bus->ci = NULL;
                goto fail;
        }
+       sdiodev->settings = brcmf_get_module_param(sdiodev->dev,
+                                                  BRCMF_BUSTYPE_SDIO,
+                                                  bus->ci->chip,
+                                                  bus->ci->chiprev);
+       if (!sdiodev->settings) {
+               brcmf_err("Failed to get device parameters\n");
+               goto fail;
+       }
+       /* platform specific configuration:
+        *   alignments must be at least 4 bytes for ADMA
+        */
+       bus->head_align = ALIGNMENT;
+       bus->sgentry_align = ALIGNMENT;
+       if (sdiodev->settings->bus.sdio.sd_head_align > ALIGNMENT)
+               bus->head_align = sdiodev->settings->bus.sdio.sd_head_align;
+       if (sdiodev->settings->bus.sdio.sd_sgentry_align > ALIGNMENT)
+               bus->sgentry_align =
+                               sdiodev->settings->bus.sdio.sd_sgentry_align;
+
+       /* allocate scatter-gather table. sg support
+        * will be disabled upon allocation failure.
+        */
+       brcmf_sdiod_sgtable_alloc(sdiodev);
+
+#ifdef CONFIG_PM_SLEEP
+       /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
+        * is true or when platform data OOB irq is true).
+        */
+       if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
+           ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
+            (sdiodev->settings->bus.sdio.oob_irq_supported)))
+               sdiodev->bus_if->wowl_supported = true;
+#endif
 
        if (brcmf_sdio_kso_init(bus)) {
                brcmf_err("error enabling KSO\n");
                goto fail;
        }
 
-       if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
-               drivestrength = bus->sdiodev->pdata->drive_strength;
+       if (sdiodev->settings->bus.sdio.drive_strength)
+               drivestrength = sdiodev->settings->bus.sdio.drive_strength;
        else
                drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
-       brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
+       brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength);
 
        /* Set card control so an SDIO card reset does a WLAN backplane reset */
-       reg_val = brcmf_sdiod_regrb(bus->sdiodev,
-                                   SDIO_CCCR_BRCM_CARDCTRL, &err);
+       reg_val = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err);
        if (err)
                goto fail;
 
        reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
 
-       brcmf_sdiod_regwb(bus->sdiodev,
-                         SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
+       brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
        if (err)
                goto fail;
 
        /* set PMUControl so a backplane reset does PMU state reload */
-       reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
-                              pmucontrol);
-       reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
+       reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
+       reg_val = brcmf_sdiod_regrl(sdiodev, reg_addr, &err);
        if (err)
                goto fail;
 
        reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
 
-       brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
+       brcmf_sdiod_regwl(sdiodev, reg_addr, reg_val, &err);
        if (err)
                goto fail;
 
-       sdio_release_host(bus->sdiodev->func[1]);
+       sdio_release_host(sdiodev->func[1]);
 
        brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
 
@@ -3868,7 +3900,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
        return true;
 
 fail:
-       sdio_release_host(bus->sdiodev->func[1]);
+       sdio_release_host(sdiodev->func[1]);
        return false;
 }
 
@@ -4046,18 +4078,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        bus->txminmax = BRCMF_TXMINMAX;
        bus->tx_seq = SDPCM_SEQ_WRAP - 1;
 
-       /* platform specific configuration:
-        *   alignments must be at least 4 bytes for ADMA
-        */
-       bus->head_align = ALIGNMENT;
-       bus->sgentry_align = ALIGNMENT;
-       if (sdiodev->pdata) {
-               if (sdiodev->pdata->sd_head_align > ALIGNMENT)
-                       bus->head_align = sdiodev->pdata->sd_head_align;
-               if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
-                       bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
-       }
-
        /* single-threaded workqueue */
        wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
                                     dev_name(&sdiodev->func[1]->dev));
@@ -4108,7 +4128,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
 
        /* Attach to the common layer, reserve hdr space */
-       ret = brcmf_attach(bus->sdiodev->dev);
+       ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings);
        if (ret != 0) {
                brcmf_err("brcmf_attach failed\n");
                goto fail;
@@ -4212,6 +4232,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
                        }
                        brcmf_chip_detach(bus->ci);
                }
+               if (bus->sdiodev->settings)
+                       brcmf_release_module_param(bus->sdiodev->settings);
 
                kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
index 23f223150cef2cf4ec768b196d906603b92f36b2..dcf0ce8cd2c1e5335967f91bf81e3d891becfff2 100644 (file)
@@ -184,7 +184,7 @@ struct brcmf_sdio_dev {
        struct brcmf_sdio *bus;
        struct device *dev;
        struct brcmf_bus *bus_if;
-       struct brcmfmac_sdio_platform_data *pdata;
+       struct brcmf_mp_device *settings;
        bool oob_irq_requested;
        bool irq_en;                    /* irq enable flags */
        spinlock_t irq_en_lock;
index c72b7b352a77615a76bc624c4acbf34e533a9266..869eb82db8b1a69c80c55a1fc4c7c702e043866e 100644 (file)
@@ -27,6 +27,8 @@
 #include "debug.h"
 #include "firmware.h"
 #include "usb.h"
+#include "core.h"
+#include "common.h"
 
 
 #define IOCTL_RESP_TIMEOUT             msecs_to_jiffies(2000)
@@ -171,6 +173,7 @@ struct brcmf_usbdev_info {
        struct urb *bulk_urb; /* used for FW download */
 
        bool wowl_enabled;
+       struct brcmf_mp_device *settings;
 };
 
 static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
@@ -1027,6 +1030,9 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
 
        kfree(devinfo->tx_reqs);
        kfree(devinfo->rx_reqs);
+
+       if (devinfo->settings)
+               brcmf_release_module_param(devinfo->settings);
 }
 
 
@@ -1136,7 +1142,7 @@ static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
        int ret;
 
        /* Attach to the common driver interface */
-       ret = brcmf_attach(devinfo->dev);
+       ret = brcmf_attach(devinfo->dev, devinfo->settings);
        if (ret) {
                brcmf_err("brcmf_attach failed\n");
                return ret;
@@ -1223,6 +1229,14 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->wowl_supported = true;
 #endif
 
+       devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB,
+                                                  bus_pub->devid,
+                                                  bus_pub->chiprev);
+       if (!devinfo->settings) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
        if (!brcmf_usb_dlneeded(devinfo)) {
                ret = brcmf_usb_bus_setup(devinfo);
                if (ret)
index bec2dc1ca2e406bcf4ac0ee0d00fa27a704cf7f2..61ae2768132a0b16f0f98a57b3319c82adfda95b 100644 (file)
@@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 static int
 brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
-                   enum ieee80211_ampdu_mlme_action action,
-                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                   u8 buf_size, bool amsdu)
+                   struct ieee80211_ampdu_params *params)
 {
        struct brcms_info *wl = hw->priv;
        struct scb *scb = &wl->wlc->pri_scb;
        int status;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u8 buf_size = params->buf_size;
 
        if (WARN_ON(scb->magic != SCB_MAGIC))
                return -EIDRM;
index 3f68dd5ecd116e7cdfc36a04590f1ae1d64b3039..7b9a77981df16bd7f78dbb7ef2abdf2b1dfedf8c 100644 (file)
@@ -236,6 +236,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
 #define WPA2_AUTH_RESERVED3    0x0200
 #define WPA2_AUTH_RESERVED4    0x0400
 #define WPA2_AUTH_RESERVED5    0x0800
+#define WPA2_AUTH_1X_SHA256    0x1000  /* 1X with SHA256 key derivation */
+#define WPA2_AUTH_PSK_SHA256   0x8000  /* PSK with SHA256 key derivation */
 
 #define DOT11_DEFAULT_RTS_LEN          2347
 #define DOT11_DEFAULT_FRAG_LEN         2346
index fd38aa0763e4f5f30384d29249e7bf205b7d5eeb..b75f4ef3cdc7b278ec837f83fd576444f5ce0008 100644 (file)
@@ -5982,12 +5982,14 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 int
 il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 * ssn,
-                       u8 buf_size, bool amsdu)
+                       struct ieee80211_ampdu_params *params)
 {
        struct il_priv *il = hw->priv;
        int ret = -EINVAL;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
 
        D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid);
 
index 8ab8706f942267fcd2467928b1cbdf248a05921f..e432715e02d89dedcce89615d855233662c26d82 100644 (file)
@@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw,
                                struct ieee80211_sta *sta, u32 iv32,
                                u16 *phase1key);
 int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                           enum ieee80211_ampdu_mlme_action action,
-                           struct ieee80211_sta *sta, u16 tid, u16 * ssn,
-                           u8 buf_size, bool amsdu);
+                           struct ieee80211_ampdu_params *params);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
 void
index 866067789330ad4f4eaf0cebd7f807aa9403d1ec..16c4f383488fcc5160d22dca5980d72bb1a78edd 100644 (file)
@@ -53,7 +53,6 @@ config IWLWIFI_LEDS
 
 config IWLDVM
        tristate "Intel Wireless WiFi DVM Firmware support"
-       depends on m
        help
          This is the driver that supports the DVM firmware. The list
          of the devices that use this firmware is available here:
@@ -99,6 +98,18 @@ config IWLWIFI_UAPSD
 
          If unsure, say N.
 
+config IWLWIFI_PCIE_RTPM
+       bool "Enable runtime power management mode for PCIe devices"
+       depends on IWLMVM && PM
+       default false
+       help
+         Say Y here to enable runtime power management for PCIe
+         devices.  If enabled, the device will go into low power mode
+         when idle for a short period of time, allowing for improved
+         power saving during runtime.
+
+        If unsure, say N.
+
 menu "Debugging Options"
 
 config IWLWIFI_DEBUG
index 1aabb5ec096f5061082508bf4fe6acc0e0d96099..1bbd17ada974723623acc6b1da53b77131f6121b 100644 (file)
@@ -152,11 +152,14 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev,
 {
        struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
        unsigned long on = 0;
+       unsigned long off = 0;
 
        if (brightness > 0)
                on = IWL_LED_SOLID;
+       else
+               off = IWL_LED_SOLID;
 
-       iwl_led_cmd(priv, on, 0);
+       iwl_led_cmd(priv, on, off);
 }
 
 static int iwl_led_blink_set(struct led_classdev *led_cdev,
index 4841be2aa4994cafa42254f362753136f5debfa5..1799469268ea8e8a24d8d3fd33b0221b92ccfcd3 100644 (file)
@@ -943,14 +943,16 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
                if (sta) {
+                       u64 pn64;
+
                        tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
                        tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
 
                        rx_p1ks = data->tkip->rx_uni;
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+                       pn64 = atomic64_read(&key->tx_pn);
+                       tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
+                       tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
 
                        ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
                        iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
@@ -996,19 +998,13 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
                break;
        case WLAN_CIPHER_SUITE_CCMP:
                if (sta) {
-                       u8 *pn = seq.ccmp.pn;
+                       u64 pn64;
 
                        aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
                        aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       aes_tx_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
+                       pn64 = atomic64_read(&key->tx_pn);
+                       aes_tx_sc->pn = cpu_to_le64(pn64);
                } else
                        aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
 
index 29ea1c6705b406f5c9bb410ddb5feaad6c59eb86..c63ea79571ff5f0d6b0bbfd07b4a6faba42f1593 100644 (file)
@@ -396,7 +396,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
                    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
-       iwl_trans_d3_suspend(priv->trans, false);
+       iwl_trans_d3_suspend(priv->trans, false, true);
 
        goto out;
 
@@ -469,7 +469,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        /* we'll clear ctx->vif during iwlagn_prepare_restart() */
        vif = ctx->vif;
 
-       ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
+       ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true);
        if (ret)
                goto out_unlock;
 
@@ -732,12 +732,15 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
 
 static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size, bool amsdu)
+                                  struct ieee80211_ampdu_params *params)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
        int ret = -EINVAL;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
        struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
 
        IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
index fa41a5e1c8902002d3bf8a1d3991a416d6600499..fc475ce59b47efe0c7a19ccddacfd3b580615915 100644 (file)
@@ -73,8 +73,8 @@
 /* Highest firmware API version supported */
 #define IWL7260_UCODE_API_MAX  17
 #define IWL7265_UCODE_API_MAX  17
-#define IWL7265D_UCODE_API_MAX 20
-#define IWL3168_UCODE_API_MAX  20
+#define IWL7265D_UCODE_API_MAX 21
+#define IWL3168_UCODE_API_MAX  21
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   13
index c84a0299d43e0f12b3ad80128eea8838cb2bb2ff..97be104d12030f194a07ab67b5f0e0b8ee15f3e6 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX  20
+#define IWL8000_UCODE_API_MAX  21
+#define IWL8265_UCODE_API_MAX  21
 
 /* Oldest version we won't warn about */
 #define IWL8000_UCODE_API_OK   13
+#define IWL8265_UCODE_API_OK   20
 
 /* Lowest firmware API version supported */
 #define IWL8000_UCODE_API_MIN  13
+#define IWL8265_UCODE_API_MIN  20
 
 /* NVM versions */
 #define IWL8000_NVM_VERSION            0x0a1d
 #define IWL8000_MODULE_FIRMWARE(api) \
        IWL8000_FW_PRE "-" __stringify(api) ".ucode"
 
+#define IWL8265_FW_PRE "iwlwifi-8265-"
+#define IWL8265_MODULE_FIRMWARE(api) \
+       IWL8265_FW_PRE __stringify(api) ".ucode"
+
 #define NVM_HW_SECTION_NUM_FAMILY_8000         10
 #define DEFAULT_NVM_FILE_FAMILY_8000B          "nvmData-8000B"
 #define DEFAULT_NVM_FILE_FAMILY_8000C          "nvmData-8000C"
@@ -144,10 +152,7 @@ static const struct iwl_tt_params iwl8000_tt_params = {
        .support_tx_backoff = true,
 };
 
-#define IWL_DEVICE_8000                                                        \
-       .ucode_api_max = IWL8000_UCODE_API_MAX,                         \
-       .ucode_api_ok = IWL8000_UCODE_API_OK,                           \
-       .ucode_api_min = IWL8000_UCODE_API_MIN,                         \
+#define IWL_DEVICE_8000_COMMON                                         \
        .device_family = IWL_DEVICE_FAMILY_8000,                        \
        .max_inst_size = IWL60_RTC_INST_SIZE,                           \
        .max_data_size = IWL60_RTC_DATA_SIZE,                           \
@@ -167,10 +172,28 @@ static const struct iwl_tt_params iwl8000_tt_params = {
        .thermal_params = &iwl8000_tt_params,                           \
        .apmg_not_supported = true
 
+#define IWL_DEVICE_8000                                                        \
+       IWL_DEVICE_8000_COMMON,                                         \
+       .ucode_api_max = IWL8000_UCODE_API_MAX,                         \
+       .ucode_api_ok = IWL8000_UCODE_API_OK,                           \
+       .ucode_api_min = IWL8000_UCODE_API_MIN                          \
+
+#define IWL_DEVICE_8260                                                        \
+       IWL_DEVICE_8000_COMMON,                                         \
+       .ucode_api_max = IWL8000_UCODE_API_MAX,                         \
+       .ucode_api_ok = IWL8000_UCODE_API_OK,                           \
+       .ucode_api_min = IWL8000_UCODE_API_MIN                          \
+
+#define IWL_DEVICE_8265                                                        \
+       IWL_DEVICE_8000_COMMON,                                         \
+       .ucode_api_max = IWL8265_UCODE_API_MAX,                         \
+       .ucode_api_ok = IWL8265_UCODE_API_OK,                           \
+       .ucode_api_min = IWL8265_UCODE_API_MIN                          \
+
 const struct iwl_cfg iwl8260_2n_cfg = {
        .name = "Intel(R) Dual Band Wireless N 8260",
        .fw_name_pre = IWL8000_FW_PRE,
-       IWL_DEVICE_8000,
+       IWL_DEVICE_8260,
        .ht_params = &iwl8000_ht_params,
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -179,7 +202,7 @@ const struct iwl_cfg iwl8260_2n_cfg = {
 const struct iwl_cfg iwl8260_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 8260",
        .fw_name_pre = IWL8000_FW_PRE,
-       IWL_DEVICE_8000,
+       IWL_DEVICE_8260,
        .ht_params = &iwl8000_ht_params,
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -188,12 +211,13 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
 
 const struct iwl_cfg iwl8265_2ac_cfg = {
        .name = "Intel(R) Dual Band Wireless AC 8265",
-       .fw_name_pre = IWL8000_FW_PRE,
-       IWL_DEVICE_8000,
+       .fw_name_pre = IWL8265_FW_PRE,
+       IWL_DEVICE_8265,
        .ht_params = &iwl8000_ht_params,
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
        .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+       .vht_mu_mimo_supported = true,
 };
 
 const struct iwl_cfg iwl4165_2ac_cfg = {
@@ -209,7 +233,7 @@ const struct iwl_cfg iwl4165_2ac_cfg = {
 const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
        .name = "Intel(R) Dual Band Wireless-AC 8260",
        .fw_name_pre = IWL8000_FW_PRE,
-       IWL_DEVICE_8000,
+       IWL_DEVICE_8260,
        .ht_params = &iwl8000_ht_params,
        .nvm_ver = IWL8000_NVM_VERSION,
        .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
@@ -236,3 +260,4 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
 };
 
 MODULE_FIRMWARE(IWL8000_MODULE_FIRMWARE(IWL8000_UCODE_API_OK));
+MODULE_FIRMWARE(IWL8265_MODULE_FIRMWARE(IWL8265_UCODE_API_OK));
index ecbf4822cd697aa9dc1cf0e3a84bf5d376113bd1..8e32a57dda0f9016310fc01b27ebd1be061b0304 100644 (file)
@@ -55,7 +55,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL9000_UCODE_API_MAX  20
+#define IWL9000_UCODE_API_MAX  21
 
 /* Oldest version we won't warn about */
 #define IWL9000_UCODE_API_OK   13
@@ -138,7 +138,9 @@ static const struct iwl_tt_params iwl9000_tt_params = {
        .smem_offset = IWL9000_SMEM_OFFSET,                             \
        .smem_len = IWL9000_SMEM_LEN,                                   \
        .thermal_params = &iwl9000_tt_params,                           \
-       .apmg_not_supported = true
+       .apmg_not_supported = true,                                     \
+       .mq_rx_supported = true,                                        \
+       .vht_mu_mimo_supported = true
 
 const struct iwl_cfg iwl9260_2ac_cfg = {
                .name = "Intel(R) Dual Band Wireless AC 9260",
index f99048135fb996a632675ea426de3d1da34b6224..4f2b57e8bbc7ede32c03f2383ac26cf811418b2f 100644 (file)
@@ -311,6 +311,8 @@ struct iwl_pwr_tx_backoff {
  * @dccm2_len: length of the second DCCM
  * @smem_offset: offset from which the SMEM begins
  * @smem_len: the length of SMEM
+ * @mq_rx_supported: multi-queue rx support
+ * @vht_mu_mimo_supported: VHT MU-MIMO support
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -362,6 +364,8 @@ struct iwl_cfg {
        const u32 smem_len;
        const struct iwl_tt_params *thermal_params;
        bool apmg_not_supported;
+       bool mq_rx_supported;
+       bool vht_mu_mimo_supported;
 };
 
 /*
index 163b21bc20cb7a7d4753e63b03a27823209cfe18..a79c4f61a851d11c13937060740e539f2ed643f1 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -549,4 +550,52 @@ enum dtd_diode_reg {
        DTS_DIODE_REG_FLAGS_PASS_ONCE           = 0x00000080, /* bits [7:7] */
 };
 
+/*****************************************************************************
+ *                        MSIX related registers                             *
+ *****************************************************************************/
+
+#define CSR_MSIX_BASE                  (0x2000)
+#define CSR_MSIX_FH_INT_CAUSES_AD      (CSR_MSIX_BASE + 0x800)
+#define CSR_MSIX_FH_INT_MASK_AD                (CSR_MSIX_BASE + 0x804)
+#define CSR_MSIX_HW_INT_CAUSES_AD      (CSR_MSIX_BASE + 0x808)
+#define CSR_MSIX_HW_INT_MASK_AD                (CSR_MSIX_BASE + 0x80C)
+#define CSR_MSIX_AUTOMASK_ST_AD                (CSR_MSIX_BASE + 0x810)
+#define CSR_MSIX_RX_IVAR_AD_REG                (CSR_MSIX_BASE + 0x880)
+#define CSR_MSIX_IVAR_AD_REG           (CSR_MSIX_BASE + 0x890)
+#define CSR_MSIX_PENDING_PBA_AD                (CSR_MSIX_BASE + 0x1000)
+#define CSR_MSIX_RX_IVAR(cause)                (CSR_MSIX_RX_IVAR_AD_REG + (cause))
+#define CSR_MSIX_IVAR(cause)           (CSR_MSIX_IVAR_AD_REG + (cause))
+
+#define MSIX_FH_INT_CAUSES_Q(q)                (q)
+
+/*
+ * Causes for the FH register interrupts
+ */
+enum msix_fh_int_causes {
+       MSIX_FH_INT_CAUSES_D2S_CH0_NUM          = BIT(16),
+       MSIX_FH_INT_CAUSES_D2S_CH1_NUM          = BIT(17),
+       MSIX_FH_INT_CAUSES_S2D                  = BIT(19),
+       MSIX_FH_INT_CAUSES_FH_ERR               = BIT(21),
+};
+
+/*
+ * Causes for the HW register interrupts
+ */
+enum msix_hw_int_causes {
+       MSIX_HW_INT_CAUSES_REG_ALIVE            = BIT(0),
+       MSIX_HW_INT_CAUSES_REG_WAKEUP           = BIT(1),
+       MSIX_HW_INT_CAUSES_REG_CT_KILL          = BIT(6),
+       MSIX_HW_INT_CAUSES_REG_RF_KILL          = BIT(7),
+       MSIX_HW_INT_CAUSES_REG_PERIODIC         = BIT(8),
+       MSIX_HW_INT_CAUSES_REG_SW_ERR           = BIT(25),
+       MSIX_HW_INT_CAUSES_REG_SCD              = BIT(26),
+       MSIX_HW_INT_CAUSES_REG_FH_TX            = BIT(27),
+       MSIX_HW_INT_CAUSES_REG_HW_ERR           = BIT(29),
+       MSIX_HW_INT_CAUSES_REG_HAP              = BIT(30),
+};
+
+#define MSIX_MIN_INTERRUPT_VECTORS             2
+#define MSIX_AUTO_CLEAR_CAUSE                  0
+#define MSIX_NON_AUTO_CLEAR_CAUSE              BIT(7)
+
 #endif /* !__iwl_csr_h__ */
index 22786d7dc00a3eba375055a6a0c0817771c1ac91..2a0703fcec560afe2e1495afa79fd6ccc7375262 100644 (file)
@@ -73,12 +73,12 @@ TRACE_EVENT(iwlwifi_dev_rx,
        TP_ARGS(dev, trans, pkt, len),
        TP_STRUCT__entry(
                DEV_ENTRY
-               __field(u8, cmd)
+               __field(u16, cmd)
                __dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len))
        ),
        TP_fast_assign(
                DEV_ASSIGN;
-               __entry->cmd = pkt->hdr.cmd;
+               __entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
                memcpy(__get_dynamic_array(rxbuf), pkt,
                       iwl_rx_trace_len(trans, pkt, len));
        ),
index 7acb49075683c115d602b20619eb03700718123f..184c0fef37c000b0babb7ff562fbd3f91304f65f 100644 (file)
@@ -243,8 +243,10 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
        if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
                char rev_step = 'A' + CSR_HW_REV_STEP(drv->trans->hw_rev);
 
-               snprintf(drv->firmware_name, sizeof(drv->firmware_name),
-                        "%s%c-%s.ucode", name_pre, rev_step, tag);
+               if (rev_step != 'A')
+                       snprintf(drv->firmware_name,
+                                sizeof(drv->firmware_name), "%s%c-%s.ucode",
+                                name_pre, rev_step, tag);
        }
 
        IWL_DEBUG_INFO(drv, "attempting to load firmware %s'%s'\n",
@@ -1031,7 +1033,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                }
        }
 
-       if (usniffer_req && !*usniffer_images) {
+       if (!fw_has_capa(capa, IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED) &&
+           usniffer_req && !*usniffer_images) {
                IWL_ERR(drv,
                        "user selected to work with usniffer but usniffer image isn't available in ucode package\n");
                return -EINVAL;
@@ -1716,3 +1719,7 @@ MODULE_PARM_DESC(fw_monitor,
 module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_entry_delay,
                   uint, S_IRUGO);
 MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)");
+
+module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool,
+                  S_IRUGO);
+MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities");
index 5cc6be927eab95d7f5c2b616bf5ddebe4380f050..8af818b10e71694a0fa762feff3c641bd0c1b55e 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -312,6 +314,81 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT        28
 #define FH_MEM_TB_MAX_LENGTH                   (0x00020000)
 
+/* 9000 rx series registers */
+
+#define RFH_Q0_FRBDCB_BA_LSB 0xA08000 /* 64 bit address */
+#define RFH_Q_FRBDCB_BA_LSB(q) (RFH_Q0_FRBDCB_BA_LSB + (q) * 8)
+/* Write index table */
+#define RFH_Q0_FRBDCB_WIDX 0xA08080
+#define RFH_Q_FRBDCB_WIDX(q) (RFH_Q0_FRBDCB_WIDX + (q) * 4)
+/* Read index table */
+#define RFH_Q0_FRBDCB_RIDX 0xA080C0
+#define RFH_Q_FRBDCB_RIDX(q) (RFH_Q0_FRBDCB_RIDX + (q) * 4)
+/* Used list table */
+#define RFH_Q0_URBDCB_BA_LSB 0xA08100 /* 64 bit address */
+#define RFH_Q_URBDCB_BA_LSB(q) (RFH_Q0_URBDCB_BA_LSB + (q) * 8)
+/* Write index table */
+#define RFH_Q0_URBDCB_WIDX 0xA08180
+#define RFH_Q_URBDCB_WIDX(q) (RFH_Q0_URBDCB_WIDX + (q) * 4)
+#define RFH_Q0_URBDCB_VAID 0xA081C0
+#define RFH_Q_URBDCB_VAID(q) (RFH_Q0_URBDCB_VAID + (q) * 4)
+/* stts */
+#define RFH_Q0_URBD_STTS_WPTR_LSB 0xA08200 /*64 bits address */
+#define RFH_Q_URBD_STTS_WPTR_LSB(q) (RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8)
+
+#define RFH_Q0_ORB_WPTR_LSB 0xA08280
+#define RFH_Q_ORB_WPTR_LSB(q) (RFH_Q0_ORB_WPTR_LSB + (q) * 8)
+#define RFH_RBDBUF_RBD0_LSB 0xA08300
+#define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8)
+
+/* DMA configuration */
+#define RFH_RXF_DMA_CFG 0xA09820
+/* RB size */
+#define RFH_RXF_DMA_RB_SIZE_MASK (0x000F0000) /* bits 16-19 */
+#define RFH_RXF_DMA_RB_SIZE_POS 16
+#define RFH_RXF_DMA_RB_SIZE_1K (0x1 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_2K (0x2 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_4K (0x4 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_8K (0x8 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_12K        (0x9 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_16K        (0xA << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_20K        (0xB << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_24K        (0xC << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_28K        (0xD << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_32K        (0xE << RFH_RXF_DMA_RB_SIZE_POS)
+/* RB Circular Buffer size:defines the table sizes in RBD units */
+#define RFH_RXF_DMA_RBDCB_SIZE_MASK (0x00F00000) /* bits 20-23 */
+#define RFH_RXF_DMA_RBDCB_SIZE_POS 20
+#define RFH_RXF_DMA_RBDCB_SIZE_8       (0x3 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_16      (0x4 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_32      (0x5 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_64      (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_128     (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_256     (0x8 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_512     (0x9 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_1024    (0xA << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_2048    (0xB << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_MIN_RB_SIZE_MASK   (0x03000000) /* bit 24-25 */
+#define RFH_RXF_DMA_MIN_RB_SIZE_POS    24
+#define RFH_RXF_DMA_MIN_RB_4_8         (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS)
+#define RFH_RXF_DMA_DROP_TOO_LARGE_MASK        (0x04000000) /* bit 26 */
+#define RFH_RXF_DMA_SINGLE_FRAME_MASK  (0x20000000) /* bit 29 */
+#define RFH_DMA_EN_MASK                        (0xC0000000) /* bits 30-31*/
+#define RFH_DMA_EN_ENABLE_VAL          BIT(31)
+
+#define RFH_RXF_RXQ_ACTIVE 0xA0980C
+
+#define RFH_GEN_CFG    0xA09800
+#define RFH_GEN_CFG_SERVICE_DMA_SNOOP  BIT(0)
+#define RFH_GEN_CFG_RFH_DMA_SNOOP      BIT(1)
+#define RFH_GEN_CFG_RB_CHUNK_SIZE      BIT(4) /* 0 - 64B, 1- 128B */
+#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
+#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8
+
+#define DEFAULT_RXQ_NUM                        0
+
+/* end of 9000 rx series registers */
+
 /* TFDB  Area - TFDs buffer table */
 #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
 #define FH_TFDIB_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0x900)
@@ -434,6 +511,10 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
  */
 #define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN   (0x00000002)
 
+#define MQ_RX_TABLE_SIZE               512
+#define MQ_RX_TABLE_MASK               (MQ_RX_TABLE_SIZE - 1)
+#define MQ_RX_POOL_SIZE                        MQ_RX_TABLE_MASK
+
 #define RX_QUEUE_SIZE                         256
 #define RX_QUEUE_MASK                         255
 #define RX_QUEUE_SIZE_LOG                     8
index a5aaf685370462d97bae6b9c0935c567ad758bfa..8425e1a587d97a5ea00d914ce8f78538df1eb910 100644 (file)
@@ -293,6 +293,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
  * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a
  *     threshold.
  * @FW_DBG_TDLS: trigger log collection upon TDLS related events.
+ * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when
+ *  the firmware sends a tx reply.
  */
 enum iwl_fw_dbg_trigger {
        FW_DBG_TRIGGER_INVALID = 0,
@@ -309,6 +311,7 @@ enum iwl_fw_dbg_trigger {
        FW_DBG_TRIGGER_BA,
        FW_DBG_TRIGGER_TX_LATENCY,
        FW_DBG_TRIGGER_TDLS,
+       FW_DBG_TRIGGER_TX_STATUS,
 
        /* must be last */
        FW_DBG_TRIGGER_MAX,
index 84f8aeb926c8748f443e15ab74c01dfd1a51f77d..5f69bf5e04c79f64811312e128fd7d6f2ed9323c 100644 (file)
@@ -297,10 +297,12 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
  *     which also implies support for the scheduler configuration command
  * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
+ * @IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image
  * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
  * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
  * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload
  * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
+ * @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD
  * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
  * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
  *     sources for the MCC. This TLV bit is a future replacement to
@@ -313,7 +315,15 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
  * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
  *     antenna the beacon should be transmitted
+ * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
+ *     from AP and will send it upon d0i3 exit.
  * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
+ * @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill
+ * @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature
+ *     thresholds reporting
+ * @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command
+ * @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in
+ *     regular image.
  *
  * @NUM_IWL_UCODE_TLV_CAPA: number of bits used
  */
@@ -330,10 +340,12 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT         = (__force iwl_ucode_tlv_capa_t)11,
        IWL_UCODE_TLV_CAPA_DQA_SUPPORT                  = (__force iwl_ucode_tlv_capa_t)12,
        IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH          = (__force iwl_ucode_tlv_capa_t)13,
+       IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG            = (__force iwl_ucode_tlv_capa_t)17,
        IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT              = (__force iwl_ucode_tlv_capa_t)18,
        IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT         = (__force iwl_ucode_tlv_capa_t)19,
        IWL_UCODE_TLV_CAPA_CSUM_SUPPORT                 = (__force iwl_ucode_tlv_capa_t)21,
        IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS           = (__force iwl_ucode_tlv_capa_t)22,
+       IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD         = (__force iwl_ucode_tlv_capa_t)26,
        IWL_UCODE_TLV_CAPA_BT_COEX_PLCR                 = (__force iwl_ucode_tlv_capa_t)28,
        IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC                = (__force iwl_ucode_tlv_capa_t)29,
        IWL_UCODE_TLV_CAPA_BT_COEX_RRC                  = (__force iwl_ucode_tlv_capa_t)30,
@@ -341,8 +353,14 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE         = (__force iwl_ucode_tlv_capa_t)64,
        IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS            = (__force iwl_ucode_tlv_capa_t)65,
        IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT             = (__force iwl_ucode_tlv_capa_t)67,
+       IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT       = (__force iwl_ucode_tlv_capa_t)68,
        IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION         = (__force iwl_ucode_tlv_capa_t)71,
+       IWL_UCODE_TLV_CAPA_BEACON_STORING               = (__force iwl_ucode_tlv_capa_t)72,
        IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2               = (__force iwl_ucode_tlv_capa_t)73,
+       IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW                = (__force iwl_ucode_tlv_capa_t)74,
+       IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT      = (__force iwl_ucode_tlv_capa_t)75,
+       IWL_UCODE_TLV_CAPA_CTDP_SUPPORT                 = (__force iwl_ucode_tlv_capa_t)76,
+       IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED             = (__force iwl_ucode_tlv_capa_t)77,
 
        NUM_IWL_UCODE_TLV_CAPA
 #ifdef __CHECKER__
@@ -747,6 +765,19 @@ struct iwl_fw_dbg_trigger_tdls {
        u8 reserved[4];
 } __packed;
 
+/**
+ * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response
+ *  status.
+ * @statuses: the list of statuses to trigger the collection on
+ */
+struct iwl_fw_dbg_trigger_tx_status {
+       struct tx_status {
+               u8 status;
+               u8 reserved[3];
+       } __packed statuses[16];
+       __le32 reserved[2];
+} __packed;
+
 /**
  * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
  * @id: conf id
index fd42f63f5e84a0b7db8c3be5831e956704fe5868..d1a5dd1602f5894c52a286d18b18ad233a7b0715 100644 (file)
@@ -108,11 +108,14 @@ enum iwl_amsdu_size {
  * @power_level: power level, default = 1
  * @debug_level: levels are IWL_DL_*
  * @ant_coupling: antenna coupling in dB, default = 0
+ * @nvm_file: specifies a external NVM file
+ * @uapsd_disable: disable U-APSD, default = 1
  * @d0i3_disable: disable d0i3, default = 1,
  * @d0i3_entry_delay: time to wait after no refs are taken before
  *     entering D0i3 (in msecs)
  * @lar_disable: disable LAR (regulatory), default = 0
  * @fw_monitor: allow to use firmware monitor
+ * @disable_11ac: disable VHT capabilities, default = false.
  */
 struct iwl_mod_params {
        int sw_crypto;
@@ -133,6 +136,7 @@ struct iwl_mod_params {
        unsigned int d0i3_entry_delay;
        bool lar_disable;
        bool fw_monitor;
+       bool disable_11ac;
 };
 
 #endif /* #__iwl_modparams_h__ */
index 7b89bfc8c8ac3b1025b913e1dfd0bd017853dfa0..348135792f3ebccc2efa005d9f2088678f0378cc 100644 (file)
@@ -366,6 +366,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
                       max_ampdu_exponent <<
                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
 
+       if (cfg->vht_mu_mimo_supported)
+               vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
        if (cfg->ht_params->ldpc)
                vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
 
@@ -449,7 +452,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
                                          IEEE80211_BAND_5GHZ);
        iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
                             tx_chains, rx_chains);
-       if (data->sku_cap_11ac_enable)
+       if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac)
                iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
                                      tx_chains, rx_chains);
 
@@ -539,7 +542,7 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
                                           struct iwl_nvm_data *data,
                                           const __le16 *mac_override,
                                           const __le16 *nvm_hw,
-                                          u32 mac_addr0, u32 mac_addr1)
+                                          __le32 mac_addr0, __le32 mac_addr1)
 {
        const u8 *hw_addr;
 
@@ -583,7 +586,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
 
                if (!is_valid_ether_addr(data->hw_addr))
                        IWL_ERR_DEV(dev,
-                                   "mac address from hw section is not valid\n");
+                                   "mac address (%pM) from hw section is not valid\n",
+                                   data->hw_addr);
 
                return;
        }
@@ -597,7 +601,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_calib, const __le16 *regulatory,
                   const __le16 *mac_override, const __le16 *phy_sku,
                   u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
-                  u32 mac_addr0, u32 mac_addr1)
+                  __le32 mac_addr0, __le32 mac_addr1)
 {
        struct iwl_nvm_data *data;
        u32 sku;
index 92466ee72806218a5825da285ddebdc2e6768d9c..4e8e0dc474d49fec9c33d9b8598c1eb050f70cc5 100644 (file)
@@ -79,7 +79,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_calib, const __le16 *regulatory,
                   const __le16 *mac_override, const __le16 *phy_sku,
                   u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
-                  u32 mac_addr0, u32 mac_addr1);
+                  __le32 mac_addr0, __le32 mac_addr1);
 
 /**
  * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
index 5bde23a472b4ebfec1a082309eb72c733d292074..c46e596e12b1807ade821c2b4ac07f1b1c265174 100644 (file)
@@ -404,4 +404,6 @@ enum {
        LMPM_PAGE_PASS_NOTIF_POS = BIT(20),
 };
 
+#define UREG_CHICK             (0xA05C00)
+#define UREG_CHICK_MSIX_ENABLE BIT(25)
 #endif                         /* __iwl_prph_h__ */
index 82fb3a97a46d3f6a165a5623d4a5be83883b092e..91d74b3f666b5d5e316ea4d0a66654f5a5533700 100644 (file)
@@ -506,7 +506,7 @@ struct iwl_trans_config {
        bool sw_csum_tx;
        const struct iwl_hcmd_arr *command_groups;
        int command_groups_size;
+
        u32 sdio_adma_addr;
 };
 
@@ -618,9 +618,9 @@ struct iwl_trans_ops {
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
        void (*stop_device)(struct iwl_trans *trans, bool low_power);
 
-       void (*d3_suspend)(struct iwl_trans *trans, bool test);
+       void (*d3_suspend)(struct iwl_trans *trans, bool test, bool reset);
        int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
-                        bool test);
+                        bool test, bool reset);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -736,6 +736,11 @@ enum iwl_plat_pm_mode {
        IWL_PLAT_PM_MODE_D0I3,
 };
 
+/* Max time to wait for trans to become idle/non-idle on d0i3
+ * enter/exit (in msecs).
+ */
+#define IWL_TRANS_IDLE_TIMEOUT 2000
+
 /**
  * struct iwl_trans - transport common data
  *
@@ -831,6 +836,7 @@ struct iwl_trans {
 
        enum iwl_plat_pm_mode system_pm_mode;
        enum iwl_plat_pm_mode runtime_pm_mode;
+       bool suspending;
 
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
@@ -920,22 +926,23 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
        _iwl_trans_stop_device(trans, true);
 }
 
-static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test,
+                                       bool reset)
 {
        might_sleep();
        if (trans->ops->d3_suspend)
-               trans->ops->d3_suspend(trans, test);
+               trans->ops->d3_suspend(trans, test, reset);
 }
 
 static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
                                      enum iwl_d3_status *status,
-                                     bool test)
+                                     bool test, bool reset)
 {
        might_sleep();
        if (!trans->ops->d3_resume)
                return 0;
 
-       return trans->ops->d3_resume(trans, status, test);
+       return trans->ops->d3_resume(trans, status, test, reset);
 }
 
 static inline void iwl_trans_ref(struct iwl_trans *trans)
index b00c03fcd4473cc670cd1489c3504c767de62c65..4b560e4417ee55fa1da2539dbe7f3c1482fe8790 100644 (file)
@@ -6,7 +6,8 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +33,8 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,6 +75,7 @@
 #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT      (10 * USEC_PER_MSEC)
 #define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT       (2 * 1024) /* defined in TU */
 #define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT       (40 * 1024) /* defined in TU */
+#define IWL_MVM_P2P_UAPSD_STANDALONE           0
 #define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE       0
 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT          (50 * USEC_PER_MSEC)
 #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT          (50 * USEC_PER_MSEC)
 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK       1
 #define IWL_MVM_TOF_IS_RESPONDER               0
 #define IWL_MVM_SW_TX_CSUM_OFFLOAD             0
+#define IWL_MVM_COLLECT_FW_ERR_DUMP            1
 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE    1
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE      2
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW   1
index d3e21d95cecec52830163c4cd674d444b6940a41..c1a313149eed876fea73a764d0d519e0244c6e9d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016   Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016   Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -249,16 +251,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                return;
        case WLAN_CIPHER_SUITE_TKIP:
                if (sta) {
+                       u64 pn64;
+
                        tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
                        tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
 
                        rx_p1ks = data->tkip->rx_uni;
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+                       pn64 = atomic64_read(&key->tx_pn);
+                       tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
+                       tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
 
-                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+                       ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64),
+                                                 p1k);
                        iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
 
                        memcpy(data->tkip->mic_keys.tx,
@@ -811,8 +816,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
 {
        iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
 
-       iwl_trans_stop_device(mvm->trans);
-
+       iwl_mvm_stop_device(mvm);
        /*
         * Set the HW restart bit -- this is mostly true as we're
         * going to load new firmware and reprogram that, though
@@ -1023,14 +1027,18 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
                      struct ieee80211_sta *ap_sta)
 {
        int ret;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
-       ret = iwl_mvm_switch_to_d3(mvm);
-       if (ret)
-               return ret;
+       if (!unified_image) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       return ret;
 
-       ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
-       if (ret)
-               return ret;
+               ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
+               if (ret)
+                       return ret;
+       }
 
        if (!iwlwifi_mod_params.sw_crypto) {
                /*
@@ -1072,10 +1080,14 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
 {
        struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
        int ret;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
-       ret = iwl_mvm_switch_to_d3(mvm);
-       if (ret)
-               return ret;
+       if (!unified_image) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       return ret;
+       }
 
        /* rfkill release can be either for wowlan or netdetect */
        if (wowlan->rfkill_release)
@@ -1151,6 +1163,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        };
        int ret;
        int len __maybe_unused;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
        if (!wowlan) {
                /*
@@ -1236,7 +1250,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
 
-       iwl_trans_d3_suspend(mvm->trans, test);
+       iwl_trans_d3_suspend(mvm->trans, test, !unified_image);
  out:
        if (ret < 0) {
                iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -1299,7 +1313,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
                mutex_unlock(&mvm->d0i3_suspend_mutex);
 
-               iwl_trans_d3_suspend(trans, false);
+               iwl_trans_d3_suspend(trans, false, false);
 
                return 0;
        }
@@ -1601,7 +1615,9 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
                case WLAN_CIPHER_SUITE_TKIP:
                        iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
                        iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
-                       ieee80211_set_key_tx_seq(key, &seq);
+                       atomic64_set(&key->tx_pn,
+                                    (u64)seq.tkip.iv16 |
+                                    ((u64)seq.tkip.iv32 << 16));
                        break;
                }
 
@@ -2041,9 +2057,14 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
 static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
        struct ieee80211_vif *vif = NULL;
-       int ret;
+       int ret = 1;
        enum iwl_d3_status d3_status;
        bool keep = false;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
+
+       u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
+                                   CMD_WAKE_UP_TRANS;
 
        mutex_lock(&mvm->mutex);
 
@@ -2052,7 +2073,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        if (IS_ERR_OR_NULL(vif))
                goto err;
 
-       ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
+       ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image);
        if (ret)
                goto err;
 
@@ -2095,17 +2116,28 @@ out_iterate:
                        iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
 
 out:
-       /* return 1 to reconfigure the device */
+       if (unified_image && !ret) {
+               ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
+               if (!ret) /* D3 ended successfully - no need to reset device */
+                       return 0;
+       }
+
+       /*
+        * Reconfigure the device in one of the following cases:
+        * 1. We are not using a unified image
+        * 2. We are using a unified image but had an error while exiting D3
+        */
        set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
-
-       /* We always return 1, which causes mac80211 to do a reconfig
-        * with IEEE80211_RECONFIG_TYPE_RESTART.  This type of
-        * reconfig calls iwl_mvm_restart_complete(), where we unref
-        * the IWL_MVM_REF_UCODE_DOWN, so we need to take the
-        * reference here.
+       /*
+        * When switching images we return 1, which causes mac80211
+        * to do a reconfig with IEEE80211_RECONFIG_TYPE_RESTART.
+        * This type of reconfig calls iwl_mvm_restart_complete(),
+        * where we unref the IWL_MVM_REF_UCODE_DOWN, so we need
+        * to take the reference here.
         */
        iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+
        return 1;
 }
 
@@ -2122,7 +2154,7 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm)
        enum iwl_d3_status d3_status;
        struct iwl_trans *trans = mvm->trans;
 
-       iwl_trans_d3_resume(trans, &d3_status, false);
+       iwl_trans_d3_resume(trans, &d3_status, false, false);
 
        /*
         * make sure to clear D0I3_DEFER_WAKEUP before
index 9e0d46368cdd1c0581f218ce757ab8a258ee93e3..14004456bf550db58ff95c511e6dee3203e32fed 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1255,6 +1257,7 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm *mvm = mvmvif->mvm;
+       bool prev;
        u8 value;
        int ret;
 
@@ -1265,7 +1268,9 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
                return -EINVAL;
 
        mutex_lock(&mvm->mutex);
-       iwl_mvm_update_low_latency(mvm, vif, value);
+       prev = iwl_mvm_vif_low_latency(mvmvif);
+       mvmvif->low_latency_dbgfs = value;
+       iwl_mvm_update_low_latency(mvm, vif, prev);
        mutex_unlock(&mvm->mutex);
 
        return count;
@@ -1277,11 +1282,15 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
 {
        struct ieee80211_vif *vif = file->private_data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       char buf[2];
+       char buf[30] = {};
+       int len;
 
-       buf[0] = mvmvif->low_latency ? '1' : '0';
-       buf[1] = '\n';
-       return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+       len = snprintf(buf, sizeof(buf) - 1,
+                      "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
+                      mvmvif->low_latency_traffic,
+                      mvmvif->low_latency_dbgfs,
+                      mvmvif->low_latency_vcmd);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
@@ -1363,6 +1372,59 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
 }
 
+static void iwl_dbgfs_quota_check(void *data, u8 *mac,
+                                 struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       int *ret = data;
+
+       if (mvmvif->dbgfs_quota_min)
+               *ret = -EINVAL;
+}
+
+static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = mvmvif->mvm;
+       u16 value;
+       int ret;
+
+       ret = kstrtou16(buf, 0, &value);
+       if (ret)
+               return ret;
+
+       if (value > 95)
+               return -EINVAL;
+
+       mutex_lock(&mvm->mutex);
+
+       mvmvif->dbgfs_quota_min = 0;
+       ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                                    iwl_dbgfs_quota_check, &ret);
+       if (ret == 0) {
+               mvmvif->dbgfs_quota_min = value;
+               iwl_mvm_update_quotas(mvm, false, NULL);
+       }
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_vif *vif = file->private_data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       char buf[10];
+       int len;
+
+       len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -1386,6 +1448,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
 
 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
@@ -1423,6 +1486,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                                 S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
                                 S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
+                                S_IRUSR | S_IWUSR);
 
        if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
            mvmvif == mvm->bf_allowed_vif)
index 90500e2d107b60ada39c82adaacedc9a5051cb7e..56e6b0b8b9cc44d299f66a89ece1ad3217ab7a6f 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -63,6 +64,7 @@
  *
  *****************************************************************************/
 #include <linux/vmalloc.h>
+#include <linux/ieee80211.h>
 
 #include "mvm.h"
 #include "fw-dbg.h"
@@ -261,17 +263,18 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
 {
        struct iwl_mvm *mvm = file->private_data;
        char buf[16];
-       int pos, temp;
+       int pos, ret;
+       s32 temp;
 
        if (!mvm->ucode_loaded)
                return -EIO;
 
        mutex_lock(&mvm->mutex);
-       temp = iwl_mvm_get_temp(mvm);
+       ret = iwl_mvm_get_temp(mvm, &temp);
        mutex_unlock(&mvm->mutex);
 
-       if (temp < 0)
-               return temp;
+       if (ret)
+               return -EIO;
 
        pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
 
@@ -942,6 +945,47 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
        return count;
 }
 
+static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
+                                              char *buf, size_t count,
+                                              loff_t *ppos)
+{
+       struct iwl_rss_config_cmd cmd = {
+               .flags = cpu_to_le32(IWL_RSS_ENABLE),
+               .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
+                            IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
+                            IWL_RSS_HASH_TYPE_IPV6_TCP |
+                            IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+       };
+       int ret, i, num_repeats, nbytes = count / 2;
+
+       ret = hex2bin(cmd.indirection_table, buf, nbytes);
+       if (ret)
+               return ret;
+
+       /*
+        * The input is the redirection table, partial or full.
+        * Repeat the pattern if needed.
+        * For example, input of 01020F will be repeated 42 times,
+        * indirecting RSS hash results to queues 1, 2, 15 (skipping
+        * queues 3 - 14).
+        */
+       num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes;
+       for (i = 1; i < num_repeats; i++)
+               memcpy(&cmd.indirection_table[i * nbytes],
+                      cmd.indirection_table, nbytes);
+       /* handle cut in the middle pattern for the last places */
+       memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
+              ARRAY_SIZE(cmd.indirection_table) % nbytes);
+
+       memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key));
+
+       mutex_lock(&mvm->mutex);
+       ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
 static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
                                          char __user *user_buf,
                                          size_t count, loff_t *ppos)
@@ -983,7 +1027,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
            trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
                return -EOPNOTSUPP;
 
-       ret = kstrtouint(buf, 0, &rec_mode);
+       ret = kstrtoint(buf, 0, &rec_mode);
        if (ret)
                return ret;
 
@@ -1037,6 +1081,22 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
        return count;
 }
 
+static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
+                                            char *buf, size_t count,
+                                            loff_t *ppos)
+{
+       unsigned int max_amsdu_len;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &max_amsdu_len);
+
+       if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
+               return -EINVAL;
+       mvm->max_amsdu_len = max_amsdu_len;
+
+       return count;
+}
+
 #define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@@ -1454,6 +1514,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
 MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
 MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
+                          (IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1496,13 +1559,18 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
        if (!debugfs_create_bool("enable_scan_iteration_notif",
                                 S_IRUSR | S_IWUSR,
                                 mvm->debugfs_dir,
                                 &mvm->scan_iter_notif_enabled))
                goto err;
+       if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
+                                mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
+               goto err;
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
index 62b9a0a96700738ad5df1c15a8d02305804fbb0d..eec52c57f71831014d550c917f5452015373d5fd 100644 (file)
@@ -251,6 +251,7 @@ enum iwl_wowlan_flags {
        ENABLE_L3_FILTERING     = BIT(1),
        ENABLE_NBNS_FILTERING   = BIT(2),
        ENABLE_DHCP_FILTERING   = BIT(3),
+       ENABLE_STORE_BEACON     = BIT(4),
 };
 
 struct iwl_wowlan_config_cmd {
index fb6d341d6f3dce33f26fe4e1abe73a531dc58d80..eb9b87038e1f7ed7a54f776200e90d58b6f7f162 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -287,16 +287,13 @@ enum iwl_rx_mpdu_status {
        IWL_RX_MPDU_STATUS_KEY_ERROR            = BIT(4),
        IWL_RX_MPDU_STATUS_ICV_OK               = BIT(5),
        IWL_RX_MPDU_STATUS_MIC_OK               = BIT(6),
-       /* TODO - verify this is the correct value */
        IWL_RX_MPDU_RES_STATUS_TTAK_OK          = BIT(7),
        IWL_RX_MPDU_STATUS_SEC_MASK             = 0x7 << 8,
        IWL_RX_MPDU_STATUS_SEC_NONE             = 0x0 << 8,
        IWL_RX_MPDU_STATUS_SEC_WEP              = 0x1 << 8,
        IWL_RX_MPDU_STATUS_SEC_CCM              = 0x2 << 8,
        IWL_RX_MPDU_STATUS_SEC_TKIP             = 0x3 << 8,
-       /* TODO - define IWL_RX_MPDU_STATUS_SEC_EXT_ENC - this is a stub */
        IWL_RX_MPDU_STATUS_SEC_EXT_ENC          = 0x4 << 8,
-       /* TODO - define IWL_RX_MPDU_STATUS_SEC_GCM - this is a stub */
        IWL_RX_MPDU_STATUS_SEC_GCM              = 0x5 << 8,
        IWL_RX_MPDU_STATUS_DECRYPTED            = BIT(11),
        IWL_RX_MPDU_STATUS_WEP_MATCH            = BIT(12),
@@ -350,11 +347,11 @@ struct iwl_rx_mpdu_desc {
        /* DW8 */
        __le32 filter_match;
        /* DW9 */
-       __le32 gp2_on_air_rise;
-       /* DW10 */
        __le32 rate_n_flags;
+       /* DW10 */
+       u8 energy_a, energy_b, channel, reserved;
        /* DW11 */
-       u8 energy_a, energy_b, energy_c, channel;
+       __le32 gp2_on_air_rise;
        /* DW12 & DW13 */
        __le64 tsf_on_air_rise;
 } __packed;
@@ -365,4 +362,85 @@ struct iwl_frame_release {
        __le16 nssn;
 };
 
+enum iwl_rss_hash_func_en {
+       IWL_RSS_HASH_TYPE_IPV4_TCP,
+       IWL_RSS_HASH_TYPE_IPV4_UDP,
+       IWL_RSS_HASH_TYPE_IPV4_PAYLOAD,
+       IWL_RSS_HASH_TYPE_IPV6_TCP,
+       IWL_RSS_HASH_TYPE_IPV6_UDP,
+       IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+};
+
+#define IWL_RSS_HASH_KEY_CNT 10
+#define IWL_RSS_INDIRECTION_TABLE_SIZE 128
+#define IWL_RSS_ENABLE 1
+
+/**
+ * struct iwl_rss_config_cmd - RSS (Receive Side Scaling) configuration
+ *
+ * @flags: 1 - enable, 0 - disable
+ * @hash_mask: Type of RSS to use. Values are from %iwl_rss_hash_func_en
+ * @secret_key: 320 bit input of random key configuration from driver
+ * @indirection_table: indirection table
+ */
+struct iwl_rss_config_cmd {
+       __le32 flags;
+       u8 hash_mask;
+       u8 reserved[3];
+       __le32 secret_key[IWL_RSS_HASH_KEY_CNT];
+       u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE];
+} __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */
+
+#define IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE 128
+#define IWL_MULTI_QUEUE_SYNC_SENDER_POS 0
+#define IWL_MULTI_QUEUE_SYNC_SENDER_MSK 0xf
+
+/**
+ * struct iwl_rxq_sync_cmd - RXQ notification trigger
+ *
+ * @flags: flags of the notification. bit 0:3 are the sender queue
+ * @rxq_mask: rx queues to send the notification on
+ * @count: number of bytes in payload, should be DWORD aligned
+ * @payload: data to send to rx queues
+ */
+struct iwl_rxq_sync_cmd {
+       __le32 flags;
+       __le32 rxq_mask;
+       __le32 count;
+       u8 payload[];
+} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_rxq_sync_notification - Notification triggered by RXQ
+ * sync command
+ *
+ * @count: number of bytes in payload
+ * @payload: data to send to rx queues
+ */
+struct iwl_rxq_sync_notification {
+       __le32 count;
+       u8 payload[];
+} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
+
+/**
+* Internal message identifier
+*
+* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
+*/
+enum iwl_mvm_rxq_notif_type {
+       IWL_MVM_RXQ_NOTIF_DEL_BA,
+};
+
+/**
+* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
+* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
+*
+* @type: value from &iwl_mvm_rxq_notif_type
+* @data: payload
+*/
+struct iwl_mvm_internal_rxq_notif {
+       u32 type;
+       u8 data[];
+} __packed;
+
 #endif /* __fw_api_rx_h__ */
index 6fca4fb1d3064d8b090e57c9ed681d33ca744ea7..90d9113948363740ae4cda336bcf19a2649c2e8c 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -253,6 +255,68 @@ struct iwl_mvm_keyinfo {
        __le64 hw_tkip_mic_tx_key;
 } __packed;
 
+#define IWL_ADD_STA_STATUS_MASK        0xFF
+#define IWL_ADD_STA_BAID_MASK  0xFF00
+
+/**
+ * struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.
+ * ( REPLY_ADD_STA = 0x18 )
+ * @add_modify: 1: modify existing, 0: add new station
+ * @awake_acs:
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ *     AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
+ * @mac_id_n_color: the Mac context this station belongs to
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
+ *     alone. 1 - modify, 0 - don't change.
+ * @station_flags: look at %iwl_sta_flags
+ * @station_flags_msk: what of %station_flags have changed
+ * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
+ *     Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
+ *     add_immediate_ba_ssn.
+ * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx)
+ *     Set %STA_MODIFY_REMOVE_BA_TID to use this field
+ * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with
+ *     add_immediate_ba_tid.
+ * @sleep_tx_count: number of packets to transmit to station even though it is
+ *     asleep. Used to synchronise PS-poll and u-APSD responses while ucode
+ *     keeps track of STA sleep state.
+ * @sleep_state_flags: Look at %iwl_sta_sleep_flag.
+ * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
+ *     mac-addr.
+ * @beamform_flags: beam forming controls
+ * @tfd_queue_msk: tfd queues used by this station
+ *
+ * The device contains an internal table of per-station information, with info
+ * on security keys, aggregation parameters, and Tx rates for initial Tx
+ * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD).
+ *
+ * ADD_STA sets up the table entry for one station, either creating a new
+ * entry, or modifying a pre-existing one.
+ */
+struct iwl_mvm_add_sta_cmd_v7 {
+       u8 add_modify;
+       u8 awake_acs;
+       __le16 tid_disable_tx;
+       __le32 mac_id_n_color;
+       u8 addr[ETH_ALEN];      /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
+       __le16 reserved2;
+       u8 sta_id;
+       u8 modify_mask;
+       __le16 reserved3;
+       __le32 station_flags;
+       __le32 station_flags_msk;
+       u8 add_immediate_ba_tid;
+       u8 remove_immediate_ba_tid;
+       __le16 add_immediate_ba_ssn;
+       __le16 sleep_tx_count;
+       __le16 sleep_state_flags;
+       __le16 assoc_id;
+       __le16 beamform_flags;
+       __le32 tfd_queue_msk;
+} __packed; /* ADD_STA_CMD_API_S_VER_7 */
+
 /**
  * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table.
  * ( REPLY_ADD_STA = 0x18 )
@@ -282,6 +346,7 @@ struct iwl_mvm_keyinfo {
  *     mac-addr.
  * @beamform_flags: beam forming controls
  * @tfd_queue_msk: tfd queues used by this station
+ * @rx_ba_window: aggregation window size
  *
  * The device contains an internal table of per-station information, with info
  * on security keys, aggregation parameters, and Tx rates for initial Tx
@@ -310,7 +375,9 @@ struct iwl_mvm_add_sta_cmd {
        __le16 assoc_id;
        __le16 beamform_flags;
        __le32 tfd_queue_msk;
-} __packed; /* ADD_STA_CMD_API_S_VER_7 */
+       __le16 rx_ba_window;
+       __le16 reserved;
+} __packed; /* ADD_STA_CMD_API_S_VER_8 */
 
 /**
  * struct iwl_mvm_add_sta_key_cmd - add/modify sta key
index 82049bb139c26b2ae68f3d8a8ce191bde5f97de5..4a0fc47c81f2fad865af95ae579e9dfef50cca34 100644 (file)
@@ -119,6 +119,8 @@ enum {
        SCAN_ABORT_UMAC = 0xe,
        SCAN_COMPLETE_UMAC = 0xf,
 
+       BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13,
+
        /* station table */
        ADD_STA_KEY = 0x17,
        ADD_STA = 0x18,
@@ -213,6 +215,8 @@ enum {
 
        MFUART_LOAD_NOTIFICATION = 0xb1,
 
+       RSS_CONFIG_CMD = 0xb3,
+
        REPLY_RX_PHY_CMD = 0xc0,
        REPLY_RX_MPDU_CMD = 0xc1,
        FRAME_RELEASE = 0xc3,
@@ -277,14 +281,30 @@ enum {
  */
 enum iwl_phy_ops_subcmd_ids {
        CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0,
+       CTDP_CONFIG_CMD = 0x03,
+       TEMP_REPORTING_THRESHOLDS_CMD = 0x04,
+       CT_KILL_NOTIFICATION = 0xFE,
        DTS_MEASUREMENT_NOTIF_WIDE = 0xFF,
 };
 
+enum iwl_data_path_subcmd_ids {
+       UPDATE_MU_GROUPS_CMD = 0x1,
+       TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2,
+       MU_GROUP_MGMT_NOTIF = 0xFE,
+       RX_QUEUES_NOTIFICATION = 0xFF,
+};
+
+enum iwl_prot_offload_subcmd_ids {
+       STORED_BEACON_NTF = 0xFF,
+};
+
 /* command groups */
 enum {
        LEGACY_GROUP = 0x0,
        LONG_GROUP = 0x1,
        PHY_OPS_GROUP = 0x4,
+       DATA_PATH_GROUP = 0x5,
+       PROT_OFFLOAD_GROUP = 0xb,
 };
 
 /**
@@ -1271,6 +1291,26 @@ struct iwl_fw_bcast_filter {
        struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS];
 } __packed; /* BCAST_FILTER_S_VER_1 */
 
+#define BA_WINDOW_STREAMS_MAX          16
+#define BA_WINDOW_STATUS_TID_MSK       0x000F
+#define BA_WINDOW_STATUS_STA_ID_POS    4
+#define BA_WINDOW_STATUS_STA_ID_MSK    0x01F0
+#define BA_WINDOW_STATUS_VALID_MSK     BIT(9)
+
+/**
+ * struct iwl_ba_window_status_notif - reordering window's status notification
+ * @bitmap: bitmap of received frames [start_seq_num + 0]..[start_seq_num + 63]
+ * @ra_tid: bit 3:0 - TID, bit 8:4 - STA_ID, bit 9 - valid
+ * @start_seq_num: the start sequence number of the bitmap
+ * @mpdu_rx_count: the number of received MPDUs since entering D0i3
+ */
+struct iwl_ba_window_status_notif {
+       __le64 bitmap[BA_WINDOW_STREAMS_MAX];
+       __le16 ra_tid[BA_WINDOW_STREAMS_MAX];
+       __le32 start_seq_num[BA_WINDOW_STREAMS_MAX];
+       __le16 mpdu_rx_count[BA_WINDOW_STREAMS_MAX];
+} __packed; /* BA_WINDOW_STATUS_NTFY_API_S_VER_1 */
+
 /**
  * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration.
  * @default_discard: default action for this mac (discard (1) / pass (0)).
@@ -1668,15 +1708,77 @@ struct iwl_ext_dts_measurement_cmd {
 } __packed; /* XVT_FW_DTS_CONTROL_MEASUREMENT_REQUEST_API_S */
 
 /**
- * iwl_dts_measurement_notif - notification received with the measurements
+ * struct iwl_dts_measurement_notif_v1 - measurements notification
  *
  * @temp: the measured temperature
  * @voltage: the measured voltage
  */
-struct iwl_dts_measurement_notif {
+struct iwl_dts_measurement_notif_v1 {
        __le32 temp;
        __le32 voltage;
-} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_1*/
+
+/**
+ * struct iwl_dts_measurement_notif_v2 - measurements notification
+ *
+ * @temp: the measured temperature
+ * @voltage: the measured voltage
+ * @threshold_idx: the trip index that was crossed
+ */
+struct iwl_dts_measurement_notif_v2 {
+       __le32 temp;
+       __le32 voltage;
+       __le32 threshold_idx;
+} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_2 */
+
+/**
+ * struct ct_kill_notif - CT-kill entry notification
+ *
+ * @temperature: the current temperature in celsius
+ * @reserved: reserved
+ */
+struct ct_kill_notif {
+       __le16 temperature;
+       __le16 reserved;
+} __packed; /* GRP_PHY_CT_KILL_NTF */
+
+/**
+* enum ctdp_cmd_operation - CTDP command operations
+* @CTDP_CMD_OPERATION_START: update the current budget
+* @CTDP_CMD_OPERATION_STOP: stop ctdp
+* @CTDP_CMD_OPERATION_REPORT: get the avgerage budget
+*/
+enum iwl_mvm_ctdp_cmd_operation {
+       CTDP_CMD_OPERATION_START        = 0x1,
+       CTDP_CMD_OPERATION_STOP         = 0x2,
+       CTDP_CMD_OPERATION_REPORT       = 0x4,
+};/* CTDP_CMD_OPERATION_TYPE_E */
+
+/**
+ * struct iwl_mvm_ctdp_cmd - track and manage the FW power consumption budget
+ *
+ * @operation: see &enum iwl_mvm_ctdp_cmd_operation
+ * @budget: the budget in milliwatt
+ * @window_size: defined in API but not used
+ */
+struct iwl_mvm_ctdp_cmd {
+       __le32 operation;
+       __le32 budget;
+       __le32 window_size;
+} __packed;
+
+#define IWL_MAX_DTS_TRIPS      8
+
+/**
+ * struct iwl_temp_report_ths_cmd - set temperature thresholds
+ *
+ * @num_temps: number of temperature thresholds passed
+ * @thresholds: array with the thresholds to be configured
+ */
+struct temp_report_ths_cmd {
+       __le32 num_temps;
+       __le16 thresholds[IWL_MAX_DTS_TRIPS];
+} __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */
 
 /***********************************
  * TDLS API
@@ -1851,4 +1953,53 @@ struct iwl_shared_mem_cfg {
        __le32 page_buff_size;
 } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */
 
+/**
+ * VHT MU-MIMO group configuration
+ *
+ * @membership_status: a bitmap of MU groups
+ * @user_position:the position of station in a group. If the station is in the
+ *     group then bits (group * 2) is the position -1
+ */
+struct iwl_mu_group_mgmt_cmd {
+       __le32 reserved;
+       __le32 membership_status[2];
+       __le32 user_position[4];
+} __packed; /* MU_GROUP_ID_MNG_TABLE_API_S_VER_1 */
+
+/**
+ * struct iwl_mu_group_mgmt_notif - VHT MU-MIMO group id notification
+ *
+ * @membership_status: a bitmap of MU groups
+ * @user_position: the position of station in a group. If the station is in the
+ *     group then bits (group * 2) is the position -1
+ */
+struct iwl_mu_group_mgmt_notif {
+       __le32 membership_status[2];
+       __le32 user_position[4];
+} __packed; /* MU_GROUP_MNG_NTFY_API_S_VER_1 */
+
+#define MAX_STORED_BEACON_SIZE 600
+
+/**
+ * Stored beacon notification
+ *
+ * @system_time: system time on air rise
+ * @tsf: TSF on air rise
+ * @beacon_timestamp: beacon on air rise
+ * @phy_flags: general phy flags: band, modulation, etc.
+ * @channel: channel this beacon was received on
+ * @rates: rate in ucode internal format
+ * @byte_count: frame's byte count
+ */
+struct iwl_stored_beacon_notif {
+       __le32 system_time;
+       __le64 tsf;
+       __le32 beacon_timestamp;
+       __le16 phy_flags;
+       __le16 channel;
+       __le32 rates;
+       __le32 byte_count;
+       u8 data[MAX_STORED_BEACON_SIZE];
+} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_1 */
+
 #endif /* __fw_api_h__ */
index 0813f8184e10cbcb2472910847b789e7d57f454d..4856eac120f60d5eff2e9707e828e541761a76ae 100644 (file)
@@ -435,6 +435,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        bool monitor_dump_only = false;
        int i;
 
+       if (!IWL_MVM_COLLECT_FW_ERR_DUMP &&
+           !mvm->trans->dbg_dest_tlv)
+               return;
+
        lockdep_assert_held(&mvm->mutex);
 
        /* there's no point in fw dump if the bus is dead */
@@ -640,8 +644,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        /* Dump fw's virtual image */
        if (mvm->fw->img[mvm->cur_ucode].paging_mem_size) {
-               u32 i;
-
                for (i = 1; i < mvm->num_of_paging_blk + 1; i++) {
                        struct iwl_fw_error_dump_paging *paging;
                        struct page *pages =
index 4ed5180c547bb6ce8af288a6653220b5cf2c61b4..594cd0dc7df937d8b495f9c2864de13ed51f795d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -107,7 +108,25 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
                                    sizeof(tx_ant_cmd), &tx_ant_cmd);
 }
 
-static void iwl_free_fw_paging(struct iwl_mvm *mvm)
+static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
+{
+       int i;
+       struct iwl_rss_config_cmd cmd = {
+               .flags = cpu_to_le32(IWL_RSS_ENABLE),
+               .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
+                            IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
+                            IWL_RSS_HASH_TYPE_IPV6_TCP |
+                            IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++)
+               cmd.indirection_table[i] = i % mvm->trans->num_rx_queues;
+       memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key));
+
+       return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
+}
+
+void iwl_free_fw_paging(struct iwl_mvm *mvm)
 {
        int i;
 
@@ -127,6 +146,8 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm)
                             get_order(mvm->fw_paging_db[i].fw_paging_size));
        }
        kfree(mvm->trans->paging_download_buf);
+       mvm->trans->paging_download_buf = NULL;
+
        memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db));
 }
 
@@ -518,7 +539,9 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        struct iwl_sf_region st_fwrd_space;
 
        if (ucode_type == IWL_UCODE_REGULAR &&
-           iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE))
+           iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
+           !(fw_has_capa(&mvm->fw->ucode_capa,
+                         IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED)))
                fw = iwl_get_ucode_image(mvm, IWL_UCODE_REGULAR_USNIFFER);
        else
                fw = iwl_get_ucode_image(mvm, ucode_type);
@@ -894,6 +917,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       /* Init RSS configuration */
+       if (iwl_mvm_has_new_rx_api(mvm)) {
+               ret = iwl_send_rss_cfg_cmd(mvm);
+               if (ret) {
+                       IWL_ERR(mvm, "Failed to configure RSS queues: %d\n",
+                               ret);
+                       goto error;
+               }
+       }
+
        /* init the fw <-> mac80211 STA mapping */
        for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
                RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
@@ -923,8 +956,26 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
                        goto error;
        }
 
+#ifdef CONFIG_THERMAL
+       if (iwl_mvm_is_tt_in_fw(mvm)) {
+               /* in order to give the responsibility of ct-kill and
+                * TX backoff to FW we need to send empty temperature reporting
+                * cmd during init time
+                */
+               iwl_mvm_send_temp_report_ths_cmd(mvm);
+       } else {
+               /* Initialize tx backoffs to the minimal possible */
+               iwl_mvm_tt_tx_backoff(mvm, 0);
+       }
+
+       /* TODO: read the budget from BIOS / Platform NVM */
+       if (iwl_mvm_is_ctdp_supported(mvm) && mvm->cooling_dev.cur_state > 0)
+               ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
+                                          mvm->cooling_dev.cur_state);
+#else
        /* Initialize tx backoffs to the minimal possible */
        iwl_mvm_tt_tx_backoff(mvm, 0);
+#endif
 
        WARN_ON(iwl_mvm_config_ltr(mvm));
 
@@ -960,7 +1011,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
        return 0;
  error:
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
        return ret;
 }
 
@@ -1004,7 +1055,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
 
        return 0;
  error:
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
        return ret;
 }
 
index bf1e5eb5dbdba3657071ae1492e52b7073e6a9cd..e885db3464b094aa498df64091b6f1eaaa68993a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -744,7 +744,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                 * wake-ups.
                 */
                cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
-               if (mvmvif->ap_assoc_sta_count) {
+               if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
                        cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
                        IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
                } else {
@@ -1462,3 +1462,42 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                                   iwl_mvm_beacon_loss_iterator,
                                                   mb);
 }
+
+void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
+                                   struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_stored_beacon_notif *sb = (void *)pkt->data;
+       struct ieee80211_rx_status rx_status;
+       struct sk_buff *skb;
+       u32 size = le32_to_cpu(sb->byte_count);
+
+       if (size == 0)
+               return;
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb) {
+               IWL_ERR(mvm, "alloc_skb failed\n");
+               return;
+       }
+
+       /* update rx_status according to the notification's metadata */
+       memset(&rx_status, 0, sizeof(rx_status));
+       rx_status.mactime = le64_to_cpu(sb->tsf);
+       /* TSF as indicated by the firmware  is at INA time */
+       rx_status.flag |= RX_FLAG_MACTIME_PLCP_START;
+       rx_status.device_timestamp = le32_to_cpu(sb->system_time);
+       rx_status.band =
+               (sb->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+       rx_status.freq =
+               ieee80211_channel_to_frequency(le16_to_cpu(sb->channel),
+                                              rx_status.band);
+
+       /* copy the data */
+       memcpy(skb_put(skb, size), sb->data, size);
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+
+       /* pass it as regular rx to mac80211 */
+       ieee80211_rx_napi(mvm->hw, skb, NULL);
+}
index d70a1716f3e08e8856ec30aa66376b8437ef3108..ec6b07282e7dd84c7df6b8c825c3c7e929ed832d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -69,7 +70,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
-#include <linux/devcoredump.h>
 #include <linux/time.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
@@ -85,7 +85,6 @@
 #include "testmode.h"
 #include "iwl-fw-error-dump.h"
 #include "iwl-prph.h"
-#include "iwl-csr.h"
 #include "iwl-nvm-parse.h"
 #include "fw-dbg.h"
 
@@ -611,6 +610,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
                        IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT))
                hw->wiphy->features |= NL80211_FEATURE_WFA_TPC_IE_IN_PROBES;
 
+       wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_RRM);
+
        mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 
 #ifdef CONFIG_PM_SLEEP
@@ -837,13 +838,17 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
 static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
-                                   enum ieee80211_ampdu_mlme_action action,
-                                   struct ieee80211_sta *sta, u16 tid,
-                                   u16 *ssn, u8 buf_size, bool amsdu)
+                                   struct ieee80211_ampdu_params *params)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
        bool tx_agg_ref = false;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
+       bool amsdu = params->amsdu;
 
        IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
                     sta->addr, tid, action);
@@ -884,10 +889,10 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                        ret = -EINVAL;
                        break;
                }
-               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true);
+               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);
                break;
        case IEEE80211_AMPDU_RX_STOP:
-               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
+               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);
                break;
        case IEEE80211_AMPDU_TX_START:
                if (!iwl_enable_tx_ampdu(mvm->cfg)) {
@@ -904,7 +909,8 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
+               ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid,
+                                             buf_size, amsdu);
                break;
        default:
                WARN_ON_ONCE(1);
@@ -966,7 +972,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
         */
        iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
 
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
 
        mvm->scan_status = 0;
        mvm->ps_disabled = false;
@@ -1135,7 +1141,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
         */
        flush_work(&mvm->roc_done_wk);
 
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
 
        iwl_mvm_async_handlers_purge(mvm);
        /* async_handlers_list is empty and will stay empty: HW is stopped */
@@ -1166,8 +1172,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
                                mvm->scan_uid_status[i] = 0;
                }
        }
-
-       mvm->ucode_loaded = false;
 }
 
 static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
@@ -1759,6 +1763,50 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
 }
 #endif
 
+static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif)
+{
+       struct iwl_mu_group_mgmt_cmd cmd = {};
+
+       memcpy(cmd.membership_status, vif->bss_conf.mu_group.membership,
+              WLAN_MEMBERSHIP_LEN);
+       memcpy(cmd.user_position, vif->bss_conf.mu_group.position,
+              WLAN_USER_POSITION_LEN);
+
+       return iwl_mvm_send_cmd_pdu(mvm,
+                                   WIDE_ID(DATA_PATH_GROUP,
+                                           UPDATE_MU_GROUPS_CMD),
+                                   0, sizeof(cmd), &cmd);
+}
+
+static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac,
+                                          struct ieee80211_vif *vif)
+{
+       if (vif->mu_mimo_owner) {
+               struct iwl_mu_group_mgmt_notif *notif = _data;
+
+               /*
+                * MU-MIMO Group Id action frame is little endian. We treat
+                * the data received from firmware as if it came from the
+                * action frame, so no conversion is needed.
+                */
+               ieee80211_update_mu_groups(vif,
+                                          (u8 *)&notif->membership_status,
+                                          (u8 *)&notif->user_position);
+       }
+}
+
+void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
+                              struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;
+
+       ieee80211_iterate_active_interfaces_atomic(
+                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       iwl_mvm_mu_mimo_iface_iterator, notif);
+}
+
 static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                             struct ieee80211_vif *vif,
                                             struct ieee80211_bss_conf *bss_conf,
@@ -1867,6 +1915,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                        vif->addr);
                }
 
+               /*
+                * The firmware tracks the MU-MIMO group on its own.
+                * However, on HW restart we should restore this data.
+                */
+               if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+                   (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) {
+                       ret = iwl_mvm_update_mu_groups(mvm, vif);
+                       if (ret)
+                               IWL_ERR(mvm,
+                                       "failed to update VHT MU_MIMO groups\n");
+               }
+
                iwl_mvm_recalc_multicast(mvm);
                iwl_mvm_configure_bcast_filter(mvm);
 
@@ -1893,7 +1953,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
        }
 
-       if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) {
+       if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS |
+                      /*
+                       * Send power command on every beacon change,
+                       * because we may have not enabled beacon abort yet.
+                       */
+                      BSS_CHANGED_BEACON_INFO)) {
                ret = iwl_mvm_power_update_mac(mvm);
                if (ret)
                        IWL_ERR(mvm, "failed to update power mode\n");
@@ -2080,7 +2145,6 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
                                bss_conf->txpower);
                iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
        }
-
 }
 
 static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
@@ -2273,6 +2337,11 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
                return;
 
+       if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) {
+               vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+               return;
+       }
+
        if (iwlwifi_mod_params.uapsd_disable) {
                vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
                return;
@@ -2582,7 +2651,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+               key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
                key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
index 5f3ac8cccf49d2c5a07644f894b1ba920dca8bfc..ab410b4659f3ba7fc8114c51447c56ab624acd0d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <linux/leds.h>
 #include <linux/in6.h>
 
+#ifdef CONFIG_THERMAL
+#include <linux/thermal.h>
+#endif
+
 #include "iwl-op-mode.h"
 #include "iwl-trans.h"
 #include "iwl-notif-wait.h"
@@ -346,8 +352,9 @@ struct iwl_mvm_vif_bf_data {
  * @pm_enabled - Indicate if MAC power management is allowed
  * @monitor_active: indicates that monitor context is configured, and that the
  *     interface should get quota etc.
- * @low_latency: indicates that this interface is in low-latency mode
- *     (VMACLowLatencyMode)
+ * @low_latency_traffic: indicates low latency traffic was detected
+ * @low_latency_dbgfs: low latency mode set from debugfs
+ * @low_latency_vcmd: low latency mode set from vendor command
  * @ps_disabled: indicates that this interface requires PS to be disabled
  * @queue_params: QoS params for this MAC
  * @bcast_sta: station used for broadcast packets. Used by the following
@@ -375,7 +382,7 @@ struct iwl_mvm_vif {
        bool ap_ibss_active;
        bool pm_enabled;
        bool monitor_active;
-       bool low_latency;
+       bool low_latency_traffic, low_latency_dbgfs, low_latency_vcmd;
        bool ps_disabled;
        struct iwl_mvm_vif_bf_data bf_data;
 
@@ -432,6 +439,7 @@ struct iwl_mvm_vif {
        struct iwl_dbgfs_pm dbgfs_pm;
        struct iwl_dbgfs_bf dbgfs_bf;
        struct iwl_mac_power_cmd mac_pwr_cmd;
+       int dbgfs_quota_min;
 #endif
 
        enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
@@ -485,6 +493,12 @@ enum iwl_mvm_scan_type {
        IWL_SCAN_TYPE_FRAGMENTED,
 };
 
+enum iwl_mvm_sched_scan_pass_all_states {
+       SCHED_SCAN_PASS_ALL_DISABLED,
+       SCHED_SCAN_PASS_ALL_ENABLED,
+       SCHED_SCAN_PASS_ALL_FOUND,
+};
+
 /**
  * struct iwl_nvm_section - describes an NVM section in memory.
  *
@@ -515,6 +529,30 @@ struct iwl_mvm_tt_mgmt {
        bool throttle;
 };
 
+#ifdef CONFIG_THERMAL
+/**
+ *struct iwl_mvm_thermal_device - thermal zone related data
+ * @temp_trips: temperature thresholds for report
+ * @fw_trips_index: keep indexes to original array - temp_trips
+ * @tzone: thermal zone device data
+*/
+struct iwl_mvm_thermal_device {
+       s16 temp_trips[IWL_MAX_DTS_TRIPS];
+       u8 fw_trips_index[IWL_MAX_DTS_TRIPS];
+       struct thermal_zone_device *tzone;
+};
+
+/*
+ * iwl_mvm_cooling_device
+ * @cur_state: current state in milliwatts
+ * @cdev: struct thermal cooling device
+ */
+struct iwl_mvm_cooling_device {
+       u32 cur_state;
+       struct thermal_cooling_device *cdev;
+};
+#endif
+
 #define IWL_MVM_NUM_LAST_FRAMES_UCODE_RATES 8
 
 struct iwl_mvm_frame_stats {
@@ -645,6 +683,7 @@ struct iwl_mvm {
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
        u32 tfd_drained[IWL_MVM_STATION_COUNT];
        u8 rx_ba_sessions;
+       u32 secret_key[IWL_RSS_HASH_KEY_CNT];
 
        /* configured by mac80211 */
        u32 rts_threshold;
@@ -654,6 +693,7 @@ struct iwl_mvm {
        void *scan_cmd;
        struct iwl_mcast_filter_cmd *mcast_filter_cmd;
        enum iwl_mvm_scan_type scan_type;
+       enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all;
 
        /* max number of simultaneous scans the FW supports */
        unsigned int max_scans;
@@ -794,6 +834,11 @@ struct iwl_mvm {
 
        /* Thermal Throttling and CTkill */
        struct iwl_mvm_tt_mgmt thermal_throttle;
+#ifdef CONFIG_THERMAL
+       struct iwl_mvm_thermal_device tz_device;
+       struct iwl_mvm_cooling_device cooling_dev;
+#endif
+
        s32 temperature;        /* Celsius */
        /*
         * Debug option to set the NIC temperature. This option makes the
@@ -816,6 +861,7 @@ struct iwl_mvm {
 
        /* Indicate if device power save is allowed */
        u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
+       unsigned int max_amsdu_len; /* used for debugfs only */
 
        struct ieee80211_vif __rcu *csa_vif;
        struct ieee80211_vif __rcu *csa_tx_blocked_vif;
@@ -856,6 +902,12 @@ struct iwl_mvm {
 
        u32 ciphers[6];
        struct iwl_mvm_tof_data tof_data;
+
+       /*
+        * Drop beacons from other APs in AP mode when there are no connected
+        * clients.
+        */
+       bool drop_bcn_ap_mode;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -934,8 +986,9 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
 
 static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
 {
-       return fw_has_capa(&mvm->fw->ucode_capa,
-                          IWL_UCODE_TLV_CAPA_DQA_SUPPORT);
+       /* Make sure DQA isn't allowed in driver until feature is complete */
+       return false && fw_has_capa(&mvm->fw->ucode_capa,
+                                   IWL_UCODE_TLV_CAPA_DQA_SUPPORT);
 }
 
 static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm)
@@ -1005,10 +1058,40 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
                IWL_MVM_BT_COEX_MPLUT;
 }
 
+static inline
+bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm)
+{
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) &&
+               IWL_MVM_P2P_UAPSD_STANDALONE;
+}
+
 static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm)
 {
-       /* firmware flag isn't defined yet */
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT);
+}
+
+static inline bool iwl_mvm_is_tt_in_fw(struct iwl_mvm *mvm)
+{
+#ifdef CONFIG_THERMAL
+       /* these two TLV are redundant since the responsibility to CT-kill by
+        * FW happens only after we send at least one command of
+        * temperature THs report.
+        */
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW) &&
+              fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT);
+#else /* CONFIG_THERMAL */
        return false;
+#endif /* CONFIG_THERMAL */
+}
+
+static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm)
+{
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_CTDP_SUPPORT);
 }
 
 extern const u8 iwl_mvm_ac_to_tx_fifo[];
@@ -1143,6 +1226,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                        struct iwl_rx_cmd_buffer *rxb, int queue);
 void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm,
                              struct iwl_rx_cmd_buffer *rxb, int queue);
+int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
+                           const u8 *data, u32 count);
+void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+                           int queue);
 void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm,
@@ -1184,6 +1271,12 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                     struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
+                                   struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
+                              struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
+                                struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
 unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
@@ -1225,6 +1318,9 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
 void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                                              struct iwl_rx_cmd_buffer *rxb);
 
+/* Paging */
+void iwl_free_fw_paging(struct iwl_mvm *mvm);
+
 /* MVM debugfs */
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
@@ -1417,8 +1513,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
         * binding, so this has no real impact. For now, just return
         * the current desired low-latency state.
         */
-
-       return mvmvif->low_latency;
+       return mvmvif->low_latency_dbgfs ||
+              mvmvif->low_latency_traffic ||
+              mvmvif->low_latency_vcmd;
 }
 
 /* hw scheduler queue config */
@@ -1456,32 +1553,30 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
        iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout);
 }
 
-static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
-                                         int mac80211_queue, int fifo,
-                                         int sta_id, int tid, int frame_limit,
-                                         u16 ssn, unsigned int wdg_timeout)
+static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
 {
-       struct iwl_trans_txq_scd_cfg cfg = {
-               .fifo = fifo,
-               .sta_id = sta_id,
-               .tid = tid,
-               .frame_limit = frame_limit,
-               .aggregate = true,
-       };
-
-       iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout);
+       mvm->ucode_loaded = false;
+       iwl_trans_stop_device(mvm->trans);
 }
 
+/* Stop/start all mac queues in a given bitmap */
+void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
+void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq);
+
 /* Thermal management and CT-kill */
 void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
 void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp);
 void iwl_mvm_temp_notif(struct iwl_mvm *mvm,
                        struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);
-void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
+void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff);
+void iwl_mvm_thermal_exit(struct iwl_mvm *mvm);
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
-int iwl_mvm_get_temp(struct iwl_mvm *mvm);
+int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp);
+void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
+int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm);
+int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm);
+int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget);
 
 /* Location Aware Regulatory */
 struct iwl_mcc_update_resp *
index 7a3da2da6fd0bfe280415849764ca84361ea573a..c446e0da97899a45781d87e4b5bcb7341ee0c1fd 100644 (file)
@@ -300,7 +300,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
        struct iwl_nvm_section *sections = mvm->nvm_sections;
        const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
        bool lar_enabled;
-       u32 mac_addr0, mac_addr1;
+       __le32 mac_addr0, mac_addr1;
 
        /* Checking for required sections */
        if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
@@ -337,8 +337,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
                return NULL;
 
        /* read the mac address from WFMP registers */
-       mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0);
-       mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1);
+       mac_addr0 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+                                                   WFMP_MAC_ADDR_0));
+       mac_addr1 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+                                                   WFMP_MAC_ADDR_1));
 
        hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
        sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
index 89ea70deeb84410edd0e3ad07ae77abc08476107..699a80863e86bc9a0b94b8e266edd4cb2c831d0f 100644 (file)
@@ -33,6 +33,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -235,6 +236,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION,
                   iwl_mvm_rx_ant_coupling_notif, true),
 
+       RX_HANDLER(BA_WINDOW_STATUS_NOTIFICATION_ID,
+                  iwl_mvm_window_status_notif, false),
+
        RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, false),
        RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, true),
 
@@ -262,11 +266,17 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
        RX_HANDLER(DTS_MEASUREMENT_NOTIFICATION, iwl_mvm_temp_notif, true),
        RX_HANDLER_GRP(PHY_OPS_GROUP, DTS_MEASUREMENT_NOTIF_WIDE,
                       iwl_mvm_temp_notif, true),
+       RX_HANDLER_GRP(PHY_OPS_GROUP, CT_KILL_NOTIFICATION,
+                      iwl_mvm_ct_kill_notif, false),
 
        RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif,
                   true),
        RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false),
        RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true),
+       RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF,
+                      iwl_mvm_rx_stored_beacon_notif, false),
+       RX_HANDLER_GRP(DATA_PATH_GROUP, MU_GROUP_MGMT_NOTIF,
+                      iwl_mvm_mu_mimo_grp_notif, false),
 
 };
 #undef RX_HANDLER
@@ -289,6 +299,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
        HCMD_NAME(SCAN_COMPLETE_UMAC),
        HCMD_NAME(TOF_CMD),
        HCMD_NAME(TOF_NOTIFICATION),
+       HCMD_NAME(BA_WINDOW_STATUS_NOTIFICATION_ID),
        HCMD_NAME(ADD_STA_KEY),
        HCMD_NAME(ADD_STA),
        HCMD_NAME(REMOVE_STA),
@@ -344,6 +355,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
        HCMD_NAME(MAC_PM_POWER_TABLE),
        HCMD_NAME(TDLS_CHANNEL_SWITCH_NOTIFICATION),
        HCMD_NAME(MFUART_LOAD_NOTIFICATION),
+       HCMD_NAME(RSS_CONFIG_CMD),
        HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
        HCMD_NAME(REPLY_RX_PHY_CMD),
        HCMD_NAME(REPLY_RX_MPDU_CMD),
@@ -383,16 +395,37 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
  */
 static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
        HCMD_NAME(CMD_DTS_MEASUREMENT_TRIGGER_WIDE),
+       HCMD_NAME(CTDP_CONFIG_CMD),
+       HCMD_NAME(TEMP_REPORTING_THRESHOLDS_CMD),
+       HCMD_NAME(CT_KILL_NOTIFICATION),
        HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
 };
 
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
+static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = {
+       HCMD_NAME(UPDATE_MU_GROUPS_CMD),
+       HCMD_NAME(TRIGGER_RX_QUEUES_NOTIF_CMD),
+       HCMD_NAME(MU_GROUP_MGMT_NOTIF),
+       HCMD_NAME(RX_QUEUES_NOTIFICATION),
+};
+
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
+static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
+       HCMD_NAME(STORED_BEACON_NTF),
+};
+
 static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
        [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
        [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
        [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
+       [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names),
+       [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),
 };
 
-
 /* this forward declaration can avoid to export the function */
 static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
 static void iwl_mvm_d0i3_exit_work(struct work_struct *wk);
@@ -463,8 +496,11 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        if (iwl_mvm_has_new_rx_api(mvm)) {
                op_mode->ops = &iwl_mvm_ops_mq;
+               trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
        } else {
                op_mode->ops = &iwl_mvm_ops;
+               trans->rx_mpdu_cmd_hdr_size =
+                       sizeof(struct iwl_rx_mpdu_res_start);
 
                if (WARN_ON(trans->num_rx_queues > 1))
                        goto out_free;
@@ -481,6 +517,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        }
        mvm->sf_state = SF_UNINIT;
        mvm->cur_ucode = IWL_UCODE_INIT;
+       mvm->drop_bcn_ap_mode = true;
 
        mutex_init(&mvm->mutex);
        mutex_init(&mvm->d0i3_suspend_mutex);
@@ -555,7 +592,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_trans_configure(mvm->trans, &trans_cfg);
 
        trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
-       trans->rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
        trans->dbg_dest_tlv = mvm->fw->dbg_dest_tlv;
        trans->dbg_dest_reg_num = mvm->fw->dbg_dest_reg_num;
        memcpy(trans->dbg_conf_tlv, mvm->fw->dbg_conf_tlv,
@@ -576,7 +612,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                 mvm->cfg->name, mvm->trans->hw_rev);
 
        min_backoff = calc_min_backoff(trans, cfg);
-       iwl_mvm_tt_initialize(mvm, min_backoff);
+       iwl_mvm_thermal_initialize(mvm, min_backoff);
 
        if (iwlwifi_mod_params.nvm_file)
                mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
@@ -607,7 +643,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                iwl_mvm_ref(mvm, IWL_MVM_REF_INIT_UCODE);
                err = iwl_run_init_mvm_ucode(mvm, true);
                if (!err || !iwlmvm_mod_params.init_dbg)
-                       iwl_trans_stop_device(trans);
+                       iwl_mvm_stop_device(mvm);
                iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE);
                mutex_unlock(&mvm->mutex);
                /* returns 0 if successful, 1 if success but in rfkill */
@@ -636,16 +672,22 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        memset(&mvm->rx_stats, 0, sizeof(struct mvm_statistics_rx));
 
-       /* rpm starts with a taken reference, we can release it now */
-       iwl_trans_unref(mvm->trans);
+       /* The transport always starts with a taken reference, we can
+        * release it now if d0i3 is supported */
+       if (iwl_mvm_is_d0i3_supported(mvm))
+               iwl_trans_unref(mvm->trans);
 
        iwl_mvm_tof_init(mvm);
 
+       /* init RSS hash key */
+       get_random_bytes(mvm->secret_key, sizeof(mvm->secret_key));
+
        return op_mode;
 
  out_unregister:
        ieee80211_unregister_hw(mvm->hw);
        iwl_mvm_leds_exit(mvm);
+       iwl_mvm_thermal_exit(mvm);
  out_free:
        flush_delayed_work(&mvm->fw_dump_wk);
        iwl_phy_db_free(mvm->phy_db);
@@ -661,9 +703,16 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        int i;
 
+       /* If d0i3 is supported, we have released the reference that
+        * the transport started with, so we should take it back now
+        * that we are leaving.
+        */
+       if (iwl_mvm_is_d0i3_supported(mvm))
+               iwl_trans_ref(mvm->trans);
+
        iwl_mvm_leds_exit(mvm);
 
-       iwl_mvm_tt_exit(mvm);
+       iwl_mvm_thermal_exit(mvm);
 
        ieee80211_unregister_hw(mvm->hw);
 
@@ -684,6 +733,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++)
                kfree(mvm->nvm_sections[i].data);
 
+       iwl_free_fw_paging(mvm);
+
        iwl_mvm_tof_clean(mvm);
 
        ieee80211_free_hw(mvm->hw);
@@ -841,28 +892,24 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
                iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
        else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
                iwl_mvm_rx_phy_cmd_mq(mvm, rxb);
+       else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP &&
+                         pkt->hdr.cmd == RX_QUEUES_NOTIFICATION))
+               iwl_mvm_rx_queue_notif(mvm, rxb, 0);
        else
                iwl_mvm_rx_common(mvm, rxb, pkt);
 }
 
-static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
+void iwl_mvm_stop_mac_queues(struct iwl_mvm *mvm, unsigned long mq)
 {
-       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
-       unsigned long mq;
        int q;
 
-       spin_lock_bh(&mvm->queue_info_lock);
-       mq = mvm->queue_info[queue].hw_queue_to_mac80211;
-       spin_unlock_bh(&mvm->queue_info_lock);
-
        if (WARN_ON_ONCE(!mq))
                return;
 
        for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
                if (atomic_inc_return(&mvm->mac80211_queue_stop_count[q]) > 1) {
                        IWL_DEBUG_TX_QUEUES(mvm,
-                                           "queue %d (mac80211 %d) already stopped\n",
-                                           queue, q);
+                                           "mac80211 %d already stopped\n", q);
                        continue;
                }
 
@@ -882,24 +929,29 @@ static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode,
        iwl_trans_block_txq_ptrs(mvm->trans, false);
 }
 
-static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
+static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
 {
        struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
        unsigned long mq;
-       int q;
 
        spin_lock_bh(&mvm->queue_info_lock);
-       mq = mvm->queue_info[queue].hw_queue_to_mac80211;
+       mq = mvm->queue_info[hw_queue].hw_queue_to_mac80211;
        spin_unlock_bh(&mvm->queue_info_lock);
 
+       iwl_mvm_stop_mac_queues(mvm, mq);
+}
+
+void iwl_mvm_start_mac_queues(struct iwl_mvm *mvm, unsigned long mq)
+{
+       int q;
+
        if (WARN_ON_ONCE(!mq))
                return;
 
        for_each_set_bit(q, &mq, IEEE80211_MAX_QUEUES) {
                if (atomic_dec_return(&mvm->mac80211_queue_stop_count[q]) > 0) {
                        IWL_DEBUG_TX_QUEUES(mvm,
-                                           "queue %d (mac80211 %d) still stopped\n",
-                                           queue, q);
+                                           "mac80211 %d still stopped\n", q);
                        continue;
                }
 
@@ -907,6 +959,18 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
        }
 }
 
+static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int hw_queue)
+{
+       struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
+       unsigned long mq;
+
+       spin_lock_bh(&mvm->queue_info_lock);
+       mq = mvm->queue_info[hw_queue].hw_queue_to_mac80211;
+       spin_unlock_bh(&mvm->queue_info_lock);
+
+       iwl_mvm_start_mac_queues(mvm, mq);
+}
+
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
 {
        if (state)
@@ -1196,7 +1260,7 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
        cmd->is_11n_connection = ap_sta->ht_cap.ht_supported;
        cmd->offloading_tid = iter_data->offloading_tid;
        cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING |
-               ENABLE_DHCP_FILTERING;
+               ENABLE_DHCP_FILTERING | ENABLE_STORE_BEACON;
        /*
         * The d0i3 uCode takes care of the nonqos counters,
         * so configure only the qos seq ones.
@@ -1217,8 +1281,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
        struct iwl_wowlan_config_cmd wowlan_config_cmd = {
                .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME |
                                             IWL_WOWLAN_WAKEUP_BEACON_MISS |
-                                            IWL_WOWLAN_WAKEUP_LINK_CHANGE |
-                                            IWL_WOWLAN_WAKEUP_BCN_FILTERING),
+                                            IWL_WOWLAN_WAKEUP_LINK_CHANGE),
        };
        struct iwl_d3_manager_config d3_cfg_cmd = {
                .min_sleep_time = cpu_to_le32(1000),
@@ -1268,6 +1331,12 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
 
        /* configure wowlan configuration only if needed */
        if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) {
+               /* wake on beacons only if beacon storing isn't supported */
+               if (!fw_has_capa(&mvm->fw->ucode_capa,
+                                IWL_UCODE_TLV_CAPA_BEACON_STORING))
+                       wowlan_config_cmd.wakeup_filter |=
+                               cpu_to_le32(IWL_WOWLAN_WAKEUP_BCN_FILTERING);
+
                iwl_mvm_wowlan_config_key_params(mvm,
                                                 d0i3_iter_data.connected_vif,
                                                 true, flags);
@@ -1508,6 +1577,9 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode,
 
        if (unlikely(pkt->hdr.cmd == FRAME_RELEASE))
                iwl_mvm_rx_frame_release(mvm, rxb, queue);
+       else if (unlikely(pkt->hdr.cmd == RX_QUEUES_NOTIFICATION &&
+                         pkt->hdr.group_id == DATA_PATH_GROUP))
+               iwl_mvm_rx_queue_notif(mvm, rxb, queue);
        else
                iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, queue);
 }
index 9de159f1ef2dd366fbfeb67a75c1547952a26087..f313910cd0269f9e764b527ae886a49b1d9e4ef7 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -259,6 +259,26 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
                IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
 }
 
+static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac,
+                                           struct ieee80211_vif *vif)
+{
+       bool *is_p2p_standalone = _data;
+
+       switch (ieee80211_vif_type_p2p(vif)) {
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_AP:
+               *is_p2p_standalone = false;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (vif->bss_conf.assoc)
+                       *is_p2p_standalone = false;
+               break;
+
+       default:
+               break;
+       }
+}
+
 static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif)
 {
@@ -268,9 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                    ETH_ALEN))
                return false;
 
-       if (vif->p2p &&
-           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
-               return false;
        /*
         * Avoid using uAPSD if P2P client is associated to GO that uses
         * opportunistic power save. This is due to current FW limitation.
@@ -287,6 +304,22 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
        if (iwl_mvm_phy_ctx_count(mvm) >= 2)
                return false;
 
+       if (vif->p2p) {
+               /* Allow U-APSD only if p2p is stand alone */
+               bool is_p2p_standalone = true;
+
+               if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm))
+                       return false;
+
+               ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_p2p_standalone_iterator,
+                                       &is_p2p_standalone);
+
+               if (!is_p2p_standalone)
+                       return false;
+       }
+
        return true;
 }
 
@@ -544,7 +577,6 @@ void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
 
 struct iwl_power_vifs {
        struct iwl_mvm *mvm;
-       struct ieee80211_vif *bf_vif;
        struct ieee80211_vif *bss_vif;
        struct ieee80211_vif *p2p_vif;
        struct ieee80211_vif *ap_vif;
@@ -617,11 +649,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
                if (mvmvif->phy_ctxt)
                        if (mvmvif->phy_ctxt->id < MAX_PHYS)
                                power_iterator->bss_active = true;
-
-               if (mvmvif->bf_data.bf_enabled &&
-                   !WARN_ON(power_iterator->bf_vif))
-                       power_iterator->bf_vif = vif;
-
                break;
 
        default:
@@ -850,29 +877,9 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
        return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false);
 }
 
-static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
-                                      struct ieee80211_vif *vif,
-                                      bool enable)
-{
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_beacon_filter_cmd cmd = {
-               IWL_BF_CMD_CONFIG_DEFAULTS,
-               .bf_enable_beacon_filter = cpu_to_le32(1),
-       };
-
-       if (!mvmvif->bf_data.bf_enabled)
-               return 0;
-
-       if (mvm->cur_ucode == IWL_UCODE_WOWLAN)
-               cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
-
-       mvmvif->bf_data.ba_enabled = enable;
-       return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false);
-}
-
-int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif,
-                                 u32 flags)
+static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         u32 flags, bool d0i3)
 {
        struct iwl_beacon_filter_cmd cmd = {};
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -883,12 +890,20 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
 
        ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
 
-       if (!ret)
+       /* don't change bf_enabled in case of temporary d0i3 configuration */
+       if (!ret && !d0i3)
                mvmvif->bf_data.bf_enabled = false;
 
        return ret;
 }
 
+int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                 struct ieee80211_vif *vif,
+                                 u32 flags)
+{
+       return _iwl_mvm_disable_beacon_filter(mvm, vif, flags, false);
+}
+
 static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
 {
        bool disable_ps;
@@ -918,21 +933,26 @@ static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
 }
 
 static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
-                               struct iwl_power_vifs *vifs)
+                               struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_vif *mvmvif;
-       bool ba_enable;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_beacon_filter_cmd cmd = {
+               IWL_BF_CMD_CONFIG_DEFAULTS,
+               .bf_enable_beacon_filter = cpu_to_le32(1),
+       };
 
-       if (!vifs->bf_vif)
+       if (!mvmvif->bf_data.bf_enabled)
                return 0;
 
-       mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif);
+       if (mvm->cur_ucode == IWL_UCODE_WOWLAN)
+               cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
 
-       ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
-                     !vifs->bf_vif->bss_conf.ps ||
-                     iwl_mvm_vif_low_latency(mvmvif));
+       mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled ||
+                                      mvm->ps_disabled ||
+                                      !vif->bss_conf.ps ||
+                                      iwl_mvm_vif_low_latency(mvmvif));
 
-       return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable);
+       return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false);
 }
 
 int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
@@ -953,7 +973,10 @@ int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return iwl_mvm_power_set_ba(mvm, &vifs);
+       if (vifs.bss_vif)
+               return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
+
+       return 0;
 }
 
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
@@ -988,7 +1011,10 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
                        return ret;
        }
 
-       return iwl_mvm_power_set_ba(mvm, &vifs);
+       if (vifs.bss_vif)
+               return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
+
+       return 0;
 }
 
 int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
@@ -1025,8 +1051,17 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
                        IWL_BF_CMD_CONFIG_D0I3,
                        .bf_enable_beacon_filter = cpu_to_le32(1),
                };
-               ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
-                                                   flags, true);
+               /*
+                * When beacon storing is supported - disable beacon filtering
+                * altogether - the latest beacon will be sent when exiting d0i3
+                */
+               if (fw_has_capa(&mvm->fw->ucode_capa,
+                               IWL_UCODE_TLV_CAPA_BEACON_STORING))
+                       ret = _iwl_mvm_disable_beacon_filter(mvm, vif, flags,
+                                                            true);
+               else
+                       ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
+                                                           flags, true);
        } else {
                if (mvmvif->bf_data.bf_enabled)
                        ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags);
index 0b762b4f8fadfb26b36f103b64308239edda9c23..2141db5bff82a28cbe2b5cc1280af264a5f0cc06 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,6 +76,9 @@ struct iwl_mvm_quota_iterator_data {
        int n_interfaces[MAX_BINDINGS];
        int colors[MAX_BINDINGS];
        int low_latency[MAX_BINDINGS];
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       int dbgfs_min[MAX_BINDINGS];
+#endif
        int n_low_latency_bindings;
        struct ieee80211_vif *disabled_vif;
 };
@@ -129,6 +134,12 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
 
        data->n_interfaces[id]++;
 
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (mvmvif->dbgfs_quota_min)
+               data->dbgfs_min[id] = max(data->dbgfs_min[id],
+                                         mvmvif->dbgfs_quota_min);
+#endif
+
        if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
                data->n_low_latency_bindings++;
                data->low_latency[id] = true;
@@ -259,6 +270,11 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
 
                if (data.n_interfaces[i] <= 0)
                        cmd.quotas[idx].quota = cpu_to_le32(0);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               else if (data.dbgfs_min[i])
+                       cmd.quotas[idx].quota =
+                               cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100);
+#endif
                else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
                         data.low_latency[i])
                        /*
index 94caa88df4422764573dbd6099af5315c962bdc5..61d0a8cd13f918b0a75fbce2840751b252b3836d 100644 (file)
@@ -556,6 +556,7 @@ static char *rs_pretty_rate(const struct rs_rate *rate)
        if (is_type_legacy(rate->type) && (rate->index <= IWL_RATE_54M_INDEX))
                rate_str = legacy_rates[rate->index];
        else if ((is_type_ht(rate->type) || is_type_vht(rate->type)) &&
+                (rate->index >= IWL_RATE_MCS_0_INDEX) &&
                 (rate->index <= IWL_RATE_MCS_9_INDEX))
                rate_str = ht_vht_rates[rate->index];
        else
@@ -1672,6 +1673,20 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
        }
 }
 
+static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+                            struct iwl_scale_tbl_info *tbl,
+                            enum rs_action scale_action)
+{
+       struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
+
+       if ((!is_vht(&tbl->rate) && !is_ht(&tbl->rate)) ||
+           tbl->rate.index < IWL_RATE_MCS_5_INDEX ||
+           scale_action == RS_ACTION_DOWNSCALE)
+               sta_priv->tlc_amsdu = false;
+       else
+               sta_priv->tlc_amsdu = true;
+}
+
 /*
  * setup rate table in uCode
  */
@@ -2062,7 +2077,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
        }
 
        /* try decreasing first if applicable */
-       if (weak != TPC_INVALID) {
+       if (sr >= RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) &&
+           weak != TPC_INVALID) {
                if (weak_tpt == IWL_INVALID_VALUE &&
                    (strong_tpt == IWL_INVALID_VALUE ||
                     current_tpt >= strong_tpt)) {
@@ -2414,6 +2430,7 @@ lq_update:
                tbl->rate.index = index;
                if (IWL_MVM_RS_80_20_FAR_RANGE_TWEAK)
                        rs_tweak_rate_tbl(mvm, sta, lq_sta, tbl, scale_action);
+               rs_set_amsdu_len(mvm, sta, tbl, scale_action);
                rs_update_rate_tbl(mvm, sta, lq_sta, tbl);
        }
 
@@ -3097,6 +3114,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        sband = hw->wiphy->bands[band];
 
        lq_sta->lq.sta_id = sta_priv->sta_id;
+       sta_priv->tlc_amsdu = false;
 
        for (j = 0; j < LQ_SIZE; j++)
                rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]);
@@ -3656,10 +3674,13 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
        ssize_t ret;
 
        struct iwl_lq_sta *lq_sta = file->private_data;
+       struct iwl_mvm_sta *mvmsta =
+               container_of(lq_sta, struct iwl_mvm_sta, lq_sta);
        struct iwl_mvm *mvm;
        struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
        struct rs_rate *rate = &tbl->rate;
        u32 ss_params;
+
        mvm = lq_sta->pers.drv;
        buff = kmalloc(2048, GFP_KERNEL);
        if (!buff)
@@ -3685,10 +3706,11 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                                (is_ht20(rate)) ? "20MHz" :
                                (is_ht40(rate)) ? "40MHz" :
                                (is_ht80(rate)) ? "80Mhz" : "BAD BW");
-               desc += sprintf(buff + desc, " %s %s %s\n",
+               desc += sprintf(buff + desc, " %s %s %s %s\n",
                                (rate->sgi) ? "SGI" : "NGI",
                                (rate->ldpc) ? "LDPC" : "BCC",
-                               (lq_sta->is_agg) ? "AGG on" : "");
+                               (lq_sta->is_agg) ? "AGG on" : "",
+                               (mvmsta->tlc_amsdu) ? "AMSDU on" : "");
        }
        desc += sprintf(buff+desc, "last tx rate=0x%X\n",
                        lq_sta->last_rate_n_flags);
index 145ec68ce6f9a398c3bed94f3f4d4f5d2eb38e64..485cfc1a4daafd5f30ad82fde8bc873e6f47daa6 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -322,11 +323,9 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
        rx_status->freq =
                ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
                                               rx_status->band);
-       /*
-        * TSF as indicated by the fw is at INA time, but mac80211 expects the
-        * TSF at the beginning of the MPDU.
-        */
-       /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/
+
+       /* TSF as indicated by the firmware  is at INA time */
+       rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
 
        iwl_mvm_get_signal_strength(mvm, phy_info, rx_status);
 
@@ -448,6 +447,12 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
        iwl_mvm_update_frame_stats(mvm, rate_n_flags,
                                   rx_status->flag & RX_FLAG_AMPDU_DETAILS);
 #endif
+
+       if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
+                     ieee80211_is_probe_resp(hdr->frame_control)) &&
+                    mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED))
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
+
        iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, hdr, len, ampdu_status,
                                        crypt_len, rxb);
 }
@@ -622,3 +627,51 @@ void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 {
        iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb));
 }
+
+void iwl_mvm_window_status_notif(struct iwl_mvm *mvm,
+                                struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_ba_window_status_notif *notif = (void *)pkt->data;
+       int i;
+       u32 pkt_len = iwl_rx_packet_payload_len(pkt);
+
+       if (WARN_ONCE(pkt_len != sizeof(*notif),
+                     "Received window status notification of wrong size (%u)\n",
+                     pkt_len))
+               return;
+
+       rcu_read_lock();
+       for (i = 0; i < BA_WINDOW_STREAMS_MAX; i++) {
+               struct ieee80211_sta *sta;
+               u8 sta_id, tid;
+               u64 bitmap;
+               u32 ssn;
+               u16 ratid;
+               u16 received_mpdu;
+
+               ratid = le16_to_cpu(notif->ra_tid[i]);
+               /* check that this TID is valid */
+               if (!(ratid & BA_WINDOW_STATUS_VALID_MSK))
+                       continue;
+
+               received_mpdu = le16_to_cpu(notif->mpdu_rx_count[i]);
+               if (received_mpdu == 0)
+                       continue;
+
+               tid = ratid & BA_WINDOW_STATUS_TID_MSK;
+               /* get the station */
+               sta_id = (ratid & BA_WINDOW_STATUS_STA_ID_MSK)
+                        >> BA_WINDOW_STATUS_STA_ID_POS;
+               sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+               if (IS_ERR_OR_NULL(sta))
+                       continue;
+               bitmap = le64_to_cpu(notif->bitmap[i]);
+               ssn = le32_to_cpu(notif->start_seq_num[i]);
+
+               /* update mac80211 with the bitmap for the reordering buffer */
+               ieee80211_mark_rx_ba_filtered_frames(sta, tid, ssn, bitmap,
+                                                    received_mpdu);
+       }
+       rcu_read_unlock();
+}
index 0c073e02fd4cba9d07c8410c2ec1b4e99c46a8d7..cd6ca374e5d38774be0b7f779a6245912b4e3da9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -29,7 +29,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -156,7 +156,14 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr,
                               u16 len, u8 crypt_len,
                               struct iwl_rx_cmd_buffer *rxb)
 {
-       unsigned int hdrlen, fraglen;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rx_mpdu_desc *desc = (void *)pkt->data;
+       unsigned int headlen, fraglen, pad_len = 0;
+       unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+
+       if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD)
+               pad_len = 2;
+       len -= pad_len;
 
        /* If frame is small enough to fit in skb->head, pull it completely.
         * If not, only pull ieee80211_hdr (including crypto if present, and
@@ -170,14 +177,23 @@ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr,
         * If the latter changes (there are efforts in the standards group
         * to do so) we should revisit this and ieee80211_data_to_8023().
         */
-       hdrlen = (len <= skb_tailroom(skb)) ? len :
-                                             sizeof(*hdr) + crypt_len + 8;
+       headlen = (len <= skb_tailroom(skb)) ? len :
+                                              hdrlen + crypt_len + 8;
 
+       /* The firmware may align the packet to DWORD.
+        * The padding is inserted after the IV.
+        * After copying the header + IV skip the padding if
+        * present before copying packet data.
+        */
+       hdrlen += crypt_len;
        memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
-       fraglen = len - hdrlen;
+       memcpy(skb_put(skb, headlen - hdrlen), (u8 *)hdr + hdrlen + pad_len,
+              headlen - hdrlen);
+
+       fraglen = len - headlen;
 
        if (fraglen) {
-               int offset = (void *)hdr + hdrlen -
+               int offset = (void *)hdr + headlen + pad_len -
                             rxb_addr(rxb) + rxb_offset(rxb);
 
                skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset,
@@ -201,25 +217,22 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
                                        struct iwl_rx_mpdu_desc *desc,
                                        struct ieee80211_rx_status *rx_status)
 {
-       int energy_a, energy_b, energy_c, max_energy;
+       int energy_a, energy_b, max_energy;
 
        energy_a = desc->energy_a;
        energy_a = energy_a ? -energy_a : S8_MIN;
        energy_b = desc->energy_b;
        energy_b = energy_b ? -energy_b : S8_MIN;
-       energy_c = desc->energy_c;
-       energy_c = energy_c ? -energy_c : S8_MIN;
        max_energy = max(energy_a, energy_b);
-       max_energy = max(max_energy, energy_c);
 
-       IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n",
-                       energy_a, energy_b, energy_c, max_energy);
+       IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n",
+                       energy_a, energy_b, max_energy);
 
        rx_status->signal = max_energy;
        rx_status->chains = 0; /* TODO: phy info */
        rx_status->chain_signal[0] = energy_a;
        rx_status->chain_signal[1] = energy_b;
-       rx_status->chain_signal[2] = energy_c;
+       rx_status->chain_signal[2] = S8_MIN;
 }
 
 static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
@@ -288,13 +301,121 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
 
+/*
+ * returns true if a packet outside BA session is a duplicate and
+ * should be dropped
+ */
+static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
+                                 struct ieee80211_rx_status *rx_status,
+                                 struct ieee80211_hdr *hdr,
+                                 struct iwl_rx_mpdu_desc *desc)
+{
+       struct iwl_mvm_sta *mvm_sta;
+       struct iwl_mvm_rxq_dup_data *dup_data;
+       u8 baid, tid, sub_frame_idx;
+
+       if (WARN_ON(IS_ERR_OR_NULL(sta)))
+               return false;
+
+       baid = (le32_to_cpu(desc->reorder_data) &
+               IWL_RX_MPDU_REORDER_BAID_MASK) >>
+               IWL_RX_MPDU_REORDER_BAID_SHIFT;
+
+       if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
+               return false;
+
+       mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+       dup_data = &mvm_sta->dup_data[queue];
+
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (ieee80211_is_ctl(hdr->frame_control) ||
+           ieee80211_is_qos_nullfunc(hdr->frame_control) ||
+           is_multicast_ether_addr(hdr->addr1)) {
+               rx_status->flag |= RX_FLAG_DUP_VALIDATED;
+               return false;
+       }
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               /* frame has qos control */
+               tid = *ieee80211_get_qos_ctl(hdr) &
+                       IEEE80211_QOS_CTL_TID_MASK;
+       else
+               tid = IWL_MAX_TID_COUNT;
+
+       /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */
+       sub_frame_idx = desc->amsdu_info & IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
+
+       if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
+                    dup_data->last_seq[tid] == hdr->seq_ctrl &&
+                    dup_data->last_sub_frame[tid] >= sub_frame_idx))
+               return true;
+
+       dup_data->last_seq[tid] = hdr->seq_ctrl;
+       dup_data->last_sub_frame[tid] = sub_frame_idx;
+
+       rx_status->flag |= RX_FLAG_DUP_VALIDATED;
+
+       return false;
+}
+
+int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
+                           const u8 *data, u32 count)
+{
+       struct iwl_rxq_sync_cmd *cmd;
+       u32 data_size = sizeof(*cmd) + count;
+       int ret;
+
+       /* should be DWORD aligned */
+       if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE))
+               return -EINVAL;
+
+       cmd = kzalloc(data_size, GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->rxq_mask = cpu_to_le32(rxq_mask);
+       cmd->count =  cpu_to_le32(count);
+       cmd->flags = 0;
+       memcpy(cmd->payload, data, count);
+
+       ret = iwl_mvm_send_cmd_pdu(mvm,
+                                  WIDE_ID(DATA_PATH_GROUP,
+                                          TRIGGER_RX_QUEUES_NOTIF_CMD),
+                                  0, data_size, cmd);
+
+       kfree(cmd);
+       return ret;
+}
+
+void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
+                           int queue)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rxq_sync_notification *notif;
+       struct iwl_mvm_internal_rxq_notif *internal_notif;
+
+       notif = (void *)pkt->data;
+       internal_notif = (void *)notif->payload;
+
+       switch (internal_notif->type) {
+       case IWL_MVM_RXQ_NOTIF_DEL_BA:
+               /* TODO */
+               break;
+       default:
+               WARN_ONCE(1, "Invalid identifier %d", internal_notif->type);
+       }
+}
+
 void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                        struct iwl_rx_cmd_buffer *rxb, int queue)
 {
        struct ieee80211_rx_status *rx_status;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_rx_mpdu_desc *desc = (void *)pkt->data;
-       struct ieee80211_hdr *hdr = (void *)(desc + 1);
+       struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc));
        u32 len = le16_to_cpu(desc->mpdu_len);
        u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
        struct ieee80211_sta *sta = NULL;
@@ -335,6 +456,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
        rx_status->freq = ieee80211_channel_to_frequency(desc->channel,
                                                         rx_status->band);
        iwl_mvm_get_signal_strength(mvm, desc, rx_status);
+       /* TSF as indicated by the firmware is at INA time */
+       rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
 
        rcu_read_lock();
 
@@ -390,6 +513,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
 
                if (ieee80211_is_data(hdr->frame_control))
                        iwl_mvm_rx_csum(sta, skb, desc);
+
+               if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) {
+                       kfree_skb(skb);
+                       rcu_read_unlock();
+                       return;
+               }
        }
 
        /*
index 9a15642f80dd28b88dc4ae8326f465a7ec583e35..09eb72c4ae439206aefe2fd7d223bd5d8bea6a5a 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -297,6 +299,12 @@ void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                       iwl_mvm_dump_channel_list(notif->results,
                                                 notif->scanned_channels, buf,
                                                 sizeof(buf)));
+
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) {
+               IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n");
+               ieee80211_sched_scan_results(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
+       }
 }
 
 void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm,
@@ -380,6 +388,7 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
 
                mvm->scan_status &= ~IWL_MVM_SCAN_SCHED;
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
                IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
                               aborted ? "aborted" : "completed",
@@ -533,10 +542,13 @@ static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm,
                IWL_DEBUG_SCAN(mvm,
                               "Sending scheduled scan with filtering, n_match_sets %d\n",
                               req->n_match_sets);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
                return false;
        }
 
        IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n");
+
+       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
        return true;
 }
 
@@ -788,6 +800,9 @@ static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
                flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
 #endif
 
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+
        if (iwl_mvm_is_regular_scan(params) &&
            vif->type != NL80211_IFTYPE_P2P_DEVICE &&
            params->type != IWL_SCAN_TYPE_FRAGMENTED)
@@ -930,8 +945,11 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
        if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels))
                return -ENOBUFS;
 
-       if (type == mvm->scan_type)
+       if (type == mvm->scan_type) {
+               IWL_DEBUG_SCAN(mvm,
+                              "Ignoring UMAC scan config of the same type\n");
                return 0;
+       }
 
        cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels;
 
@@ -1071,6 +1089,9 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
                flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
 #endif
 
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED)
+               flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE;
+
        if (iwl_mvm_is_regular_scan(params) &&
            vif->type != NL80211_IFTYPE_P2P_DEVICE &&
            params->type != IWL_SCAN_TYPE_FRAGMENTED)
@@ -1109,7 +1130,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params,
                                                                 vif));
 
-       if (type == IWL_MVM_SCAN_SCHED)
+       if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
                cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
 
        if (iwl_mvm_scan_use_ebs(mvm, vif))
@@ -1351,7 +1372,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
 
        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
                hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0);
-               ret = iwl_mvm_scan_umac(mvm, vif, &params, IWL_MVM_SCAN_SCHED);
+               ret = iwl_mvm_scan_umac(mvm, vif, &params, type);
        } else {
                hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
                ret = iwl_mvm_scan_lmac(mvm, vif, &params);
@@ -1393,6 +1414,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        }
 
        mvm->scan_status &= ~mvm->scan_uid_status[uid];
@@ -1427,6 +1449,12 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm,
                       iwl_mvm_dump_channel_list(notif->results,
                                                 notif->scanned_channels, buf,
                                                 sizeof(buf)));
+
+       if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_FOUND) {
+               IWL_DEBUG_SCAN(mvm, "Pass all scheduled scan results found\n");
+               ieee80211_sched_scan_results(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_ENABLED;
+       }
 }
 
 static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type)
@@ -1521,6 +1549,7 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
                if (uid >= 0 && !mvm->restart_fw) {
                        ieee80211_sched_scan_stopped(mvm->hw);
+                       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
                        mvm->scan_uid_status[uid] = 0;
                }
 
@@ -1542,8 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
                 * restart_hw, so do not report if FW is about to be
                 * restarted.
                 */
-               if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) && !mvm->restart_fw)
+               if ((mvm->scan_status & IWL_MVM_SCAN_SCHED) &&
+                   !mvm->restart_fw) {
                        ieee80211_sched_scan_stopped(mvm->hw);
+                       mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
+               }
        }
 }
 
@@ -1579,6 +1611,7 @@ out:
                        ieee80211_scan_completed(mvm->hw, true);
        } else if (notify) {
                ieee80211_sched_scan_stopped(mvm->hw);
+               mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
        }
 
        return ret;
index b556e33658d734974d8534b271cf5e57ea755be3..ef99942d71696b48163c83081d8e8c6944fd51c3 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "sta.h"
 #include "rs.h"
 
+/*
+ * New version of ADD_STA_sta command added new fields at the end of the
+ * structure, so sending the size of the relevant API's structure is enough to
+ * support both API versions.
+ */
+static inline int iwl_mvm_add_sta_cmd_size(struct iwl_mvm *mvm)
+{
+       return iwl_mvm_has_new_rx_api(mvm) ?
+               sizeof(struct iwl_mvm_add_sta_cmd) :
+               sizeof(struct iwl_mvm_add_sta_cmd_v7);
+}
+
 static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
                                    enum nl80211_iftype iftype)
 {
@@ -187,12 +201,13 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &add_sta_cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n");
                break;
@@ -265,6 +280,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+       struct iwl_mvm_rxq_dup_data *dup_data;
        int i, ret, sta_id;
 
        lockdep_assert_held(&mvm->mutex);
@@ -312,6 +328,16 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
        }
        mvm_sta->agg_tids = 0;
 
+       if (iwl_mvm_has_new_rx_api(mvm) &&
+           !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+               dup_data = kcalloc(mvm->trans->num_rx_queues,
+                                  sizeof(*dup_data),
+                                  GFP_KERNEL);
+               if (!dup_data)
+                       return -ENOMEM;
+               mvm_sta->dup_data = dup_data;
+       }
+
        ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
        if (ret)
                goto err;
@@ -357,12 +383,13 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
        cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n",
                               mvmsta->sta_id);
@@ -492,6 +519,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (iwl_mvm_has_new_rx_api(mvm))
+               kfree(mvm_sta->dup_data);
+
        if (vif->type == NL80211_IFTYPE_STATION &&
            mvmvif->ap_sta_id == mvm_sta->sta_id) {
                ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
@@ -623,12 +653,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
        if (addr)
                memcpy(cmd.addr, addr, ETH_ALEN);
 
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "Internal station added.\n");
                return 0;
@@ -819,7 +850,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 #define IWL_MAX_RX_BA_SESSIONS 16
 
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                      int tid, u16 ssn, bool start)
+                      int tid, u16 ssn, bool start, u8 buf_size)
 {
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_add_sta_cmd cmd = {};
@@ -839,6 +870,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (start) {
                cmd.add_immediate_ba_tid = (u8) tid;
                cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+               cmd.rx_ba_window = cpu_to_le16((u16)buf_size);
        } else {
                cmd.remove_immediate_ba_tid = (u8) tid;
        }
@@ -846,12 +878,13 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                  STA_MODIFY_REMOVE_BA_TID;
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
                               start ? "start" : "stopp");
@@ -904,12 +937,13 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                break;
        default:
@@ -1011,15 +1045,23 @@ release_locks:
 }
 
 int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                           struct ieee80211_sta *sta, u16 tid, u8 buf_size)
+                           struct ieee80211_sta *sta, u16 tid, u8 buf_size,
+                           bool amsdu)
 {
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
        unsigned int wdg_timeout =
                iwl_mvm_get_wd_timeout(mvm, vif, sta->tdls, false);
-       int queue, fifo, ret;
+       int queue, ret;
        u16 ssn;
 
+       struct iwl_trans_txq_scd_cfg cfg = {
+               .sta_id = mvmsta->sta_id,
+               .tid = tid,
+               .frame_limit = buf_size,
+               .aggregate = true,
+       };
+
        BUILD_BUG_ON((sizeof(mvmsta->agg_tids) * BITS_PER_BYTE)
                     != IWL_MAX_TID_COUNT);
 
@@ -1031,13 +1073,13 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        tid_data->state = IWL_AGG_ON;
        mvmsta->agg_tids |= BIT(tid);
        tid_data->ssn = 0xffff;
+       tid_data->amsdu_in_ampdu_allowed = amsdu;
        spin_unlock_bh(&mvmsta->lock);
 
-       fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+       cfg.fifo = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
 
-       iwl_mvm_enable_agg_txq(mvm, queue,
-                              vif->hw_queue[tid_to_mac80211_ac[tid]], fifo,
-                              mvmsta->sta_id, tid, buf_size, ssn, wdg_timeout);
+       iwl_mvm_enable_txq(mvm, queue, vif->hw_queue[tid_to_mac80211_ac[tid]],
+                          ssn, &cfg, wdg_timeout);
 
        ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
        if (ret)
@@ -1640,7 +1682,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
        };
        int ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
@@ -1731,7 +1774,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
 
        ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA,
                                   CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK,
-                                  sizeof(cmd), &cmd);
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
@@ -1766,7 +1809,8 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
        };
        int ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
index 39fdf5224e81741aacccec2f43f4783dd65b78fb..1a8f69a41405da4625b83d9d193e0fba4d09dae4 100644 (file)
@@ -258,8 +258,7 @@ enum iwl_mvm_agg_state {
  *     This is basically (last acked packet++).
  * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
  *     Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
- * @reduced_tpc: Reduced tx power. Holds the data between the
- *     Tx response (TX_CMD), and the block ack notification (COMPRESSED_BA).
+ * @amsdu_in_ampdu_allowed: true if A-MSDU in A-MPDU is allowed.
  * @state: state of the BA agreement establishment / tear down.
  * @txq_id: Tx queue used by the BA session
  * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
@@ -273,7 +272,7 @@ struct iwl_mvm_tid_data {
        u16 next_reclaimed;
        /* The rest is Tx AGG related */
        u32 rate_n_flags;
-       u8 reduced_tpc;
+       bool amsdu_in_ampdu_allowed;
        enum iwl_mvm_agg_state state;
        u16 txq_id;
        u16 ssn;
@@ -293,6 +292,16 @@ struct iwl_mvm_key_pn {
        } ____cacheline_aligned_in_smp q[];
 };
 
+/**
+ * struct iwl_mvm_rxq_dup_data - per station per rx queue data
+ * @last_seq: last sequence per tid for duplicate packet detection
+ * @last_sub_frame: last subframe packet
+ */
+struct iwl_mvm_rxq_dup_data {
+       __le16 last_seq[IWL_MAX_TID_COUNT + 1];
+       u8 last_sub_frame[IWL_MAX_TID_COUNT + 1];
+} ____cacheline_aligned_in_smp;
+
 /**
  * struct iwl_mvm_sta - representation of a station in the driver
  * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
@@ -311,6 +320,7 @@ struct iwl_mvm_key_pn {
  * @tx_protection: reference counter for controlling the Tx protection.
  * @tt_tx_protection: is thermal throttling enable Tx protection?
  * @disable_tx: is tx to this STA disabled?
+ * @tlc_amsdu: true if A-MSDU is allowed
  * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
  * @sleep_tx_count: the number of frames that we told the firmware to let out
  *     even when that station is asleep. This is useful in case the queue
@@ -318,6 +328,7 @@ struct iwl_mvm_key_pn {
  *     we are sending frames from an AMPDU queue and there was a hole in
  *     the BA window. To be used for UAPSD only.
  * @ptk_pn: per-queue PTK PN data structures
+ * @dup_data: per queue duplicate packet detection data
  *
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is placed in that
@@ -337,14 +348,15 @@ struct iwl_mvm_sta {
        struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
        struct iwl_lq_sta lq_sta;
        struct ieee80211_vif *vif;
-
        struct iwl_mvm_key_pn __rcu *ptk_pn[4];
+       struct iwl_mvm_rxq_dup_data *dup_data;
 
        /* Temporary, until the new TLC will control the Tx protection */
        s8 tx_protection;
        bool tt_tx_protection;
 
        bool disable_tx;
+       bool tlc_amsdu;
        u8 agg_tids;
        u8 sleep_tx_count;
 };
@@ -401,11 +413,12 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
 
 /* AMPDU */
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                      int tid, u16 ssn, bool start);
+                      int tid, u16 ssn, bool start, u8 buf_size);
 int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                       struct ieee80211_sta *sta, u16 tid, u8 buf_size);
+                           struct ieee80211_sta *sta, u16 tid, u8 buf_size,
+                           bool amsdu);
 int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, u16 tid);
 int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
index fb76004eede4c4f29cc5835e90d1cfbe8262247b..999bcb898be884e9ff30b317b3aba1d7d2a108b0 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,6 +65,8 @@
  *
  *****************************************************************************/
 
+#include <linux/sort.h>
+
 #include "mvm.h"
 
 #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT        HZ
@@ -79,8 +82,10 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
        IWL_ERR(mvm, "Enter CT Kill\n");
        iwl_mvm_set_hw_ctkill_state(mvm, true);
 
-       tt->throttle = false;
-       tt->dynamic_smps = false;
+       if (!iwl_mvm_is_tt_in_fw(mvm)) {
+               tt->throttle = false;
+               tt->dynamic_smps = false;
+       }
 
        /* Don't schedule an exit work if we're in test mode, since
         * the temperature will not change unless we manually set it
@@ -116,18 +121,21 @@ void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp)
 static int iwl_mvm_temp_notif_parse(struct iwl_mvm *mvm,
                                    struct iwl_rx_packet *pkt)
 {
-       struct iwl_dts_measurement_notif *notif;
+       struct iwl_dts_measurement_notif_v1 *notif_v1;
        int len = iwl_rx_packet_payload_len(pkt);
        int temp;
 
-       if (WARN_ON_ONCE(len < sizeof(*notif))) {
+       /* we can use notif_v1 only, because v2 only adds an additional
+        * parameter, which is not used in this function.
+       */
+       if (WARN_ON_ONCE(len < sizeof(*notif_v1))) {
                IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
                return -EINVAL;
        }
 
-       notif = (void *)pkt->data;
+       notif_v1 = (void *)pkt->data;
 
-       temp = le32_to_cpu(notif->temp);
+       temp = le32_to_cpu(notif_v1->temp);
 
        /* shouldn't be negative, but since it's s32, make sure it isn't */
        if (WARN_ON_ONCE(temp < 0))
@@ -158,17 +166,74 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait,
 void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_dts_measurement_notif_v2 *notif_v2;
+       int len = iwl_rx_packet_payload_len(pkt);
        int temp;
+       u32 ths_crossed;
 
        /* the notification is handled synchronously in ctkill, so skip here */
        if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
                return;
 
        temp = iwl_mvm_temp_notif_parse(mvm, pkt);
-       if (temp < 0)
+
+       if (!iwl_mvm_is_tt_in_fw(mvm)) {
+               if (temp >= 0)
+                       iwl_mvm_tt_temp_changed(mvm, temp);
                return;
+       }
+
+       if (WARN_ON_ONCE(len < sizeof(*notif_v2))) {
+               IWL_ERR(mvm, "Invalid DTS_MEASUREMENT_NOTIFICATION\n");
+               return;
+       }
+
+       notif_v2 = (void *)pkt->data;
+       ths_crossed = le32_to_cpu(notif_v2->threshold_idx);
 
-       iwl_mvm_tt_temp_changed(mvm, temp);
+       /* 0xFF in ths_crossed means the notification is not related
+        * to a trip, so we can ignore it here.
+        */
+       if (ths_crossed == 0xFF)
+               return;
+
+       IWL_DEBUG_TEMP(mvm, "Temp = %d Threshold crossed = %d\n",
+                      temp, ths_crossed);
+
+#ifdef CONFIG_THERMAL
+       if (WARN_ON(ths_crossed >= IWL_MAX_DTS_TRIPS))
+               return;
+
+       /*
+        * We are now handling a temperature notification from the firmware
+        * in ASYNC and hold the mutex. thermal_notify_framework will call
+        * us back through get_temp() which ought to send a SYNC command to
+        * the firmware and hence to take the mutex.
+        * Avoid the deadlock by unlocking the mutex here.
+        */
+       mutex_unlock(&mvm->mutex);
+       thermal_notify_framework(mvm->tz_device.tzone,
+                                mvm->tz_device.fw_trips_index[ths_crossed]);
+       mutex_lock(&mvm->mutex);
+#endif /* CONFIG_THERMAL */
+}
+
+void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct ct_kill_notif *notif;
+       int len = iwl_rx_packet_payload_len(pkt);
+
+       if (WARN_ON_ONCE(len != sizeof(*notif))) {
+               IWL_ERR(mvm, "Invalid CT_KILL_NOTIFICATION\n");
+               return;
+       }
+
+       notif = (struct ct_kill_notif *)pkt->data;
+       IWL_DEBUG_TEMP(mvm, "CT Kill notification temperature = %d\n",
+                      notif->temperature);
+
+       iwl_mvm_enter_ctkill(mvm);
 }
 
 static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
@@ -194,12 +259,12 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
        return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
 }
 
-int iwl_mvm_get_temp(struct iwl_mvm *mvm)
+int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp)
 {
        struct iwl_notification_wait wait_temp_notif;
        static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
                                            DTS_MEASUREMENT_NOTIF_WIDE) };
-       int ret, temp;
+       int ret;
 
        if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
                temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION;
@@ -208,7 +273,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm)
 
        iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
                                   temp_notif, ARRAY_SIZE(temp_notif),
-                                  iwl_mvm_temp_notif_wait, &temp);
+                                  iwl_mvm_temp_notif_wait, temp);
 
        ret = iwl_mvm_get_temp_cmd(mvm);
        if (ret) {
@@ -219,12 +284,10 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm)
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
                                    IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
-       if (ret) {
+       if (ret)
                IWL_ERR(mvm, "Getting the temperature timed out\n");
-               return ret;
-       }
 
-       return temp;
+       return ret;
 }
 
 static void check_exit_ctkill(struct work_struct *work)
@@ -233,10 +296,17 @@ static void check_exit_ctkill(struct work_struct *work)
        struct iwl_mvm *mvm;
        u32 duration;
        s32 temp;
+       int ret;
 
        tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
        mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
 
+       if (iwl_mvm_is_tt_in_fw(mvm)) {
+               iwl_mvm_exit_ctkill(mvm);
+
+               return;
+       }
+
        duration = tt->params.ct_kill_duration;
 
        mutex_lock(&mvm->mutex);
@@ -250,13 +320,13 @@ static void check_exit_ctkill(struct work_struct *work)
                goto reschedule;
        }
 
-       temp = iwl_mvm_get_temp(mvm);
+       ret = iwl_mvm_get_temp(mvm, &temp);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
 
        __iwl_mvm_mac_stop(mvm);
 
-       if (temp < 0)
+       if (ret)
                goto reschedule;
 
        IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
@@ -436,7 +506,365 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = {
        .support_tx_backoff = true,
 };
 
-void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
+#ifdef CONFIG_THERMAL
+static int compare_temps(const void *a, const void *b)
+{
+       return ((s16)le16_to_cpu(*(__le16 *)a) -
+               (s16)le16_to_cpu(*(__le16 *)b));
+}
+
+int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
+{
+       struct temp_report_ths_cmd cmd = {0};
+       int ret, i, j, idx = 0;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       /* The driver holds array of temperature trips that are unsorted
+        * and uncompressed, the FW should get it compressed and sorted
+        */
+
+       /* compress temp_trips to cmd array, remove uninitialized values*/
+       for (i = 0; i < IWL_MAX_DTS_TRIPS; i++)
+               if (mvm->tz_device.temp_trips[i] != S16_MIN) {
+                       cmd.thresholds[idx++] =
+                               cpu_to_le16(mvm->tz_device.temp_trips[i]);
+               }
+       cmd.num_temps = cpu_to_le32(idx);
+
+       if (!idx)
+               goto send;
+
+       /*sort cmd array*/
+       sort(cmd.thresholds, idx, sizeof(s16), compare_temps, NULL);
+
+       /* we should save the indexes of trips because we sort
+        * and compress the orginal array
+        */
+       for (i = 0; i < idx; i++) {
+               for (j = 0; j < IWL_MAX_DTS_TRIPS; j++) {
+                       if (le16_to_cpu(cmd.thresholds[i]) ==
+                               mvm->tz_device.temp_trips[j])
+                               mvm->tz_device.fw_trips_index[i] = j;
+               }
+       }
+
+send:
+       ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
+                                               TEMP_REPORTING_THRESHOLDS_CMD),
+                                  0, sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERR(mvm, "TEMP_REPORT_THS_CMD command failed (err=%d)\n",
+                       ret);
+
+       return ret;
+}
+
+static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device,
+                                 int *temperature)
+{
+       struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
+       int ret;
+       int temp;
+
+       mutex_lock(&mvm->mutex);
+
+       if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       ret = iwl_mvm_get_temp(mvm, &temp);
+       if (ret)
+               goto out;
+
+       *temperature = temp * 1000;
+
+out:
+       mutex_unlock(&mvm->mutex);
+       return ret;
+}
+
+static int iwl_mvm_tzone_get_trip_temp(struct thermal_zone_device *device,
+                                      int trip, int *temp)
+{
+       struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
+
+       if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
+               return -EINVAL;
+
+       *temp = mvm->tz_device.temp_trips[trip] * 1000;
+
+       return 0;
+}
+
+static int iwl_mvm_tzone_get_trip_type(struct thermal_zone_device *device,
+                                      int trip, enum thermal_trip_type *type)
+{
+       if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS)
+               return -EINVAL;
+
+       *type = THERMAL_TRIP_PASSIVE;
+
+       return 0;
+}
+
+static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device,
+                                      int trip, int temp)
+{
+       struct iwl_mvm *mvm = (struct iwl_mvm *)device->devdata;
+       struct iwl_mvm_thermal_device *tzone;
+       int i, ret;
+       s16 temperature;
+
+       mutex_lock(&mvm->mutex);
+
+       if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       if (trip < 0 || trip >= IWL_MAX_DTS_TRIPS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if ((temp / 1000) > S16_MAX) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       temperature = (s16)(temp / 1000);
+       tzone = &mvm->tz_device;
+
+       if (!tzone) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* no updates*/
+       if (tzone->temp_trips[trip] == temperature) {
+               ret = 0;
+               goto out;
+       }
+
+       /* already existing temperature */
+       for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
+               if (tzone->temp_trips[i] == temperature) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       tzone->temp_trips[trip] = temperature;
+
+       ret = iwl_mvm_send_temp_report_ths_cmd(mvm);
+out:
+       mutex_unlock(&mvm->mutex);
+       return ret;
+}
+
+static  struct thermal_zone_device_ops tzone_ops = {
+       .get_temp = iwl_mvm_tzone_get_temp,
+       .get_trip_temp = iwl_mvm_tzone_get_trip_temp,
+       .get_trip_type = iwl_mvm_tzone_get_trip_type,
+       .set_trip_temp = iwl_mvm_tzone_set_trip_temp,
+};
+
+/* make all trips writable */
+#define IWL_WRITABLE_TRIPS_MSK (BIT(IWL_MAX_DTS_TRIPS) - 1)
+
+static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
+{
+       int i;
+       char name[] = "iwlwifi";
+
+       if (!iwl_mvm_is_tt_in_fw(mvm)) {
+               mvm->tz_device.tzone = NULL;
+
+               return;
+       }
+
+       BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
+
+       mvm->tz_device.tzone = thermal_zone_device_register(name,
+                                                       IWL_MAX_DTS_TRIPS,
+                                                       IWL_WRITABLE_TRIPS_MSK,
+                                                       mvm, &tzone_ops,
+                                                       NULL, 0, 0);
+       if (IS_ERR(mvm->tz_device.tzone)) {
+               IWL_DEBUG_TEMP(mvm,
+                              "Failed to register to thermal zone (err = %ld)\n",
+                              PTR_ERR(mvm->tz_device.tzone));
+               return;
+       }
+
+       /* 0 is a valid temperature,
+        * so initialize the array with S16_MIN which invalid temperature
+        */
+       for (i = 0 ; i < IWL_MAX_DTS_TRIPS; i++)
+               mvm->tz_device.temp_trips[i] = S16_MIN;
+}
+
+static const u32 iwl_mvm_cdev_budgets[] = {
+       2000,   /* cooling state 0 */
+       1800,   /* cooling state 1 */
+       1600,   /* cooling state 2 */
+       1400,   /* cooling state 3 */
+       1200,   /* cooling state 4 */
+       1000,   /* cooling state 5 */
+       900,    /* cooling state 6 */
+       800,    /* cooling state 7 */
+       700,    /* cooling state 8 */
+       650,    /* cooling state 9 */
+       600,    /* cooling state 10 */
+       550,    /* cooling state 11 */
+       500,    /* cooling state 12 */
+       450,    /* cooling state 13 */
+       400,    /* cooling state 14 */
+       350,    /* cooling state 15 */
+       300,    /* cooling state 16 */
+       250,    /* cooling state 17 */
+       200,    /* cooling state 18 */
+       150,    /* cooling state 19 */
+};
+
+int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
+{
+       struct iwl_mvm_ctdp_cmd cmd = {
+               .operation = cpu_to_le32(op),
+               .budget = cpu_to_le32(budget),
+               .window_size = 0,
+       };
+       int ret;
+       u32 status;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, WIDE_ID(PHY_OPS_GROUP,
+                                                      CTDP_CONFIG_CMD),
+                                         sizeof(cmd), &cmd, &status);
+
+       if (ret) {
+               IWL_ERR(mvm, "cTDP command failed (err=%d)\n", ret);
+               return ret;
+       }
+
+       if (op == CTDP_CMD_OPERATION_START)
+               mvm->cooling_dev.cur_state = budget;
+
+       else if (op == CTDP_CMD_OPERATION_REPORT)
+               IWL_DEBUG_TEMP(mvm, "cTDP avg energy in mWatt = %d\n", status);
+
+       return 0;
+}
+
+static int iwl_mvm_tcool_get_max_state(struct thermal_cooling_device *cdev,
+                                      unsigned long *state)
+{
+       *state = ARRAY_SIZE(iwl_mvm_cdev_budgets) - 1;
+
+       return 0;
+}
+
+static int iwl_mvm_tcool_get_cur_state(struct thermal_cooling_device *cdev,
+                                      unsigned long *state)
+{
+       struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
+
+       if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
+               return -EBUSY;
+
+       *state = mvm->cooling_dev.cur_state;
+       return 0;
+}
+
+static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev,
+                                      unsigned long new_state)
+{
+       struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
+       int ret;
+
+       if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR))
+               return -EIO;
+
+       if (test_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status))
+               return -EBUSY;
+
+       mutex_lock(&mvm->mutex);
+
+       if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
+               ret = -EINVAL;
+               goto unlock;
+       }
+
+       ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START,
+                                  iwl_mvm_cdev_budgets[new_state]);
+
+unlock:
+       mutex_unlock(&mvm->mutex);
+       return ret;
+}
+
+static struct thermal_cooling_device_ops tcooling_ops = {
+       .get_max_state = iwl_mvm_tcool_get_max_state,
+       .get_cur_state = iwl_mvm_tcool_get_cur_state,
+       .set_cur_state = iwl_mvm_tcool_set_cur_state,
+};
+
+int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
+{
+       char name[] = "iwlwifi";
+
+       if (!iwl_mvm_is_ctdp_supported(mvm)) {
+               mvm->cooling_dev.cdev = NULL;
+
+               return 0;
+       }
+
+       BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
+
+       mvm->cooling_dev.cdev =
+               thermal_cooling_device_register(name,
+                                               mvm,
+                                               &tcooling_ops);
+
+       if (IS_ERR(mvm->cooling_dev.cdev)) {
+               IWL_DEBUG_TEMP(mvm,
+                              "Failed to register to cooling device (err = %ld)\n",
+                              PTR_ERR(mvm->cooling_dev.cdev));
+               return PTR_ERR(mvm->cooling_dev.cdev);
+       }
+
+       return 0;
+}
+
+static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
+{
+       if (!iwl_mvm_is_tt_in_fw(mvm))
+               return;
+
+       if (mvm->tz_device.tzone) {
+               IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
+               thermal_zone_device_unregister(mvm->tz_device.tzone);
+               mvm->tz_device.tzone = NULL;
+       }
+}
+
+static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
+{
+       if (!iwl_mvm_is_ctdp_supported(mvm))
+               return;
+
+       if (mvm->cooling_dev.cdev) {
+               IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
+               thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
+               mvm->cooling_dev.cdev = NULL;
+       }
+}
+#endif /* CONFIG_THERMAL */
+
+void iwl_mvm_thermal_initialize(struct iwl_mvm *mvm, u32 min_backoff)
 {
        struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
 
@@ -451,10 +879,20 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
        tt->dynamic_smps = false;
        tt->min_backoff = min_backoff;
        INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
+
+#ifdef CONFIG_THERMAL
+       iwl_mvm_cooling_device_register(mvm);
+       iwl_mvm_thermal_zone_register(mvm);
+#endif
 }
 
-void iwl_mvm_tt_exit(struct iwl_mvm *mvm)
+void iwl_mvm_thermal_exit(struct iwl_mvm *mvm)
 {
        cancel_delayed_work_sync(&mvm->thermal_throttle.ct_kill_exit);
        IWL_DEBUG_TEMP(mvm, "Exit Thermal Throttling\n");
+
+#ifdef CONFIG_THERMAL
+       iwl_mvm_cooling_device_unregister(mvm);
+       iwl_mvm_thermal_zone_unregister(mvm);
+#endif
 }
index 0914ec2fd57467023b0f5336b2e630856c06cf81..271e8da6d1409ac1cfcbfa736b1296ab905a9fbd 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/ieee80211.h>
 #include <linux/etherdevice.h>
 #include <linux/tcp.h>
+#include <net/ip.h>
 
 #include "iwl-trans.h"
 #include "iwl-eeprom-parse.h"
@@ -182,7 +183,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
 
        tx_cmd->tx_flags = cpu_to_le32(tx_flags);
        /* Total # bytes to be transmitted */
-       tx_cmd->len = cpu_to_le16((u16)skb->len);
+       tx_cmd->len = cpu_to_le16((u16)skb->len +
+               (uintptr_t)info->driver_data[0]);
        tx_cmd->next_frame_len = 0;
        tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
        tx_cmd->sta_id = sta_id;
@@ -299,6 +301,8 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
 
        case WLAN_CIPHER_SUITE_TKIP:
                tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+               pn = atomic64_inc_return(&keyconf->tx_pn);
+               ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn);
                ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
                break;
 
@@ -370,6 +374,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
                          info->hw_queue != info->control.vif->cab_queue)))
                return -1;
 
+       /* This holds the amsdu headers length */
+       info->driver_data[0] = (void *)(uintptr_t)0;
+
        /*
         * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets that can be used
         * in 2 different types of vifs, P2P & STATION. P2P uses the offchannel
@@ -423,36 +430,206 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
                return -1;
        }
 
+       /*
+        * Increase the pending frames counter, so that later when a reply comes
+        * in and the counter is decreased - we don't start getting negative
+        * values.
+        * Note that we don't need to make sure it isn't agg'd, since we're
+        * TXing non-sta
+        */
+       atomic_inc(&mvm->pending_frames[sta_id]);
+
        return 0;
 }
 
-static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb_gso,
+#ifdef CONFIG_INET
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
                          struct ieee80211_sta *sta,
                          struct sk_buff_head *mpdus_skb)
 {
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       unsigned int mss = skb_shinfo(skb)->gso_size;
        struct sk_buff *tmp, *next;
-       char cb[sizeof(skb_gso->cb)];
+       char cb[sizeof(skb->cb)];
+       unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
+       bool ipv4 = (skb->protocol == htons(ETH_P_IP));
+       u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
+       u16 amsdu_add, snap_ip_tcp, pad, i = 0;
+       unsigned int dbg_max_amsdu_len;
+       u8 *qc, tid, txf;
+
+       snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
+               tcp_hdrlen(skb);
+
+       qc = ieee80211_get_qos_ctl(hdr);
+       tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+       if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+               return -EINVAL;
+
+       if (!sta->max_amsdu_len ||
+           !ieee80211_is_data_qos(hdr->frame_control) ||
+           !mvmsta->tlc_amsdu) {
+               num_subframes = 1;
+               pad = 0;
+               goto segment;
+       }
+
+       /*
+        * No need to lock amsdu_in_ampdu_allowed since it can't be modified
+        * during an BA session.
+        */
+       if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+           !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) {
+               num_subframes = 1;
+               pad = 0;
+               goto segment;
+       }
+
+       max_amsdu_len = sta->max_amsdu_len;
+       dbg_max_amsdu_len = ACCESS_ONCE(mvm->max_amsdu_len);
+
+       /* the Tx FIFO to which this A-MSDU will be routed */
+       txf = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]];
+
+       /*
+        * Don't send an AMSDU that will be longer than the TXF.
+        * Add a security margin of 256 for the TX command + headers.
+        * We also want to have the start of the next packet inside the
+        * fifo to be able to send bursts.
+        */
+       max_amsdu_len = min_t(unsigned int, max_amsdu_len,
+                             mvm->shared_mem_cfg.txfifo_size[txf] - 256);
+
+       if (dbg_max_amsdu_len)
+               max_amsdu_len = min_t(unsigned int, max_amsdu_len,
+                                     dbg_max_amsdu_len);
+
+       /*
+        * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
+        * supported. This is a spec requirement (IEEE 802.11-2015
+        * section 8.7.3 NOTE 3).
+        */
+       if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+           !sta->vht_cap.vht_supported)
+               max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095);
+
+       /* Sub frame header + SNAP + IP header + TCP header + MSS */
+       subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss;
+       pad = (4 - subf_len) & 0x3;
+
+       /*
+        * If we have N subframes in the A-MSDU, then the A-MSDU's size is
+        * N * subf_len + (N - 1) * pad.
+        */
+       num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
+       if (num_subframes > 1)
+               *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+
+       tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
+               tcp_hdrlen(skb) + skb->data_len;
+
+       /*
+        * Make sure we have enough TBs for the A-MSDU:
+        *      2 for each subframe
+        *      1 more for each fragment
+        *      1 more for the potential data in the header
+        */
+       num_subframes =
+               min_t(unsigned int, num_subframes,
+                     (mvm->trans->max_skb_frags - 1 -
+                      skb_shinfo(skb)->nr_frags) / 2);
+
+       /* This skb fits in one single A-MSDU */
+       if (num_subframes * mss >= tcp_payload_len) {
+               /*
+                * Compute the length of all the data added for the A-MSDU.
+                * This will be used to compute the length to write in the TX
+                * command. We have: SNAP + IP + TCP for n -1 subframes and
+                * ETH header for n subframes. Note that the original skb
+                * already had one set of SNAP / IP / TCP headers.
+                */
+               num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
+               info = IEEE80211_SKB_CB(skb);
+               amsdu_add = num_subframes * sizeof(struct ethhdr) +
+                       (num_subframes - 1) * (snap_ip_tcp + pad);
+               /* This holds the amsdu headers length */
+               info->driver_data[0] = (void *)(uintptr_t)amsdu_add;
+
+               __skb_queue_tail(mpdus_skb, skb);
+               return 0;
+       }
+
+       /*
+        * Trick the segmentation function to make it
+        * create SKBs that can fit into one A-MSDU.
+        */
+segment:
+       skb_shinfo(skb)->gso_size = num_subframes * mss;
+       memcpy(cb, skb->cb, sizeof(cb));
 
-       memcpy(cb, skb_gso->cb, sizeof(cb));
-       next = skb_gso_segment(skb_gso, 0);
-       if (IS_ERR(next))
+       next = skb_gso_segment(skb, NETIF_F_CSUM_MASK | NETIF_F_SG);
+       skb_shinfo(skb)->gso_size = mss;
+       if (WARN_ON_ONCE(IS_ERR(next)))
                return -EINVAL;
        else if (next)
-               consume_skb(skb_gso);
+               consume_skb(skb);
 
        while (next) {
                tmp = next;
                next = tmp->next;
+
                memcpy(tmp->cb, cb, sizeof(tmp->cb));
+               /*
+                * Compute the length of all the data added for the A-MSDU.
+                * This will be used to compute the length to write in the TX
+                * command. We have: SNAP + IP + TCP for n -1 subframes and
+                * ETH header for n subframes.
+                */
+               tcp_payload_len = skb_tail_pointer(tmp) -
+                       skb_transport_header(tmp) -
+                       tcp_hdrlen(tmp) + tmp->data_len;
+
+               if (ipv4)
+                       ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
+
+               if (tcp_payload_len > mss) {
+                       num_subframes = DIV_ROUND_UP(tcp_payload_len, mss);
+                       info = IEEE80211_SKB_CB(tmp);
+                       amsdu_add = num_subframes * sizeof(struct ethhdr) +
+                               (num_subframes - 1) * (snap_ip_tcp + pad);
+                       info->driver_data[0] = (void *)(uintptr_t)amsdu_add;
+                       skb_shinfo(tmp)->gso_size = mss;
+               } else {
+                       qc = ieee80211_get_qos_ctl((void *)tmp->data);
+
+                       if (ipv4)
+                               ip_send_check(ip_hdr(tmp));
+                       *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+                       skb_shinfo(tmp)->gso_size = 0;
+               }
 
                tmp->prev = NULL;
                tmp->next = NULL;
 
                __skb_queue_tail(mpdus_skb, tmp);
+               i++;
        }
 
        return 0;
 }
+#else /* CONFIG_INET */
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
+                         struct ieee80211_sta *sta,
+                         struct sk_buff_head *mpdus_skb)
+{
+       /* Impossible to get TSO with CONFIG_INET */
+       WARN_ON(1);
+
+       return -1;
+}
+#endif
 
 /*
  * Sets the fields in the Tx cmd that are crypto related
@@ -558,6 +735,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
                   struct ieee80211_sta *sta)
 {
        struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct sk_buff_head mpdus_skbs;
        unsigned int payload_len;
        int ret;
@@ -568,6 +746,9 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
        if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
                return -1;
 
+       /* This holds the amsdu headers length */
+       info->driver_data[0] = (void *)(uintptr_t)0;
+
        if (!skb_is_gso(skb))
                return iwl_mvm_tx_mpdu(mvm, skb, sta);
 
@@ -587,7 +768,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
                return ret;
 
        while (!skb_queue_empty(&mpdus_skbs)) {
-               struct sk_buff *skb = __skb_dequeue(&mpdus_skbs);
+               skb = __skb_dequeue(&mpdus_skbs);
 
                ret = iwl_mvm_tx_mpdu(mvm, skb, sta);
                if (ret) {
@@ -736,6 +917,37 @@ static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags,
        iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
 }
 
+static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
+                                           u32 status)
+{
+       struct iwl_fw_dbg_trigger_tlv *trig;
+       struct iwl_fw_dbg_trigger_tx_status *status_trig;
+       int i;
+
+       if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS))
+               return;
+
+       trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS);
+       status_trig = (void *)trig->data;
+
+       if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
+               /* don't collect on status 0 */
+               if (!status_trig->statuses[i].status)
+                       break;
+
+               if (status_trig->statuses[i].status != (status & TX_STATUS_MSK))
+                       continue;
+
+               iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+                                           "Tx status %d was received",
+                                           status & TX_STATUS_MSK);
+               break;
+       }
+}
+
 static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                                     struct iwl_rx_packet *pkt)
 {
@@ -784,6 +996,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        break;
                }
 
+               iwl_mvm_tx_status_check_trigger(mvm, status);
+
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
                                            info);
index 3a989f5c20db2b1a360361be970a97266f52ad25..59453c17658086ac757e2124f46cacfc842c4500 100644 (file)
@@ -937,18 +937,16 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
 }
 
 int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                              bool value)
+                              bool prev)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int res;
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvmvif->low_latency == value)
+       if (iwl_mvm_vif_low_latency(mvmvif) == prev)
                return 0;
 
-       mvmvif->low_latency = value;
-
        res = iwl_mvm_update_quotas(mvm, false, NULL);
        if (res)
                return res;
index 00335ea6b3eb5fa6035a2ce06e9fcfb0ea612ac7..d33b6baf5f9872156707c27cee8e2a8755160974 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -66,6 +67,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/pci-aspm.h>
 #include <linux/acpi.h>
@@ -627,6 +629,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto out_free_drv;
 
+       /* if RTPM is in use, enable it in our device */
+       if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_set_autosuspend_delay(&pdev->dev,
+                                        iwlwifi_mod_params.d0i3_entry_delay);
+               pm_runtime_use_autosuspend(&pdev->dev);
+               pm_runtime_allow(&pdev->dev);
+       }
+
        return 0;
 
 out_free_drv:
@@ -693,15 +704,173 @@ static int iwl_pci_resume(struct device *device)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+
+       if (test_bit(STATUS_FW_ERROR, &trans->status))
+               return 0;
+
+       set_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+       /* config the fw */
+       ret = iwl_op_mode_enter_d0i3(trans->op_mode);
+       if (ret == 1) {
+               IWL_DEBUG_RPM(trans, "aborting d0i3 entrance\n");
+               clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+               return -EBUSY;
+       }
+       if (ret)
+               goto err;
+
+       ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+                                test_bit(STATUS_TRANS_IDLE, &trans->status),
+                                msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+       if (!ret) {
+               IWL_ERR(trans, "Timeout entering D0i3\n");
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+       return 0;
+err:
+       clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+       iwl_trans_fw_error(trans);
+       return ret;
+}
+
+int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+
+       /* sometimes a D0i3 entry is not followed through */
+       if (!test_bit(STATUS_TRANS_IDLE, &trans->status))
+               return 0;
+
+       /* config the fw */
+       ret = iwl_op_mode_exit_d0i3(trans->op_mode);
+       if (ret)
+               goto err;
+
+       /* we clear STATUS_TRANS_IDLE only when D0I3_END command is completed */
+
+       ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+                                !test_bit(STATUS_TRANS_IDLE, &trans->status),
+                                msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+       if (!ret) {
+               IWL_ERR(trans, "Timeout exiting D0i3\n");
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       return 0;
+err:
+       clear_bit(STATUS_TRANS_IDLE, &trans->status);
+       iwl_trans_fw_error(trans);
+       return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+static int iwl_pci_runtime_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+       int ret;
+
+       IWL_DEBUG_RPM(trans, "entering runtime suspend\n");
+
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
+               ret = iwl_pci_fw_enter_d0i3(trans);
+               if (ret < 0)
+                       return ret;
+       }
+
+       trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+
+       iwl_trans_d3_suspend(trans, false, false);
+
+       return 0;
+}
+
+static int iwl_pci_runtime_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+       enum iwl_d3_status d3_status;
+
+       IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n");
+
+       iwl_trans_d3_resume(trans, &d3_status, false, false);
+
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+               return iwl_pci_fw_exit_d0i3(trans);
+
+       return 0;
+}
+
+static int iwl_pci_system_prepare(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+       IWL_DEBUG_RPM(trans, "preparing for system suspend\n");
+
+       /* This is called before entering system suspend and before
+        * the runtime resume is called.  Set the suspending flag to
+        * prevent the wakelock from being taken.
+        */
+       trans->suspending = true;
+
+       /* Wake the device up from runtime suspend before going to
+        * platform suspend.  This is needed because we don't know
+        * whether wowlan any is set and, if it's not, mac80211 will
+        * disconnect (in which case, we can't be in D0i3).
+        */
+       pm_runtime_resume(device);
+
+       return 0;
+}
+
+static void iwl_pci_system_complete(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+       IWL_DEBUG_RPM(trans, "completing system suspend\n");
+
+       /* This is called as a counterpart to the prepare op.  It is
+        * called either when suspending fails or when suspend
+        * completed successfully.  Now there's no risk of grabbing
+        * the wakelock anymore, so we can release the suspending
+        * flag.
+        */
+       trans->suspending = false;
+}
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
+static const struct dev_pm_ops iwl_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend,
+                               iwl_pci_resume)
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+       SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend,
+                          iwl_pci_runtime_resume,
+                          NULL)
+       .prepare = iwl_pci_system_prepare,
+       .complete = iwl_pci_system_complete,
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+};
 
 #define IWL_PM_OPS     (&iwl_dev_pm_ops)
 
-#else
+#else /* CONFIG_PM_SLEEP */
 
 #define IWL_PM_OPS     NULL
 
-#endif
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver iwl_pci_driver = {
        .name = DRV_NAME,
index cc3888e2700daf1cfe07ebb4e003ca53bcf6d934..6677f31222260f6f59772ca02db4882609cb260a 100644 (file)
@@ -2,6 +2,7 @@
  *
  * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
 #define RX_NUM_QUEUES 1
 #define RX_POST_REQ_ALLOC 2
 #define RX_CLAIM_REQ_ALLOC 8
-#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
-#define RX_LOW_WATERMARK 8
+#define RX_PENDING_WATERMARK 16
 
 struct iwl_host_cmd;
 
 /*This file includes the declaration that are internal to the
  * trans_pcie layer */
 
+/**
+ * struct iwl_rx_mem_buffer
+ * @page_dma: bus address of rxb page
+ * @page: driver's pointer to the rxb page
+ * @vid: index of this rxb in the global table
+ */
 struct iwl_rx_mem_buffer {
        dma_addr_t page_dma;
        struct page *page;
+       u16 vid;
        struct list_head list;
 };
 
@@ -90,8 +97,12 @@ struct isr_statistics {
 
 /**
  * struct iwl_rxq - Rx queue
- * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
+ * @id: queue index
+ * @bd: driver's pointer to buffer of receive buffer descriptors (rbd).
+ *     Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices.
  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd)
+ * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd)
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
  * @free_count: Number of pre-allocated buffers in rx_free
@@ -103,32 +114,34 @@ struct isr_statistics {
  * @rb_stts: driver's pointer to receive buffer status
  * @rb_stts_dma: bus address of receive buffer status
  * @lock:
- * @pool: initial pool of iwl_rx_mem_buffer for the queue
- * @queue: actual rx queue
+ * @queue: actual rx queue. Not used for multi-rx queue.
  *
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
 struct iwl_rxq {
-       __le32 *bd;
+       int id;
+       void *bd;
        dma_addr_t bd_dma;
+       __le32 *used_bd;
+       dma_addr_t used_bd_dma;
        u32 read;
        u32 write;
        u32 free_count;
        u32 used_count;
        u32 write_actual;
+       u32 queue_size;
        struct list_head rx_free;
        struct list_head rx_used;
        bool need_update;
        struct iwl_rb_status *rb_stts;
        dma_addr_t rb_stts_dma;
        spinlock_t lock;
-       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
+       struct napi_struct napi;
        struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
 };
 
 /**
  * struct iwl_rb_allocator - Rx allocator
- * @pool: initial pool of allocator
  * @req_pending: number of requests the allcator had not processed yet
  * @req_ready: number of requests honored and ready for claiming
  * @rbd_allocated: RBDs with pages allocated and ready to be handled to
@@ -140,7 +153,6 @@ struct iwl_rxq {
  * @rx_alloc: work struct for background calls
  */
 struct iwl_rb_allocator {
-       struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
        atomic_t req_pending;
        atomic_t req_ready;
        struct list_head rbd_allocated;
@@ -280,6 +292,7 @@ struct iwl_txq {
        bool ampdu;
        bool block;
        unsigned long wd_timeout;
+       struct sk_buff_head overflow_q;
 };
 
 static inline dma_addr_t
@@ -297,6 +310,8 @@ struct iwl_tso_hdr_page {
 /**
  * struct iwl_trans_pcie - PCIe transport specific data
  * @rxq: all the RX queue data
+ * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues
+ * @global_table: table mapping received VID from hw to rxb
  * @rba: allocator for RX replenishing
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
@@ -321,15 +336,24 @@ struct iwl_tso_hdr_page {
  * @fw_mon_phys: physical address of the buffer for the firmware monitor
  * @fw_mon_page: points to the first page of the buffer for the firmware monitor
  * @fw_mon_size: size of the buffer for the firmware monitor
+ * @msix_entries: array of MSI-X entries
+ * @msix_enabled: true if managed to enable MSI-X
+ * @allocated_vector: the number of interrupt vector allocated by the OS
+ * @default_irq_num: default irq for non rx interrupt
+ * @fh_init_mask: initial unmasked fh causes
+ * @hw_init_mask: initial unmasked hw causes
+ * @fh_mask: current unmasked fh causes
+ * @hw_mask: current unmasked hw causes
  */
 struct iwl_trans_pcie {
-       struct iwl_rxq rxq;
+       struct iwl_rxq *rxq;
+       struct iwl_rx_mem_buffer rx_pool[MQ_RX_POOL_SIZE];
+       struct iwl_rx_mem_buffer *global_table[MQ_RX_TABLE_SIZE];
        struct iwl_rb_allocator rba;
        struct iwl_trans *trans;
        struct iwl_drv *drv;
 
        struct net_device napi_dev;
-       struct napi_struct napi;
 
        struct __percpu iwl_tso_hdr_page *tso_hdr_page;
 
@@ -359,6 +383,7 @@ struct iwl_trans_pcie {
        bool ucode_write_complete;
        wait_queue_head_t ucode_write_waitq;
        wait_queue_head_t wait_command_queue;
+       wait_queue_head_t d0i3_waitq;
 
        u8 cmd_queue;
        u8 cmd_fifo;
@@ -385,6 +410,15 @@ struct iwl_trans_pcie {
        dma_addr_t fw_mon_phys;
        struct page *fw_mon_page;
        u32 fw_mon_size;
+
+       struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES];
+       bool msix_enabled;
+       u32 allocated_vector;
+       u32 default_irq_num;
+       u32 fh_init_mask;
+       u32 hw_init_mask;
+       u32 fh_mask;
+       u32 hw_mask;
 };
 
 static inline struct iwl_trans_pcie *
@@ -413,7 +447,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
 * RX
 ******************************************************/
 int iwl_pcie_rx_init(struct iwl_trans *trans);
+irqreturn_t iwl_pcie_msix_isr(int irq, void *data);
 irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id);
+irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id);
+irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id);
 int iwl_pcie_rx_stop(struct iwl_trans *trans);
 void iwl_pcie_rx_free(struct iwl_trans *trans);
 
@@ -468,15 +505,24 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
 ******************************************************/
 static inline void iwl_disable_interrupts(struct iwl_trans *trans)
 {
-       clear_bit(STATUS_INT_ENABLED, &trans->status);
-
-       /* disable interrupts from uCode/NIC to host */
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(trans, CSR_INT, 0xffffffff);
-       iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
+       clear_bit(STATUS_INT_ENABLED, &trans->status);
+       if (!trans_pcie->msix_enabled) {
+               /* disable interrupts from uCode/NIC to host */
+               iwl_write32(trans, CSR_INT_MASK, 0x00000000);
+
+               /* acknowledge/clear/reset any interrupts still pending
+                * from uCode or flow handler (Rx/Tx DMA) */
+               iwl_write32(trans, CSR_INT, 0xffffffff);
+               iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff);
+       } else {
+               /* disable all the interrupt we might use */
+               iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
+                           trans_pcie->fh_init_mask);
+               iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
+                           trans_pcie->hw_init_mask);
+       }
        IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
 }
 
@@ -486,8 +532,53 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
 
        IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
        set_bit(STATUS_INT_ENABLED, &trans->status);
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
-       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       if (!trans_pcie->msix_enabled) {
+               trans_pcie->inta_mask = CSR_INI_SET_MASK;
+               iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       } else {
+               /*
+                * fh/hw_mask keeps all the unmasked causes.
+                * Unlike msi, in msix cause is enabled when it is unset.
+                */
+               trans_pcie->hw_mask = trans_pcie->hw_init_mask;
+               trans_pcie->fh_mask = trans_pcie->fh_init_mask;
+               iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
+                           ~trans_pcie->fh_mask);
+               iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
+                           ~trans_pcie->hw_mask);
+       }
+}
+
+static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk);
+       trans_pcie->hw_mask = msk;
+}
+
+static inline void iwl_enable_fh_int_msk_msix(struct iwl_trans *trans, u32 msk)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk);
+       trans_pcie->fh_mask = msk;
+}
+
+static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n");
+       if (!trans_pcie->msix_enabled) {
+               trans_pcie->inta_mask = CSR_INT_BIT_FH_TX;
+               iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       } else {
+               iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD,
+                           trans_pcie->hw_init_mask);
+               iwl_enable_fh_int_msk_msix(trans,
+                                          MSIX_FH_INT_CAUSES_D2S_CH0_NUM);
+       }
 }
 
 static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
@@ -495,8 +586,15 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-       trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
-       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       if (!trans_pcie->msix_enabled) {
+               trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
+               iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+       } else {
+               iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD,
+                           trans_pcie->fh_init_mask);
+               iwl_enable_hw_int_msk_msix(trans,
+                                          MSIX_HW_INT_CAUSES_REG_RF_KILL);
+       }
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
@@ -579,4 +677,7 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
 }
 #endif
 
+int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans);
+int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans);
+
 #endif /* __iwl_trans_int_pcie_h__ */
index ccafbd8cf4b3b224649b3fbc87da69207884743c..489b07a9e4717fa0b8344e944e26e0f332db4de8 100644 (file)
@@ -2,6 +2,7 @@
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
  */
 static int iwl_rxq_space(const struct iwl_rxq *rxq)
 {
-       /* Make sure RX_QUEUE_SIZE is a power of 2 */
-       BUILD_BUG_ON(RX_QUEUE_SIZE & (RX_QUEUE_SIZE - 1));
+       /* Make sure rx queue size is a power of 2 */
+       WARN_ON(rxq->queue_size & (rxq->queue_size - 1));
 
        /*
         * There can be up to (RX_QUEUE_SIZE - 1) free slots, to avoid ambiguity
@@ -149,7 +150,7 @@ static int iwl_rxq_space(const struct iwl_rxq *rxq)
         * The following is equivalent to modulo by RX_QUEUE_SIZE and is well
         * defined for negative dividends.
         */
-       return (rxq->read - rxq->write - 1) & (RX_QUEUE_SIZE - 1);
+       return (rxq->read - rxq->write - 1) & (rxq->queue_size - 1);
 }
 
 /*
@@ -160,6 +161,12 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr)
        return cpu_to_le32((u32)(dma_addr >> 8));
 }
 
+static void iwl_pcie_write_prph_64(struct iwl_trans *trans, u64 ofs, u64 val)
+{
+       iwl_write_prph(trans, ofs, val & 0xffffffff);
+       iwl_write_prph(trans, ofs + 4, val >> 32);
+}
+
 /*
  * iwl_pcie_rx_stop - stops the Rx DMA
  */
@@ -173,10 +180,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans)
 /*
  * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue
  */
-static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans)
+static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
+                                   struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        u32 reg;
 
        lockdep_assert_held(&rxq->lock);
@@ -201,24 +207,73 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans)
        }
 
        rxq->write_actual = round_down(rxq->write, 8);
-       iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
+       if (trans->cfg->mq_rx_supported)
+               iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(rxq->id),
+                              rxq->write_actual);
+       else
+               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
 }
 
 static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       int i;
 
-       spin_lock(&rxq->lock);
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (!rxq->need_update)
+                       continue;
+               spin_lock(&rxq->lock);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
+               rxq->need_update = false;
+               spin_unlock(&rxq->lock);
+       }
+}
+
+static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
+                                   struct iwl_rxq *rxq)
+{
+       struct iwl_rx_mem_buffer *rxb;
+
+       /*
+        * If the device isn't enabled - no need to try to add buffers...
+        * This can happen when we stop the device and still have an interrupt
+        * pending. We stop the APM before we sync the interrupts because we
+        * have to (see comment there). On the other hand, since the APM is
+        * stopped, we cannot access the HW (in particular not prph).
+        * So don't try to restock if the APM has been already stopped.
+        */
+       if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+               return;
 
-       if (!rxq->need_update)
-               goto exit_unlock;
+       spin_lock(&rxq->lock);
+       while (rxq->free_count) {
+               __le64 *bd = (__le64 *)rxq->bd;
 
-       iwl_pcie_rxq_inc_wr_ptr(trans);
-       rxq->need_update = false;
+               /* Get next free Rx buffer, remove from free list */
+               rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
+                                      list);
+               list_del(&rxb->list);
 
- exit_unlock:
+               /* 12 first bits are expected to be empty */
+               WARN_ON(rxb->page_dma & DMA_BIT_MASK(12));
+               /* Point to Rx buffer via next RBD in circular buffer */
+               bd[rxq->write] = cpu_to_le64(rxb->page_dma | rxb->vid);
+               rxq->write = (rxq->write + 1) & MQ_RX_TABLE_MASK;
+               rxq->free_count--;
+       }
        spin_unlock(&rxq->lock);
+
+       /*
+        * If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8.
+        */
+       if (rxq->write_actual != (rxq->write & ~0x7)) {
+               spin_lock(&rxq->lock);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
+               spin_unlock(&rxq->lock);
+       }
 }
 
 /*
@@ -232,10 +287,8 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
+static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
 
        /*
@@ -251,6 +304,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
 
        spin_lock(&rxq->lock);
        while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) {
+               __le32 *bd = (__le32 *)rxq->bd;
                /* The overwritten rxb must be a used one */
                rxb = rxq->queue[rxq->write];
                BUG_ON(rxb && rxb->page);
@@ -261,7 +315,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                list_del(&rxb->list);
 
                /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
+               bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
                rxq->queue[rxq->write] = rxb;
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
                rxq->free_count--;
@@ -272,7 +326,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
         * Increment device's write pointer in multiples of 8. */
        if (rxq->write_actual != (rxq->write & ~0x7)) {
                spin_lock(&rxq->lock);
-               iwl_pcie_rxq_inc_wr_ptr(trans);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
                spin_unlock(&rxq->lock);
        }
 }
@@ -285,13 +339,9 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
                                           gfp_t priority)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct page *page;
        gfp_t gfp_mask = priority;
 
-       if (rxq->free_count > RX_LOW_WATERMARK)
-               gfp_mask |= __GFP_NOWARN;
-
        if (trans_pcie->rx_page_order > 0)
                gfp_mask |= __GFP_COMP;
 
@@ -301,16 +351,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
                if (net_ratelimit())
                        IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
                                       trans_pcie->rx_page_order);
-               /* Issue an error if the hardware has consumed more than half
-                * of its free buffer list and we don't have enough
-                * pre-allocated buffers.
+               /*
+                * Issue an error if we don't have enough pre-allocated
+                 * buffers.
 `               */
-               if (rxq->free_count <= RX_LOW_WATERMARK &&
-                   iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
-                   net_ratelimit())
+               if (!(gfp_mask & __GFP_NOWARN) && net_ratelimit())
                        IWL_CRIT(trans,
-                                "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
-                                rxq->free_count);
+                                "Failed to alloc_pages\n");
                return NULL;
        }
        return page;
@@ -325,10 +372,10 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
  * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
  * allocated buffers.
  */
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority,
+                                  struct iwl_rxq *rxq)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
 
@@ -372,10 +419,6 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
-               /* dma address must be no more than 36 bits */
-               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-               /* and also 256 byte aligned! */
-               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
                spin_lock(&rxq->lock);
 
@@ -386,40 +429,23 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
        }
 }
 
-static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
+static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        int i;
 
-       lockdep_assert_held(&rxq->lock);
-
-       for (i = 0; i < RX_QUEUE_SIZE; i++) {
-               if (!rxq->pool[i].page)
+       for (i = 0; i < MQ_RX_POOL_SIZE; i++) {
+               if (!trans_pcie->rx_pool[i].page)
                        continue;
-               dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
+               dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma,
                               PAGE_SIZE << trans_pcie->rx_page_order,
                               DMA_FROM_DEVICE);
-               __free_pages(rxq->pool[i].page, trans_pcie->rx_page_order);
-               rxq->pool[i].page = NULL;
+               __free_pages(trans_pcie->rx_pool[i].page,
+                            trans_pcie->rx_page_order);
+               trans_pcie->rx_pool[i].page = NULL;
        }
 }
 
-/*
- * iwl_pcie_rx_replenish - Move all used buffers from rx_used to rx_free
- *
- * When moving to rx_free an page is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called only during initialization
- */
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
-{
-       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
-
-       iwl_pcie_rxq_restock(trans);
-}
-
 /*
  * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
  *
@@ -444,6 +470,11 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
        while (pending) {
                int i;
                struct list_head local_allocated;
+               gfp_t gfp_mask = GFP_KERNEL;
+
+               /* Do not post a warning if there are only a few requests */
+               if (pending < RX_PENDING_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
 
                INIT_LIST_HEAD(&local_allocated);
 
@@ -463,7 +494,7 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
                        BUG_ON(rxb->page);
 
                        /* Alloc a new receive buffer */
-                       page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL);
+                       page = iwl_pcie_rx_alloc_page(trans, gfp_mask);
                        if (!page)
                                continue;
                        rxb->page = page;
@@ -477,10 +508,6 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
                                __free_pages(page, trans_pcie->rx_page_order);
                                continue;
                        }
-                       /* dma address must be no more than 36 bits */
-                       BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-                       /* and also 256 byte aligned! */
-                       BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
                        /* move the allocated entry to the out list */
                        list_move(&rxb->list, &local_allocated);
@@ -561,38 +588,83 @@ static void iwl_pcie_rx_allocator_work(struct work_struct *data)
 static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
        struct device *dev = trans->dev;
+       int i;
+       int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) :
+                                                     sizeof(__le32);
+
+       if (WARN_ON(trans_pcie->rxq))
+               return -EINVAL;
 
-       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+       trans_pcie->rxq = kcalloc(trans->num_rx_queues, sizeof(struct iwl_rxq),
+                                 GFP_KERNEL);
+       if (!trans_pcie->rxq)
+               return -EINVAL;
 
-       spin_lock_init(&rxq->lock);
        spin_lock_init(&rba->lock);
 
-       if (WARN_ON(rxq->bd || rxq->rb_stts))
-               return -EINVAL;
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
 
-       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                     &rxq->bd_dma, GFP_KERNEL);
-       if (!rxq->bd)
-               goto err_bd;
+               spin_lock_init(&rxq->lock);
+               if (trans->cfg->mq_rx_supported)
+                       rxq->queue_size = MQ_RX_TABLE_SIZE;
+               else
+                       rxq->queue_size = RX_QUEUE_SIZE;
 
-       /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                          &rxq->rb_stts_dma, GFP_KERNEL);
-       if (!rxq->rb_stts)
-               goto err_rb_stts;
+               /*
+                * Allocate the circular buffer of Read Buffer Descriptors
+                * (RBDs)
+                */
+               rxq->bd = dma_zalloc_coherent(dev,
+                                            free_size * rxq->queue_size,
+                                            &rxq->bd_dma, GFP_KERNEL);
+               if (!rxq->bd)
+                       goto err;
+
+               if (trans->cfg->mq_rx_supported) {
+                       rxq->used_bd = dma_zalloc_coherent(dev,
+                                                          sizeof(__le32) *
+                                                          rxq->queue_size,
+                                                          &rxq->used_bd_dma,
+                                                          GFP_KERNEL);
+                       if (!rxq->used_bd)
+                               goto err;
+               }
 
+               /*Allocate the driver's pointer to receive buffer status */
+               rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                                  &rxq->rb_stts_dma,
+                                                  GFP_KERNEL);
+               if (!rxq->rb_stts)
+                       goto err;
+       }
        return 0;
 
-err_rb_stts:
-       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       rxq->bd_dma = 0;
-       rxq->bd = NULL;
-err_bd:
+err:
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (rxq->bd)
+                       dma_free_coherent(dev, free_size * rxq->queue_size,
+                                         rxq->bd, rxq->bd_dma);
+               rxq->bd_dma = 0;
+               rxq->bd = NULL;
+
+               if (rxq->rb_stts)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(struct iwl_rb_status),
+                                         rxq->rb_stts, rxq->rb_stts_dma);
+
+               if (rxq->used_bd)
+                       dma_free_coherent(dev, sizeof(__le32) * rxq->queue_size,
+                                         rxq->used_bd, rxq->used_bd_dma);
+               rxq->used_bd_dma = 0;
+               rxq->used_bd = NULL;
+       }
+       kfree(trans_pcie->rxq);
+
        return -ENOMEM;
 }
 
@@ -659,65 +731,113 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
                iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE);
 }
 
-static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
+static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 rb_size, enabled = 0;
        int i;
 
-       lockdep_assert_held(&rxq->lock);
-
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-       rxq->free_count = 0;
-       rxq->used_count = 0;
+       switch (trans_pcie->rx_buf_size) {
+       case IWL_AMSDU_4K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_4K;
+               break;
+       case IWL_AMSDU_8K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_8K;
+               break;
+       case IWL_AMSDU_12K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_12K;
+               break;
+       default:
+               WARN_ON(1);
+               rb_size = RFH_RXF_DMA_RB_SIZE_4K;
+       }
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
-               list_add(&rxq->pool[i].list, &rxq->rx_used);
-}
+       /* Stop Rx DMA */
+       iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0);
+       /* disable free amd used rx queue operation */
+       iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, 0);
+
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               /* Tell device where to find RBD free table in DRAM */
+               iwl_pcie_write_prph_64(trans, RFH_Q_FRBDCB_BA_LSB(i),
+                                      (u64)(trans_pcie->rxq[i].bd_dma));
+               /* Tell device where to find RBD used table in DRAM */
+               iwl_pcie_write_prph_64(trans, RFH_Q_URBDCB_BA_LSB(i),
+                                      (u64)(trans_pcie->rxq[i].used_bd_dma));
+               /* Tell device where in DRAM to update its Rx status */
+               iwl_pcie_write_prph_64(trans, RFH_Q_URBD_STTS_WPTR_LSB(i),
+                                      trans_pcie->rxq[i].rb_stts_dma);
+               /* Reset device indice tables */
+               iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(i), 0);
+               iwl_write_prph(trans, RFH_Q_FRBDCB_RIDX(i), 0);
+               iwl_write_prph(trans, RFH_Q_URBDCB_WIDX(i), 0);
+
+               enabled |= BIT(i) | BIT(i + 16);
+       }
 
-static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
-{
-       int i;
+       /* restock default queue */
+       iwl_pcie_rxq_mq_restock(trans, &trans_pcie->rxq[0]);
 
-       lockdep_assert_held(&rba->lock);
+       /*
+        * Enable Rx DMA
+        * Single frame mode
+        * Rx buffer size 4 or 8k or 12k
+        * Min RB size 4 or 8
+        * Drop frames that exceed RB size
+        * 512 RBDs
+        */
+       iwl_write_prph(trans, RFH_RXF_DMA_CFG,
+                      RFH_DMA_EN_ENABLE_VAL |
+                      rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
+                      RFH_RXF_DMA_MIN_RB_4_8 |
+                      RFH_RXF_DMA_DROP_TOO_LARGE_MASK |
+                      RFH_RXF_DMA_RBDCB_SIZE_512);
 
-       INIT_LIST_HEAD(&rba->rbd_allocated);
-       INIT_LIST_HEAD(&rba->rbd_empty);
+       /*
+        * Activate DMA snooping.
+        * Set RX DMA chunk size to 128 bit
+        * Default queue is 0
+        */
+       iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
+                      RFH_GEN_CFG_RB_CHUNK_SIZE |
+                      (DEFAULT_RXQ_NUM << RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
+                      RFH_GEN_CFG_SERVICE_DMA_SNOOP);
+       /* Enable the relevant rx queues */
+       iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, enabled);
 
-       for (i = 0; i < RX_POOL_SIZE; i++)
-               list_add(&rba->pool[i].list, &rba->rbd_empty);
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
 }
 
-static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
+static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
+       lockdep_assert_held(&rxq->lock);
 
-       lockdep_assert_held(&rba->lock);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+       rxq->free_count = 0;
+       rxq->used_count = 0;
+}
 
-       for (i = 0; i < RX_POOL_SIZE; i++) {
-               if (!rba->pool[i].page)
-                       continue;
-               dma_unmap_page(trans->dev, rba->pool[i].page_dma,
-                              PAGE_SIZE << trans_pcie->rx_page_order,
-                              DMA_FROM_DEVICE);
-               __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
-               rba->pool[i].page = NULL;
-       }
+static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
+{
+       WARN_ON(1);
+       return 0;
 }
 
 int iwl_pcie_rx_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *def_rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i, err;
+       int i, err, num_rbds, allocator_pool_size;
 
-       if (!rxq->bd) {
+       if (!trans_pcie->rxq) {
                err = iwl_pcie_rx_alloc(trans);
                if (err)
                        return err;
        }
+       def_rxq = trans_pcie->rxq;
        if (!rba->alloc_wq)
                rba->alloc_wq = alloc_workqueue("rb_allocator",
                                                WQ_HIGHPRI | WQ_UNBOUND, 1);
@@ -726,34 +846,68 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        spin_lock(&rba->lock);
        atomic_set(&rba->req_pending, 0);
        atomic_set(&rba->req_ready, 0);
-       /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rx_free_rba(trans);
-       iwl_pcie_rx_init_rba(rba);
+       INIT_LIST_HEAD(&rba->rbd_allocated);
+       INIT_LIST_HEAD(&rba->rbd_empty);
        spin_unlock(&rba->lock);
 
-       spin_lock(&rxq->lock);
-
        /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rxq_free_rbs(trans);
-       iwl_pcie_rx_init_rxb_lists(rxq);
+       iwl_pcie_free_rbs_pool(trans);
 
        for (i = 0; i < RX_QUEUE_SIZE; i++)
-               rxq->queue[i] = NULL;
+               def_rxq->queue[i] = NULL;
 
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-       spin_unlock(&rxq->lock);
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
 
-       iwl_pcie_rx_replenish(trans);
+               rxq->id = i;
 
-       iwl_pcie_rx_hw_init(trans, rxq);
+               spin_lock(&rxq->lock);
+               /*
+                * Set read write pointer to reflect that we have processed
+                * and used all buffers, but have not restocked the Rx queue
+                * with fresh buffers
+                */
+               rxq->read = 0;
+               rxq->write = 0;
+               rxq->write_actual = 0;
+               memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
 
-       spin_lock(&rxq->lock);
-       iwl_pcie_rxq_inc_wr_ptr(trans);
-       spin_unlock(&rxq->lock);
+               iwl_pcie_rx_init_rxb_lists(rxq);
+
+               if (!rxq->napi.poll)
+                       netif_napi_add(&trans_pcie->napi_dev, &rxq->napi,
+                                      iwl_pcie_dummy_napi_poll, 64);
+
+               spin_unlock(&rxq->lock);
+       }
+
+       /* move the pool to the default queue and allocator ownerships */
+       num_rbds = trans->cfg->mq_rx_supported ?
+                    MQ_RX_POOL_SIZE : RX_QUEUE_SIZE;
+       allocator_pool_size = trans->num_rx_queues *
+               (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC);
+       for (i = 0; i < num_rbds; i++) {
+               struct iwl_rx_mem_buffer *rxb = &trans_pcie->rx_pool[i];
+
+               if (i < allocator_pool_size)
+                       list_add(&rxb->list, &rba->rbd_empty);
+               else
+                       list_add(&rxb->list, &def_rxq->rx_used);
+               trans_pcie->global_table[i] = rxb;
+               rxb->vid = (u16)i;
+       }
+
+       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq);
+       if (trans->cfg->mq_rx_supported) {
+               iwl_pcie_rx_mq_hw_init(trans);
+       } else {
+               iwl_pcie_rxq_restock(trans, def_rxq);
+               iwl_pcie_rx_hw_init(trans, def_rxq);
+       }
+
+       spin_lock(&def_rxq->lock);
+       iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq);
+       spin_unlock(&def_rxq->lock);
 
        return 0;
 }
@@ -761,12 +915,16 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
 void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
+       int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) :
+                                             sizeof(__le32);
+       int i;
 
-       /*if rxq->bd is NULL, it means that nothing has been allocated,
-        * exit now */
-       if (!rxq->bd) {
+       /*
+        * if rxq is NULL, it means that nothing has been allocated,
+        * exit now
+        */
+       if (!trans_pcie->rxq) {
                IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
                return;
        }
@@ -777,27 +935,37 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                rba->alloc_wq = NULL;
        }
 
-       spin_lock(&rba->lock);
-       iwl_pcie_rx_free_rba(trans);
-       spin_unlock(&rba->lock);
-
-       spin_lock(&rxq->lock);
-       iwl_pcie_rxq_free_rbs(trans);
-       spin_unlock(&rxq->lock);
-
-       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       rxq->bd_dma = 0;
-       rxq->bd = NULL;
-
-       if (rxq->rb_stts)
-               dma_free_coherent(trans->dev,
-                                 sizeof(struct iwl_rb_status),
-                                 rxq->rb_stts, rxq->rb_stts_dma);
-       else
-               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       rxq->rb_stts_dma = 0;
-       rxq->rb_stts = NULL;
+       iwl_pcie_free_rbs_pool(trans);
+
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (rxq->bd)
+                       dma_free_coherent(trans->dev,
+                                         free_size * rxq->queue_size,
+                                         rxq->bd, rxq->bd_dma);
+               rxq->bd_dma = 0;
+               rxq->bd = NULL;
+
+               if (rxq->rb_stts)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(struct iwl_rb_status),
+                                         rxq->rb_stts, rxq->rb_stts_dma);
+               else
+                       IWL_DEBUG_INFO(trans,
+                                      "Free rxq->rb_stts which is NULL\n");
+
+               if (rxq->used_bd)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(__le32) * rxq->queue_size,
+                                         rxq->used_bd, rxq->used_bd_dma);
+               rxq->used_bd_dma = 0;
+               rxq->used_bd = NULL;
+
+               if (rxq->napi.poll)
+                       netif_napi_del(&rxq->napi);
+       }
+       kfree(trans_pcie->rxq);
 }
 
 /*
@@ -841,11 +1009,11 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
 }
 
 static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
+                               struct iwl_rxq *rxq,
                                struct iwl_rx_mem_buffer *rxb,
                                bool emergency)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
        bool page_stolen = false;
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
@@ -911,7 +1079,12 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                index = SEQ_TO_INDEX(sequence);
                cmd_index = get_cmd_index(&txq->q, index);
 
-               iwl_op_mode_rx(trans->op_mode, &trans_pcie->napi, &rxcb);
+               if (rxq->id == 0)
+                       iwl_op_mode_rx(trans->op_mode, &rxq->napi,
+                                      &rxcb);
+               else
+                       iwl_op_mode_rx_rss(trans->op_mode, &rxq->napi,
+                                          &rxcb, rxq->id);
 
                if (reclaim) {
                        kzfree(txq->entries[cmd_index].free_buf);
@@ -972,10 +1145,10 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
 /*
  * iwl_pcie_rx_handle - Main entry function for receiving responses from fw
  */
-static void iwl_pcie_rx_handle(struct iwl_trans *trans)
+static void iwl_pcie_rx_handle(struct iwl_trans *trans, int queue)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *rxq = &trans_pcie->rxq[queue];
        u32 r, i, j, count = 0;
        bool emergency = false;
 
@@ -986,23 +1159,39 @@ restart:
        r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF;
        i = rxq->read;
 
+       /* W/A 9000 device step A0 wrap-around bug */
+       r &= (rxq->queue_size - 1);
+
        /* Rx interrupt, but nothing sent from uCode */
        if (i == r)
-               IWL_DEBUG_RX(trans, "HW = SW = %d\n", r);
+               IWL_DEBUG_RX(trans, "Q %d: HW = SW = %d\n", rxq->id, r);
 
        while (i != r) {
                struct iwl_rx_mem_buffer *rxb;
 
-               if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2))
+               if (unlikely(rxq->used_count == rxq->queue_size / 2))
                        emergency = true;
 
-               rxb = rxq->queue[i];
-               rxq->queue[i] = NULL;
+               if (trans->cfg->mq_rx_supported) {
+                       /*
+                        * used_bd is a 32 bit but only 12 are used to retrieve
+                        * the vid
+                        */
+                       u16 vid = le32_to_cpu(rxq->used_bd[i]) & 0x0FFF;
+
+                       if (WARN(vid >= ARRAY_SIZE(trans_pcie->global_table),
+                                "Invalid rxb index from HW %u\n", (u32)vid))
+                               goto out;
+                       rxb = trans_pcie->global_table[vid];
+               } else {
+                       rxb = rxq->queue[i];
+                       rxq->queue[i] = NULL;
+               }
 
-               IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d\n", r, i);
-               iwl_pcie_rx_handle_rb(trans, rxb, emergency);
+               IWL_DEBUG_RX(trans, "Q %d: HW = %d, SW = %d\n", rxq->id, r, i);
+               iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency);
 
-               i = (i + 1) & RX_QUEUE_MASK;
+               i = (i + 1) & (rxq->queue_size - 1);
 
                /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
                 * try to claim the pre-allocated buffers from the allocator */
@@ -1040,10 +1229,10 @@ restart:
                        count++;
                        if (count == 8) {
                                count = 0;
-                               if (rxq->used_count < RX_QUEUE_SIZE / 3)
+                               if (rxq->used_count < rxq->queue_size / 3)
                                        emergency = false;
                                spin_unlock(&rxq->lock);
-                               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
+                               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
                                spin_lock(&rxq->lock);
                        }
                }
@@ -1055,11 +1244,14 @@ restart:
                if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {
                        rxq->read = i;
                        spin_unlock(&rxq->lock);
-                       iwl_pcie_rxq_restock(trans);
+                       if (trans->cfg->mq_rx_supported)
+                               iwl_pcie_rxq_mq_restock(trans, rxq);
+                       else
+                               iwl_pcie_rxq_restock(trans, rxq);
                        goto restart;
                }
        }
-
+out:
        /* Backtrack one entry */
        rxq->read = i;
        spin_unlock(&rxq->lock);
@@ -1077,10 +1269,58 @@ restart:
         * will be restocked by the next call of iwl_pcie_rxq_restock.
         */
        if (unlikely(emergency && count))
-               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
+               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
+
+       if (rxq->napi.poll)
+               napi_gro_flush(&rxq->napi, false);
+}
+
+static struct iwl_trans_pcie *iwl_pcie_get_trans_pcie(struct msix_entry *entry)
+{
+       u8 queue = entry->entry;
+       struct msix_entry *entries = entry - queue;
 
-       if (trans_pcie->napi.poll)
-               napi_gro_flush(&trans_pcie->napi, false);
+       return container_of(entries, struct iwl_trans_pcie, msix_entries[0]);
+}
+
+static inline void iwl_pcie_clear_irq(struct iwl_trans *trans,
+                                     struct msix_entry *entry)
+{
+       /*
+        * Before sending the interrupt the HW disables it to prevent
+        * a nested interrupt. This is done by writing 1 to the corresponding
+        * bit in the mask register. After handling the interrupt, it should be
+        * re-enabled by clearing this bit. This register is defined as
+        * write 1 clear (W1C) register, meaning that it's being clear
+        * by writing 1 to the bit.
+        */
+       iwl_write_direct32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(entry->entry));
+}
+
+/*
+ * iwl_pcie_rx_msix_handle - Main entry function for receiving responses from fw
+ * This interrupt handler should be used with RSS queue only.
+ */
+irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id)
+{
+       struct msix_entry *entry = dev_id;
+       struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry);
+       struct iwl_trans *trans = trans_pcie->trans;
+
+       if (WARN_ON(entry->entry >= trans->num_rx_queues))
+               return IRQ_NONE;
+
+       lock_map_acquire(&trans->sync_cmd_lockdep_map);
+
+       local_bh_disable();
+       iwl_pcie_rx_handle(trans, entry->entry);
+       local_bh_enable();
+
+       iwl_pcie_clear_irq(trans, entry);
+
+       lock_map_release(&trans->sync_cmd_lockdep_map);
+
+       return IRQ_HANDLED;
 }
 
 /*
@@ -1413,7 +1653,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                isr_stats->rx++;
 
                local_bh_disable();
-               iwl_pcie_rx_handle(trans);
+               iwl_pcie_rx_handle(trans, 0);
                local_bh_enable();
        }
 
@@ -1438,9 +1678,11 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
                         inta & ~trans_pcie->inta_mask);
        }
 
-       /* Re-enable all interrupts */
-       /* only Re-enable if disabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &trans->status))
+       /* we are loading the firmware, enable FH_TX interrupt only */
+       if (handled & CSR_INT_BIT_FH_TX)
+               iwl_enable_fw_load_int(trans);
+       /* only Re-enable all interrupt if disabled by irq */
+       else if (test_bit(STATUS_INT_ENABLED, &trans->status))
                iwl_enable_interrupts(trans);
        /* Re-enable RF_KILL if it occurred */
        else if (handled & CSR_INT_BIT_RF_KILL)
@@ -1554,3 +1796,129 @@ irqreturn_t iwl_pcie_isr(int irq, void *data)
 
        return IRQ_WAKE_THREAD;
 }
+
+irqreturn_t iwl_pcie_msix_isr(int irq, void *data)
+{
+       return IRQ_WAKE_THREAD;
+}
+
+irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
+{
+       struct msix_entry *entry = dev_id;
+       struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry);
+       struct iwl_trans *trans = trans_pcie->trans;
+       struct isr_statistics *isr_stats = isr_stats = &trans_pcie->isr_stats;
+       u32 inta_fh, inta_hw;
+
+       lock_map_acquire(&trans->sync_cmd_lockdep_map);
+
+       spin_lock(&trans_pcie->irq_lock);
+       inta_fh = iwl_read_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD);
+       inta_hw = iwl_read_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD);
+       /*
+        * Clear causes registers to avoid being handling the same cause.
+        */
+       iwl_write_direct32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh);
+       iwl_write_direct32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw);
+       spin_unlock(&trans_pcie->irq_lock);
+
+       if (unlikely(!(inta_fh | inta_hw))) {
+               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+               lock_map_release(&trans->sync_cmd_lockdep_map);
+               return IRQ_NONE;
+       }
+
+       if (iwl_have_debug_level(IWL_DL_ISR))
+               IWL_DEBUG_ISR(trans, "ISR inta_fh 0x%08x, enabled 0x%08x\n",
+                             inta_fh,
+                             iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD));
+
+       /* This "Tx" DMA channel is used only for loading uCode */
+       if (inta_fh & MSIX_FH_INT_CAUSES_D2S_CH0_NUM) {
+               IWL_DEBUG_ISR(trans, "uCode load interrupt\n");
+               isr_stats->tx++;
+               /*
+                * Wake up uCode load routine,
+                * now that load is complete
+                */
+               trans_pcie->ucode_write_complete = true;
+               wake_up(&trans_pcie->ucode_write_waitq);
+       }
+
+       /* Error detected by uCode */
+       if ((inta_fh & MSIX_FH_INT_CAUSES_FH_ERR) ||
+           (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR)) {
+               IWL_ERR(trans,
+                       "Microcode SW error detected. Restarting 0x%X.\n",
+                       inta_fh);
+               isr_stats->sw++;
+               iwl_pcie_irq_handle_error(trans);
+       }
+
+       /* After checking FH register check HW register */
+       if (iwl_have_debug_level(IWL_DL_ISR))
+               IWL_DEBUG_ISR(trans,
+                             "ISR inta_hw 0x%08x, enabled 0x%08x\n",
+                             inta_hw,
+                             iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD));
+
+       /* Alive notification via Rx interrupt will do the real work */
+       if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) {
+               IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+               isr_stats->alive++;
+       }
+
+       /* uCode wakes up after power-down sleep */
+       if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP) {
+               IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
+               iwl_pcie_rxq_check_wrptr(trans);
+               iwl_pcie_txq_check_wrptrs(trans);
+
+               isr_stats->wakeup++;
+       }
+
+       /* Chip got too hot and stopped itself */
+       if (inta_hw & MSIX_HW_INT_CAUSES_REG_CT_KILL) {
+               IWL_ERR(trans, "Microcode CT kill error detected.\n");
+               isr_stats->ctkill++;
+       }
+
+       /* HW RF KILL switch toggled */
+       if (inta_hw & MSIX_HW_INT_CAUSES_REG_RF_KILL) {
+               bool hw_rfkill;
+
+               hw_rfkill = iwl_is_rfkill_set(trans);
+               IWL_WARN(trans, "RF_KILL bit toggled to %s.\n",
+                        hw_rfkill ? "disable radio" : "enable radio");
+
+               isr_stats->rfkill++;
+
+               mutex_lock(&trans_pcie->mutex);
+               iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+               mutex_unlock(&trans_pcie->mutex);
+               if (hw_rfkill) {
+                       set_bit(STATUS_RFKILL, &trans->status);
+                       if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                              &trans->status))
+                               IWL_DEBUG_RF_KILL(trans,
+                                                 "Rfkill while SYNC HCMD in flight\n");
+                       wake_up(&trans_pcie->wait_command_queue);
+               } else {
+                       clear_bit(STATUS_RFKILL, &trans->status);
+               }
+       }
+
+       if (inta_hw & MSIX_HW_INT_CAUSES_REG_HW_ERR) {
+               IWL_ERR(trans,
+                       "Hardware error detected. Restarting.\n");
+
+               isr_stats->hw++;
+               iwl_pcie_irq_handle_error(trans);
+       }
+
+       iwl_pcie_clear_irq(trans, entry);
+
+       lock_map_release(&trans->sync_cmd_lockdep_map);
+
+       return IRQ_HANDLED;
+}
index d60a467a983c6f220384b701953eb42d2cc4c1ae..e67957d6ac79f3ddeb1e7afb863bb1ac046308a1 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/bitops.h>
 #include <linux/gfp.h>
 #include <linux/vmalloc.h>
+#include <linux/pm_runtime.h>
 
 #include "iwl-drv.h"
 #include "iwl-trans.h"
@@ -615,38 +616,38 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
                                   dma_addr_t phy_addr, u32 byte_cnt)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       unsigned long flags;
        int ret;
 
        trans_pcie->ucode_write_complete = false;
 
-       iwl_write_direct32(trans,
-                          FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+       if (!iwl_trans_grab_nic_access(trans, &flags))
+               return -EIO;
+
+       iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+                   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
 
-       iwl_write_direct32(trans,
-                          FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
-                          dst_addr);
+       iwl_write32(trans, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL),
+                   dst_addr);
 
-       iwl_write_direct32(trans,
-                          FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
-                          phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+       iwl_write32(trans, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+                   phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
 
-       iwl_write_direct32(trans,
-                          FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-                          (iwl_get_dma_hi_addr(phy_addr)
-                               << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+       iwl_write32(trans, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+                   (iwl_get_dma_hi_addr(phy_addr)
+                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
 
-       iwl_write_direct32(trans,
-                          FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
-                          1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
-                          1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
-                          FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+       iwl_write32(trans, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+                   BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) |
+                   BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) |
+                   FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
 
-       iwl_write_direct32(trans,
-                          FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE    |
-                          FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
-                          FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+       iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+                   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                   FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
+                   FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+       iwl_trans_release_nic_access(trans, &flags);
 
        ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
                                 trans_pcie->ucode_write_complete, 5 * HZ);
@@ -1021,82 +1022,6 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans,
                                               &first_ucode_section);
 }
 
-static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
-                                  const struct fw_img *fw, bool run_in_rfkill)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       bool hw_rfkill;
-       int ret;
-
-       mutex_lock(&trans_pcie->mutex);
-
-       /* Someone called stop_device, don't try to start_fw */
-       if (trans_pcie->is_down) {
-               IWL_WARN(trans,
-                        "Can't start_fw since the HW hasn't been started\n");
-               ret = EIO;
-               goto out;
-       }
-
-       /* This may fail if AMT took ownership of the device */
-       if (iwl_pcie_prepare_card_hw(trans)) {
-               IWL_WARN(trans, "Exit HW not ready\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       iwl_enable_rfkill_int(trans);
-
-       /* If platform's RF_KILL switch is NOT set to KILL */
-       hw_rfkill = iwl_is_rfkill_set(trans);
-       if (hw_rfkill)
-               set_bit(STATUS_RFKILL, &trans->status);
-       else
-               clear_bit(STATUS_RFKILL, &trans->status);
-       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
-       if (hw_rfkill && !run_in_rfkill) {
-               ret = -ERFKILL;
-               goto out;
-       }
-
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-
-       ret = iwl_pcie_nic_init(trans);
-       if (ret) {
-               IWL_ERR(trans, "Unable to init nic\n");
-               goto out;
-       }
-
-       /* make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-       /* clear (again), then enable host interrupts */
-       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
-       iwl_enable_interrupts(trans);
-
-       /* really make sure rfkill handshake bits are cleared */
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       /* Load the given image to the HW */
-       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
-               ret = iwl_pcie_load_given_ucode_8000(trans, fw);
-       else
-               ret = iwl_pcie_load_given_ucode(trans, fw);
-
-out:
-       mutex_unlock(&trans_pcie->mutex);
-       return ret;
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
-{
-       iwl_pcie_reset_ict(trans);
-       iwl_pcie_tx_start(trans, scd_addr);
-}
-
 static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1127,7 +1052,8 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
         * already dead.
         */
        if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
-               IWL_DEBUG_INFO(trans, "DEVICE_ENABLED bit was set and is now cleared\n");
+               IWL_DEBUG_INFO(trans,
+                              "DEVICE_ENABLED bit was set and is now cleared\n");
                iwl_pcie_tx_stop(trans);
                iwl_pcie_rx_stop(trans);
 
@@ -1161,7 +1087,6 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
        iwl_disable_interrupts(trans);
        spin_unlock(&trans_pcie->irq_lock);
 
-
        /* clear all status bits */
        clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
        clear_bit(STATUS_INT_ENABLED, &trans->status);
@@ -1194,10 +1119,130 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
        if (hw_rfkill != was_hw_rfkill)
                iwl_trans_pcie_rf_kill(trans, hw_rfkill);
 
-       /* re-take ownership to prevent other users from stealing the deivce */
+       /* re-take ownership to prevent other users from stealing the device */
        iwl_pcie_prepare_card_hw(trans);
 }
 
+static void iwl_pcie_synchronize_irqs(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (trans_pcie->msix_enabled) {
+               int i;
+
+               for (i = 0; i < trans_pcie->allocated_vector; i++)
+                       synchronize_irq(trans_pcie->msix_entries[i].vector);
+       } else {
+               synchronize_irq(trans_pcie->pci_dev->irq);
+       }
+}
+
+static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
+                                  const struct fw_img *fw, bool run_in_rfkill)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       bool hw_rfkill;
+       int ret;
+
+       /* This may fail if AMT took ownership of the device */
+       if (iwl_pcie_prepare_card_hw(trans)) {
+               IWL_WARN(trans, "Exit HW not ready\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       iwl_enable_rfkill_int(trans);
+
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       /*
+        * We enabled the RF-Kill interrupt and the handler may very
+        * well be running. Disable the interrupts to make sure no other
+        * interrupt can be fired.
+        */
+       iwl_disable_interrupts(trans);
+
+       /* Make sure it finished running */
+       iwl_pcie_synchronize_irqs(trans);
+
+       mutex_lock(&trans_pcie->mutex);
+
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans->status);
+       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+       if (hw_rfkill && !run_in_rfkill) {
+               ret = -ERFKILL;
+               goto out;
+       }
+
+       /* Someone called stop_device, don't try to start_fw */
+       if (trans_pcie->is_down) {
+               IWL_WARN(trans,
+                        "Can't start_fw since the HW hasn't been started\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       /* make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+       /* clear (again), then enable host interrupts */
+       iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
+
+       ret = iwl_pcie_nic_init(trans);
+       if (ret) {
+               IWL_ERR(trans, "Unable to init nic\n");
+               goto out;
+       }
+
+       /*
+        * Now, we load the firmware and don't want to be interrupted, even
+        * by the RF-Kill interrupt (hence mask all the interrupt besides the
+        * FH_TX interrupt which is needed to load the firmware). If the
+        * RF-Kill switch is toggled, we will find out after having loaded
+        * the firmware and return the proper value to the caller.
+        */
+       iwl_enable_fw_load_int(trans);
+
+       /* really make sure rfkill handshake bits are cleared */
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+       /* Load the given image to the HW */
+       if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+               ret = iwl_pcie_load_given_ucode_8000(trans, fw);
+       else
+               ret = iwl_pcie_load_given_ucode(trans, fw);
+       iwl_enable_interrupts(trans);
+
+       /* re-check RF-Kill state since we may have missed the interrupt */
+       hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans->status);
+
+       iwl_trans_pcie_rf_kill(trans, hw_rfkill);
+       if (hw_rfkill && !run_in_rfkill)
+               ret = -ERFKILL;
+
+out:
+       mutex_unlock(&trans_pcie->mutex);
+       return ret;
+}
+
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
+{
+       iwl_pcie_reset_ict(trans);
+       iwl_pcie_tx_start(trans, scd_addr);
+}
+
 static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1218,11 +1263,10 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
                _iwl_trans_pcie_stop_device(trans, true);
 }
 
-static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test,
+                                     bool reset)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
+       if (!reset) {
                /* Enable persistence mode to avoid reset */
                iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
@@ -1239,14 +1283,14 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
 
        iwl_pcie_disable_ict(trans);
 
-       synchronize_irq(trans_pcie->pci_dev->irq);
+       iwl_pcie_synchronize_irqs(trans);
 
        iwl_clear_bit(trans, CSR_GP_CNTRL,
                      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        iwl_clear_bit(trans, CSR_GP_CNTRL,
                      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D3) {
+       if (reset) {
                /*
                 * reset TX queues -- some of their registers reset during S3
                 * so if we don't reset everything here the D3 image would try
@@ -1260,7 +1304,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
 
 static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                                    enum iwl_d3_status *status,
-                                   bool test)
+                                   bool test,  bool reset)
 {
        u32 val;
        int ret;
@@ -1295,7 +1339,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
 
        iwl_pcie_set_pwr(trans, false);
 
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
+       if (!reset) {
                iwl_clear_bit(trans, CSR_GP_CNTRL,
                              CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        } else {
@@ -1318,6 +1362,153 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
        return 0;
 }
 
+struct iwl_causes_list {
+       u32 cause_num;
+       u32 mask_reg;
+       u8 addr;
+};
+
+static struct iwl_causes_list causes_list[] = {
+       {MSIX_FH_INT_CAUSES_D2S_CH0_NUM,        CSR_MSIX_FH_INT_MASK_AD, 0},
+       {MSIX_FH_INT_CAUSES_D2S_CH1_NUM,        CSR_MSIX_FH_INT_MASK_AD, 0x1},
+       {MSIX_FH_INT_CAUSES_S2D,                CSR_MSIX_FH_INT_MASK_AD, 0x3},
+       {MSIX_FH_INT_CAUSES_FH_ERR,             CSR_MSIX_FH_INT_MASK_AD, 0x5},
+       {MSIX_HW_INT_CAUSES_REG_ALIVE,          CSR_MSIX_HW_INT_MASK_AD, 0x10},
+       {MSIX_HW_INT_CAUSES_REG_WAKEUP,         CSR_MSIX_HW_INT_MASK_AD, 0x11},
+       {MSIX_HW_INT_CAUSES_REG_CT_KILL,        CSR_MSIX_HW_INT_MASK_AD, 0x16},
+       {MSIX_HW_INT_CAUSES_REG_RF_KILL,        CSR_MSIX_HW_INT_MASK_AD, 0x17},
+       {MSIX_HW_INT_CAUSES_REG_PERIODIC,       CSR_MSIX_HW_INT_MASK_AD, 0x18},
+       {MSIX_HW_INT_CAUSES_REG_SW_ERR,         CSR_MSIX_HW_INT_MASK_AD, 0x29},
+       {MSIX_HW_INT_CAUSES_REG_SCD,            CSR_MSIX_HW_INT_MASK_AD, 0x2A},
+       {MSIX_HW_INT_CAUSES_REG_FH_TX,          CSR_MSIX_HW_INT_MASK_AD, 0x2B},
+       {MSIX_HW_INT_CAUSES_REG_HW_ERR,         CSR_MSIX_HW_INT_MASK_AD, 0x2D},
+       {MSIX_HW_INT_CAUSES_REG_HAP,            CSR_MSIX_HW_INT_MASK_AD, 0x2E},
+};
+
+static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
+{
+       u32 val, max_rx_vector, i;
+       struct iwl_trans *trans = trans_pcie->trans;
+
+       max_rx_vector = trans_pcie->allocated_vector - 1;
+
+       if (!trans_pcie->msix_enabled)
+               return;
+
+       iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);
+
+       /*
+        * Each cause from the list above and the RX causes is represented as
+        * a byte in the IVAR table. We access the first (N - 1) bytes and map
+        * them to the (N - 1) vectors so these vectors will be used as rx
+        * vectors. Then access all non rx causes and map them to the
+        * default queue (N'th queue).
+        */
+       for (i = 0; i < max_rx_vector; i++) {
+               iwl_write8(trans, CSR_MSIX_RX_IVAR(i), MSIX_FH_INT_CAUSES_Q(i));
+               iwl_clear_bit(trans, CSR_MSIX_FH_INT_MASK_AD,
+                             BIT(MSIX_FH_INT_CAUSES_Q(i)));
+       }
+
+       for (i = 0; i < ARRAY_SIZE(causes_list); i++) {
+               val = trans_pcie->default_irq_num |
+                       MSIX_NON_AUTO_CLEAR_CAUSE;
+               iwl_write8(trans, CSR_MSIX_IVAR(causes_list[i].addr), val);
+               iwl_clear_bit(trans, causes_list[i].mask_reg,
+                             causes_list[i].cause_num);
+       }
+       trans_pcie->fh_init_mask =
+               ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD);
+       trans_pcie->fh_mask = trans_pcie->fh_init_mask;
+       trans_pcie->hw_init_mask =
+               ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD);
+       trans_pcie->hw_mask = trans_pcie->hw_init_mask;
+}
+
+static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev,
+                                       struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u16 pci_cmd;
+       int max_vector;
+       int ret, i;
+
+       if (trans->cfg->mq_rx_supported) {
+               max_vector = min_t(u32, (num_possible_cpus() + 1),
+                                  IWL_MAX_RX_HW_QUEUES);
+               for (i = 0; i < max_vector; i++)
+                       trans_pcie->msix_entries[i].entry = i;
+
+               ret = pci_enable_msix_range(pdev, trans_pcie->msix_entries,
+                                           MSIX_MIN_INTERRUPT_VECTORS,
+                                           max_vector);
+               if (ret > 1) {
+                       IWL_DEBUG_INFO(trans,
+                                      "Enable MSI-X allocate %d interrupt vector\n",
+                                      ret);
+                       trans_pcie->allocated_vector = ret;
+                       trans_pcie->default_irq_num =
+                               trans_pcie->allocated_vector - 1;
+                       trans_pcie->trans->num_rx_queues =
+                               trans_pcie->allocated_vector - 1;
+                       trans_pcie->msix_enabled = true;
+
+                       return;
+               }
+               IWL_DEBUG_INFO(trans,
+                              "ret = %d %s move to msi mode\n", ret,
+                              (ret == 1) ?
+                              "can't allocate more than 1 interrupt vector" :
+                              "failed to enable msi-x mode");
+               pci_disable_msix(pdev);
+       }
+
+       ret = pci_enable_msi(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret);
+               /* enable rfkill interrupt: hw bug w/a */
+               pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+               if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+                       pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+                       pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+               }
+       }
+}
+
+static int iwl_pcie_init_msix_handler(struct pci_dev *pdev,
+                                     struct iwl_trans_pcie *trans_pcie)
+{
+       int i, last_vector;
+
+       last_vector = trans_pcie->trans->num_rx_queues;
+
+       for (i = 0; i < trans_pcie->allocated_vector; i++) {
+               int ret;
+
+               ret = request_threaded_irq(trans_pcie->msix_entries[i].vector,
+                                          iwl_pcie_msix_isr,
+                                          (i == last_vector) ?
+                                          iwl_pcie_irq_msix_handler :
+                                          iwl_pcie_irq_rx_msix_handler,
+                                          IRQF_SHARED,
+                                          DRV_NAME,
+                                          &trans_pcie->msix_entries[i]);
+               if (ret) {
+                       int j;
+
+                       IWL_ERR(trans_pcie->trans,
+                               "Error allocating IRQ %d\n", i);
+                       for (j = 0; j < i; j++)
+                               free_irq(trans_pcie->msix_entries[i].vector,
+                                        &trans_pcie->msix_entries[i]);
+                       pci_disable_msix(pdev);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1339,6 +1530,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
 
        iwl_pcie_apm_init(trans);
 
+       iwl_pcie_init_msix(trans_pcie);
        /* From now on, the op_mode will be kept updated about RF kill state */
        iwl_enable_rfkill_int(trans);
 
@@ -1353,6 +1545,10 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
        /* ... rfkill can call stop_device and set it false if needed */
        iwl_trans_pcie_rf_kill(trans, hw_rfkill);
 
+       /* Make sure we sync here, because we'll need full access later */
+       if (low_power)
+               pm_runtime_resume(trans->dev);
+
        return 0;
 }
 
@@ -1389,7 +1585,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
 
        mutex_unlock(&trans_pcie->mutex);
 
-       synchronize_irq(trans_pcie->pci_dev->irq);
+       iwl_pcie_synchronize_irqs(trans);
 }
 
 static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
@@ -1422,12 +1618,6 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
 }
 
-static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
-{
-       WARN_ON(1);
-       return 0;
-}
-
 static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                                     const struct iwl_trans_config *trans_cfg)
 {
@@ -1464,11 +1654,8 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
         * As this function may be called again in some corner cases don't
         * do anything if NAPI was already initialized.
         */
-       if (!trans_pcie->napi.poll) {
+       if (trans_pcie->napi_dev.reg_state != NETREG_DUMMY)
                init_dummy_netdev(&trans_pcie->napi_dev);
-               netif_napi_add(&trans_pcie->napi_dev, &trans_pcie->napi,
-                              iwl_pcie_dummy_napi_poll, 64);
-       }
 }
 
 void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1476,22 +1663,32 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int i;
 
-       synchronize_irq(trans_pcie->pci_dev->irq);
+       /* TODO: check if this is really needed */
+       pm_runtime_disable(trans->dev);
+
+       iwl_pcie_synchronize_irqs(trans);
 
        iwl_pcie_tx_free(trans);
        iwl_pcie_rx_free(trans);
 
-       free_irq(trans_pcie->pci_dev->irq, trans);
-       iwl_pcie_free_ict(trans);
+       if (trans_pcie->msix_enabled) {
+               for (i = 0; i < trans_pcie->allocated_vector; i++)
+                       free_irq(trans_pcie->msix_entries[i].vector,
+                                &trans_pcie->msix_entries[i]);
+
+               pci_disable_msix(trans_pcie->pci_dev);
+               trans_pcie->msix_enabled = false;
+       } else {
+               free_irq(trans_pcie->pci_dev->irq, trans);
 
-       pci_disable_msi(trans_pcie->pci_dev);
+               iwl_pcie_free_ict(trans);
+
+               pci_disable_msi(trans_pcie->pci_dev);
+       }
        iounmap(trans_pcie->hw_base);
        pci_release_regions(trans_pcie->pci_dev);
        pci_disable_device(trans_pcie->pci_dev);
 
-       if (trans_pcie->napi.poll)
-               netif_napi_del(&trans_pcie->napi);
-
        iwl_pcie_free_fw_monitor(trans);
 
        for_each_possible_cpu(i) {
@@ -1831,6 +2028,7 @@ void iwl_trans_pcie_ref(struct iwl_trans *trans)
        spin_lock_irqsave(&trans_pcie->ref_lock, flags);
        IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
        trans_pcie->ref_count++;
+       pm_runtime_get(&trans_pcie->pci_dev->dev);
        spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
 }
 
@@ -1849,6 +2047,10 @@ void iwl_trans_pcie_unref(struct iwl_trans *trans)
                return;
        }
        trans_pcie->ref_count--;
+
+       pm_runtime_mark_last_busy(&trans_pcie->pci_dev->dev);
+       pm_runtime_put_autosuspend(&trans_pcie->pci_dev->dev);
+
        spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
 }
 
@@ -2001,29 +2203,48 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
 {
        struct iwl_trans *trans = file->private_data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
-       char buf[256];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
-                                               rxq->read);
-       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
-                                               rxq->write);
-       pos += scnprintf(buf + pos, bufsz - pos, "write_actual: %u\n",
-                                               rxq->write_actual);
-       pos += scnprintf(buf + pos, bufsz - pos, "need_update: %d\n",
-                                               rxq->need_update);
-       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
-                                               rxq->free_count);
-       if (rxq->rb_stts) {
-               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
-                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
-       } else {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                       "closed_rb_num: Not Allocated\n");
+       char *buf;
+       int pos = 0, i, ret;
+       size_t bufsz = sizeof(buf);
+
+       bufsz = sizeof(char) * 121 * trans->num_rx_queues;
+
+       if (!trans_pcie->rxq)
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < trans->num_rx_queues && pos < bufsz; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               pos += scnprintf(buf + pos, bufsz - pos, "queue#: %2d\n",
+                                i);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tread: %u\n",
+                                rxq->read);
+               pos += scnprintf(buf + pos, bufsz - pos, "\twrite: %u\n",
+                                rxq->write);
+               pos += scnprintf(buf + pos, bufsz - pos, "\twrite_actual: %u\n",
+                                rxq->write_actual);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tneed_update: %2d\n",
+                                rxq->need_update);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tfree_count: %u\n",
+                                rxq->free_count);
+               if (rxq->rb_stts) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                        "\tclosed_rb_num: %u\n",
+                                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &
+                                        0x0FFF);
+               } else {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                        "\tclosed_rb_num: Not Allocated\n");
+               }
        }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
 }
 
 static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
@@ -2188,7 +2409,8 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans,
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       /* Dump RBs is supported only for pre-9000 devices (1 queue) */
+       struct iwl_rxq *rxq = &trans_pcie->rxq[0];
        u32 i, r, j, rb_len = 0;
 
        spin_lock(&rxq->lock);
@@ -2383,7 +2605,8 @@ static struct iwl_trans_dump_data
        u32 len, num_rbs;
        u32 monitor_len;
        int i, ptr;
-       bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status);
+       bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) &&
+                       !trans->cfg->mq_rx_supported;
 
        /* transport dump header */
        len = sizeof(*dump_data);
@@ -2438,11 +2661,12 @@ static struct iwl_trans_dump_data
        len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
 
        if (dump_rbs) {
+               /* Dump RBs is supported only for pre-9000 devices (1 queue) */
+               struct iwl_rxq *rxq = &trans_pcie->rxq[0];
                /* RBs */
-               num_rbs = le16_to_cpu(ACCESS_ONCE(
-                                     trans_pcie->rxq.rb_stts->closed_rb_num))
+               num_rbs = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num))
                                      & 0x0FFF;
-               num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK;
+               num_rbs = (num_rbs - rxq->read) & RX_QUEUE_MASK;
                len += num_rbs * (sizeof(*data) +
                                  sizeof(struct iwl_fw_error_dump_rb) +
                                  (PAGE_SIZE << trans_pcie->rx_page_order));
@@ -2493,6 +2717,22 @@ static struct iwl_trans_dump_data
        return dump_data;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
+{
+       if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+               return iwl_pci_fw_enter_d0i3(trans);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_resume(struct iwl_trans *trans)
+{
+       if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+               iwl_pci_fw_exit_d0i3(trans);
+}
+#endif /* CONFIG_PM_SLEEP */
+
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
        .op_mode_leave = iwl_trans_pcie_op_mode_leave,
@@ -2503,6 +2743,11 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .d3_suspend = iwl_trans_pcie_d3_suspend,
        .d3_resume = iwl_trans_pcie_d3_resume,
 
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwl_trans_pcie_suspend,
+       .resume = iwl_trans_pcie_resume,
+#endif /* CONFIG_PM_SLEEP */
+
        .send_cmd = iwl_trans_pcie_send_hcmd,
 
        .tx = iwl_trans_pcie_tx,
@@ -2540,8 +2785,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 {
        struct iwl_trans_pcie *trans_pcie;
        struct iwl_trans *trans;
-       u16 pci_cmd;
-       int ret;
+       int ret, addr_size;
 
        trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
                                &pdev->dev, cfg, &trans_ops_pcie, 0);
@@ -2579,11 +2823,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                       PCIE_LINK_STATE_CLKPM);
        }
 
+       if (cfg->mq_rx_supported)
+               addr_size = 64;
+       else
+               addr_size = 36;
+
        pci_set_master(pdev);
 
-       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(addr_size));
        if (!ret)
-               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+               ret = pci_set_consistent_dma_mask(pdev,
+                                                 DMA_BIT_MASK(addr_size));
        if (ret) {
                ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (!ret)
@@ -2617,17 +2867,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans_pcie->pci_dev = pdev;
        iwl_disable_interrupts(trans);
 
-       ret = pci_enable_msi(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", ret);
-               /* enable rfkill interrupt: hw bug w/a */
-               pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
-               if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
-                       pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
-                       pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
-               }
-       }
-
        trans->hw_rev = iwl_read32(trans, CSR_HW_REV);
        /*
         * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have
@@ -2679,6 +2918,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                }
        }
 
+       iwl_pcie_set_interrupt_capa(pdev, trans);
        trans->hw_id = (pdev->device << 16) + pdev->subsystem_device;
        snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
                 "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
@@ -2686,19 +2926,31 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        /* Initialize the wait queue for commands */
        init_waitqueue_head(&trans_pcie->wait_command_queue);
 
-       ret = iwl_pcie_alloc_ict(trans);
-       if (ret)
-               goto out_pci_disable_msi;
+       init_waitqueue_head(&trans_pcie->d0i3_waitq);
 
-       ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,
-                                  iwl_pcie_irq_handler,
-                                  IRQF_SHARED, DRV_NAME, trans);
-       if (ret) {
-               IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
-               goto out_free_ict;
-       }
+       if (trans_pcie->msix_enabled) {
+               if (iwl_pcie_init_msix_handler(pdev, trans_pcie))
+                       goto out_pci_release_regions;
+        } else {
+               ret = iwl_pcie_alloc_ict(trans);
+               if (ret)
+                       goto out_pci_disable_msi;
 
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
+               ret = request_threaded_irq(pdev->irq, iwl_pcie_isr,
+                                          iwl_pcie_irq_handler,
+                                          IRQF_SHARED, DRV_NAME, trans);
+               if (ret) {
+                       IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq);
+                       goto out_free_ict;
+               }
+               trans_pcie->inta_mask = CSR_INI_SET_MASK;
+        }
+
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+       trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+#else
+       trans->runtime_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
 
        return trans;
 
index 5262028b55055e4ca9243e8d27fee38bd9769f0e..16ad820ca8248717a26a050d165e1011aec301ca 100644 (file)
@@ -1,7 +1,8 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -33,7 +34,6 @@
 #include <linux/sched.h>
 #include <net/ip6_checksum.h>
 #include <net/tso.h>
-#include <net/ip6_checksum.h>
 
 #include "iwl-debug.h"
 #include "iwl-csr.h"
@@ -571,6 +571,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
                return ret;
 
        spin_lock_init(&txq->lock);
+       __skb_queue_head_init(&txq->overflow_q);
 
        /*
         * Tell nic where to find circular buffer of Tx Frame Descriptors for
@@ -621,6 +622,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr);
        }
        txq->active = false;
+
+       while (!skb_queue_empty(&txq->overflow_q)) {
+               struct sk_buff *skb = __skb_dequeue(&txq->overflow_q);
+
+               iwl_op_mode_free_skb(trans->op_mode, skb);
+       }
+
        spin_unlock_bh(&txq->lock);
 
        /* just in case - this queue may have been stopped */
@@ -1052,8 +1060,41 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
 
        iwl_pcie_txq_progress(txq);
 
-       if (iwl_queue_space(&txq->q) > txq->q.low_mark)
-               iwl_wake_queue(trans, txq);
+       if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+           test_bit(txq_id, trans_pcie->queue_stopped)) {
+               struct sk_buff_head overflow_skbs;
+
+               __skb_queue_head_init(&overflow_skbs);
+               skb_queue_splice_init(&txq->overflow_q, &overflow_skbs);
+
+               /*
+                * This is tricky: we are in reclaim path which is non
+                * re-entrant, so noone will try to take the access the
+                * txq data from that path. We stopped tx, so we can't
+                * have tx as well. Bottom line, we can unlock and re-lock
+                * later.
+                */
+               spin_unlock_bh(&txq->lock);
+
+               while (!skb_queue_empty(&overflow_skbs)) {
+                       struct sk_buff *skb = __skb_dequeue(&overflow_skbs);
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                       u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1;
+                       struct iwl_device_cmd *dev_cmd =
+                               info->driver_data[dev_cmd_idx];
+
+                       /*
+                        * Note that we can very well be overflowing again.
+                        * In that case, iwl_queue_space will be small again
+                        * and we won't wake mac80211's queue.
+                        */
+                       iwl_trans_pcie_tx(trans, skb, dev_cmd, txq_id);
+               }
+               spin_lock_bh(&txq->lock);
+
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+                       iwl_wake_queue(trans, txq);
+       }
 
        if (q->read_ptr == q->write_ptr) {
                IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
@@ -1686,6 +1727,20 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                wake_up(&trans_pcie->wait_command_queue);
        }
 
+       if (meta->flags & CMD_MAKE_TRANS_IDLE) {
+               IWL_DEBUG_INFO(trans, "complete %s - mark trans as idle\n",
+                              iwl_get_cmd_string(trans, cmd->hdr.cmd));
+               set_bit(STATUS_TRANS_IDLE, &trans->status);
+               wake_up(&trans_pcie->d0i3_waitq);
+       }
+
+       if (meta->flags & CMD_WAKE_UP_TRANS) {
+               IWL_DEBUG_INFO(trans, "complete %s - clear trans idle flag\n",
+                              iwl_get_cmd_string(trans, cmd->hdr.cmd));
+               clear_bit(STATUS_TRANS_IDLE, &trans->status);
+               wake_up(&trans_pcie->d0i3_waitq);
+       }
+
        meta->flags = 0;
 
        spin_unlock_bh(&txq->lock);
@@ -2161,6 +2216,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
                csum = skb_checksum(skb, offs, skb->len - offs, 0);
                *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum);
+
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
        if (skb_is_nonlinear(skb) &&
@@ -2177,6 +2234,22 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
        spin_lock(&txq->lock);
 
+       if (iwl_queue_space(q) < q->high_mark) {
+               iwl_stop_queue(trans, txq);
+
+               /* don't put the packet on the ring, if there is no room */
+               if (unlikely(iwl_queue_space(q) < 3)) {
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+                       info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA + 1] =
+                               dev_cmd;
+                       __skb_queue_tail(&txq->overflow_q, skb);
+
+                       spin_unlock(&txq->lock);
+                       return 0;
+               }
+       }
+
        /* In AGG mode, the index in the ring must correspond to the WiFi
         * sequence number. This is a HW requirements to help the SCD to parse
         * the BA.
@@ -2281,12 +2354,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
         * At this point the frame is "transmitted" successfully
         * and we will get a TX status notification eventually.
         */
-       if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr)
-                       iwl_pcie_txq_inc_wr_ptr(trans, txq);
-               else
-                       iwl_stop_queue(trans, txq);
-       }
        spin_unlock(&txq->lock);
        return 0;
 out_err:
index 6df3ee561d5214725c3c881895a6056861df74e1..515aa3f993f3dd8d1a65936472bfa6b00f4420de 100644 (file)
@@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
        spin_lock_bh(&local->baplock);
 
        res = hfa384x_setup_bap(dev, BAP0, rid, 0);
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
+
+       res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
 
        if (le16_to_cpu(rec.len) == 0) {
                /* RID not available */
                res = -ENODATA;
+               goto unlock;
        }
 
        rlen = (le16_to_cpu(rec.len) - 1) * 2;
-       if (!res && exact_len && rlen != len) {
+       if (exact_len && rlen != len) {
                printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
                       "rid=0x%04x, len=%d (expected %d)\n",
                       dev->name, rid, rlen, len);
                res = -ENODATA;
        }
 
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, buf, len);
+       res = hfa384x_from_bap(dev, BAP0, buf, len);
 
+unlock:
        spin_unlock_bh(&local->baplock);
        mutex_unlock(&local->rid_bap_mtx);
 
index a28414c50edf11131e41aa65f02957a5a07c796f..e85e0737771c87e4b9d445e3fa998d8eb0bbfc28 100644 (file)
@@ -844,7 +844,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
        hdr->rt_chbitmask = cpu_to_le16(flags);
 
        skb->dev = hwsim_mon;
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -887,7 +887,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
        memcpy(hdr11->addr1, addr, ETH_ALEN);
 
        skb->dev = hwsim_mon;
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -1334,10 +1334,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
        data->tx_bytes += skb->len;
        ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
 
-       if (ack && skb->len >= 16) {
-               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       if (ack && skb->len >= 16)
                mac80211_hwsim_monitor_ack(channel, hdr->addr2);
-       }
 
        ieee80211_tx_info_clear_status(txi);
 
@@ -1846,10 +1844,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
 
 static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
-                                      enum ieee80211_ampdu_mlme_action action,
-                                      struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                      u8 buf_size, bool amsdu)
+                                      struct ieee80211_ampdu_params *params)
 {
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
index 86955c416b30ed20ec48a5013d42df1e5257f89b..2eea76a340b7b44087d160304faf0a9767882d12 100644 (file)
@@ -2039,6 +2039,43 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 
 
 
+int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+                      bool enabled, int timeout)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       if  (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
+               if (!enabled)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       /* firmware does not work well with too long latency with power saving
+        * enabled, so do not enable it if there is only polling, no
+        * interrupts (like in some sdio hosts which can only
+        * poll for sdio irqs)
+        */
+       if  (priv->is_polling) {
+               if (!enabled)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       if (!enabled) {
+               priv->psmode = LBS802_11POWERMODECAM;
+               if (priv->psstate != PS_STATE_FULL_POWER)
+                       lbs_set_ps_mode(priv,
+                                       PS_MODE_ACTION_EXIT_PS,
+                                       true);
+               return 0;
+       }
+       if (priv->psmode != LBS802_11POWERMODECAM)
+               return 0;
+       priv->psmode = LBS802_11POWERMODEMAX_PSP;
+       if (priv->connect_status == LBS_CONNECTED)
+               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS, true);
+       return 0;
+}
 
 /*
  * Initialization
@@ -2057,6 +2094,7 @@ static struct cfg80211_ops lbs_cfg80211_ops = {
        .change_virtual_intf = lbs_change_intf,
        .join_ibss = lbs_join_ibss,
        .leave_ibss = lbs_leave_ibss,
+       .set_power_mgmt = lbs_set_power_mgmt,
 };
 
 
index 0387a5b380c80f5eeafd05c53c3ec12fc5b892f5..4ddd0e5a6b85c68102483b7f42e27cab096a2a9f 100644 (file)
@@ -957,7 +957,7 @@ static void lbs_queue_cmd(struct lbs_private *priv,
 
        /* Exit_PS command needs to be queued in the header always. */
        if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
-               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
+               struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf;
 
                if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                        if (priv->psstate != PS_STATE_FULL_POWER)
@@ -1387,7 +1387,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                 * PS command. Ignore it if it is not Exit_PS.
                                 * otherwise send it down immediately.
                                 */
-                               struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
+                               struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;
 
                                lbs_deb_host(
                                       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
@@ -1428,40 +1428,14 @@ int lbs_execute_next_command(struct lbs_private *priv)
                 * check if in power save mode, if yes, put the device back
                 * to PS mode
                 */
-#ifdef TODO
-               /*
-                * This was the old code for libertas+wext. Someone that
-                * understands this beast should re-code it in a sane way.
-                *
-                * I actually don't understand why this is related to WPA
-                * and to connection status, shouldn't powering should be
-                * independ of such things?
-                */
                if ((priv->psmode != LBS802_11POWERMODECAM) &&
                    (priv->psstate == PS_STATE_FULL_POWER) &&
-                   ((priv->connect_status == LBS_CONNECTED) ||
-                   lbs_mesh_connected(priv))) {
-                       if (priv->secinfo.WPAenabled ||
-                           priv->secinfo.WPA2enabled) {
-                               /* check for valid WPA group keys */
-                               if (priv->wpa_mcast_key.len ||
-                                   priv->wpa_unicast_key.len) {
-                                       lbs_deb_host(
-                                              "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
-                                              " go back to PS_SLEEP");
-                                       lbs_set_ps_mode(priv,
-                                                       PS_MODE_ACTION_ENTER_PS,
-                                                       false);
-                               }
-                       } else {
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: cmdpendingq empty, "
-                                      "go back to PS_SLEEP");
-                               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
-                                               false);
-                       }
+                   (priv->connect_status == LBS_CONNECTED)) {
+                       lbs_deb_host(
+                               "EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP");
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+                                       false);
                }
-#endif
        }
 
        ret = 0;
index e5442e8956f7ac3b1182058864816dc700548fe5..c95bf6dc9522eae5bdd4824e4c157ddc15dbc562 100644 (file)
@@ -123,7 +123,10 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
        priv->cmd_timed_out = 0;
 
        if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
-               struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
+               /* struct cmd_ds_802_11_ps_mode also contains
+                * the header
+                */
+               struct cmd_ds_802_11_ps_mode *psmode = (void *)resp;
                u16 action = le16_to_cpu(psmode->action);
 
                lbs_deb_host(
@@ -254,6 +257,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
                               "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
                        break;
                }
+               if (!list_empty(&priv->cmdpendingq)) {
+                       lbs_deb_cmd("EVENT: commands in queue, do not sleep\n");
+                       break;
+               }
                priv->psstate = PS_STATE_PRE_SLEEP;
 
                lbs_ps_confirm_sleep(priv);
index 6bd1608992b00bec61b596d1c770674df8e11024..edf710bc5e77dedcfcc03fd77054ccd93b88bf90 100644 (file)
@@ -99,6 +99,7 @@ struct lbs_private {
        /* Hardware access */
        void *card;
        bool iface_running;
+       u8 is_polling; /* host has to poll the card irq */
        u8 fw_ready;
        u8 surpriseremoved;
        u8 setup_fw_on_resume;
index 68fd3a9779bdb99a06fad6735445ecda9dca7842..13eae9ff8c354384a6c8a172f73b7d9da2bbddee 100644 (file)
@@ -1267,7 +1267,7 @@ static int if_sdio_probe(struct sdio_func *func,
        priv->reset_card = if_sdio_reset_card;
        priv->power_save = if_sdio_power_save;
        priv->power_restore = if_sdio_power_restore;
-
+       priv->is_polling = !(func->card->host->caps & MMC_CAP_SDIO_IRQ);
        ret = if_sdio_power_on(card);
        if (ret)
                goto err_activate_card;
index dff08a2896a38f644894749c006787e26b1f3ea6..aba0c9995b14b143f716d4a83c0a695f0cc628eb 100644 (file)
@@ -267,6 +267,7 @@ static int if_usb_probe(struct usb_interface *intf,
        priv->enter_deep_sleep = NULL;
        priv->exit_deep_sleep = NULL;
        priv->reset_deep_sleep_wakeup = NULL;
+       priv->is_polling = false;
 #ifdef CONFIG_OLPC
        if (machine_is_olpc())
                priv->reset_card = if_usb_reset_olpc_card;
index 8079560f496581600cb658c4fa09d8e5d1faed81..b35b8bcce24cc0a34081fab73928c6d44b2fd91e 100644 (file)
@@ -1060,7 +1060,12 @@ void lbs_remove_card(struct lbs_private *priv)
 
        if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
                priv->psmode = LBS802_11POWERMODECAM;
-               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
+               /* no need to wakeup if already woken up,
+                * on suspend, this exit ps command is not processed
+                * the driver hangs
+                */
+               if (priv->psstate != PS_STATE_FULL_POWER)
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
        }
 
        if (priv->is_deep_sleep) {
index 71a1b580796f12723e8b6725e938993acfbd1e85..81c60d0a1bda348728fb539e4d487285d3367aa3 100644 (file)
@@ -123,8 +123,7 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
 void mwifiex_dfs_cac_work_queue(struct work_struct *work)
 {
        struct cfg80211_chan_def chandef;
-       struct delayed_work *delayed_work =
-                       container_of(work, struct delayed_work, work);
+       struct delayed_work *delayed_work = to_delayed_work(work);
        struct mwifiex_private *priv =
                        container_of(delayed_work, struct mwifiex_private,
                                     dfs_cac_work);
@@ -289,8 +288,7 @@ int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
 void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
 {
        struct mwifiex_uap_bss_param *bss_cfg;
-       struct delayed_work *delayed_work =
-                       container_of(work, struct delayed_work, work);
+       struct delayed_work *delayed_work = to_delayed_work(work);
        struct mwifiex_private *priv =
                        container_of(delayed_work, struct mwifiex_private,
                                     dfs_chan_sw_work);
index 2f0f9b5609d0139a301f7e57866f212cc1daefe1..24e649b1eb2453444967439166f2b9dd8b21e9b6 100644 (file)
@@ -237,4 +237,14 @@ device_dump
 
        cat fw_dump
 
+verext
+       This command is used to get extended firmware version string using
+       different configuration parameters.
+
+       Usage:
+               echo "[version_str_sel]" > verext
+               cat verext
+
+               [version_str_sel]: firmware support several extend version
+                                  string cases, include 0/1/10/20/21/99
 ===============================================================================
index e7adef72c05fcfd197f9aadb4eef24e5ef5f9511..29b7f6eed240640b988051a2d2228aa44f61905d 100644 (file)
@@ -676,7 +676,7 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
                }
                break;
 
-               case MWIFIEX_BSS_ROLE_STA:
+       case MWIFIEX_BSS_ROLE_STA:
                if (priv->media_connected) {
                        mwifiex_dbg(adapter, ERROR,
                                    "cannot change wiphy params when connected");
@@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        if (mwifiex_deauthenticate(priv, NULL))
                return -EFAULT;
 
@@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                    "info: Trying to associate to %s and bssid %pM\n",
                    (char *)sme->ssid, sme->bssid);
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
                                     priv->bss_mode, sme->channel, sme, 0);
        if (!ret) {
@@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
                return -EBUSY;
        }
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
        if (!user_scan_cfg)
                return -ENOMEM;
@@ -2487,6 +2496,125 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
        return 0;
 }
 
+/* CFG802.11 operation handler for sched_scan_start.
+ *
+ * This function issues a bgscan config request to the firmware based upon
+ * the user specified sched_scan configuration. On successful completion,
+ * firmware will generate BGSCAN_REPORT event, driver should issue bgscan
+ * query command to get sched_scan results from firmware.
+ */
+static int
+mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy,
+                                 struct net_device *dev,
+                                 struct cfg80211_sched_scan_request *request)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       int i, offset;
+       struct ieee80211_channel *chan;
+       struct mwifiex_bg_scan_cfg *bgscan_cfg;
+       struct ieee_types_header *ie;
+
+       if (!request || (!request->n_ssids && !request->n_match_sets)) {
+               wiphy_err(wiphy, "%s : Invalid Sched_scan parameters",
+                         __func__);
+               return -EINVAL;
+       }
+
+       wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ",
+                  request->n_ssids, request->n_match_sets);
+       wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n",
+                  request->n_channels, request->scan_plans->interval,
+                  (int)request->ie_len);
+
+       bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
+       if (!bgscan_cfg)
+               return -ENOMEM;
+
+       if (priv->scan_request || priv->scan_aborting)
+               bgscan_cfg->start_later = true;
+
+       bgscan_cfg->num_ssids = request->n_match_sets;
+       bgscan_cfg->ssid_list = request->match_sets;
+
+       if (request->ie && request->ie_len) {
+               offset = 0;
+               for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+                       if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
+                               continue;
+                       priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN;
+                       ie = (struct ieee_types_header *)(request->ie + offset);
+                       memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len);
+                       offset += sizeof(*ie) + ie->len;
+
+                       if (offset >= request->ie_len)
+                               break;
+               }
+       }
+
+       for (i = 0; i < min_t(u32, request->n_channels,
+                             MWIFIEX_BG_SCAN_CHAN_MAX); i++) {
+               chan = request->channels[i];
+               bgscan_cfg->chan_list[i].chan_number = chan->hw_value;
+               bgscan_cfg->chan_list[i].radio_type = chan->band;
+
+               if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
+                       bgscan_cfg->chan_list[i].scan_type =
+                                               MWIFIEX_SCAN_TYPE_PASSIVE;
+               else
+                       bgscan_cfg->chan_list[i].scan_type =
+                                               MWIFIEX_SCAN_TYPE_ACTIVE;
+
+               bgscan_cfg->chan_list[i].scan_time = 0;
+       }
+
+       bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels,
+                                         MWIFIEX_BG_SCAN_CHAN_MAX);
+
+       /* Use at least 15 second for per scan cycle */
+       bgscan_cfg->scan_interval = (request->scan_plans->interval >
+                                    MWIFIEX_BGSCAN_INTERVAL) ?
+                               request->scan_plans->interval :
+                               MWIFIEX_BGSCAN_INTERVAL;
+
+       bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT;
+       bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH |
+                               MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE;
+       bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
+       bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
+       bgscan_cfg->enable = true;
+       if (request->min_rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) {
+               bgscan_cfg->report_condition |= MWIFIEX_BGSCAN_SSID_RSSI_MATCH;
+               bgscan_cfg->rssi_threshold = request->min_rssi_thold;
+       }
+
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                            HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
+               kfree(bgscan_cfg);
+               return -EFAULT;
+       }
+
+       priv->sched_scanning = true;
+
+       kfree(bgscan_cfg);
+       return 0;
+}
+
+/* CFG802.11 operation handler for sched_scan_stop.
+ *
+ * This function issues a bgscan config command to disable
+ * previous bgscan configuration in the firmware
+ */
+static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy,
+                                           struct net_device *dev)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+       wiphy_info(wiphy, "sched scan stop!");
+       mwifiex_stop_bg_scan(priv);
+
+       return 0;
+}
+
 static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
                                   struct mwifiex_private *priv)
 {
@@ -2848,6 +2976,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
        mwifiex_dev_debugfs_remove(priv);
 #endif
 
+       if (priv->sched_scanning)
+               priv->sched_scanning = false;
+
        mwifiex_stop_net_dev_queue(priv->netdev, adapter);
 
        skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
@@ -3044,10 +3175,12 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
                                sizeof(byte_seq));
                mef_entry->filter[filt_num].filt_type = TYPE_EQ;
 
-               if (first_pat)
+               if (first_pat) {
                        first_pat = false;
-               else
+                       mwifiex_dbg(priv->adapter, INFO, "Wake on patterns\n");
+               } else {
                        mef_entry->filter[filt_num].filt_action = TYPE_AND;
+               }
 
                filt_num++;
        }
@@ -3073,6 +3206,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
                mef_entry->filter[filt_num].offset = 56;
                mef_entry->filter[filt_num].filt_type = TYPE_EQ;
                mef_entry->filter[filt_num].filt_action = TYPE_OR;
+               mwifiex_dbg(priv->adapter, INFO, "Wake on magic packet\n");
        }
        return ret;
 }
@@ -3143,7 +3277,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
 
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
 
-       if (!priv->media_connected) {
+       if (!priv->media_connected && !wowlan->nd_config) {
                mwifiex_dbg(adapter, ERROR,
                            "Can not configure WOWLAN in disconnected state\n");
                return 0;
@@ -3155,19 +3289,30 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
                return ret;
        }
 
+       memset(&hs_cfg, 0, sizeof(hs_cfg));
+       hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions);
+
+       if (wowlan->nd_config) {
+               mwifiex_dbg(adapter, INFO, "Wake on net detect\n");
+               hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
+               mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev,
+                                                 wowlan->nd_config);
+       }
+
        if (wowlan->disconnect) {
-               memset(&hs_cfg, 0, sizeof(hs_cfg));
-               hs_cfg.is_invoke_hostcmd = false;
-               hs_cfg.conditions = HS_CFG_COND_MAC_EVENT;
-               hs_cfg.gpio = adapter->hs_cfg.gpio;
-               hs_cfg.gap = adapter->hs_cfg.gap;
-               ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
-                                           MWIFIEX_SYNC_CMD, &hs_cfg);
-               if (ret) {
-                       mwifiex_dbg(adapter, ERROR,
-                                   "Failed to set HS params\n");
-                       return ret;
-               }
+               hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
+               mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n");
+       }
+
+       hs_cfg.is_invoke_hostcmd = false;
+       hs_cfg.gpio = adapter->hs_cfg.gpio;
+       hs_cfg.gap = adapter->hs_cfg.gap;
+       ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+                                   MWIFIEX_SYNC_CMD, &hs_cfg);
+       if (ret) {
+               mwifiex_dbg(adapter, ERROR,
+                           "Failed to set HS params\n");
+               return ret;
        }
 
        return ret;
@@ -3175,6 +3320,64 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
 
 static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
 {
+       struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+       struct mwifiex_private *priv =
+               mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+       struct mwifiex_ds_wakeup_reason wakeup_reason;
+       struct cfg80211_wowlan_wakeup wakeup_report;
+       int i;
+
+       mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD,
+                                 &wakeup_reason);
+       memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup));
+
+       wakeup_report.pattern_idx = -1;
+
+       switch (wakeup_reason.hs_wakeup_reason) {
+       case NO_HSWAKEUP_REASON:
+               break;
+       case BCAST_DATA_MATCHED:
+               break;
+       case MCAST_DATA_MATCHED:
+               break;
+       case UCAST_DATA_MATCHED:
+               break;
+       case MASKTABLE_EVENT_MATCHED:
+               break;
+       case NON_MASKABLE_EVENT_MATCHED:
+               if (wiphy->wowlan_config->disconnect)
+                       wakeup_report.disconnect = true;
+               if (wiphy->wowlan_config->nd_config)
+                       wakeup_report.net_detect = adapter->nd_info;
+               break;
+       case NON_MASKABLE_CONDITION_MATCHED:
+               break;
+       case MAGIC_PATTERN_MATCHED:
+               if (wiphy->wowlan_config->magic_pkt)
+                       wakeup_report.magic_pkt = true;
+               if (wiphy->wowlan_config->n_patterns)
+                       wakeup_report.pattern_idx = 1;
+               break;
+       case CONTROL_FRAME_MATCHED:
+               break;
+       case    MANAGEMENT_FRAME_MATCHED:
+               break;
+       default:
+               break;
+       }
+
+       if ((wakeup_reason.hs_wakeup_reason > 0) &&
+           (wakeup_reason.hs_wakeup_reason <= 7))
+               cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report,
+                                             GFP_KERNEL);
+
+       if (adapter->nd_info) {
+               for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
+                       kfree(adapter->nd_info->matches[i]);
+               kfree(adapter->nd_info);
+               adapter->nd_info = NULL;
+       }
+
        return 0;
 }
 
@@ -3590,8 +3793,8 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
                freq = ieee80211_channel_to_frequency(curr_bss->channel, band);
                chan = ieee80211_get_channel(wiphy, freq);
 
-               if (curr_bss->bcn_ht_oper) {
-                       second_chan_offset = curr_bss->bcn_ht_oper->ht_param &
+               if (priv->ht_param_present) {
+                       second_chan_offset = priv->assoc_resp_ht_param &
                                        IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
                        chan_type = mwifiex_sec_chan_offset_to_chan_type
                                                        (second_chan_offset);
@@ -3701,6 +3904,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
        .set_antenna = mwifiex_cfg80211_set_antenna,
        .del_station = mwifiex_cfg80211_del_station,
+       .sched_scan_start = mwifiex_cfg80211_sched_scan_start,
+       .sched_scan_stop = mwifiex_cfg80211_sched_scan_stop,
 #ifdef CONFIG_PM
        .suspend = mwifiex_cfg80211_suspend,
        .resume = mwifiex_cfg80211_resume,
@@ -3720,11 +3925,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
 
 #ifdef CONFIG_PM
 static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
-       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+               WIPHY_WOWLAN_NET_DETECT,
        .n_patterns = MWIFIEX_MEF_MAX_FILTERS,
        .pattern_min_len = 1,
        .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
        .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
+       .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS,
 };
 #endif
 
@@ -3829,6 +4036,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
                        WIPHY_FLAG_AP_UAPSD |
+                       WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                        WIPHY_FLAG_HAS_CHANNEL_SWITCH |
                        WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -3847,6 +4055,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
+       wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
+       wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
+       wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH;
+
        wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
        wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
 
index cb25aa7e90db19d54df9b556d677c3a460093d77..a12adee776c6c6ac76c2f24d3bc44b88a1f5a6af 100644 (file)
@@ -1657,3 +1657,16 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
 
        return 0;
 }
+
+/* This function handles the command response of hs wakeup reason
+ * command.
+ */
+int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv,
+                             struct host_cmd_ds_command *resp,
+                             struct host_cmd_ds_wakeup_reason *wakeup_reason)
+{
+       wakeup_reason->wakeup_reason =
+               resp->params.hs_wakeup_reason.wakeup_reason;
+
+       return 0;
+}
index 0b9c580af988cd502e4ab4b05c351ffc030935ab..df28836a1d1100672050bf878a4dba70f40b87c6 100644 (file)
@@ -95,8 +95,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
 
        mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
 
-       if (!priv->version_str[0])
-               mwifiex_get_ver_ext(priv);
+       mwifiex_get_ver_ext(priv, 0);
 
        p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
        p += sprintf(p, "driver_version = %s", fmt);
@@ -583,6 +582,52 @@ done:
        return ret;
 }
 
+/* debugfs verext file write handler.
+ * This function is called when the 'verext' file is opened for write
+ */
+static ssize_t
+mwifiex_verext_write(struct file *file, const char __user *ubuf,
+                    size_t count, loff_t *ppos)
+{
+       int ret;
+       u32 versionstrsel;
+       struct mwifiex_private *priv = (void *)file->private_data;
+       char buf[16];
+
+       memset(buf, 0, sizeof(buf));
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       ret = kstrtou32(buf, 10, &versionstrsel);
+       if (ret)
+               return ret;
+
+       priv->versionstrsel = versionstrsel;
+
+       return count;
+}
+
+/* Proc verext file read handler.
+ * This function is called when the 'verext' file is opened for reading
+ * This function can be used read driver exteneed verion string.
+ */
+static ssize_t
+mwifiex_verext_read(struct file *file, char __user *ubuf,
+                   size_t count, loff_t *ppos)
+{
+       struct mwifiex_private *priv =
+               (struct mwifiex_private *)file->private_data;
+       char buf[256];
+       int ret;
+
+       mwifiex_get_ver_ext(priv, priv->versionstrsel);
+       ret = snprintf(buf, sizeof(buf), "version string: %s\n",
+                      priv->version_str);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+}
+
 /* Proc memrw file write handler.
  * This function is called when the 'memrw' file is opened for writing
  * This function can be used to write to a memory location.
@@ -940,6 +985,7 @@ MWIFIEX_DFS_FILE_OPS(histogram);
 MWIFIEX_DFS_FILE_OPS(debug_mask);
 MWIFIEX_DFS_FILE_OPS(timeshare_coex);
 MWIFIEX_DFS_FILE_WRITE_OPS(reset);
+MWIFIEX_DFS_FILE_OPS(verext);
 
 /*
  * This function creates the debug FS directory structure and the files.
@@ -968,6 +1014,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
        MWIFIEX_DFS_ADD_FILE(debug_mask);
        MWIFIEX_DFS_ADD_FILE(timeshare_coex);
        MWIFIEX_DFS_ADD_FILE(reset);
+       MWIFIEX_DFS_ADD_FILE(verext);
 }
 
 /*
index d9c15cd36f1277f8a9a4e87a08a5b5fbc4ea9e97..bec300b9c2ea51bf478d6060b19b952360a36f31 100644 (file)
 #define BLOCK_NUMBER_OFFSET            15
 #define SDIO_HEADER_OFFSET             28
 
+#define MWIFIEX_SIZE_4K 0x4000
+
 enum mwifiex_bss_type {
        MWIFIEX_BSS_TYPE_STA = 0,
        MWIFIEX_BSS_TYPE_UAP = 1,
@@ -270,4 +272,26 @@ struct mwifiex_11h_intf_state {
        bool is_11h_enabled;
        bool is_11h_active;
 } __packed;
+
+#define MWIFIEX_FW_DUMP_IDX            0xff
+#define MWIFIEX_FW_DUMP_MAX_MEMSIZE     0x160000
+#define MWIFIEX_DRV_INFO_IDX           20
+#define FW_DUMP_MAX_NAME_LEN           8
+#define FW_DUMP_HOST_READY      0xEE
+#define FW_DUMP_DONE                   0xFF
+#define FW_DUMP_READ_DONE              0xFE
+
+struct memory_type_mapping {
+       u8 mem_name[FW_DUMP_MAX_NAME_LEN];
+       u8 *mem_ptr;
+       u32 mem_size;
+       u8 done_flag;
+};
+
+enum rdwr_status {
+       RDWR_STATUS_SUCCESS = 0,
+       RDWR_STATUS_FAILURE = 1,
+       RDWR_STATUS_DONE = 2
+};
+
 #endif /* !_MWIFIEX_DECL_H_ */
index ced7af2be29a3259eed41f33b0ea7ecea327e047..c134cf8652910b0381421f9e7c6ed746401ac719 100644 (file)
@@ -96,7 +96,7 @@ enum KEY_TYPE_ID {
 #define WAPI_KEY_LEN                   (WLAN_KEY_LEN_SMS4 + PN_LEN + 2)
 
 #define MAX_POLL_TRIES                 100
-#define MAX_FIRMWARE_POLL_TRIES                        100
+#define MAX_FIRMWARE_POLL_TRIES                        150
 
 #define FIRMWARE_READY_SDIO                            0xfedc
 #define FIRMWARE_READY_PCIE                            0xfedcba00
@@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
 #define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
 #define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30)
 #define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
 #define TLV_TYPE_STA_MAC_ADDR       (PROPRIETARY_TLV_BASE_ID + 32)
 #define TLV_TYPE_BSSID              (PROPRIETARY_TLV_BASE_ID + 35)
@@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_TX_PAUSE           (PROPRIETARY_TLV_BASE_ID + 148)
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
+#define TLV_TYPE_REPEAT_COUNT       (PROPRIETARY_TLV_BASE_ID + 176)
 #define TLV_TYPE_MULTI_CHAN_INFO    (PROPRIETARY_TLV_BASE_ID + 183)
 #define TLV_TYPE_MC_GROUP_INFO      (PROPRIETARY_TLV_BASE_ID + 184)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
@@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_MAC_ADDRESS                0x004D
 #define HostCmd_CMD_802_11D_DOMAIN_INFO               0x005b
 #define HostCmd_CMD_802_11_KEY_MATERIAL               0x005e
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG             0x006b
 #define HostCmd_CMD_802_11_BG_SCAN_QUERY              0x006c
 #define HostCmd_CMD_WMM_GET_STATUS                    0x0071
 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
@@ -370,6 +373,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_MGMT_FRAME_REG                    0x010c
 #define HostCmd_CMD_REMAIN_ON_CHAN                    0x010d
 #define HostCmd_CMD_11AC_CFG                         0x0112
+#define HostCmd_CMD_HS_WAKEUP_REASON                  0x0116
 #define HostCmd_CMD_TDLS_CONFIG                       0x0100
 #define HostCmd_CMD_MC_POLICY                         0x0121
 #define HostCmd_CMD_TDLS_OPER                         0x0122
@@ -523,6 +527,7 @@ enum P2P_MODES {
 #define EVENT_CHANNEL_REPORT_RDY        0x00000054
 #define EVENT_TX_DATA_PAUSE             0x00000055
 #define EVENT_EXT_SCAN_REPORT           0x00000058
+#define EVENT_BG_SCAN_STOPPED           0x00000065
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 #define EVENT_MULTI_CHAN_INFO           0x0000006a
 #define EVENT_TX_STATUS_REPORT         0x00000074
@@ -539,6 +544,8 @@ enum P2P_MODES {
 
 #define MWIFIEX_MAX_PATTERN_LEN                40
 #define MWIFIEX_MAX_OFFSET_LEN         100
+#define MWIFIEX_MAX_ND_MATCH_SETS      10
+
 #define STACK_NBYTES                   100
 #define TYPE_DNUM                      1
 #define TYPE_BYTESEQ                   2
@@ -601,6 +608,20 @@ struct mwifiex_ie_types_data {
 #define MWIFIEX_RXPD_FLAGS_TDLS_PACKET      0x01
 #define MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS    0x20
 
+enum HS_WAKEUP_REASON {
+       NO_HSWAKEUP_REASON = 0,
+       BCAST_DATA_MATCHED,
+       MCAST_DATA_MATCHED,
+       UCAST_DATA_MATCHED,
+       MASKTABLE_EVENT_MATCHED,
+       NON_MASKABLE_EVENT_MATCHED,
+       NON_MASKABLE_CONDITION_MATCHED,
+       MAGIC_PATTERN_MATCHED,
+       CONTROL_FRAME_MATCHED,
+       MANAGEMENT_FRAME_MATCHED,
+       RESERVED
+};
+
 struct txpd {
        u8 bss_type;
        u8 bss_num;
@@ -733,6 +754,21 @@ struct mwifiex_ie_types_num_probes {
        __le16 num_probes;
 } __packed;
 
+struct mwifiex_ie_types_repeat_count {
+       struct mwifiex_ie_types_header header;
+       __le16 repeat_count;
+} __packed;
+
+struct mwifiex_ie_types_min_rssi_threshold {
+       struct mwifiex_ie_types_header header;
+       __le16 rssi_threshold;
+} __packed;
+
+struct mwifiex_ie_types_bgscan_start_later {
+       struct mwifiex_ie_types_header header;
+       __le16 start_later;
+} __packed;
+
 struct mwifiex_ie_types_scan_chan_gap {
        struct mwifiex_ie_types_header header;
        /* time gap in TUs to be used between two consecutive channels scan */
@@ -1027,7 +1063,7 @@ struct ieee_types_assoc_rsp {
        __le16 cap_info_bitmap;
        __le16 status_code;
        __le16 a_id;
-       u8 ie_buffer[1];
+       u8 ie_buffer[0];
 } __packed;
 
 struct host_cmd_ds_802_11_associate_rsp {
@@ -1425,6 +1461,36 @@ struct mwifiex_user_scan_cfg {
        u16 scan_chan_gap;
 } __packed;
 
+#define MWIFIEX_BG_SCAN_CHAN_MAX 38
+#define MWIFIEX_BSS_MODE_INFRA 1
+#define MWIFIEX_BGSCAN_ACT_GET     0x0000
+#define MWIFIEX_BGSCAN_ACT_SET     0x0001
+#define MWIFIEX_BGSCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define MWIFIEX_BGSCAN_SSID_MATCH          0x0001
+/** ssid match and RSSI exceeded */
+#define MWIFIEX_BGSCAN_SSID_RSSI_MATCH     0x0004
+/**wait for all channel scan to complete to report scan result*/
+#define MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE  0x80000000
+
+struct mwifiex_bg_scan_cfg {
+       u16 action;
+       u8 enable;
+       u8 bss_type;
+       u8 chan_per_scan;
+       u32 scan_interval;
+       u32 report_condition;
+       u8 num_probes;
+       u8 rssi_threshold;
+       u8 snr_threshold;
+       u16 repeat_count;
+       u16 start_later;
+       struct cfg80211_match_set *ssid_list;
+       u8 num_ssids;
+       struct mwifiex_user_scan_chan chan_list[MWIFIEX_BG_SCAN_CHAN_MAX];
+       u16 scan_chan_gap;
+} __packed;
+
 struct ie_body {
        u8 grp_key_oui[4];
        u8 ptk_cnt[2];
@@ -1470,6 +1536,20 @@ struct mwifiex_ie_types_bss_scan_info {
        __le64 tsf;
 } __packed;
 
+struct host_cmd_ds_802_11_bg_scan_config {
+       __le16 action;
+       u8 enable;
+       u8 bss_type;
+       u8 chan_per_scan;
+       u8 reserved;
+       __le16 reserved1;
+       __le32 scan_interval;
+       __le32 reserved2;
+       __le32 report_condition;
+       __le16 reserved3;
+       u8 tlv[0];
+} __packed;
+
 struct host_cmd_ds_802_11_bg_scan_query {
        u8 flush;
 } __packed;
@@ -2099,6 +2179,10 @@ struct host_cmd_ds_robust_coex {
        __le16 reserved;
 } __packed;
 
+struct host_cmd_ds_wakeup_reason {
+       u16  wakeup_reason;
+} __packed;
+
 struct host_cmd_ds_command {
        __le16 command;
        __le16 size;
@@ -2124,6 +2208,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_802_11_scan scan;
                struct host_cmd_ds_802_11_scan_ext ext_scan;
                struct host_cmd_ds_802_11_scan_rsp scan_resp;
+               struct host_cmd_ds_802_11_bg_scan_config bg_scan_config;
                struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
                struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
                struct host_cmd_ds_802_11_associate associate;
@@ -2170,6 +2255,7 @@ struct host_cmd_ds_command {
                struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg;
                struct host_cmd_ds_multi_chan_policy mc_policy;
                struct host_cmd_ds_robust_coex coex;
+               struct host_cmd_ds_wakeup_reason hs_wakeup_reason;
        } params;
 } __packed;
 
index 6f7876ec31b7a6af705593139318df63bfd77a84..517653b3adabd8481edc73cd8eb08046e44f8484 100644 (file)
@@ -741,8 +741,6 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
        u32 poll_num = 1;
 
        if (adapter->if_ops.check_fw_status) {
-               adapter->winner = 0;
-
                /* check if firmware is already running */
                ret = adapter->if_ops.check_fw_status(adapter, poll_num);
                if (!ret) {
@@ -750,13 +748,23 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                                    "WLAN FW already running! Skip FW dnld\n");
                        return 0;
                }
+       }
+
+       /* check if we are the winner for downloading FW */
+       if (adapter->if_ops.check_winner_status) {
+               adapter->winner = 0;
+               ret = adapter->if_ops.check_winner_status(adapter);
 
                poll_num = MAX_FIRMWARE_POLL_TRIES;
+               if (ret) {
+                       mwifiex_dbg(adapter, MSG,
+                                   "WLAN read winner status failed!\n");
+                       return ret;
+               }
 
-               /* check if we are the winner for downloading FW */
                if (!adapter->winner) {
                        mwifiex_dbg(adapter, MSG,
-                                   "FW already running! Skip FW dnld\n");
+                                   "WLAN is not the winner! Skip FW dnld\n");
                        goto poll_fw;
                }
        }
index 4f0174c649461ed3ac219419cb676921f31a66e6..a5a48c183d375e4e1214a3618d03401ab5c4069a 100644 (file)
@@ -184,6 +184,7 @@ struct mwifiex_ds_tx_ba_stream_tbl {
 };
 
 #define DBG_CMD_NUM    5
+#define MWIFIEX_DBG_SDIO_MP_NUM    10
 
 struct tdls_peer_info {
        u8 peer_addr[ETH_ALEN];
@@ -235,6 +236,11 @@ struct mwifiex_debug_info {
        u8 cmd_sent;
        u8 cmd_resp_received;
        u8 event_received;
+       u32 last_mp_wr_bitmap[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_wr_ports[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_wr_len[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_curr_wr_port[MWIFIEX_DBG_SDIO_MP_NUM];
+       u8 last_sdio_mp_index;
 };
 
 #define MWIFIEX_KEY_INDEX_UNICAST      0x40000000
@@ -271,6 +277,10 @@ struct mwifiex_ds_hs_cfg {
        u32 gap;
 };
 
+struct mwifiex_ds_wakeup_reason {
+       u16  hs_wakeup_reason;
+};
+
 #define DEEP_SLEEP_ON  1
 #define DEEP_SLEEP_OFF 0
 #define DEEP_SLEEP_IDLE_TIME   100
@@ -414,6 +424,7 @@ struct mwifiex_ds_mef_cfg {
 #define MWIFIEX_VSIE_MASK_SCAN     0x01
 #define MWIFIEX_VSIE_MASK_ASSOC    0x02
 #define MWIFIEX_VSIE_MASK_ADHOC    0x04
+#define MWIFIEX_VSIE_MASK_BGSCAN   0x08
 
 enum {
        MWIFIEX_FUNC_INIT = 1,
index cc09a81dbf6a8eac3f4b4ac8ee84839bcbafe811..62211fca91b7456ff71fae76be6e0ffe9a01753f 100644 (file)
@@ -644,6 +644,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
        struct mwifiex_bssdescriptor *bss_desc;
        bool enable_data = true;
        u16 cap_info, status_code, aid;
+       const u8 *ie_ptr;
+       struct ieee80211_ht_operation *assoc_resp_ht_oper;
 
        assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
 
@@ -733,6 +735,19 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
                        = ((bss_desc->wmm_ie.qos_info_bitmap &
                                IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
 
+       /* Store the bandwidth information from assoc response */
+       ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer,
+                                 priv->assoc_rsp_size
+                                 - sizeof(struct ieee_types_assoc_rsp));
+       if (ie_ptr) {
+               assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr
+                                       + sizeof(struct ieee_types_header));
+               priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param;
+               priv->ht_param_present = true;
+       } else {
+               priv->ht_param_present = false;
+       }
+
        mwifiex_dbg(priv->adapter, INFO,
                    "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
                    priv->curr_pkt_filter);
index 79c16de8743e1945262f49aa82ec18f9022a2d2f..3cfa94677a8e2384bcbcc7ed188baf02814b84c9 100644 (file)
@@ -132,6 +132,13 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
                }
        }
 
+       if (adapter->nd_info) {
+               for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
+                       kfree(adapter->nd_info->matches[i]);
+               kfree(adapter->nd_info);
+               adapter->nd_info = NULL;
+       }
+
        vfree(adapter->chan_stats);
        kfree(adapter);
        return 0;
@@ -746,6 +753,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
 
        mwifiex_queue_main_work(priv->adapter);
 
+       if (priv->sched_scanning) {
+               mwifiex_dbg(priv->adapter, INFO,
+                           "aborting bgscan on ndo_stop\n");
+               mwifiex_stop_bg_scan(priv);
+               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+       }
+
        return 0;
 }
 
index 2f7f478ce04b6d9ea179022bb52ff92c97255026..aafc4ab4e5aed3f65e09f8231e8262ce27520162 100644 (file)
@@ -198,6 +198,11 @@ do {                                                               \
                               buf, len, false);                \
 } while (0)
 
+/** Min BGSCAN interval 15 second */
+#define MWIFIEX_BGSCAN_INTERVAL 15000
+/** default repeat count */
+#define MWIFIEX_BGSCAN_REPEAT_COUNT 6
+
 struct mwifiex_dbg {
        u32 num_cmd_host_to_card_failure;
        u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -218,6 +223,11 @@ struct mwifiex_dbg {
        u16 last_cmd_resp_index;
        u16 last_event[DBG_CMD_NUM];
        u16 last_event_index;
+       u32 last_mp_wr_bitmap[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_wr_ports[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_wr_len[MWIFIEX_DBG_SDIO_MP_NUM];
+       u32 last_mp_curr_wr_port[MWIFIEX_DBG_SDIO_MP_NUM];
+       u8 last_sdio_mp_index;
 };
 
 enum MWIFIEX_HARDWARE_STATUS {
@@ -293,6 +303,7 @@ struct mwifiex_tid_tbl {
 #define WMM_HIGHEST_PRIORITY           7
 #define HIGH_PRIO_TID                          7
 #define LOW_PRIO_TID                           0
+#define MWIFIEX_WMM_DRV_DELAY_MAX 510
 
 struct mwifiex_wmm_desc {
        struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -483,26 +494,6 @@ struct mwifiex_roc_cfg {
        struct ieee80211_channel chan;
 };
 
-#define MWIFIEX_FW_DUMP_IDX            0xff
-#define MWIFIEX_DRV_INFO_IDX           20
-#define FW_DUMP_MAX_NAME_LEN           8
-#define FW_DUMP_HOST_READY             0xEE
-#define FW_DUMP_DONE                   0xFF
-#define FW_DUMP_READ_DONE              0xFE
-
-struct memory_type_mapping {
-       u8 mem_name[FW_DUMP_MAX_NAME_LEN];
-       u8 *mem_ptr;
-       u32 mem_size;
-       u8 done_flag;
-};
-
-enum rdwr_status {
-       RDWR_STATUS_SUCCESS = 0,
-       RDWR_STATUS_FAILURE = 1,
-       RDWR_STATUS_DONE = 2
-};
-
 enum mwifiex_iface_work_flags {
        MWIFIEX_IFACE_WORK_DEVICE_DUMP,
        MWIFIEX_IFACE_WORK_CARD_RESET,
@@ -616,6 +607,7 @@ struct mwifiex_private {
        spinlock_t curr_bcn_buf_lock;
        struct wireless_dev wdev;
        struct mwifiex_chan_freq_power cfp;
+       u32 versionstrsel;
        char version_str[128];
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dfs_dev_dir;
@@ -640,6 +632,7 @@ struct mwifiex_private {
        u32 mgmt_frame_mask;
        struct mwifiex_roc_cfg roc_cfg;
        bool scan_aborting;
+       u8 sched_scanning;
        u8 csa_chan;
        unsigned long csa_expire_time;
        u8 del_list_idx;
@@ -667,6 +660,8 @@ struct mwifiex_private {
        struct mwifiex_ds_mem_rw mem_rw;
        struct sk_buff_head bypass_txq;
        struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];
+       u8 assoc_resp_ht_param;
+       bool ht_param_present;
 };
 
 
@@ -791,6 +786,7 @@ struct mwifiex_if_ops {
        int (*init_if) (struct mwifiex_adapter *);
        void (*cleanup_if) (struct mwifiex_adapter *);
        int (*check_fw_status) (struct mwifiex_adapter *, u32);
+       int (*check_winner_status)(struct mwifiex_adapter *);
        int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
        int (*register_dev) (struct mwifiex_adapter *);
        void (*unregister_dev) (struct mwifiex_adapter *);
@@ -994,6 +990,7 @@ struct mwifiex_adapter {
        u8 active_scan_triggered;
        bool usb_mc_status;
        bool usb_mc_setup;
+       struct cfg80211_wowlan_nd_info *nd_info;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1196,6 +1193,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
                                struct host_cmd_ds_command *resp);
 int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
                                         void *buf);
+int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
+                                     struct host_cmd_ds_command *cmd,
+                                     void *data_buf);
+int mwifiex_stop_bg_scan(struct mwifiex_private *priv);
 
 /*
  * This function checks if the queuing is RA based or not.
@@ -1417,7 +1418,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
 
 int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len);
 
-int mwifiex_get_ver_ext(struct mwifiex_private *priv);
+int mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel);
 
 int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
                               struct ieee80211_channel *chan,
@@ -1586,6 +1587,12 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter);
 void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
 void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
 void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
+int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
+                             int cmd_type,
+                             struct mwifiex_ds_wakeup_reason *wakeup_reason);
+int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv,
+                             struct host_cmd_ds_command *resp,
+                             struct host_cmd_ds_wakeup_reason *wakeup_reason);
 void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);
 void mwifiex_11n_delba(struct mwifiex_private *priv, int tid);
 int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy);
index 6d0dc40e20e5c535f127e69743e046162fb71138..de364381fe7be82d76c1bb282f7aa0649e1c586b 100644 (file)
@@ -37,17 +37,6 @@ static struct mwifiex_if_ops pcie_ops;
 
 static struct semaphore add_remove_card_sem;
 
-static struct memory_type_mapping mem_type_mapping_tbl[] = {
-       {"ITCM", NULL, 0, 0xF0},
-       {"DTCM", NULL, 0, 0xF1},
-       {"SQRAM", NULL, 0, 0xF2},
-       {"IRAM", NULL, 0, 0xF3},
-       {"APU", NULL, 0, 0xF4},
-       {"CIU", NULL, 0, 0xF5},
-       {"ICU", NULL, 0, 0xF6},
-       {"MAC", NULL, 0, 0xF7},
-};
-
 static int
 mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
                       size_t size, int flags)
@@ -206,6 +195,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
                card->pcie.blksz_fw_dl = data->blksz_fw_dl;
                card->pcie.tx_buf_size = data->tx_buf_size;
                card->pcie.can_dump_fw = data->can_dump_fw;
+               card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl;
+               card->pcie.num_mem_types = data->num_mem_types;
                card->pcie.can_ext_scan = data->can_ext_scan;
        }
 
@@ -323,6 +314,8 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
        struct pcie_service_card *card = adapter->card;
 
        *data = ioread32(card->pci_mmap1 + reg);
+       if (*data == 0xffffffff)
+               return 0xffffffff;
 
        return 0;
 }
@@ -1408,7 +1401,7 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                return -1;
        }
 
-       if (mwifiex_map_pci_memory(adapter, skb, skb->len , PCI_DMA_TODEVICE))
+       if (mwifiex_map_pci_memory(adapter, skb, skb->len, PCI_DMA_TODEVICE))
                return -1;
 
        buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
@@ -2007,14 +2000,12 @@ done:
 
 /*
  * This function checks the firmware status in card.
- *
- * The winner interface is also determined by this function.
  */
 static int
 mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 {
        int ret = 0;
-       u32 firmware_stat, winner_status;
+       u32 firmware_stat;
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
        u32 tries;
@@ -2054,19 +2045,28 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
                }
        }
 
-       if (ret) {
-               if (mwifiex_read_reg(adapter, reg->fw_status,
-                                    &winner_status))
-                       ret = -1;
-               else if (!winner_status) {
-                       mwifiex_dbg(adapter, INFO,
-                                   "PCI-E is the winner\n");
-                       adapter->winner = 1;
-               } else {
-                       mwifiex_dbg(adapter, ERROR,
-                                   "PCI-E is not the winner <%#x,%d>, exit dnld\n",
-                                   ret, adapter->winner);
-               }
+       return ret;
+}
+
+/* This function checks if WLAN is the winner.
+ */
+static int
+mwifiex_check_winner_status(struct mwifiex_adapter *adapter)
+{
+       u32 winner = 0;
+       int ret = 0;
+       struct pcie_service_card *card = adapter->card;
+       const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+       if (mwifiex_read_reg(adapter, reg->fw_status, &winner)) {
+               ret = -1;
+       } else if (!winner) {
+               mwifiex_dbg(adapter, INFO, "PCI-E is the winner\n");
+               adapter->winner = 1;
+       } else {
+               mwifiex_dbg(adapter, ERROR,
+                           "PCI-E is not the winner <%#x,%d>, exit dnld\n",
+                           ret, adapter->winner);
        }
 
        return ret;
@@ -2075,20 +2075,28 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 /*
  * This function reads the interrupt status from card.
  */
-static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
+                                    int msg_id)
 {
        u32 pcie_ireg;
        unsigned long flags;
+       struct pcie_service_card *card = adapter->card;
 
        if (!mwifiex_pcie_ok_to_access_hw(adapter))
                return;
 
-       if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
-               mwifiex_dbg(adapter, ERROR, "Read register failed\n");
-               return;
-       }
+       if (card->msix_enable && msg_id >= 0) {
+               pcie_ireg = BIT(msg_id);
+       } else {
+               if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+                                    &pcie_ireg)) {
+                       mwifiex_dbg(adapter, ERROR, "Read register failed\n");
+                       return;
+               }
+
+               if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
+                       return;
 
-       if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
 
                mwifiex_pcie_disable_host_int(adapter);
 
@@ -2099,21 +2107,24 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
                                    "Write register failed\n");
                        return;
                }
-               spin_lock_irqsave(&adapter->int_lock, flags);
-               adapter->int_status |= pcie_ireg;
-               spin_unlock_irqrestore(&adapter->int_lock, flags);
-
-               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 */
-                               adapter->ps_state = PS_STATE_AWAKE;
-                               adapter->pm_wakeup_fw_try = false;
-                               del_timer(&adapter->wakeup_timer);
-               }
        }
+
+       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
+                */
+               adapter->ps_state = PS_STATE_AWAKE;
+               adapter->pm_wakeup_fw_try = false;
+               del_timer(&adapter->wakeup_timer);
+       }
+
+       spin_lock_irqsave(&adapter->int_lock, flags);
+       adapter->int_status |= pcie_ireg;
+       spin_unlock_irqrestore(&adapter->int_lock, flags);
+       mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
 }
 
 /*
@@ -2124,7 +2135,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
  */
 static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
 {
-       struct pci_dev *pdev = (struct pci_dev *)context;
+       struct mwifiex_msix_context *ctx = context;
+       struct pci_dev *pdev = ctx->dev;
        struct pcie_service_card *card;
        struct mwifiex_adapter *adapter;
 
@@ -2144,7 +2156,11 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
        if (adapter->surprise_removed)
                goto exit;
 
-       mwifiex_interrupt_status(adapter);
+       if (card->msix_enable)
+               mwifiex_interrupt_status(adapter, ctx->msg_id);
+       else
+               mwifiex_interrupt_status(adapter, -1);
+
        mwifiex_queue_main_work(adapter);
 
 exit:
@@ -2164,7 +2180,7 @@ exit:
  * In case of Rx packets received, the packets are uploaded from card to
  * host and processed accordingly.
  */
-static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
 {
        int ret;
        u32 pcie_ireg;
@@ -2244,6 +2260,69 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
        return 0;
 }
 
+static int mwifiex_process_msix_int(struct mwifiex_adapter *adapter)
+{
+       int ret;
+       u32 pcie_ireg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->int_lock, flags);
+       /* Clear out unused interrupts */
+       pcie_ireg = adapter->int_status;
+       adapter->int_status = 0;
+       spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+       if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: TX DNLD Done\n");
+               ret = mwifiex_pcie_send_data_complete(adapter);
+               if (ret)
+                       return ret;
+       }
+       if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: Rx DATA\n");
+               ret = mwifiex_pcie_process_recv_data(adapter);
+               if (ret)
+                       return ret;
+       }
+       if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: Rx EVENT\n");
+               ret = mwifiex_pcie_process_event_ready(adapter);
+               if (ret)
+                       return ret;
+       }
+
+       if (pcie_ireg & HOST_INTR_CMD_DONE) {
+               if (adapter->cmd_sent) {
+                       mwifiex_dbg(adapter, INTR,
+                                   "info: CMD sent Interrupt\n");
+                       adapter->cmd_sent = false;
+               }
+               /* Handle command response */
+               ret = mwifiex_pcie_process_cmd_complete(adapter);
+               if (ret)
+                       return ret;
+       }
+
+       mwifiex_dbg(adapter, INTR,
+                   "info: cmd_sent=%d data_sent=%d\n",
+                   adapter->cmd_sent, adapter->data_sent);
+
+       return 0;
+}
+
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       if (card->msix_enable)
+               return mwifiex_process_msix_int(adapter);
+       else
+               return mwifiex_process_pcie_int(adapter);
+}
+
 /*
  * This function downloads data from driver to card.
  *
@@ -2278,10 +2357,15 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
 {
        int ret, tries;
        u8 ctrl_data;
+       u32 fw_status;
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-       ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY);
+       if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status))
+               return RDWR_STATUS_FAILURE;
+
+       ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
+                               reg->fw_dump_host_ready);
        if (ret) {
                mwifiex_dbg(adapter, ERROR,
                            "PCIE write err\n");
@@ -2294,11 +2378,11 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
                        return RDWR_STATUS_SUCCESS;
                if (doneflag && ctrl_data == doneflag)
                        return RDWR_STATUS_DONE;
-               if (ctrl_data != FW_DUMP_HOST_READY) {
+               if (ctrl_data != reg->fw_dump_host_ready) {
                        mwifiex_dbg(adapter, WARN,
                                    "The ctrl reg was changed, re-try again!\n");
                        ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
-                                               FW_DUMP_HOST_READY);
+                                               reg->fw_dump_host_ready);
                        if (ret) {
                                mwifiex_dbg(adapter, ERROR,
                                            "PCIE write err\n");
@@ -2318,7 +2402,8 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
        unsigned int reg, reg_start, reg_end;
-       u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
+       u8 *dbg_ptr, *end_ptr, *tmp_ptr, fw_dump_num, dump_num;
+       u8 idx, i, read_reg, doneflag = 0;
        enum rdwr_status stat;
        u32 memory_size;
        int ret;
@@ -2326,8 +2411,9 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
        if (!card->pcie.can_dump_fw)
                return;
 
-       for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
-               struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
+       for (idx = 0; idx < adapter->num_mem_types; idx++) {
+               struct memory_type_mapping *entry =
+                               &adapter->mem_type_mapping_tbl[idx];
 
                if (entry->mem_ptr) {
                        vfree(entry->mem_ptr);
@@ -2336,7 +2422,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                entry->mem_size = 0;
        }
 
-       mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump start ==\n");
+       mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
 
        /* Read the number of the memories which will dump */
        stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
@@ -2344,28 +2430,38 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                return;
 
        reg = creg->fw_dump_start;
-       mwifiex_read_reg_byte(adapter, reg, &dump_num);
+       mwifiex_read_reg_byte(adapter, reg, &fw_dump_num);
+
+       /* W8997 chipset firmware dump will be restore in single region*/
+       if (fw_dump_num == 0)
+               dump_num = 1;
+       else
+               dump_num = fw_dump_num;
 
        /* Read the length of every memory which will dump */
        for (idx = 0; idx < dump_num; idx++) {
-               struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
-
-               stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
-               if (stat == RDWR_STATUS_FAILURE)
-                       return;
-
+               struct memory_type_mapping *entry =
+                               &adapter->mem_type_mapping_tbl[idx];
                memory_size = 0;
-               reg = creg->fw_dump_start;
-               for (i = 0; i < 4; i++) {
-                       mwifiex_read_reg_byte(adapter, reg, &read_reg);
-                       memory_size |= (read_reg << (i * 8));
-                       reg++;
+               if (fw_dump_num != 0) {
+                       stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
+                       if (stat == RDWR_STATUS_FAILURE)
+                               return;
+
+                       reg = creg->fw_dump_start;
+                       for (i = 0; i < 4; i++) {
+                               mwifiex_read_reg_byte(adapter, reg, &read_reg);
+                               memory_size |= (read_reg << (i * 8));
+                               reg++;
+                       }
+               } else {
+                       memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE;
                }
 
                if (memory_size == 0) {
                        mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
                        ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
-                                               FW_DUMP_READ_DONE);
+                                               creg->fw_dump_read_done);
                        if (ret) {
                                mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
                                return;
@@ -2400,11 +2496,21 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                                mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
                                if (dbg_ptr < end_ptr) {
                                        dbg_ptr++;
-                               } else {
-                                       mwifiex_dbg(adapter, ERROR,
-                                                   "Allocated buf not enough\n");
-                                       return;
+                                       continue;
                                }
+                               mwifiex_dbg(adapter, ERROR,
+                                           "pre-allocated buf not enough\n");
+                               tmp_ptr =
+                                       vzalloc(memory_size + MWIFIEX_SIZE_4K);
+                               if (!tmp_ptr)
+                                       return;
+                               memcpy(tmp_ptr, entry->mem_ptr, memory_size);
+                               vfree(entry->mem_ptr);
+                               entry->mem_ptr = tmp_ptr;
+                               tmp_ptr = NULL;
+                               dbg_ptr = entry->mem_ptr + memory_size;
+                               memory_size += MWIFIEX_SIZE_4K;
+                               end_ptr = entry->mem_ptr + memory_size;
                        }
 
                        if (stat != RDWR_STATUS_DONE)
@@ -2416,7 +2522,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                        break;
                } while (true);
        }
-       mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n");
+       mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
 }
 
 static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
@@ -2595,10 +2701,43 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
 
 static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
 {
-       int ret;
+       int ret, i, j;
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
 
+       if (card->pcie.reg->msix_support) {
+               for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                       card->msix_entries[i].entry = i;
+               ret = pci_enable_msix_exact(pdev, card->msix_entries,
+                                           MWIFIEX_NUM_MSIX_VECTORS);
+               if (!ret) {
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) {
+                               card->msix_ctx[i].dev = pdev;
+                               card->msix_ctx[i].msg_id = i;
+
+                               ret = request_irq(card->msix_entries[i].vector,
+                                                 mwifiex_pcie_interrupt, 0,
+                                                 "MWIFIEX_PCIE_MSIX",
+                                                 &card->msix_ctx[i]);
+                               if (ret)
+                                       break;
+                       }
+
+                       if (ret) {
+                               mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n",
+                                           ret);
+                               for (j = 0; j < i; j++)
+                                       free_irq(card->msix_entries[j].vector,
+                                                &card->msix_ctx[i]);
+                               pci_disable_msix(pdev);
+                       } else {
+                               mwifiex_dbg(adapter, MSG, "MSIx enabled!");
+                               card->msix_enable = 1;
+                               return 0;
+                       }
+               }
+       }
+
        if (pci_enable_msi(pdev) != 0)
                pci_disable_msi(pdev);
        else
@@ -2606,8 +2745,10 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
 
        mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable);
 
+       card->share_irq_ctx.dev = pdev;
+       card->share_irq_ctx.msg_id = -1;
        ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
-                         "MRVL_PCIE", pdev);
+                         "MRVL_PCIE", &card->share_irq_ctx);
        if (ret) {
                pr_err("request_irq failed: ret=%d\n", ret);
                adapter->card = NULL;
@@ -2635,8 +2776,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
                return -1;
 
        adapter->tx_buf_size = card->pcie.tx_buf_size;
-       adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
-       adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
+       adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl;
+       adapter->num_mem_types = card->pcie.num_mem_types;
        strcpy(adapter->fw_name, card->pcie.firmware);
        adapter->ext_scan = card->pcie.can_ext_scan;
 
@@ -2653,11 +2794,28 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg;
+       struct pci_dev *pdev = card->dev;
+       int i;
 
        if (card) {
-               mwifiex_dbg(adapter, INFO,
-                           "%s(): calling free_irq()\n", __func__);
-               free_irq(card->dev->irq, card->dev);
+               if (card->msix_enable) {
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                               synchronize_irq(card->msix_entries[i].vector);
+
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                               free_irq(card->msix_entries[i].vector,
+                                        &card->msix_ctx[i]);
+
+                       card->msix_enable = 0;
+                       pci_disable_msix(pdev);
+              } else {
+                       mwifiex_dbg(adapter, INFO,
+                                   "%s(): calling free_irq()\n", __func__);
+                      free_irq(card->dev->irq, &card->share_irq_ctx);
+
+                       if (card->msi_enable)
+                               pci_disable_msi(pdev);
+              }
 
                reg = card->pcie.reg;
                if (reg->sleep_cookie)
@@ -2675,6 +2833,7 @@ static struct mwifiex_if_ops pcie_ops = {
        .init_if =                      mwifiex_pcie_init,
        .cleanup_if =                   mwifiex_pcie_cleanup,
        .check_fw_status =              mwifiex_check_fw_status,
+       .check_winner_status =          mwifiex_check_winner_status,
        .prog_fw =                      mwifiex_prog_fw_w_helper,
        .register_dev =                 mwifiex_register_dev,
        .unregister_dev =               mwifiex_unregister_dev,
index 6fc28737b576c64b1ac52d0199611cb81c8bad2b..29e58ce877e349649c747080bce913f1063362c8 100644 (file)
@@ -26,6 +26,7 @@
 #include    <linux/pcieport_if.h>
 #include    <linux/interrupt.h>
 
+#include    "decl.h"
 #include    "main.h"
 
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
@@ -135,6 +136,9 @@ struct mwifiex_pcie_card_reg {
        u16 fw_dump_ctrl;
        u16 fw_dump_start;
        u16 fw_dump_end;
+       u8 fw_dump_host_ready;
+       u8 fw_dump_read_done;
+       u8 msix_support;
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
@@ -166,6 +170,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
        .ring_tx_start_ptr = 0,
        .pfu_enabled = 0,
        .sleep_cookie = 1,
+       .msix_support = 0,
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
@@ -200,6 +205,9 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
        .fw_dump_ctrl = 0xcf4,
        .fw_dump_start = 0xcf8,
        .fw_dump_end = 0xcff,
+       .fw_dump_host_ready = 0xee,
+       .fw_dump_read_done = 0xfe,
+       .msix_support = 0,
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
@@ -231,6 +239,27 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
        .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
        .pfu_enabled = 1,
        .sleep_cookie = 0,
+       .fw_dump_ctrl = 0xcf4,
+       .fw_dump_start = 0xcf8,
+       .fw_dump_end = 0xcff,
+       .fw_dump_host_ready = 0xcc,
+       .fw_dump_read_done = 0xdd,
+       .msix_support = 1,
+};
+
+static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = {
+       {"ITCM", NULL, 0, 0xF0},
+       {"DTCM", NULL, 0, 0xF1},
+       {"SQRAM", NULL, 0, 0xF2},
+       {"IRAM", NULL, 0, 0xF3},
+       {"APU", NULL, 0, 0xF4},
+       {"CIU", NULL, 0, 0xF5},
+       {"ICU", NULL, 0, 0xF6},
+       {"MAC", NULL, 0, 0xF7},
+};
+
+static struct memory_type_mapping mem_type_mapping_tbl_w8997[] = {
+       {"DUMP", NULL, 0, 0xDD},
 };
 
 struct mwifiex_pcie_device {
@@ -239,6 +268,8 @@ struct mwifiex_pcie_device {
        u16 blksz_fw_dl;
        u16 tx_buf_size;
        bool can_dump_fw;
+       struct memory_type_mapping *mem_type_mapping_tbl;
+       u8 num_mem_types;
        bool can_ext_scan;
 };
 
@@ -257,6 +288,8 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
        .can_dump_fw = true,
+       .mem_type_mapping_tbl = mem_type_mapping_tbl_w8897,
+       .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8897),
        .can_ext_scan = true,
 };
 
@@ -265,7 +298,9 @@ static const struct mwifiex_pcie_device mwifiex_pcie8997 = {
        .reg            = &mwifiex_reg_8997,
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
-       .can_dump_fw = false,
+       .can_dump_fw = true,
+       .mem_type_mapping_tbl = mem_type_mapping_tbl_w8997,
+       .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8997),
        .can_ext_scan = true,
 };
 
@@ -290,6 +325,13 @@ struct mwifiex_pfu_buf_desc {
        u32 reserved;
 } __packed;
 
+#define MWIFIEX_NUM_MSIX_VECTORS   4
+
+struct mwifiex_msix_context {
+       struct pci_dev *dev;
+       u16 msg_id;
+};
+
 struct pcie_service_card {
        struct pci_dev *dev;
        struct mwifiex_adapter *adapter;
@@ -327,6 +369,12 @@ struct pcie_service_card {
        void __iomem *pci_mmap;
        void __iomem *pci_mmap1;
        int msi_enable;
+       int msix_enable;
+#ifdef CONFIG_PCI
+       struct msix_entry msix_entries[MWIFIEX_NUM_MSIX_VECTORS];
+#endif
+       struct mwifiex_msix_context msix_ctx[MWIFIEX_NUM_MSIX_VECTORS];
+       struct mwifiex_msix_context share_irq_ctx;
 };
 
 static inline int
index c20017ced5667c796abec645ae5cc8ca620b530f..489f7a911a83f225561a2ddf902c637457b6b960 100644 (file)
@@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
        return chan_idx;
 }
 
+/* This function creates a channel list tlv for bgscan config, based
+ * on region/band information.
+ */
+static int
+mwifiex_bgscan_create_channel_list(struct mwifiex_private *priv,
+                                  const struct mwifiex_bg_scan_cfg
+                                               *bgscan_cfg_in,
+                                  struct mwifiex_chan_scan_param_set
+                                               *scan_chan_list)
+{
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       int chan_idx = 0, i;
+
+       for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
+               if (!priv->wdev.wiphy->bands[band])
+                       continue;
+
+               sband = priv->wdev.wiphy->bands[band];
+
+               for (i = 0; (i < sband->n_channels) ; i++) {
+                       ch = &sband->channels[i];
+                       if (ch->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+                       scan_chan_list[chan_idx].radio_type = band;
+
+                       if (bgscan_cfg_in->chan_list[0].scan_time)
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16((u16)bgscan_cfg_in->
+                                       chan_list[0].scan_time);
+                       else if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16(adapter->passive_scan_time);
+                       else
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16(adapter->
+                                                   specific_scan_time);
+
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                                       |= MWIFIEX_PASSIVE_SCAN;
+                       else
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                                       &= ~MWIFIEX_PASSIVE_SCAN;
+
+                       scan_chan_list[chan_idx].chan_number =
+                                                       (u32)ch->hw_value;
+                       chan_idx++;
+               }
+       }
+       return chan_idx;
+}
+
 /* This function appends rate TLV to scan config command. */
 static int
 mwifiex_append_rate_tlv(struct mwifiex_private *priv,
@@ -2037,6 +2092,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
        u8 is_bgscan_resp;
        __le64 fw_tsf = 0;
        u8 *radio_type;
+       struct cfg80211_wowlan_nd_match *pmatch;
+       struct cfg80211_sched_scan_request *nd_config = NULL;
 
        is_bgscan_resp = (le16_to_cpu(resp->command)
                          == HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -2099,6 +2156,21 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                             (struct mwifiex_ie_types_data **)
                                             &chan_band_tlv);
 
+#ifdef CONFIG_PM
+       if (priv->wdev.wiphy->wowlan_config)
+               nd_config = priv->wdev.wiphy->wowlan_config->nd_config;
+#endif
+
+       if (nd_config) {
+               adapter->nd_info =
+                       kzalloc(sizeof(struct cfg80211_wowlan_nd_match) +
+                               sizeof(struct cfg80211_wowlan_nd_match *) *
+                               scan_rsp->number_of_sets, GFP_ATOMIC);
+
+               if (adapter->nd_info)
+                       adapter->nd_info->n_matches = scan_rsp->number_of_sets;
+       }
+
        for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
                /*
                 * If the TSF TLV was appended to the scan results, save this
@@ -2117,6 +2189,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        radio_type = NULL;
                }
 
+               if (chan_band_tlv && adapter->nd_info) {
+                       adapter->nd_info->matches[idx] =
+                               kzalloc(sizeof(*pmatch) +
+                               sizeof(u32), GFP_ATOMIC);
+
+                       pmatch = adapter->nd_info->matches[idx];
+
+                       if (pmatch) {
+                               memset(pmatch, 0, sizeof(*pmatch));
+                               if (chan_band_tlv) {
+                                       pmatch->n_channels = 1;
+                                       pmatch->channels[0] =
+                                               chan_band->chan_number;
+                               }
+                       }
+               }
+
                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
                                                        &bytes_left,
                                                        le64_to_cpu(fw_tsf),
@@ -2155,6 +2244,227 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
        return 0;
 }
 
+/* This function prepares an background scan config command to be sent
+ * to the firmware
+ */
+int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
+                                     struct host_cmd_ds_command *cmd,
+                                     void *data_buf)
+{
+       struct host_cmd_ds_802_11_bg_scan_config *bgscan_config =
+                                       &cmd->params.bg_scan_config;
+       struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf;
+       u8 *tlv_pos = bgscan_config->tlv;
+       u8 num_probes;
+       u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num;
+       int i;
+       struct mwifiex_ie_types_num_probes *num_probes_tlv;
+       struct mwifiex_ie_types_repeat_count *repeat_count_tlv;
+       struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv;
+       struct mwifiex_ie_types_bgscan_start_later *start_later_tlv;
+       struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
+       struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv;
+       struct mwifiex_chan_scan_param_set *temp_chan;
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+       cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN);
+
+       bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action);
+       bgscan_config->enable = bgscan_cfg_in->enable;
+       bgscan_config->bss_type = bgscan_cfg_in->bss_type;
+       bgscan_config->scan_interval =
+               cpu_to_le32(bgscan_cfg_in->scan_interval);
+       bgscan_config->report_condition =
+               cpu_to_le32(bgscan_cfg_in->report_condition);
+
+       /*  stop sched scan  */
+       if (!bgscan_config->enable)
+               return 0;
+
+       bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan;
+
+       num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in->
+                     num_probes : priv->adapter->scan_probes);
+
+       if (num_probes) {
+               num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos;
+               num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
+               num_probes_tlv->header.len =
+                       cpu_to_le16(sizeof(num_probes_tlv->num_probes));
+               num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes);
+
+               tlv_pos += sizeof(num_probes_tlv->header) +
+                       le16_to_cpu(num_probes_tlv->header.len);
+       }
+
+       if (bgscan_cfg_in->repeat_count) {
+               repeat_count_tlv =
+                       (struct mwifiex_ie_types_repeat_count *)tlv_pos;
+               repeat_count_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
+               repeat_count_tlv->header.len =
+                       cpu_to_le16(sizeof(repeat_count_tlv->repeat_count));
+               repeat_count_tlv->repeat_count =
+                       cpu_to_le16(bgscan_cfg_in->repeat_count);
+
+               tlv_pos += sizeof(repeat_count_tlv->header) +
+                       le16_to_cpu(repeat_count_tlv->header.len);
+       }
+
+       if (bgscan_cfg_in->rssi_threshold) {
+               rssi_threshold_tlv =
+                       (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos;
+               rssi_threshold_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_RSSI_LOW);
+               rssi_threshold_tlv->header.len =
+                       cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold));
+               rssi_threshold_tlv->rssi_threshold =
+                       cpu_to_le16(bgscan_cfg_in->rssi_threshold);
+
+               tlv_pos += sizeof(rssi_threshold_tlv->header) +
+                       le16_to_cpu(rssi_threshold_tlv->header.len);
+       }
+
+       for (i = 0; i < bgscan_cfg_in->num_ssids; i++) {
+               ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len;
+
+               wildcard_ssid_tlv =
+                       (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos;
+               wildcard_ssid_tlv->header.type =
+                               cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+               wildcard_ssid_tlv->header.len = cpu_to_le16(
+                               (u16)(ssid_len + sizeof(wildcard_ssid_tlv->
+                                                        max_ssid_length)));
+
+               /* max_ssid_length = 0 tells firmware to perform
+                * specific scan for the SSID filled, whereas
+                * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
+                * wildcard scan.
+                */
+               if (ssid_len)
+                       wildcard_ssid_tlv->max_ssid_length = 0;
+               else
+                       wildcard_ssid_tlv->max_ssid_length =
+                                               IEEE80211_MAX_SSID_LEN;
+
+               memcpy(wildcard_ssid_tlv->ssid,
+                      bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len);
+
+               tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+                               + le16_to_cpu(wildcard_ssid_tlv->header.len));
+       }
+
+       chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos;
+
+       if (bgscan_cfg_in->chan_list[0].chan_number) {
+               dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n");
+
+               chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+               for (chan_idx = 0;
+                    chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX &&
+                    bgscan_cfg_in->chan_list[chan_idx].chan_number;
+                    chan_idx++) {
+                       temp_chan = chan_list_tlv->chan_scan_param + chan_idx;
+
+                       /* Increment the TLV header length by size appended */
+                       le16_add_cpu(&chan_list_tlv->header.len,
+                                    sizeof(chan_list_tlv->chan_scan_param));
+
+                       temp_chan->chan_number =
+                               bgscan_cfg_in->chan_list[chan_idx].chan_number;
+                       temp_chan->radio_type =
+                               bgscan_cfg_in->chan_list[chan_idx].radio_type;
+
+                       scan_type =
+                               bgscan_cfg_in->chan_list[chan_idx].scan_type;
+
+                       if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+                               temp_chan->chan_scan_mode_bitmap
+                                       |= MWIFIEX_PASSIVE_SCAN;
+                       else
+                               temp_chan->chan_scan_mode_bitmap
+                                       &= ~MWIFIEX_PASSIVE_SCAN;
+
+                       if (bgscan_cfg_in->chan_list[chan_idx].scan_time) {
+                               scan_dur = (u16)bgscan_cfg_in->
+                                       chan_list[chan_idx].scan_time;
+                       } else {
+                               scan_dur = (scan_type ==
+                                           MWIFIEX_SCAN_TYPE_PASSIVE) ?
+                                           priv->adapter->passive_scan_time :
+                                           priv->adapter->specific_scan_time;
+                       }
+
+                       temp_chan->min_scan_time = cpu_to_le16(scan_dur);
+                       temp_chan->max_scan_time = cpu_to_le16(scan_dur);
+               }
+       } else {
+               dev_dbg(priv->adapter->dev,
+                       "info: bgscan: Creating full region channel list\n");
+               chan_num =
+                       mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in,
+                                                          chan_list_tlv->
+                                                          chan_scan_param);
+               le16_add_cpu(&chan_list_tlv->header.len,
+                            chan_num *
+                            sizeof(chan_list_tlv->chan_scan_param[0]));
+       }
+
+       tlv_pos += (sizeof(chan_list_tlv->header)
+                       + le16_to_cpu(chan_list_tlv->header.len));
+
+       if (bgscan_cfg_in->start_later) {
+               start_later_tlv =
+                       (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos;
+               start_later_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER);
+               start_later_tlv->header.len =
+                       cpu_to_le16(sizeof(start_later_tlv->start_later));
+               start_later_tlv->start_later =
+                       cpu_to_le16(bgscan_cfg_in->start_later);
+
+               tlv_pos += sizeof(start_later_tlv->header) +
+                       le16_to_cpu(start_later_tlv->header.len);
+       }
+
+       /* Append vendor specific IE TLV */
+       mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos);
+
+       le16_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv);
+
+       return 0;
+}
+
+int mwifiex_stop_bg_scan(struct mwifiex_private *priv)
+{
+       struct mwifiex_bg_scan_cfg *bgscan_cfg;
+
+       if (!priv->sched_scanning) {
+               dev_dbg(priv->adapter->dev, "bgscan already stopped!\n");
+               return 0;
+       }
+
+       bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
+       if (!bgscan_cfg)
+               return -ENOMEM;
+
+       bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
+       bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
+       bgscan_cfg->enable = false;
+
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                            HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
+               kfree(bgscan_cfg);
+               return -EFAULT;
+       }
+
+       kfree(bgscan_cfg);
+       priv->sched_scanning = false;
+
+       return 0;
+}
+
 static void
 mwifiex_update_chan_statistics(struct mwifiex_private *priv,
                               struct mwifiex_ietypes_chanstats *tlv_stat)
index 4c8cae682c89c727de4518d3b78d42da388d0ac6..b2c839ae2c3c146e3d32786a2a99360fa254eb89 100644 (file)
@@ -181,7 +181,7 @@ static int mwifiex_sdio_resume(struct device *dev)
 
        /* Disable Host Sleep */
        mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
-                         MWIFIEX_ASYNC_CMD);
+                         MWIFIEX_SYNC_CMD);
 
        return 0;
 }
@@ -1039,19 +1039,14 @@ done:
 
 /*
  * This function checks the firmware status in card.
- *
- * The winner interface is also determined by this function.
  */
 static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
                                   u32 poll_num)
 {
-       struct sdio_mmc_card *card = adapter->card;
        int ret = 0;
        u16 firmware_stat;
        u32 tries;
-       u8 winner_status;
 
-       /* Wait for firmware initialization event */
        for (tries = 0; tries < poll_num; tries++) {
                ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
                if (ret)
@@ -1065,16 +1060,25 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
                }
        }
 
-       if (ret) {
-               if (mwifiex_read_reg
-                   (adapter, card->reg->status_reg_0, &winner_status))
-                       winner_status = 0;
+       return ret;
+}
+
+/* This function checks if WLAN is the winner.
+ */
+static int mwifiex_check_winner_status(struct mwifiex_adapter *adapter)
+{
+       int ret = 0;
+       u8 winner = 0;
+       struct sdio_mmc_card *card = adapter->card;
+
+       if (mwifiex_read_reg(adapter, card->reg->status_reg_0, &winner))
+               return -1;
+
+       if (winner)
+               adapter->winner = 0;
+       else
+               adapter->winner = 1;
 
-               if (winner_status)
-                       adapter->winner = 0;
-               else
-                       adapter->winner = 1;
-       }
        return ret;
 }
 
@@ -1351,6 +1355,9 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
                                 card->mpa_rx.start_port;
                }
 
+               if (card->mpa_rx.pkt_cnt == 1)
+                       mport = adapter->ioport + port;
+
                if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
                                           card->mpa_rx.buf_len, mport, 1))
                        goto error;
@@ -1680,6 +1687,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
        s32 f_precopy_cur_buf = 0;
        s32 f_postcopy_cur_buf = 0;
        u32 mport;
+       int index;
 
        if (!card->mpa_tx.enabled ||
            (card->has_control_mask && (port == CTRL_PORT)) ||
@@ -1781,9 +1789,21 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
                                 card->mpa_tx.start_port;
                }
 
+               if (card->mpa_tx.pkt_cnt == 1)
+                       mport = adapter->ioport + port;
+
                ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
                                                 card->mpa_tx.buf_len, mport);
 
+               /* Save the last multi port tx aggreagation info to debug log */
+               index = adapter->dbg.last_sdio_mp_index;
+               index = (index + 1) % MWIFIEX_DBG_SDIO_MP_NUM;
+               adapter->dbg.last_sdio_mp_index = index;
+               adapter->dbg.last_mp_wr_ports[index] = mport;
+               adapter->dbg.last_mp_wr_bitmap[index] = card->mp_wr_bitmap;
+               adapter->dbg.last_mp_wr_len[index] = card->mpa_tx.buf_len;
+               adapter->dbg.last_mp_curr_wr_port[index] = card->curr_wr_port;
+
                MP_TX_AGGR_BUF_RESET(card);
        }
 
@@ -2620,6 +2640,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .init_if = mwifiex_init_sdio,
        .cleanup_if = mwifiex_cleanup_sdio,
        .check_fw_status = mwifiex_check_fw_status,
+       .check_winner_status = mwifiex_check_winner_status,
        .prog_fw = mwifiex_prog_fw_w_helper,
        .register_dev = mwifiex_register_dev,
        .unregister_dev = mwifiex_unregister_dev,
index e486867a4c67520fc2a8a8520368009975fd8878..30f152601c5774e266219066acee03f2cb3b21a8 100644 (file)
@@ -1813,6 +1813,22 @@ static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd,
        return 0;
 }
 
+/* This function prepares command to get HS wakeup reason.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv,
+                                        struct host_cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON);
+       cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_wakeup_reason) +
+                               S_DS_GEN);
+
+       return 0;
+}
+
 /*
  * This function prepares the commands before sending them to the firmware.
  *
@@ -1873,6 +1889,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_802_11_SCAN:
                ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
                break;
+       case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+               ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr,
+                                                       data_buf);
+               break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
                ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
                break;
@@ -2063,6 +2083,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
                ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,
                                                   data_buf);
                break;
+       case HostCmd_CMD_HS_WAKEUP_REASON:
+               ret = mwifiex_cmd_get_wakeup_reason(priv, cmd_ptr);
+               break;
        case HostCmd_CMD_MC_POLICY:
                ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action,
                                                data_buf);
index 9ac7aa2431b41533ab68f8495693c36c41f40801..d96523e10eb46ef051a1b40a35f408d42dc0404d 100644 (file)
@@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
                ret = mwifiex_ret_802_11_scan(priv, resp);
+               cfg80211_sched_scan_results(priv->wdev.wiphy);
                mwifiex_dbg(adapter, CMD,
                            "info: CMD_RESP: BG_SCAN result is ready!\n");
                break;
+       case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+               break;
        case HostCmd_CMD_TXPWR_CFG:
                ret = mwifiex_ret_tx_power_cfg(priv, resp);
                break;
@@ -1233,6 +1236,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
        case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
                ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp);
                break;
+       case HostCmd_CMD_HS_WAKEUP_REASON:
+               ret = mwifiex_ret_wakeup_reason(priv, resp, data_buf);
+               break;
        case HostCmd_CMD_TDLS_CONFIG:
                break;
        case HostCmd_CMD_ROBUST_COEX:
index ff3ee9dfbbd54f51dbd42f8ff5478d78bc63013b..070bce401151a522983a3ce20fe6055ae4113612 100644 (file)
@@ -92,6 +92,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        priv->is_data_rate_auto = true;
        priv->data_rate = 0;
 
+       priv->assoc_resp_ht_param = 0;
+       priv->ht_param_present = false;
+
        if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
             GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data)
                mwifiex_hist_data_reset(priv);
@@ -607,11 +610,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_PS_AWAKE:
                mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
-               if (!adapter->pps_uapsd_mode && priv->port_open &&
+               if (!adapter->pps_uapsd_mode &&
+                   (priv->port_open ||
+                    (priv->bss_mode == NL80211_IFTYPE_ADHOC)) &&
                    priv->media_connected && adapter->sleep_period.period) {
-                               adapter->pps_uapsd_mode = true;
-                               mwifiex_dbg(adapter, EVENT,
-                                           "event: PPS/UAPSD mode activated\n");
+                       adapter->pps_uapsd_mode = true;
+                       mwifiex_dbg(adapter, EVENT,
+                                   "event: PPS/UAPSD mode activated\n");
                }
                adapter->tx_lock_flag = false;
                if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -686,6 +691,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                                       HostCmd_ACT_GEN_GET, 0, NULL, false);
                break;
 
+       case EVENT_BG_SCAN_STOPPED:
+               dev_dbg(adapter->dev, "event: BGS_STOPPED\n");
+               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+               if (priv->sched_scanning)
+                       priv->sched_scanning = false;
+               break;
+
        case EVENT_PORT_RELEASE:
                mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
                priv->port_open = true;
index 6a4fc5d183cfec34780d8ac0d6dcd2f30e0b7f0c..d5c56eb9e985f3be8d8270b5b2b9fbd6f57e6b1a 100644 (file)
@@ -314,6 +314,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        mwifiex_dbg(adapter, ERROR,
                                    "Attempt to reconnect on csa closed chan(%d)\n",
                                    bss_desc->channel);
+                       ret = -1;
                        goto done;
                }
 
@@ -504,6 +505,20 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
                }
        }
 
+       priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+       if (priv && priv->sched_scanning) {
+#ifdef CONFIG_PM
+               if (!priv->wdev.wiphy->wowlan_config->nd_config) {
+#endif
+                       mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
+                       mwifiex_stop_bg_scan(priv);
+                       cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+#ifdef CONFIG_PM
+               }
+#endif
+       }
+
        if (adapter->hs_activated) {
                mwifiex_dbg(adapter, CMD,
                            "cmd: HS Already activated\n");
@@ -1114,11 +1129,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
  * with requisite parameters and calls the IOCTL handler.
  */
 int
-mwifiex_get_ver_ext(struct mwifiex_private *priv)
+mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)
 {
        struct mwifiex_ver_ext ver_ext;
 
        memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
+       ver_ext.version_str_sel = version_str_sel;
        if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
                             HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
                return -1;
@@ -1450,3 +1466,19 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
 
        return 0;
 }
+
+/* This function get Host Sleep wake up reason.
+ *
+ */
+int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
+                             int cmd_type,
+                             struct mwifiex_ds_wakeup_reason *wakeup_reason)
+{
+       int status = 0;
+
+       status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,
+                                 HostCmd_ACT_GEN_GET, 0, wakeup_reason,
+                                 cmd_type == MWIFIEX_SYNC_CMD);
+
+       return status;
+}
index 9275f9c3f869bbb0bc43be93f7480e8cf3ffba9f..150649602e98298bed2975f8444c945e640dfb1a 100644 (file)
@@ -680,6 +680,13 @@ int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer,
        __net_timestamp(skb);
        mwifiex_queue_tx_pkt(priv, skb);
 
+       /* Delay 10ms to make sure tdls setup confirm/teardown frame
+        * is received by peer
+       */
+       if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
+           action_code == WLAN_TDLS_TEARDOWN)
+               msleep_interruptible(10);
+
        return 0;
 }
 
index e791166d90c4496dd15b3ddda622977c3cdde16a..16d95b22fe5c99a2803ceed9527e637c17e75b05 100644 (file)
@@ -192,7 +192,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
                }
                priv->ap_11n_enabled = 1;
        } else {
-               memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
+               memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap));
                bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
                bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
        }
index e43aff932360ef3e99801956b5bca6b8e8649303..05108618430da866e680ac51498f229e1be8f4ea 100644 (file)
@@ -244,9 +244,9 @@ setup_for_next:
        if (card->rx_cmd_ep == context->ep) {
                mwifiex_usb_submit_rx_urb(context, size);
        } else {
-               if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){
+               if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) {
                        mwifiex_usb_submit_rx_urb(context, size);
-               }else{
+               } else {
                        context->skb = NULL;
                }
        }
index 0cec8a64473e9c1f764b841b27c74c9b36800fc5..6681be0511c76919465e24f0e01980c21f2f4381 100644 (file)
@@ -78,6 +78,16 @@ static struct mwifiex_debug_data items[] = {
         item_addr(last_event), DBG_CMD_NUM},
        {"last_event_index", item_size(last_event_index),
         item_addr(last_event_index), 1},
+       {"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap),
+        item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM},
+       {"last_mp_wr_ports", item_size(last_mp_wr_ports),
+        item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM},
+       {"last_mp_wr_len", item_size(last_mp_wr_len),
+        item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM},
+       {"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port),
+        item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM},
+       {"last_sdio_mp_index", item_size(last_sdio_mp_index),
+        item_addr(last_sdio_mp_index), 1},
        {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
         item_addr(num_cmd_host_to_card_failure), 1},
        {"num_cmd_sleep_cfm_fail",
@@ -233,6 +243,16 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
                memcpy(info->last_event, adapter->dbg.last_event,
                       sizeof(adapter->dbg.last_event));
                info->last_event_index = adapter->dbg.last_event_index;
+               memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap,
+                      sizeof(adapter->dbg.last_mp_wr_bitmap));
+               memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports,
+                      sizeof(adapter->dbg.last_mp_wr_ports));
+               memcpy(info->last_mp_curr_wr_port,
+                      adapter->dbg.last_mp_curr_wr_port,
+                      sizeof(adapter->dbg.last_mp_curr_wr_port));
+               memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len,
+                      sizeof(adapter->dbg.last_mp_wr_len));
+               info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index;
                info->data_sent = adapter->data_sent;
                info->cmd_sent = adapter->cmd_sent;
                info->cmd_resp_received = adapter->cmd_resp_received;
index acccd6734e3b332cb172789e9b210c077465371f..0eb246502e1d119b03d83874cba3030ac4849092 100644 (file)
@@ -438,6 +438,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                mwifiex_set_ba_params(priv);
                mwifiex_reset_11n_rx_seq_num(priv);
 
+               priv->wmm.drv_pkt_delay_max = MWIFIEX_WMM_DRV_DELAY_MAX;
                atomic_set(&priv->wmm.tx_pkts_queued, 0);
                atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
@@ -475,7 +476,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
                priv = adapter->priv[i];
                if (!priv)
                        continue;
-               if (!priv->port_open)
+               if (!priv->port_open &&
+                   (priv->bss_mode != NL80211_IFTYPE_ADHOC))
                        continue;
                if (adapter->if_ops.is_port_ready &&
                    !adapter->if_ops.is_port_ready(priv))
@@ -1099,7 +1101,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
 
                        priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv;
 
-                       if (!priv_tmp->port_open ||
+                       if (((priv_tmp->bss_mode != NL80211_IFTYPE_ADHOC) &&
+                            !priv_tmp->port_open) ||
                            (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0))
                                continue;
 
index 30e3aaae32e2288ed1f7541b6da7a42eb6a8729a..088429d0a634d8c4372d45e2dc1cd3b7d2fabf1e 100644 (file)
@@ -5421,11 +5421,13 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
 
 static int
 mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                  enum ieee80211_ampdu_mlme_action action,
-                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                  u8 buf_size, bool amsdu)
+                  struct ieee80211_ampdu_params *params)
 {
-
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
        int i, rc = 0;
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_ampdu_stream *stream;
index f715eee398510df829a61ba0f431610d1ab32baa..e70dd95239117f7e0ef8a2d668b6798727a06b46 100644 (file)
@@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 
 static int
 mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                 enum ieee80211_ampdu_mlme_action action,
-                 struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
-                 bool amsdu)
+                 struct ieee80211_ampdu_params *params)
 {
        struct mt7601u_dev *dev = hw->priv;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 
        WARN_ON(msta->wcid.idx > GROUP_WCID(0));
index fbb1986eda3cb4eada8181979b157d7c88fe1b8b..91c4b34279657659dfbf2cdce58084b8517ea4f6 100644 (file)
@@ -362,7 +362,9 @@ mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw)
        int i, ret;
 
        ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL);
-       if (!ivb || mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) {
+       if (!ivb)
+               return -ENOMEM;
+       if (mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) {
                ret = -ENOMEM;
                goto error;
        }
index a26afcab03ed02242fdc7fa2f3b94307fc52024e..7fa0128de7e310be2978b35a97746bc011acb324 100644 (file)
@@ -7936,10 +7936,11 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 EXPORT_SYMBOL_GPL(rt2800_get_tsf);
 
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size, bool amsdu)
+                       struct ieee80211_ampdu_params *params)
 {
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
        struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
        int ret = 0;
 
index 440790b92b19e2927fd9b9d7446cbd3c8eef4f30..83f1a44fb9b481cb5f2a8dda9e9914b8113e91bb 100644 (file)
@@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw,
                   const struct ieee80211_tx_queue_params *params);
 u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size, bool amsdu);
+                       struct ieee80211_ampdu_params *params);
 int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
                      struct survey_info *survey);
 void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
index bf9afbf46c1bbbc1220bad06e429d2622a1f9f58..4b0bb6b4f6f11d4b2c924d1d77ab8bbcc4d80e98 100644 (file)
@@ -1026,6 +1026,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0411, 0x01a2) },
        { USB_DEVICE(0x0411, 0x01ee) },
        { USB_DEVICE(0x0411, 0x01a8) },
+       { USB_DEVICE(0x0411, 0x01fd) },
        /* Corega */
        { USB_DEVICE(0x07aa, 0x002f) },
        { USB_DEVICE(0x07aa, 0x003c) },
index 26427140a963b592a52d6c2443e45dfa24f73cf6..6418620f95ff62a7e1a562b7cb29d6e306d2d4ad 100644 (file)
  * amount of bytes needed to move the data.
  */
 #define ALIGN_SIZE(__skb, __header) \
-       (  ((unsigned long)((__skb)->data + (__header))) & 3 )
+       (((unsigned long)((__skb)->data + (__header))) & 3)
 
 /*
  * Constants for extra TX headroom for alignment purposes.
 #define SLOT_TIME              20
 #define SHORT_SLOT_TIME                9
 #define SIFS                   10
-#define PIFS                   ( SIFS + SLOT_TIME )
-#define SHORT_PIFS             ( SIFS + SHORT_SLOT_TIME )
-#define DIFS                   ( PIFS + SLOT_TIME )
-#define SHORT_DIFS             ( SHORT_PIFS + SHORT_SLOT_TIME )
-#define EIFS                   ( SIFS + DIFS + \
-                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
-#define SHORT_EIFS             ( SIFS + SHORT_DIFS + \
-                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
+#define PIFS                   (SIFS + SLOT_TIME)
+#define SHORT_PIFS             (SIFS + SHORT_SLOT_TIME)
+#define DIFS                   (PIFS + SLOT_TIME)
+#define SHORT_DIFS             (SHORT_PIFS + SHORT_SLOT_TIME)
+#define EIFS                   (SIFS + DIFS + \
+                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
+#define SHORT_EIFS             (SIFS + SHORT_DIFS + \
+                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
 
 enum rt2x00_chip_intf {
        RT2X00_CHIP_INTF_PCI,
index 90fdb02b55e79debd5bd89b31104e90a260c596c..72ae530e4a3bdc499f73ef72e3ce8c85351b8033 100644 (file)
@@ -478,7 +478,7 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,        \
 {                                                              \
        struct rt2x00debug_intf *intf = file->private_data;     \
        const struct rt2x00debug *debug = intf->debug;          \
-       char line[16];                                          \
+       char line[17];                                          \
        size_t size;                                            \
        unsigned int index = intf->offset_##__name;             \
        __type value;                                           \
@@ -494,7 +494,8 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,        \
                                                                \
        if (copy_from_user(line, buf, length))                  \
                return -EFAULT;                                 \
-                                                               \
+       line[16] = 0;                                           \
+                                               \
        size = strlen(line);                                    \
        value = simple_strtoul(line, NULL, 0);                  \
                                                                \
@@ -629,7 +630,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
        data += sprintf(data, "register\tbase\twords\twordsize\n");
 #define RT2X00DEBUGFS_SPRINTF_REGISTER(__name)                 \
 {                                                              \
-       if(debug->__name.read)                                  \
+       if (debug->__name.read)                                 \
                data += sprintf(data, __stringify(__name)       \
                                "\t%d\t%d\t%d\n",               \
                                debug->__name.word_base,        \
@@ -699,7 +700,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 
 #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name)                    \
 ({                                                                             \
-       if(debug->__name.read) {                                                \
+       if (debug->__name.read) {                                               \
                (__intf)->__name##_off_entry =                                  \
                debugfs_create_u32(__stringify(__name) "_offset",               \
                                       S_IRUSR | S_IWUSR,                       \
index 1442075a838218f61366d84d1ec5d40fb45bc7be..ab8641547a1f6a61f763f9ab7dfc2e8e15dd7a4f 100644 (file)
 #define PAIRWISE_TA_TABLE_BASE         0x1a00
 
 #define SHARED_KEY_ENTRY(__idx) \
-       ( SHARED_KEY_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_key_entry)) )
+       (SHARED_KEY_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_key_entry)))
 #define PAIRWISE_KEY_ENTRY(__idx) \
-       ( PAIRWISE_KEY_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_key_entry)) )
+       (PAIRWISE_KEY_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_key_entry)))
 #define PAIRWISE_TA_ENTRY(__idx) \
-       ( PAIRWISE_TA_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+       (PAIRWISE_TA_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_pairwise_ta_entry)))
 
 struct hw_key_entry {
        u8 key[16];
@@ -180,7 +180,7 @@ struct hw_pairwise_ta_entry {
 #define HW_BEACON_BASE3                        0x2f00
 
 #define HW_BEACON_OFFSET(__index) \
-       ( HW_BEACON_BASE0 + (__index * 0x0100) )
+       (HW_BEACON_BASE0 + (__index * 0x0100))
 
 /*
  * HOST-MCU shared memory.
@@ -1287,9 +1287,9 @@ struct hw_pairwise_ta_entry {
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE                  ( 16 * sizeof(__le32) )
-#define TXINFO_SIZE                    ( 6 * sizeof(__le32) )
-#define RXD_DESC_SIZE                  ( 16 * sizeof(__le32) )
+#define TXD_DESC_SIZE                  (16 * sizeof(__le32))
+#define TXINFO_SIZE                    (6 * sizeof(__le32))
+#define RXD_DESC_SIZE                  (16 * sizeof(__le32))
 
 /*
  * TX descriptor format for TX, PRIO and Beacon Ring.
index dd4d626aecbc4482b70d0d60daee7fab4657761b..8f053c35022734b4deaa6ed4eaea6ed723a58bf7 100644 (file)
@@ -13,7 +13,7 @@ config RTL8XXXU
          This driver is under development and has a limited feature
          set. In particular it does not yet support 40MHz channels
          and power management. However it should have a smaller
-         memory footprint than the vendor drivers and benetifs
+         memory footprint than the vendor drivers and benefits
          from the in kernel mac80211 stack.
 
          It can coexist with drivers from drivers/staging/rtl8723au,
index 6aed923a709ae3606225307cdcb2b7170442e11d..e654bd33b43408c59e23e5e1d01fe09c2105d03a 100644 (file)
@@ -1599,9 +1599,9 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
 static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
                                  enum nl80211_iftype linktype)
 {
-       u16 val8;
+       u8 val8;
 
-       val8 = rtl8xxxu_read16(priv, REG_MSR);
+       val8 = rtl8xxxu_read8(priv, REG_MSR);
        val8 &= ~MSR_LINKTYPE_MASK;
 
        switch (linktype) {
@@ -1704,6 +1704,7 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
                        priv->has_bluetooth = 1;
                if (val32 & MULTI_GPS_FUNC_EN)
                        priv->has_gps = 1;
+               priv->is_multi_func = 1;
        } else if (val32 & SYS_CFG_TYPE_ID) {
                bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
                bonding &= HPON_FSM_BONDING_MASK;
@@ -1938,9 +1939,11 @@ static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)
        if (val16 & EEPROM_BOOT)
                priv->boot_eeprom = 1;
 
-       val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
-       val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
-       rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
+       if (priv->is_multi_func) {
+               val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
+               val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
+               rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
+       }
 
        dev_dbg(dev, "Booting from %s\n",
                priv->boot_eeprom ? "EEPROM" : "EFUSE");
@@ -2043,6 +2046,24 @@ exit:
        return ret;
 }
 
+static void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u16 sys_func;
+
+       val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+       val8 &= ~BIT(0);
+       rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+       sys_func = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+       sys_func &= ~SYS_FUNC_CPU_ENABLE;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func);
+       val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+       val8 |= BIT(0);
+       rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+       sys_func |= SYS_FUNC_CPU_ENABLE;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, sys_func);
+}
+
 static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
 {
        struct device *dev = &priv->udev->dev;
@@ -2067,6 +2088,12 @@ static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
        val32 &= ~MCU_WINT_INIT_READY;
        rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
 
+       /*
+        * Reset the 8051 in order for the firmware to start running,
+        * otherwise it won't come up on the 8192eu
+        */
+       rtl8xxxu_reset_8051(priv);
+
        /* Wait for firmware to become ready */
        for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
                val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
@@ -2100,19 +2127,30 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
 
        /* 8051 enable */
        val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
-       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE);
+       val16 |= SYS_FUNC_CPU_ENABLE;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+       val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+       if (val8 & MCU_FW_RAM_SEL) {
+               pr_info("do the RAM reset\n");
+               rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
+               rtl8xxxu_reset_8051(priv);
+       }
 
        /* MCU firmware download enable */
        val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
-       rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE);
+       val8 |= MCU_FW_DL_ENABLE;
+       rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8);
 
        /* 8051 reset */
        val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
-       rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19));
+       val32 &= ~BIT(19);
+       rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
 
        /* Reset firmware download checksum */
        val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
-       rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT);
+       val8 |= MCU_FW_DL_CSUM_REPORT;
+       rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8);
 
        pages = priv->fw_size / RTL_FW_PAGE_SIZE;
        remainder = priv->fw_size % RTL_FW_PAGE_SIZE;
@@ -2121,7 +2159,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
 
        for (i = 0; i < pages; i++) {
                val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
-               rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+               val8 |= i;
+               rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8);
 
                ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS,
                                      fwptr, RTL_FW_PAGE_SIZE);
@@ -2135,7 +2174,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
 
        if (remainder) {
                val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
-               rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+               val8 |= i;
+               rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8);
                ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS,
                                      fwptr, remainder);
                if (ret != remainder) {
@@ -2148,8 +2188,8 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
 fw_abort:
        /* MCU firmware download disable */
        val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL);
-       rtl8xxxu_write16(priv, REG_MCU_FW_DL,
-                        val16 & (~MCU_FW_DL_ENABLE & 0xff));
+       val16 &= ~MCU_FW_DL_ENABLE;
+       rtl8xxxu_write16(priv, REG_MCU_FW_DL, val16);
 
        return ret;
 }
@@ -2174,6 +2214,10 @@ static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name)
        }
 
        priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+       if (!priv->fw_data) {
+               ret = -ENOMEM;
+               goto exit;
+       }
        priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header);
 
        signature = le16_to_cpu(priv->fw_data->signature);
@@ -2492,8 +2536,6 @@ static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv,
                        continue;
                }
 
-               reg &= 0x3f;
-
                ret = rtl8xxxu_write_rfreg(priv, path, reg, val);
                if (ret) {
                        dev_warn(&priv->udev->dev,
@@ -4155,7 +4197,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
         * Configure initial WMAC settings
         */
        val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST |
-               /* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */
                RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL |
                RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC;
        rtl8xxxu_write32(priv, REG_RCR, val32);
@@ -4248,17 +4289,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
 
        rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0);
 
-       /*
-        * Not sure if we should get into this at all
-        */
-       if (priv->iqk_initialized) {
-               rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
-                                     priv->bb_recovery_backup,
-                                     RTL8XXXU_BB_REGS);
-       } else {
-               rtl8723a_phy_iq_calibrate(priv);
-               priv->iqk_initialized = true;
-       }
+       rtl8723a_phy_iq_calibrate(priv);
 
        /*
         * This should enable thermal meter
@@ -4312,14 +4343,17 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT);
        rtl8xxxu_write8(priv, REG_NAV_UPPER, val8);
 
-       /*
-        * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
-        * but we need to fin root cause.
-        */
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
-       if ((val32 & 0xff000000) != 0x83000000) {
-               val32 |= FPGA_RF_MODE_CCK;
-               rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+       if (priv->rtlchip == 0x8723a) {
+               /*
+                * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
+                * but we need to find root cause.
+                * This is 8723au only.
+                */
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+               if ((val32 & 0xff000000) != 0x83000000) {
+                       val32 |= FPGA_RF_MODE_CCK;
+                       rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+               }
        }
 
        val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
@@ -4381,7 +4415,7 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
 }
 
 static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif, const u8mac)
+                                  struct ieee80211_vif *vif, const u8 *mac)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
        u8 val8;
@@ -4488,13 +4522,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
                        rtl8xxxu_update_rate_mask(priv, ramask, sgi);
 
-                       val32 = rtl8xxxu_read32(priv, REG_RCR);
-                       val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON;
-                       rtl8xxxu_write32(priv, REG_RCR, val32);
-
-                       /* Enable RX of data frames */
-                       rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
-
                        rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
 
                        rtl8723a_stop_tx_beacon(priv);
@@ -4505,17 +4532,10 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
                        h2c.joinbss.data = H2C_JOIN_BSS_CONNECT;
                } else {
-                       val32 = rtl8xxxu_read32(priv, REG_RCR);
-                       val32 &= ~(RCR_CHECK_BSSID_MATCH |
-                                  RCR_CHECK_BSSID_BEACON);
-                       rtl8xxxu_write32(priv, REG_RCR, val32);
-
                        val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
                        val8 |= BEACON_DISABLE_TSF_UPDATE;
                        rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
 
-                       /* Disable RX of data frames */
-                       rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
                        h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT;
                }
                h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT;
@@ -5012,17 +5032,14 @@ static void rtl8xxxu_rx_complete(struct urb *urb)
        struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
        struct rtl8723au_phy_stats *phy_stats;
        struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_mgmt *mgmt;
        struct device *dev = &priv->udev->dev;
        __le32 *_rx_desc_le = (__le32 *)skb->data;
        u32 *_rx_desc = (u32 *)skb->data;
-       int cnt, len, drvinfo_sz, desc_shift, i;
+       int drvinfo_sz, desc_shift, i;
 
        for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
                _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
 
-       cnt = rx_desc->frag;
-       len = rx_desc->pktlen;
        drvinfo_sz = rx_desc->drvinfo_sz * 8;
        desc_shift = rx_desc->shift;
        skb_put(skb, urb->actual_length);
@@ -5033,8 +5050,6 @@ static void rtl8xxxu_rx_complete(struct urb *urb)
 
                skb_pull(skb, drvinfo_sz + desc_shift);
 
-               mgmt = (struct ieee80211_mgmt *)skb->data;
-
                memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
 
                if (rx_desc->phy_stats)
@@ -5284,11 +5299,56 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw,
                                      unsigned int *total_flags, u64 multicast)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
+       u32 rcr = rtl8xxxu_read32(priv, REG_RCR);
 
        dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n",
                __func__, changed_flags, *total_flags);
 
-       *total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC);
+       /*
+        * FIF_ALLMULTI ignored as all multicast frames are accepted (REG_MAR)
+        */
+
+       if (*total_flags & FIF_FCSFAIL)
+               rcr |= RCR_ACCEPT_CRC32;
+       else
+               rcr &= ~RCR_ACCEPT_CRC32;
+
+       /*
+        * FIF_PLCPFAIL not supported?
+        */
+
+       if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+               rcr &= ~RCR_CHECK_BSSID_BEACON;
+       else
+               rcr |= RCR_CHECK_BSSID_BEACON;
+
+       if (*total_flags & FIF_CONTROL)
+               rcr |= RCR_ACCEPT_CTRL_FRAME;
+       else
+               rcr &= ~RCR_ACCEPT_CTRL_FRAME;
+
+       if (*total_flags & FIF_OTHER_BSS) {
+               rcr |= RCR_ACCEPT_AP;
+               rcr &= ~RCR_CHECK_BSSID_MATCH;
+       } else {
+               rcr &= ~RCR_ACCEPT_AP;
+               rcr |= RCR_CHECK_BSSID_MATCH;
+       }
+
+       if (*total_flags & FIF_PSPOLL)
+               rcr |= RCR_ACCEPT_PM;
+       else
+               rcr &= ~RCR_ACCEPT_PM;
+
+       /*
+        * FIF_PROBE_REQ ignored as probe requests always seem to be accepted
+        */
+
+       rtl8xxxu_write32(priv, REG_RCR, rcr);
+
+       *total_flags &= (FIF_ALLMULTI | FIF_FCSFAIL | FIF_BCN_PRBRESP_PROMISC |
+                        FIF_CONTROL | FIF_OTHER_BSS | FIF_PSPOLL |
+                        FIF_PROBE_REQ);
 }
 
 static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts)
@@ -5375,13 +5435,13 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 static int
 rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                     enum ieee80211_ampdu_mlme_action action,
-                     struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
-                     bool amsdu)
+                     struct ieee80211_ampdu_params *params)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
        struct device *dev = &priv->udev->dev;
        u8 ampdu_factor, ampdu_density;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
 
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
@@ -5473,12 +5533,9 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw)
        }
 exit:
        /*
-        * Disable all data frames
-        */
-       rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
-       /*
-        * Accept all mgmt frames
+        * Accept all data and mgmt frames
         */
+       rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
        rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff);
 
        rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e);
@@ -5891,8 +5948,6 @@ static struct usb_device_id dev_table[] = {
        .driver_info = (unsigned long)&rtl8192cu_fops},
 {USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
-{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
-       .driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */
 {USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
 {USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff),
index f2a1bac6c8ec966200f1bc86a28fae0ac7e53e13..bbd0f6b76b820ecfcf7acfefd618fd367b62fed8 100644 (file)
@@ -597,6 +597,7 @@ struct rtl8xxxu_priv {
        struct rtl8723au_idx ht20_max_power_offset[3];
        u32 chip_cut:4;
        u32 rom_rev:4;
+       u32 is_multi_func:1;
        u32 has_wifi:1;
        u32 has_bluetooth:1;
        u32 enable_bluetooth:1;
@@ -652,7 +653,6 @@ struct rtl8xxxu_priv {
        u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
        u32 rtlchip;
        u8 pi_enabled:1;
-       u8 iqk_initialized:1;
        u8 int_buf[USB_INTR_CONTENT_LENGTH];
 };
 
index 23208f79b97ce3e13ba1dd5f11b877ffac3cc5d6..8f6c9c6c7c094fdade4fb10dc1e655d8ead31058 100644 (file)
@@ -45,6 +45,7 @@
 #define  APS_FSMCO_ENABLE_POWERDOWN    BIT(4)
 #define  APS_FSMCO_MAC_ENABLE          BIT(8)
 #define  APS_FSMCO_MAC_OFF             BIT(9)
+#define  APS_FSMCO_SW_LPS              BIT(10)
 #define  APS_FSMCO_HW_SUSPEND          BIT(11)
 #define  APS_FSMCO_PCIE                        BIT(12)
 #define  APS_FSMCO_HW_POWERDOWN                BIT(15)
 #define  SYS_CFG_PCIRSTB               BIT(4)
 #define  SYS_CFG_V15_VLD               BIT(5)
 #define  SYS_CFG_TRP_B15V_EN           BIT(7)
+#define  SYS_CFG_SW_OFFLOAD_EN         BIT(7)  /* For chips with IOL support */
 #define  SYS_CFG_SIC_IDLE              BIT(8)
 #define  SYS_CFG_BD_MAC2               BIT(9)
 #define  SYS_CFG_BD_MAC1               BIT(10)
 #define REG_BB_ACCEESS_CTRL            0x01e8
 #define REG_BB_ACCESS_DATA             0x01ec
 
+#define REG_HMBOX_EXT0_8723B           0x01f0
+#define REG_HMBOX_EXT1_8723B           0x01f4
+#define REG_HMBOX_EXT2_8723B           0x01f8
+#define REG_HMBOX_EXT3_8723B           0x01fc
+
 /* 0x0200 ~ 0x027F     TXDMA Configuration */
 #define REG_RQPN                       0x0200
 #define  RQPN_HI_PQ_SHIFT              0
 #define REG_TXDMA_OFFSET_CHK           0x020c
 #define REG_TXDMA_STATUS               0x0210
 #define REG_RQPN_NPQ                   0x0214
+#define  RQPN_NPQ_SHIFT                        0
+#define  RQPN_EPQ_SHIFT                        16
 
 /* 0x0280 ~ 0x02FF     RXDMA Configuration */
 #define REG_RXDMA_AGG_PG_TH            0x0280
 #define REG_NEED_CPU_HANDLE            0x04e0
 #define REG_PKT_LOSE_RPT               0x04e1
 #define REG_PTCL_ERR_STATUS            0x04e2
+#define REG_TX_REPORT_CTRL             0x04ec
+#define REG_TX_REPORT_TIME             0x04f0
 #define REG_DUMMY                      0x04fc
 
 /* 0x0500 ~ 0x05FF     EDCA Configuration */
                                                 (Rx beacon, probe rsp) */
 #define  RCR_ACCEPT_CRC32              BIT(8)  /* Accept CRC32 error packet */
 #define  RCR_ACCEPT_ICV                        BIT(9)  /* Accept ICV error packet */
-#define  RCR_ACCEPT_DATA_FRAME         BIT(11)
-#define  RCR_ACCEPT_CTRL_FRAME         BIT(12)
-#define  RCR_ACCEPT_MGMT_FRAME         BIT(13)
+#define  RCR_ACCEPT_DATA_FRAME         BIT(11) /* Accept all data pkt or use
+                                                  REG_RXFLTMAP2 */
+#define  RCR_ACCEPT_CTRL_FRAME         BIT(12) /* Accept all control pkt or use
+                                                  REG_RXFLTMAP1 */
+#define  RCR_ACCEPT_MGMT_FRAME         BIT(13) /* Accept all mgmt pkt or use
+                                                  REG_RXFLTMAP0 */
 #define  RCR_HTC_LOC_CTRL              BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */
+#define  RCR_UC_DATA_PKT_INT_ENABLE    BIT(16) /* Enable unicast data packet
+                                                  interrupt */
+#define  RCR_BM_DATA_PKT_INT_ENABLE    BIT(17) /* Enable broadcast data packet
+                                                  interrupt */
+#define  RCR_TIM_PARSER_ENABLE         BIT(18) /* Enable RX beacon TIM parser*/
 #define  RCR_MFBEN                     BIT(22)
-#define  RCR_LSIGEN                    BIT(23)
+#define  RCR_LSIG_ENABLE               BIT(23) /* Enable LSIG TXOP Protection
+                                                  function. Search KEYCAM for
+                                                  each rx packet to check if
+                                                  LSIGEN bit is set. */
 #define  RCR_MULTI_BSSID_ENABLE                BIT(24) /* Enable Multiple BssId */
+#define  RCR_FORCE_ACK                 BIT(26)
 #define  RCR_ACCEPT_BA_SSN             BIT(27) /* Accept BA SSN */
 #define  RCR_APPEND_PHYSTAT            BIT(28)
 #define  RCR_APPEND_ICV                        BIT(29)
 #define REG_LPNAV_CTRL                 0x0694
 #define REG_WKFMCAM_CMD                        0x0698
 #define REG_WKFMCAM_RWD                        0x069c
-#define REG_RXFLTMAP0                  0x06a0
-#define REG_RXFLTMAP1                  0x06a2
-#define REG_RXFLTMAP2                  0x06a4
+
+/*
+ * RX Filters: each bit corresponds to the numerical value of the subtype.
+ * If it is set the subtype frame type is passed. The filter is only used when
+ * the RCR_ACCEPT_DATA_FRAME, RCR_ACCEPT_CTRL_FRAME, RCR_ACCEPT_MGMT_FRAME bit
+ * in the RCR are low.
+ *
+ * Example: Beacon subtype is binary 1000 which is decimal 8 so we have to set
+ * bit 8 (0x100) in REG_RXFLTMAP0 to enable reception.
+ */
+#define REG_RXFLTMAP0                  0x06a0  /* Management frames */
+#define REG_RXFLTMAP1                  0x06a2  /* Control frames */
+#define REG_RXFLTMAP2                  0x06a4  /* Data frames */
+
 #define REG_BCN_PSR_RPT                        0x06a8
 #define REG_CALB32K_CTRL               0x06ac
 #define REG_PKT_MON_CTRL               0x06b4
 #define REG_FPGA1_RF_MODE              0x0900
 
 #define REG_FPGA1_TX_INFO              0x090c
+#define REG_DPDT_CTRL                  0x092c  /* 8723BU */
+#define REG_RFE_CTRL_ANTA_SRC          0x0930  /* 8723BU */
+#define REG_RFE_PATH_SELECT            0x0940  /* 8723BU */
+#define REG_RFE_BUFFER                 0x0944  /* 8723BU */
 
 #define REG_CCK0_SYSTEM                        0x0a00
 #define  CCK0_SIDEBAND                 BIT(4)
 
 #define REG_OFDM0_ENERGY_CCA_THRES     0x0c4c
 
+#define REG_OFDM0_RX_D_SYNC_PATH       0x0c40
+#define  OFDM0_SYNC_PATH_NOTCH_FILTER  BIT(1)
+
 #define REG_OFDM0_XA_AGC_CORE1         0x0c50
 #define REG_OFDM0_XA_AGC_CORE2         0x0c54
 #define REG_OFDM0_XB_AGC_CORE1         0x0c58
index 4ae421ef30d94f4f8bc93d85645eeda4548ba835..0f48048b865407fe8d984b1057bd262ccd28dc7f 100644 (file)
 #include <linux/export.h>
 #include <net/cfg80211.h>
 
+u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
+       36, 38, 40, 42, 44, 46, 48,             /* Band 1 */
+       52, 54, 56, 58, 60, 62, 64,             /* Band 2 */
+       100, 102, 104, 106, 108, 110, 112,      /* Band 3 */
+       116, 118, 120, 122, 124, 126, 128,      /* Band 3 */
+       132, 134, 136, 138, 140, 142, 144,      /* Band 3 */
+       149, 151, 153, 155, 157, 159, 161,      /* Band 4 */
+       165, 167, 169, 171, 173, 175, 177       /* Band 4 */
+};
+EXPORT_SYMBOL(channel5g);
+
+u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
+       42, 58, 106, 122, 138, 155, 171
+};
+EXPORT_SYMBOL(channel5g_80m);
+
 void rtl_addr_delay(u32 addr)
 {
        if (addr == 0xfe)
-               mdelay(50);
+               msleep(50);
        else if (addr == 0xfd)
-               mdelay(5);
+               msleep(5);
        else if (addr == 0xfc)
-               mdelay(1);
+               msleep(1);
        else if (addr == 0xfb)
-               udelay(50);
+               usleep_range(50, 100);
        else if (addr == 0xfa)
-               udelay(5);
+               usleep_range(5, 10);
        else if (addr == 0xf9)
-               udelay(1);
+               usleep_range(1, 2);
 }
 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);
+       if (addr >= 0xf9 && addr <= 0xfe) {
+               rtl_addr_delay(addr);
        } else {
                rtl_set_rfreg(hw, rfpath, addr, mask, data);
-               udelay(1);
+               usleep_range(1, 2);
        }
 }
 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);
+       if (addr >= 0xf9 && addr <= 0xfe) {
+               rtl_addr_delay(addr);
        } else {
                rtl_set_bbreg(hw, addr, MASKDWORD, data);
-               udelay(1);
+               usleep_range(1, 2);
        }
 }
 EXPORT_SYMBOL(rtl_bb_delay);
@@ -1371,11 +1367,13 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw,
 
 static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
-                              enum ieee80211_ampdu_mlme_action action,
-                              struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                              u8 buf_size, bool amsdu)
+                              struct ieee80211_ampdu_params *params)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
 
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
index 7f471bff435c08ec1dc009b3fa7288dc0f7dcc80..283d608b9973490e06367f0f0d74a1840f0a21db 100644 (file)
@@ -855,7 +855,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                }
                /* handle command packet here */
                if (rtlpriv->cfg->ops->rx_command_packet &&
-                   rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
+                   rtlpriv->cfg->ops->rx_command_packet(hw, &stats, skb)) {
                                dev_kfree_skb_any(skb);
                                goto new_trx_end;
                }
@@ -2392,7 +2392,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
        rtlpriv->cfg->ops->deinit_sw_vars(hw);
 
        if (rtlpci->irq_alloc) {
-               synchronize_irq(rtlpci->pdev->irq);
                free_irq(rtlpci->pdev->irq, hw);
                rtlpci->irq_alloc = 0;
        }
index 74c14ce28238eed70f8ad798f0724642147411d3..1aca777195210928f6da8664e06a86c2454f9427 100644 (file)
@@ -41,7 +41,7 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
        struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_sta_info *sta_entry = NULL;
-       u8 wireless_mode = 0;
+       u16 wireless_mode = 0;
 
        /*
         *this rate is no use for true rate, firmware
@@ -99,7 +99,7 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
 {
        struct rtl_mac *mac = rtl_mac(rtlpriv);
        struct rtl_sta_info *sta_entry = NULL;
-       u8 wireless_mode = 0;
+       u16 wireless_mode = 0;
        u8 sgi_20 = 0, sgi_40 = 0, sgi_80 = 0;
 
        if (sta) {
@@ -138,6 +138,11 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
                    ((wireless_mode == WIRELESS_MODE_N_5G) ||
                     (wireless_mode == WIRELESS_MODE_N_24G)))
                        rate->flags |= IEEE80211_TX_RC_MCS;
+               if (sta && sta->vht_cap.vht_supported &&
+                   (wireless_mode == WIRELESS_MODE_AC_5G ||
+                    wireless_mode == WIRELESS_MODE_AC_24G ||
+                    wireless_mode == WIRELESS_MODE_AC_ONLY))
+                       rate->flags |= IEEE80211_TX_RC_VHT_MCS;
        }
 }
 
index 791efbe6b18c1daa9791d8885327043837a43f70..11701064b0e10f0c7f09f4f058991e03cf5f264d 100644 (file)
@@ -851,7 +851,7 @@ void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 }
 
 u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw,
-                             struct rtl_stats status,
+                             const struct rtl_stats *status,
                              struct sk_buff *skb)
 {
        return 0;
index eab5ae0eb46c4b65cecdc192c2e82da54e74944d..5a24d194ac76d765984d4bf3d3207ffdc4b9c611 100644 (file)
@@ -790,7 +790,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                             bool firstseg, bool lastseg,
                             struct sk_buff *skb);
 u32 rtl88ee_rx_command_packet(struct ieee80211_hw *hw,
-                             struct rtl_stats status,
+                             const struct rtl_stats *status,
                              struct sk_buff *skb);
 
 #endif
index bb06fe836fe753037925bf18dcfa6f8d4186ffb8..7810fe87dca795b57eec8e9cc7895f4bcd1f615d 100644 (file)
@@ -924,19 +924,11 @@ static void _rtl92d_ccxpower_index_check(struct ieee80211_hw *hw,
 
 static u8 _rtl92c_phy_get_rightchnlplace(u8 chnl)
 {
-       u8 channel_5g[59] = {
-               1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
-               60, 62, 64, 100, 102, 104, 106, 108, 110, 112,
-               114, 116, 118, 120, 122, 124, 126, 128,
-               130, 132, 134, 136, 138, 140, 149, 151,
-               153, 155, 157, 159, 161, 163, 165
-       };
        u8 place = chnl;
 
        if (chnl > 14) {
-               for (place = 14; place < sizeof(channel_5g); place++) {
-                       if (channel_5g[place] == chnl) {
+               for (place = 14; place < sizeof(channel5g); place++) {
+                       if (channel5g[place] == chnl) {
                                place++;
                                break;
                        }
@@ -2471,16 +2463,9 @@ static bool _rtl92d_is_legal_5g_channel(struct ieee80211_hw *hw, u8 channel)
 {
 
        int i;
-       u8 channel_5g[45] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
-               60, 62, 64, 100, 102, 104, 106, 108, 110, 112,
-               114, 116, 118, 120, 122, 124, 126, 128, 130, 132,
-               134, 136, 138, 140, 149, 151, 153, 155, 157, 159,
-               161, 163, 165
-       };
 
-       for (i = 0; i < sizeof(channel_5g); i++)
-               if (channel == channel_5g[i])
+       for (i = 0; i < sizeof(channel5g); i++)
+               if (channel == channel5g[i])
                        return true;
        return false;
 }
index 5f14308e8eb35e9914724ce8b610e14497dccef7..9fd3f1b6e4a8852ca97844098dfdd62c24f8d5c0 100644 (file)
@@ -2018,18 +2018,6 @@ static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
        struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw));
        struct txpower_info_2g pwr2g;
        struct txpower_info_5g pwr5g;
-       u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
-               56, 58, 60, 62, 64, 100, 102, 104, 106,
-               108, 110, 112, 114, 116, 118, 120, 122,
-               124, 126, 128, 130, 132, 134, 136, 138,
-               140, 142, 144, 149, 151, 153, 155, 157,
-               159, 161, 163, 165, 167, 168, 169, 171,
-               173, 175, 177
-       };
-       u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
-               42, 58, 106, 122, 138, 155, 171
-       };
        u8 rf, idx;
        u8 i;
 
index d39ee67f611368f535a8bb0669e4510a4d22692a..24eff8ea4c2e2e28ef8d77136f412d3b4661b0fa 100644 (file)
@@ -1105,13 +1105,13 @@ void rtl92ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 }
 
 u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw,
-                             struct rtl_stats status,
+                             const struct rtl_stats *status,
                              struct sk_buff *skb)
 {
        u32 result = 0;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       switch (status.packet_report_type) {
+       switch (status->packet_report_type) {
        case NORMAL_RX:
                result = 0;
                break;
@@ -1121,7 +1121,7 @@ u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw,
                break;
        default:
                RT_TRACE(rtlpriv, COMP_RECV, DBG_TRACE,
-                        "Unknown packet type %d\n", status.packet_report_type);
+                        "Unknown packet type %d\n", status->packet_report_type);
                break;
        }
 
index 8f78ac9e6040d4f8694c7ce0b093683aa4af6585..a4c38345233e2df9d4e333ab47e7acac93c675e2 100644 (file)
@@ -857,6 +857,6 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                             bool firstseg, bool lastseg,
                             struct sk_buff *skb);
 u32 rtl92ee_rx_command_packet(struct ieee80211_hw *hw,
-                             struct rtl_stats status,
+                             const struct rtl_stats *status,
                              struct sk_buff *skb);
 #endif
index 2f7c144d7980903b5268b46e349d420b8ee5962e..7b4a9b63583b64b4b1f049676b4d4db7523c16df 100644 (file)
@@ -710,7 +710,7 @@ void rtl8723e_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 }
 
 u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw,
-                              struct rtl_stats status,
+                              const struct rtl_stats *status,
                               struct sk_buff *skb)
 {
        return 0;
index 017da7e194d8385754ae1e3de5ab09c630078e53..32970bf18856006fc83f5683d866424083064425 100644 (file)
@@ -716,6 +716,6 @@ void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                              bool firstseg, bool lastseg,
                              struct sk_buff *skb);
 u32 rtl8723e_rx_command_packet(struct ieee80211_hw *hw,
-                              struct rtl_stats status,
+                              const struct rtl_stats *status,
                               struct sk_buff *skb);
 #endif
index 338ec9a9d09b9003d3d75eee793d8847459bbb35..60345975f9fd3aeabd71d5323ddbf1af9567f658 100644 (file)
@@ -758,13 +758,13 @@ void rtl8723be_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 }
 
 u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw,
-                               struct rtl_stats status,
+                               const struct rtl_stats *status,
                                struct sk_buff *skb)
 {
        u32 result = 0;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       switch (status.packet_report_type) {
+       switch (status->packet_report_type) {
        case NORMAL_RX:
                        result = 0;
                        break;
index 45949ac4854c6579e4eafc86c20140a519fd94db..40c36607b8b93f459c82e1e4c55dc55acba2219a 100644 (file)
@@ -620,6 +620,6 @@ void rtl8723be_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                               bool firstseg, bool lastseg,
                               struct sk_buff *skb);
 u32 rtl8723be_rx_command_packet(struct ieee80211_hw *hw,
-                               struct rtl_stats status,
+                               const struct rtl_stats *status,
                                struct sk_buff *skb);
 #endif
index 525eb234627c965daa3d0c7e9611163b9734df3a..a4fc70e8c9c0db5c37a659a7e0eb262fbd60952e 100644 (file)
@@ -271,7 +271,7 @@ int rtl8821ae_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
 
        err = _rtl8821ae_fw_free_to_go(hw);
        if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
                         "Firmware is not ready to run!\n");
        } else {
                RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
index bbb789f8990b10944d0a8eed60c7700af2a4121e..fe900badd468ebb45b10a800281f2d89c210eb40 100644 (file)
@@ -2786,14 +2786,6 @@ static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
        struct txpower_info_2g pwrinfo24g;
        struct txpower_info_5g pwrinfo5g;
-       u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
-               56, 58, 60, 62, 64, 100, 102, 104, 106,
-               108, 110, 112, 114, 116, 118, 120, 122,
-               124, 126, 128, 130, 132, 134, 136, 138,
-               140, 142, 144, 149, 151, 153, 155, 157,
-               159, 161, 163, 165, 167, 168, 169, 171, 173, 175, 177};
-       u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {42, 58, 106, 122, 138, 155, 171};
        u8 rf_path, index;
        u8 i;
 
@@ -2872,16 +2864,6 @@ static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
        struct txpower_info_2g pwrinfo24g;
        struct txpower_info_5g pwrinfo5g;
-       u8 channel5g[CHANNEL_MAX_NUMBER_5G] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54,
-               56, 58, 60, 62, 64, 100, 102, 104, 106,
-               108, 110, 112, 114, 116, 118, 120, 122,
-               124, 126, 128, 130, 132, 134, 136, 138,
-               140, 142, 144, 149, 151, 153, 155, 157,
-               159, 161, 163, 165, 167, 168, 169, 171,
-               173, 175, 177};
-       u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
-               42, 58, 106, 122, 138, 155, 171};
        u8 rf_path, index;
        u8 i;
 
@@ -3855,7 +3837,7 @@ void rtl8821ae_update_channel_access_setting(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       u8 wireless_mode = mac->mode;
+       u16 wireless_mode = mac->mode;
        u8 sifs_timer, r2t_sifs;
 
        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
index 9b4d8a63791511ae54b143dae0209f65cd2cb387..74165b3eb362ceae01eaded6d600d2b64518235a 100644 (file)
@@ -1472,18 +1472,13 @@ static char _rtl8812ae_phy_get_chnl_idx_of_txpwr_lmt(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        char channel_index = -1;
-       u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64,
-               100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
-               124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 149,
-               151, 153, 155, 157, 159, 161, 163, 165, 167, 168, 169, 171,
-               173, 175, 177};
        u8  i = 0;
+
        if (band == BAND_ON_2_4G)
                channel_index = channel - 1;
        else if (band == BAND_ON_5G) {
-               for (i = 0; i < sizeof(channel_5g)/sizeof(u8); ++i) {
-                       if (channel_5g[i] == channel)
+               for (i = 0; i < sizeof(channel5g)/sizeof(u8); ++i) {
+                       if (channel5g[i] == channel)
                                channel_index = i;
                }
        } else
@@ -2240,13 +2235,6 @@ void rtl8821ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
 
 static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index)
 {
-       u8 channel_5g[CHANNEL_MAX_NUMBER_5G] = {
-               36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
-               64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
-               120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140,
-               142, 144, 149, 151, 153, 155, 157, 159, 161, 163, 165,
-               167, 168, 169, 171, 173, 175, 177
-       };
        u8 i = 0;
        bool in_24g = true;
 
@@ -2257,7 +2245,7 @@ static bool _rtl8821ae_phy_get_chnl_index(u8 channel, u8 *chnl_index)
                in_24g = false;
 
                for (i = 0; i < CHANNEL_MAX_NUMBER_5G; ++i) {
-                       if (channel_5g[i] == channel) {
+                       if (channel5g[i] == channel) {
                                *chnl_index = i;
                                return in_24g;
                        }
@@ -2728,13 +2716,10 @@ static u8 _rtl8821ae_get_txpower_index(struct ieee80211_hw *hw, u8 path,
                             rate <= DESC_RATEVHT2SS_MCS9))
                                txpower += rtlefuse->txpwr_5g_bw40diff[path][TX_2S];
                } else if (bandwidth == HT_CHANNEL_WIDTH_80) {
-                       u8 channel_5g_80m[CHANNEL_MAX_NUMBER_5G_80M] = {
-                               42, 58, 106, 122, 138, 155, 171
-                       };
                        u8 i;
 
-                       for (i = 0; i < sizeof(channel_5g_80m) / sizeof(u8); ++i)
-                               if (channel_5g_80m[i] == channel)
+                       for (i = 0; i < sizeof(channel5g_80m) / sizeof(u8); ++i)
+                               if (channel5g_80m[i] == channel)
                                        index = i;
 
                        if ((DESC_RATEMCS0 <= rate && rate <= DESC_RATEMCS15) ||
index 174743aef9431c16673ff69f4d1ff79e47ecf752..41efaa148d138b1f10bcca27a4ad1b1cf5438ac7 100644 (file)
@@ -998,13 +998,13 @@ void rtl8821ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
 }
 
 u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw,
-                               struct rtl_stats status,
+                               const struct rtl_stats *status,
                                struct sk_buff *skb)
 {
        u32 result = 0;
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       switch (status.packet_report_type) {
+       switch (status->packet_report_type) {
        case NORMAL_RX:
                result = 0;
                break;
index 31409042d8dd313cf3905c1a873ea2011963b3e9..ad565bebf1d5842a920acfac645aac75b4015d29 100644 (file)
@@ -615,6 +615,6 @@ void rtl8821ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                               bool firstseg, bool lastseg,
                               struct sk_buff *skb);
 u32 rtl8821ae_rx_command_packet(struct ieee80211_hw *hw,
-                               struct rtl_stats status,
+                               const struct rtl_stats *status,
                                struct sk_buff *skb);
 #endif
index 4544752a2ba83ca173f7cb4f14abc72538b73beb..554d81420f19ecbc598c995dec3bbab86c8558e5 100644 (file)
 
 #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
+#define CHANNEL_MAX_NUMBER_5G          49 /* 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
@@ -1323,14 +1318,13 @@ struct rtl_tid_data {
 
 struct rtl_sta_info {
        struct list_head list;
-       u8 ratr_index;
-       u8 wireless_mode;
-       u8 mimo_ps;
-       u8 mac_addr[ETH_ALEN];
        struct rtl_tid_data tids[MAX_TID_COUNT];
-
        /* just used for ap adhoc or mesh*/
        struct rssi_sta rssi_stat;
+       u16 wireless_mode;
+       u8 ratr_index;
+       u8 mimo_ps;
+       u8 mac_addr[ETH_ALEN];
 } __packed;
 
 struct rtl_priv;
@@ -2194,7 +2188,7 @@ struct rtl_hal_ops {
        bool (*get_btc_status) (void);
        bool (*is_fw_header)(struct rtlwifi_firmware_header *hdr);
        u32 (*rx_command_packet)(struct ieee80211_hw *hw,
-                                struct rtl_stats status, struct sk_buff *skb);
+                                const struct rtl_stats *status, struct sk_buff *skb);
        void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
                                   struct rtl_wow_pattern *rtl_pattern,
                                   u8 index);
@@ -2904,6 +2898,10 @@ value to host byte ordering.*/
 #define        STBC_VHT_TEST_TX_ENABLE                 BIT(2)
 #define        STBC_VHT_CAP_TX                         BIT(3)
 
+extern u8 channel5g[CHANNEL_MAX_NUMBER_5G];
+
+extern u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M];
+
 static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
 {
        return rtlpriv->io.read8_sync(rtlpriv, addr);
index b5bcc933a2a683df412139b1204fee320096a889..4df992de7d0731508a6c42fccf51096928156e9e 100644 (file)
@@ -659,29 +659,24 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
  *                              informs the f/w regarding this.
  * @hw: Pointer to the ieee80211_hw structure.
  * @vif: Pointer to the ieee80211_vif structure.
- * @action: ieee80211_ampdu_mlme_action enum.
- * @sta: Pointer to the ieee80211_sta structure.
- * @tid: Traffic identifier.
- * @ssn: Pointer to ssn value.
- * @buf_size: Buffer size (for kernel version > 2.6.38).
- * @amsdu: is AMSDU in AMPDU allowed
+ * @params: Pointer to A-MPDU action parameters
  *
  * Return: status: 0 on success, negative error code on failure.
  */
 static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
-                                    enum ieee80211_ampdu_mlme_action action,
-                                    struct ieee80211_sta *sta,
-                                    unsigned short tid,
-                                    unsigned short *ssn,
-                                    unsigned char buf_size,
-                                    bool amsdu)
+                                    struct ieee80211_ampdu_params *params)
 {
        int status = -EOPNOTSUPP;
        struct rsi_hw *adapter = hw->priv;
        struct rsi_common *common = adapter->priv;
        u16 seq_no = 0;
        u8 ii = 0;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
 
        for (ii = 0; ii < RSI_MAX_VIFS; ii++) {
                if (vif == adapter->vifs[ii])
index a740083634d83b1c4543d5d6024f533810f34397..63f95e9c29922b46ec77cf188019e5b1880cbbad 100644 (file)
@@ -446,8 +446,7 @@ static int cw1200_spi_disconnect(struct spi_device *func)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int cw1200_spi_suspend(struct device *dev)
+static int __maybe_unused cw1200_spi_suspend(struct device *dev)
 {
        struct hwbus_priv *self = spi_get_drvdata(to_spi_device(dev));
 
@@ -460,16 +459,12 @@ static int cw1200_spi_suspend(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(cw1200_pm_ops, cw1200_spi_suspend, NULL);
 
-#endif
-
 static struct spi_driver spi_driver = {
        .probe          = cw1200_spi_probe,
        .remove         = cw1200_spi_disconnect,
        .driver = {
                .name           = "cw1200_wlan_spi",
-#ifdef CONFIG_PM
-               .pm             = &cw1200_pm_ops,
-#endif
+               .pm             = IS_ENABLED(CONFIG_PM) ? &cw1200_pm_ops : NULL,
        },
 };
 
index 3ed90ff22bb852312a59db1b326cdd2ecbfcd2bb..534548470ebc57d844bb2ce819bcb24587a3a317 100644 (file)
@@ -31,13 +31,18 @@ int cw1200_pm_init(struct cw1200_pm_state *pm,
 void cw1200_pm_deinit(struct cw1200_pm_state *pm);
 int cw1200_wow_suspend(struct ieee80211_hw *hw,
                       struct cfg80211_wowlan *wowlan);
-int cw1200_wow_resume(struct ieee80211_hw *hw);
 int cw1200_can_suspend(struct cw1200_common *priv);
+int cw1200_wow_resume(struct ieee80211_hw *hw);
 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
                          unsigned long tmo);
 #else
 static inline void cw1200_pm_stay_awake(struct cw1200_pm_state *pm,
-                                       unsigned long tmo) {
+                                       unsigned long tmo)
+{
+}
+static inline int cw1200_can_suspend(struct cw1200_common *priv)
+{
+       return 0;
 }
 #endif
 #endif
index 06321c799c902689825c89098c796e875c737079..d0ddcde6c695fb6c5efd9b2283c76e98328fdbdf 100644 (file)
@@ -2129,9 +2129,7 @@ void cw1200_mcast_timeout(unsigned long arg)
 
 int cw1200_ampdu_action(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size, bool amsdu)
+                       struct ieee80211_ampdu_params *params)
 {
        /* Aggregation is implemented fully in firmware,
         * including block ack negotiation. Do not allow
index bebb3379017f6d40c3cd58b92ddfaabab1259f59..a0bacaa39b3193f230c61526afe6bdc68f38b7a0 100644 (file)
@@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev,
                             u32 changed);
 int cw1200_ampdu_action(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif,
-                       enum ieee80211_ampdu_mlme_action action,
-                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                       u8 buf_size, bool amsdu);
+                       struct ieee80211_ampdu_params *params);
 
 void cw1200_suspend_resume(struct cw1200_common *priv,
                          struct wsm_suspend_resume *arg);
index 969c9d79bfc8bd92c2c4e48c213c8e88c9611121..8a8f1e7113846af0ac1bec70d19c815dcf60c9b1 100644 (file)
@@ -13,7 +13,7 @@ config WLCORE
 
 config WLCORE_SPI
        tristate "TI wlcore SPI support"
-       depends on WLCORE && SPI_MASTER
+       depends on WLCORE && SPI_MASTER && OF
        select CRC7
        ---help---
          This module adds support for the SPI interface of adapters using
index c96405498bf43c68b997e73d512e88be4b153ec0..4b59f67724dead0621174da68b2e6167506b3b95 100644 (file)
@@ -38,7 +38,7 @@
 
 int wlcore_event_fw_logger(struct wl1271 *wl)
 {
-       u32 ret;
+       int ret;
        struct fw_logger_information fw_log;
        u8  *buffer;
        u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS;
index 9ac118e727e9402032bdfe972ee40c9d34d12a00..564ca750c5ee8895a702e9a9ea145e75391e02bf 100644 (file)
@@ -175,14 +175,14 @@ int wlcore_set_partition(struct wl1271 *wl,
        if (ret < 0)
                goto out;
 
+       /* We don't need the size of the last partition, as it is
+        * automatically calculated based on the total memory size and
+        * the sizes of the previous partitions.
+        */
        ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start);
        if (ret < 0)
                goto out;
 
-       ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size);
-       if (ret < 0)
-               goto out;
-
 out:
        return ret;
 }
index 6c257b54f4150323811c46d2a49251251c113170..10cf3747694d5bf46b865fc68a990b5b4c7c5a59 100644 (file)
@@ -36,8 +36,8 @@
 #define HW_PART1_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 12)
 #define HW_PART2_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 16)
 #define HW_PART2_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 20)
-#define HW_PART3_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 24)
-#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 28)
+#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 24)
+
 #define HW_ACCESS_REGISTER_SIZE         4
 
 #define HW_ACCESS_PRAM_MAX_RANGE       0x3c000
index d1109c4f0f0d1d7570ec373734db3f93117556f9..45662cf3169f78dd20554cde3373336f84cb6516 100644 (file)
@@ -5187,14 +5187,16 @@ out:
 
 static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
-                                 enum ieee80211_ampdu_mlme_action action,
-                                 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                 u8 buf_size, bool amsdu)
+                                 struct ieee80211_ampdu_params *params)
 {
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
        u8 hlid, *ba_bitmap;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
                     tid);
index 44f059f7f34e9473ce4e4b33648a3af9b2e44f1e..020ac1a4b40834131d6355a7464b73129fd93ad1 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/spi/spi.h>
 #include <linux/wl12xx.h>
 #include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
 
 #include "wlcore.h"
 #include "wl12xx_80211.h"
@@ -81,6 +83,7 @@
 struct wl12xx_spi_glue {
        struct device *dev;
        struct platform_device *core;
+       struct regulator *reg; /* Power regulator */
 };
 
 static void wl12xx_spi_reset(struct device *child)
@@ -318,14 +321,76 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
        return 0;
 }
 
+/**
+ * wl12xx_spi_set_power - power on/off the wl12xx unit
+ * @child: wl12xx device handle.
+ * @enable: true/false to power on/off the unit.
+ *
+ * use the WiFi enable regulator to enable/disable the WiFi unit.
+ */
+static int wl12xx_spi_set_power(struct device *child, bool enable)
+{
+       int ret = 0;
+       struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
+
+       WARN_ON(!glue->reg);
+
+       /* Update regulator state */
+       if (enable) {
+               ret = regulator_enable(glue->reg);
+               if (ret)
+                       dev_err(child, "Power enable failure\n");
+       } else {
+               ret =  regulator_disable(glue->reg);
+               if (ret)
+                       dev_err(child, "Power disable failure\n");
+       }
+
+       return ret;
+}
+
 static struct wl1271_if_operations spi_ops = {
        .read           = wl12xx_spi_raw_read,
        .write          = wl12xx_spi_raw_write,
        .reset          = wl12xx_spi_reset,
        .init           = wl12xx_spi_init,
+       .power          = wl12xx_spi_set_power,
        .set_block_size = NULL,
 };
 
+static const struct of_device_id wlcore_spi_of_match_table[] = {
+       { .compatible = "ti,wl1271" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table);
+
+/**
+ * wlcore_probe_of - DT node parsing.
+ * @spi: SPI slave device parameters.
+ * @res: resource parameters.
+ * @glue: wl12xx SPI bus to slave device glue parameters.
+ * @pdev_data: wlcore device parameters
+ */
+static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue,
+                          struct wlcore_platdev_data *pdev_data)
+{
+       struct device_node *dt_node = spi->dev.of_node;
+       int ret;
+
+       if (of_find_property(dt_node, "clock-xtal", NULL))
+               pdev_data->ref_clock_xtal = true;
+
+       ret = of_property_read_u32(dt_node, "ref-clock-frequency",
+                                  &pdev_data->ref_clock_freq);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(glue->dev,
+                       "can't get reference clock frequency (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int wl1271_probe(struct spi_device *spi)
 {
        struct wl12xx_spi_glue *glue;
@@ -335,8 +400,6 @@ static int wl1271_probe(struct spi_device *spi)
 
        memset(&pdev_data, 0x00, sizeof(pdev_data));
 
-       /* TODO: add DT parsing when needed */
-
        pdev_data.if_ops = &spi_ops;
 
        glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
@@ -353,6 +416,21 @@ static int wl1271_probe(struct spi_device *spi)
         * comes from the board-peripherals file */
        spi->bits_per_word = 32;
 
+       glue->reg = devm_regulator_get(&spi->dev, "vwlan");
+       if (PTR_ERR(glue->reg) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (IS_ERR(glue->reg)) {
+               dev_err(glue->dev, "can't get regulator\n");
+               return PTR_ERR(glue->reg);
+       }
+
+       ret = wlcore_probe_of(spi, glue, &pdev_data);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(glue->dev,
+                       "can't get device tree parameters (%d)\n", ret);
+               return ret;
+       }
+
        ret = spi_setup(spi);
        if (ret < 0) {
                dev_err(glue->dev, "spi_setup failed\n");
@@ -370,7 +448,7 @@ static int wl1271_probe(struct spi_device *spi)
        memset(res, 0x00, sizeof(res));
 
        res[0].start = spi->irq;
-       res[0].flags = IORESOURCE_IRQ;
+       res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(spi->irq);
        res[0].name = "irq";
 
        ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
@@ -408,10 +486,10 @@ static int wl1271_remove(struct spi_device *spi)
        return 0;
 }
 
-
 static struct spi_driver wl1271_spi_driver = {
        .driver = {
                .name           = "wl1271_spi",
+               .of_match_table = of_match_ptr(wlcore_spi_of_match_table),
        },
 
        .probe          = wl1271_probe,
index 112825200d4192d6da01ae5b70ba52e41c886ffc..f44b388464208d25b4d11613a2f8b16862256ec4 100644 (file)
@@ -52,6 +52,7 @@ typedef unsigned int pending_ring_idx_t;
 
 struct pending_tx_info {
        struct xen_netif_tx_request req; /* tx request */
+       unsigned int extra_count;
        /* 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
index 61b97c34bb3b86412b06578f97a15a596df9965e..b42f26029225fd69d9c57fe3088b31fdb5ab39bb 100644 (file)
@@ -95,6 +95,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
+                            unsigned int extra_count,
                             s8       st);
 static void push_tx_responses(struct xenvif_queue *queue);
 
@@ -696,14 +697,15 @@ void xenvif_tx_credit_callback(unsigned long data)
 }
 
 static void xenvif_tx_err(struct xenvif_queue *queue,
-                         struct xen_netif_tx_request *txp, RING_IDX end)
+                         struct xen_netif_tx_request *txp,
+                         unsigned int extra_count, RING_IDX end)
 {
        RING_IDX cons = queue->tx.req_cons;
        unsigned long flags;
 
        do {
                spin_lock_irqsave(&queue->response_lock, flags);
-               make_tx_response(queue, txp, XEN_NETIF_RSP_ERROR);
+               make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR);
                push_tx_responses(queue);
                spin_unlock_irqrestore(&queue->response_lock, flags);
                if (cons == end)
@@ -724,6 +726,7 @@ static void xenvif_fatal_tx_err(struct xenvif *vif)
 
 static int xenvif_count_requests(struct xenvif_queue *queue,
                                 struct xen_netif_tx_request *first,
+                                unsigned int extra_count,
                                 struct xen_netif_tx_request *txp,
                                 int work_to_do)
 {
@@ -812,7 +815,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
        } while (more_data);
 
        if (drop_err) {
-               xenvif_tx_err(queue, first, cons + slots);
+               xenvif_tx_err(queue, first, extra_count, cons + slots);
                return drop_err;
        }
 
@@ -827,9 +830,10 @@ struct xenvif_tx_cb {
 #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
 
 static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue,
-                                         u16 pending_idx,
-                                         struct xen_netif_tx_request *txp,
-                                         struct gnttab_map_grant_ref *mop)
+                                          u16 pending_idx,
+                                          struct xen_netif_tx_request *txp,
+                                          unsigned int extra_count,
+                                          struct gnttab_map_grant_ref *mop)
 {
        queue->pages_to_map[mop-queue->tx_map_ops] = queue->mmap_pages[pending_idx];
        gnttab_set_map_op(mop, idx_to_kaddr(queue, pending_idx),
@@ -838,6 +842,7 @@ static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue,
 
        memcpy(&queue->pending_tx_info[pending_idx].req, txp,
               sizeof(*txp));
+       queue->pending_tx_info[pending_idx].extra_count = extra_count;
 }
 
 static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
@@ -880,7 +885,7 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
             shinfo->nr_frags++, txp++, gop++) {
                index = pending_index(queue->pending_cons++);
                pending_idx = queue->pending_ring[index];
-               xenvif_tx_create_map_op(queue, pending_idx, txp, gop);
+               xenvif_tx_create_map_op(queue, pending_idx, txp, 0, gop);
                frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
        }
 
@@ -893,7 +898,8 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif_queue *que
                     shinfo->nr_frags++, txp++, gop++) {
                        index = pending_index(queue->pending_cons++);
                        pending_idx = queue->pending_ring[index];
-                       xenvif_tx_create_map_op(queue, pending_idx, txp, gop);
+                       xenvif_tx_create_map_op(queue, pending_idx, txp, 0,
+                                               gop);
                        frag_set_pending_idx(&frags[shinfo->nr_frags],
                                             pending_idx);
                }
@@ -1095,8 +1101,9 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb)
 }
 
 static int xenvif_get_extras(struct xenvif_queue *queue,
-                               struct xen_netif_extra_info *extras,
-                               int work_to_do)
+                            struct xen_netif_extra_info *extras,
+                            unsigned int *extra_count,
+                            int work_to_do)
 {
        struct xen_netif_extra_info extra;
        RING_IDX cons = queue->tx.req_cons;
@@ -1109,9 +1116,12 @@ static int xenvif_get_extras(struct xenvif_queue *queue,
                }
 
                RING_COPY_REQUEST(&queue->tx, cons, &extra);
+
+               queue->tx.req_cons = ++cons;
+               (*extra_count)++;
+
                if (unlikely(!extra.type ||
                             extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-                       queue->tx.req_cons = ++cons;
                        netdev_err(queue->vif->dev,
                                   "Invalid extra type: %d\n", extra.type);
                        xenvif_fatal_tx_err(queue->vif);
@@ -1119,7 +1129,6 @@ static int xenvif_get_extras(struct xenvif_queue *queue,
                }
 
                memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-               queue->tx.req_cons = ++cons;
        } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
 
        return work_to_do;
@@ -1294,6 +1303,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                struct xen_netif_tx_request txreq;
                struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
                struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
+               unsigned int extra_count;
                u16 pending_idx;
                RING_IDX idx;
                int work_to_do;
@@ -1330,8 +1340,10 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                queue->tx.req_cons = ++idx;
 
                memset(extras, 0, sizeof(extras));
+               extra_count = 0;
                if (txreq.flags & XEN_NETTXF_extra_info) {
                        work_to_do = xenvif_get_extras(queue, extras,
+                                                      &extra_count,
                                                       work_to_do);
                        idx = queue->tx.req_cons;
                        if (unlikely(work_to_do < 0))
@@ -1344,7 +1356,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1];
                        ret = xenvif_mcast_add(queue->vif, extra->u.mcast.addr);
 
-                       make_tx_response(queue, &txreq,
+                       make_tx_response(queue, &txreq, extra_count,
                                         (ret == 0) ?
                                         XEN_NETIF_RSP_OKAY :
                                         XEN_NETIF_RSP_ERROR);
@@ -1358,12 +1370,14 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1];
                        xenvif_mcast_del(queue->vif, extra->u.mcast.addr);
 
-                       make_tx_response(queue, &txreq, XEN_NETIF_RSP_OKAY);
+                       make_tx_response(queue, &txreq, extra_count,
+                                        XEN_NETIF_RSP_OKAY);
                        push_tx_responses(queue);
                        continue;
                }
 
-               ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do);
+               ret = xenvif_count_requests(queue, &txreq, extra_count,
+                                           txfrags, work_to_do);
                if (unlikely(ret < 0))
                        break;
 
@@ -1372,7 +1386,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                if (unlikely(txreq.size < ETH_HLEN)) {
                        netdev_dbg(queue->vif->dev,
                                   "Bad packet size: %d\n", txreq.size);
-                       xenvif_tx_err(queue, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, extra_count, idx);
                        break;
                }
 
@@ -1397,7 +1411,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                if (unlikely(skb == NULL)) {
                        netdev_dbg(queue->vif->dev,
                                   "Can't allocate a skb in start_xmit.\n");
-                       xenvif_tx_err(queue, &txreq, idx);
+                       xenvif_tx_err(queue, &txreq, extra_count, idx);
                        break;
                }
 
@@ -1416,7 +1430,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                        nskb = xenvif_alloc_skb(0);
                        if (unlikely(nskb == NULL)) {
                                kfree_skb(skb);
-                               xenvif_tx_err(queue, &txreq, idx);
+                               xenvif_tx_err(queue, &txreq, extra_count, idx);
                                if (net_ratelimit())
                                        netdev_err(queue->vif->dev,
                                                   "Can't allocate the frag_list skb.\n");
@@ -1457,13 +1471,16 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
                if (data_len < txreq.size) {
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             pending_idx);
-                       xenvif_tx_create_map_op(queue, pending_idx, &txreq, gop);
+                       xenvif_tx_create_map_op(queue, pending_idx, &txreq,
+                                               extra_count, gop);
                        gop++;
                } else {
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             INVALID_PENDING_IDX);
-                       memcpy(&queue->pending_tx_info[pending_idx].req, &txreq,
-                              sizeof(txreq));
+                       memcpy(&queue->pending_tx_info[pending_idx].req,
+                              &txreq, sizeof(txreq));
+                       queue->pending_tx_info[pending_idx].extra_count =
+                               extra_count;
                }
 
                queue->pending_cons++;
@@ -1804,7 +1821,8 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 
        spin_lock_irqsave(&queue->response_lock, flags);
 
-       make_tx_response(queue, &pending_tx_info->req, status);
+       make_tx_response(queue, &pending_tx_info->req,
+                        pending_tx_info->extra_count, status);
 
        /* Release the pending index before pusing the Tx response so
         * its available before a new Tx request is pushed by the
@@ -1821,6 +1839,7 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
 
 static void make_tx_response(struct xenvif_queue *queue,
                             struct xen_netif_tx_request *txp,
+                            unsigned int extra_count,
                             s8       st)
 {
        RING_IDX i = queue->tx.rsp_prod_pvt;
@@ -1830,7 +1849,7 @@ static void make_tx_response(struct xenvif_queue *queue,
        resp->id     = txp->id;
        resp->status = st;
 
-       if (txp->flags & XEN_NETTXF_extra_info)
+       while (extra_count-- != 0)
                RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
 
        queue->tx.rsp_prod_pvt = ++i;
index 39a303de20dd4e0f37bfa00d4c5eaade6590519c..bd182cd55dda87c76b3984bbec8cfef493284dd1 100644 (file)
@@ -511,8 +511,6 @@ static void set_backend_state(struct backend_info *be,
                        switch (state) {
                        case XenbusStateInitWait:
                        case XenbusStateConnected:
-                               pr_info("%s: prepare for reconnect\n",
-                                       be->dev->nodename);
                                backend_switch_state(be, XenbusStateInitWait);
                                break;
                        case XenbusStateClosing:
index 7e2c43f701bc451463c5273ed3a5a1e49f6be15f..5d28e9405f32fb96dc79049d5cc4dbca01af14c3 100644 (file)
@@ -382,18 +382,18 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
        [ND_CMD_ARS_CAP] = {
                .in_num = 2,
                .in_sizes = { 8, 8, },
-               .out_num = 2,
-               .out_sizes = { 4, 4, },
+               .out_num = 4,
+               .out_sizes = { 4, 4, 4, 4, },
        },
        [ND_CMD_ARS_START] = {
-               .in_num = 4,
-               .in_sizes = { 8, 8, 2, 6, },
-               .out_num = 1,
-               .out_sizes = { 4, },
+               .in_num = 5,
+               .in_sizes = { 8, 8, 2, 1, 5, },
+               .out_num = 2,
+               .out_sizes = { 4, 4, },
        },
        [ND_CMD_ARS_STATUS] = {
-               .out_num = 2,
-               .out_sizes = { 4, UINT_MAX, },
+               .out_num = 3,
+               .out_sizes = { 4, 4, UINT_MAX, },
        },
 };
 
@@ -442,8 +442,8 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                return in_field[1];
        else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
                return out_field[1];
-       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 1)
-               return ND_CMD_ARS_STATUS_MAX;
+       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
+               return out_field[1] - 8;
 
        return UINT_MAX;
 }
index 7edf31671dabed8f8d193806f54f3d1b30401e7c..8d0b546701848eb2b57d87b7207490133e5c32a9 100644 (file)
@@ -41,7 +41,7 @@ struct pmem_device {
        phys_addr_t             phys_addr;
        /* when non-zero this device is hosting a 'pfn' instance */
        phys_addr_t             data_offset;
-       unsigned long           pfn_flags;
+       u64                     pfn_flags;
        void __pmem             *virt_addr;
        size_t                  size;
        struct badblocks        bb;
index 5d6237391dcd4e3851390abe9b1412217d2428d8..b586d84f251881801ae75023fd3fd6e6bd884047 100644 (file)
@@ -17,5 +17,6 @@ config BLK_DEV_NVME_SCSI
          and block devices nodes, as well a a translation for a small
          number of selected SCSI commands to NVMe commands to the NVMe
          driver.  If you don't know what this means you probably want
-         to say N here, and if you know what it means you probably
-         want to say N as well.
+         to say N here, unless you run a distro that abuses the SCSI
+         emulation to provide stable device names for mount by id, like
+         some OpenSuSE and SLES versions.
index c5bf001af55954e2c9275d34c65cbb5dfa2a037d..03c46412fff4d602477239d0672cbdeb54c13dfb 100644 (file)
@@ -55,8 +55,9 @@ static void nvme_free_ns(struct kref *kref)
        ns->disk->private_data = NULL;
        spin_unlock(&dev_list_lock);
 
-       nvme_put_ctrl(ns->ctrl);
        put_disk(ns->disk);
+       ida_simple_remove(&ns->ctrl->ns_ida, ns->instance);
+       nvme_put_ctrl(ns->ctrl);
        kfree(ns);
 }
 
@@ -183,7 +184,7 @@ int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
                        goto out_unmap;
                }
 
-               if (meta_buffer) {
+               if (meta_buffer && meta_len) {
                        struct bio_integrity_payload *bip;
 
                        meta = kmalloc(meta_len, GFP_KERNEL);
@@ -373,6 +374,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
 
        if (copy_from_user(&io, uio, sizeof(io)))
                return -EFAULT;
+       if (io.flags)
+               return -EINVAL;
 
        switch (io.opcode) {
        case nvme_cmd_write:
@@ -424,6 +427,8 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                return -EACCES;
        if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
                return -EFAULT;
+       if (cmd.flags)
+               return -EINVAL;
 
        memset(&c, 0, sizeof(c));
        c.common.opcode = cmd.opcode;
@@ -556,6 +561,10 @@ static int nvme_revalidate_disk(struct gendisk *disk)
        u16 old_ms;
        unsigned short bs;
 
+       if (test_bit(NVME_NS_DEAD, &ns->flags)) {
+               set_capacity(disk, 0);
+               return -ENODEV;
+       }
        if (nvme_identify_ns(ns->ctrl, ns->ns_id, &id)) {
                dev_warn(ns->ctrl->dev, "%s: Identify failure nvme%dn%d\n",
                                __func__, ns->ctrl->instance, ns->ns_id);
@@ -831,6 +840,23 @@ int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl)
        return ret;
 }
 
+static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
+               struct request_queue *q)
+{
+       if (ctrl->max_hw_sectors) {
+               u32 max_segments =
+                       (ctrl->max_hw_sectors / (ctrl->page_size >> 9)) + 1;
+
+               blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors);
+               blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX));
+       }
+       if (ctrl->stripe_size)
+               blk_queue_chunk_sectors(q, ctrl->stripe_size >> 9);
+       if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
+               blk_queue_flush(q, REQ_FLUSH | REQ_FUA);
+       blk_queue_virt_boundary(q, ctrl->page_size - 1);
+}
+
 /*
  * Initialize the cached copies of the Identify data and various controller
  * register in our nvme_ctrl structure.  This should be called as soon as
@@ -888,6 +914,8 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
                }
        }
 
+       nvme_set_queue_limits(ctrl, ctrl->admin_q);
+
        kfree(id);
        return 0;
 }
@@ -1118,10 +1146,13 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        if (!ns)
                return;
 
+       ns->instance = ida_simple_get(&ctrl->ns_ida, 1, 0, GFP_KERNEL);
+       if (ns->instance < 0)
+               goto out_free_ns;
+
        ns->queue = blk_mq_init_queue(ctrl->tagset);
        if (IS_ERR(ns->queue))
-               goto out_free_ns;
-       queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, ns->queue);
+               goto out_release_instance;
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, ns->queue);
        ns->queue->queuedata = ns;
        ns->ctrl = ctrl;
@@ -1135,17 +1166,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        ns->disk = disk;
        ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
 
+
        blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
-       if (ctrl->max_hw_sectors) {
-               blk_queue_max_hw_sectors(ns->queue, ctrl->max_hw_sectors);
-               blk_queue_max_segments(ns->queue,
-                       (ctrl->max_hw_sectors / (ctrl->page_size >> 9)) + 1);
-       }
-       if (ctrl->stripe_size)
-               blk_queue_chunk_sectors(ns->queue, ctrl->stripe_size >> 9);
-       if (ctrl->vwc & NVME_CTRL_VWC_PRESENT)
-               blk_queue_flush(ns->queue, REQ_FLUSH | REQ_FUA);
-       blk_queue_virt_boundary(ns->queue, ctrl->page_size - 1);
+       nvme_set_queue_limits(ctrl, ns->queue);
 
        disk->major = nvme_major;
        disk->first_minor = 0;
@@ -1154,7 +1177,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        disk->queue = ns->queue;
        disk->driverfs_dev = ctrl->device;
        disk->flags = GENHD_FL_EXT_DEVT;
-       sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, nsid);
+       sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
 
        if (nvme_revalidate_disk(ns->disk))
                goto out_free_disk;
@@ -1174,40 +1197,29 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        kfree(disk);
  out_free_queue:
        blk_cleanup_queue(ns->queue);
+ out_release_instance:
+       ida_simple_remove(&ctrl->ns_ida, ns->instance);
  out_free_ns:
        kfree(ns);
 }
 
 static void nvme_ns_remove(struct nvme_ns *ns)
 {
-       bool kill = nvme_io_incapable(ns->ctrl) &&
-                       !blk_queue_dying(ns->queue);
-
-       lockdep_assert_held(&ns->ctrl->namespaces_mutex);
-
-       if (kill) {
-               blk_set_queue_dying(ns->queue);
+       if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
+               return;
 
-               /*
-                * The controller was shutdown first if we got here through
-                * device removal. The shutdown may requeue outstanding
-                * requests. These need to be aborted immediately so
-                * del_gendisk doesn't block indefinitely for their completion.
-                */
-               blk_mq_abort_requeue_list(ns->queue);
-       }
        if (ns->disk->flags & GENHD_FL_UP) {
                if (blk_get_integrity(ns->disk))
                        blk_integrity_unregister(ns->disk);
                sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
                                        &nvme_ns_attr_group);
                del_gendisk(ns->disk);
-       }
-       if (kill || !blk_queue_dying(ns->queue)) {
                blk_mq_abort_requeue_list(ns->queue);
                blk_cleanup_queue(ns->queue);
        }
+       mutex_lock(&ns->ctrl->namespaces_mutex);
        list_del_init(&ns->list);
+       mutex_unlock(&ns->ctrl->namespaces_mutex);
        nvme_put_ns(ns);
 }
 
@@ -1301,10 +1313,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
 {
        struct nvme_ns *ns, *next;
 
-       mutex_lock(&ctrl->namespaces_mutex);
        list_for_each_entry_safe(ns, next, &ctrl->namespaces, list)
                nvme_ns_remove(ns);
-       mutex_unlock(&ctrl->namespaces_mutex);
 }
 
 static DEFINE_IDA(nvme_instance_ida);
@@ -1351,6 +1361,7 @@ static void nvme_free_ctrl(struct kref *kref)
 
        put_device(ctrl->device);
        nvme_release_instance(ctrl);
+       ida_destroy(&ctrl->ns_ida);
 
        ctrl->ops->free_ctrl(ctrl);
 }
@@ -1391,6 +1402,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
        }
        get_device(ctrl->device);
        dev_set_drvdata(ctrl->device, ctrl);
+       ida_init(&ctrl->ns_ida);
 
        spin_lock(&dev_list_lock);
        list_add_tail(&ctrl->node, &nvme_ctrl_list);
@@ -1403,6 +1415,38 @@ out:
        return ret;
 }
 
+/**
+ * nvme_kill_queues(): Ends all namespace queues
+ * @ctrl: the dead controller that needs to end
+ *
+ * Call this function when the driver determines it is unable to get the
+ * controller in a state capable of servicing IO.
+ */
+void nvme_kill_queues(struct nvme_ctrl *ctrl)
+{
+       struct nvme_ns *ns;
+
+       mutex_lock(&ctrl->namespaces_mutex);
+       list_for_each_entry(ns, &ctrl->namespaces, list) {
+               if (!kref_get_unless_zero(&ns->kref))
+                       continue;
+
+               /*
+                * Revalidating a dead namespace sets capacity to 0. This will
+                * end buffered writers dirtying pages that can't be synced.
+                */
+               if (!test_and_set_bit(NVME_NS_DEAD, &ns->flags))
+                       revalidate_disk(ns->disk);
+
+               blk_set_queue_dying(ns->queue);
+               blk_mq_abort_requeue_list(ns->queue);
+               blk_mq_start_stopped_hw_queues(ns->queue, true);
+
+               nvme_put_ns(ns);
+       }
+       mutex_unlock(&ctrl->namespaces_mutex);
+}
+
 void nvme_stop_queues(struct nvme_ctrl *ctrl)
 {
        struct nvme_ns *ns;
index 5cd3725e2fa44ae7379a81a6f1bf03bf0d45e895..6bb15e4926dc86ed8b30e5cc2c504dc29090d545 100644 (file)
@@ -146,9 +146,10 @@ struct nvme_nvm_command {
        };
 };
 
+#define NVME_NVM_LP_MLC_PAIRS 886
 struct nvme_nvm_lp_mlc {
        __u16                   num_pairs;
-       __u8                    pairs[886];
+       __u8                    pairs[NVME_NVM_LP_MLC_PAIRS];
 };
 
 struct nvme_nvm_lp_tbl {
@@ -282,9 +283,14 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
                        memcpy(dst->lptbl.id, src->lptbl.id, 8);
                        dst->lptbl.mlc.num_pairs =
                                        le16_to_cpu(src->lptbl.mlc.num_pairs);
-                       /* 4 bits per pair */
+
+                       if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) {
+                               pr_err("nvm: number of MLC pairs not supported\n");
+                               return -EINVAL;
+                       }
+
                        memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs,
-                                               dst->lptbl.mlc.num_pairs >> 1);
+                                               dst->lptbl.mlc.num_pairs);
                }
        }
 
index 4fb5bb737868ce2db7da41700cd238c8804b086c..fb15ba5f5d19f5650fd2cb76643b2217b06891b0 100644 (file)
@@ -72,6 +72,7 @@ struct nvme_ctrl {
        struct mutex namespaces_mutex;
        struct device *device;  /* char device */
        struct list_head node;
+       struct ida ns_ida;
 
        char name[12];
        char serial[20];
@@ -102,6 +103,7 @@ struct nvme_ns {
        struct request_queue *queue;
        struct gendisk *disk;
        struct kref kref;
+       int instance;
 
        u8 eui[8];
        u8 uuid[16];
@@ -112,6 +114,11 @@ struct nvme_ns {
        bool ext;
        u8 pi_type;
        int type;
+       unsigned long flags;
+
+#define NVME_NS_REMOVING 0
+#define NVME_NS_DEAD     1
+
        u64 mode_select_num_blocks;
        u32 mode_select_block_len;
 };
@@ -139,9 +146,9 @@ static inline bool nvme_io_incapable(struct nvme_ctrl *ctrl)
        u32 val = 0;
 
        if (ctrl->ops->io_incapable(ctrl))
-               return false;
+               return true;
        if (ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &val))
-               return false;
+               return true;
        return val & NVME_CSTS_CFS;
 }
 
@@ -240,6 +247,7 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl);
 
 void nvme_stop_queues(struct nvme_ctrl *ctrl);
 void nvme_start_queues(struct nvme_ctrl *ctrl);
+void nvme_kill_queues(struct nvme_ctrl *ctrl);
 
 struct request *nvme_alloc_request(struct request_queue *q,
                struct nvme_command *cmd, unsigned int flags);
index 72ef8322d32ac7180912e2ae2cf38245f3713d9a..680f5780750cffa45efc93101fb60eb744fdd04c 100644 (file)
@@ -86,7 +86,6 @@ struct nvme_queue;
 
 static int nvme_reset(struct nvme_dev *dev);
 static void nvme_process_cq(struct nvme_queue *nvmeq);
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev);
 static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown);
 
 /*
@@ -120,6 +119,7 @@ struct nvme_dev {
        unsigned long flags;
 
 #define NVME_CTRL_RESETTING    0
+#define NVME_CTRL_REMOVING     1
 
        struct nvme_ctrl ctrl;
        struct completion ioq_wait;
@@ -286,6 +286,17 @@ static int nvme_init_request(void *data, struct request *req,
        return 0;
 }
 
+static void nvme_queue_scan(struct nvme_dev *dev)
+{
+       /*
+        * Do not queue new scan work when a controller is reset during
+        * removal.
+        */
+       if (test_bit(NVME_CTRL_REMOVING, &dev->flags))
+               return;
+       queue_work(nvme_workq, &dev->scan_work);
+}
+
 static void nvme_complete_async_event(struct nvme_dev *dev,
                struct nvme_completion *cqe)
 {
@@ -300,7 +311,7 @@ static void nvme_complete_async_event(struct nvme_dev *dev,
        switch (result & 0xff07) {
        case NVME_AER_NOTICE_NS_CHANGED:
                dev_info(dev->dev, "rescanning\n");
-               queue_work(nvme_workq, &dev->scan_work);
+               nvme_queue_scan(dev);
        default:
                dev_warn(dev->dev, "async event result %08x\n", result);
        }
@@ -678,6 +689,14 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
        blk_mq_start_request(req);
 
        spin_lock_irq(&nvmeq->q_lock);
+       if (unlikely(nvmeq->cq_vector < 0)) {
+               if (ns && !test_bit(NVME_NS_DEAD, &ns->flags))
+                       ret = BLK_MQ_RQ_QUEUE_BUSY;
+               else
+                       ret = BLK_MQ_RQ_QUEUE_ERROR;
+               spin_unlock_irq(&nvmeq->q_lock);
+               goto out;
+       }
        __nvme_submit_cmd(nvmeq, &cmnd);
        nvme_process_cq(nvmeq);
        spin_unlock_irq(&nvmeq->q_lock);
@@ -999,7 +1018,7 @@ static void nvme_cancel_queue_ios(struct request *req, void *data, bool reserved
        if (!blk_mq_request_started(req))
                return;
 
-       dev_warn(nvmeq->q_dmadev,
+       dev_dbg_ratelimited(nvmeq->q_dmadev,
                 "Cancelling I/O %d QID %d\n", req->tag, nvmeq->qid);
 
        status = NVME_SC_ABORT_REQ;
@@ -1245,6 +1264,12 @@ static struct blk_mq_ops nvme_mq_ops = {
 static void nvme_dev_remove_admin(struct nvme_dev *dev)
 {
        if (dev->ctrl.admin_q && !blk_queue_dying(dev->ctrl.admin_q)) {
+               /*
+                * If the controller was reset during removal, it's possible
+                * user requests may be waiting on a stopped queue. Start the
+                * queue to flush these to completion.
+                */
+               blk_mq_start_stopped_hw_queues(dev->ctrl.admin_q, true);
                blk_cleanup_queue(dev->ctrl.admin_q);
                blk_mq_free_tag_set(&dev->admin_tagset);
        }
@@ -1685,14 +1710,14 @@ static int nvme_dev_add(struct nvme_dev *dev)
                        return 0;
                dev->ctrl.tagset = &dev->tagset;
        }
-       queue_work(nvme_workq, &dev->scan_work);
+       nvme_queue_scan(dev);
        return 0;
 }
 
-static int nvme_dev_map(struct nvme_dev *dev)
+static int nvme_pci_enable(struct nvme_dev *dev)
 {
        u64 cap;
-       int bars, result = -ENOMEM;
+       int result = -ENOMEM;
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        if (pci_enable_device_mem(pdev))
@@ -1700,24 +1725,14 @@ static int nvme_dev_map(struct nvme_dev *dev)
 
        dev->entry[0].vector = pdev->irq;
        pci_set_master(pdev);
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (!bars)
-               goto disable_pci;
-
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
-               goto disable_pci;
 
        if (dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64)) &&
            dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(32)))
                goto disable;
 
-       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
-       if (!dev->bar)
-               goto disable;
-
        if (readl(dev->bar + NVME_REG_CSTS) == -1) {
                result = -ENODEV;
-               goto unmap;
+               goto disable;
        }
 
        /*
@@ -1727,7 +1742,7 @@ static int nvme_dev_map(struct nvme_dev *dev)
        if (!pdev->irq) {
                result = pci_enable_msix(pdev, dev->entry, 1);
                if (result < 0)
-                       goto unmap;
+                       goto disable;
        }
 
        cap = lo_hi_readq(dev->bar + NVME_REG_CAP);
@@ -1754,17 +1769,19 @@ static int nvme_dev_map(struct nvme_dev *dev)
        pci_save_state(pdev);
        return 0;
 
- unmap:
-       iounmap(dev->bar);
-       dev->bar = NULL;
  disable:
-       pci_release_regions(pdev);
- disable_pci:
        pci_disable_device(pdev);
        return result;
 }
 
 static void nvme_dev_unmap(struct nvme_dev *dev)
+{
+       if (dev->bar)
+               iounmap(dev->bar);
+       pci_release_regions(to_pci_dev(dev->dev));
+}
+
+static void nvme_pci_disable(struct nvme_dev *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
@@ -1773,12 +1790,6 @@ static void nvme_dev_unmap(struct nvme_dev *dev)
        else if (pdev->msix_enabled)
                pci_disable_msix(pdev);
 
-       if (dev->bar) {
-               iounmap(dev->bar);
-               dev->bar = NULL;
-               pci_release_regions(pdev);
-       }
-
        if (pci_is_enabled(pdev)) {
                pci_disable_pcie_error_reporting(pdev);
                pci_disable_device(pdev);
@@ -1837,7 +1848,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
        nvme_dev_list_remove(dev);
 
        mutex_lock(&dev->shutdown_lock);
-       if (dev->bar) {
+       if (pci_is_enabled(to_pci_dev(dev->dev))) {
                nvme_stop_queues(&dev->ctrl);
                csts = readl(dev->bar + NVME_REG_CSTS);
        }
@@ -1850,7 +1861,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
                nvme_disable_io_queues(dev);
                nvme_disable_admin_queue(dev, shutdown);
        }
-       nvme_dev_unmap(dev);
+       nvme_pci_disable(dev);
 
        for (i = dev->queue_count - 1; i >= 0; i--)
                nvme_clear_queue(dev->queues[i]);
@@ -1894,10 +1905,20 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
        kfree(dev);
 }
 
+static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status)
+{
+       dev_warn(dev->dev, "Removing after probe failure status: %d\n", status);
+
+       kref_get(&dev->ctrl.kref);
+       nvme_dev_disable(dev, false);
+       if (!schedule_work(&dev->remove_work))
+               nvme_put_ctrl(&dev->ctrl);
+}
+
 static void nvme_reset_work(struct work_struct *work)
 {
        struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
-       int result;
+       int result = -ENODEV;
 
        if (WARN_ON(test_bit(NVME_CTRL_RESETTING, &dev->flags)))
                goto out;
@@ -1906,37 +1927,37 @@ static void nvme_reset_work(struct work_struct *work)
         * If we're called to reset a live controller first shut it down before
         * moving on.
         */
-       if (dev->bar)
+       if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
                nvme_dev_disable(dev, false);
 
        set_bit(NVME_CTRL_RESETTING, &dev->flags);
 
-       result = nvme_dev_map(dev);
+       result = nvme_pci_enable(dev);
        if (result)
                goto out;
 
        result = nvme_configure_admin_queue(dev);
        if (result)
-               goto unmap;
+               goto out;
 
        nvme_init_queue(dev->queues[0], 0);
        result = nvme_alloc_admin_tags(dev);
        if (result)
-               goto disable;
+               goto out;
 
        result = nvme_init_identify(&dev->ctrl);
        if (result)
-               goto free_tags;
+               goto out;
 
        result = nvme_setup_io_queues(dev);
        if (result)
-               goto free_tags;
+               goto out;
 
        dev->ctrl.event_limit = NVME_NR_AEN_COMMANDS;
 
        result = nvme_dev_list_add(dev);
        if (result)
-               goto remove;
+               goto out;
 
        /*
         * Keep the controller around but remove all namespaces if we don't have
@@ -1953,19 +1974,8 @@ static void nvme_reset_work(struct work_struct *work)
        clear_bit(NVME_CTRL_RESETTING, &dev->flags);
        return;
 
- remove:
-       nvme_dev_list_remove(dev);
- free_tags:
-       nvme_dev_remove_admin(dev);
-       blk_put_queue(dev->ctrl.admin_q);
-       dev->ctrl.admin_q = NULL;
-       dev->queues[0]->tags = NULL;
- disable:
-       nvme_disable_admin_queue(dev, false);
- unmap:
-       nvme_dev_unmap(dev);
  out:
-       nvme_remove_dead_ctrl(dev);
+       nvme_remove_dead_ctrl(dev, result);
 }
 
 static void nvme_remove_dead_ctrl_work(struct work_struct *work)
@@ -1973,19 +1983,12 @@ static void nvme_remove_dead_ctrl_work(struct work_struct *work)
        struct nvme_dev *dev = container_of(work, struct nvme_dev, remove_work);
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
+       nvme_kill_queues(&dev->ctrl);
        if (pci_get_drvdata(pdev))
                pci_stop_and_remove_bus_device_locked(pdev);
        nvme_put_ctrl(&dev->ctrl);
 }
 
-static void nvme_remove_dead_ctrl(struct nvme_dev *dev)
-{
-       dev_warn(dev->dev, "Removing after probe failure\n");
-       kref_get(&dev->ctrl.kref);
-       if (!schedule_work(&dev->remove_work))
-               nvme_put_ctrl(&dev->ctrl);
-}
-
 static int nvme_reset(struct nvme_dev *dev)
 {
        if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
@@ -2037,6 +2040,27 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
        .free_ctrl              = nvme_pci_free_ctrl,
 };
 
+static int nvme_dev_map(struct nvme_dev *dev)
+{
+       int bars;
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
+
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (!bars)
+               return -ENODEV;
+       if (pci_request_selected_regions(pdev, bars, "nvme"))
+               return -ENODEV;
+
+       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+       if (!dev->bar)
+               goto release;
+
+       return 0;
+  release:
+       pci_release_regions(pdev);
+       return -ENODEV;
+}
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int node, result = -ENOMEM;
@@ -2061,6 +2085,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev->dev = get_device(&pdev->dev);
        pci_set_drvdata(pdev, dev);
 
+       result = nvme_dev_map(dev);
+       if (result)
+               goto free;
+
        INIT_LIST_HEAD(&dev->node);
        INIT_WORK(&dev->scan_work, nvme_dev_scan);
        INIT_WORK(&dev->reset_work, nvme_reset_work);
@@ -2084,6 +2112,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        nvme_release_prp_pools(dev);
  put_pci:
        put_device(dev->dev);
+       nvme_dev_unmap(dev);
  free:
        kfree(dev->queues);
        kfree(dev->entry);
@@ -2107,24 +2136,27 @@ static void nvme_shutdown(struct pci_dev *pdev)
        nvme_dev_disable(dev, true);
 }
 
+/*
+ * The driver's remove may be called on a device in a partially initialized
+ * state. This function must not have any dependencies on the device state in
+ * order to proceed.
+ */
 static void nvme_remove(struct pci_dev *pdev)
 {
        struct nvme_dev *dev = pci_get_drvdata(pdev);
 
-       spin_lock(&dev_list_lock);
-       list_del_init(&dev->node);
-       spin_unlock(&dev_list_lock);
-
+       set_bit(NVME_CTRL_REMOVING, &dev->flags);
        pci_set_drvdata(pdev, NULL);
-       flush_work(&dev->reset_work);
        flush_work(&dev->scan_work);
        nvme_remove_namespaces(&dev->ctrl);
        nvme_uninit_ctrl(&dev->ctrl);
        nvme_dev_disable(dev, true);
+       flush_work(&dev->reset_work);
        nvme_dev_remove_admin(dev);
        nvme_free_queues(dev, 0);
        nvme_release_cmb(dev);
        nvme_release_prp_pools(dev);
+       nvme_dev_unmap(dev);
        nvme_put_ctrl(&dev->ctrl);
 }
 
index 6fd4e5a5ef4a495bbd412ee33b931f4fb3a8a24f..9d11d98373128fef3de3406975d8bcc2ca286b9a 100644 (file)
@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
        if (pos >= nvmem->size)
                return 0;
 
+       if (count < nvmem->word_size)
+               return -EINVAL;
+
        if (pos + count > nvmem->size)
                count = nvmem->size - pos;
 
@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
        if (pos >= nvmem->size)
                return 0;
 
+       if (count < nvmem->word_size)
+               return -EINVAL;
+
        if (pos + count > nvmem->size)
                count = nvmem->size - pos;
 
index afb67e7eeee4a89612d56d0404726d7778c12a53..3829e5fbf8c366bf3ae7fa7149e87e5c0ddcf6f3 100644 (file)
@@ -21,6 +21,7 @@ static struct regmap_config qfprom_regmap_config = {
        .reg_bits = 32,
        .val_bits = 8,
        .reg_stride = 1,
+       .val_format_endian = REGMAP_ENDIAN_LITTLE,
 };
 
 static struct nvmem_config econfig = {
index 7ee21ae305ae10d480adce961ad59fe284ca366e..e7bfc175b8e1e9a0a171a3173191861399d21b1d 100644 (file)
@@ -635,6 +635,13 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
                msi_base = be32_to_cpup(msi_map + 2);
                rid_len = be32_to_cpup(msi_map + 3);
 
+               if (rid_base & ~map_mask) {
+                       dev_err(parent_dev,
+                               "Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n",
+                               map_mask, rid_base);
+                       return rid_out;
+               }
+
                msi_controller_node = of_find_node_by_phandle(phandle);
 
                matched = (masked_rid >= rid_base &&
@@ -654,7 +661,7 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
        if (!matched)
                return rid_out;
 
-       rid_out = masked_rid + msi_base;
+       rid_out = masked_rid - rid_base + msi_base;
        dev_dbg(dev,
                "msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n",
                dev_name(parent_dev), map_mask, rid_base, msi_base,
index 5648317d355f1c4cde7cf7b48cdd21f644d882ca..5e7838290998edb9ec7737b2a6bf2380ebdffbc2 100644 (file)
@@ -154,6 +154,7 @@ static const struct of_device_id whitelist_phys[] = {
        { .compatible = "marvell,88E1111", },
        { .compatible = "marvell,88e1116", },
        { .compatible = "marvell,88e1118", },
+       { .compatible = "marvell,88e1145", },
        { .compatible = "marvell,88e1149r", },
        { .compatible = "marvell,88e1310", },
        { .compatible = "marvell,88E1510", },
@@ -210,7 +211,6 @@ static bool of_mdiobus_child_is_phy(struct device_node *child)
 int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 {
        struct device_node *child;
-       const __be32 *paddr;
        bool scanphys = false;
        int addr, rc;
 
@@ -245,8 +245,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
        /* auto scan for PHYs with empty reg property */
        for_each_available_child_of_node(np, child) {
                /* Skip PHYs with reg property set */
-               paddr = of_get_property(child, "reg", NULL);
-               if (paddr)
+               if (of_find_property(child, "reg", NULL))
                        continue;
 
                for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
@@ -304,6 +303,7 @@ EXPORT_SYMBOL(of_phy_find_device);
  * @dev: pointer to net_device claiming the phy
  * @phy_np: Pointer to device tree node for the PHY
  * @hndlr: Link state callback for the network device
+ * @flags: flags to pass to the PHY
  * @iface: PHY data interface type
  *
  * If successful, returns a pointer to the phy_device with the embedded
index 75a6054265384d806623caabcc34d98e29a45f82..d1cdd9c992ac018fb0d8adb45780a01c201bac25 100644 (file)
@@ -14,6 +14,7 @@ config PCI_DRA7XX
 config PCI_MVEBU
        bool "Marvell EBU PCIe controller"
        depends on ARCH_MVEBU || ARCH_DOVE
+       depends on ARM
        depends on OF
 
 config PCIE_DW
index ed34c9520a02987503b02e2f371ea9e2a6d3a1a4..6153853ca9c31e319f4c6aae6dd92ed05215ba07 100644 (file)
 
 #define to_keystone_pcie(x)    container_of(x, struct keystone_pcie, pp)
 
-static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
-{
-       return sys->private_data;
-}
-
 static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
                                             u32 *bit_pos)
 {
@@ -108,7 +103,7 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
        struct pcie_port *pp;
 
        msi = irq_data_get_msi_desc(d);
-       pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+       pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
        ks_pcie = to_keystone_pcie(pp);
        offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
        update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
@@ -146,7 +141,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
        u32 offset;
 
        msi = irq_data_get_msi_desc(d);
-       pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+       pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
        ks_pcie = to_keystone_pcie(pp);
        offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
 
@@ -167,7 +162,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
        u32 offset;
 
        msi = irq_data_get_msi_desc(d);
-       pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi));
+       pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi);
        ks_pcie = to_keystone_pcie(pp);
        offset = d->irq - irq_linear_revmap(pp->irq_domain, 0);
 
index 3923bed93c7e06fa8327cafef9429c34d1b063cb..f39961bcf7aadb8b79d6635d3a7d9ecbce2f1cae 100644 (file)
@@ -77,6 +77,16 @@ static void ls_pcie_fix_class(struct ls_pcie *pcie)
        iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
 }
 
+/* Drop MSG TLP except for Vendor MSG */
+static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
+{
+       u32 val;
+
+       val = ioread32(pcie->dbi + PCIE_STRFMR1);
+       val &= 0xDFFFFFFF;
+       iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+}
+
 static int ls1021_pcie_link_up(struct pcie_port *pp)
 {
        u32 state;
@@ -97,7 +107,7 @@ static int ls1021_pcie_link_up(struct pcie_port *pp)
 static void ls1021_pcie_host_init(struct pcie_port *pp)
 {
        struct ls_pcie *pcie = to_ls_pcie(pp);
-       u32 val, index[2];
+       u32 index[2];
 
        pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node,
                                                     "fsl,pcie-scfg");
@@ -116,13 +126,7 @@ static void ls1021_pcie_host_init(struct pcie_port *pp)
 
        dw_pcie_setup_rc(pp);
 
-       /*
-        * LS1021A Workaround for internal TKT228622
-        * to fix the INTx hang issue
-        */
-       val = ioread32(pcie->dbi + PCIE_STRFMR1);
-       val &= 0xffff;
-       iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+       ls_pcie_drop_msg_tlp(pcie);
 }
 
 static int ls_pcie_link_up(struct pcie_port *pp)
@@ -147,6 +151,7 @@ static void ls_pcie_host_init(struct pcie_port *pp)
        iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
        ls_pcie_fix_class(pcie);
        ls_pcie_clear_multifunction(pcie);
+       ls_pcie_drop_msg_tlp(pcie);
        iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
 }
 
index 5816bceddb650c24576464913f9b7044d38be585..a576aeeb22da6cec1a01784328e209a66e96e8df 100644 (file)
@@ -64,7 +64,6 @@
 #define OARR_SIZE_CFG                BIT(OARR_SIZE_CFG_SHIFT)
 
 #define MAX_NUM_OB_WINDOWS           2
-#define MAX_NUM_PAXC_PF              4
 
 #define IPROC_PCIE_REG_INVALID 0xffff
 
@@ -170,20 +169,6 @@ static inline void iproc_pcie_ob_write(struct iproc_pcie *pcie,
        writel(val, pcie->base + offset + (window * 8));
 }
 
-static inline bool iproc_pcie_device_is_valid(struct iproc_pcie *pcie,
-                                             unsigned int slot,
-                                             unsigned int fn)
-{
-       if (slot > 0)
-               return false;
-
-       /* PAXC can only support limited number of functions */
-       if (pcie->type == IPROC_PCIE_PAXC && fn >= MAX_NUM_PAXC_PF)
-               return false;
-
-       return true;
-}
-
 /**
  * Note access to the configuration registers are protected at the higher layer
  * by 'pci_lock' in drivers/pci/access.c
@@ -199,11 +184,11 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus,
        u32 val;
        u16 offset;
 
-       if (!iproc_pcie_device_is_valid(pcie, slot, fn))
-               return NULL;
-
        /* root complex access */
        if (busno == 0) {
+               if (slot > 0 || fn > 0)
+                       return NULL;
+
                iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
                                     where & CFG_IND_ADDR_MASK);
                offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_IND_DATA);
@@ -213,6 +198,14 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus,
                        return (pcie->base + offset);
        }
 
+       /*
+        * PAXC is connected to an internally emulated EP within the SoC.  It
+        * allows only one device.
+        */
+       if (pcie->type == IPROC_PCIE_PAXC)
+               if (slot > 0)
+                       return NULL;
+
        /* EP device access */
        val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
                (slot << CFG_ADDR_DEV_NUM_SHIFT) |
index 0bf82a20a0fb479ccfbdb43479bf9b0cf6ecff6a..48d21e0edd568cedc16b1626f78f0a95b22bca1c 100644 (file)
@@ -262,7 +262,6 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev)
        rpc->rpd = dev;
        INIT_WORK(&rpc->dpc_handler, aer_isr);
        mutex_init(&rpc->rpc_mutex);
-       init_waitqueue_head(&rpc->wait_release);
 
        /* Use PCIe bus function to store rpc into PCIe device */
        set_service_data(dev, rpc);
@@ -285,8 +284,7 @@ static void aer_remove(struct pcie_device *dev)
                if (rpc->isr)
                        free_irq(dev->irq, dev);
 
-               wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
-
+               flush_work(&rpc->dpc_handler);
                aer_disable_rootport(rpc);
                kfree(rpc);
                set_service_data(dev, NULL);
index 84420b7c9456ecbb0e43a9e8ca539af5b2ee1a20..945c939a86c5c2919335d85a95dbeee34f9c0bff 100644 (file)
@@ -72,7 +72,6 @@ struct aer_rpc {
                                         * recovery on the same
                                         * root port hierarchy
                                         */
-       wait_queue_head_t wait_release;
 };
 
 struct aer_broadcast_data {
index 712392504ed9b9f1a8992079f801cf2c271a0ae6..521e39c1b66d597f8881d9ab02a4e4b41c1b68a0 100644 (file)
@@ -811,8 +811,6 @@ void aer_isr(struct work_struct *work)
        while (get_e_source(rpc, &e_src))
                aer_isr_one_error(p_device, &e_src);
        mutex_unlock(&rpc->rpc_mutex);
-
-       wake_up(&rpc->wait_release);
 }
 
 /**
index c777b97207d5378936a8f25a54be603d76691ab9..5f70fee59a947da1daddbeb2253043dc79c794fb 100644 (file)
@@ -53,7 +53,7 @@ struct pcifront_device {
 };
 
 struct pcifront_sd {
-       int domain;
+       struct pci_sysdata sd;
        struct pcifront_device *pdev;
 };
 
@@ -67,7 +67,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd,
                                    unsigned int domain, unsigned int bus,
                                    struct pcifront_device *pdev)
 {
-       sd->domain = domain;
+       /* Because we do not expose that information via XenBus. */
+       sd->sd.node = first_online_node;
+       sd->sd.domain = domain;
        sd->pdev = pdev;
 }
 
@@ -468,8 +470,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
        dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
                 domain, bus);
 
-       bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
-       sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+       bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL);
+       sd = kzalloc(sizeof(*sd), GFP_KERNEL);
        if (!bus_entry || !sd) {
                err = -ENOMEM;
                goto err_out;
index e7e117d5dbbe466f71d7a836ee3b898a560a1bed..0124d17bd9fe4bbff14eaced2db3a5f6d5e09b1b 100644 (file)
@@ -224,6 +224,7 @@ config PHY_MT65XX_USB3
 
 config PHY_HI6220_USB
        tristate "hi6220 USB PHY support"
+       depends on (ARCH_HISI && ARM64) || COMPILE_TEST
        select GENERIC_PHY
        select MFD_SYSCON
        help
index 8c7f27db6ad352260f8ad8675758ed365b6390a6..e7e574dc667a35d6d2c68ddf9e21744453d11bec 100644 (file)
@@ -275,20 +275,21 @@ EXPORT_SYMBOL_GPL(phy_exit);
 
 int phy_power_on(struct phy *phy)
 {
-       int ret;
+       int ret = 0;
 
        if (!phy)
-               return 0;
+               goto out;
 
        if (phy->pwr) {
                ret = regulator_enable(phy->pwr);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
-               return ret;
+               goto err_pm_sync;
+
        ret = 0; /* Override possible ret == -ENOTSUPP */
 
        mutex_lock(&phy->mutex);
@@ -296,19 +297,20 @@ int phy_power_on(struct phy *phy)
                ret = phy->ops->power_on(phy);
                if (ret < 0) {
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
-                       goto out;
+                       goto err_pwr_on;
                }
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
        return 0;
 
-out:
+err_pwr_on:
        mutex_unlock(&phy->mutex);
        phy_pm_runtime_put_sync(phy);
+err_pm_sync:
        if (phy->pwr)
                regulator_disable(phy->pwr);
-
+out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(phy_power_on);
index 4a3fc6e59f8e1982ecdd4b13b1500456959c0b71..840f3eae428b84292534d324ef856b485d001584 100644 (file)
@@ -715,6 +715,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        /* Our job is to use irqs and status from the power module
         * to keep the transceiver disabled when nothing's connected.
@@ -750,6 +751,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
        struct twl4030_usb *twl = platform_get_drvdata(pdev);
        int val;
 
+       usb_remove_phy(&twl->phy);
        pm_runtime_get_sync(twl->dev);
        cancel_delayed_work(&twl->id_workaround_work);
        device_remove_file(twl->dev, &dev_attr_vbus);
@@ -757,6 +759,13 @@ static int twl4030_usb_remove(struct platform_device *pdev)
        /* set transceiver mode to power on defaults */
        twl4030_usb_set_mode(twl, -1);
 
+       /* idle ulpi before powering off */
+       if (cable_present(twl->linkstat))
+               pm_runtime_put_noidle(twl->dev);
+       pm_runtime_mark_last_busy(twl->dev);
+       pm_runtime_put_sync_suspend(twl->dev);
+       pm_runtime_disable(twl->dev);
+
        /* autogate 60MHz ULPI clock,
         * clear dpll clock request for i2c access,
         * disable 32KHz
@@ -771,11 +780,6 @@ static int twl4030_usb_remove(struct platform_device *pdev)
        /* disable complete OTG block */
        twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
 
-       if (cable_present(twl->linkstat))
-               pm_runtime_put_noidle(twl->dev);
-       pm_runtime_mark_last_busy(twl->dev);
-       pm_runtime_put(twl->dev);
-
        return 0;
 }
 
index 16d48a4ed2253b7760e296deb95de9d76a6d85b4..e96e86d2e745e06e691344cca3fd38922450de58 100644 (file)
@@ -347,6 +347,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
                ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
                break;
        case PIN_CONFIG_INPUT_ENABLE:
+               mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
                ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
                break;
        case PIN_CONFIG_OUTPUT:
@@ -354,6 +355,7 @@ static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
                ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
                break;
        case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
                ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
                break;
        case PIN_CONFIG_DRIVE_STRENGTH:
index e4d473811bb366c84cf5ab180529c36411aacd6d..3ef798fac81bdba4926273f74b8c2b62b80102b3 100644 (file)
@@ -666,16 +666,19 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                struct mvebu_mpp_ctrl_setting *set = &mode->settings[0];
                struct mvebu_pinctrl_group *grp;
                unsigned num_settings;
+               unsigned supp_settings;
 
-               for (num_settings = 0; ; set++) {
+               for (num_settings = 0, supp_settings = 0; ; set++) {
                        if (!set->name)
                                break;
 
+                       num_settings++;
+
                        /* skip unsupported settings for this variant */
                        if (pctl->variant && !(pctl->variant & set->variant))
                                continue;
 
-                       num_settings++;
+                       supp_settings++;
 
                        /* find gpio/gpo/gpi settings */
                        if (strcmp(set->name, "gpio") == 0)
@@ -688,7 +691,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
                }
 
                /* skip modes with no settings for this variant */
-               if (!num_settings)
+               if (!supp_settings)
                        continue;
 
                grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
index 085e60106ec2c2f94dd83bfbc2f21fbd8ba17da6..1f7469c9857d6ad14f80a4232aa836ce65d39620 100644 (file)
@@ -191,6 +191,7 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
                dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
 }
 
+#ifdef CONFIG_DEBUG_FS
 static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset,
                                  enum abx500_gpio_pull_updown *pull_updown)
 {
@@ -226,6 +227,7 @@ out:
 
        return ret;
 }
+#endif
 
 static int abx500_set_pull_updown(struct abx500_pinctrl *pct,
                                  int offset, enum abx500_gpio_pull_updown val)
@@ -468,6 +470,7 @@ out:
        return ret;
 }
 
+#ifdef CONFIG_DEBUG_FS
 static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
                          unsigned gpio)
 {
@@ -553,8 +556,6 @@ out:
        return ret;
 }
 
-#ifdef CONFIG_DEBUG_FS
-
 #include <linux/seq_file.h>
 
 static void abx500_gpio_dbg_show_one(struct seq_file *s,
index d90e205cf809e5f3ec4c9d9ed9ca15bec8288d82..216f227c60092f580df47bc5e5f7c64828419d80 100644 (file)
@@ -426,6 +426,7 @@ int pxa2xx_pinctrl_init(struct platform_device *pdev,
 
        return 0;
 }
+EXPORT_SYMBOL(pxa2xx_pinctrl_init);
 
 int pxa2xx_pinctrl_exit(struct platform_device *pdev)
 {
index f67b1e958589b9f9b4a891ce860bcfeb8909690d..5cc97f85db02d4986b3c9249a1116d952838fde0 100644 (file)
@@ -514,25 +514,35 @@ static const struct pinconf_ops samsung_pinconf_ops = {
        .pin_config_group_set   = samsung_pinconf_group_set,
 };
 
-/* gpiolib gpio_set callback function */
-static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+/*
+ * The samsung_gpio_set_vlaue() should be called with "bank->slock" held
+ * to avoid race condition.
+ */
+static void samsung_gpio_set_value(struct gpio_chip *gc,
+                                         unsigned offset, int value)
 {
        struct samsung_pin_bank *bank = gpiochip_get_data(gc);
        const struct samsung_pin_bank_type *type = bank->type;
-       unsigned long flags;
        void __iomem *reg;
        u32 data;
 
        reg = bank->drvdata->virt_base + bank->pctl_offset;
 
-       spin_lock_irqsave(&bank->slock, flags);
-
        data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
        data &= ~(1 << offset);
        if (value)
                data |= 1 << offset;
        writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
+}
+
+/* gpiolib gpio_set callback function */
+static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+       unsigned long flags;
 
+       spin_lock_irqsave(&bank->slock, flags);
+       samsung_gpio_set_value(gc, offset, value);
        spin_unlock_irqrestore(&bank->slock, flags);
 }
 
@@ -553,6 +563,8 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
 }
 
 /*
+ * The samsung_gpio_set_direction() should be called with "bank->slock" held
+ * to avoid race condition.
  * The calls to gpio_direction_output() and gpio_direction_input()
  * leads to this function call.
  */
@@ -564,7 +576,6 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
        struct samsung_pinctrl_drv_data *drvdata;
        void __iomem *reg;
        u32 data, mask, shift;
-       unsigned long flags;
 
        bank = gpiochip_get_data(gc);
        type = bank->type;
@@ -581,31 +592,42 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc,
                reg += 4;
        }
 
-       spin_lock_irqsave(&bank->slock, flags);
-
        data = readl(reg);
        data &= ~(mask << shift);
        if (!input)
                data |= FUNC_OUTPUT << shift;
        writel(data, reg);
 
-       spin_unlock_irqrestore(&bank->slock, flags);
-
        return 0;
 }
 
 /* gpiolib gpio_direction_input callback function. */
 static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
 {
-       return samsung_gpio_set_direction(gc, offset, true);
+       struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&bank->slock, flags);
+       ret = samsung_gpio_set_direction(gc, offset, true);
+       spin_unlock_irqrestore(&bank->slock, flags);
+       return ret;
 }
 
 /* gpiolib gpio_direction_output callback function. */
 static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
                                                        int value)
 {
-       samsung_gpio_set(gc, offset, value);
-       return samsung_gpio_set_direction(gc, offset, false);
+       struct samsung_pin_bank *bank = gpiochip_get_data(gc);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&bank->slock, flags);
+       samsung_gpio_set_value(gc, offset, value);
+       ret = samsung_gpio_set_direction(gc, offset, false);
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       return ret;
 }
 
 /*
index 77d4cf047ceea71dd9bcc50bf0d4e59527d7aac8..11760bbe9d51acd4ebb4d44b82af2c525f68e1dd 100644 (file)
@@ -492,6 +492,7 @@ static const struct sunxi_pinctrl_desc sun8i_h3_pinctrl_data = {
        .pins = sun8i_h3_pins,
        .npins = ARRAY_SIZE(sun8i_h3_pins),
        .irq_banks = 2,
+       .irq_read_needs_mux = true
 };
 
 static int sun8i_h3_pinctrl_probe(struct platform_device *pdev)
index 20f0ad9bb9f373efedfdf42de3af7da5321f21a6..e20f23e04c24ce8071ea03ea238b5a1a765d70ff 100644 (file)
@@ -41,8 +41,7 @@ static const struct key_entry intel_hid_keymap[] = {
        { KE_KEY, 4, { KEY_HOME } },
        { KE_KEY, 5, { KEY_END } },
        { KE_KEY, 6, { KEY_PAGEUP } },
-       { KE_KEY, 4, { KEY_PAGEDOWN } },
-       { KE_KEY, 4, { KEY_HOME } },
+       { KE_KEY, 7, { KEY_PAGEDOWN } },
        { KE_KEY, 8, { KEY_RFKILL } },
        { KE_KEY, 9, { KEY_POWER } },
        { KE_KEY, 11, { KEY_SLEEP } },
index 02bc5a6343c3fbeeb34b00ef282ba5f31ceff96a..aa454241489c9f541864f34828e19318514d3560 100644 (file)
@@ -49,7 +49,7 @@ struct scu_ipc_data {
 
 static int scu_reg_access(u32 cmd, struct scu_ipc_data  *data)
 {
-       int count = data->count;
+       unsigned int count = data->count;
 
        if (count == 0 || count == 3 || count > 4)
                return -EINVAL;
index f700723ca5d6b1a8a0c342c568908f9c53aa2435..d28e3ab9479c64e41fe014714c08721fc503faf3 100644 (file)
@@ -342,6 +342,7 @@ static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
 /* Device IDs of parts that have 32KB MCH space */
 static const unsigned int mch_quirk_devices[] = {
        0x0154, /* Ivy Bridge */
+       0x0a04, /* Haswell-ULT */
        0x0c00, /* Haswell */
        0x1604, /* Broadwell */
 };
index 9429e66be09641fd818f8da593d47c45124d3efe..8eafc6f0df88be5fbf26c6725beb656e49464c0b 100644 (file)
@@ -21,6 +21,9 @@
 
 #include <linux/power/bq27xxx_battery.h>
 
+static DEFINE_IDR(battery_id);
+static DEFINE_MUTEX(battery_mutex);
+
 static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
 {
        struct bq27xxx_device_info *di = data;
@@ -70,19 +73,33 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 {
        struct bq27xxx_device_info *di;
        int ret;
+       char *name;
+       int num;
+
+       /* Get new ID for the new battery device */
+       mutex_lock(&battery_mutex);
+       num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
+       mutex_unlock(&battery_mutex);
+       if (num < 0)
+               return num;
+
+       name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
+       if (!name)
+               goto err_mem;
 
        di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
        if (!di)
-               return -ENOMEM;
+               goto err_mem;
 
+       di->id = num;
        di->dev = &client->dev;
        di->chip = id->driver_data;
-       di->name = id->name;
+       di->name = name;
        di->bus.read = bq27xxx_battery_i2c_read;
 
        ret = bq27xxx_battery_setup(di);
        if (ret)
-               return ret;
+               goto err_failed;
 
        /* Schedule a polling after about 1 min */
        schedule_delayed_work(&di->work, 60 * HZ);
@@ -103,6 +120,16 @@ static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
        }
 
        return 0;
+
+err_mem:
+       ret = -ENOMEM;
+
+err_failed:
+       mutex_lock(&battery_mutex);
+       idr_remove(&battery_id, num);
+       mutex_unlock(&battery_mutex);
+
+       return ret;
 }
 
 static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
@@ -111,6 +138,10 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
 
        bq27xxx_battery_teardown(di);
 
+       mutex_lock(&battery_mutex);
+       idr_remove(&battery_id, di->id);
+       mutex_unlock(&battery_mutex);
+
        return 0;
 }
 
index 41605dac83094813441530ae9cacad093a352f71..c78db05e75b1323f9b0adb35aac8cc78316355ab 100644 (file)
@@ -3035,6 +3035,7 @@ static void dasd_setup_queue(struct dasd_block *block)
                max = block->base->discipline->max_blocks << block->s2b_shift;
        }
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue);
+       block->request_queue->limits.max_dev_sectors = max;
        blk_queue_logical_block_size(block->request_queue,
                                     block->bp_block);
        blk_queue_max_hw_sectors(block->request_queue, max);
index 184b1dbeb55463b768eb9aa7215665686d5e4591..286782c60da4e3b197d7d9901b7e17c2e69673ac 100644 (file)
@@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
                spin_unlock_irqrestore(&lcu->lock, flags);
                cancel_work_sync(&lcu->suc_data.worker);
                spin_lock_irqsave(&lcu->lock, flags);
-               if (device == lcu->suc_data.device)
+               if (device == lcu->suc_data.device) {
+                       dasd_put_device(device);
                        lcu->suc_data.device = NULL;
+               }
        }
        was_pending = 0;
        if (device == lcu->ruac_data.device) {
@@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
                was_pending = 1;
                cancel_delayed_work_sync(&lcu->ruac_data.dwork);
                spin_lock_irqsave(&lcu->lock, flags);
-               if (device == lcu->ruac_data.device)
+               if (device == lcu->ruac_data.device) {
+                       dasd_put_device(device);
                        lcu->ruac_data.device = NULL;
+               }
        }
        private->lcu = NULL;
        spin_unlock_irqrestore(&lcu->lock, flags);
@@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work)
        if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) {
                DBF_DEV_EVENT(DBF_WARNING, device, "could not update"
                            " alias data in lcu (rc = %d), retry later", rc);
-               schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+               if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ))
+                       dasd_put_device(device);
        } else {
+               dasd_put_device(device);
                lcu->ruac_data.device = NULL;
                lcu->flags &= ~UPDATE_PENDING;
        }
@@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu,
         */
        if (!usedev)
                return -EINVAL;
+       dasd_get_device(usedev);
        lcu->ruac_data.device = usedev;
-       schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+       if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0))
+               dasd_put_device(usedev);
        return 0;
 }
 
@@ -723,7 +731,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu,
        ASCEBC((char *) &cqr->magic, 4);
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_RSCK;
-       ccw->flags = ;
+       ccw->flags = CCW_FLAG_SLI;
        ccw->count = 16;
        ccw->cda = (__u32)(addr_t) cqr->data;
        ((char *)cqr->data)[0] = reason;
@@ -930,6 +938,7 @@ static void summary_unit_check_handling_work(struct work_struct *work)
        /* 3. read new alias configuration */
        _schedule_lcu_update(lcu, device);
        lcu->suc_data.device = NULL;
+       dasd_put_device(device);
        spin_unlock_irqrestore(&lcu->lock, flags);
 }
 
@@ -989,6 +998,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
        }
        lcu->suc_data.reason = reason;
        lcu->suc_data.device = device;
+       dasd_get_device(device);
        spin_unlock(&lcu->lock);
-       schedule_work(&lcu->suc_data.worker);
+       if (!schedule_work(&lcu->suc_data.worker))
+               dasd_put_device(device);
 };
index 804806e1cbb4be79d3223a2d5684de4c6ff58afd..339f6b7f480375d55f28883ee77a172844fd1e73 100644 (file)
@@ -13,6 +13,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
 
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <scsi/scsi_host.h>
@@ -158,7 +159,6 @@ static struct scsi_transport_template *cxgb4i_stt;
  * open/close/abort and data send/receive.
  */
 
-#define DIV_ROUND_UP(n, d)     (((n) + (d) - 1) / (d))
 #define RCV_BUFSIZ_MASK                0x3FFU
 #define MAX_IMM_TX_PKT_LEN     256
 
index 3613581343159dc67e8980424b2346d301dec01f..93880ed6291cfbda8a88ad6130a433c0c461c727 100644 (file)
@@ -562,7 +562,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
                        /*
                         * Command Lock contention
                         */
-                       err = SCSI_DH_RETRY;
+                       err = SCSI_DH_IMM_RETRY;
                break;
        default:
                break;
@@ -612,6 +612,8 @@ retry:
                err = mode_select_handle_sense(sdev, h->sense);
                if (err == SCSI_DH_RETRY && retry_cnt--)
                        goto retry;
+               if (err == SCSI_DH_IMM_RETRY)
+                       goto retry;
        }
        if (err == SCSI_DH_OK) {
                h->state = RDAC_STATE_ACTIVE;
index d7597c08fa1194d35f0068f183deb7aec2b022da..641c60e8fda33b03a3f5f32b41cced7ac9eb8943 100644 (file)
@@ -93,36 +93,40 @@ static struct notifier_block libfcoe_notifier = {
 int fcoe_link_speed_update(struct fc_lport *lport)
 {
        struct net_device *netdev = fcoe_get_netdev(lport);
-       struct ethtool_cmd ecmd;
+       struct ethtool_link_ksettings ecmd;
 
-       if (!__ethtool_get_settings(netdev, &ecmd)) {
+       if (!__ethtool_get_link_ksettings(netdev, &ecmd)) {
                lport->link_supported_speeds &= ~(FC_PORTSPEED_1GBIT  |
                                                  FC_PORTSPEED_10GBIT |
                                                  FC_PORTSPEED_20GBIT |
                                                  FC_PORTSPEED_40GBIT);
 
-               if (ecmd.supported & (SUPPORTED_1000baseT_Half |
-                                     SUPPORTED_1000baseT_Full |
-                                     SUPPORTED_1000baseKX_Full))
+               if (ecmd.link_modes.supported[0] & (
+                           SUPPORTED_1000baseT_Half |
+                           SUPPORTED_1000baseT_Full |
+                           SUPPORTED_1000baseKX_Full))
                        lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
 
-               if (ecmd.supported & (SUPPORTED_10000baseT_Full   |
-                                     SUPPORTED_10000baseKX4_Full |
-                                     SUPPORTED_10000baseKR_Full  |
-                                     SUPPORTED_10000baseR_FEC))
+               if (ecmd.link_modes.supported[0] & (
+                           SUPPORTED_10000baseT_Full   |
+                           SUPPORTED_10000baseKX4_Full |
+                           SUPPORTED_10000baseKR_Full  |
+                           SUPPORTED_10000baseR_FEC))
                        lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
 
-               if (ecmd.supported & (SUPPORTED_20000baseMLD2_Full |
-                                     SUPPORTED_20000baseKR2_Full))
+               if (ecmd.link_modes.supported[0] & (
+                           SUPPORTED_20000baseMLD2_Full |
+                           SUPPORTED_20000baseKR2_Full))
                        lport->link_supported_speeds |= FC_PORTSPEED_20GBIT;
 
-               if (ecmd.supported & (SUPPORTED_40000baseKR4_Full |
-                                     SUPPORTED_40000baseCR4_Full |
-                                     SUPPORTED_40000baseSR4_Full |
-                                     SUPPORTED_40000baseLR4_Full))
+               if (ecmd.link_modes.supported[0] & (
+                           SUPPORTED_40000baseKR4_Full |
+                           SUPPORTED_40000baseCR4_Full |
+                           SUPPORTED_40000baseSR4_Full |
+                           SUPPORTED_40000baseLR4_Full))
                        lport->link_supported_speeds |= FC_PORTSPEED_40GBIT;
 
-               switch (ethtool_cmd_speed(&ecmd)) {
+               switch (ecmd.base.speed) {
                case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
                        break;
index b67661836c9fa26fccd1e23a82508c1d567a5916..d1dd1616f983bb7a567d4eb465e09a5c9cd611c5 100644 (file)
@@ -1,6 +1,6 @@
 config SCSI_HISI_SAS
        tristate "HiSilicon SAS"
-       depends on HAS_DMA
+       depends on HAS_DMA && HAS_IOMEM
        depends on ARM64 || COMPILE_TEST
        select SCSI_SAS_LIBSAS
        select BLK_DEV_INTEGRITY
index 057fdeb720acec997f4a4a5952318c58ab2f0b3e..eea24d7531cf51eec585afbe0575a0dc6d804279 100644 (file)
@@ -1289,13 +1289,10 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba,
                goto out;
        }
 
-       if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK) {
-               if (!(cmplt_hdr_data & CMPLT_HDR_CMD_CMPLT_MSK) ||
-                   !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK))
-                       ts->stat = SAS_DATA_OVERRUN;
-               else
-                       slot_err_v1_hw(hisi_hba, task, slot);
+       if (cmplt_hdr_data & CMPLT_HDR_ERR_RCRD_XFRD_MSK &&
+               !(cmplt_hdr_data & CMPLT_HDR_RSPNS_XFRD_MSK)) {
 
+               slot_err_v1_hw(hisi_hba, task, slot);
                goto out;
        }
 
index 3b3e0998fa6e72b71f5417c4f942ff9bb67caee0..d6a691e27d33317c72d785340b5b371378932741 100644 (file)
@@ -4002,6 +4002,7 @@ static ssize_t ipr_store_update_fw(struct device *dev,
        struct ipr_sglist *sglist;
        char fname[100];
        char *src;
+       char *endline;
        int result, dnld_size;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -4009,6 +4010,10 @@ static ssize_t ipr_store_update_fw(struct device *dev,
 
        snprintf(fname, sizeof(fname), "%s", buf);
 
+       endline = strchr(fname, '\n');
+       if (endline)
+               *endline = '\0';
+
        if (request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
                dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
                return -EIO;
index 52a87657c7dd3e4945aad29e9b3cbf983b94efad..692a7570b5e1475da8371f1d08939b8898912ebe 100644 (file)
@@ -2204,7 +2204,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
        /* Clear outstanding commands array. */
        for (que = 0; que < ha->max_req_queues; que++) {
                req = ha->req_q_map[que];
-               if (!req)
+               if (!req || !test_bit(que, ha->req_qid_map))
                        continue;
                req->out_ptr = (void *)(req->ring + req->length);
                *req->out_ptr = 0;
@@ -2221,7 +2221,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
 
        for (que = 0; que < ha->max_rsp_queues; que++) {
                rsp = ha->rsp_q_map[que];
-               if (!rsp)
+               if (!rsp || !test_bit(que, ha->rsp_qid_map))
                        continue;
                rsp->in_ptr = (void *)(rsp->ring + rsp->length);
                *rsp->in_ptr = 0;
@@ -4981,7 +4981,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
 
        for (i = 1; i < ha->max_rsp_queues; i++) {
                rsp = ha->rsp_q_map[i];
-               if (rsp) {
+               if (rsp && test_bit(i, ha->rsp_qid_map)) {
                        rsp->options &= ~BIT_0;
                        ret = qla25xx_init_rsp_que(base_vha, rsp);
                        if (ret != QLA_SUCCESS)
@@ -4996,8 +4996,8 @@ qla25xx_init_queues(struct qla_hw_data *ha)
        }
        for (i = 1; i < ha->max_req_queues; i++) {
                req = ha->req_q_map[i];
-               if (req) {
-               /* Clear outstanding commands array. */
+               if (req && test_bit(i, ha->req_qid_map)) {
+                       /* Clear outstanding commands array. */
                        req->options &= ~BIT_0;
                        ret = qla25xx_init_req_que(base_vha, req);
                        if (ret != QLA_SUCCESS)
index d4d65eb0e9b41264eb2d86e4d4af4997e0268c5c..4af95479a9db9325d8bb42fff0dc0d0f5ec6b682 100644 (file)
@@ -3063,9 +3063,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
                    "MSI-X: Failed to enable support "
                    "-- %d/%d\n Retry with %d vectors.\n",
                    ha->msix_count, ret, ret);
+               ha->msix_count = ret;
+               ha->max_rsp_queues = ha->msix_count - 1;
        }
-       ha->msix_count = ret;
-       ha->max_rsp_queues = ha->msix_count - 1;
        ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
                                ha->msix_count, GFP_KERNEL);
        if (!ha->msix_entries) {
index c5dd594f6c316185b203f3e25c1595b4c320da81..cf7ba52bae665fa482b8535f92e5fcb1dbe25244 100644 (file)
@@ -600,7 +600,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
        /* Delete request queues */
        for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
                req = ha->req_q_map[cnt];
-               if (req) {
+               if (req && test_bit(cnt, ha->req_qid_map)) {
                        ret = qla25xx_delete_req_que(vha, req);
                        if (ret != QLA_SUCCESS) {
                                ql_log(ql_log_warn, vha, 0x00ea,
@@ -614,7 +614,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha)
        /* Delete response queues */
        for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
                rsp = ha->rsp_q_map[cnt];
-               if (rsp) {
+               if (rsp && test_bit(cnt, ha->rsp_qid_map)) {
                        ret = qla25xx_delete_rsp_que(vha, rsp);
                        if (ret != QLA_SUCCESS) {
                                ql_log(ql_log_warn, vha, 0x00eb,
index f1788db4319560c8210eda5a0fc4f576d5ec321f..f6c7ce35b542ecadfe0305095e300bfabe95950c 100644 (file)
@@ -409,6 +409,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
        int cnt;
 
        for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
+               if (!test_bit(cnt, ha->req_qid_map))
+                       continue;
+
                req = ha->req_q_map[cnt];
                qla2x00_free_req_que(ha, req);
        }
@@ -416,6 +419,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
        ha->req_q_map = NULL;
 
        for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
+               if (!test_bit(cnt, ha->rsp_qid_map))
+                       continue;
+
                rsp = ha->rsp_q_map[cnt];
                qla2x00_free_rsp_que(ha, rsp);
        }
index 8075a4cdb45cf85aaa09c1e26fef1bdd8dc82b55..ee967becd257e1b5a5724aed241a9537fc0f3bc3 100644 (file)
@@ -105,7 +105,7 @@ static void qlt_response_pkt(struct scsi_qla_host *ha, response_t *pkt);
 static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
        int fn, void *iocb, int flags);
 static void qlt_send_term_exchange(struct scsi_qla_host *ha, struct qla_tgt_cmd
-       *cmd, struct atio_from_isp *atio, int ha_locked);
+       *cmd, struct atio_from_isp *atio, int ha_locked, int ul_abort);
 static void qlt_reject_free_srr_imm(struct scsi_qla_host *ha,
        struct qla_tgt_srr_imm *imm, int ha_lock);
 static void qlt_abort_cmd_on_host_reset(struct scsi_qla_host *vha,
@@ -1756,7 +1756,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd)
                qlt_send_notify_ack(vha, &mcmd->orig_iocb.imm_ntfy,
                    0, 0, 0, 0, 0, 0);
        else {
-               if (mcmd->se_cmd.se_tmr_req->function == TMR_ABORT_TASK)
+               if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX)
                        qlt_24xx_send_abts_resp(vha, &mcmd->orig_iocb.abts,
                            mcmd->fc_tm_rsp, false);
                else
@@ -2665,7 +2665,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
                        /* no need to terminate. FW already freed exchange. */
                        qlt_abort_cmd_on_host_reset(cmd->vha, cmd);
                else
-                       qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+                       qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
                return 0;
        }
@@ -3173,7 +3173,8 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha,
 }
 
 static void qlt_send_term_exchange(struct scsi_qla_host *vha,
-       struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked)
+       struct qla_tgt_cmd *cmd, struct atio_from_isp *atio, int ha_locked,
+       int ul_abort)
 {
        unsigned long flags = 0;
        int rc;
@@ -3193,8 +3194,7 @@ static void qlt_send_term_exchange(struct scsi_qla_host *vha,
                qlt_alloc_qfull_cmd(vha, atio, 0, 0);
 
 done:
-       if (cmd && (!cmd->aborted ||
-           !cmd->cmd_sent_to_fw)) {
+       if (cmd && !ul_abort && !cmd->aborted) {
                if (cmd->sg_mapped)
                        qlt_unmap_sg(vha, cmd);
                vha->hw->tgt.tgt_ops->free_cmd(cmd);
@@ -3253,21 +3253,38 @@ static void qlt_chk_exch_leak_thresh_hold(struct scsi_qla_host *vha)
 
 }
 
-void qlt_abort_cmd(struct qla_tgt_cmd *cmd)
+int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
 {
        struct qla_tgt *tgt = cmd->tgt;
        struct scsi_qla_host *vha = tgt->vha;
        struct se_cmd *se_cmd = &cmd->se_cmd;
+       unsigned long flags;
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf014,
            "qla_target(%d): terminating exchange for aborted cmd=%p "
            "(se_cmd=%p, tag=%llu)", vha->vp_idx, cmd, &cmd->se_cmd,
            se_cmd->tag);
 
+       spin_lock_irqsave(&cmd->cmd_lock, flags);
+       if (cmd->aborted) {
+               spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+               /*
+                * It's normal to see 2 calls in this path:
+                *  1) XFER Rdy completion + CMD_T_ABORT
+                *  2) TCM TMR - drain_state_list
+                */
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xffff,
+                       "multiple abort. %p transport_state %x, t_state %x,"
+                       " se_cmd_flags %x \n", cmd, cmd->se_cmd.transport_state,
+                       cmd->se_cmd.t_state,cmd->se_cmd.se_cmd_flags);
+               return EIO;
+       }
        cmd->aborted = 1;
        cmd->cmd_flags |= BIT_6;
+       spin_unlock_irqrestore(&cmd->cmd_lock, flags);
 
-       qlt_send_term_exchange(vha, cmd, &cmd->atio, 0);
+       qlt_send_term_exchange(vha, cmd, &cmd->atio, 0, 1);
+       return 0;
 }
 EXPORT_SYMBOL(qlt_abort_cmd);
 
@@ -3282,6 +3299,9 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
 
        BUG_ON(cmd->cmd_in_wq);
 
+       if (cmd->sg_mapped)
+               qlt_unmap_sg(cmd->vha, cmd);
+
        if (!cmd->q_full)
                qlt_decr_num_pend_cmds(cmd->vha);
 
@@ -3399,7 +3419,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio,
                term = 1;
 
        if (term)
-               qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+               qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
 
        return term;
 }
@@ -3580,12 +3600,13 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
                case CTIO_PORT_LOGGED_OUT:
                case CTIO_PORT_UNAVAILABLE:
                {
-                       int logged_out = (status & 0xFFFF);
+                       int logged_out =
+                               (status & 0xFFFF) == CTIO_PORT_LOGGED_OUT;
+
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf059,
                            "qla_target(%d): CTIO with %s status %x "
                            "received (state %x, se_cmd %p)\n", vha->vp_idx,
-                           (logged_out == CTIO_PORT_LOGGED_OUT) ?
-                           "PORT LOGGED OUT" : "PORT UNAVAILABLE",
+                           logged_out ? "PORT LOGGED OUT" : "PORT UNAVAILABLE",
                            status, cmd->state, se_cmd);
 
                        if (logged_out && cmd->sess) {
@@ -3754,6 +3775,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
                goto out_term;
        }
 
+       spin_lock_init(&cmd->cmd_lock);
        cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
        cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
        cmd->unpacked_lun = scsilun_to_int(
@@ -3796,7 +3818,7 @@ out_term:
         */
        cmd->cmd_flags |= BIT_2;
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qlt_send_term_exchange(vha, NULL, &cmd->atio, 1);
+       qlt_send_term_exchange(vha, NULL, &cmd->atio, 1, 0);
 
        qlt_decr_num_pend_cmds(vha);
        percpu_ida_free(&sess->se_sess->sess_tag_pool, cmd->se_cmd.map_tag);
@@ -3918,7 +3940,7 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
 
 out_term:
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qlt_send_term_exchange(vha, NULL, &op->atio, 1);
+       qlt_send_term_exchange(vha, NULL, &op->atio, 1, 0);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        kfree(op);
 
@@ -3982,7 +4004,8 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
        cmd->cmd_in_wq = 1;
        cmd->cmd_flags |= BIT_0;
-       cmd->se_cmd.cpuid = -1;
+       cmd->se_cmd.cpuid = ha->msix_count ?
+               ha->tgt.rspq_vector_cpuid : WORK_CPU_UNBOUND;
 
        spin_lock(&vha->cmd_list_lock);
        list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
@@ -3990,7 +4013,6 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
        INIT_WORK(&cmd->work, qlt_do_work);
        if (ha->msix_count) {
-               cmd->se_cmd.cpuid = ha->tgt.rspq_vector_cpuid;
                if (cmd->atio.u.isp24.fcp_cmnd.rddata)
                        queue_work_on(smp_processor_id(), qla_tgt_wq,
                            &cmd->work);
@@ -4771,7 +4793,7 @@ out_reject:
                dump_stack();
        } else {
                cmd->cmd_flags |= BIT_9;
-               qlt_send_term_exchange(vha, cmd, &cmd->atio, 1);
+               qlt_send_term_exchange(vha, cmd, &cmd->atio, 1, 0);
        }
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
@@ -4950,7 +4972,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
                                    sctio, sctio->srr_id);
                                list_del(&sctio->srr_list_entry);
                                qlt_send_term_exchange(vha, sctio->cmd,
-                                   &sctio->cmd->atio, 1);
+                                   &sctio->cmd->atio, 1, 0);
                                kfree(sctio);
                        }
                }
@@ -5123,7 +5145,7 @@ static int __qlt_send_busy(struct scsi_qla_host *vha,
            atio->u.isp24.fcp_hdr.s_id);
        spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
        if (!sess) {
-               qlt_send_term_exchange(vha, NULL, atio, 1);
+               qlt_send_term_exchange(vha, NULL, atio, 1, 0);
                return 0;
        }
        /* Sending marker isn't necessary, since we called from ISR */
@@ -5406,7 +5428,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
                                qlt_send_busy(vha, atio, SAM_STAT_BUSY);
 #else
-                               qlt_send_term_exchange(vha, NULL, atio, 1);
+                               qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
 
                                if (!ha_locked)
@@ -5523,7 +5545,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
 #if 1 /* With TERM EXCHANGE some FC cards refuse to boot */
                                qlt_send_busy(vha, atio, 0);
 #else
-                               qlt_send_term_exchange(vha, NULL, atio, 1);
+                               qlt_send_term_exchange(vha, NULL, atio, 1, 0);
 #endif
                        } else {
                                if (tgt->tgt_stop) {
@@ -5532,7 +5554,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
                                            "command to target, sending TERM "
                                            "EXCHANGE for rsp\n");
                                        qlt_send_term_exchange(vha, NULL,
-                                           atio, 1);
+                                           atio, 1, 0);
                                } else {
                                        ql_dbg(ql_dbg_tgt, vha, 0xe060,
                                            "qla_target(%d): Unable to send "
@@ -5960,7 +5982,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
        return;
 
 out_term:
-       qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 0);
+       qlt_send_term_exchange(vha, NULL, &prm->tm_iocb2, 1, 0);
        if (sess)
                ha->tgt.tgt_ops->put_sess(sess);
        spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
index 71b2865ba3c8416d6ce583df64125dfb7071ca2b..22a6a767fe07b1eba54e23007606bb3c39226b0f 100644 (file)
@@ -943,6 +943,36 @@ struct qla_tgt_sess {
        qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
 };
 
+typedef enum {
+       /*
+        * BIT_0 - Atio Arrival / schedule to work
+        * BIT_1 - qlt_do_work
+        * BIT_2 - qlt_do work failed
+        * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
+        * BIT_4 - read respond/tcm_qla2xx_queue_data_in
+        * BIT_5 - status respond / tcm_qla2xx_queue_status
+        * BIT_6 - tcm request to abort/Term exchange.
+        *      pre_xmit_response->qlt_send_term_exchange
+        * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
+        * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
+        * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
+        * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
+
+        * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
+        * BIT_13 - Bad completion -
+        *      qlt_ctio_do_completion --> qlt_term_ctio_exchange
+        * BIT_14 - Back end data received/sent.
+        * BIT_15 - SRR prepare ctio
+        * BIT_16 - complete free
+        * BIT_17 - flush - qlt_abort_cmd_on_host_reset
+        * BIT_18 - completion w/abort status
+        * BIT_19 - completion w/unknown status
+        * BIT_20 - tcm_qla2xxx_free_cmd
+        */
+       CMD_FLAG_DATA_WORK = BIT_11,
+       CMD_FLAG_DATA_WORK_FREE = BIT_21,
+} cmd_flags_t;
+
 struct qla_tgt_cmd {
        struct se_cmd se_cmd;
        struct qla_tgt_sess *sess;
@@ -952,6 +982,7 @@ struct qla_tgt_cmd {
        /* Sense buffer that will be mapped into outgoing status */
        unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
 
+       spinlock_t cmd_lock;
        /* to save extra sess dereferences */
        unsigned int conf_compl_supported:1;
        unsigned int sg_mapped:1;
@@ -986,30 +1017,8 @@ struct qla_tgt_cmd {
 
        uint64_t jiffies_at_alloc;
        uint64_t jiffies_at_free;
-       /* BIT_0 - Atio Arrival / schedule to work
-        * BIT_1 - qlt_do_work
-        * BIT_2 - qlt_do work failed
-        * BIT_3 - xfer rdy/tcm_qla2xxx_write_pending
-        * BIT_4 - read respond/tcm_qla2xx_queue_data_in
-        * BIT_5 - status respond / tcm_qla2xx_queue_status
-        * BIT_6 - tcm request to abort/Term exchange.
-        *      pre_xmit_response->qlt_send_term_exchange
-        * BIT_7 - SRR received (qlt_handle_srr->qlt_xmit_response)
-        * BIT_8 - SRR received (qlt_handle_srr->qlt_rdy_to_xfer)
-        * BIT_9 - SRR received (qla_handle_srr->qlt_send_term_exchange)
-        * BIT_10 - Data in - hanlde_data->tcm_qla2xxx_handle_data
-        * BIT_11 - Data actually going to TCM : tcm_qla2xx_handle_data_work
-        * BIT_12 - good completion - qlt_ctio_do_completion -->free_cmd
-        * BIT_13 - Bad completion -
-        *      qlt_ctio_do_completion --> qlt_term_ctio_exchange
-        * BIT_14 - Back end data received/sent.
-        * BIT_15 - SRR prepare ctio
-        * BIT_16 - complete free
-        * BIT_17 - flush - qlt_abort_cmd_on_host_reset
-        * BIT_18 - completion w/abort status
-        * BIT_19 - completion w/unknown status
-        */
-       uint32_t cmd_flags;
+
+       cmd_flags_t cmd_flags;
 };
 
 struct qla_tgt_sess_work_param {
@@ -1148,7 +1157,7 @@ static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p)
 extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
 extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
 extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
-extern void qlt_abort_cmd(struct qla_tgt_cmd *);
+extern int qlt_abort_cmd(struct qla_tgt_cmd *);
 extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
 extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
index ddbe2e7ac14d095129cc9cbd90ab87cbd414bc36..c3e62252460452aac6507db5ddc7ad576f969ffa 100644 (file)
@@ -395,6 +395,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
        if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) {
                for (i = 0; i < vha->hw->max_req_queues; i++) {
                        struct req_que *req = vha->hw->req_q_map[i];
+
+                       if (!test_bit(i, vha->hw->req_qid_map))
+                               continue;
+
                        if (req || !buf) {
                                length = req ?
                                    req->length : REQUEST_ENTRY_CNT_24XX;
@@ -408,6 +412,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha,
        } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) {
                for (i = 0; i < vha->hw->max_rsp_queues; i++) {
                        struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+                       if (!test_bit(i, vha->hw->rsp_qid_map))
+                               continue;
+
                        if (rsp || !buf) {
                                length = rsp ?
                                    rsp->length : RESPONSE_ENTRY_CNT_MQ;
@@ -634,6 +642,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
        if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) {
                for (i = 0; i < vha->hw->max_req_queues; i++) {
                        struct req_que *req = vha->hw->req_q_map[i];
+
+                       if (!test_bit(i, vha->hw->req_qid_map))
+                               continue;
+
                        if (req || !buf) {
                                qla27xx_insert16(i, buf, len);
                                qla27xx_insert16(1, buf, len);
@@ -645,6 +657,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha,
        } else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) {
                for (i = 0; i < vha->hw->max_rsp_queues; i++) {
                        struct rsp_que *rsp = vha->hw->rsp_q_map[i];
+
+                       if (!test_bit(i, vha->hw->rsp_qid_map))
+                               continue;
+
                        if (rsp || !buf) {
                                qla27xx_insert16(i, buf, len);
                                qla27xx_insert16(1, buf, len);
index faf0a126627f65d6cbe275c1ea4b34062a579a7a..1808a01cfb7e79fe9aa34d341bfcd8fc3603c898 100644 (file)
@@ -298,6 +298,10 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd)
 {
        cmd->vha->tgt_counters.core_qla_free_cmd++;
        cmd->cmd_in_wq = 1;
+
+       BUG_ON(cmd->cmd_flags & BIT_20);
+       cmd->cmd_flags |= BIT_20;
+
        INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free);
        queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work);
 }
@@ -374,6 +378,20 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
+
+       if (cmd->aborted) {
+               /* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+                * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+                * already kick start the free.
+                */
+               pr_debug("write_pending aborted cmd[%p] refcount %d "
+                       "transport_state %x, t_state %x, se_cmd_flags %x\n",
+                       cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+                       cmd->se_cmd.transport_state,
+                       cmd->se_cmd.t_state,
+                       cmd->se_cmd.se_cmd_flags);
+               return 0;
+       }
        cmd->cmd_flags |= BIT_3;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -405,7 +423,7 @@ static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd)
            se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) {
                spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
                wait_for_completion_timeout(&se_cmd->t_transport_stop_comp,
-                                           3 * HZ);
+                                               50);
                return 0;
        }
        spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
@@ -444,6 +462,9 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
        if (bidi)
                flags |= TARGET_SCF_BIDI_OP;
 
+       if (se_cmd->cpuid != WORK_CPU_UNBOUND)
+               flags |= TARGET_SCF_USE_CPUID;
+
        sess = cmd->sess;
        if (!sess) {
                pr_err("Unable to locate struct qla_tgt_sess from qla_tgt_cmd\n");
@@ -465,13 +486,25 @@ static int tcm_qla2xxx_handle_cmd(scsi_qla_host_t *vha, struct qla_tgt_cmd *cmd,
 static void tcm_qla2xxx_handle_data_work(struct work_struct *work)
 {
        struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
+       unsigned long flags;
 
        /*
         * Ensure that the complete FCP WRITE payload has been received.
         * Otherwise return an exception via CHECK_CONDITION status.
         */
        cmd->cmd_in_wq = 0;
-       cmd->cmd_flags |= BIT_11;
+
+       spin_lock_irqsave(&cmd->cmd_lock, flags);
+       cmd->cmd_flags |= CMD_FLAG_DATA_WORK;
+       if (cmd->aborted) {
+               cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+               spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
+               tcm_qla2xxx_free_cmd(cmd);
+               return;
+       }
+       spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+
        cmd->vha->tgt_counters.qla_core_ret_ctio++;
        if (!cmd->write_data_transferred) {
                /*
@@ -546,6 +579,20 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
 
+       if (cmd->aborted) {
+               /* Cmd can loop during Q-full.  tcm_qla2xxx_aborted_task
+                * can get ahead of this cmd. tcm_qla2xxx_aborted_task
+                * already kick start the free.
+                */
+               pr_debug("queue_data_in aborted cmd[%p] refcount %d "
+                       "transport_state %x, t_state %x, se_cmd_flags %x\n",
+                       cmd,cmd->se_cmd.cmd_kref.refcount.counter,
+                       cmd->se_cmd.transport_state,
+                       cmd->se_cmd.t_state,
+                       cmd->se_cmd.se_cmd_flags);
+               return 0;
+       }
+
        cmd->cmd_flags |= BIT_4;
        cmd->bufflen = se_cmd->data_length;
        cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
@@ -637,11 +684,34 @@ static void tcm_qla2xxx_queue_tm_rsp(struct se_cmd *se_cmd)
        qlt_xmit_tm_rsp(mcmd);
 }
 
+
+#define DATA_WORK_NOT_FREE(_flags) \
+       (( _flags & (CMD_FLAG_DATA_WORK|CMD_FLAG_DATA_WORK_FREE)) == \
+        CMD_FLAG_DATA_WORK)
 static void tcm_qla2xxx_aborted_task(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
-       qlt_abort_cmd(cmd);
+       unsigned long flags;
+
+       if (qlt_abort_cmd(cmd))
+               return;
+
+       spin_lock_irqsave(&cmd->cmd_lock, flags);
+       if ((cmd->state == QLA_TGT_STATE_NEW)||
+               ((cmd->state == QLA_TGT_STATE_DATA_IN) &&
+                DATA_WORK_NOT_FREE(cmd->cmd_flags)) ) {
+
+               cmd->cmd_flags |= CMD_FLAG_DATA_WORK_FREE;
+               spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+               /* Cmd have not reached firmware.
+                * Use this trigger to free it. */
+               tcm_qla2xxx_free_cmd(cmd);
+               return;
+       }
+       spin_unlock_irqrestore(&cmd->cmd_lock, flags);
+       return;
+
 }
 
 static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *,
index 47b9d13f97b880033c20144968cf715c8af41623..bbfbfd9e5aa391ff65d5e31859f31765bb5b77c3 100644 (file)
@@ -205,6 +205,8 @@ static struct {
        {"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC},
        {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
        {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+       {"Marvell", "Console", NULL, BLIST_SKIP_VPD_PAGES},
+       {"Marvell", "91xx Config", "1.01", BLIST_SKIP_VPD_PAGES},
        {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
        {"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
        {"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
index fa6b2c4eb7a2b1dc620bcf22db3abf1001a7f3d3..8c6e31874171b47459232d74f882328cdb967efb 100644 (file)
@@ -1344,6 +1344,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
 
        switch (ret) {
        case BLKPREP_KILL:
+       case BLKPREP_INVALID:
                req->errors = DID_NO_CONNECT << 16;
                /* release the command and kill it */
                if (req->special) {
index 4f18a851e2c7f7de25e590e9a6f93750150e5f37..00bc7218a7f80f06a139a7743b5a2c51331f68f0 100644 (file)
@@ -1272,16 +1272,18 @@ static void __scsi_remove_target(struct scsi_target *starget)
 void scsi_remove_target(struct device *dev)
 {
        struct Scsi_Host *shost = dev_to_shost(dev->parent);
-       struct scsi_target *starget;
+       struct scsi_target *starget, *last_target = NULL;
        unsigned long flags;
 
 restart:
        spin_lock_irqsave(shost->host_lock, flags);
        list_for_each_entry(starget, &shost->__targets, siblings) {
-               if (starget->state == STARGET_DEL)
+               if (starget->state == STARGET_DEL ||
+                   starget == last_target)
                        continue;
                if (starget->dev.parent == dev || &starget->dev == dev) {
                        kref_get(&starget->reap_ref);
+                       last_target = starget;
                        spin_unlock_irqrestore(shost->host_lock, flags);
                        __scsi_remove_target(starget);
                        scsi_target_reap(starget);
index bb669d32ccd0daee203a69840313fcb9cf343ee0..d749da765df141d7aa66ef2a31e591f6cbc94fed 100644 (file)
@@ -761,7 +761,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)
                break;
 
        default:
-               ret = BLKPREP_KILL;
+               ret = BLKPREP_INVALID;
                goto out;
        }
 
@@ -839,7 +839,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
        int ret;
 
        if (sdkp->device->no_write_same)
-               return BLKPREP_KILL;
+               return BLKPREP_INVALID;
 
        BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size);
 
index 503ab8b46c0b4e8a73d7e826ba1aaf3be1abd6b0..5e820674432ca38c46ad154b831c8eb19e974d34 100644 (file)
@@ -1261,7 +1261,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
        }
 
        sfp->mmap_called = 1;
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
        vma->vm_private_data = sfp;
        vma->vm_ops = &sg_mmap_vm_ops;
        return 0;
index 55627d097873a85780a878e32b32c20e6c4a9524..292c04eec9ad4b56518afc243d92b37602a3f456 100644 (file)
@@ -42,6 +42,7 @@
 #include <scsi/scsi_devinfo.h>
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
 
 /*
  * All wire protocol details (storage protocol between the guest and the host)
@@ -477,19 +478,18 @@ struct hv_host_device {
 struct storvsc_scan_work {
        struct work_struct work;
        struct Scsi_Host *host;
-       uint lun;
+       u8 lun;
+       u8 tgt_id;
 };
 
 static void storvsc_device_scan(struct work_struct *work)
 {
        struct storvsc_scan_work *wrk;
-       uint lun;
        struct scsi_device *sdev;
 
        wrk = container_of(work, struct storvsc_scan_work, work);
-       lun = wrk->lun;
 
-       sdev = scsi_device_lookup(wrk->host, 0, 0, lun);
+       sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
        if (!sdev)
                goto done;
        scsi_rescan_device(&sdev->sdev_gendev);
@@ -540,7 +540,7 @@ static void storvsc_remove_lun(struct work_struct *work)
        if (!scsi_host_get(wrk->host))
                goto done;
 
-       sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun);
+       sdev = scsi_device_lookup(wrk->host, 0, wrk->tgt_id, wrk->lun);
 
        if (sdev) {
                scsi_remove_device(sdev);
@@ -940,6 +940,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
 
        wrk->host = host;
        wrk->lun = vm_srb->lun;
+       wrk->tgt_id = vm_srb->target_id;
        INIT_WORK(&wrk->work, process_err_fn);
        schedule_work(&wrk->work);
 }
@@ -1770,6 +1771,11 @@ static int __init storvsc_drv_init(void)
        fc_transport_template = fc_attach_transport(&fc_transport_functions);
        if (!fc_transport_template)
                return -ENODEV;
+
+       /*
+        * Install Hyper-V specific timeout handler.
+        */
+       fc_transport_template->eh_timed_out = storvsc_eh_timed_out;
 #endif
 
        ret = vmbus_driver_register(&storvsc_drv);
index 91a003011acfacb277e892b47c99771ceae80ffa..a9bac3bf20de14e541a22608fcb1542cad0f6d5f 100644 (file)
@@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = {
 
 static int __init sh_pm_runtime_init(void)
 {
-       if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
+       if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
                if (!of_find_compatible_node(NULL, NULL,
                                             "renesas,cpg-mstp-clocks"))
                        return 0;
index aebad36391c93b36658c52222e761366c111216f..8feac599e9ab4bfe886b8da89960f04ed32c1aba 100644 (file)
@@ -1571,6 +1571,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
 
        as->use_cs_gpios = true;
        if (atmel_spi_is_v2(as) &&
+           pdev->dev.of_node &&
            !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
                as->use_cs_gpios = false;
                master->num_chipselect = 4;
index 7de6f8472a8100656884647ad5447be94604e7bb..ecc73c0a97cf5ebf0d2a6c623cf3ce1ac311e62b 100644 (file)
@@ -73,8 +73,8 @@
 
 /* Bitfields in CNTL1 */
 #define BCM2835_AUX_SPI_CNTL1_CSHIGH   0x00000700
-#define BCM2835_AUX_SPI_CNTL1_IDLE     0x00000080
-#define BCM2835_AUX_SPI_CNTL1_TXEMPTY  0x00000040
+#define BCM2835_AUX_SPI_CNTL1_TXEMPTY  0x00000080
+#define BCM2835_AUX_SPI_CNTL1_IDLE     0x00000040
 #define BCM2835_AUX_SPI_CNTL1_MSBF_IN  0x00000002
 #define BCM2835_AUX_SPI_CNTL1_KEEP_IN  0x00000001
 
index 7fd6a4c009d25d8ebfd3f739bd72220f1701320a..7cb0c1921495959dcb6c919c3cb9f1811a5e90bb 100644 (file)
@@ -84,7 +84,7 @@ struct fsl_espi_transfer {
 /* SPCOM register values */
 #define SPCOM_CS(x)            ((x) << 30)
 #define SPCOM_TRANLEN(x)       ((x) << 0)
-#define        SPCOM_TRANLEN_MAX       0xFFFF  /* Max transaction length */
+#define        SPCOM_TRANLEN_MAX       0x10000 /* Max transaction length */
 
 #define AUTOSUSPEND_TIMEOUT 2000
 
@@ -233,7 +233,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
        reinit_completion(&mpc8xxx_spi->done);
 
        /* Set SPCOM[CS] and SPCOM[TRANLEN] field */
-       if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
+       if (t->len > SPCOM_TRANLEN_MAX) {
                dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
                                " beyond the SPCOM[TRANLEN] field\n", t->len);
                return -EINVAL;
index d98c33cb64f9b4825998eb1faa2316b1e4796a7d..6a4ff27f4357eb229815c18b535327487f2df580 100644 (file)
@@ -929,7 +929,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                                        tx->sgl, tx->nents, DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (!desc_tx)
-                       goto no_dma;
+                       goto tx_nodma;
 
                desc_tx->callback = spi_imx_dma_tx_callback;
                desc_tx->callback_param = (void *)spi_imx;
@@ -941,7 +941,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
                                        rx->sgl, rx->nents, DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (!desc_rx)
-                       goto no_dma;
+                       goto rx_nodma;
 
                desc_rx->callback = spi_imx_dma_rx_callback;
                desc_rx->callback_param = (void *)spi_imx;
@@ -1008,7 +1008,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
 
        return ret;
 
-no_dma:
+rx_nodma:
+       dmaengine_terminate_all(master->dma_tx);
+tx_nodma:
        pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
                     dev_driver_string(&master->dev),
                     dev_name(&master->dev));
index 894616f687b0f314168bc17e77d14b7e477a4ec8..cf4bb36bee25c9bdf8ad39a570ceb61fda3a7421 100644 (file)
@@ -761,6 +761,7 @@ static int spi_test_run_iter(struct spi_device *spi,
                test.iterate_transfer_mask = 1;
 
        /* count number of transfers with tx/rx_buf != NULL */
+       rx_count = tx_count = 0;
        for (i = 0; i < test.transfer_count; i++) {
                if (test.transfers[i].tx_buf)
                        tx_count++;
index 7273820275e90c86ddee32b796187d2b940a5c27..0caa3c8bef46c46e0ed66bf89f518cc5c5236449 100644 (file)
@@ -1490,6 +1490,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        return status;
 
 disable_pm:
+       pm_runtime_dont_use_autosuspend(&pdev->dev);
+       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 free_master:
        spi_master_put(master);
@@ -1501,6 +1503,7 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
 
+       pm_runtime_dont_use_autosuspend(mcspi->dev);
        pm_runtime_put_sync(mcspi->dev);
        pm_runtime_disable(&pdev->dev);
 
index 0c675861623f4abeb2054b65c87fe185d8188bf3..d8e4219c2324900c583245407a7c78f20e20325e 100644 (file)
@@ -83,6 +83,7 @@ config SSB_SDIOHOST
 config SSB_HOST_SOC
        bool "Support for SSB bus on SoC"
        depends on SSB && BCM47XX_NVRAM
+       select SSB_SPROM
        help
          Host interface for a SSB directly mapped into memory. This is
          for some Broadcom SoCs from the BCM47xx and BCM53xx lines.
index 58d4517e18369f984fd1fac9bfe53b9cc9ba4a3a..b9519be90fdae94ad5dbd278a336216de2971ce8 100644 (file)
@@ -6,6 +6,7 @@ menu "Analog to digital converters"
 config AD7606
        tristate "Analog Devices AD7606 ADC driver"
        depends on GPIOLIB || COMPILE_TEST
+       depends on HAS_IOMEM
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        help
index f129039bece3c74b96fb78e70996ea65279502ea..69287108f793bcb81bcf91451b64f1f4f86c2257 100644 (file)
@@ -217,8 +217,12 @@ error_ret:
 static int ade7753_reset(struct device *dev)
 {
        u16 val;
+       int ret;
+
+       ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
+       if (ret)
+               return ret;
 
-       ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
        val |= BIT(6); /* Software Chip Reset */
 
        return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
@@ -343,8 +347,12 @@ error_ret:
 static int ade7753_stop_device(struct device *dev)
 {
        u16 val;
+       int ret;
+
+       ret = ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
+       if (ret)
+               return ret;
 
-       ade7753_spi_read_reg_16(dev, ADE7753_MODE, &val);
        val |= BIT(4);  /* AD converters can be turned off */
 
        return ade7753_spi_write_reg_16(dev, ADE7753_MODE, val);
index 3ec7e65a3ffa524efb6e95d98bbc6916592d2a18..db49af90217e3f62cc6f8e3dcf1ec713a732abb2 100644 (file)
@@ -147,7 +147,7 @@ static int vpfe_prepare_pipeline(struct vpfe_video_device *video)
        mutex_lock(&mdev->graph_mutex);
        ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
        if (ret) {
-               mutex_unlock(&video->lock);
+               mutex_unlock(&mdev->graph_mutex);
                return -ENOMEM;
        }
        media_entity_graph_walk_start(&graph, entity);
index ba8765063174c4e05b517cdf45d33c6c5f57cf25..f1f3ecadf0fb0d0e1a0bb11d014d766e1187e55c 100644 (file)
@@ -22,12 +22,6 @@ menuconfig STAGING_RDMA
 # Please keep entries in alphabetic order
 if STAGING_RDMA
 
-source "drivers/staging/rdma/amso1100/Kconfig"
-
-source "drivers/staging/rdma/ehca/Kconfig"
-
 source "drivers/staging/rdma/hfi1/Kconfig"
 
-source "drivers/staging/rdma/ipath/Kconfig"
-
 endif
index 139d78ef2c24388b93ed6a008090190cff6de663..8c7fc1de48a7bf6f86f103ad120f9052ea399c58 100644 (file)
@@ -1,5 +1,2 @@
 # Entries for RDMA_STAGING tree
-obj-$(CONFIG_INFINIBAND_AMSO1100)      += amso1100/
-obj-$(CONFIG_INFINIBAND_EHCA)  += ehca/
 obj-$(CONFIG_INFINIBAND_HFI1)  += hfi1/
-obj-$(CONFIG_INFINIBAND_IPATH) += ipath/
diff --git a/drivers/staging/rdma/amso1100/Kbuild b/drivers/staging/rdma/amso1100/Kbuild
deleted file mode 100644 (file)
index 950dfab..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-ccflags-$(CONFIG_INFINIBAND_AMSO1100_DEBUG) := -DDEBUG
-
-obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
-
-iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \
-       c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o
diff --git a/drivers/staging/rdma/amso1100/Kconfig b/drivers/staging/rdma/amso1100/Kconfig
deleted file mode 100644 (file)
index e6ce5f2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-config INFINIBAND_AMSO1100
-       tristate "Ammasso 1100 HCA support"
-       depends on PCI && INET
-       ---help---
-         This is a low-level driver for the Ammasso 1100 host
-         channel adapter (HCA).
-
-config INFINIBAND_AMSO1100_DEBUG
-       bool "Verbose debugging output"
-       depends on INFINIBAND_AMSO1100
-       default n
-       ---help---
-         This option causes the amso1100 driver to produce a bunch of
-         debug messages.  Select this if you are developing the driver
-         or trying to diagnose a problem.
diff --git a/drivers/staging/rdma/amso1100/TODO b/drivers/staging/rdma/amso1100/TODO
deleted file mode 100644 (file)
index 18b00a5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-7/2015
-
-The amso1100 driver has been deprecated and moved to drivers/staging.
-It will be removed in the 4.6 merge window.
diff --git a/drivers/staging/rdma/amso1100/c2.c b/drivers/staging/rdma/amso1100/c2.c
deleted file mode 100644 (file)
index b46ebd1..0000000
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <linux/crc32.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/prefetch.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-
-#include <rdma/ib_smi.h>
-#include "c2.h"
-#include "c2_provider.h"
-
-MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
-MODULE_DESCRIPTION("Ammasso AMSO1100 Low-level iWARP Driver");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_VERSION(DRV_VERSION);
-
-static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
-    | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
-
-static int debug = -1;         /* defaults above */
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
-
-static int c2_up(struct net_device *netdev);
-static int c2_down(struct net_device *netdev);
-static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
-static void c2_tx_interrupt(struct net_device *netdev);
-static void c2_rx_interrupt(struct net_device *netdev);
-static irqreturn_t c2_interrupt(int irq, void *dev_id);
-static void c2_tx_timeout(struct net_device *netdev);
-static int c2_change_mtu(struct net_device *netdev, int new_mtu);
-static void c2_reset(struct c2_port *c2_port);
-
-static struct pci_device_id c2_pci_table[] = {
-       { PCI_DEVICE(0x18b8, 0xb001) },
-       { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, c2_pci_table);
-
-static void c2_set_rxbufsize(struct c2_port *c2_port)
-{
-       struct net_device *netdev = c2_port->netdev;
-
-       if (netdev->mtu > RX_BUF_SIZE)
-               c2_port->rx_buf_size =
-                   netdev->mtu + ETH_HLEN + sizeof(struct c2_rxp_hdr) +
-                   NET_IP_ALIGN;
-       else
-               c2_port->rx_buf_size = sizeof(struct c2_rxp_hdr) + RX_BUF_SIZE;
-}
-
-/*
- * Allocate TX ring elements and chain them together.
- * One-to-one association of adapter descriptors with ring elements.
- */
-static int c2_tx_ring_alloc(struct c2_ring *tx_ring, void *vaddr,
-                           dma_addr_t base, void __iomem * mmio_txp_ring)
-{
-       struct c2_tx_desc *tx_desc;
-       struct c2_txp_desc __iomem *txp_desc;
-       struct c2_element *elem;
-       int i;
-
-       tx_ring->start = kmalloc_array(tx_ring->count, sizeof(*elem),
-                                      GFP_KERNEL);
-       if (!tx_ring->start)
-               return -ENOMEM;
-
-       elem = tx_ring->start;
-       tx_desc = vaddr;
-       txp_desc = mmio_txp_ring;
-       for (i = 0; i < tx_ring->count; i++, elem++, tx_desc++, txp_desc++) {
-               tx_desc->len = 0;
-               tx_desc->status = 0;
-
-               /* Set TXP_HTXD_UNINIT */
-               __raw_writeq((__force u64) cpu_to_be64(0x1122334455667788ULL),
-                            (void __iomem *) txp_desc + C2_TXP_ADDR);
-               __raw_writew(0, (void __iomem *) txp_desc + C2_TXP_LEN);
-               __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_UNINIT),
-                            (void __iomem *) txp_desc + C2_TXP_FLAGS);
-
-               elem->skb = NULL;
-               elem->ht_desc = tx_desc;
-               elem->hw_desc = txp_desc;
-
-               if (i == tx_ring->count - 1) {
-                       elem->next = tx_ring->start;
-                       tx_desc->next_offset = base;
-               } else {
-                       elem->next = elem + 1;
-                       tx_desc->next_offset =
-                           base + (i + 1) * sizeof(*tx_desc);
-               }
-       }
-
-       tx_ring->to_use = tx_ring->to_clean = tx_ring->start;
-
-       return 0;
-}
-
-/*
- * Allocate RX ring elements and chain them together.
- * One-to-one association of adapter descriptors with ring elements.
- */
-static int c2_rx_ring_alloc(struct c2_ring *rx_ring, void *vaddr,
-                           dma_addr_t base, void __iomem * mmio_rxp_ring)
-{
-       struct c2_rx_desc *rx_desc;
-       struct c2_rxp_desc __iomem *rxp_desc;
-       struct c2_element *elem;
-       int i;
-
-       rx_ring->start = kmalloc_array(rx_ring->count, sizeof(*elem),
-                                      GFP_KERNEL);
-       if (!rx_ring->start)
-               return -ENOMEM;
-
-       elem = rx_ring->start;
-       rx_desc = vaddr;
-       rxp_desc = mmio_rxp_ring;
-       for (i = 0; i < rx_ring->count; i++, elem++, rx_desc++, rxp_desc++) {
-               rx_desc->len = 0;
-               rx_desc->status = 0;
-
-               /* Set RXP_HRXD_UNINIT */
-               __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_OK),
-                      (void __iomem *) rxp_desc + C2_RXP_STATUS);
-               __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_COUNT);
-               __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_LEN);
-               __raw_writeq((__force u64) cpu_to_be64(0x99aabbccddeeffULL),
-                            (void __iomem *) rxp_desc + C2_RXP_ADDR);
-               __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_UNINIT),
-                            (void __iomem *) rxp_desc + C2_RXP_FLAGS);
-
-               elem->skb = NULL;
-               elem->ht_desc = rx_desc;
-               elem->hw_desc = rxp_desc;
-
-               if (i == rx_ring->count - 1) {
-                       elem->next = rx_ring->start;
-                       rx_desc->next_offset = base;
-               } else {
-                       elem->next = elem + 1;
-                       rx_desc->next_offset =
-                           base + (i + 1) * sizeof(*rx_desc);
-               }
-       }
-
-       rx_ring->to_use = rx_ring->to_clean = rx_ring->start;
-
-       return 0;
-}
-
-/* Setup buffer for receiving */
-static inline int c2_rx_alloc(struct c2_port *c2_port, struct c2_element *elem)
-{
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_rx_desc *rx_desc = elem->ht_desc;
-       struct sk_buff *skb;
-       dma_addr_t mapaddr;
-       u32 maplen;
-       struct c2_rxp_hdr *rxp_hdr;
-
-       skb = dev_alloc_skb(c2_port->rx_buf_size);
-       if (unlikely(!skb)) {
-               pr_debug("%s: out of memory for receive\n",
-                       c2_port->netdev->name);
-               return -ENOMEM;
-       }
-
-       /* Zero out the rxp hdr in the sk_buff */
-       memset(skb->data, 0, sizeof(*rxp_hdr));
-
-       skb->dev = c2_port->netdev;
-
-       maplen = c2_port->rx_buf_size;
-       mapaddr =
-           pci_map_single(c2dev->pcidev, skb->data, maplen,
-                          PCI_DMA_FROMDEVICE);
-
-       /* Set the sk_buff RXP_header to RXP_HRXD_READY */
-       rxp_hdr = (struct c2_rxp_hdr *) skb->data;
-       rxp_hdr->flags = RXP_HRXD_READY;
-
-       __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
-       __raw_writew((__force u16) cpu_to_be16((u16) maplen - sizeof(*rxp_hdr)),
-                    elem->hw_desc + C2_RXP_LEN);
-       __raw_writeq((__force u64) cpu_to_be64(mapaddr), elem->hw_desc + C2_RXP_ADDR);
-       __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_READY),
-                    elem->hw_desc + C2_RXP_FLAGS);
-
-       elem->skb = skb;
-       elem->mapaddr = mapaddr;
-       elem->maplen = maplen;
-       rx_desc->len = maplen;
-
-       return 0;
-}
-
-/*
- * Allocate buffers for the Rx ring
- * For receive:  rx_ring.to_clean is next received frame
- */
-static int c2_rx_fill(struct c2_port *c2_port)
-{
-       struct c2_ring *rx_ring = &c2_port->rx_ring;
-       struct c2_element *elem;
-       int ret = 0;
-
-       elem = rx_ring->start;
-       do {
-               if (c2_rx_alloc(c2_port, elem)) {
-                       ret = 1;
-                       break;
-               }
-       } while ((elem = elem->next) != rx_ring->start);
-
-       rx_ring->to_clean = rx_ring->start;
-       return ret;
-}
-
-/* Free all buffers in RX ring, assumes receiver stopped */
-static void c2_rx_clean(struct c2_port *c2_port)
-{
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_ring *rx_ring = &c2_port->rx_ring;
-       struct c2_element *elem;
-       struct c2_rx_desc *rx_desc;
-
-       elem = rx_ring->start;
-       do {
-               rx_desc = elem->ht_desc;
-               rx_desc->len = 0;
-
-               __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
-               __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
-               __raw_writew(0, elem->hw_desc + C2_RXP_LEN);
-               __raw_writeq((__force u64) cpu_to_be64(0x99aabbccddeeffULL),
-                            elem->hw_desc + C2_RXP_ADDR);
-               __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_UNINIT),
-                            elem->hw_desc + C2_RXP_FLAGS);
-
-               if (elem->skb) {
-                       pci_unmap_single(c2dev->pcidev, elem->mapaddr,
-                                        elem->maplen, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(elem->skb);
-                       elem->skb = NULL;
-               }
-       } while ((elem = elem->next) != rx_ring->start);
-}
-
-static inline int c2_tx_free(struct c2_dev *c2dev, struct c2_element *elem)
-{
-       struct c2_tx_desc *tx_desc = elem->ht_desc;
-
-       tx_desc->len = 0;
-
-       pci_unmap_single(c2dev->pcidev, elem->mapaddr, elem->maplen,
-                        PCI_DMA_TODEVICE);
-
-       if (elem->skb) {
-               dev_kfree_skb_any(elem->skb);
-               elem->skb = NULL;
-       }
-
-       return 0;
-}
-
-/* Free all buffers in TX ring, assumes transmitter stopped */
-static void c2_tx_clean(struct c2_port *c2_port)
-{
-       struct c2_ring *tx_ring = &c2_port->tx_ring;
-       struct c2_element *elem;
-       struct c2_txp_desc txp_htxd;
-       int retry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&c2_port->tx_lock, flags);
-
-       elem = tx_ring->start;
-
-       do {
-               retry = 0;
-               do {
-                       txp_htxd.flags =
-                           readw(elem->hw_desc + C2_TXP_FLAGS);
-
-                       if (txp_htxd.flags == TXP_HTXD_READY) {
-                               retry = 1;
-                               __raw_writew(0,
-                                            elem->hw_desc + C2_TXP_LEN);
-                               __raw_writeq(0,
-                                            elem->hw_desc + C2_TXP_ADDR);
-                               __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_DONE),
-                                            elem->hw_desc + C2_TXP_FLAGS);
-                               c2_port->netdev->stats.tx_dropped++;
-                               break;
-                       } else {
-                               __raw_writew(0,
-                                            elem->hw_desc + C2_TXP_LEN);
-                               __raw_writeq((__force u64) cpu_to_be64(0x1122334455667788ULL),
-                                            elem->hw_desc + C2_TXP_ADDR);
-                               __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_UNINIT),
-                                            elem->hw_desc + C2_TXP_FLAGS);
-                       }
-
-                       c2_tx_free(c2_port->c2dev, elem);
-
-               } while ((elem = elem->next) != tx_ring->start);
-       } while (retry);
-
-       c2_port->tx_avail = c2_port->tx_ring.count - 1;
-       c2_port->c2dev->cur_tx = tx_ring->to_use - tx_ring->start;
-
-       if (c2_port->tx_avail > MAX_SKB_FRAGS + 1)
-               netif_wake_queue(c2_port->netdev);
-
-       spin_unlock_irqrestore(&c2_port->tx_lock, flags);
-}
-
-/*
- * Process transmit descriptors marked 'DONE' by the firmware,
- * freeing up their unneeded sk_buffs.
- */
-static void c2_tx_interrupt(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_ring *tx_ring = &c2_port->tx_ring;
-       struct c2_element *elem;
-       struct c2_txp_desc txp_htxd;
-
-       spin_lock(&c2_port->tx_lock);
-
-       for (elem = tx_ring->to_clean; elem != tx_ring->to_use;
-            elem = elem->next) {
-               txp_htxd.flags =
-                   be16_to_cpu((__force __be16) readw(elem->hw_desc + C2_TXP_FLAGS));
-
-               if (txp_htxd.flags != TXP_HTXD_DONE)
-                       break;
-
-               if (netif_msg_tx_done(c2_port)) {
-                       /* PCI reads are expensive in fast path */
-                       txp_htxd.len =
-                           be16_to_cpu((__force __be16) readw(elem->hw_desc + C2_TXP_LEN));
-                       pr_debug("%s: tx done slot %3Zu status 0x%x len "
-                               "%5u bytes\n",
-                               netdev->name, elem - tx_ring->start,
-                               txp_htxd.flags, txp_htxd.len);
-               }
-
-               c2_tx_free(c2dev, elem);
-               ++(c2_port->tx_avail);
-       }
-
-       tx_ring->to_clean = elem;
-
-       if (netif_queue_stopped(netdev)
-           && c2_port->tx_avail > MAX_SKB_FRAGS + 1)
-               netif_wake_queue(netdev);
-
-       spin_unlock(&c2_port->tx_lock);
-}
-
-static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem)
-{
-       struct c2_rx_desc *rx_desc = elem->ht_desc;
-       struct c2_rxp_hdr *rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
-
-       if (rxp_hdr->status != RXP_HRXD_OK ||
-           rxp_hdr->len > (rx_desc->len - sizeof(*rxp_hdr))) {
-               pr_debug("BAD RXP_HRXD\n");
-               pr_debug("  rx_desc : %p\n", rx_desc);
-               pr_debug("    index : %Zu\n",
-                       elem - c2_port->rx_ring.start);
-               pr_debug("    len   : %u\n", rx_desc->len);
-               pr_debug("  rxp_hdr : %p [PA %p]\n", rxp_hdr,
-                       (void *) __pa((unsigned long) rxp_hdr));
-               pr_debug("    flags : 0x%x\n", rxp_hdr->flags);
-               pr_debug("    status: 0x%x\n", rxp_hdr->status);
-               pr_debug("    len   : %u\n", rxp_hdr->len);
-               pr_debug("    rsvd  : 0x%x\n", rxp_hdr->rsvd);
-       }
-
-       /* Setup the skb for reuse since we're dropping this pkt */
-       elem->skb->data = elem->skb->head;
-       skb_reset_tail_pointer(elem->skb);
-
-       /* Zero out the rxp hdr in the sk_buff */
-       memset(elem->skb->data, 0, sizeof(*rxp_hdr));
-
-       /* Write the descriptor to the adapter's rx ring */
-       __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
-       __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
-       __raw_writew((__force u16) cpu_to_be16((u16) elem->maplen - sizeof(*rxp_hdr)),
-                    elem->hw_desc + C2_RXP_LEN);
-       __raw_writeq((__force u64) cpu_to_be64(elem->mapaddr),
-                    elem->hw_desc + C2_RXP_ADDR);
-       __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_READY),
-                    elem->hw_desc + C2_RXP_FLAGS);
-
-       pr_debug("packet dropped\n");
-       c2_port->netdev->stats.rx_dropped++;
-}
-
-static void c2_rx_interrupt(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_ring *rx_ring = &c2_port->rx_ring;
-       struct c2_element *elem;
-       struct c2_rx_desc *rx_desc;
-       struct c2_rxp_hdr *rxp_hdr;
-       struct sk_buff *skb;
-       dma_addr_t mapaddr;
-       u32 maplen, buflen;
-       unsigned long flags;
-
-       spin_lock_irqsave(&c2dev->lock, flags);
-
-       /* Begin where we left off */
-       rx_ring->to_clean = rx_ring->start + c2dev->cur_rx;
-
-       for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean;
-            elem = elem->next) {
-               rx_desc = elem->ht_desc;
-               mapaddr = elem->mapaddr;
-               maplen = elem->maplen;
-               skb = elem->skb;
-               rxp_hdr = (struct c2_rxp_hdr *) skb->data;
-
-               if (rxp_hdr->flags != RXP_HRXD_DONE)
-                       break;
-               buflen = rxp_hdr->len;
-
-               /* Sanity check the RXP header */
-               if (rxp_hdr->status != RXP_HRXD_OK ||
-                   buflen > (rx_desc->len - sizeof(*rxp_hdr))) {
-                       c2_rx_error(c2_port, elem);
-                       continue;
-               }
-
-               /*
-                * Allocate and map a new skb for replenishing the host
-                * RX desc
-                */
-               if (c2_rx_alloc(c2_port, elem)) {
-                       c2_rx_error(c2_port, elem);
-                       continue;
-               }
-
-               /* Unmap the old skb */
-               pci_unmap_single(c2dev->pcidev, mapaddr, maplen,
-                                PCI_DMA_FROMDEVICE);
-
-               prefetch(skb->data);
-
-               /*
-                * Skip past the leading 8 bytes comprising of the
-                * "struct c2_rxp_hdr", prepended by the adapter
-                * to the usual Ethernet header ("struct ethhdr"),
-                * to the start of the raw Ethernet packet.
-                *
-                * Fix up the various fields in the sk_buff before
-                * passing it up to netif_rx(). The transfer size
-                * (in bytes) specified by the adapter len field of
-                * the "struct rxp_hdr_t" does NOT include the
-                * "sizeof(struct c2_rxp_hdr)".
-                */
-               skb->data += sizeof(*rxp_hdr);
-               skb_set_tail_pointer(skb, buflen);
-               skb->len = buflen;
-               skb->protocol = eth_type_trans(skb, netdev);
-
-               netif_rx(skb);
-
-               netdev->stats.rx_packets++;
-               netdev->stats.rx_bytes += buflen;
-       }
-
-       /* Save where we left off */
-       rx_ring->to_clean = elem;
-       c2dev->cur_rx = elem - rx_ring->start;
-       C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
-
-       spin_unlock_irqrestore(&c2dev->lock, flags);
-}
-
-/*
- * Handle netisr0 TX & RX interrupts.
- */
-static irqreturn_t c2_interrupt(int irq, void *dev_id)
-{
-       unsigned int netisr0, dmaisr;
-       int handled = 0;
-       struct c2_dev *c2dev = dev_id;
-
-       /* Process CCILNET interrupts */
-       netisr0 = readl(c2dev->regs + C2_NISR0);
-       if (netisr0) {
-
-               /*
-                * There is an issue with the firmware that always
-                * provides the status of RX for both TX & RX
-                * interrupts.  So process both queues here.
-                */
-               c2_rx_interrupt(c2dev->netdev);
-               c2_tx_interrupt(c2dev->netdev);
-
-               /* Clear the interrupt */
-               writel(netisr0, c2dev->regs + C2_NISR0);
-               handled++;
-       }
-
-       /* Process RNIC interrupts */
-       dmaisr = readl(c2dev->regs + C2_DISR);
-       if (dmaisr) {
-               writel(dmaisr, c2dev->regs + C2_DISR);
-               c2_rnic_interrupt(c2dev);
-               handled++;
-       }
-
-       if (handled) {
-               return IRQ_HANDLED;
-       } else {
-               return IRQ_NONE;
-       }
-}
-
-static int c2_up(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_element *elem;
-       struct c2_rxp_hdr *rxp_hdr;
-       struct in_device *in_dev;
-       size_t rx_size, tx_size;
-       int ret, i;
-       unsigned int netimr0;
-
-       if (netif_msg_ifup(c2_port))
-               pr_debug("%s: enabling interface\n", netdev->name);
-
-       /* Set the Rx buffer size based on MTU */
-       c2_set_rxbufsize(c2_port);
-
-       /* Allocate DMA'able memory for Tx/Rx host descriptor rings */
-       rx_size = c2_port->rx_ring.count * sizeof(struct c2_rx_desc);
-       tx_size = c2_port->tx_ring.count * sizeof(struct c2_tx_desc);
-
-       c2_port->mem_size = tx_size + rx_size;
-       c2_port->mem = pci_zalloc_consistent(c2dev->pcidev, c2_port->mem_size,
-                                            &c2_port->dma);
-       if (c2_port->mem == NULL) {
-               pr_debug("Unable to allocate memory for "
-                       "host descriptor rings\n");
-               return -ENOMEM;
-       }
-
-       /* Create the Rx host descriptor ring */
-       if ((ret =
-            c2_rx_ring_alloc(&c2_port->rx_ring, c2_port->mem, c2_port->dma,
-                             c2dev->mmio_rxp_ring))) {
-               pr_debug("Unable to create RX ring\n");
-               goto bail0;
-       }
-
-       /* Allocate Rx buffers for the host descriptor ring */
-       if (c2_rx_fill(c2_port)) {
-               pr_debug("Unable to fill RX ring\n");
-               goto bail1;
-       }
-
-       /* Create the Tx host descriptor ring */
-       if ((ret = c2_tx_ring_alloc(&c2_port->tx_ring, c2_port->mem + rx_size,
-                                   c2_port->dma + rx_size,
-                                   c2dev->mmio_txp_ring))) {
-               pr_debug("Unable to create TX ring\n");
-               goto bail1;
-       }
-
-       /* Set the TX pointer to where we left off */
-       c2_port->tx_avail = c2_port->tx_ring.count - 1;
-       c2_port->tx_ring.to_use = c2_port->tx_ring.to_clean =
-           c2_port->tx_ring.start + c2dev->cur_tx;
-
-       /* missing: Initialize MAC */
-
-       BUG_ON(c2_port->tx_ring.to_use != c2_port->tx_ring.to_clean);
-
-       /* Reset the adapter, ensures the driver is in sync with the RXP */
-       c2_reset(c2_port);
-
-       /* Reset the READY bit in the sk_buff RXP headers & adapter HRXDQ */
-       for (i = 0, elem = c2_port->rx_ring.start; i < c2_port->rx_ring.count;
-            i++, elem++) {
-               rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
-               rxp_hdr->flags = 0;
-               __raw_writew((__force u16) cpu_to_be16(RXP_HRXD_READY),
-                            elem->hw_desc + C2_RXP_FLAGS);
-       }
-
-       /* Enable network packets */
-       netif_start_queue(netdev);
-
-       /* Enable IRQ */
-       writel(0, c2dev->regs + C2_IDIS);
-       netimr0 = readl(c2dev->regs + C2_NIMR0);
-       netimr0 &= ~(C2_PCI_HTX_INT | C2_PCI_HRX_INT);
-       writel(netimr0, c2dev->regs + C2_NIMR0);
-
-       /* Tell the stack to ignore arp requests for ipaddrs bound to
-        * other interfaces.  This is needed to prevent the host stack
-        * from responding to arp requests to the ipaddr bound on the
-        * rdma interface.
-        */
-       in_dev = in_dev_get(netdev);
-       IN_DEV_CONF_SET(in_dev, ARP_IGNORE, 1);
-       in_dev_put(in_dev);
-
-       return 0;
-
-bail1:
-       c2_rx_clean(c2_port);
-       kfree(c2_port->rx_ring.start);
-
-bail0:
-       pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
-                           c2_port->dma);
-
-       return ret;
-}
-
-static int c2_down(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-       struct c2_dev *c2dev = c2_port->c2dev;
-
-       if (netif_msg_ifdown(c2_port))
-               pr_debug("%s: disabling interface\n",
-                       netdev->name);
-
-       /* Wait for all the queued packets to get sent */
-       c2_tx_interrupt(netdev);
-
-       /* Disable network packets */
-       netif_stop_queue(netdev);
-
-       /* Disable IRQs by clearing the interrupt mask */
-       writel(1, c2dev->regs + C2_IDIS);
-       writel(0, c2dev->regs + C2_NIMR0);
-
-       /* missing: Stop transmitter */
-
-       /* missing: Stop receiver */
-
-       /* Reset the adapter, ensures the driver is in sync with the RXP */
-       c2_reset(c2_port);
-
-       /* missing: Turn off LEDs here */
-
-       /* Free all buffers in the host descriptor rings */
-       c2_tx_clean(c2_port);
-       c2_rx_clean(c2_port);
-
-       /* Free the host descriptor rings */
-       kfree(c2_port->rx_ring.start);
-       kfree(c2_port->tx_ring.start);
-       pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
-                           c2_port->dma);
-
-       return 0;
-}
-
-static void c2_reset(struct c2_port *c2_port)
-{
-       struct c2_dev *c2dev = c2_port->c2dev;
-       unsigned int cur_rx = c2dev->cur_rx;
-
-       /* Tell the hardware to quiesce */
-       C2_SET_CUR_RX(c2dev, cur_rx | C2_PCI_HRX_QUI);
-
-       /*
-        * The hardware will reset the C2_PCI_HRX_QUI bit once
-        * the RXP is quiesced.  Wait 2 seconds for this.
-        */
-       ssleep(2);
-
-       cur_rx = C2_GET_CUR_RX(c2dev);
-
-       if (cur_rx & C2_PCI_HRX_QUI)
-               pr_debug("c2_reset: failed to quiesce the hardware!\n");
-
-       cur_rx &= ~C2_PCI_HRX_QUI;
-
-       c2dev->cur_rx = cur_rx;
-
-       pr_debug("Current RX: %u\n", c2dev->cur_rx);
-}
-
-static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-       struct c2_dev *c2dev = c2_port->c2dev;
-       struct c2_ring *tx_ring = &c2_port->tx_ring;
-       struct c2_element *elem;
-       dma_addr_t mapaddr;
-       u32 maplen;
-       unsigned long flags;
-       unsigned int i;
-
-       spin_lock_irqsave(&c2_port->tx_lock, flags);
-
-       if (unlikely(c2_port->tx_avail < (skb_shinfo(skb)->nr_frags + 1))) {
-               netif_stop_queue(netdev);
-               spin_unlock_irqrestore(&c2_port->tx_lock, flags);
-
-               pr_debug("%s: Tx ring full when queue awake!\n",
-                       netdev->name);
-               return NETDEV_TX_BUSY;
-       }
-
-       maplen = skb_headlen(skb);
-       mapaddr =
-           pci_map_single(c2dev->pcidev, skb->data, maplen, PCI_DMA_TODEVICE);
-
-       elem = tx_ring->to_use;
-       elem->skb = skb;
-       elem->mapaddr = mapaddr;
-       elem->maplen = maplen;
-
-       /* Tell HW to xmit */
-       __raw_writeq((__force u64) cpu_to_be64(mapaddr),
-                    elem->hw_desc + C2_TXP_ADDR);
-       __raw_writew((__force u16) cpu_to_be16(maplen),
-                    elem->hw_desc + C2_TXP_LEN);
-       __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_READY),
-                    elem->hw_desc + C2_TXP_FLAGS);
-
-       netdev->stats.tx_packets++;
-       netdev->stats.tx_bytes += maplen;
-
-       /* Loop thru additional data fragments and queue them */
-       if (skb_shinfo(skb)->nr_frags) {
-               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-                       const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-                       maplen = skb_frag_size(frag);
-                       mapaddr = skb_frag_dma_map(&c2dev->pcidev->dev, frag,
-                                                  0, maplen, DMA_TO_DEVICE);
-                       elem = elem->next;
-                       elem->skb = NULL;
-                       elem->mapaddr = mapaddr;
-                       elem->maplen = maplen;
-
-                       /* Tell HW to xmit */
-                       __raw_writeq((__force u64) cpu_to_be64(mapaddr),
-                                    elem->hw_desc + C2_TXP_ADDR);
-                       __raw_writew((__force u16) cpu_to_be16(maplen),
-                                    elem->hw_desc + C2_TXP_LEN);
-                       __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_READY),
-                                    elem->hw_desc + C2_TXP_FLAGS);
-
-                       netdev->stats.tx_packets++;
-                       netdev->stats.tx_bytes += maplen;
-               }
-       }
-
-       tx_ring->to_use = elem->next;
-       c2_port->tx_avail -= (skb_shinfo(skb)->nr_frags + 1);
-
-       if (c2_port->tx_avail <= MAX_SKB_FRAGS + 1) {
-               netif_stop_queue(netdev);
-               if (netif_msg_tx_queued(c2_port))
-                       pr_debug("%s: transmit queue full\n",
-                               netdev->name);
-       }
-
-       spin_unlock_irqrestore(&c2_port->tx_lock, flags);
-
-       netdev->trans_start = jiffies;
-
-       return NETDEV_TX_OK;
-}
-
-static void c2_tx_timeout(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-
-       if (netif_msg_timer(c2_port))
-               pr_debug("%s: tx timeout\n", netdev->name);
-
-       c2_tx_clean(c2_port);
-}
-
-static int c2_change_mtu(struct net_device *netdev, int new_mtu)
-{
-       int ret = 0;
-
-       if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
-               return -EINVAL;
-
-       netdev->mtu = new_mtu;
-
-       if (netif_running(netdev)) {
-               c2_down(netdev);
-
-               c2_up(netdev);
-       }
-
-       return ret;
-}
-
-static const struct net_device_ops c2_netdev = {
-       .ndo_open               = c2_up,
-       .ndo_stop               = c2_down,
-       .ndo_start_xmit         = c2_xmit_frame,
-       .ndo_tx_timeout         = c2_tx_timeout,
-       .ndo_change_mtu         = c2_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-/* Initialize network device */
-static struct net_device *c2_devinit(struct c2_dev *c2dev,
-                                    void __iomem * mmio_addr)
-{
-       struct c2_port *c2_port = NULL;
-       struct net_device *netdev = alloc_etherdev(sizeof(*c2_port));
-
-       if (!netdev) {
-               pr_debug("c2_port etherdev alloc failed");
-               return NULL;
-       }
-
-       SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
-
-       netdev->netdev_ops = &c2_netdev;
-       netdev->watchdog_timeo = C2_TX_TIMEOUT;
-       netdev->irq = c2dev->pcidev->irq;
-
-       c2_port = netdev_priv(netdev);
-       c2_port->netdev = netdev;
-       c2_port->c2dev = c2dev;
-       c2_port->msg_enable = netif_msg_init(debug, default_msg);
-       c2_port->tx_ring.count = C2_NUM_TX_DESC;
-       c2_port->rx_ring.count = C2_NUM_RX_DESC;
-
-       spin_lock_init(&c2_port->tx_lock);
-
-       /* Copy our 48-bit ethernet hardware address */
-       memcpy_fromio(netdev->dev_addr, mmio_addr + C2_REGS_ENADDR, 6);
-
-       /* Validate the MAC address */
-       if (!is_valid_ether_addr(netdev->dev_addr)) {
-               pr_debug("Invalid MAC Address\n");
-               pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name,
-                        netdev->dev_addr, netdev->irq);
-               free_netdev(netdev);
-               return NULL;
-       }
-
-       c2dev->netdev = netdev;
-
-       return netdev;
-}
-
-static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
-       int ret = 0, i;
-       unsigned long reg0_start, reg0_flags, reg0_len;
-       unsigned long reg2_start, reg2_flags, reg2_len;
-       unsigned long reg4_start, reg4_flags, reg4_len;
-       unsigned kva_map_size;
-       struct net_device *netdev = NULL;
-       struct c2_dev *c2dev = NULL;
-       void __iomem *mmio_regs = NULL;
-
-       printk(KERN_INFO PFX "AMSO1100 Gigabit Ethernet driver v%s loaded\n",
-               DRV_VERSION);
-
-       /* Enable PCI device */
-       ret = pci_enable_device(pcidev);
-       if (ret) {
-               printk(KERN_ERR PFX "%s: Unable to enable PCI device\n",
-                       pci_name(pcidev));
-               goto bail0;
-       }
-
-       reg0_start = pci_resource_start(pcidev, BAR_0);
-       reg0_len = pci_resource_len(pcidev, BAR_0);
-       reg0_flags = pci_resource_flags(pcidev, BAR_0);
-
-       reg2_start = pci_resource_start(pcidev, BAR_2);
-       reg2_len = pci_resource_len(pcidev, BAR_2);
-       reg2_flags = pci_resource_flags(pcidev, BAR_2);
-
-       reg4_start = pci_resource_start(pcidev, BAR_4);
-       reg4_len = pci_resource_len(pcidev, BAR_4);
-       reg4_flags = pci_resource_flags(pcidev, BAR_4);
-
-       pr_debug("BAR0 size = 0x%lX bytes\n", reg0_len);
-       pr_debug("BAR2 size = 0x%lX bytes\n", reg2_len);
-       pr_debug("BAR4 size = 0x%lX bytes\n", reg4_len);
-
-       /* Make sure PCI base addr are MMIO */
-       if (!(reg0_flags & IORESOURCE_MEM) ||
-           !(reg2_flags & IORESOURCE_MEM) || !(reg4_flags & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
-               ret = -ENODEV;
-               goto bail1;
-       }
-
-       /* Check for weird/broken PCI region reporting */
-       if ((reg0_len < C2_REG0_SIZE) ||
-           (reg2_len < C2_REG2_SIZE) || (reg4_len < C2_REG4_SIZE)) {
-               printk(KERN_ERR PFX "Invalid PCI region sizes\n");
-               ret = -ENODEV;
-               goto bail1;
-       }
-
-       /* Reserve PCI I/O and memory resources */
-       ret = pci_request_regions(pcidev, DRV_NAME);
-       if (ret) {
-               printk(KERN_ERR PFX "%s: Unable to request regions\n",
-                       pci_name(pcidev));
-               goto bail1;
-       }
-
-       if ((sizeof(dma_addr_t) > 4)) {
-               ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(64));
-               if (ret < 0) {
-                       printk(KERN_ERR PFX "64b DMA configuration failed\n");
-                       goto bail2;
-               }
-       } else {
-               ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32));
-               if (ret < 0) {
-                       printk(KERN_ERR PFX "32b DMA configuration failed\n");
-                       goto bail2;
-               }
-       }
-
-       /* Enables bus-mastering on the device */
-       pci_set_master(pcidev);
-
-       /* Remap the adapter PCI registers in BAR4 */
-       mmio_regs = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
-                                   sizeof(struct c2_adapter_pci_regs));
-       if (!mmio_regs) {
-               printk(KERN_ERR PFX
-                       "Unable to remap adapter PCI registers in BAR4\n");
-               ret = -EIO;
-               goto bail2;
-       }
-
-       /* Validate PCI regs magic */
-       for (i = 0; i < sizeof(c2_magic); i++) {
-               if (c2_magic[i] != readb(mmio_regs + C2_REGS_MAGIC + i)) {
-                       printk(KERN_ERR PFX "Downlevel Firmware boot loader "
-                               "[%d/%Zd: got 0x%x, exp 0x%x]. Use the cc_flash "
-                              "utility to update your boot loader\n",
-                               i + 1, sizeof(c2_magic),
-                               readb(mmio_regs + C2_REGS_MAGIC + i),
-                               c2_magic[i]);
-                       printk(KERN_ERR PFX "Adapter not claimed\n");
-                       iounmap(mmio_regs);
-                       ret = -EIO;
-                       goto bail2;
-               }
-       }
-
-       /* Validate the adapter version */
-       if (be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_VERS)) != C2_VERSION) {
-               printk(KERN_ERR PFX "Version mismatch "
-                       "[fw=%u, c2=%u], Adapter not claimed\n",
-                       be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_VERS)),
-                       C2_VERSION);
-               ret = -EINVAL;
-               iounmap(mmio_regs);
-               goto bail2;
-       }
-
-       /* Validate the adapter IVN */
-       if (be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_IVN)) != C2_IVN) {
-               printk(KERN_ERR PFX "Downlevel FIrmware level. You should be using "
-                      "the OpenIB device support kit. "
-                      "[fw=0x%x, c2=0x%x], Adapter not claimed\n",
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_IVN)),
-                      C2_IVN);
-               ret = -EINVAL;
-               iounmap(mmio_regs);
-               goto bail2;
-       }
-
-       /* Allocate hardware structure */
-       c2dev = (struct c2_dev *) ib_alloc_device(sizeof(*c2dev));
-       if (!c2dev) {
-               printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n",
-                       pci_name(pcidev));
-               ret = -ENOMEM;
-               iounmap(mmio_regs);
-               goto bail2;
-       }
-
-       memset(c2dev, 0, sizeof(*c2dev));
-       spin_lock_init(&c2dev->lock);
-       c2dev->pcidev = pcidev;
-       c2dev->cur_tx = 0;
-
-       /* Get the last RX index */
-       c2dev->cur_rx =
-           (be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_HRX_CUR)) -
-            0xffffc000) / sizeof(struct c2_rxp_desc);
-
-       /* Request an interrupt line for the driver */
-       ret = request_irq(pcidev->irq, c2_interrupt, IRQF_SHARED, DRV_NAME, c2dev);
-       if (ret) {
-               printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
-                       pci_name(pcidev), pcidev->irq);
-               iounmap(mmio_regs);
-               goto bail3;
-       }
-
-       /* Set driver specific data */
-       pci_set_drvdata(pcidev, c2dev);
-
-       /* Initialize network device */
-       if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) {
-               ret = -ENOMEM;
-               iounmap(mmio_regs);
-               goto bail4;
-       }
-
-       /* Save off the actual size prior to unmapping mmio_regs */
-       kva_map_size = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_PCI_WINSIZE));
-
-       /* Unmap the adapter PCI registers in BAR4 */
-       iounmap(mmio_regs);
-
-       /* Register network device */
-       ret = register_netdev(netdev);
-       if (ret) {
-               printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n",
-                       ret);
-               goto bail5;
-       }
-
-       /* Disable network packets */
-       netif_stop_queue(netdev);
-
-       /* Remap the adapter HRXDQ PA space to kernel VA space */
-       c2dev->mmio_rxp_ring = ioremap_nocache(reg4_start + C2_RXP_HRXDQ_OFFSET,
-                                              C2_RXP_HRXDQ_SIZE);
-       if (!c2dev->mmio_rxp_ring) {
-               printk(KERN_ERR PFX "Unable to remap MMIO HRXDQ region\n");
-               ret = -EIO;
-               goto bail6;
-       }
-
-       /* Remap the adapter HTXDQ PA space to kernel VA space */
-       c2dev->mmio_txp_ring = ioremap_nocache(reg4_start + C2_TXP_HTXDQ_OFFSET,
-                                              C2_TXP_HTXDQ_SIZE);
-       if (!c2dev->mmio_txp_ring) {
-               printk(KERN_ERR PFX "Unable to remap MMIO HTXDQ region\n");
-               ret = -EIO;
-               goto bail7;
-       }
-
-       /* Save off the current RX index in the last 4 bytes of the TXP Ring */
-       C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
-
-       /* Remap the PCI registers in adapter BAR0 to kernel VA space */
-       c2dev->regs = ioremap_nocache(reg0_start, reg0_len);
-       if (!c2dev->regs) {
-               printk(KERN_ERR PFX "Unable to remap BAR0\n");
-               ret = -EIO;
-               goto bail8;
-       }
-
-       /* Remap the PCI registers in adapter BAR4 to kernel VA space */
-       c2dev->pa = reg4_start + C2_PCI_REGS_OFFSET;
-       c2dev->kva = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
-                                    kva_map_size);
-       if (!c2dev->kva) {
-               printk(KERN_ERR PFX "Unable to remap BAR4\n");
-               ret = -EIO;
-               goto bail9;
-       }
-
-       /* Print out the MAC address */
-       pr_debug("%s: MAC %pM, IRQ %u\n", netdev->name, netdev->dev_addr,
-                netdev->irq);
-
-       ret = c2_rnic_init(c2dev);
-       if (ret) {
-               printk(KERN_ERR PFX "c2_rnic_init failed: %d\n", ret);
-               goto bail10;
-       }
-
-       ret = c2_register_device(c2dev);
-       if (ret)
-               goto bail10;
-
-       return 0;
-
- bail10:
-       iounmap(c2dev->kva);
-
- bail9:
-       iounmap(c2dev->regs);
-
- bail8:
-       iounmap(c2dev->mmio_txp_ring);
-
- bail7:
-       iounmap(c2dev->mmio_rxp_ring);
-
- bail6:
-       unregister_netdev(netdev);
-
- bail5:
-       free_netdev(netdev);
-
- bail4:
-       free_irq(pcidev->irq, c2dev);
-
- bail3:
-       ib_dealloc_device(&c2dev->ibdev);
-
- bail2:
-       pci_release_regions(pcidev);
-
- bail1:
-       pci_disable_device(pcidev);
-
- bail0:
-       return ret;
-}
-
-static void c2_remove(struct pci_dev *pcidev)
-{
-       struct c2_dev *c2dev = pci_get_drvdata(pcidev);
-       struct net_device *netdev = c2dev->netdev;
-
-       /* Unregister with OpenIB */
-       c2_unregister_device(c2dev);
-
-       /* Clean up the RNIC resources */
-       c2_rnic_term(c2dev);
-
-       /* Remove network device from the kernel */
-       unregister_netdev(netdev);
-
-       /* Free network device */
-       free_netdev(netdev);
-
-       /* Free the interrupt line */
-       free_irq(pcidev->irq, c2dev);
-
-       /* missing: Turn LEDs off here */
-
-       /* Unmap adapter PA space */
-       iounmap(c2dev->kva);
-       iounmap(c2dev->regs);
-       iounmap(c2dev->mmio_txp_ring);
-       iounmap(c2dev->mmio_rxp_ring);
-
-       /* Free the hardware structure */
-       ib_dealloc_device(&c2dev->ibdev);
-
-       /* Release reserved PCI I/O and memory resources */
-       pci_release_regions(pcidev);
-
-       /* Disable PCI device */
-       pci_disable_device(pcidev);
-
-       /* Clear driver specific data */
-       pci_set_drvdata(pcidev, NULL);
-}
-
-static struct pci_driver c2_pci_driver = {
-       .name = DRV_NAME,
-       .id_table = c2_pci_table,
-       .probe = c2_probe,
-       .remove = c2_remove,
-};
-
-module_pci_driver(c2_pci_driver);
diff --git a/drivers/staging/rdma/amso1100/c2.h b/drivers/staging/rdma/amso1100/c2.h
deleted file mode 100644 (file)
index 21b565a..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef __C2_H
-#define __C2_H
-
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/idr.h>
-
-#include "c2_provider.h"
-#include "c2_mq.h"
-#include "c2_status.h"
-
-#define DRV_NAME     "c2"
-#define DRV_VERSION  "1.1"
-#define PFX          DRV_NAME ": "
-
-#define BAR_0                0
-#define BAR_2                2
-#define BAR_4                4
-
-#define RX_BUF_SIZE         (1536 + 8)
-#define ETH_JUMBO_MTU        9000
-#define C2_MAGIC            "CEPHEUS"
-#define C2_VERSION           4
-#define C2_IVN              (18 & 0x7fffffff)
-
-#define C2_REG0_SIZE        (16 * 1024)
-#define C2_REG2_SIZE        (2 * 1024 * 1024)
-#define C2_REG4_SIZE        (256 * 1024 * 1024)
-#define C2_NUM_TX_DESC       341
-#define C2_NUM_RX_DESC       256
-#define C2_PCI_REGS_OFFSET  (0x10000)
-#define C2_RXP_HRXDQ_OFFSET (((C2_REG4_SIZE)/2))
-#define C2_RXP_HRXDQ_SIZE   (4096)
-#define C2_TXP_HTXDQ_OFFSET (((C2_REG4_SIZE)/2) + C2_RXP_HRXDQ_SIZE)
-#define C2_TXP_HTXDQ_SIZE   (4096)
-#define C2_TX_TIMEOUT      (6*HZ)
-
-/* CEPHEUS */
-static const u8 c2_magic[] = {
-       0x43, 0x45, 0x50, 0x48, 0x45, 0x55, 0x53
-};
-
-enum adapter_pci_regs {
-       C2_REGS_MAGIC = 0x0000,
-       C2_REGS_VERS = 0x0008,
-       C2_REGS_IVN = 0x000C,
-       C2_REGS_PCI_WINSIZE = 0x0010,
-       C2_REGS_Q0_QSIZE = 0x0014,
-       C2_REGS_Q0_MSGSIZE = 0x0018,
-       C2_REGS_Q0_POOLSTART = 0x001C,
-       C2_REGS_Q0_SHARED = 0x0020,
-       C2_REGS_Q1_QSIZE = 0x0024,
-       C2_REGS_Q1_MSGSIZE = 0x0028,
-       C2_REGS_Q1_SHARED = 0x0030,
-       C2_REGS_Q2_QSIZE = 0x0034,
-       C2_REGS_Q2_MSGSIZE = 0x0038,
-       C2_REGS_Q2_SHARED = 0x0040,
-       C2_REGS_ENADDR = 0x004C,
-       C2_REGS_RDMA_ENADDR = 0x0054,
-       C2_REGS_HRX_CUR = 0x006C,
-};
-
-struct c2_adapter_pci_regs {
-       char reg_magic[8];
-       u32 version;
-       u32 ivn;
-       u32 pci_window_size;
-       u32 q0_q_size;
-       u32 q0_msg_size;
-       u32 q0_pool_start;
-       u32 q0_shared;
-       u32 q1_q_size;
-       u32 q1_msg_size;
-       u32 q1_pool_start;
-       u32 q1_shared;
-       u32 q2_q_size;
-       u32 q2_msg_size;
-       u32 q2_pool_start;
-       u32 q2_shared;
-       u32 log_start;
-       u32 log_size;
-       u8 host_enaddr[8];
-       u8 rdma_enaddr[8];
-       u32 crash_entry;
-       u32 crash_ready[2];
-       u32 fw_txd_cur;
-       u32 fw_hrxd_cur;
-       u32 fw_rxd_cur;
-};
-
-enum pci_regs {
-       C2_HISR = 0x0000,
-       C2_DISR = 0x0004,
-       C2_HIMR = 0x0008,
-       C2_DIMR = 0x000C,
-       C2_NISR0 = 0x0010,
-       C2_NISR1 = 0x0014,
-       C2_NIMR0 = 0x0018,
-       C2_NIMR1 = 0x001C,
-       C2_IDIS = 0x0020,
-};
-
-enum {
-       C2_PCI_HRX_INT = 1 << 8,
-       C2_PCI_HTX_INT = 1 << 17,
-       C2_PCI_HRX_QUI = 1 << 31,
-};
-
-/*
- * Cepheus registers in BAR0.
- */
-struct c2_pci_regs {
-       u32 hostisr;
-       u32 dmaisr;
-       u32 hostimr;
-       u32 dmaimr;
-       u32 netisr0;
-       u32 netisr1;
-       u32 netimr0;
-       u32 netimr1;
-       u32 int_disable;
-};
-
-/* TXP flags */
-enum c2_txp_flags {
-       TXP_HTXD_DONE = 0,
-       TXP_HTXD_READY = 1 << 0,
-       TXP_HTXD_UNINIT = 1 << 1,
-};
-
-/* RXP flags */
-enum c2_rxp_flags {
-       RXP_HRXD_UNINIT = 0,
-       RXP_HRXD_READY = 1 << 0,
-       RXP_HRXD_DONE = 1 << 1,
-};
-
-/* RXP status */
-enum c2_rxp_status {
-       RXP_HRXD_ZERO = 0,
-       RXP_HRXD_OK = 1 << 0,
-       RXP_HRXD_BUF_OV = 1 << 1,
-};
-
-/* TXP descriptor fields */
-enum txp_desc {
-       C2_TXP_FLAGS = 0x0000,
-       C2_TXP_LEN = 0x0002,
-       C2_TXP_ADDR = 0x0004,
-};
-
-/* RXP descriptor fields */
-enum rxp_desc {
-       C2_RXP_FLAGS = 0x0000,
-       C2_RXP_STATUS = 0x0002,
-       C2_RXP_COUNT = 0x0004,
-       C2_RXP_LEN = 0x0006,
-       C2_RXP_ADDR = 0x0008,
-};
-
-struct c2_txp_desc {
-       u16 flags;
-       u16 len;
-       u64 addr;
-} __attribute__ ((packed));
-
-struct c2_rxp_desc {
-       u16 flags;
-       u16 status;
-       u16 count;
-       u16 len;
-       u64 addr;
-} __attribute__ ((packed));
-
-struct c2_rxp_hdr {
-       u16 flags;
-       u16 status;
-       u16 len;
-       u16 rsvd;
-} __attribute__ ((packed));
-
-struct c2_tx_desc {
-       u32 len;
-       u32 status;
-       dma_addr_t next_offset;
-};
-
-struct c2_rx_desc {
-       u32 len;
-       u32 status;
-       dma_addr_t next_offset;
-};
-
-struct c2_alloc {
-       u32 last;
-       u32 max;
-       spinlock_t lock;
-       unsigned long *table;
-};
-
-struct c2_array {
-       struct {
-               void **page;
-               int used;
-       } *page_list;
-};
-
-/*
- * The MQ shared pointer pool is organized as a linked list of
- * chunks. Each chunk contains a linked list of free shared pointers
- * that can be allocated to a given user mode client.
- *
- */
-struct sp_chunk {
-       struct sp_chunk *next;
-       dma_addr_t dma_addr;
-       DEFINE_DMA_UNMAP_ADDR(mapping);
-       u16 head;
-       u16 shared_ptr[0];
-};
-
-struct c2_pd_table {
-       u32 last;
-       u32 max;
-       spinlock_t lock;
-       unsigned long *table;
-};
-
-struct c2_qp_table {
-       struct idr idr;
-       spinlock_t lock;
-};
-
-struct c2_element {
-       struct c2_element *next;
-       void *ht_desc;          /* host     descriptor */
-       void __iomem *hw_desc;  /* hardware descriptor */
-       struct sk_buff *skb;
-       dma_addr_t mapaddr;
-       u32 maplen;
-};
-
-struct c2_ring {
-       struct c2_element *to_clean;
-       struct c2_element *to_use;
-       struct c2_element *start;
-       unsigned long count;
-};
-
-struct c2_dev {
-       struct ib_device ibdev;
-       void __iomem *regs;
-       void __iomem *mmio_txp_ring; /* remapped adapter memory for hw rings */
-       void __iomem *mmio_rxp_ring;
-       spinlock_t lock;
-       struct pci_dev *pcidev;
-       struct net_device *netdev;
-       struct net_device *pseudo_netdev;
-       unsigned int cur_tx;
-       unsigned int cur_rx;
-       u32 adapter_handle;
-       int device_cap_flags;
-       void __iomem *kva;      /* KVA device memory */
-       unsigned long pa;       /* PA device memory */
-       void **qptr_array;
-
-       struct kmem_cache *host_msg_cache;
-
-       struct list_head cca_link;              /* adapter list */
-       struct list_head eh_wakeup_list;        /* event wakeup list */
-       wait_queue_head_t req_vq_wo;
-
-       /* Cached RNIC properties */
-       struct ib_device_attr props;
-
-       struct c2_pd_table pd_table;
-       struct c2_qp_table qp_table;
-       int ports;              /* num of GigE ports */
-       int devnum;
-       spinlock_t vqlock;      /* sync vbs req MQ */
-
-       /* Verbs Queues */
-       struct c2_mq req_vq;    /* Verbs Request MQ */
-       struct c2_mq rep_vq;    /* Verbs Reply MQ */
-       struct c2_mq aeq;       /* Async Events MQ */
-
-       /* Kernel client MQs */
-       struct sp_chunk *kern_mqsp_pool;
-
-       /* Device updates these values when posting messages to a host
-        * target queue */
-       u16 req_vq_shared;
-       u16 rep_vq_shared;
-       u16 aeq_shared;
-       u16 irq_claimed;
-
-       /*
-        * Shared host target pages for user-accessible MQs.
-        */
-       int hthead;             /* index of first free entry */
-       void *htpages;          /* kernel vaddr */
-       int htlen;              /* length of htpages memory */
-       void *htuva;            /* user mapped vaddr */
-       spinlock_t htlock;      /* serialize allocation */
-
-       u64 adapter_hint_uva;   /* access to the activity FIFO */
-
-       //      spinlock_t aeq_lock;
-       //      spinlock_t rnic_lock;
-
-       __be16 *hint_count;
-       dma_addr_t hint_count_dma;
-       u16 hints_read;
-
-       int init;               /* TRUE if it's ready */
-       char ae_cache_name[16];
-       char vq_cache_name[16];
-};
-
-struct c2_port {
-       u32 msg_enable;
-       struct c2_dev *c2dev;
-       struct net_device *netdev;
-
-       spinlock_t tx_lock;
-       u32 tx_avail;
-       struct c2_ring tx_ring;
-       struct c2_ring rx_ring;
-
-       void *mem;              /* PCI memory for host rings */
-       dma_addr_t dma;
-       unsigned long mem_size;
-
-       u32 rx_buf_size;
-};
-
-/*
- * Activity FIFO registers in BAR0.
- */
-#define PCI_BAR0_HOST_HINT     0x100
-#define PCI_BAR0_ADAPTER_HINT  0x2000
-
-/*
- * Ammasso PCI vendor id and Cepheus PCI device id.
- */
-#define CQ_ARMED       0x01
-#define CQ_WAIT_FOR_DMA        0x80
-
-/*
- * The format of a hint is as follows:
- * Lower 16 bits are the count of hints for the queue.
- * Next 15 bits are the qp_index
- * Upper most bit depends on who reads it:
- *    If read by producer, then it means Full (1) or Not-Full (0)
- *    If read by consumer, then it means Empty (1) or Not-Empty (0)
- */
-#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
-#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
-#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
-
-
-/*
- * The following defines the offset in SDRAM for the c2_adapter_pci_regs_t
- * struct.
- */
-#define C2_ADAPTER_PCI_REGS_OFFSET 0x10000
-
-#ifndef readq
-static inline u64 readq(const void __iomem * addr)
-{
-       u64 ret = readl(addr + 4);
-       ret <<= 32;
-       ret |= readl(addr);
-
-       return ret;
-}
-#endif
-
-#ifndef writeq
-static inline void __raw_writeq(u64 val, void __iomem * addr)
-{
-       __raw_writel((u32) (val), addr);
-       __raw_writel((u32) (val >> 32), (addr + 4));
-}
-#endif
-
-#define C2_SET_CUR_RX(c2dev, cur_rx) \
-       __raw_writel((__force u32) cpu_to_be32(cur_rx), c2dev->mmio_txp_ring + 4092)
-
-#define C2_GET_CUR_RX(c2dev) \
-       be32_to_cpu((__force __be32) readl(c2dev->mmio_txp_ring + 4092))
-
-static inline struct c2_dev *to_c2dev(struct ib_device *ibdev)
-{
-       return container_of(ibdev, struct c2_dev, ibdev);
-}
-
-static inline int c2_errno(void *reply)
-{
-       switch (c2_wr_get_result(reply)) {
-       case C2_OK:
-               return 0;
-       case CCERR_NO_BUFS:
-       case CCERR_INSUFFICIENT_RESOURCES:
-       case CCERR_ZERO_RDMA_READ_RESOURCES:
-               return -ENOMEM;
-       case CCERR_MR_IN_USE:
-       case CCERR_QP_IN_USE:
-               return -EBUSY;
-       case CCERR_ADDR_IN_USE:
-               return -EADDRINUSE;
-       case CCERR_ADDR_NOT_AVAIL:
-               return -EADDRNOTAVAIL;
-       case CCERR_CONN_RESET:
-               return -ECONNRESET;
-       case CCERR_NOT_IMPLEMENTED:
-       case CCERR_INVALID_WQE:
-               return -ENOSYS;
-       case CCERR_QP_NOT_PRIVILEGED:
-               return -EPERM;
-       case CCERR_STACK_ERROR:
-               return -EPROTO;
-       case CCERR_ACCESS_VIOLATION:
-       case CCERR_BASE_AND_BOUNDS_VIOLATION:
-               return -EFAULT;
-       case CCERR_STAG_STATE_NOT_INVALID:
-       case CCERR_INVALID_ADDRESS:
-       case CCERR_INVALID_CQ:
-       case CCERR_INVALID_EP:
-       case CCERR_INVALID_MODIFIER:
-       case CCERR_INVALID_MTU:
-       case CCERR_INVALID_PD_ID:
-       case CCERR_INVALID_QP:
-       case CCERR_INVALID_RNIC:
-       case CCERR_INVALID_STAG:
-               return -EINVAL;
-       default:
-               return -EAGAIN;
-       }
-}
-
-/* Device */
-int c2_register_device(struct c2_dev *c2dev);
-void c2_unregister_device(struct c2_dev *c2dev);
-int c2_rnic_init(struct c2_dev *c2dev);
-void c2_rnic_term(struct c2_dev *c2dev);
-void c2_rnic_interrupt(struct c2_dev *c2dev);
-int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
-int c2_add_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask);
-
-/* QPs */
-int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd,
-                      struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp);
-void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp);
-struct ib_qp *c2_get_qp(struct ib_device *device, int qpn);
-int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
-                       struct ib_qp_attr *attr, int attr_mask);
-int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
-                                int ord, int ird);
-int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
-                       struct ib_send_wr **bad_wr);
-int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
-                          struct ib_recv_wr **bad_wr);
-void c2_init_qp_table(struct c2_dev *c2dev);
-void c2_cleanup_qp_table(struct c2_dev *c2dev);
-void c2_set_qp_state(struct c2_qp *, int);
-struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
-
-/* PDs */
-int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
-void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
-int c2_init_pd_table(struct c2_dev *c2dev);
-void c2_cleanup_pd_table(struct c2_dev *c2dev);
-
-/* CQs */
-int c2_init_cq(struct c2_dev *c2dev, int entries,
-                     struct c2_ucontext *ctx, struct c2_cq *cq);
-void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
-void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
-void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
-int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
-
-/* CM */
-int c2_llp_connect(struct iw_cm_id *cm_id,
-                         struct iw_cm_conn_param *iw_param);
-int c2_llp_accept(struct iw_cm_id *cm_id,
-                        struct iw_cm_conn_param *iw_param);
-int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata,
-                        u8 pdata_len);
-int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog);
-int c2_llp_service_destroy(struct iw_cm_id *cm_id);
-
-/* MM */
-int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
-                                     int page_size, int pbl_depth, u32 length,
-                                     u32 off, u64 *va, enum c2_acf acf,
-                                     struct c2_mr *mr);
-int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index);
-
-/* AE */
-void c2_ae_event(struct c2_dev *c2dev, u32 mq_index);
-
-/* MQSP Allocator */
-int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
-                            struct sp_chunk **root);
-void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root);
-__be16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
-                            dma_addr_t *dma_addr, gfp_t gfp_mask);
-void c2_free_mqsp(__be16* mqsp);
-#endif
diff --git a/drivers/staging/rdma/amso1100/c2_ae.c b/drivers/staging/rdma/amso1100/c2_ae.c
deleted file mode 100644 (file)
index eb7a92b..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "c2.h"
-#include <rdma/iw_cm.h>
-#include "c2_status.h"
-#include "c2_ae.h"
-
-static int c2_convert_cm_status(u32 c2_status)
-{
-       switch (c2_status) {
-       case C2_CONN_STATUS_SUCCESS:
-               return 0;
-       case C2_CONN_STATUS_REJECTED:
-               return -ENETRESET;
-       case C2_CONN_STATUS_REFUSED:
-               return -ECONNREFUSED;
-       case C2_CONN_STATUS_TIMEDOUT:
-               return -ETIMEDOUT;
-       case C2_CONN_STATUS_NETUNREACH:
-               return -ENETUNREACH;
-       case C2_CONN_STATUS_HOSTUNREACH:
-               return -EHOSTUNREACH;
-       case C2_CONN_STATUS_INVALID_RNIC:
-               return -EINVAL;
-       case C2_CONN_STATUS_INVALID_QP:
-               return -EINVAL;
-       case C2_CONN_STATUS_INVALID_QP_STATE:
-               return -EINVAL;
-       case C2_CONN_STATUS_ADDR_NOT_AVAIL:
-               return -EADDRNOTAVAIL;
-       default:
-               printk(KERN_ERR PFX
-                      "%s - Unable to convert CM status: %d\n",
-                      __func__, c2_status);
-               return -EIO;
-       }
-}
-
-static const char* to_event_str(int event)
-{
-       static const char* event_str[] = {
-               "CCAE_REMOTE_SHUTDOWN",
-               "CCAE_ACTIVE_CONNECT_RESULTS",
-               "CCAE_CONNECTION_REQUEST",
-               "CCAE_LLP_CLOSE_COMPLETE",
-               "CCAE_TERMINATE_MESSAGE_RECEIVED",
-               "CCAE_LLP_CONNECTION_RESET",
-               "CCAE_LLP_CONNECTION_LOST",
-               "CCAE_LLP_SEGMENT_SIZE_INVALID",
-               "CCAE_LLP_INVALID_CRC",
-               "CCAE_LLP_BAD_FPDU",
-               "CCAE_INVALID_DDP_VERSION",
-               "CCAE_INVALID_RDMA_VERSION",
-               "CCAE_UNEXPECTED_OPCODE",
-               "CCAE_INVALID_DDP_QUEUE_NUMBER",
-               "CCAE_RDMA_READ_NOT_ENABLED",
-               "CCAE_RDMA_WRITE_NOT_ENABLED",
-               "CCAE_RDMA_READ_TOO_SMALL",
-               "CCAE_NO_L_BIT",
-               "CCAE_TAGGED_INVALID_STAG",
-               "CCAE_TAGGED_BASE_BOUNDS_VIOLATION",
-               "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION",
-               "CCAE_TAGGED_INVALID_PD",
-               "CCAE_WRAP_ERROR",
-               "CCAE_BAD_CLOSE",
-               "CCAE_BAD_LLP_CLOSE",
-               "CCAE_INVALID_MSN_RANGE",
-               "CCAE_INVALID_MSN_GAP",
-               "CCAE_IRRQ_OVERFLOW",
-               "CCAE_IRRQ_MSN_GAP",
-               "CCAE_IRRQ_MSN_RANGE",
-               "CCAE_IRRQ_INVALID_STAG",
-               "CCAE_IRRQ_BASE_BOUNDS_VIOLATION",
-               "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION",
-               "CCAE_IRRQ_INVALID_PD",
-               "CCAE_IRRQ_WRAP_ERROR",
-               "CCAE_CQ_SQ_COMPLETION_OVERFLOW",
-               "CCAE_CQ_RQ_COMPLETION_ERROR",
-               "CCAE_QP_SRQ_WQE_ERROR",
-               "CCAE_QP_LOCAL_CATASTROPHIC_ERROR",
-               "CCAE_CQ_OVERFLOW",
-               "CCAE_CQ_OPERATION_ERROR",
-               "CCAE_SRQ_LIMIT_REACHED",
-               "CCAE_QP_RQ_LIMIT_REACHED",
-               "CCAE_SRQ_CATASTROPHIC_ERROR",
-               "CCAE_RNIC_CATASTROPHIC_ERROR"
-       };
-
-       if (event < CCAE_REMOTE_SHUTDOWN ||
-           event > CCAE_RNIC_CATASTROPHIC_ERROR)
-               return "<invalid event>";
-
-       event -= CCAE_REMOTE_SHUTDOWN;
-       return event_str[event];
-}
-
-static const char *to_qp_state_str(int state)
-{
-       switch (state) {
-       case C2_QP_STATE_IDLE:
-               return "C2_QP_STATE_IDLE";
-       case C2_QP_STATE_CONNECTING:
-               return "C2_QP_STATE_CONNECTING";
-       case C2_QP_STATE_RTS:
-               return "C2_QP_STATE_RTS";
-       case C2_QP_STATE_CLOSING:
-               return "C2_QP_STATE_CLOSING";
-       case C2_QP_STATE_TERMINATE:
-               return "C2_QP_STATE_TERMINATE";
-       case C2_QP_STATE_ERROR:
-               return "C2_QP_STATE_ERROR";
-       default:
-               return "<invalid QP state>";
-       }
-}
-
-void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
-{
-       struct c2_mq *mq = c2dev->qptr_array[mq_index];
-       union c2wr *wr;
-       void *resource_user_context;
-       struct iw_cm_event cm_event;
-       struct ib_event ib_event;
-       enum c2_resource_indicator resource_indicator;
-       enum c2_event_id event_id;
-       unsigned long flags;
-       int status;
-       struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_event.local_addr;
-       struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_event.remote_addr;
-
-       /*
-        * retrieve the message
-        */
-       wr = c2_mq_consume(mq);
-       if (!wr)
-               return;
-
-       memset(&ib_event, 0, sizeof(ib_event));
-       memset(&cm_event, 0, sizeof(cm_event));
-
-       event_id = c2_wr_get_id(wr);
-       resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type);
-       resource_user_context =
-           (void *) (unsigned long) wr->ae.ae_generic.user_context;
-
-       status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr));
-
-       pr_debug("event received c2_dev=%p, event_id=%d, "
-               "resource_indicator=%d, user_context=%p, status = %d\n",
-               c2dev, event_id, resource_indicator, resource_user_context,
-               status);
-
-       switch (resource_indicator) {
-       case C2_RES_IND_QP:{
-
-               struct c2_qp *qp = resource_user_context;
-               struct iw_cm_id *cm_id = qp->cm_id;
-               struct c2wr_ae_active_connect_results *res;
-
-               if (!cm_id) {
-                       pr_debug("event received, but cm_id is <nul>, qp=%p!\n",
-                               qp);
-                       goto ignore_it;
-               }
-               pr_debug("%s: event = %s, user_context=%llx, "
-                       "resource_type=%x, "
-                       "resource=%x, qp_state=%s\n",
-                       __func__,
-                       to_event_str(event_id),
-                       (unsigned long long) wr->ae.ae_generic.user_context,
-                       be32_to_cpu(wr->ae.ae_generic.resource_type),
-                       be32_to_cpu(wr->ae.ae_generic.resource),
-                       to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state)));
-
-               c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state));
-
-               switch (event_id) {
-               case CCAE_ACTIVE_CONNECT_RESULTS:
-                       res = &wr->ae.ae_active_connect_results;
-                       cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
-                       laddr->sin_addr.s_addr = res->laddr;
-                       raddr->sin_addr.s_addr = res->raddr;
-                       laddr->sin_port = res->lport;
-                       raddr->sin_port = res->rport;
-                       if (status == 0) {
-                               cm_event.private_data_len =
-                                       be32_to_cpu(res->private_data_length);
-                               cm_event.private_data = res->private_data;
-                       } else {
-                               spin_lock_irqsave(&qp->lock, flags);
-                               if (qp->cm_id) {
-                                       qp->cm_id->rem_ref(qp->cm_id);
-                                       qp->cm_id = NULL;
-                               }
-                               spin_unlock_irqrestore(&qp->lock, flags);
-                               cm_event.private_data_len = 0;
-                               cm_event.private_data = NULL;
-                       }
-                       if (cm_id->event_handler)
-                               cm_id->event_handler(cm_id, &cm_event);
-                       break;
-               case CCAE_TERMINATE_MESSAGE_RECEIVED:
-               case CCAE_CQ_SQ_COMPLETION_OVERFLOW:
-                       ib_event.device = &c2dev->ibdev;
-                       ib_event.element.qp = &qp->ibqp;
-                       ib_event.event = IB_EVENT_QP_REQ_ERR;
-
-                       if (qp->ibqp.event_handler)
-                               qp->ibqp.event_handler(&ib_event,
-                                                      qp->ibqp.
-                                                      qp_context);
-                       break;
-               case CCAE_BAD_CLOSE:
-               case CCAE_LLP_CLOSE_COMPLETE:
-               case CCAE_LLP_CONNECTION_RESET:
-               case CCAE_LLP_CONNECTION_LOST:
-                       BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b);
-
-                       spin_lock_irqsave(&qp->lock, flags);
-                       if (qp->cm_id) {
-                               qp->cm_id->rem_ref(qp->cm_id);
-                               qp->cm_id = NULL;
-                       }
-                       spin_unlock_irqrestore(&qp->lock, flags);
-                       cm_event.event = IW_CM_EVENT_CLOSE;
-                       cm_event.status = 0;
-                       if (cm_id->event_handler)
-                               cm_id->event_handler(cm_id, &cm_event);
-                       break;
-               default:
-                       BUG_ON(1);
-                       pr_debug("%s:%d Unexpected event_id=%d on QP=%p, "
-                               "CM_ID=%p\n",
-                               __func__, __LINE__,
-                               event_id, qp, cm_id);
-                       break;
-               }
-               break;
-       }
-
-       case C2_RES_IND_EP:{
-
-               struct c2wr_ae_connection_request *req =
-                       &wr->ae.ae_connection_request;
-               struct iw_cm_id *cm_id =
-                       resource_user_context;
-
-               pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
-               if (event_id != CCAE_CONNECTION_REQUEST) {
-                       pr_debug("%s: Invalid event_id: %d\n",
-                               __func__, event_id);
-                       break;
-               }
-               cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
-               cm_event.provider_data = (void*)(unsigned long)req->cr_handle;
-               laddr->sin_addr.s_addr = req->laddr;
-               raddr->sin_addr.s_addr = req->raddr;
-               laddr->sin_port = req->lport;
-               raddr->sin_port = req->rport;
-               cm_event.private_data_len =
-                       be32_to_cpu(req->private_data_length);
-               cm_event.private_data = req->private_data;
-               /*
-                * Until ird/ord negotiation via MPAv2 support is added, send
-                * max supported values
-                */
-               cm_event.ird = cm_event.ord = 128;
-
-               if (cm_id->event_handler)
-                       cm_id->event_handler(cm_id, &cm_event);
-               break;
-       }
-
-       case C2_RES_IND_CQ:{
-               struct c2_cq *cq =
-                   resource_user_context;
-
-               pr_debug("IB_EVENT_CQ_ERR\n");
-               ib_event.device = &c2dev->ibdev;
-               ib_event.element.cq = &cq->ibcq;
-               ib_event.event = IB_EVENT_CQ_ERR;
-
-               if (cq->ibcq.event_handler)
-                       cq->ibcq.event_handler(&ib_event,
-                                              cq->ibcq.cq_context);
-               break;
-       }
-
-       default:
-               printk("Bad resource indicator = %d\n",
-                      resource_indicator);
-               break;
-       }
-
- ignore_it:
-       c2_mq_free(mq);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_ae.h b/drivers/staging/rdma/amso1100/c2_ae.h
deleted file mode 100644 (file)
index 3a065c3..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _C2_AE_H_
-#define _C2_AE_H_
-
-/*
- * WARNING: If you change this file, also bump C2_IVN_BASE
- * in common/include/clustercore/c2_ivn.h.
- */
-
-/*
- * Asynchronous Event Identifiers
- *
- * These start at 0x80 only so it's obvious from inspection that
- * they are not work-request statuses.  This isn't critical.
- *
- * NOTE: these event id's must fit in eight bits.
- */
-enum c2_event_id {
-       CCAE_REMOTE_SHUTDOWN = 0x80,
-       CCAE_ACTIVE_CONNECT_RESULTS,
-       CCAE_CONNECTION_REQUEST,
-       CCAE_LLP_CLOSE_COMPLETE,
-       CCAE_TERMINATE_MESSAGE_RECEIVED,
-       CCAE_LLP_CONNECTION_RESET,
-       CCAE_LLP_CONNECTION_LOST,
-       CCAE_LLP_SEGMENT_SIZE_INVALID,
-       CCAE_LLP_INVALID_CRC,
-       CCAE_LLP_BAD_FPDU,
-       CCAE_INVALID_DDP_VERSION,
-       CCAE_INVALID_RDMA_VERSION,
-       CCAE_UNEXPECTED_OPCODE,
-       CCAE_INVALID_DDP_QUEUE_NUMBER,
-       CCAE_RDMA_READ_NOT_ENABLED,
-       CCAE_RDMA_WRITE_NOT_ENABLED,
-       CCAE_RDMA_READ_TOO_SMALL,
-       CCAE_NO_L_BIT,
-       CCAE_TAGGED_INVALID_STAG,
-       CCAE_TAGGED_BASE_BOUNDS_VIOLATION,
-       CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION,
-       CCAE_TAGGED_INVALID_PD,
-       CCAE_WRAP_ERROR,
-       CCAE_BAD_CLOSE,
-       CCAE_BAD_LLP_CLOSE,
-       CCAE_INVALID_MSN_RANGE,
-       CCAE_INVALID_MSN_GAP,
-       CCAE_IRRQ_OVERFLOW,
-       CCAE_IRRQ_MSN_GAP,
-       CCAE_IRRQ_MSN_RANGE,
-       CCAE_IRRQ_INVALID_STAG,
-       CCAE_IRRQ_BASE_BOUNDS_VIOLATION,
-       CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION,
-       CCAE_IRRQ_INVALID_PD,
-       CCAE_IRRQ_WRAP_ERROR,
-       CCAE_CQ_SQ_COMPLETION_OVERFLOW,
-       CCAE_CQ_RQ_COMPLETION_ERROR,
-       CCAE_QP_SRQ_WQE_ERROR,
-       CCAE_QP_LOCAL_CATASTROPHIC_ERROR,
-       CCAE_CQ_OVERFLOW,
-       CCAE_CQ_OPERATION_ERROR,
-       CCAE_SRQ_LIMIT_REACHED,
-       CCAE_QP_RQ_LIMIT_REACHED,
-       CCAE_SRQ_CATASTROPHIC_ERROR,
-       CCAE_RNIC_CATASTROPHIC_ERROR
-/* WARNING If you add more id's, make sure their values fit in eight bits. */
-};
-
-/*
- * Resource Indicators and Identifiers
- */
-enum c2_resource_indicator {
-       C2_RES_IND_QP = 1,
-       C2_RES_IND_EP,
-       C2_RES_IND_CQ,
-       C2_RES_IND_SRQ,
-};
-
-#endif /* _C2_AE_H_ */
diff --git a/drivers/staging/rdma/amso1100/c2_alloc.c b/drivers/staging/rdma/amso1100/c2_alloc.c
deleted file mode 100644 (file)
index 039872d..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/errno.h>
-#include <linux/bitmap.h>
-
-#include "c2.h"
-
-static int c2_alloc_mqsp_chunk(struct c2_dev *c2dev, gfp_t gfp_mask,
-                              struct sp_chunk **head)
-{
-       int i;
-       struct sp_chunk *new_head;
-       dma_addr_t dma_addr;
-
-       new_head = dma_alloc_coherent(&c2dev->pcidev->dev, PAGE_SIZE,
-                                     &dma_addr, gfp_mask);
-       if (new_head == NULL)
-               return -ENOMEM;
-
-       new_head->dma_addr = dma_addr;
-       dma_unmap_addr_set(new_head, mapping, new_head->dma_addr);
-
-       new_head->next = NULL;
-       new_head->head = 0;
-
-       /* build list where each index is the next free slot */
-       for (i = 0;
-            i < (PAGE_SIZE - sizeof(struct sp_chunk) -
-                 sizeof(u16)) / sizeof(u16) - 1;
-            i++) {
-               new_head->shared_ptr[i] = i + 1;
-       }
-       /* terminate list */
-       new_head->shared_ptr[i] = 0xFFFF;
-
-       *head = new_head;
-       return 0;
-}
-
-int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
-                     struct sp_chunk **root)
-{
-       return c2_alloc_mqsp_chunk(c2dev, gfp_mask, root);
-}
-
-void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root)
-{
-       struct sp_chunk *next;
-
-       while (root) {
-               next = root->next;
-               dma_free_coherent(&c2dev->pcidev->dev, PAGE_SIZE, root,
-                                 dma_unmap_addr(root, mapping));
-               root = next;
-       }
-}
-
-__be16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
-                     dma_addr_t *dma_addr, gfp_t gfp_mask)
-{
-       u16 mqsp;
-
-       while (head) {
-               mqsp = head->head;
-               if (mqsp != 0xFFFF) {
-                       head->head = head->shared_ptr[mqsp];
-                       break;
-               } else if (head->next == NULL) {
-                       if (c2_alloc_mqsp_chunk(c2dev, gfp_mask, &head->next) ==
-                           0) {
-                               head = head->next;
-                               mqsp = head->head;
-                               head->head = head->shared_ptr[mqsp];
-                               break;
-                       } else
-                               return NULL;
-               } else
-                       head = head->next;
-       }
-       if (head) {
-               *dma_addr = head->dma_addr +
-                           ((unsigned long) &(head->shared_ptr[mqsp]) -
-                            (unsigned long) head);
-               pr_debug("%s addr %p dma_addr %llx\n", __func__,
-                        &(head->shared_ptr[mqsp]), (unsigned long long) *dma_addr);
-               return (__force __be16 *) &(head->shared_ptr[mqsp]);
-       }
-       return NULL;
-}
-
-void c2_free_mqsp(__be16 *mqsp)
-{
-       struct sp_chunk *head;
-       u16 idx;
-
-       /* The chunk containing this ptr begins at the page boundary */
-       head = (struct sp_chunk *) ((unsigned long) mqsp & PAGE_MASK);
-
-       /* Link head to new mqsp */
-       *mqsp = (__force __be16) head->head;
-
-       /* Compute the shared_ptr index */
-       idx = (offset_in_page(mqsp)) >> 1;
-       idx -= (unsigned long) &(((struct sp_chunk *) 0)->shared_ptr[0]) >> 1;
-
-       /* Point this index at the head */
-       head->shared_ptr[idx] = head->head;
-
-       /* Point head at this index */
-       head->head = idx;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_cm.c b/drivers/staging/rdma/amso1100/c2_cm.c
deleted file mode 100644 (file)
index f8dbdb9..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc.  All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/slab.h>
-
-#include "c2.h"
-#include "c2_wr.h"
-#include "c2_vq.h"
-#include <rdma/iw_cm.h>
-
-int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
-{
-       struct c2_dev *c2dev = to_c2dev(cm_id->device);
-       struct ib_qp *ibqp;
-       struct c2_qp *qp;
-       struct c2wr_qp_connect_req *wr; /* variable size needs a malloc. */
-       struct c2_vq_req *vq_req;
-       int err;
-       struct sockaddr_in *raddr = (struct sockaddr_in *)&cm_id->remote_addr;
-
-       if (cm_id->remote_addr.ss_family != AF_INET)
-               return -ENOSYS;
-
-       ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
-       if (!ibqp)
-               return -EINVAL;
-       qp = to_c2qp(ibqp);
-
-       /* Associate QP <--> CM_ID */
-       cm_id->provider_data = qp;
-       cm_id->add_ref(cm_id);
-       qp->cm_id = cm_id;
-
-       /*
-        * only support the max private_data length
-        */
-       if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
-               err = -EINVAL;
-               goto bail0;
-       }
-       /*
-        * Set the rdma read limits
-        */
-       err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
-       if (err)
-               goto bail0;
-
-       /*
-        * Create and send a WR_QP_CONNECT...
-        */
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       c2_wr_set_id(wr, CCWR_QP_CONNECT);
-       wr->hdr.context = 0;
-       wr->rnic_handle = c2dev->adapter_handle;
-       wr->qp_handle = qp->adapter_handle;
-
-       wr->remote_addr = raddr->sin_addr.s_addr;
-       wr->remote_port = raddr->sin_port;
-
-       /*
-        * Move any private data from the callers's buf into
-        * the WR.
-        */
-       if (iw_param->private_data) {
-               wr->private_data_length =
-                       cpu_to_be32(iw_param->private_data_len);
-               memcpy(&wr->private_data[0], iw_param->private_data,
-                      iw_param->private_data_len);
-       } else
-               wr->private_data_length = 0;
-
-       /*
-        * Send WR to adapter.  NOTE: There is no synch reply from
-        * the adapter.
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) wr);
-       vq_req_free(c2dev, vq_req);
-
- bail1:
-       kfree(wr);
- bail0:
-       if (err) {
-               /*
-                * If we fail, release reference on QP and
-                * disassociate QP from CM_ID
-                */
-               cm_id->provider_data = NULL;
-               qp->cm_id = NULL;
-               cm_id->rem_ref(cm_id);
-       }
-       return err;
-}
-
-int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog)
-{
-       struct c2_dev *c2dev;
-       struct c2wr_ep_listen_create_req wr;
-       struct c2wr_ep_listen_create_rep *reply;
-       struct c2_vq_req *vq_req;
-       int err;
-       struct sockaddr_in *laddr = (struct sockaddr_in *)&cm_id->local_addr;
-
-       if (cm_id->local_addr.ss_family != AF_INET)
-               return -ENOSYS;
-
-       c2dev = to_c2dev(cm_id->device);
-       if (c2dev == NULL)
-               return -EINVAL;
-
-       /*
-        * Allocate verbs request.
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       /*
-        * Build the WR
-        */
-       c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE);
-       wr.hdr.context = (u64) (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.local_addr = laddr->sin_addr.s_addr;
-       wr.local_port = laddr->sin_port;
-       wr.backlog = cpu_to_be32(backlog);
-       wr.user_context = (u64) (unsigned long) cm_id;
-
-       /*
-        * Reference the request struct.  Dereferenced in the int handler.
-        */
-       vq_req_get(c2dev, vq_req);
-
-       /*
-        * Send WR to adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       /*
-        * Wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail0;
-
-       /*
-        * Process reply
-        */
-       reply =
-           (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       if ((err = c2_errno(reply)) != 0)
-               goto bail1;
-
-       /*
-        * Keep the adapter handle. Used in subsequent destroy
-        */
-       cm_id->provider_data = (void*)(unsigned long) reply->ep_handle;
-
-       /*
-        * free vq stuff
-        */
-       vq_repbuf_free(c2dev, reply);
-       vq_req_free(c2dev, vq_req);
-
-       return 0;
-
- bail1:
-       vq_repbuf_free(c2dev, reply);
- bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-
-int c2_llp_service_destroy(struct iw_cm_id *cm_id)
-{
-
-       struct c2_dev *c2dev;
-       struct c2wr_ep_listen_destroy_req wr;
-       struct c2wr_ep_listen_destroy_rep *reply;
-       struct c2_vq_req *vq_req;
-       int err;
-
-       c2dev = to_c2dev(cm_id->device);
-       if (c2dev == NULL)
-               return -EINVAL;
-
-       /*
-        * Allocate verbs request.
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       /*
-        * Build the WR
-        */
-       c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.ep_handle = (u32)(unsigned long)cm_id->provider_data;
-
-       /*
-        * reference the request struct.  dereferenced in the int handler.
-        */
-       vq_req_get(c2dev, vq_req);
-
-       /*
-        * Send WR to adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       /*
-        * Wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail0;
-
-       /*
-        * Process reply
-        */
-       reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       vq_repbuf_free(c2dev, reply);
- bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
-{
-       struct c2_dev *c2dev = to_c2dev(cm_id->device);
-       struct c2_qp *qp;
-       struct ib_qp *ibqp;
-       struct c2wr_cr_accept_req *wr;  /* variable length WR */
-       struct c2_vq_req *vq_req;
-       struct c2wr_cr_accept_rep *reply;       /* VQ Reply msg ptr. */
-       int err;
-
-       ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
-       if (!ibqp)
-               return -EINVAL;
-       qp = to_c2qp(ibqp);
-
-       /* Set the RDMA read limits */
-       err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
-       if (err)
-               goto bail0;
-
-       /* Allocate verbs request. */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-       vq_req->qp = qp;
-       vq_req->cm_id = cm_id;
-       vq_req->event = IW_CM_EVENT_ESTABLISHED;
-
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       /* Build the WR */
-       c2_wr_set_id(wr, CCWR_CR_ACCEPT);
-       wr->hdr.context = (unsigned long) vq_req;
-       wr->rnic_handle = c2dev->adapter_handle;
-       wr->ep_handle = (u32) (unsigned long) cm_id->provider_data;
-       wr->qp_handle = qp->adapter_handle;
-
-       /* Replace the cr_handle with the QP after accept */
-       cm_id->provider_data = qp;
-       cm_id->add_ref(cm_id);
-       qp->cm_id = cm_id;
-
-       cm_id->provider_data = qp;
-
-       /* Validate private_data length */
-       if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
-               err = -EINVAL;
-               goto bail1;
-       }
-
-       if (iw_param->private_data) {
-               wr->private_data_length = cpu_to_be32(iw_param->private_data_len);
-               memcpy(&wr->private_data[0],
-                      iw_param->private_data, iw_param->private_data_len);
-       } else
-               wr->private_data_length = 0;
-
-       /* Reference the request struct.  Dereferenced in the int handler. */
-       vq_req_get(c2dev, vq_req);
-
-       /* Send WR to adapter */
-       err = vq_send_wr(c2dev, (union c2wr *) wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       /* Wait for reply from adapter */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail1;
-
-       /* Check that reply is present */
-       reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       err = c2_errno(reply);
-       vq_repbuf_free(c2dev, reply);
-
-       if (!err)
-               c2_set_qp_state(qp, C2_QP_STATE_RTS);
- bail1:
-       kfree(wr);
-       vq_req_free(c2dev, vq_req);
- bail0:
-       if (err) {
-               /*
-                * If we fail, release reference on QP and
-                * disassociate QP from CM_ID
-                */
-               cm_id->provider_data = NULL;
-               qp->cm_id = NULL;
-               cm_id->rem_ref(cm_id);
-       }
-       return err;
-}
-
-int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
-{
-       struct c2_dev *c2dev;
-       struct c2wr_cr_reject_req wr;
-       struct c2_vq_req *vq_req;
-       struct c2wr_cr_reject_rep *reply;
-       int err;
-
-       c2dev = to_c2dev(cm_id->device);
-
-       /*
-        * Allocate verbs request.
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       /*
-        * Build the WR
-        */
-       c2_wr_set_id(&wr, CCWR_CR_REJECT);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.ep_handle = (u32) (unsigned long) cm_id->provider_data;
-
-       /*
-        * reference the request struct.  dereferenced in the int handler.
-        */
-       vq_req_get(c2dev, vq_req);
-
-       /*
-        * Send WR to adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       /*
-        * Wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail0;
-
-       /*
-        * Process reply
-        */
-       reply = (struct c2wr_cr_reject_rep *) (unsigned long)
-               vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-       err = c2_errno(reply);
-       /*
-        * free vq stuff
-        */
-       vq_repbuf_free(c2dev, reply);
-
- bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_cq.c b/drivers/staging/rdma/amso1100/c2_cq.c
deleted file mode 100644 (file)
index 7ad0c08..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
- * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/gfp.h>
-
-#include "c2.h"
-#include "c2_vq.h"
-#include "c2_status.h"
-
-#define C2_CQ_MSG_SIZE ((sizeof(struct c2wr_ce) + 32-1) & ~(32-1))
-
-static struct c2_cq *c2_cq_get(struct c2_dev *c2dev, int cqn)
-{
-       struct c2_cq *cq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&c2dev->lock, flags);
-       cq = c2dev->qptr_array[cqn];
-       if (!cq) {
-               spin_unlock_irqrestore(&c2dev->lock, flags);
-               return NULL;
-       }
-       atomic_inc(&cq->refcount);
-       spin_unlock_irqrestore(&c2dev->lock, flags);
-       return cq;
-}
-
-static void c2_cq_put(struct c2_cq *cq)
-{
-       if (atomic_dec_and_test(&cq->refcount))
-               wake_up(&cq->wait);
-}
-
-void c2_cq_event(struct c2_dev *c2dev, u32 mq_index)
-{
-       struct c2_cq *cq;
-
-       cq = c2_cq_get(c2dev, mq_index);
-       if (!cq) {
-               printk("discarding events on destroyed CQN=%d\n", mq_index);
-               return;
-       }
-
-       (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
-       c2_cq_put(cq);
-}
-
-void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index)
-{
-       struct c2_cq *cq;
-       struct c2_mq *q;
-
-       cq = c2_cq_get(c2dev, mq_index);
-       if (!cq)
-               return;
-
-       spin_lock_irq(&cq->lock);
-       q = &cq->mq;
-       if (q && !c2_mq_empty(q)) {
-               u16 priv = q->priv;
-               struct c2wr_ce *msg;
-
-               while (priv != be16_to_cpu(*q->shared)) {
-                       msg = (struct c2wr_ce *)
-                               (q->msg_pool.host + priv * q->msg_size);
-                       if (msg->qp_user_context == (u64) (unsigned long) qp) {
-                               msg->qp_user_context = (u64) 0;
-                       }
-                       priv = (priv + 1) % q->q_size;
-               }
-       }
-       spin_unlock_irq(&cq->lock);
-       c2_cq_put(cq);
-}
-
-static inline enum ib_wc_status c2_cqe_status_to_openib(u8 status)
-{
-       switch (status) {
-       case C2_OK:
-               return IB_WC_SUCCESS;
-       case CCERR_FLUSHED:
-               return IB_WC_WR_FLUSH_ERR;
-       case CCERR_BASE_AND_BOUNDS_VIOLATION:
-               return IB_WC_LOC_PROT_ERR;
-       case CCERR_ACCESS_VIOLATION:
-               return IB_WC_LOC_ACCESS_ERR;
-       case CCERR_TOTAL_LENGTH_TOO_BIG:
-               return IB_WC_LOC_LEN_ERR;
-       case CCERR_INVALID_WINDOW:
-               return IB_WC_MW_BIND_ERR;
-       default:
-               return IB_WC_GENERAL_ERR;
-       }
-}
-
-
-static inline int c2_poll_one(struct c2_dev *c2dev,
-                             struct c2_cq *cq, struct ib_wc *entry)
-{
-       struct c2wr_ce *ce;
-       struct c2_qp *qp;
-       int is_recv = 0;
-
-       ce = c2_mq_consume(&cq->mq);
-       if (!ce) {
-               return -EAGAIN;
-       }
-
-       /*
-        * if the qp returned is null then this qp has already
-        * been freed and we are unable process the completion.
-        * try pulling the next message
-        */
-       while ((qp =
-               (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) {
-               c2_mq_free(&cq->mq);
-               ce = c2_mq_consume(&cq->mq);
-               if (!ce)
-                       return -EAGAIN;
-       }
-
-       entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
-       entry->wr_id = ce->hdr.context;
-       entry->qp = &qp->ibqp;
-       entry->wc_flags = 0;
-       entry->slid = 0;
-       entry->sl = 0;
-       entry->src_qp = 0;
-       entry->dlid_path_bits = 0;
-       entry->pkey_index = 0;
-
-       switch (c2_wr_get_id(ce)) {
-       case C2_WR_TYPE_SEND:
-               entry->opcode = IB_WC_SEND;
-               break;
-       case C2_WR_TYPE_RDMA_WRITE:
-               entry->opcode = IB_WC_RDMA_WRITE;
-               break;
-       case C2_WR_TYPE_RDMA_READ:
-               entry->opcode = IB_WC_RDMA_READ;
-               break;
-       case C2_WR_TYPE_RECV:
-               entry->byte_len = be32_to_cpu(ce->bytes_rcvd);
-               entry->opcode = IB_WC_RECV;
-               is_recv = 1;
-               break;
-       default:
-               break;
-       }
-
-       /* consume the WQEs */
-       if (is_recv)
-               c2_mq_lconsume(&qp->rq_mq, 1);
-       else
-               c2_mq_lconsume(&qp->sq_mq,
-                              be32_to_cpu(c2_wr_get_wqe_count(ce)) + 1);
-
-       /* free the message */
-       c2_mq_free(&cq->mq);
-
-       return 0;
-}
-
-int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
-{
-       struct c2_dev *c2dev = to_c2dev(ibcq->device);
-       struct c2_cq *cq = to_c2cq(ibcq);
-       unsigned long flags;
-       int npolled, err;
-
-       spin_lock_irqsave(&cq->lock, flags);
-
-       for (npolled = 0; npolled < num_entries; ++npolled) {
-
-               err = c2_poll_one(c2dev, cq, entry + npolled);
-               if (err)
-                       break;
-       }
-
-       spin_unlock_irqrestore(&cq->lock, flags);
-
-       return npolled;
-}
-
-int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
-{
-       struct c2_mq_shared __iomem *shared;
-       struct c2_cq *cq;
-       unsigned long flags;
-       int ret = 0;
-
-       cq = to_c2cq(ibcq);
-       shared = cq->mq.peer;
-
-       if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
-               writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
-       else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
-               writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
-       else
-               return -EINVAL;
-
-       writeb(CQ_WAIT_FOR_DMA | CQ_ARMED, &shared->armed);
-
-       /*
-        * Now read back shared->armed to make the PCI
-        * write synchronous.  This is necessary for
-        * correct cq notification semantics.
-        */
-       readb(&shared->armed);
-
-       if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
-               spin_lock_irqsave(&cq->lock, flags);
-               ret = !c2_mq_empty(&cq->mq);
-               spin_unlock_irqrestore(&cq->lock, flags);
-       }
-
-       return ret;
-}
-
-static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
-{
-       dma_free_coherent(&c2dev->pcidev->dev, mq->q_size * mq->msg_size,
-                         mq->msg_pool.host, dma_unmap_addr(mq, mapping));
-}
-
-static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq,
-                          size_t q_size, size_t msg_size)
-{
-       u8 *pool_start;
-
-       if (q_size > SIZE_MAX / msg_size)
-               return -EINVAL;
-
-       pool_start = dma_alloc_coherent(&c2dev->pcidev->dev, q_size * msg_size,
-                                       &mq->host_dma, GFP_KERNEL);
-       if (!pool_start)
-               return -ENOMEM;
-
-       c2_mq_rep_init(mq,
-                      0,               /* index (currently unknown) */
-                      q_size,
-                      msg_size,
-                      pool_start,
-                      NULL,    /* peer (currently unknown) */
-                      C2_MQ_HOST_TARGET);
-
-       dma_unmap_addr_set(mq, mapping, mq->host_dma);
-
-       return 0;
-}
-
-int c2_init_cq(struct c2_dev *c2dev, int entries,
-              struct c2_ucontext *ctx, struct c2_cq *cq)
-{
-       struct c2wr_cq_create_req wr;
-       struct c2wr_cq_create_rep *reply;
-       unsigned long peer_pa;
-       struct c2_vq_req *vq_req;
-       int err;
-
-       might_sleep();
-
-       cq->ibcq.cqe = entries - 1;
-       cq->is_kernel = !ctx;
-
-       /* Allocate a shared pointer */
-       cq->mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                     &cq->mq.shared_dma, GFP_KERNEL);
-       if (!cq->mq.shared)
-               return -ENOMEM;
-
-       /* Allocate pages for the message pool */
-       err = c2_alloc_cq_buf(c2dev, &cq->mq, entries + 1, C2_CQ_MSG_SIZE);
-       if (err)
-               goto bail0;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_CQ_CREATE);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.msg_size = cpu_to_be32(cq->mq.msg_size);
-       wr.depth = cpu_to_be32(cq->mq.q_size);
-       wr.shared_ht = cpu_to_be64(cq->mq.shared_dma);
-       wr.msg_pool = cpu_to_be64(cq->mq.host_dma);
-       wr.user_context = (u64) (unsigned long) (cq);
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail2;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail2;
-
-       reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail2;
-       }
-
-       if ((err = c2_errno(reply)) != 0)
-               goto bail3;
-
-       cq->adapter_handle = reply->cq_handle;
-       cq->mq.index = be32_to_cpu(reply->mq_index);
-
-       peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared);
-       cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE);
-       if (!cq->mq.peer) {
-               err = -ENOMEM;
-               goto bail3;
-       }
-
-       vq_repbuf_free(c2dev, reply);
-       vq_req_free(c2dev, vq_req);
-
-       spin_lock_init(&cq->lock);
-       atomic_set(&cq->refcount, 1);
-       init_waitqueue_head(&cq->wait);
-
-       /*
-        * Use the MQ index allocated by the adapter to
-        * store the CQ in the qptr_array
-        */
-       cq->cqn = cq->mq.index;
-       c2dev->qptr_array[cq->cqn] = cq;
-
-       return 0;
-
-bail3:
-       vq_repbuf_free(c2dev, reply);
-bail2:
-       vq_req_free(c2dev, vq_req);
-bail1:
-       c2_free_cq_buf(c2dev, &cq->mq);
-bail0:
-       c2_free_mqsp(cq->mq.shared);
-
-       return err;
-}
-
-void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq)
-{
-       int err;
-       struct c2_vq_req *vq_req;
-       struct c2wr_cq_destroy_req wr;
-       struct c2wr_cq_destroy_rep *reply;
-
-       might_sleep();
-
-       /* Clear CQ from the qptr array */
-       spin_lock_irq(&c2dev->lock);
-       c2dev->qptr_array[cq->mq.index] = NULL;
-       atomic_dec(&cq->refcount);
-       spin_unlock_irq(&c2dev->lock);
-
-       wait_event(cq->wait, !atomic_read(&cq->refcount));
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               goto bail0;
-       }
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_CQ_DESTROY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.cq_handle = cq->adapter_handle;
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail1;
-
-       reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg);
-       if (reply)
-               vq_repbuf_free(c2dev, reply);
-bail1:
-       vq_req_free(c2dev, vq_req);
-bail0:
-       if (cq->is_kernel) {
-               c2_free_cq_buf(c2dev, &cq->mq);
-       }
-
-       return;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_intr.c b/drivers/staging/rdma/amso1100/c2_intr.c
deleted file mode 100644 (file)
index 74b32a9..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "c2.h"
-#include <rdma/iw_cm.h>
-#include "c2_vq.h"
-
-static void handle_mq(struct c2_dev *c2dev, u32 index);
-static void handle_vq(struct c2_dev *c2dev, u32 mq_index);
-
-/*
- * Handle RNIC interrupts
- */
-void c2_rnic_interrupt(struct c2_dev *c2dev)
-{
-       unsigned int mq_index;
-
-       while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
-               mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
-               if (mq_index & 0x80000000) {
-                       break;
-               }
-
-               c2dev->hints_read++;
-               handle_mq(c2dev, mq_index);
-       }
-
-}
-
-/*
- * Top level MQ handler
- */
-static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
-{
-       if (c2dev->qptr_array[mq_index] == NULL) {
-               pr_debug("handle_mq: stray activity for mq_index=%d\n",
-                        mq_index);
-               return;
-       }
-
-       switch (mq_index) {
-       case (0):
-               /*
-                * An index of 0 in the activity queue
-                * indicates the req vq now has messages
-                * available...
-                *
-                * Wake up any waiters waiting on req VQ
-                * message availability.
-                */
-               wake_up(&c2dev->req_vq_wo);
-               break;
-       case (1):
-               handle_vq(c2dev, mq_index);
-               break;
-       case (2):
-               /* We have to purge the VQ in case there are pending
-                * accept reply requests that would result in the
-                * generation of an ESTABLISHED event. If we don't
-                * generate these first, a CLOSE event could end up
-                * being delivered before the ESTABLISHED event.
-                */
-               handle_vq(c2dev, 1);
-
-               c2_ae_event(c2dev, mq_index);
-               break;
-       default:
-               /* There is no event synchronization between CQ events
-                * and AE or CM events. In fact, CQE could be
-                * delivered for all of the I/O up to and including the
-                * FLUSH for a peer disconenct prior to the ESTABLISHED
-                * event being delivered to the app. The reason for this
-                * is that CM events are delivered on a thread, while AE
-                * and CM events are delivered on interrupt context.
-                */
-               c2_cq_event(c2dev, mq_index);
-               break;
-       }
-
-       return;
-}
-
-/*
- * Handles verbs WR replies.
- */
-static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
-{
-       void *adapter_msg, *reply_msg;
-       struct c2wr_hdr *host_msg;
-       struct c2wr_hdr tmp;
-       struct c2_mq *reply_vq;
-       struct c2_vq_req *req;
-       struct iw_cm_event cm_event;
-       int err;
-
-       reply_vq = c2dev->qptr_array[mq_index];
-
-       /*
-        * get next msg from mq_index into adapter_msg.
-        * don't free it yet.
-        */
-       adapter_msg = c2_mq_consume(reply_vq);
-       if (adapter_msg == NULL) {
-               return;
-       }
-
-       host_msg = vq_repbuf_alloc(c2dev);
-
-       /*
-        * If we can't get a host buffer, then we'll still
-        * wakeup the waiter, we just won't give him the msg.
-        * It is assumed the waiter will deal with this...
-        */
-       if (!host_msg) {
-               pr_debug("handle_vq: no repbufs!\n");
-
-               /*
-                * just copy the WR header into a local variable.
-                * this allows us to still demux on the context
-                */
-               host_msg = &tmp;
-               memcpy(host_msg, adapter_msg, sizeof(tmp));
-               reply_msg = NULL;
-       } else {
-               memcpy(host_msg, adapter_msg, reply_vq->msg_size);
-               reply_msg = host_msg;
-       }
-
-       /*
-        * consume the msg from the MQ
-        */
-       c2_mq_free(reply_vq);
-
-       /*
-        * wakeup the waiter.
-        */
-       req = (struct c2_vq_req *) (unsigned long) host_msg->context;
-       if (req == NULL) {
-               /*
-                * We should never get here, as the adapter should
-                * never send us a reply that we're not expecting.
-                */
-               if (reply_msg != NULL)
-                       vq_repbuf_free(c2dev, host_msg);
-               pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
-               return;
-       }
-
-       if (reply_msg)
-               err = c2_errno(reply_msg);
-       else
-               err = -ENOMEM;
-
-       if (!err) switch (req->event) {
-       case IW_CM_EVENT_ESTABLISHED:
-               c2_set_qp_state(req->qp,
-                               C2_QP_STATE_RTS);
-               /*
-                * Until ird/ord negotiation via MPAv2 support is added, send
-                * max supported values
-                */
-               cm_event.ird = cm_event.ord = 128;
-       case IW_CM_EVENT_CLOSE:
-
-               /*
-                * Move the QP to RTS if this is
-                * the established event
-                */
-               cm_event.event = req->event;
-               cm_event.status = 0;
-               cm_event.local_addr = req->cm_id->local_addr;
-               cm_event.remote_addr = req->cm_id->remote_addr;
-               cm_event.private_data = NULL;
-               cm_event.private_data_len = 0;
-               req->cm_id->event_handler(req->cm_id, &cm_event);
-               break;
-       default:
-               break;
-       }
-
-       req->reply_msg = (u64) (unsigned long) (reply_msg);
-       atomic_set(&req->reply_ready, 1);
-       wake_up(&req->wait_object);
-
-       /*
-        * If the request was cancelled, then this put will
-        * free the vq_req memory...and reply_msg!!!
-        */
-       vq_req_put(c2dev, req);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_mm.c b/drivers/staging/rdma/amso1100/c2_mm.c
deleted file mode 100644 (file)
index 25081e2..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <linux/slab.h>
-
-#include "c2.h"
-#include "c2_vq.h"
-
-#define PBL_VIRT 1
-#define PBL_PHYS 2
-
-/*
- * Send all the PBL messages to convey the remainder of the PBL
- * Wait for the adapter's reply on the last one.
- * This is indicated by setting the MEM_PBL_COMPLETE in the flags.
- *
- * NOTE:  vq_req is _not_ freed by this function.  The VQ Host
- *       Reply buffer _is_ freed by this function.
- */
-static int
-send_pbl_messages(struct c2_dev *c2dev, __be32 stag_index,
-                 unsigned long va, u32 pbl_depth,
-                 struct c2_vq_req *vq_req, int pbl_type)
-{
-       u32 pbe_count;          /* amt that fits in a PBL msg */
-       u32 count;              /* amt in this PBL MSG. */
-       struct c2wr_nsmr_pbl_req *wr;   /* PBL WR ptr */
-       struct c2wr_nsmr_pbl_rep *reply;        /* reply ptr */
-       int err, pbl_virt, pbl_index, i;
-
-       switch (pbl_type) {
-       case PBL_VIRT:
-               pbl_virt = 1;
-               break;
-       case PBL_PHYS:
-               pbl_virt = 0;
-               break;
-       default:
-               return -EINVAL;
-               break;
-       }
-
-       pbe_count = (c2dev->req_vq.msg_size -
-                    sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64);
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               return -ENOMEM;
-       }
-       c2_wr_set_id(wr, CCWR_NSMR_PBL);
-
-       /*
-        * Only the last PBL message will generate a reply from the verbs,
-        * so we set the context to 0 indicating there is no kernel verbs
-        * handler blocked awaiting this reply.
-        */
-       wr->hdr.context = 0;
-       wr->rnic_handle = c2dev->adapter_handle;
-       wr->stag_index = stag_index;    /* already swapped */
-       wr->flags = 0;
-       pbl_index = 0;
-       while (pbl_depth) {
-               count = min(pbe_count, pbl_depth);
-               wr->addrs_length = cpu_to_be32(count);
-
-               /*
-                *  If this is the last message, then reference the
-                *  vq request struct cuz we're gonna wait for a reply.
-                *  also make this PBL msg as the last one.
-                */
-               if (count == pbl_depth) {
-                       /*
-                        * reference the request struct.  dereferenced in the
-                        * int handler.
-                        */
-                       vq_req_get(c2dev, vq_req);
-                       wr->flags = cpu_to_be32(MEM_PBL_COMPLETE);
-
-                       /*
-                        * This is the last PBL message.
-                        * Set the context to our VQ Request Object so we can
-                        * wait for the reply.
-                        */
-                       wr->hdr.context = (unsigned long) vq_req;
-               }
-
-               /*
-                * If pbl_virt is set then va is a virtual address
-                * that describes a virtually contiguous memory
-                * allocation. The wr needs the start of each virtual page
-                * to be converted to the corresponding physical address
-                * of the page. If pbl_virt is not set then va is an array
-                * of physical addresses and there is no conversion to do.
-                * Just fill in the wr with what is in the array.
-                */
-               for (i = 0; i < count; i++) {
-                       if (pbl_virt) {
-                               va += PAGE_SIZE;
-                       } else {
-                               wr->paddrs[i] =
-                                   cpu_to_be64(((u64 *)va)[pbl_index + i]);
-                       }
-               }
-
-               /*
-                * Send WR to adapter
-                */
-               err = vq_send_wr(c2dev, (union c2wr *) wr);
-               if (err) {
-                       if (count <= pbe_count) {
-                               vq_req_put(c2dev, vq_req);
-                       }
-                       goto bail0;
-               }
-               pbl_depth -= count;
-               pbl_index += count;
-       }
-
-       /*
-        *  Now wait for the reply...
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail0;
-       }
-
-       /*
-        * Process reply
-        */
-       reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       err = c2_errno(reply);
-
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       kfree(wr);
-       return err;
-}
-
-#define C2_PBL_MAX_DEPTH 131072
-int
-c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
-                          int page_size, int pbl_depth, u32 length,
-                          u32 offset, u64 *va, enum c2_acf acf,
-                          struct c2_mr *mr)
-{
-       struct c2_vq_req *vq_req;
-       struct c2wr_nsmr_register_req *wr;
-       struct c2wr_nsmr_register_rep *reply;
-       u16 flags;
-       int i, pbe_count, count;
-       int err;
-
-       if (!va || !length || !addr_list || !pbl_depth)
-               return -EINTR;
-
-       /*
-        * Verify PBL depth is within rnic max
-        */
-       if (pbl_depth > C2_PBL_MAX_DEPTH) {
-               return -EINTR;
-       }
-
-       /*
-        * allocate verbs request object
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       /*
-        * build the WR
-        */
-       c2_wr_set_id(wr, CCWR_NSMR_REGISTER);
-       wr->hdr.context = (unsigned long) vq_req;
-       wr->rnic_handle = c2dev->adapter_handle;
-
-       flags = (acf | MEM_VA_BASED | MEM_REMOTE);
-
-       /*
-        * compute how many pbes can fit in the message
-        */
-       pbe_count = (c2dev->req_vq.msg_size -
-                    sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64);
-
-       if (pbl_depth <= pbe_count) {
-               flags |= MEM_PBL_COMPLETE;
-       }
-       wr->flags = cpu_to_be16(flags);
-       wr->stag_key = 0;       //stag_key;
-       wr->va = cpu_to_be64(*va);
-       wr->pd_id = mr->pd->pd_id;
-       wr->pbe_size = cpu_to_be32(page_size);
-       wr->length = cpu_to_be32(length);
-       wr->pbl_depth = cpu_to_be32(pbl_depth);
-       wr->fbo = cpu_to_be32(offset);
-       count = min(pbl_depth, pbe_count);
-       wr->addrs_length = cpu_to_be32(count);
-
-       /*
-        * fill out the PBL for this message
-        */
-       for (i = 0; i < count; i++) {
-               wr->paddrs[i] = cpu_to_be64(addr_list[i]);
-       }
-
-       /*
-        * regerence the request struct
-        */
-       vq_req_get(c2dev, vq_req);
-
-       /*
-        * send the WR to the adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       /*
-        * wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail1;
-       }
-
-       /*
-        * process reply
-        */
-       reply =
-           (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-       if ((err = c2_errno(reply))) {
-               goto bail2;
-       }
-       //*p_pb_entries = be32_to_cpu(reply->pbl_depth);
-       mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index);
-       vq_repbuf_free(c2dev, reply);
-
-       /*
-        * if there are still more PBEs we need to send them to
-        * the adapter and wait for a reply on the final one.
-        * reuse vq_req for this purpose.
-        */
-       pbl_depth -= count;
-       if (pbl_depth) {
-
-               vq_req->reply_msg = (unsigned long) NULL;
-               atomic_set(&vq_req->reply_ready, 0);
-               err = send_pbl_messages(c2dev,
-                                       cpu_to_be32(mr->ibmr.lkey),
-                                       (unsigned long) &addr_list[i],
-                                       pbl_depth, vq_req, PBL_PHYS);
-               if (err) {
-                       goto bail1;
-               }
-       }
-
-       vq_req_free(c2dev, vq_req);
-       kfree(wr);
-
-       return err;
-
-bail2:
-       vq_repbuf_free(c2dev, reply);
-bail1:
-       kfree(wr);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index)
-{
-       struct c2_vq_req *vq_req;       /* verbs request object */
-       struct c2wr_stag_dealloc_req wr;        /* work request */
-       struct c2wr_stag_dealloc_rep *reply;    /* WR reply  */
-       int err;
-
-
-       /*
-        * allocate verbs request object
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               return -ENOMEM;
-       }
-
-       /*
-        * Build the WR
-        */
-       c2_wr_set_id(&wr, CCWR_STAG_DEALLOC);
-       wr.hdr.context = (u64) (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.stag_index = cpu_to_be32(stag_index);
-
-       /*
-        * reference the request struct.  dereferenced in the int handler.
-        */
-       vq_req_get(c2dev, vq_req);
-
-       /*
-        * Send WR to adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       /*
-        * Wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail0;
-       }
-
-       /*
-        * Process reply
-        */
-       reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       err = c2_errno(reply);
-
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_mq.c b/drivers/staging/rdma/amso1100/c2_mq.c
deleted file mode 100644 (file)
index 7827fb8..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include "c2.h"
-#include "c2_mq.h"
-
-void *c2_mq_alloc(struct c2_mq *q)
-{
-       BUG_ON(q->magic != C2_MQ_MAGIC);
-       BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
-
-       if (c2_mq_full(q)) {
-               return NULL;
-       } else {
-#ifdef DEBUG
-               struct c2wr_hdr *m =
-                   (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size);
-#ifdef CCMSGMAGIC
-               BUG_ON(m->magic != be32_to_cpu(~CCWR_MAGIC));
-               m->magic = cpu_to_be32(CCWR_MAGIC);
-#endif
-               return m;
-#else
-               return q->msg_pool.host + q->priv * q->msg_size;
-#endif
-       }
-}
-
-void c2_mq_produce(struct c2_mq *q)
-{
-       BUG_ON(q->magic != C2_MQ_MAGIC);
-       BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
-
-       if (!c2_mq_full(q)) {
-               q->priv = (q->priv + 1) % q->q_size;
-               q->hint_count++;
-               /* Update peer's offset. */
-               __raw_writew((__force u16) cpu_to_be16(q->priv), &q->peer->shared);
-       }
-}
-
-void *c2_mq_consume(struct c2_mq *q)
-{
-       BUG_ON(q->magic != C2_MQ_MAGIC);
-       BUG_ON(q->type != C2_MQ_HOST_TARGET);
-
-       if (c2_mq_empty(q)) {
-               return NULL;
-       } else {
-#ifdef DEBUG
-               struct c2wr_hdr *m = (struct c2wr_hdr *)
-                   (q->msg_pool.host + q->priv * q->msg_size);
-#ifdef CCMSGMAGIC
-               BUG_ON(m->magic != be32_to_cpu(CCWR_MAGIC));
-#endif
-               return m;
-#else
-               return q->msg_pool.host + q->priv * q->msg_size;
-#endif
-       }
-}
-
-void c2_mq_free(struct c2_mq *q)
-{
-       BUG_ON(q->magic != C2_MQ_MAGIC);
-       BUG_ON(q->type != C2_MQ_HOST_TARGET);
-
-       if (!c2_mq_empty(q)) {
-
-#ifdef CCMSGMAGIC
-               {
-                       struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *)
-                           (q->msg_pool.adapter + q->priv * q->msg_size);
-                       __raw_writel(cpu_to_be32(~CCWR_MAGIC), &m->magic);
-               }
-#endif
-               q->priv = (q->priv + 1) % q->q_size;
-               /* Update peer's offset. */
-               __raw_writew((__force u16) cpu_to_be16(q->priv), &q->peer->shared);
-       }
-}
-
-
-void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count)
-{
-       BUG_ON(q->magic != C2_MQ_MAGIC);
-       BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
-
-       while (wqe_count--) {
-               BUG_ON(c2_mq_empty(q));
-               *q->shared = cpu_to_be16((be16_to_cpu(*q->shared)+1) % q->q_size);
-       }
-}
-
-#if 0
-u32 c2_mq_count(struct c2_mq *q)
-{
-       s32 count;
-
-       if (q->type == C2_MQ_HOST_TARGET)
-               count = be16_to_cpu(*q->shared) - q->priv;
-       else
-               count = q->priv - be16_to_cpu(*q->shared);
-
-       if (count < 0)
-               count += q->q_size;
-
-       return (u32) count;
-}
-#endif  /*  0  */
-
-void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
-                   u8 __iomem *pool_start, u16 __iomem *peer, u32 type)
-{
-       BUG_ON(!q->shared);
-
-       /* This code assumes the byte swapping has already been done! */
-       q->index = index;
-       q->q_size = q_size;
-       q->msg_size = msg_size;
-       q->msg_pool.adapter = pool_start;
-       q->peer = (struct c2_mq_shared __iomem *) peer;
-       q->magic = C2_MQ_MAGIC;
-       q->type = type;
-       q->priv = 0;
-       q->hint_count = 0;
-       return;
-}
-
-void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
-                   u8 *pool_start, u16 __iomem *peer, u32 type)
-{
-       BUG_ON(!q->shared);
-
-       /* This code assumes the byte swapping has already been done! */
-       q->index = index;
-       q->q_size = q_size;
-       q->msg_size = msg_size;
-       q->msg_pool.host = pool_start;
-       q->peer = (struct c2_mq_shared __iomem *) peer;
-       q->magic = C2_MQ_MAGIC;
-       q->type = type;
-       q->priv = 0;
-       q->hint_count = 0;
-       return;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_mq.h b/drivers/staging/rdma/amso1100/c2_mq.h
deleted file mode 100644 (file)
index 8e1b4d1..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _C2_MQ_H_
-#define _C2_MQ_H_
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include "c2_wr.h"
-
-enum c2_shared_regs {
-
-       C2_SHARED_ARMED = 0x10,
-       C2_SHARED_NOTIFY = 0x18,
-       C2_SHARED_SHARED = 0x40,
-};
-
-struct c2_mq_shared {
-       u16 unused1;
-       u8 armed;
-       u8 notification_type;
-       u32 unused2;
-       u16 shared;
-       /* Pad to 64 bytes. */
-       u8 pad[64 - sizeof(u16) - 2 * sizeof(u8) - sizeof(u32) - sizeof(u16)];
-};
-
-enum c2_mq_type {
-       C2_MQ_HOST_TARGET = 1,
-       C2_MQ_ADAPTER_TARGET = 2,
-};
-
-/*
- * c2_mq_t is for kernel-mode MQs like the VQs Cand the AEQ.
- * c2_user_mq_t (which is the same format) is for user-mode MQs...
- */
-#define C2_MQ_MAGIC 0x4d512020 /* 'MQ  ' */
-struct c2_mq {
-       u32 magic;
-       union {
-               u8 *host;
-               u8 __iomem *adapter;
-       } msg_pool;
-       dma_addr_t host_dma;
-       DEFINE_DMA_UNMAP_ADDR(mapping);
-       u16 hint_count;
-       u16 priv;
-       struct c2_mq_shared __iomem *peer;
-       __be16 *shared;
-       dma_addr_t shared_dma;
-       u32 q_size;
-       u32 msg_size;
-       u32 index;
-       enum c2_mq_type type;
-};
-
-static __inline__ int c2_mq_empty(struct c2_mq *q)
-{
-       return q->priv == be16_to_cpu(*q->shared);
-}
-
-static __inline__ int c2_mq_full(struct c2_mq *q)
-{
-       return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size;
-}
-
-void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
-void *c2_mq_alloc(struct c2_mq *q);
-void c2_mq_produce(struct c2_mq *q);
-void *c2_mq_consume(struct c2_mq *q);
-void c2_mq_free(struct c2_mq *q);
-void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
-                      u8 __iomem *pool_start, u16 __iomem *peer, u32 type);
-void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
-                          u8 *pool_start, u16 __iomem *peer, u32 type);
-
-#endif                         /* _C2_MQ_H_ */
diff --git a/drivers/staging/rdma/amso1100/c2_pd.c b/drivers/staging/rdma/amso1100/c2_pd.c
deleted file mode 100644 (file)
index f3e81dc..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-
-#include "c2.h"
-#include "c2_provider.h"
-
-int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd)
-{
-       u32 obj;
-       int ret = 0;
-
-       spin_lock(&c2dev->pd_table.lock);
-       obj = find_next_zero_bit(c2dev->pd_table.table, c2dev->pd_table.max,
-                                c2dev->pd_table.last);
-       if (obj >= c2dev->pd_table.max)
-               obj = find_first_zero_bit(c2dev->pd_table.table,
-                                         c2dev->pd_table.max);
-       if (obj < c2dev->pd_table.max) {
-               pd->pd_id = obj;
-               __set_bit(obj, c2dev->pd_table.table);
-               c2dev->pd_table.last = obj+1;
-               if (c2dev->pd_table.last >= c2dev->pd_table.max)
-                       c2dev->pd_table.last = 0;
-       } else
-               ret = -ENOMEM;
-       spin_unlock(&c2dev->pd_table.lock);
-       return ret;
-}
-
-void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd)
-{
-       spin_lock(&c2dev->pd_table.lock);
-       __clear_bit(pd->pd_id, c2dev->pd_table.table);
-       spin_unlock(&c2dev->pd_table.lock);
-}
-
-int c2_init_pd_table(struct c2_dev *c2dev)
-{
-
-       c2dev->pd_table.last = 0;
-       c2dev->pd_table.max = c2dev->props.max_pd;
-       spin_lock_init(&c2dev->pd_table.lock);
-       c2dev->pd_table.table = kmalloc(BITS_TO_LONGS(c2dev->props.max_pd) *
-                                       sizeof(long), GFP_KERNEL);
-       if (!c2dev->pd_table.table)
-               return -ENOMEM;
-       bitmap_zero(c2dev->pd_table.table, c2dev->props.max_pd);
-       return 0;
-}
-
-void c2_cleanup_pd_table(struct c2_dev *c2dev)
-{
-       kfree(c2dev->pd_table.table);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_provider.c b/drivers/staging/rdma/amso1100/c2_provider.c
deleted file mode 100644 (file)
index de8d10e..0000000
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <linux/crc32.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/if_arp.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-
-#include <rdma/ib_smi.h>
-#include <rdma/ib_umem.h>
-#include <rdma/ib_user_verbs.h>
-#include "c2.h"
-#include "c2_provider.h"
-#include "c2_user.h"
-
-static int c2_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
-                          struct ib_udata *uhw)
-{
-       struct c2_dev *c2dev = to_c2dev(ibdev);
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       if (uhw->inlen || uhw->outlen)
-               return -EINVAL;
-
-       *props = c2dev->props;
-       return 0;
-}
-
-static int c2_query_port(struct ib_device *ibdev,
-                        u8 port, struct ib_port_attr *props)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       props->max_mtu = IB_MTU_4096;
-       props->lid = 0;
-       props->lmc = 0;
-       props->sm_lid = 0;
-       props->sm_sl = 0;
-       props->state = IB_PORT_ACTIVE;
-       props->phys_state = 0;
-       props->port_cap_flags =
-           IB_PORT_CM_SUP |
-           IB_PORT_REINIT_SUP |
-           IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
-       props->gid_tbl_len = 1;
-       props->pkey_tbl_len = 1;
-       props->qkey_viol_cntr = 0;
-       props->active_width = 1;
-       props->active_speed = IB_SPEED_SDR;
-
-       return 0;
-}
-
-static int c2_query_pkey(struct ib_device *ibdev,
-                        u8 port, u16 index, u16 * pkey)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       *pkey = 0;
-       return 0;
-}
-
-static int c2_query_gid(struct ib_device *ibdev, u8 port,
-                       int index, union ib_gid *gid)
-{
-       struct c2_dev *c2dev = to_c2dev(ibdev);
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       memset(&(gid->raw[0]), 0, sizeof(gid->raw));
-       memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6);
-
-       return 0;
-}
-
-/* Allocate the user context data structure. This keeps track
- * of all objects associated with a particular user-mode client.
- */
-static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev,
-                                            struct ib_udata *udata)
-{
-       struct c2_ucontext *context;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       context = kmalloc(sizeof(*context), GFP_KERNEL);
-       if (!context)
-               return ERR_PTR(-ENOMEM);
-
-       return &context->ibucontext;
-}
-
-static int c2_dealloc_ucontext(struct ib_ucontext *context)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       kfree(context);
-       return 0;
-}
-
-static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return -ENOSYS;
-}
-
-static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev,
-                                struct ib_ucontext *context,
-                                struct ib_udata *udata)
-{
-       struct c2_pd *pd;
-       int err;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       pd = kmalloc(sizeof(*pd), GFP_KERNEL);
-       if (!pd)
-               return ERR_PTR(-ENOMEM);
-
-       err = c2_pd_alloc(to_c2dev(ibdev), !context, pd);
-       if (err) {
-               kfree(pd);
-               return ERR_PTR(err);
-       }
-
-       if (context) {
-               if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) {
-                       c2_pd_free(to_c2dev(ibdev), pd);
-                       kfree(pd);
-                       return ERR_PTR(-EFAULT);
-               }
-       }
-
-       return &pd->ibpd;
-}
-
-static int c2_dealloc_pd(struct ib_pd *pd)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       c2_pd_free(to_c2dev(pd->device), to_c2pd(pd));
-       kfree(pd);
-
-       return 0;
-}
-
-static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return ERR_PTR(-ENOSYS);
-}
-
-static int c2_ah_destroy(struct ib_ah *ah)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return -ENOSYS;
-}
-
-static void c2_add_ref(struct ib_qp *ibqp)
-{
-       struct c2_qp *qp;
-       BUG_ON(!ibqp);
-       qp = to_c2qp(ibqp);
-       atomic_inc(&qp->refcount);
-}
-
-static void c2_rem_ref(struct ib_qp *ibqp)
-{
-       struct c2_qp *qp;
-       BUG_ON(!ibqp);
-       qp = to_c2qp(ibqp);
-       if (atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-}
-
-struct ib_qp *c2_get_qp(struct ib_device *device, int qpn)
-{
-       struct c2_dev* c2dev = to_c2dev(device);
-       struct c2_qp *qp;
-
-       qp = c2_find_qpn(c2dev, qpn);
-       pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n",
-               __func__, qp, qpn, device,
-               (qp?atomic_read(&qp->refcount):0));
-
-       return (qp?&qp->ibqp:NULL);
-}
-
-static struct ib_qp *c2_create_qp(struct ib_pd *pd,
-                                 struct ib_qp_init_attr *init_attr,
-                                 struct ib_udata *udata)
-{
-       struct c2_qp *qp;
-       int err;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       if (init_attr->create_flags)
-               return ERR_PTR(-EINVAL);
-
-       switch (init_attr->qp_type) {
-       case IB_QPT_RC:
-               qp = kzalloc(sizeof(*qp), GFP_KERNEL);
-               if (!qp) {
-                       pr_debug("%s: Unable to allocate QP\n", __func__);
-                       return ERR_PTR(-ENOMEM);
-               }
-               spin_lock_init(&qp->lock);
-               if (pd->uobject) {
-                       /* userspace specific */
-               }
-
-               err = c2_alloc_qp(to_c2dev(pd->device),
-                                 to_c2pd(pd), init_attr, qp);
-
-               if (err && pd->uobject) {
-                       /* userspace specific */
-               }
-
-               break;
-       default:
-               pr_debug("%s: Invalid QP type: %d\n", __func__,
-                       init_attr->qp_type);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (err) {
-               kfree(qp);
-               return ERR_PTR(err);
-       }
-
-       return &qp->ibqp;
-}
-
-static int c2_destroy_qp(struct ib_qp *ib_qp)
-{
-       struct c2_qp *qp = to_c2qp(ib_qp);
-
-       pr_debug("%s:%u qp=%p,qp->state=%d\n",
-               __func__, __LINE__, ib_qp, qp->state);
-       c2_free_qp(to_c2dev(ib_qp->device), qp);
-       kfree(qp);
-       return 0;
-}
-
-static struct ib_cq *c2_create_cq(struct ib_device *ibdev,
-                                 const struct ib_cq_init_attr *attr,
-                                 struct ib_ucontext *context,
-                                 struct ib_udata *udata)
-{
-       int entries = attr->cqe;
-       struct c2_cq *cq;
-       int err;
-
-       if (attr->flags)
-               return ERR_PTR(-EINVAL);
-
-       cq = kmalloc(sizeof(*cq), GFP_KERNEL);
-       if (!cq) {
-               pr_debug("%s: Unable to allocate CQ\n", __func__);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq);
-       if (err) {
-               pr_debug("%s: error initializing CQ\n", __func__);
-               kfree(cq);
-               return ERR_PTR(err);
-       }
-
-       return &cq->ibcq;
-}
-
-static int c2_destroy_cq(struct ib_cq *ib_cq)
-{
-       struct c2_cq *cq = to_c2cq(ib_cq);
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       c2_free_cq(to_c2dev(ib_cq->device), cq);
-       kfree(cq);
-
-       return 0;
-}
-
-static inline u32 c2_convert_access(int acc)
-{
-       return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) |
-           (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) |
-           (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) |
-           C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND;
-}
-
-static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
-{
-       struct c2_mr *mr;
-       u64 *page_list;
-       const u32 total_len = 0xffffffff;       /* AMSO1100 limit */
-       int err, page_shift, pbl_depth, i;
-       u64 kva = 0;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       /*
-        * This is a map of all phy mem...use a 32k page_shift.
-        */
-       page_shift = PAGE_SHIFT + 3;
-       pbl_depth = ALIGN(total_len, BIT(page_shift)) >> page_shift;
-
-       page_list = vmalloc(sizeof(u64) * pbl_depth);
-       if (!page_list) {
-               pr_debug("couldn't vmalloc page_list of size %zd\n",
-                       (sizeof(u64) * pbl_depth));
-               return ERR_PTR(-ENOMEM);
-       }
-
-       for (i = 0; i < pbl_depth; i++)
-               page_list[i] = (i << page_shift);
-
-       mr = kmalloc(sizeof(*mr), GFP_KERNEL);
-       if (!mr) {
-               vfree(page_list);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       mr->pd = to_c2pd(pd);
-       mr->umem = NULL;
-       pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
-               "*iova_start %llx, first pa %llx, last pa %llx\n",
-               __func__, page_shift, pbl_depth, total_len,
-               (unsigned long long) kva,
-               (unsigned long long) page_list[0],
-               (unsigned long long) page_list[pbl_depth-1]);
-       err = c2_nsmr_register_phys_kern(to_c2dev(pd->device), page_list,
-                                        BIT(page_shift), pbl_depth,
-                                        total_len, 0, &kva,
-                                        c2_convert_access(acc), mr);
-       vfree(page_list);
-       if (err) {
-               kfree(mr);
-               return ERR_PTR(err);
-       }
-
-       return &mr->ibmr;
-}
-
-static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
-                                   u64 virt, int acc, struct ib_udata *udata)
-{
-       u64 *pages;
-       u64 kva = 0;
-       int shift, n, len;
-       int i, k, entry;
-       int err = 0;
-       struct scatterlist *sg;
-       struct c2_pd *c2pd = to_c2pd(pd);
-       struct c2_mr *c2mr;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
-       if (!c2mr)
-               return ERR_PTR(-ENOMEM);
-       c2mr->pd = c2pd;
-
-       c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
-       if (IS_ERR(c2mr->umem)) {
-               err = PTR_ERR(c2mr->umem);
-               kfree(c2mr);
-               return ERR_PTR(err);
-       }
-
-       shift = ffs(c2mr->umem->page_size) - 1;
-       n = c2mr->umem->nmap;
-
-       pages = kmalloc_array(n, sizeof(u64), GFP_KERNEL);
-       if (!pages) {
-               err = -ENOMEM;
-               goto err;
-       }
-
-       i = 0;
-       for_each_sg(c2mr->umem->sg_head.sgl, sg, c2mr->umem->nmap, entry) {
-               len = sg_dma_len(sg) >> shift;
-               for (k = 0; k < len; ++k) {
-                       pages[i++] =
-                               sg_dma_address(sg) +
-                               (c2mr->umem->page_size * k);
-               }
-       }
-
-       kva = virt;
-       err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
-                                        pages,
-                                        c2mr->umem->page_size,
-                                        i,
-                                        length,
-                                        ib_umem_offset(c2mr->umem),
-                                        &kva,
-                                        c2_convert_access(acc),
-                                        c2mr);
-       kfree(pages);
-       if (err)
-               goto err;
-       return &c2mr->ibmr;
-
-err:
-       ib_umem_release(c2mr->umem);
-       kfree(c2mr);
-       return ERR_PTR(err);
-}
-
-static int c2_dereg_mr(struct ib_mr *ib_mr)
-{
-       struct c2_mr *mr = to_c2mr(ib_mr);
-       int err;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
-       if (err)
-               pr_debug("c2_stag_dealloc failed: %d\n", err);
-       else {
-               if (mr->umem)
-                       ib_umem_release(mr->umem);
-               kfree(mr);
-       }
-
-       return err;
-}
-
-static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       struct c2_dev *c2dev = container_of(dev, struct c2_dev, ibdev.dev);
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return sprintf(buf, "%x\n", c2dev->props.hw_ver);
-}
-
-static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct c2_dev *c2dev = container_of(dev, struct c2_dev, ibdev.dev);
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return sprintf(buf, "%x.%x.%x\n",
-                      (int) (c2dev->props.fw_ver >> 32),
-                      (int) (c2dev->props.fw_ver >> 16) & 0xffff,
-                      (int) (c2dev->props.fw_ver & 0xffff));
-}
-
-static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
-                       char *buf)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return sprintf(buf, "AMSO1100\n");
-}
-
-static ssize_t show_board(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID");
-}
-
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
-
-static struct device_attribute *c2_dev_attributes[] = {
-       &dev_attr_hw_rev,
-       &dev_attr_fw_ver,
-       &dev_attr_hca_type,
-       &dev_attr_board_id
-};
-
-static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
-                       int attr_mask, struct ib_udata *udata)
-{
-       int err;
-
-       err =
-           c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr,
-                        attr_mask);
-
-       return err;
-}
-
-static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return -ENOSYS;
-}
-
-static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return -ENOSYS;
-}
-
-static int c2_process_mad(struct ib_device *ibdev,
-                         int mad_flags,
-                         u8 port_num,
-                         const struct ib_wc *in_wc,
-                         const struct ib_grh *in_grh,
-                         const struct ib_mad_hdr *in_mad,
-                         size_t in_mad_size,
-                         struct ib_mad_hdr *out_mad,
-                         size_t *out_mad_size,
-                         u16 *out_mad_pkey_index)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       return -ENOSYS;
-}
-
-static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       /* Request a connection */
-       return c2_llp_connect(cm_id, iw_param);
-}
-
-static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       /* Accept the new connection */
-       return c2_llp_accept(cm_id, iw_param);
-}
-
-static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       return c2_llp_reject(cm_id, pdata, pdata_len);
-}
-
-static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
-{
-       int err;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       err = c2_llp_service_create(cm_id, backlog);
-       pr_debug("%s:%u err=%d\n",
-               __func__, __LINE__,
-               err);
-       return err;
-}
-
-static int c2_service_destroy(struct iw_cm_id *cm_id)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-
-       return c2_llp_service_destroy(cm_id);
-}
-
-static int c2_pseudo_up(struct net_device *netdev)
-{
-       struct in_device *ind;
-       struct c2_dev *c2dev = netdev->ml_priv;
-
-       ind = in_dev_get(netdev);
-       if (!ind)
-               return 0;
-
-       pr_debug("adding...\n");
-       for_ifa(ind) {
-#ifdef DEBUG
-               u8 *ip = (u8 *) & ifa->ifa_address;
-
-               pr_debug("%s: %d.%d.%d.%d\n",
-                      ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
-#endif
-               c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
-       }
-       endfor_ifa(ind);
-       in_dev_put(ind);
-
-       return 0;
-}
-
-static int c2_pseudo_down(struct net_device *netdev)
-{
-       struct in_device *ind;
-       struct c2_dev *c2dev = netdev->ml_priv;
-
-       ind = in_dev_get(netdev);
-       if (!ind)
-               return 0;
-
-       pr_debug("deleting...\n");
-       for_ifa(ind) {
-#ifdef DEBUG
-               u8 *ip = (u8 *) & ifa->ifa_address;
-
-               pr_debug("%s: %d.%d.%d.%d\n",
-                      ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
-#endif
-               c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
-       }
-       endfor_ifa(ind);
-       in_dev_put(ind);
-
-       return 0;
-}
-
-static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
-{
-       kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
-{
-       if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
-               return -EINVAL;
-
-       netdev->mtu = new_mtu;
-
-       /* TODO: Tell rnic about new rmda interface mtu */
-       return 0;
-}
-
-static const struct net_device_ops c2_pseudo_netdev_ops = {
-       .ndo_open               = c2_pseudo_up,
-       .ndo_stop               = c2_pseudo_down,
-       .ndo_start_xmit         = c2_pseudo_xmit_frame,
-       .ndo_change_mtu         = c2_pseudo_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static void setup(struct net_device *netdev)
-{
-       netdev->netdev_ops = &c2_pseudo_netdev_ops;
-
-       netdev->watchdog_timeo = 0;
-       netdev->type = ARPHRD_ETHER;
-       netdev->mtu = 1500;
-       netdev->hard_header_len = ETH_HLEN;
-       netdev->addr_len = ETH_ALEN;
-       netdev->tx_queue_len = 0;
-       netdev->flags |= IFF_NOARP;
-}
-
-static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
-{
-       char name[IFNAMSIZ];
-       struct net_device *netdev;
-
-       /* change ethxxx to iwxxx */
-       strcpy(name, "iw");
-       strcat(name, &c2dev->netdev->name[3]);
-       netdev = alloc_netdev(0, name, NET_NAME_UNKNOWN, setup);
-       if (!netdev) {
-               printk(KERN_ERR PFX "%s -  etherdev alloc failed",
-                       __func__);
-               return NULL;
-       }
-
-       netdev->ml_priv = c2dev;
-
-       SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
-
-       memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6);
-
-       /* Print out the MAC address */
-       pr_debug("%s: MAC %pM\n", netdev->name, netdev->dev_addr);
-
-#if 0
-       /* Disable network packets */
-       netif_stop_queue(netdev);
-#endif
-       return netdev;
-}
-
-static int c2_port_immutable(struct ib_device *ibdev, u8 port_num,
-                            struct ib_port_immutable *immutable)
-{
-       struct ib_port_attr attr;
-       int err;
-
-       err = c2_query_port(ibdev, port_num, &attr);
-       if (err)
-               return err;
-
-       immutable->pkey_tbl_len = attr.pkey_tbl_len;
-       immutable->gid_tbl_len = attr.gid_tbl_len;
-       immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
-
-       return 0;
-}
-
-int c2_register_device(struct c2_dev *dev)
-{
-       int ret = -ENOMEM;
-       int i;
-
-       /* Register pseudo network device */
-       dev->pseudo_netdev = c2_pseudo_netdev_init(dev);
-       if (!dev->pseudo_netdev)
-               goto out;
-
-       ret = register_netdev(dev->pseudo_netdev);
-       if (ret)
-               goto out_free_netdev;
-
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX);
-       dev->ibdev.owner = THIS_MODULE;
-       dev->ibdev.uverbs_cmd_mask =
-           (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
-           (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
-           (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
-           (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
-           (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
-           (1ull << IB_USER_VERBS_CMD_REG_MR) |
-           (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
-           (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
-           (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
-           (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
-           (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
-           (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
-           (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
-           (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
-           (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
-           (1ull << IB_USER_VERBS_CMD_POST_SEND) |
-           (1ull << IB_USER_VERBS_CMD_POST_RECV);
-
-       dev->ibdev.node_type = RDMA_NODE_RNIC;
-       memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
-       memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
-       dev->ibdev.phys_port_cnt = 1;
-       dev->ibdev.num_comp_vectors = 1;
-       dev->ibdev.dma_device = &dev->pcidev->dev;
-       dev->ibdev.query_device = c2_query_device;
-       dev->ibdev.query_port = c2_query_port;
-       dev->ibdev.query_pkey = c2_query_pkey;
-       dev->ibdev.query_gid = c2_query_gid;
-       dev->ibdev.alloc_ucontext = c2_alloc_ucontext;
-       dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext;
-       dev->ibdev.mmap = c2_mmap_uar;
-       dev->ibdev.alloc_pd = c2_alloc_pd;
-       dev->ibdev.dealloc_pd = c2_dealloc_pd;
-       dev->ibdev.create_ah = c2_ah_create;
-       dev->ibdev.destroy_ah = c2_ah_destroy;
-       dev->ibdev.create_qp = c2_create_qp;
-       dev->ibdev.modify_qp = c2_modify_qp;
-       dev->ibdev.destroy_qp = c2_destroy_qp;
-       dev->ibdev.create_cq = c2_create_cq;
-       dev->ibdev.destroy_cq = c2_destroy_cq;
-       dev->ibdev.poll_cq = c2_poll_cq;
-       dev->ibdev.get_dma_mr = c2_get_dma_mr;
-       dev->ibdev.reg_user_mr = c2_reg_user_mr;
-       dev->ibdev.dereg_mr = c2_dereg_mr;
-       dev->ibdev.get_port_immutable = c2_port_immutable;
-
-       dev->ibdev.alloc_fmr = NULL;
-       dev->ibdev.unmap_fmr = NULL;
-       dev->ibdev.dealloc_fmr = NULL;
-       dev->ibdev.map_phys_fmr = NULL;
-
-       dev->ibdev.attach_mcast = c2_multicast_attach;
-       dev->ibdev.detach_mcast = c2_multicast_detach;
-       dev->ibdev.process_mad = c2_process_mad;
-
-       dev->ibdev.req_notify_cq = c2_arm_cq;
-       dev->ibdev.post_send = c2_post_send;
-       dev->ibdev.post_recv = c2_post_receive;
-
-       dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
-       if (dev->ibdev.iwcm == NULL) {
-               ret = -ENOMEM;
-               goto out_unregister_netdev;
-       }
-       dev->ibdev.iwcm->add_ref = c2_add_ref;
-       dev->ibdev.iwcm->rem_ref = c2_rem_ref;
-       dev->ibdev.iwcm->get_qp = c2_get_qp;
-       dev->ibdev.iwcm->connect = c2_connect;
-       dev->ibdev.iwcm->accept = c2_accept;
-       dev->ibdev.iwcm->reject = c2_reject;
-       dev->ibdev.iwcm->create_listen = c2_service_create;
-       dev->ibdev.iwcm->destroy_listen = c2_service_destroy;
-
-       ret = ib_register_device(&dev->ibdev, NULL);
-       if (ret)
-               goto out_free_iwcm;
-
-       for (i = 0; i < ARRAY_SIZE(c2_dev_attributes); ++i) {
-               ret = device_create_file(&dev->ibdev.dev,
-                                              c2_dev_attributes[i]);
-               if (ret)
-                       goto out_unregister_ibdev;
-       }
-       goto out;
-
-out_unregister_ibdev:
-       ib_unregister_device(&dev->ibdev);
-out_free_iwcm:
-       kfree(dev->ibdev.iwcm);
-out_unregister_netdev:
-       unregister_netdev(dev->pseudo_netdev);
-out_free_netdev:
-       free_netdev(dev->pseudo_netdev);
-out:
-       pr_debug("%s:%u ret=%d\n", __func__, __LINE__, ret);
-       return ret;
-}
-
-void c2_unregister_device(struct c2_dev *dev)
-{
-       pr_debug("%s:%u\n", __func__, __LINE__);
-       unregister_netdev(dev->pseudo_netdev);
-       free_netdev(dev->pseudo_netdev);
-       ib_unregister_device(&dev->ibdev);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_provider.h b/drivers/staging/rdma/amso1100/c2_provider.h
deleted file mode 100644 (file)
index bf18998..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef C2_PROVIDER_H
-#define C2_PROVIDER_H
-#include <linux/inetdevice.h>
-
-#include <rdma/ib_verbs.h>
-#include <rdma/ib_pack.h>
-
-#include "c2_mq.h"
-#include <rdma/iw_cm.h>
-
-#define C2_MPT_FLAG_ATOMIC        (1 << 14)
-#define C2_MPT_FLAG_REMOTE_WRITE  (1 << 13)
-#define C2_MPT_FLAG_REMOTE_READ   (1 << 12)
-#define C2_MPT_FLAG_LOCAL_WRITE   (1 << 11)
-#define C2_MPT_FLAG_LOCAL_READ    (1 << 10)
-
-struct c2_buf_list {
-       void *buf;
-       DEFINE_DMA_UNMAP_ADDR(mapping);
-};
-
-
-/* The user context keeps track of objects allocated for a
- * particular user-mode client. */
-struct c2_ucontext {
-       struct ib_ucontext ibucontext;
-};
-
-struct c2_mtt;
-
-/* All objects associated with a PD are kept in the
- * associated user context if present.
- */
-struct c2_pd {
-       struct ib_pd ibpd;
-       u32 pd_id;
-};
-
-struct c2_mr {
-       struct ib_mr ibmr;
-       struct c2_pd *pd;
-       struct ib_umem *umem;
-};
-
-struct c2_av;
-
-enum c2_ah_type {
-       C2_AH_ON_HCA,
-       C2_AH_PCI_POOL,
-       C2_AH_KMALLOC
-};
-
-struct c2_ah {
-       struct ib_ah ibah;
-};
-
-struct c2_cq {
-       struct ib_cq ibcq;
-       spinlock_t lock;
-       atomic_t refcount;
-       int cqn;
-       int is_kernel;
-       wait_queue_head_t wait;
-
-       u32 adapter_handle;
-       struct c2_mq mq;
-};
-
-struct c2_wq {
-       spinlock_t lock;
-};
-struct iw_cm_id;
-struct c2_qp {
-       struct ib_qp ibqp;
-       struct iw_cm_id *cm_id;
-       spinlock_t lock;
-       atomic_t refcount;
-       wait_queue_head_t wait;
-       int qpn;
-
-       u32 adapter_handle;
-       u32 send_sgl_depth;
-       u32 recv_sgl_depth;
-       u32 rdma_write_sgl_depth;
-       u8 state;
-
-       struct c2_mq sq_mq;
-       struct c2_mq rq_mq;
-};
-
-struct c2_cr_query_attrs {
-       u32 local_addr;
-       u32 remote_addr;
-       u16 local_port;
-       u16 remote_port;
-};
-
-static inline struct c2_pd *to_c2pd(struct ib_pd *ibpd)
-{
-       return container_of(ibpd, struct c2_pd, ibpd);
-}
-
-static inline struct c2_ucontext *to_c2ucontext(struct ib_ucontext *ibucontext)
-{
-       return container_of(ibucontext, struct c2_ucontext, ibucontext);
-}
-
-static inline struct c2_mr *to_c2mr(struct ib_mr *ibmr)
-{
-       return container_of(ibmr, struct c2_mr, ibmr);
-}
-
-
-static inline struct c2_ah *to_c2ah(struct ib_ah *ibah)
-{
-       return container_of(ibah, struct c2_ah, ibah);
-}
-
-static inline struct c2_cq *to_c2cq(struct ib_cq *ibcq)
-{
-       return container_of(ibcq, struct c2_cq, ibcq);
-}
-
-static inline struct c2_qp *to_c2qp(struct ib_qp *ibqp)
-{
-       return container_of(ibqp, struct c2_qp, ibqp);
-}
-
-static inline int is_rnic_addr(struct net_device *netdev, u32 addr)
-{
-       struct in_device *ind;
-       int ret = 0;
-
-       ind = in_dev_get(netdev);
-       if (!ind)
-               return 0;
-
-       for_ifa(ind) {
-               if (ifa->ifa_address == addr) {
-                       ret = 1;
-                       break;
-               }
-       }
-       endfor_ifa(ind);
-       in_dev_put(ind);
-       return ret;
-}
-#endif                         /* C2_PROVIDER_H */
diff --git a/drivers/staging/rdma/amso1100/c2_qp.c b/drivers/staging/rdma/amso1100/c2_qp.c
deleted file mode 100644 (file)
index ca364db..0000000
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright (c) 2004 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems. All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
- * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include "c2.h"
-#include "c2_vq.h"
-#include "c2_status.h"
-
-#define C2_MAX_ORD_PER_QP 128
-#define C2_MAX_IRD_PER_QP 128
-
-#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
-#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
-#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
-
-#define NO_SUPPORT -1
-static const u8 c2_opcode[] = {
-       [IB_WR_SEND] = C2_WR_TYPE_SEND,
-       [IB_WR_SEND_WITH_IMM] = NO_SUPPORT,
-       [IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,
-       [IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,
-       [IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,
-       [IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,
-       [IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,
-};
-
-static int to_c2_state(enum ib_qp_state ib_state)
-{
-       switch (ib_state) {
-       case IB_QPS_RESET:
-               return C2_QP_STATE_IDLE;
-       case IB_QPS_RTS:
-               return C2_QP_STATE_RTS;
-       case IB_QPS_SQD:
-               return C2_QP_STATE_CLOSING;
-       case IB_QPS_SQE:
-               return C2_QP_STATE_CLOSING;
-       case IB_QPS_ERR:
-               return C2_QP_STATE_ERROR;
-       default:
-               return -1;
-       }
-}
-
-static int to_ib_state(enum c2_qp_state c2_state)
-{
-       switch (c2_state) {
-       case C2_QP_STATE_IDLE:
-               return IB_QPS_RESET;
-       case C2_QP_STATE_CONNECTING:
-               return IB_QPS_RTR;
-       case C2_QP_STATE_RTS:
-               return IB_QPS_RTS;
-       case C2_QP_STATE_CLOSING:
-               return IB_QPS_SQD;
-       case C2_QP_STATE_ERROR:
-               return IB_QPS_ERR;
-       case C2_QP_STATE_TERMINATE:
-               return IB_QPS_SQE;
-       default:
-               return -1;
-       }
-}
-
-static const char *to_ib_state_str(int ib_state)
-{
-       static const char *state_str[] = {
-               "IB_QPS_RESET",
-               "IB_QPS_INIT",
-               "IB_QPS_RTR",
-               "IB_QPS_RTS",
-               "IB_QPS_SQD",
-               "IB_QPS_SQE",
-               "IB_QPS_ERR"
-       };
-       if (ib_state < IB_QPS_RESET ||
-           ib_state > IB_QPS_ERR)
-               return "<invalid IB QP state>";
-
-       ib_state -= IB_QPS_RESET;
-       return state_str[ib_state];
-}
-
-void c2_set_qp_state(struct c2_qp *qp, int c2_state)
-{
-       int new_state = to_ib_state(c2_state);
-
-       pr_debug("%s: qp[%p] state modify %s --> %s\n",
-              __func__,
-               qp,
-               to_ib_state_str(qp->state),
-               to_ib_state_str(new_state));
-       qp->state = new_state;
-}
-
-#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
-
-int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
-                struct ib_qp_attr *attr, int attr_mask)
-{
-       struct c2wr_qp_modify_req wr;
-       struct c2wr_qp_modify_rep *reply;
-       struct c2_vq_req *vq_req;
-       unsigned long flags;
-       u8 next_state;
-       int err;
-
-       pr_debug("%s:%d qp=%p, %s --> %s\n",
-               __func__, __LINE__,
-               qp,
-               to_ib_state_str(qp->state),
-               to_ib_state_str(attr->qp_state));
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       c2_wr_set_id(&wr, CCWR_QP_MODIFY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.qp_handle = qp->adapter_handle;
-       wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-       wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-       wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-       wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-
-       if (attr_mask & IB_QP_STATE) {
-               /* Ensure the state is valid */
-               if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) {
-                       err = -EINVAL;
-                       goto bail0;
-               }
-
-               wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));
-
-               if (attr->qp_state == IB_QPS_ERR) {
-                       spin_lock_irqsave(&qp->lock, flags);
-                       if (qp->cm_id && qp->state == IB_QPS_RTS) {
-                               pr_debug("Generating CLOSE event for QP-->ERR, "
-                                       "qp=%p, cm_id=%p\n",qp,qp->cm_id);
-                               /* Generate an CLOSE event */
-                               vq_req->cm_id = qp->cm_id;
-                               vq_req->event = IW_CM_EVENT_CLOSE;
-                       }
-                       spin_unlock_irqrestore(&qp->lock, flags);
-               }
-               next_state =  attr->qp_state;
-
-       } else if (attr_mask & IB_QP_CUR_STATE) {
-
-               if (attr->cur_qp_state != IB_QPS_RTR &&
-                   attr->cur_qp_state != IB_QPS_RTS &&
-                   attr->cur_qp_state != IB_QPS_SQD &&
-                   attr->cur_qp_state != IB_QPS_SQE) {
-                       err = -EINVAL;
-                       goto bail0;
-               } else
-                       wr.next_qp_state =
-                           cpu_to_be32(to_c2_state(attr->cur_qp_state));
-
-               next_state = attr->cur_qp_state;
-
-       } else {
-               err = 0;
-               goto bail0;
-       }
-
-       /* reference the request struct */
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail0;
-
-       reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       err = c2_errno(reply);
-       if (!err)
-               qp->state = next_state;
-#ifdef DEBUG
-       else
-               pr_debug("%s: c2_errno=%d\n", __func__, err);
-#endif
-       /*
-        * If we're going to error and generating the event here, then
-        * we need to remove the reference because there will be no
-        * close event generated by the adapter
-       */
-       spin_lock_irqsave(&qp->lock, flags);
-       if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) {
-               qp->cm_id->rem_ref(qp->cm_id);
-               qp->cm_id = NULL;
-       }
-       spin_unlock_irqrestore(&qp->lock, flags);
-
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-
-       pr_debug("%s:%d qp=%p, cur_state=%s\n",
-               __func__, __LINE__,
-               qp,
-               to_ib_state_str(qp->state));
-       return err;
-}
-
-int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
-                         int ord, int ird)
-{
-       struct c2wr_qp_modify_req wr;
-       struct c2wr_qp_modify_rep *reply;
-       struct c2_vq_req *vq_req;
-       int err;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       c2_wr_set_id(&wr, CCWR_QP_MODIFY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.qp_handle = qp->adapter_handle;
-       wr.ord = cpu_to_be32(ord);
-       wr.ird = cpu_to_be32(ird);
-       wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-       wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-       wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
-
-       /* reference the request struct */
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail0;
-
-       reply = (struct c2wr_qp_modify_rep *) (unsigned long)
-               vq_req->reply_msg;
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       err = c2_errno(reply);
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp)
-{
-       struct c2_vq_req *vq_req;
-       struct c2wr_qp_destroy_req wr;
-       struct c2wr_qp_destroy_rep *reply;
-       unsigned long flags;
-       int err;
-
-       /*
-        * Allocate a verb request message
-        */
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req) {
-               return -ENOMEM;
-       }
-
-       /*
-        * Initialize the WR
-        */
-       c2_wr_set_id(&wr, CCWR_QP_DESTROY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.qp_handle = qp->adapter_handle;
-
-       /*
-        * reference the request struct.  dereferenced in the int handler.
-        */
-       vq_req_get(c2dev, vq_req);
-
-       spin_lock_irqsave(&qp->lock, flags);
-       if (qp->cm_id && qp->state == IB_QPS_RTS) {
-               pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, "
-                       "qp=%p, cm_id=%p\n",qp,qp->cm_id);
-               /* Generate an CLOSE event */
-               vq_req->qp = qp;
-               vq_req->cm_id = qp->cm_id;
-               vq_req->event = IW_CM_EVENT_CLOSE;
-       }
-       spin_unlock_irqrestore(&qp->lock, flags);
-
-       /*
-        * Send WR to adapter
-        */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       /*
-        * Wait for reply from adapter
-        */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail0;
-       }
-
-       /*
-        * Process reply
-        */
-       reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       spin_lock_irqsave(&qp->lock, flags);
-       if (qp->cm_id) {
-               qp->cm_id->rem_ref(qp->cm_id);
-               qp->cm_id = NULL;
-       }
-       spin_unlock_irqrestore(&qp->lock, flags);
-
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp)
-{
-       int ret;
-
-       idr_preload(GFP_KERNEL);
-       spin_lock_irq(&c2dev->qp_table.lock);
-
-       ret = idr_alloc_cyclic(&c2dev->qp_table.idr, qp, 0, 0, GFP_NOWAIT);
-       if (ret >= 0)
-               qp->qpn = ret;
-
-       spin_unlock_irq(&c2dev->qp_table.lock);
-       idr_preload_end();
-       return ret < 0 ? ret : 0;
-}
-
-static void c2_free_qpn(struct c2_dev *c2dev, int qpn)
-{
-       spin_lock_irq(&c2dev->qp_table.lock);
-       idr_remove(&c2dev->qp_table.idr, qpn);
-       spin_unlock_irq(&c2dev->qp_table.lock);
-}
-
-struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn)
-{
-       unsigned long flags;
-       struct c2_qp *qp;
-
-       spin_lock_irqsave(&c2dev->qp_table.lock, flags);
-       qp = idr_find(&c2dev->qp_table.idr, qpn);
-       spin_unlock_irqrestore(&c2dev->qp_table.lock, flags);
-       return qp;
-}
-
-int c2_alloc_qp(struct c2_dev *c2dev,
-               struct c2_pd *pd,
-               struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp)
-{
-       struct c2wr_qp_create_req wr;
-       struct c2wr_qp_create_rep *reply;
-       struct c2_vq_req *vq_req;
-       struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq);
-       struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq);
-       unsigned long peer_pa;
-       u32 q_size, msg_size, mmap_size;
-       void __iomem *mmap;
-       int err;
-
-       err = c2_alloc_qpn(c2dev, qp);
-       if (err)
-               return err;
-       qp->ibqp.qp_num = qp->qpn;
-       qp->ibqp.qp_type = IB_QPT_RC;
-
-       /* Allocate the SQ and RQ shared pointers */
-       qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                        &qp->sq_mq.shared_dma, GFP_KERNEL);
-       if (!qp->sq_mq.shared) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                        &qp->rq_mq.shared_dma, GFP_KERNEL);
-       if (!qp->rq_mq.shared) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       /* Allocate the verbs request */
-       vq_req = vq_req_alloc(c2dev);
-       if (vq_req == NULL) {
-               err = -ENOMEM;
-               goto bail2;
-       }
-
-       /* Initialize the work request */
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_QP_CREATE);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-       wr.sq_cq_handle = send_cq->adapter_handle;
-       wr.rq_cq_handle = recv_cq->adapter_handle;
-       wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1);
-       wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1);
-       wr.srq_handle = 0;
-       wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND |
-                              QP_ZERO_STAG | QP_RDMA_READ_RESPONSE);
-       wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
-       wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge);
-       wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
-       wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma);
-       wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma);
-       wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP);
-       wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP);
-       wr.pd_id = pd->pd_id;
-       wr.user_context = (unsigned long) qp;
-
-       vq_req_get(c2dev, vq_req);
-
-       /* Send the WR to the adapter */
-       err = vq_send_wr(c2dev, (union c2wr *) & wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail3;
-       }
-
-       /* Wait for the verb reply  */
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail3;
-       }
-
-       /* Process the reply */
-       reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail3;
-       }
-
-       if ((err = c2_wr_get_result(reply)) != 0) {
-               goto bail4;
-       }
-
-       /* Fill in the kernel QP struct */
-       atomic_set(&qp->refcount, 1);
-       qp->adapter_handle = reply->qp_handle;
-       qp->state = IB_QPS_RESET;
-       qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
-       qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
-       qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
-       init_waitqueue_head(&qp->wait);
-
-       /* Initialize the SQ MQ */
-       q_size = be32_to_cpu(reply->sq_depth);
-       msg_size = be32_to_cpu(reply->sq_msg_size);
-       peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start);
-       mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
-       mmap = ioremap_nocache(peer_pa, mmap_size);
-       if (!mmap) {
-               err = -ENOMEM;
-               goto bail5;
-       }
-
-       c2_mq_req_init(&qp->sq_mq,
-                      be32_to_cpu(reply->sq_mq_index),
-                      q_size,
-                      msg_size,
-                      mmap + sizeof(struct c2_mq_shared),      /* pool start */
-                      mmap,                            /* peer */
-                      C2_MQ_ADAPTER_TARGET);
-
-       /* Initialize the RQ mq */
-       q_size = be32_to_cpu(reply->rq_depth);
-       msg_size = be32_to_cpu(reply->rq_msg_size);
-       peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start);
-       mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
-       mmap = ioremap_nocache(peer_pa, mmap_size);
-       if (!mmap) {
-               err = -ENOMEM;
-               goto bail6;
-       }
-
-       c2_mq_req_init(&qp->rq_mq,
-                      be32_to_cpu(reply->rq_mq_index),
-                      q_size,
-                      msg_size,
-                      mmap + sizeof(struct c2_mq_shared),      /* pool start */
-                      mmap,                            /* peer */
-                      C2_MQ_ADAPTER_TARGET);
-
-       vq_repbuf_free(c2dev, reply);
-       vq_req_free(c2dev, vq_req);
-
-       return 0;
-
-bail6:
-       iounmap(qp->sq_mq.peer);
-bail5:
-       destroy_qp(c2dev, qp);
-bail4:
-       vq_repbuf_free(c2dev, reply);
-bail3:
-       vq_req_free(c2dev, vq_req);
-bail2:
-       c2_free_mqsp(qp->rq_mq.shared);
-bail1:
-       c2_free_mqsp(qp->sq_mq.shared);
-bail0:
-       c2_free_qpn(c2dev, qp->qpn);
-       return err;
-}
-
-static inline void c2_lock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)
-{
-       if (send_cq == recv_cq)
-               spin_lock_irq(&send_cq->lock);
-       else if (send_cq > recv_cq) {
-               spin_lock_irq(&send_cq->lock);
-               spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
-       } else {
-               spin_lock_irq(&recv_cq->lock);
-               spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
-       }
-}
-
-static inline void c2_unlock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)
-{
-       if (send_cq == recv_cq)
-               spin_unlock_irq(&send_cq->lock);
-       else if (send_cq > recv_cq) {
-               spin_unlock(&recv_cq->lock);
-               spin_unlock_irq(&send_cq->lock);
-       } else {
-               spin_unlock(&send_cq->lock);
-               spin_unlock_irq(&recv_cq->lock);
-       }
-}
-
-void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
-{
-       struct c2_cq *send_cq;
-       struct c2_cq *recv_cq;
-
-       send_cq = to_c2cq(qp->ibqp.send_cq);
-       recv_cq = to_c2cq(qp->ibqp.recv_cq);
-
-       /*
-        * Lock CQs here, so that CQ polling code can do QP lookup
-        * without taking a lock.
-        */
-       c2_lock_cqs(send_cq, recv_cq);
-       c2_free_qpn(c2dev, qp->qpn);
-       c2_unlock_cqs(send_cq, recv_cq);
-
-       /*
-        * Destroy qp in the rnic...
-        */
-       destroy_qp(c2dev, qp);
-
-       /*
-        * Mark any unreaped CQEs as null and void.
-        */
-       c2_cq_clean(c2dev, qp, send_cq->cqn);
-       if (send_cq != recv_cq)
-               c2_cq_clean(c2dev, qp, recv_cq->cqn);
-       /*
-        * Unmap the MQs and return the shared pointers
-        * to the message pool.
-        */
-       iounmap(qp->sq_mq.peer);
-       iounmap(qp->rq_mq.peer);
-       c2_free_mqsp(qp->sq_mq.shared);
-       c2_free_mqsp(qp->rq_mq.shared);
-
-       atomic_dec(&qp->refcount);
-       wait_event(qp->wait, !atomic_read(&qp->refcount));
-}
-
-/*
- * Function: move_sgl
- *
- * Description:
- * Move an SGL from the user's work request struct into a CCIL Work Request
- * message, swapping to WR byte order and ensure the total length doesn't
- * overflow.
- *
- * IN:
- * dst         - ptr to CCIL Work Request message SGL memory.
- * src         - ptr to the consumers SGL memory.
- *
- * OUT: none
- *
- * Return:
- * CCIL status codes.
- */
-static int
-move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len,
-        u8 * actual_count)
-{
-       u32 tot = 0;            /* running total */
-       u8 acount = 0;          /* running total non-0 len sge's */
-
-       while (count > 0) {
-               /*
-                * If the addition of this SGE causes the
-                * total SGL length to exceed 2^32-1, then
-                * fail-n-bail.
-                *
-                * If the current total plus the next element length
-                * wraps, then it will go negative and be less than the
-                * current total...
-                */
-               if ((tot + src->length) < tot) {
-                       return -EINVAL;
-               }
-               /*
-                * Bug: 1456 (as well as 1498 & 1643)
-                * Skip over any sge's supplied with len=0
-                */
-               if (src->length) {
-                       tot += src->length;
-                       dst->stag = cpu_to_be32(src->lkey);
-                       dst->to = cpu_to_be64(src->addr);
-                       dst->length = cpu_to_be32(src->length);
-                       dst++;
-                       acount++;
-               }
-               src++;
-               count--;
-       }
-
-       if (acount == 0) {
-               /*
-                * Bug: 1476 (as well as 1498, 1456 and 1643)
-                * Setup the SGL in the WR to make it easier for the RNIC.
-                * This way, the FW doesn't have to deal with special cases.
-                * Setting length=0 should be sufficient.
-                */
-               dst->stag = 0;
-               dst->to = 0;
-               dst->length = 0;
-       }
-
-       *p_len = tot;
-       *actual_count = acount;
-       return 0;
-}
-
-/*
- * Function: c2_activity (private function)
- *
- * Description:
- * Post an mq index to the host->adapter activity fifo.
- *
- * IN:
- * c2dev       - ptr to c2dev structure
- * mq_index    - mq index to post
- * shared      - value most recently written to shared
- *
- * OUT:
- *
- * Return:
- * none
- */
-static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)
-{
-       /*
-        * First read the register to see if the FIFO is full, and if so,
-        * spin until it's not.  This isn't perfect -- there is no
-        * synchronization among the clients of the register, but in
-        * practice it prevents multiple CPU from hammering the bus
-        * with PCI RETRY. Note that when this does happen, the card
-        * cannot get on the bus and the card and system hang in a
-        * deadlock -- thus the need for this code. [TOT]
-        */
-       while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000)
-               udelay(10);
-
-       __raw_writel(C2_HINT_MAKE(mq_index, shared),
-                    c2dev->regs + PCI_BAR0_ADAPTER_HINT);
-}
-
-/*
- * Function: qp_wr_post
- *
- * Description:
- * This in-line function allocates a MQ msg, then moves the host-copy of
- * the completed WR into msg.  Then it posts the message.
- *
- * IN:
- * q           - ptr to user MQ.
- * wr          - ptr to host-copy of the WR.
- * qp          - ptr to user qp
- * size                - Number of bytes to post.  Assumed to be divisible by 4.
- *
- * OUT: none
- *
- * Return:
- * CCIL status codes.
- */
-static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size)
-{
-       union c2wr *msg;
-
-       msg = c2_mq_alloc(q);
-       if (msg == NULL) {
-               return -EINVAL;
-       }
-#ifdef CCMSGMAGIC
-       ((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC);
-#endif
-
-       /*
-        * Since all header fields in the WR are the same as the
-        * CQE, set the following so the adapter need not.
-        */
-       c2_wr_set_result(wr, CCERR_PENDING);
-
-       /*
-        * Copy the wr down to the adapter
-        */
-       memcpy((void *) msg, (void *) wr, size);
-
-       c2_mq_produce(q);
-       return 0;
-}
-
-
-int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
-                struct ib_send_wr **bad_wr)
-{
-       struct c2_dev *c2dev = to_c2dev(ibqp->device);
-       struct c2_qp *qp = to_c2qp(ibqp);
-       union c2wr wr;
-       unsigned long lock_flags;
-       int err = 0;
-
-       u32 flags;
-       u32 tot_len;
-       u8 actual_sge_count;
-       u32 msg_size;
-
-       if (qp->state > IB_QPS_RTS) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       while (ib_wr) {
-
-               flags = 0;
-               wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
-               if (ib_wr->send_flags & IB_SEND_SIGNALED) {
-                       flags |= SQ_SIGNALED;
-               }
-
-               switch (ib_wr->opcode) {
-               case IB_WR_SEND:
-               case IB_WR_SEND_WITH_INV:
-                       if (ib_wr->opcode == IB_WR_SEND) {
-                               if (ib_wr->send_flags & IB_SEND_SOLICITED)
-                                       c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE);
-                               else
-                                       c2_wr_set_id(&wr, C2_WR_TYPE_SEND);
-                               wr.sqwr.send.remote_stag = 0;
-                       } else {
-                               if (ib_wr->send_flags & IB_SEND_SOLICITED)
-                                       c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE_INV);
-                               else
-                                       c2_wr_set_id(&wr, C2_WR_TYPE_SEND_INV);
-                               wr.sqwr.send.remote_stag =
-                                       cpu_to_be32(ib_wr->ex.invalidate_rkey);
-                       }
-
-                       msg_size = sizeof(struct c2wr_send_req) +
-                               sizeof(struct c2_data_addr) * ib_wr->num_sge;
-                       if (ib_wr->num_sge > qp->send_sgl_depth) {
-                               err = -EINVAL;
-                               break;
-                       }
-                       if (ib_wr->send_flags & IB_SEND_FENCE) {
-                               flags |= SQ_READ_FENCE;
-                       }
-                       err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data),
-                                      ib_wr->sg_list,
-                                      ib_wr->num_sge,
-                                      &tot_len, &actual_sge_count);
-                       wr.sqwr.send.sge_len = cpu_to_be32(tot_len);
-                       c2_wr_set_sge_count(&wr, actual_sge_count);
-                       break;
-               case IB_WR_RDMA_WRITE:
-                       c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE);
-                       msg_size = sizeof(struct c2wr_rdma_write_req) +
-                           (sizeof(struct c2_data_addr) * ib_wr->num_sge);
-                       if (ib_wr->num_sge > qp->rdma_write_sgl_depth) {
-                               err = -EINVAL;
-                               break;
-                       }
-                       if (ib_wr->send_flags & IB_SEND_FENCE) {
-                               flags |= SQ_READ_FENCE;
-                       }
-                       wr.sqwr.rdma_write.remote_stag =
-                           cpu_to_be32(rdma_wr(ib_wr)->rkey);
-                       wr.sqwr.rdma_write.remote_to =
-                           cpu_to_be64(rdma_wr(ib_wr)->remote_addr);
-                       err = move_sgl((struct c2_data_addr *)
-                                      & (wr.sqwr.rdma_write.data),
-                                      ib_wr->sg_list,
-                                      ib_wr->num_sge,
-                                      &tot_len, &actual_sge_count);
-                       wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len);
-                       c2_wr_set_sge_count(&wr, actual_sge_count);
-                       break;
-               case IB_WR_RDMA_READ:
-                       c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ);
-                       msg_size = sizeof(struct c2wr_rdma_read_req);
-
-                       /* IWarp only suppots 1 sge for RDMA reads */
-                       if (ib_wr->num_sge > 1) {
-                               err = -EINVAL;
-                               break;
-                       }
-
-                       /*
-                        * Move the local and remote stag/to/len into the WR.
-                        */
-                       wr.sqwr.rdma_read.local_stag =
-                           cpu_to_be32(ib_wr->sg_list->lkey);
-                       wr.sqwr.rdma_read.local_to =
-                           cpu_to_be64(ib_wr->sg_list->addr);
-                       wr.sqwr.rdma_read.remote_stag =
-                           cpu_to_be32(rdma_wr(ib_wr)->rkey);
-                       wr.sqwr.rdma_read.remote_to =
-                           cpu_to_be64(rdma_wr(ib_wr)->remote_addr);
-                       wr.sqwr.rdma_read.length =
-                           cpu_to_be32(ib_wr->sg_list->length);
-                       break;
-               default:
-                       /* error */
-                       msg_size = 0;
-                       err = -EINVAL;
-                       break;
-               }
-
-               /*
-                * If we had an error on the last wr build, then
-                * break out.  Possible errors include bogus WR
-                * type, and a bogus SGL length...
-                */
-               if (err) {
-                       break;
-               }
-
-               /*
-                * Store flags
-                */
-               c2_wr_set_flags(&wr, flags);
-
-               /*
-                * Post the puppy!
-                */
-               spin_lock_irqsave(&qp->lock, lock_flags);
-               err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);
-               if (err) {
-                       spin_unlock_irqrestore(&qp->lock, lock_flags);
-                       break;
-               }
-
-               /*
-                * Enqueue mq index to activity FIFO.
-                */
-               c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);
-               spin_unlock_irqrestore(&qp->lock, lock_flags);
-
-               ib_wr = ib_wr->next;
-       }
-
-out:
-       if (err)
-               *bad_wr = ib_wr;
-       return err;
-}
-
-int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
-                   struct ib_recv_wr **bad_wr)
-{
-       struct c2_dev *c2dev = to_c2dev(ibqp->device);
-       struct c2_qp *qp = to_c2qp(ibqp);
-       union c2wr wr;
-       unsigned long lock_flags;
-       int err = 0;
-
-       if (qp->state > IB_QPS_RTS) {
-               err = -EINVAL;
-               goto out;
-       }
-
-       /*
-        * Try and post each work request
-        */
-       while (ib_wr) {
-               u32 tot_len;
-               u8 actual_sge_count;
-
-               if (ib_wr->num_sge > qp->recv_sgl_depth) {
-                       err = -EINVAL;
-                       break;
-               }
-
-               /*
-                * Create local host-copy of the WR
-                */
-               wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
-               c2_wr_set_id(&wr, CCWR_RECV);
-               c2_wr_set_flags(&wr, 0);
-
-               /* sge_count is limited to eight bits. */
-               BUG_ON(ib_wr->num_sge >= 256);
-               err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data),
-                              ib_wr->sg_list,
-                              ib_wr->num_sge, &tot_len, &actual_sge_count);
-               c2_wr_set_sge_count(&wr, actual_sge_count);
-
-               /*
-                * If we had an error on the last wr build, then
-                * break out.  Possible errors include bogus WR
-                * type, and a bogus SGL length...
-                */
-               if (err) {
-                       break;
-               }
-
-               spin_lock_irqsave(&qp->lock, lock_flags);
-               err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);
-               if (err) {
-                       spin_unlock_irqrestore(&qp->lock, lock_flags);
-                       break;
-               }
-
-               /*
-                * Enqueue mq index to activity FIFO
-                */
-               c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);
-               spin_unlock_irqrestore(&qp->lock, lock_flags);
-
-               ib_wr = ib_wr->next;
-       }
-
-out:
-       if (err)
-               *bad_wr = ib_wr;
-       return err;
-}
-
-void c2_init_qp_table(struct c2_dev *c2dev)
-{
-       spin_lock_init(&c2dev->qp_table.lock);
-       idr_init(&c2dev->qp_table.idr);
-}
-
-void c2_cleanup_qp_table(struct c2_dev *c2dev)
-{
-       idr_destroy(&c2dev->qp_table.idr);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_rnic.c b/drivers/staging/rdma/amso1100/c2_rnic.c
deleted file mode 100644 (file)
index 5e65c6d..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/if_vlan.h>
-#include <linux/crc32.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/inet.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-
-#include <linux/route.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <rdma/ib_smi.h>
-#include "c2.h"
-#include "c2_vq.h"
-
-/* Device capabilities */
-#define C2_MIN_PAGESIZE  1024
-
-#define C2_MAX_MRS       32768
-#define C2_MAX_QPS       16000
-#define C2_MAX_WQE_SZ    256
-#define C2_MAX_QP_WR     ((128*1024)/C2_MAX_WQE_SZ)
-#define C2_MAX_SGES      4
-#define C2_MAX_SGE_RD    1
-#define C2_MAX_CQS       32768
-#define C2_MAX_CQES      4096
-#define C2_MAX_PDS       16384
-
-/*
- * Send the adapter INIT message to the amso1100
- */
-static int c2_adapter_init(struct c2_dev *c2dev)
-{
-       struct c2wr_init_req wr;
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_INIT);
-       wr.hdr.context = 0;
-       wr.hint_count = cpu_to_be64(c2dev->hint_count_dma);
-       wr.q0_host_shared = cpu_to_be64(c2dev->req_vq.shared_dma);
-       wr.q1_host_shared = cpu_to_be64(c2dev->rep_vq.shared_dma);
-       wr.q1_host_msg_pool = cpu_to_be64(c2dev->rep_vq.host_dma);
-       wr.q2_host_shared = cpu_to_be64(c2dev->aeq.shared_dma);
-       wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma);
-
-       /* Post the init message */
-       return vq_send_wr(c2dev, (union c2wr *) & wr);
-}
-
-/*
- * Send the adapter TERM message to the amso1100
- */
-static void c2_adapter_term(struct c2_dev *c2dev)
-{
-       struct c2wr_init_req wr;
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_TERM);
-       wr.hdr.context = 0;
-
-       /* Post the init message */
-       vq_send_wr(c2dev, (union c2wr *) & wr);
-       c2dev->init = 0;
-
-       return;
-}
-
-/*
- * Query the adapter
- */
-static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)
-{
-       struct c2_vq_req *vq_req;
-       struct c2wr_rnic_query_req wr;
-       struct c2wr_rnic_query_rep *reply;
-       int err;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       c2_wr_set_id(&wr, CCWR_RNIC_QUERY);
-       wr.hdr.context = (unsigned long) vq_req;
-       wr.rnic_handle = c2dev->adapter_handle;
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) &wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail1;
-
-       reply =
-           (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply)
-               err = -ENOMEM;
-       else
-               err = c2_errno(reply);
-       if (err)
-               goto bail2;
-
-       props->fw_ver =
-               ((u64)be32_to_cpu(reply->fw_ver_major) << 32) |
-               ((be32_to_cpu(reply->fw_ver_minor) & 0xFFFF) << 16) |
-               (be32_to_cpu(reply->fw_ver_patch) & 0xFFFF);
-       memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6);
-       props->max_mr_size         = 0xFFFFFFFF;
-       props->page_size_cap       = ~(C2_MIN_PAGESIZE-1);
-       props->vendor_id           = be32_to_cpu(reply->vendor_id);
-       props->vendor_part_id      = be32_to_cpu(reply->part_number);
-       props->hw_ver              = be32_to_cpu(reply->hw_version);
-       props->max_qp              = be32_to_cpu(reply->max_qps);
-       props->max_qp_wr           = be32_to_cpu(reply->max_qp_depth);
-       props->device_cap_flags    = c2dev->device_cap_flags;
-       props->max_sge             = C2_MAX_SGES;
-       props->max_sge_rd          = C2_MAX_SGE_RD;
-       props->max_cq              = be32_to_cpu(reply->max_cqs);
-       props->max_cqe             = be32_to_cpu(reply->max_cq_depth);
-       props->max_mr              = be32_to_cpu(reply->max_mrs);
-       props->max_pd              = be32_to_cpu(reply->max_pds);
-       props->max_qp_rd_atom      = be32_to_cpu(reply->max_qp_ird);
-       props->max_ee_rd_atom      = 0;
-       props->max_res_rd_atom     = be32_to_cpu(reply->max_global_ird);
-       props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord);
-       props->max_ee_init_rd_atom = 0;
-       props->atomic_cap          = IB_ATOMIC_NONE;
-       props->max_ee              = 0;
-       props->max_rdd             = 0;
-       props->max_mw              = be32_to_cpu(reply->max_mws);
-       props->max_raw_ipv6_qp     = 0;
-       props->max_raw_ethy_qp     = 0;
-       props->max_mcast_grp       = 0;
-       props->max_mcast_qp_attach = 0;
-       props->max_total_mcast_qp_attach = 0;
-       props->max_ah              = 0;
-       props->max_fmr             = 0;
-       props->max_map_per_fmr     = 0;
-       props->max_srq             = 0;
-       props->max_srq_wr          = 0;
-       props->max_srq_sge         = 0;
-       props->max_pkeys           = 0;
-       props->local_ca_ack_delay  = 0;
-
- bail2:
-       vq_repbuf_free(c2dev, reply);
-
- bail1:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-/*
- * Add an IP address to the RNIC interface
- */
-int c2_add_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask)
-{
-       struct c2_vq_req *vq_req;
-       struct c2wr_rnic_setconfig_req *wr;
-       struct c2wr_rnic_setconfig_rep *reply;
-       struct c2_netaddr netaddr;
-       int err, len;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       len = sizeof(struct c2_netaddr);
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
-       wr->hdr.context = (unsigned long) vq_req;
-       wr->rnic_handle = c2dev->adapter_handle;
-       wr->option = cpu_to_be32(C2_CFG_ADD_ADDR);
-
-       netaddr.ip_addr = inaddr;
-       netaddr.netmask = inmask;
-       netaddr.mtu = 0;
-
-       memcpy(wr->data, &netaddr, len);
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail1;
-
-       reply =
-           (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       err = c2_errno(reply);
-       vq_repbuf_free(c2dev, reply);
-
-bail1:
-       kfree(wr);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-/*
- * Delete an IP address from the RNIC interface
- */
-int c2_del_addr(struct c2_dev *c2dev, __be32 inaddr, __be32 inmask)
-{
-       struct c2_vq_req *vq_req;
-       struct c2wr_rnic_setconfig_req *wr;
-       struct c2wr_rnic_setconfig_rep *reply;
-       struct c2_netaddr netaddr;
-       int err, len;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (!vq_req)
-               return -ENOMEM;
-
-       len = sizeof(struct c2_netaddr);
-       wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
-       if (!wr) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
-       wr->hdr.context = (unsigned long) vq_req;
-       wr->rnic_handle = c2dev->adapter_handle;
-       wr->option = cpu_to_be32(C2_CFG_DEL_ADDR);
-
-       netaddr.ip_addr = inaddr;
-       netaddr.netmask = inmask;
-       netaddr.mtu = 0;
-
-       memcpy(wr->data, &netaddr, len);
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, (union c2wr *) wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail1;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err)
-               goto bail1;
-
-       reply =
-           (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       err = c2_errno(reply);
-       vq_repbuf_free(c2dev, reply);
-
-bail1:
-       kfree(wr);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-/*
- * Open a single RNIC instance to use with all
- * low level openib calls
- */
-static int c2_rnic_open(struct c2_dev *c2dev)
-{
-       struct c2_vq_req *vq_req;
-       union c2wr wr;
-       struct c2wr_rnic_open_rep *reply;
-       int err;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (vq_req == NULL) {
-               return -ENOMEM;
-       }
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_RNIC_OPEN);
-       wr.rnic_open.req.hdr.context = (unsigned long) (vq_req);
-       wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE);
-       wr.rnic_open.req.port_num = cpu_to_be16(0);
-       wr.rnic_open.req.user_context = (unsigned long) c2dev;
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, &wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail0;
-       }
-
-       reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       if ((err = c2_errno(reply)) != 0) {
-               goto bail1;
-       }
-
-       c2dev->adapter_handle = reply->rnic_handle;
-
-bail1:
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-/*
- * Close the RNIC instance
- */
-static int c2_rnic_close(struct c2_dev *c2dev)
-{
-       struct c2_vq_req *vq_req;
-       union c2wr wr;
-       struct c2wr_rnic_close_rep *reply;
-       int err;
-
-       vq_req = vq_req_alloc(c2dev);
-       if (vq_req == NULL) {
-               return -ENOMEM;
-       }
-
-       memset(&wr, 0, sizeof(wr));
-       c2_wr_set_id(&wr, CCWR_RNIC_CLOSE);
-       wr.rnic_close.req.hdr.context = (unsigned long) vq_req;
-       wr.rnic_close.req.rnic_handle = c2dev->adapter_handle;
-
-       vq_req_get(c2dev, vq_req);
-
-       err = vq_send_wr(c2dev, &wr);
-       if (err) {
-               vq_req_put(c2dev, vq_req);
-               goto bail0;
-       }
-
-       err = vq_wait_for_reply(c2dev, vq_req);
-       if (err) {
-               goto bail0;
-       }
-
-       reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg);
-       if (!reply) {
-               err = -ENOMEM;
-               goto bail0;
-       }
-
-       if ((err = c2_errno(reply)) != 0) {
-               goto bail1;
-       }
-
-       c2dev->adapter_handle = 0;
-
-bail1:
-       vq_repbuf_free(c2dev, reply);
-bail0:
-       vq_req_free(c2dev, vq_req);
-       return err;
-}
-
-/*
- * Called by c2_probe to initialize the RNIC. This principally
- * involves initializing the various limits and resource pools that
- * comprise the RNIC instance.
- */
-int c2_rnic_init(struct c2_dev *c2dev)
-{
-       int err;
-       u32 qsize, msgsize;
-       void *q1_pages;
-       void *q2_pages;
-       void __iomem *mmio_regs;
-
-       /* Device capabilities */
-       c2dev->device_cap_flags =
-           (IB_DEVICE_RESIZE_MAX_WR |
-            IB_DEVICE_CURR_QP_STATE_MOD |
-            IB_DEVICE_SYS_IMAGE_GUID |
-            IB_DEVICE_LOCAL_DMA_LKEY |
-            IB_DEVICE_MEM_WINDOW);
-
-       /* Allocate the qptr_array */
-       c2dev->qptr_array = vzalloc(C2_MAX_CQS * sizeof(void *));
-       if (!c2dev->qptr_array) {
-               return -ENOMEM;
-       }
-
-       /* Initialize the qptr_array */
-       c2dev->qptr_array[0] = (void *) &c2dev->req_vq;
-       c2dev->qptr_array[1] = (void *) &c2dev->rep_vq;
-       c2dev->qptr_array[2] = (void *) &c2dev->aeq;
-
-       /* Initialize data structures */
-       init_waitqueue_head(&c2dev->req_vq_wo);
-       spin_lock_init(&c2dev->vqlock);
-       spin_lock_init(&c2dev->lock);
-
-       /* Allocate MQ shared pointer pool for kernel clients. User
-        * mode client pools are hung off the user context
-        */
-       err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool);
-       if (err) {
-               goto bail0;
-       }
-
-       /* Allocate shared pointers for Q0, Q1, and Q2 from
-        * the shared pointer pool.
-        */
-
-       c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                            &c2dev->hint_count_dma,
-                                            GFP_KERNEL);
-       c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                            &c2dev->req_vq.shared_dma,
-                                            GFP_KERNEL);
-       c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                            &c2dev->rep_vq.shared_dma,
-                                            GFP_KERNEL);
-       c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
-                                         &c2dev->aeq.shared_dma, GFP_KERNEL);
-       if (!c2dev->hint_count || !c2dev->req_vq.shared ||
-           !c2dev->rep_vq.shared || !c2dev->aeq.shared) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-
-       mmio_regs = c2dev->kva;
-       /* Initialize the Verbs Request Queue */
-       c2_mq_req_init(&c2dev->req_vq, 0,
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_QSIZE)),
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_MSGSIZE)),
-                      mmio_regs +
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_POOLSTART)),
-                      mmio_regs +
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q0_SHARED)),
-                      C2_MQ_ADAPTER_TARGET);
-
-       /* Initialize the Verbs Reply Queue */
-       qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_QSIZE));
-       msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_MSGSIZE));
-       q1_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,
-                                     &c2dev->rep_vq.host_dma, GFP_KERNEL);
-       if (!q1_pages) {
-               err = -ENOMEM;
-               goto bail1;
-       }
-       dma_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma);
-       pr_debug("%s rep_vq va %p dma %llx\n", __func__, q1_pages,
-                (unsigned long long) c2dev->rep_vq.host_dma);
-       c2_mq_rep_init(&c2dev->rep_vq,
-                  1,
-                  qsize,
-                  msgsize,
-                  q1_pages,
-                  mmio_regs +
-                  be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q1_SHARED)),
-                  C2_MQ_HOST_TARGET);
-
-       /* Initialize the Asynchronus Event Queue */
-       qsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_QSIZE));
-       msgsize = be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_MSGSIZE));
-       q2_pages = dma_alloc_coherent(&c2dev->pcidev->dev, qsize * msgsize,
-                                     &c2dev->aeq.host_dma, GFP_KERNEL);
-       if (!q2_pages) {
-               err = -ENOMEM;
-               goto bail2;
-       }
-       dma_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma);
-       pr_debug("%s aeq va %p dma %llx\n", __func__, q2_pages,
-                (unsigned long long) c2dev->aeq.host_dma);
-       c2_mq_rep_init(&c2dev->aeq,
-                      2,
-                      qsize,
-                      msgsize,
-                      q2_pages,
-                      mmio_regs +
-                      be32_to_cpu((__force __be32) readl(mmio_regs + C2_REGS_Q2_SHARED)),
-                      C2_MQ_HOST_TARGET);
-
-       /* Initialize the verbs request allocator */
-       err = vq_init(c2dev);
-       if (err)
-               goto bail3;
-
-       /* Enable interrupts on the adapter */
-       writel(0, c2dev->regs + C2_IDIS);
-
-       /* create the WR init message */
-       err = c2_adapter_init(c2dev);
-       if (err)
-               goto bail4;
-       c2dev->init++;
-
-       /* open an adapter instance */
-       err = c2_rnic_open(c2dev);
-       if (err)
-               goto bail4;
-
-       /* Initialize cached the adapter limits */
-       err = c2_rnic_query(c2dev, &c2dev->props);
-       if (err)
-               goto bail5;
-
-       /* Initialize the PD pool */
-       err = c2_init_pd_table(c2dev);
-       if (err)
-               goto bail5;
-
-       /* Initialize the QP pool */
-       c2_init_qp_table(c2dev);
-       return 0;
-
-bail5:
-       c2_rnic_close(c2dev);
-bail4:
-       vq_term(c2dev);
-bail3:
-       dma_free_coherent(&c2dev->pcidev->dev,
-                         c2dev->aeq.q_size * c2dev->aeq.msg_size,
-                         q2_pages, dma_unmap_addr(&c2dev->aeq, mapping));
-bail2:
-       dma_free_coherent(&c2dev->pcidev->dev,
-                         c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
-                         q1_pages, dma_unmap_addr(&c2dev->rep_vq, mapping));
-bail1:
-       c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
-bail0:
-       vfree(c2dev->qptr_array);
-
-       return err;
-}
-
-/*
- * Called by c2_remove to cleanup the RNIC resources.
- */
-void c2_rnic_term(struct c2_dev *c2dev)
-{
-
-       /* Close the open adapter instance */
-       c2_rnic_close(c2dev);
-
-       /* Send the TERM message to the adapter */
-       c2_adapter_term(c2dev);
-
-       /* Disable interrupts on the adapter */
-       writel(1, c2dev->regs + C2_IDIS);
-
-       /* Free the QP pool */
-       c2_cleanup_qp_table(c2dev);
-
-       /* Free the PD pool */
-       c2_cleanup_pd_table(c2dev);
-
-       /* Free the verbs request allocator */
-       vq_term(c2dev);
-
-       /* Free the asynchronus event queue */
-       dma_free_coherent(&c2dev->pcidev->dev,
-                         c2dev->aeq.q_size * c2dev->aeq.msg_size,
-                         c2dev->aeq.msg_pool.host,
-                         dma_unmap_addr(&c2dev->aeq, mapping));
-
-       /* Free the verbs reply queue */
-       dma_free_coherent(&c2dev->pcidev->dev,
-                         c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
-                         c2dev->rep_vq.msg_pool.host,
-                         dma_unmap_addr(&c2dev->rep_vq, mapping));
-
-       /* Free the MQ shared pointer pool */
-       c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
-
-       /* Free the qptr_array */
-       vfree(c2dev->qptr_array);
-
-       return;
-}
diff --git a/drivers/staging/rdma/amso1100/c2_status.h b/drivers/staging/rdma/amso1100/c2_status.h
deleted file mode 100644 (file)
index 6ee4aa9..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef        _C2_STATUS_H_
-#define _C2_STATUS_H_
-
-/*
- * Verbs Status Codes
- */
-enum c2_status {
-       C2_OK = 0,              /* This must be zero */
-       CCERR_INSUFFICIENT_RESOURCES = 1,
-       CCERR_INVALID_MODIFIER = 2,
-       CCERR_INVALID_MODE = 3,
-       CCERR_IN_USE = 4,
-       CCERR_INVALID_RNIC = 5,
-       CCERR_INTERRUPTED_OPERATION = 6,
-       CCERR_INVALID_EH = 7,
-       CCERR_INVALID_CQ = 8,
-       CCERR_CQ_EMPTY = 9,
-       CCERR_NOT_IMPLEMENTED = 10,
-       CCERR_CQ_DEPTH_TOO_SMALL = 11,
-       CCERR_PD_IN_USE = 12,
-       CCERR_INVALID_PD = 13,
-       CCERR_INVALID_SRQ = 14,
-       CCERR_INVALID_ADDRESS = 15,
-       CCERR_INVALID_NETMASK = 16,
-       CCERR_INVALID_QP = 17,
-       CCERR_INVALID_QP_STATE = 18,
-       CCERR_TOO_MANY_WRS_POSTED = 19,
-       CCERR_INVALID_WR_TYPE = 20,
-       CCERR_INVALID_SGL_LENGTH = 21,
-       CCERR_INVALID_SQ_DEPTH = 22,
-       CCERR_INVALID_RQ_DEPTH = 23,
-       CCERR_INVALID_ORD = 24,
-       CCERR_INVALID_IRD = 25,
-       CCERR_QP_ATTR_CANNOT_CHANGE = 26,
-       CCERR_INVALID_STAG = 27,
-       CCERR_QP_IN_USE = 28,
-       CCERR_OUTSTANDING_WRS = 29,
-       CCERR_STAG_IN_USE = 30,
-       CCERR_INVALID_STAG_INDEX = 31,
-       CCERR_INVALID_SGL_FORMAT = 32,
-       CCERR_ADAPTER_TIMEOUT = 33,
-       CCERR_INVALID_CQ_DEPTH = 34,
-       CCERR_INVALID_PRIVATE_DATA_LENGTH = 35,
-       CCERR_INVALID_EP = 36,
-       CCERR_MR_IN_USE = CCERR_STAG_IN_USE,
-       CCERR_FLUSHED = 38,
-       CCERR_INVALID_WQE = 39,
-       CCERR_LOCAL_QP_CATASTROPHIC_ERROR = 40,
-       CCERR_REMOTE_TERMINATION_ERROR = 41,
-       CCERR_BASE_AND_BOUNDS_VIOLATION = 42,
-       CCERR_ACCESS_VIOLATION = 43,
-       CCERR_INVALID_PD_ID = 44,
-       CCERR_WRAP_ERROR = 45,
-       CCERR_INV_STAG_ACCESS_ERROR = 46,
-       CCERR_ZERO_RDMA_READ_RESOURCES = 47,
-       CCERR_QP_NOT_PRIVILEGED = 48,
-       CCERR_STAG_STATE_NOT_INVALID = 49,
-       CCERR_INVALID_PAGE_SIZE = 50,
-       CCERR_INVALID_BUFFER_SIZE = 51,
-       CCERR_INVALID_PBE = 52,
-       CCERR_INVALID_FBO = 53,
-       CCERR_INVALID_LENGTH = 54,
-       CCERR_INVALID_ACCESS_RIGHTS = 55,
-       CCERR_PBL_TOO_BIG = 56,
-       CCERR_INVALID_VA = 57,
-       CCERR_INVALID_REGION = 58,
-       CCERR_INVALID_WINDOW = 59,
-       CCERR_TOTAL_LENGTH_TOO_BIG = 60,
-       CCERR_INVALID_QP_ID = 61,
-       CCERR_ADDR_IN_USE = 62,
-       CCERR_ADDR_NOT_AVAIL = 63,
-       CCERR_NET_DOWN = 64,
-       CCERR_NET_UNREACHABLE = 65,
-       CCERR_CONN_ABORTED = 66,
-       CCERR_CONN_RESET = 67,
-       CCERR_NO_BUFS = 68,
-       CCERR_CONN_TIMEDOUT = 69,
-       CCERR_CONN_REFUSED = 70,
-       CCERR_HOST_UNREACHABLE = 71,
-       CCERR_INVALID_SEND_SGL_DEPTH = 72,
-       CCERR_INVALID_RECV_SGL_DEPTH = 73,
-       CCERR_INVALID_RDMA_WRITE_SGL_DEPTH = 74,
-       CCERR_INSUFFICIENT_PRIVILEGES = 75,
-       CCERR_STACK_ERROR = 76,
-       CCERR_INVALID_VERSION = 77,
-       CCERR_INVALID_MTU = 78,
-       CCERR_INVALID_IMAGE = 79,
-       CCERR_PENDING = 98,     /* not an error; user internally by adapter */
-       CCERR_DEFER = 99,       /* not an error; used internally by adapter */
-       CCERR_FAILED_WRITE = 100,
-       CCERR_FAILED_ERASE = 101,
-       CCERR_FAILED_VERIFICATION = 102,
-       CCERR_NOT_FOUND = 103,
-
-};
-
-/*
- * CCAE_ACTIVE_CONNECT_RESULTS status result codes.
- */
-enum c2_connect_status {
-       C2_CONN_STATUS_SUCCESS = C2_OK,
-       C2_CONN_STATUS_NO_MEM = CCERR_INSUFFICIENT_RESOURCES,
-       C2_CONN_STATUS_TIMEDOUT = CCERR_CONN_TIMEDOUT,
-       C2_CONN_STATUS_REFUSED = CCERR_CONN_REFUSED,
-       C2_CONN_STATUS_NETUNREACH = CCERR_NET_UNREACHABLE,
-       C2_CONN_STATUS_HOSTUNREACH = CCERR_HOST_UNREACHABLE,
-       C2_CONN_STATUS_INVALID_RNIC = CCERR_INVALID_RNIC,
-       C2_CONN_STATUS_INVALID_QP = CCERR_INVALID_QP,
-       C2_CONN_STATUS_INVALID_QP_STATE = CCERR_INVALID_QP_STATE,
-       C2_CONN_STATUS_REJECTED = CCERR_CONN_RESET,
-       C2_CONN_STATUS_ADDR_NOT_AVAIL = CCERR_ADDR_NOT_AVAIL,
-};
-
-/*
- * Flash programming status codes.
- */
-enum c2_flash_status {
-       C2_FLASH_STATUS_SUCCESS = 0x0000,
-       C2_FLASH_STATUS_VERIFY_ERR = 0x0002,
-       C2_FLASH_STATUS_IMAGE_ERR = 0x0004,
-       C2_FLASH_STATUS_ECLBS = 0x0400,
-       C2_FLASH_STATUS_PSLBS = 0x0800,
-       C2_FLASH_STATUS_VPENS = 0x1000,
-};
-
-#endif                         /* _C2_STATUS_H_ */
diff --git a/drivers/staging/rdma/amso1100/c2_user.h b/drivers/staging/rdma/amso1100/c2_user.h
deleted file mode 100644 (file)
index 7e9e7ad..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2005 Topspin Communications.  All rights reserved.
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-
-#ifndef C2_USER_H
-#define C2_USER_H
-
-#include <linux/types.h>
-
-/*
- * Make sure that all structs defined in this file remain laid out so
- * that they pack the same way on 32-bit and 64-bit architectures (to
- * avoid incompatibility between 32-bit userspace and 64-bit kernels).
- * In particular do not use pointer types -- pass pointers in __u64
- * instead.
- */
-
-struct c2_alloc_ucontext_resp {
-       __u32 qp_tab_size;
-       __u32 uarc_size;
-};
-
-struct c2_alloc_pd_resp {
-       __u32 pdn;
-       __u32 reserved;
-};
-
-struct c2_create_cq {
-       __u32 lkey;
-       __u32 pdn;
-       __u64 arm_db_page;
-       __u64 set_db_page;
-       __u32 arm_db_index;
-       __u32 set_db_index;
-};
-
-struct c2_create_cq_resp {
-       __u32 cqn;
-       __u32 reserved;
-};
-
-struct c2_create_qp {
-       __u32 lkey;
-       __u32 reserved;
-       __u64 sq_db_page;
-       __u64 rq_db_page;
-       __u32 sq_db_index;
-       __u32 rq_db_index;
-};
-
-#endif                         /* C2_USER_H */
diff --git a/drivers/staging/rdma/amso1100/c2_vq.c b/drivers/staging/rdma/amso1100/c2_vq.c
deleted file mode 100644 (file)
index 2ec716f..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-
-#include "c2_vq.h"
-#include "c2_provider.h"
-
-/*
- * Verbs Request Objects:
- *
- * VQ Request Objects are allocated by the kernel verbs handlers.
- * They contain a wait object, a refcnt, an atomic bool indicating that the
- * adapter has replied, and a copy of the verb reply work request.
- * A pointer to the VQ Request Object is passed down in the context
- * field of the work request message, and reflected back by the adapter
- * in the verbs reply message.  The function handle_vq() in the interrupt
- * path will use this pointer to:
- *     1) append a copy of the verbs reply message
- *     2) mark that the reply is ready
- *     3) wake up the kernel verbs handler blocked awaiting the reply.
- *
- *
- * The kernel verbs handlers do a "get" to put a 2nd reference on the
- * VQ Request object.  If the kernel verbs handler exits before the adapter
- * can respond, this extra reference will keep the VQ Request object around
- * until the adapter's reply can be processed.  The reason we need this is
- * because a pointer to this object is stuffed into the context field of
- * the verbs work request message, and reflected back in the reply message.
- * It is used in the interrupt handler (handle_vq()) to wake up the appropriate
- * kernel verb handler that is blocked awaiting the verb reply.
- * So handle_vq() will do a "put" on the object when it's done accessing it.
- * NOTE:  If we guarantee that the kernel verb handler will never bail before
- *        getting the reply, then we don't need these refcnts.
- *
- *
- * VQ Request objects are freed by the kernel verbs handlers only
- * after the verb has been processed, or when the adapter fails and
- * does not reply.
- *
- *
- * Verbs Reply Buffers:
- *
- * VQ Reply bufs are local host memory copies of a
- * outstanding Verb Request reply
- * message.  The are always allocated by the kernel verbs handlers, and _may_ be
- * freed by either the kernel verbs handler -or- the interrupt handler.  The
- * kernel verbs handler _must_ free the repbuf, then free the vq request object
- * in that order.
- */
-
-int vq_init(struct c2_dev *c2dev)
-{
-       sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",
-               (char) ('0' + c2dev->devnum));
-       c2dev->host_msg_cache =
-           kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
-                             SLAB_HWCACHE_ALIGN, NULL);
-       if (c2dev->host_msg_cache == NULL) {
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-void vq_term(struct c2_dev *c2dev)
-{
-       kmem_cache_destroy(c2dev->host_msg_cache);
-}
-
-/* vq_req_alloc - allocate a VQ Request Object and initialize it.
- * The refcnt is set to 1.
- */
-struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
-{
-       struct c2_vq_req *r;
-
-       r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
-       if (r) {
-               init_waitqueue_head(&r->wait_object);
-               r->reply_msg = 0;
-               r->event = 0;
-               r->cm_id = NULL;
-               r->qp = NULL;
-               atomic_set(&r->refcnt, 1);
-               atomic_set(&r->reply_ready, 0);
-       }
-       return r;
-}
-
-
-/* vq_req_free - free the VQ Request Object.  It is assumed the verbs handler
- * has already free the VQ Reply Buffer if it existed.
- */
-void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
-{
-       r->reply_msg = 0;
-       if (atomic_dec_and_test(&r->refcnt)) {
-               kfree(r);
-       }
-}
-
-/* vq_req_get - reference a VQ Request Object.  Done
- * only in the kernel verbs handlers.
- */
-void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
-{
-       atomic_inc(&r->refcnt);
-}
-
-
-/* vq_req_put - dereference and potentially free a VQ Request Object.
- *
- * This is only called by handle_vq() on the
- * interrupt when it is done processing
- * a verb reply message.  If the associated
- * kernel verbs handler has already bailed,
- * then this put will actually free the VQ
- * Request object _and_ the VQ Reply Buffer
- * if it exists.
- */
-void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
-{
-       if (atomic_dec_and_test(&r->refcnt)) {
-               if (r->reply_msg != 0)
-                       vq_repbuf_free(c2dev,
-                                      (void *) (unsigned long) r->reply_msg);
-               kfree(r);
-       }
-}
-
-
-/*
- * vq_repbuf_alloc - allocate a VQ Reply Buffer.
- */
-void *vq_repbuf_alloc(struct c2_dev *c2dev)
-{
-       return kmem_cache_alloc(c2dev->host_msg_cache, GFP_ATOMIC);
-}
-
-/*
- * vq_send_wr - post a verbs request message to the Verbs Request Queue.
- * If a message is not available in the MQ, then block until one is available.
- * NOTE: handle_mq() on the interrupt context will wake up threads blocked here.
- * When the adapter drains the Verbs Request Queue,
- * it inserts MQ index 0 in to the
- * adapter->host activity fifo and interrupts the host.
- */
-int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)
-{
-       void *msg;
-       wait_queue_t __wait;
-
-       /*
-        * grab adapter vq lock
-        */
-       spin_lock(&c2dev->vqlock);
-
-       /*
-        * allocate msg
-        */
-       msg = c2_mq_alloc(&c2dev->req_vq);
-
-       /*
-        * If we cannot get a msg, then we'll wait
-        * When a messages are available, the int handler will wake_up()
-        * any waiters.
-        */
-       while (msg == NULL) {
-               pr_debug("%s:%d no available msg in VQ, waiting...\n",
-                      __func__, __LINE__);
-               init_waitqueue_entry(&__wait, current);
-               add_wait_queue(&c2dev->req_vq_wo, &__wait);
-               spin_unlock(&c2dev->vqlock);
-               for (;;) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (!c2_mq_full(&c2dev->req_vq)) {
-                               break;
-                       }
-                       if (!signal_pending(current)) {
-                               schedule_timeout(1 * HZ);       /* 1 second... */
-                               continue;
-                       }
-                       set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&c2dev->req_vq_wo, &__wait);
-                       return -EINTR;
-               }
-               set_current_state(TASK_RUNNING);
-               remove_wait_queue(&c2dev->req_vq_wo, &__wait);
-               spin_lock(&c2dev->vqlock);
-               msg = c2_mq_alloc(&c2dev->req_vq);
-       }
-
-       /*
-        * copy wr into adapter msg
-        */
-       memcpy(msg, wr, c2dev->req_vq.msg_size);
-
-       /*
-        * post msg
-        */
-       c2_mq_produce(&c2dev->req_vq);
-
-       /*
-        * release adapter vq lock
-        */
-       spin_unlock(&c2dev->vqlock);
-       return 0;
-}
-
-
-/*
- * vq_wait_for_reply - block until the adapter posts a Verb Reply Message.
- */
-int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)
-{
-       if (!wait_event_timeout(req->wait_object,
-                               atomic_read(&req->reply_ready),
-                               60*HZ))
-               return -ETIMEDOUT;
-
-       return 0;
-}
-
-/*
- * vq_repbuf_free - Free a Verbs Reply Buffer.
- */
-void vq_repbuf_free(struct c2_dev *c2dev, void *reply)
-{
-       kmem_cache_free(c2dev->host_msg_cache, reply);
-}
diff --git a/drivers/staging/rdma/amso1100/c2_vq.h b/drivers/staging/rdma/amso1100/c2_vq.h
deleted file mode 100644 (file)
index c1f6cef..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _C2_VQ_H_
-#define _C2_VQ_H_
-#include <linux/sched.h>
-#include "c2.h"
-#include "c2_wr.h"
-#include "c2_provider.h"
-
-struct c2_vq_req {
-       u64 reply_msg;          /* ptr to reply msg */
-       wait_queue_head_t wait_object;  /* wait object for vq reqs */
-       atomic_t reply_ready;   /* set when reply is ready */
-       atomic_t refcnt;        /* used to cancel WRs... */
-       int event;
-       struct iw_cm_id *cm_id;
-       struct c2_qp *qp;
-};
-
-int vq_init(struct c2_dev *c2dev);
-void vq_term(struct c2_dev *c2dev);
-
-struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
-void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
-void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
-void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
-int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
-
-void *vq_repbuf_alloc(struct c2_dev *c2dev);
-void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
-
-int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
-#endif                         /* _C2_VQ_H_ */
diff --git a/drivers/staging/rdma/amso1100/c2_wr.h b/drivers/staging/rdma/amso1100/c2_wr.h
deleted file mode 100644 (file)
index 8d4b4ca..0000000
+++ /dev/null
@@ -1,1520 +0,0 @@
-/*
- * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
- * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _C2_WR_H_
-#define _C2_WR_H_
-
-#ifdef CCDEBUG
-#define CCWR_MAGIC             0xb07700b0
-#endif
-
-#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
-
-/* Maximum allowed size in bytes of private_data exchange
- * on connect.
- */
-#define C2_MAX_PRIVATE_DATA_SIZE 200
-
-/*
- * These types are shared among the adapter, host, and CCIL consumer.
- */
-enum c2_cq_notification_type {
-       C2_CQ_NOTIFICATION_TYPE_NONE = 1,
-       C2_CQ_NOTIFICATION_TYPE_NEXT,
-       C2_CQ_NOTIFICATION_TYPE_NEXT_SE
-};
-
-enum c2_setconfig_cmd {
-       C2_CFG_ADD_ADDR = 1,
-       C2_CFG_DEL_ADDR = 2,
-       C2_CFG_ADD_ROUTE = 3,
-       C2_CFG_DEL_ROUTE = 4
-};
-
-enum c2_getconfig_cmd {
-       C2_GETCONFIG_ROUTES = 1,
-       C2_GETCONFIG_ADDRS
-};
-
-/*
- *  CCIL Work Request Identifiers
- */
-enum c2wr_ids {
-       CCWR_RNIC_OPEN = 1,
-       CCWR_RNIC_QUERY,
-       CCWR_RNIC_SETCONFIG,
-       CCWR_RNIC_GETCONFIG,
-       CCWR_RNIC_CLOSE,
-       CCWR_CQ_CREATE,
-       CCWR_CQ_QUERY,
-       CCWR_CQ_MODIFY,
-       CCWR_CQ_DESTROY,
-       CCWR_QP_CONNECT,
-       CCWR_PD_ALLOC,
-       CCWR_PD_DEALLOC,
-       CCWR_SRQ_CREATE,
-       CCWR_SRQ_QUERY,
-       CCWR_SRQ_MODIFY,
-       CCWR_SRQ_DESTROY,
-       CCWR_QP_CREATE,
-       CCWR_QP_QUERY,
-       CCWR_QP_MODIFY,
-       CCWR_QP_DESTROY,
-       CCWR_NSMR_STAG_ALLOC,
-       CCWR_NSMR_REGISTER,
-       CCWR_NSMR_PBL,
-       CCWR_STAG_DEALLOC,
-       CCWR_NSMR_REREGISTER,
-       CCWR_SMR_REGISTER,
-       CCWR_MR_QUERY,
-       CCWR_MW_ALLOC,
-       CCWR_MW_QUERY,
-       CCWR_EP_CREATE,
-       CCWR_EP_GETOPT,
-       CCWR_EP_SETOPT,
-       CCWR_EP_DESTROY,
-       CCWR_EP_BIND,
-       CCWR_EP_CONNECT,
-       CCWR_EP_LISTEN,
-       CCWR_EP_SHUTDOWN,
-       CCWR_EP_LISTEN_CREATE,
-       CCWR_EP_LISTEN_DESTROY,
-       CCWR_EP_QUERY,
-       CCWR_CR_ACCEPT,
-       CCWR_CR_REJECT,
-       CCWR_CONSOLE,
-       CCWR_TERM,
-       CCWR_FLASH_INIT,
-       CCWR_FLASH,
-       CCWR_BUF_ALLOC,
-       CCWR_BUF_FREE,
-       CCWR_FLASH_WRITE,
-       CCWR_INIT,              /* WARNING: Don't move this ever again! */
-
-
-
-       /* Add new IDs here */
-
-
-
-       /*
-        * WARNING: CCWR_LAST must always be the last verbs id defined!
-        *          All the preceding IDs are fixed, and must not change.
-        *          You can add new IDs, but must not remove or reorder
-        *          any IDs. If you do, YOU will ruin any hope of
-        *          compatibility between versions.
-        */
-       CCWR_LAST,
-
-       /*
-        * Start over at 1 so that arrays indexed by user wr id's
-        * begin at 1.  This is OK since the verbs and user wr id's
-        * are always used on disjoint sets of queues.
-        */
-       /*
-        * The order of the CCWR_SEND_XX verbs must
-        * match the order of the RDMA_OPs
-        */
-       CCWR_SEND = 1,
-       CCWR_SEND_INV,
-       CCWR_SEND_SE,
-       CCWR_SEND_SE_INV,
-       CCWR_RDMA_WRITE,
-       CCWR_RDMA_READ,
-       CCWR_RDMA_READ_INV,
-       CCWR_MW_BIND,
-       CCWR_NSMR_FASTREG,
-       CCWR_STAG_INVALIDATE,
-       CCWR_RECV,
-       CCWR_NOP,
-       CCWR_UNIMPL,
-/* WARNING: This must always be the last user wr id defined! */
-};
-#define RDMA_SEND_OPCODE_FROM_WR_ID(x)   (x+2)
-
-/*
- * SQ/RQ Work Request Types
- */
-enum c2_wr_type {
-       C2_WR_TYPE_SEND = CCWR_SEND,
-       C2_WR_TYPE_SEND_SE = CCWR_SEND_SE,
-       C2_WR_TYPE_SEND_INV = CCWR_SEND_INV,
-       C2_WR_TYPE_SEND_SE_INV = CCWR_SEND_SE_INV,
-       C2_WR_TYPE_RDMA_WRITE = CCWR_RDMA_WRITE,
-       C2_WR_TYPE_RDMA_READ = CCWR_RDMA_READ,
-       C2_WR_TYPE_RDMA_READ_INV_STAG = CCWR_RDMA_READ_INV,
-       C2_WR_TYPE_BIND_MW = CCWR_MW_BIND,
-       C2_WR_TYPE_FASTREG_NSMR = CCWR_NSMR_FASTREG,
-       C2_WR_TYPE_INV_STAG = CCWR_STAG_INVALIDATE,
-       C2_WR_TYPE_RECV = CCWR_RECV,
-       C2_WR_TYPE_NOP = CCWR_NOP,
-};
-
-struct c2_netaddr {
-       __be32 ip_addr;
-       __be32 netmask;
-       u32 mtu;
-};
-
-struct c2_route {
-       u32 ip_addr;            /* 0 indicates the default route */
-       u32 netmask;            /* netmask associated with dst */
-       u32 flags;
-       union {
-               u32 ipaddr;     /* address of the nexthop interface */
-               u8 enaddr[6];
-       } nexthop;
-};
-
-/*
- * A Scatter Gather Entry.
- */
-struct c2_data_addr {
-       __be32 stag;
-       __be32 length;
-       __be64 to;
-};
-
-/*
- * MR and MW flags used by the consumer, RI, and RNIC.
- */
-enum c2_mm_flags {
-       MEM_REMOTE = 0x0001,    /* allow mw binds with remote access. */
-       MEM_VA_BASED = 0x0002,  /* Not Zero-based */
-       MEM_PBL_COMPLETE = 0x0004,      /* PBL array is complete in this msg */
-       MEM_LOCAL_READ = 0x0008,        /* allow local reads */
-       MEM_LOCAL_WRITE = 0x0010,       /* allow local writes */
-       MEM_REMOTE_READ = 0x0020,       /* allow remote reads */
-       MEM_REMOTE_WRITE = 0x0040,      /* allow remote writes */
-       MEM_WINDOW_BIND = 0x0080,       /* binds allowed */
-       MEM_SHARED = 0x0100,    /* set if MR is shared */
-       MEM_STAG_VALID = 0x0200 /* set if STAG is in valid state */
-};
-
-/*
- * CCIL API ACF flags defined in terms of the low level mem flags.
- * This minimizes translation needed in the user API
- */
-enum c2_acf {
-       C2_ACF_LOCAL_READ = MEM_LOCAL_READ,
-       C2_ACF_LOCAL_WRITE = MEM_LOCAL_WRITE,
-       C2_ACF_REMOTE_READ = MEM_REMOTE_READ,
-       C2_ACF_REMOTE_WRITE = MEM_REMOTE_WRITE,
-       C2_ACF_WINDOW_BIND = MEM_WINDOW_BIND
-};
-
-/*
- * Image types of objects written to flash
- */
-#define C2_FLASH_IMG_BITFILE 1
-#define C2_FLASH_IMG_OPTION_ROM 2
-#define C2_FLASH_IMG_VPD 3
-
-/*
- *  to fix bug 1815 we define the max size allowable of the
- *  terminate message (per the IETF spec).Refer to the IETF
- *  protocol specification, section 12.1.6, page 64)
- *  The message is prefixed by 20 types of DDP info.
- *
- *  Then the message has 6 bytes for the terminate control
- *  and DDP segment length info plus a DDP header (either
- *  14 or 18 byts) plus 28 bytes for the RDMA header.
- *  Thus the max size in:
- *  20 + (6 + 18 + 28) = 72
- */
-#define C2_MAX_TERMINATE_MESSAGE_SIZE (72)
-
-/*
- * Build String Length.  It must be the same as C2_BUILD_STR_LEN in ccil_api.h
- */
-#define WR_BUILD_STR_LEN 64
-
-/*
- * WARNING:  All of these structs need to align any 64bit types on
- * 64 bit boundaries!  64bit types include u64 and u64.
- */
-
-/*
- * Clustercore Work Request Header.  Be sensitive to field layout
- * and alignment.
- */
-struct c2wr_hdr {
-       /* wqe_count is part of the cqe.  It is put here so the
-        * adapter can write to it while the wr is pending without
-        * clobbering part of the wr.  This word need not be dma'd
-        * from the host to adapter by libccil, but we copy it anyway
-        * to make the memcpy to the adapter better aligned.
-        */
-       __be32 wqe_count;
-
-       /* Put these fields next so that later 32- and 64-bit
-        * quantities are naturally aligned.
-        */
-       u8 id;
-       u8 result;              /* adapter -> host */
-       u8 sge_count;           /* host -> adapter */
-       u8 flags;               /* host -> adapter */
-
-       u64 context;
-#ifdef CCMSGMAGIC
-       u32 magic;
-       u32 pad;
-#endif
-} __attribute__((packed));
-
-/*
- *------------------------ RNIC ------------------------
- */
-
-/*
- * WR_RNIC_OPEN
- */
-
-/*
- * Flags for the RNIC WRs
- */
-enum c2_rnic_flags {
-       RNIC_IRD_STATIC = 0x0001,
-       RNIC_ORD_STATIC = 0x0002,
-       RNIC_QP_STATIC = 0x0004,
-       RNIC_SRQ_SUPPORTED = 0x0008,
-       RNIC_PBL_BLOCK_MODE = 0x0010,
-       RNIC_SRQ_MODEL_ARRIVAL = 0x0020,
-       RNIC_CQ_OVF_DETECTED = 0x0040,
-       RNIC_PRIV_MODE = 0x0080
-};
-
-struct c2wr_rnic_open_req {
-       struct c2wr_hdr hdr;
-       u64 user_context;
-       __be16 flags;           /* See enum c2_rnic_flags */
-       __be16 port_num;
-} __attribute__((packed));
-
-struct c2wr_rnic_open_rep {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-} __attribute__((packed));
-
-union c2wr_rnic_open {
-       struct c2wr_rnic_open_req req;
-       struct c2wr_rnic_open_rep rep;
-} __attribute__((packed));
-
-struct c2wr_rnic_query_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-} __attribute__((packed));
-
-/*
- * WR_RNIC_QUERY
- */
-struct c2wr_rnic_query_rep {
-       struct c2wr_hdr hdr;
-       u64 user_context;
-       __be32 vendor_id;
-       __be32 part_number;
-       __be32 hw_version;
-       __be32 fw_ver_major;
-       __be32 fw_ver_minor;
-       __be32 fw_ver_patch;
-       char fw_ver_build_str[WR_BUILD_STR_LEN];
-       __be32 max_qps;
-       __be32 max_qp_depth;
-       u32 max_srq_depth;
-       u32 max_send_sgl_depth;
-       u32 max_rdma_sgl_depth;
-       __be32 max_cqs;
-       __be32 max_cq_depth;
-       u32 max_cq_event_handlers;
-       __be32 max_mrs;
-       u32 max_pbl_depth;
-       __be32 max_pds;
-       __be32 max_global_ird;
-       u32 max_global_ord;
-       __be32 max_qp_ird;
-       __be32 max_qp_ord;
-       u32 flags;
-       __be32 max_mws;
-       u32 pbe_range_low;
-       u32 pbe_range_high;
-       u32 max_srqs;
-       u32 page_size;
-} __attribute__((packed));
-
-union c2wr_rnic_query {
-       struct c2wr_rnic_query_req req;
-       struct c2wr_rnic_query_rep rep;
-} __attribute__((packed));
-
-/*
- * WR_RNIC_GETCONFIG
- */
-
-struct c2wr_rnic_getconfig_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 option;             /* see c2_getconfig_cmd_t */
-       u64 reply_buf;
-       u32 reply_buf_len;
-} __attribute__((packed)) ;
-
-struct c2wr_rnic_getconfig_rep {
-       struct c2wr_hdr hdr;
-       u32 option;             /* see c2_getconfig_cmd_t */
-       u32 count_len;          /* length of the number of addresses configured */
-} __attribute__((packed)) ;
-
-union c2wr_rnic_getconfig {
-       struct c2wr_rnic_getconfig_req req;
-       struct c2wr_rnic_getconfig_rep rep;
-} __attribute__((packed)) ;
-
-/*
- * WR_RNIC_SETCONFIG
- */
-struct c2wr_rnic_setconfig_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       __be32 option;          /* See c2_setconfig_cmd_t */
-       /* variable data and pad. See c2_netaddr and c2_route */
-       u8 data[0];
-} __attribute__((packed)) ;
-
-struct c2wr_rnic_setconfig_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_rnic_setconfig {
-       struct c2wr_rnic_setconfig_req req;
-       struct c2wr_rnic_setconfig_rep rep;
-} __attribute__((packed)) ;
-
-/*
- * WR_RNIC_CLOSE
- */
-struct c2wr_rnic_close_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_rnic_close_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_rnic_close {
-       struct c2wr_rnic_close_req req;
-       struct c2wr_rnic_close_rep rep;
-} __attribute__((packed)) ;
-
-/*
- *------------------------ CQ ------------------------
- */
-struct c2wr_cq_create_req {
-       struct c2wr_hdr hdr;
-       __be64 shared_ht;
-       u64 user_context;
-       __be64 msg_pool;
-       u32 rnic_handle;
-       __be32 msg_size;
-       __be32 depth;
-} __attribute__((packed)) ;
-
-struct c2wr_cq_create_rep {
-       struct c2wr_hdr hdr;
-       __be32 mq_index;
-       __be32 adapter_shared;
-       u32 cq_handle;
-} __attribute__((packed)) ;
-
-union c2wr_cq_create {
-       struct c2wr_cq_create_req req;
-       struct c2wr_cq_create_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_cq_modify_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 cq_handle;
-       u32 new_depth;
-       u64 new_msg_pool;
-} __attribute__((packed)) ;
-
-struct c2wr_cq_modify_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_cq_modify {
-       struct c2wr_cq_modify_req req;
-       struct c2wr_cq_modify_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_cq_destroy_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 cq_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_cq_destroy_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_cq_destroy {
-       struct c2wr_cq_destroy_req req;
-       struct c2wr_cq_destroy_rep rep;
-} __attribute__((packed)) ;
-
-/*
- *------------------------ PD ------------------------
- */
-struct c2wr_pd_alloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_pd_alloc_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_pd_alloc {
-       struct c2wr_pd_alloc_req req;
-       struct c2wr_pd_alloc_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_pd_dealloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_pd_dealloc_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_pd_dealloc {
-       struct c2wr_pd_dealloc_req req;
-       struct c2wr_pd_dealloc_rep rep;
-} __attribute__((packed)) ;
-
-/*
- *------------------------ SRQ ------------------------
- */
-struct c2wr_srq_create_req {
-       struct c2wr_hdr hdr;
-       u64 shared_ht;
-       u64 user_context;
-       u32 rnic_handle;
-       u32 srq_depth;
-       u32 srq_limit;
-       u32 sgl_depth;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_srq_create_rep {
-       struct c2wr_hdr hdr;
-       u32 srq_depth;
-       u32 sgl_depth;
-       u32 msg_size;
-       u32 mq_index;
-       u32 mq_start;
-       u32 srq_handle;
-} __attribute__((packed)) ;
-
-union c2wr_srq_create {
-       struct c2wr_srq_create_req req;
-       struct c2wr_srq_create_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_srq_destroy_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 srq_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_srq_destroy_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_srq_destroy {
-       struct c2wr_srq_destroy_req req;
-       struct c2wr_srq_destroy_rep rep;
-} __attribute__((packed)) ;
-
-/*
- *------------------------ QP ------------------------
- */
-enum c2wr_qp_flags {
-       QP_RDMA_READ = 0x00000001,      /* RDMA read enabled? */
-       QP_RDMA_WRITE = 0x00000002,     /* RDMA write enabled? */
-       QP_MW_BIND = 0x00000004,        /* MWs enabled */
-       QP_ZERO_STAG = 0x00000008,      /* enabled? */
-       QP_REMOTE_TERMINATION = 0x00000010,     /* remote end terminated */
-       QP_RDMA_READ_RESPONSE = 0x00000020      /* Remote RDMA read  */
-           /* enabled? */
-};
-
-struct c2wr_qp_create_req {
-       struct c2wr_hdr hdr;
-       __be64 shared_sq_ht;
-       __be64 shared_rq_ht;
-       u64 user_context;
-       u32 rnic_handle;
-       u32 sq_cq_handle;
-       u32 rq_cq_handle;
-       __be32 sq_depth;
-       __be32 rq_depth;
-       u32 srq_handle;
-       u32 srq_limit;
-       __be32 flags;           /* see enum c2wr_qp_flags */
-       __be32 send_sgl_depth;
-       __be32 recv_sgl_depth;
-       __be32 rdma_write_sgl_depth;
-       __be32 ord;
-       __be32 ird;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_create_rep {
-       struct c2wr_hdr hdr;
-       __be32 sq_depth;
-       __be32 rq_depth;
-       u32 send_sgl_depth;
-       u32 recv_sgl_depth;
-       u32 rdma_write_sgl_depth;
-       u32 ord;
-       u32 ird;
-       __be32 sq_msg_size;
-       __be32 sq_mq_index;
-       __be32 sq_mq_start;
-       __be32 rq_msg_size;
-       __be32 rq_mq_index;
-       __be32 rq_mq_start;
-       u32 qp_handle;
-} __attribute__((packed)) ;
-
-union c2wr_qp_create {
-       struct c2wr_qp_create_req req;
-       struct c2wr_qp_create_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_query_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 qp_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_query_rep {
-       struct c2wr_hdr hdr;
-       u64 user_context;
-       u32 rnic_handle;
-       u32 sq_depth;
-       u32 rq_depth;
-       u32 send_sgl_depth;
-       u32 rdma_write_sgl_depth;
-       u32 recv_sgl_depth;
-       u32 ord;
-       u32 ird;
-       u16 qp_state;
-       u16 flags;              /* see c2wr_qp_flags_t */
-       u32 qp_id;
-       u32 local_addr;
-       u32 remote_addr;
-       u16 local_port;
-       u16 remote_port;
-       u32 terminate_msg_length;       /* 0 if not present */
-       u8 data[0];
-       /* Terminate Message in-line here. */
-} __attribute__((packed)) ;
-
-union c2wr_qp_query {
-       struct c2wr_qp_query_req req;
-       struct c2wr_qp_query_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_modify_req {
-       struct c2wr_hdr hdr;
-       u64 stream_msg;
-       u32 stream_msg_length;
-       u32 rnic_handle;
-       u32 qp_handle;
-       __be32 next_qp_state;
-       __be32 ord;
-       __be32 ird;
-       __be32 sq_depth;
-       __be32 rq_depth;
-       u32 llp_ep_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_modify_rep {
-       struct c2wr_hdr hdr;
-       u32 ord;
-       u32 ird;
-       u32 sq_depth;
-       u32 rq_depth;
-       u32 sq_msg_size;
-       u32 sq_mq_index;
-       u32 sq_mq_start;
-       u32 rq_msg_size;
-       u32 rq_mq_index;
-       u32 rq_mq_start;
-} __attribute__((packed)) ;
-
-union c2wr_qp_modify {
-       struct c2wr_qp_modify_req req;
-       struct c2wr_qp_modify_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_destroy_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 qp_handle;
-} __attribute__((packed)) ;
-
-struct c2wr_qp_destroy_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_qp_destroy {
-       struct c2wr_qp_destroy_req req;
-       struct c2wr_qp_destroy_rep rep;
-} __attribute__((packed)) ;
-
-/*
- * The CCWR_QP_CONNECT msg is posted on the verbs request queue.  It can
- * only be posted when a QP is in IDLE state.  After the connect request is
- * submitted to the LLP, the adapter moves the QP to CONNECT_PENDING state.
- * No synchronous reply from adapter to this WR.  The results of
- * connection are passed back in an async event CCAE_ACTIVE_CONNECT_RESULTS
- * See c2wr_ae_active_connect_results_t
- */
-struct c2wr_qp_connect_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 qp_handle;
-       __be32 remote_addr;
-       __be16 remote_port;
-       u16 pad;
-       __be32 private_data_length;
-       u8 private_data[0];     /* Private data in-line. */
-} __attribute__((packed)) ;
-
-struct c2wr_qp_connect {
-       struct c2wr_qp_connect_req req;
-       /* no synchronous reply.         */
-} __attribute__((packed)) ;
-
-
-/*
- *------------------------ MM ------------------------
- */
-
-struct c2wr_nsmr_stag_alloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 pbl_depth;
-       u32 pd_id;
-       u32 flags;
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_stag_alloc_rep {
-       struct c2wr_hdr hdr;
-       u32 pbl_depth;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-union c2wr_nsmr_stag_alloc {
-       struct c2wr_nsmr_stag_alloc_req req;
-       struct c2wr_nsmr_stag_alloc_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_register_req {
-       struct c2wr_hdr hdr;
-       __be64 va;
-       u32 rnic_handle;
-       __be16 flags;
-       u8 stag_key;
-       u8 pad;
-       u32 pd_id;
-       __be32 pbl_depth;
-       __be32 pbe_size;
-       __be32 fbo;
-       __be32 length;
-       __be32 addrs_length;
-       /* array of paddrs (must be aligned on a 64bit boundary) */
-       __be64 paddrs[0];
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_register_rep {
-       struct c2wr_hdr hdr;
-       u32 pbl_depth;
-       __be32 stag_index;
-} __attribute__((packed)) ;
-
-union c2wr_nsmr_register {
-       struct c2wr_nsmr_register_req req;
-       struct c2wr_nsmr_register_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_pbl_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       __be32 flags;
-       __be32 stag_index;
-       __be32 addrs_length;
-       /* array of paddrs (must be aligned on a 64bit boundary) */
-       __be64 paddrs[0];
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_pbl_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_nsmr_pbl {
-       struct c2wr_nsmr_pbl_req req;
-       struct c2wr_nsmr_pbl_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_mr_query_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-struct c2wr_mr_query_rep {
-       struct c2wr_hdr hdr;
-       u8 stag_key;
-       u8 pad[3];
-       u32 pd_id;
-       u32 flags;
-       u32 pbl_depth;
-} __attribute__((packed)) ;
-
-union c2wr_mr_query {
-       struct c2wr_mr_query_req req;
-       struct c2wr_mr_query_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_mw_query_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-struct c2wr_mw_query_rep {
-       struct c2wr_hdr hdr;
-       u8 stag_key;
-       u8 pad[3];
-       u32 pd_id;
-       u32 flags;
-} __attribute__((packed)) ;
-
-union c2wr_mw_query {
-       struct c2wr_mw_query_req req;
-       struct c2wr_mw_query_rep rep;
-} __attribute__((packed)) ;
-
-
-struct c2wr_stag_dealloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       __be32 stag_index;
-} __attribute__((packed)) ;
-
-struct c2wr_stag_dealloc_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed)) ;
-
-union c2wr_stag_dealloc {
-       struct c2wr_stag_dealloc_req req;
-       struct c2wr_stag_dealloc_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_reregister_req {
-       struct c2wr_hdr hdr;
-       u64 va;
-       u32 rnic_handle;
-       u16 flags;
-       u8 stag_key;
-       u8 pad;
-       u32 stag_index;
-       u32 pd_id;
-       u32 pbl_depth;
-       u32 pbe_size;
-       u32 fbo;
-       u32 length;
-       u32 addrs_length;
-       u32 pad1;
-       /* array of paddrs (must be aligned on a 64bit boundary) */
-       u64 paddrs[0];
-} __attribute__((packed)) ;
-
-struct c2wr_nsmr_reregister_rep {
-       struct c2wr_hdr hdr;
-       u32 pbl_depth;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-union c2wr_nsmr_reregister {
-       struct c2wr_nsmr_reregister_req req;
-       struct c2wr_nsmr_reregister_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_smr_register_req {
-       struct c2wr_hdr hdr;
-       u64 va;
-       u32 rnic_handle;
-       u16 flags;
-       u8 stag_key;
-       u8 pad;
-       u32 stag_index;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_smr_register_rep {
-       struct c2wr_hdr hdr;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-union c2wr_smr_register {
-       struct c2wr_smr_register_req req;
-       struct c2wr_smr_register_rep rep;
-} __attribute__((packed)) ;
-
-struct c2wr_mw_alloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 pd_id;
-} __attribute__((packed)) ;
-
-struct c2wr_mw_alloc_rep {
-       struct c2wr_hdr hdr;
-       u32 stag_index;
-} __attribute__((packed)) ;
-
-union c2wr_mw_alloc {
-       struct c2wr_mw_alloc_req req;
-       struct c2wr_mw_alloc_rep rep;
-} __attribute__((packed)) ;
-
-/*
- *------------------------ WRs -----------------------
- */
-
-struct c2wr_user_hdr {
-       struct c2wr_hdr hdr;            /* Has status and WR Type */
-} __attribute__((packed)) ;
-
-enum c2_qp_state {
-       C2_QP_STATE_IDLE = 0x01,
-       C2_QP_STATE_CONNECTING = 0x02,
-       C2_QP_STATE_RTS = 0x04,
-       C2_QP_STATE_CLOSING = 0x08,
-       C2_QP_STATE_TERMINATE = 0x10,
-       C2_QP_STATE_ERROR = 0x20,
-};
-
-/* Completion queue entry. */
-struct c2wr_ce {
-       struct c2wr_hdr hdr;            /* Has status and WR Type */
-       u64 qp_user_context;    /* c2_user_qp_t * */
-       u32 qp_state;           /* Current QP State */
-       u32 handle;             /* QPID or EP Handle */
-       __be32 bytes_rcvd;              /* valid for RECV WCs */
-       u32 stag;
-} __attribute__((packed)) ;
-
-
-/*
- * Flags used for all post-sq WRs.  These must fit in the flags
- * field of the struct c2wr_hdr (eight bits).
- */
-enum {
-       SQ_SIGNALED = 0x01,
-       SQ_READ_FENCE = 0x02,
-       SQ_FENCE = 0x04,
-};
-
-/*
- * Common fields for all post-sq WRs.  Namely the standard header and a
- * secondary header with fields common to all post-sq WRs.
- */
-struct c2_sq_hdr {
-       struct c2wr_user_hdr user_hdr;
-} __attribute__((packed));
-
-/*
- * Same as above but for post-rq WRs.
- */
-struct c2_rq_hdr {
-       struct c2wr_user_hdr user_hdr;
-} __attribute__((packed));
-
-/*
- * use the same struct for all sends.
- */
-struct c2wr_send_req {
-       struct c2_sq_hdr sq_hdr;
-       __be32 sge_len;
-       __be32 remote_stag;
-       u8 data[0];             /* SGE array */
-} __attribute__((packed));
-
-union c2wr_send {
-       struct c2wr_send_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_rdma_write_req {
-       struct c2_sq_hdr sq_hdr;
-       __be64 remote_to;
-       __be32 remote_stag;
-       __be32 sge_len;
-       u8 data[0];             /* SGE array */
-} __attribute__((packed));
-
-union c2wr_rdma_write {
-       struct c2wr_rdma_write_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_rdma_read_req {
-       struct c2_sq_hdr sq_hdr;
-       __be64 local_to;
-       __be64 remote_to;
-       __be32 local_stag;
-       __be32 remote_stag;
-       __be32 length;
-} __attribute__((packed));
-
-union c2wr_rdma_read {
-       struct c2wr_rdma_read_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_mw_bind_req {
-       struct c2_sq_hdr sq_hdr;
-       u64 va;
-       u8 stag_key;
-       u8 pad[3];
-       u32 mw_stag_index;
-       u32 mr_stag_index;
-       u32 length;
-       u32 flags;
-} __attribute__((packed));
-
-union c2wr_mw_bind {
-       struct c2wr_mw_bind_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_nsmr_fastreg_req {
-       struct c2_sq_hdr sq_hdr;
-       u64 va;
-       u8 stag_key;
-       u8 pad[3];
-       u32 stag_index;
-       u32 pbe_size;
-       u32 fbo;
-       u32 length;
-       u32 addrs_length;
-       /* array of paddrs (must be aligned on a 64bit boundary) */
-       u64 paddrs[0];
-} __attribute__((packed));
-
-union c2wr_nsmr_fastreg {
-       struct c2wr_nsmr_fastreg_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_stag_invalidate_req {
-       struct c2_sq_hdr sq_hdr;
-       u8 stag_key;
-       u8 pad[3];
-       u32 stag_index;
-} __attribute__((packed));
-
-union c2wr_stag_invalidate {
-       struct c2wr_stag_invalidate_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-union c2wr_sqwr {
-       struct c2_sq_hdr sq_hdr;
-       struct c2wr_send_req send;
-       struct c2wr_send_req send_se;
-       struct c2wr_send_req send_inv;
-       struct c2wr_send_req send_se_inv;
-       struct c2wr_rdma_write_req rdma_write;
-       struct c2wr_rdma_read_req rdma_read;
-       struct c2wr_mw_bind_req mw_bind;
-       struct c2wr_nsmr_fastreg_req nsmr_fastreg;
-       struct c2wr_stag_invalidate_req stag_inv;
-} __attribute__((packed));
-
-
-/*
- * RQ WRs
- */
-struct c2wr_rqwr {
-       struct c2_rq_hdr rq_hdr;
-       u8 data[0];             /* array of SGEs */
-} __attribute__((packed));
-
-union c2wr_recv {
-       struct c2wr_rqwr req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-/*
- * All AEs start with this header.  Most AEs only need to convey the
- * information in the header.  Some, like LLP connection events, need
- * more info.  The union typdef c2wr_ae_t has all the possible AEs.
- *
- * hdr.context is the user_context from the rnic_open WR.  NULL If this
- * is not affiliated with an rnic
- *
- * hdr.id is the AE identifier (eg;  CCAE_REMOTE_SHUTDOWN,
- * CCAE_LLP_CLOSE_COMPLETE)
- *
- * resource_type is one of:  C2_RES_IND_QP, C2_RES_IND_CQ, C2_RES_IND_SRQ
- *
- * user_context is the context passed down when the host created the resource.
- */
-struct c2wr_ae_hdr {
-       struct c2wr_hdr hdr;
-       u64 user_context;       /* user context for this res. */
-       __be32 resource_type;   /* see enum c2_resource_indicator */
-       __be32 resource;        /* handle for resource */
-       __be32 qp_state;        /* current QP State */
-} __attribute__((packed));
-
-/*
- * After submitting the CCAE_ACTIVE_CONNECT_RESULTS message on the AEQ,
- * the adapter moves the QP into RTS state
- */
-struct c2wr_ae_active_connect_results {
-       struct c2wr_ae_hdr ae_hdr;
-       __be32 laddr;
-       __be32 raddr;
-       __be16 lport;
-       __be16 rport;
-       __be32 private_data_length;
-       u8 private_data[0];     /* data is in-line in the msg. */
-} __attribute__((packed));
-
-/*
- * When connections are established by the stack (and the private data
- * MPA frame is received), the adapter will generate an event to the host.
- * The details of the connection, any private data, and the new connection
- * request handle is passed up via the CCAE_CONNECTION_REQUEST msg on the
- * AE queue:
- */
-struct c2wr_ae_connection_request {
-       struct c2wr_ae_hdr ae_hdr;
-       u32 cr_handle;          /* connreq handle (sock ptr) */
-       __be32 laddr;
-       __be32 raddr;
-       __be16 lport;
-       __be16 rport;
-       __be32 private_data_length;
-       u8 private_data[0];     /* data is in-line in the msg. */
-} __attribute__((packed));
-
-union c2wr_ae {
-       struct c2wr_ae_hdr ae_generic;
-       struct c2wr_ae_active_connect_results ae_active_connect_results;
-       struct c2wr_ae_connection_request ae_connection_request;
-} __attribute__((packed));
-
-struct c2wr_init_req {
-       struct c2wr_hdr hdr;
-       __be64 hint_count;
-       __be64 q0_host_shared;
-       __be64 q1_host_shared;
-       __be64 q1_host_msg_pool;
-       __be64 q2_host_shared;
-       __be64 q2_host_msg_pool;
-} __attribute__((packed));
-
-struct c2wr_init_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed));
-
-union c2wr_init {
-       struct c2wr_init_req req;
-       struct c2wr_init_rep rep;
-} __attribute__((packed));
-
-/*
- * For upgrading flash.
- */
-
-struct c2wr_flash_init_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-} __attribute__((packed));
-
-struct c2wr_flash_init_rep {
-       struct c2wr_hdr hdr;
-       u32 adapter_flash_buf_offset;
-       u32 adapter_flash_len;
-} __attribute__((packed));
-
-union c2wr_flash_init {
-       struct c2wr_flash_init_req req;
-       struct c2wr_flash_init_rep rep;
-} __attribute__((packed));
-
-struct c2wr_flash_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 len;
-} __attribute__((packed));
-
-struct c2wr_flash_rep {
-       struct c2wr_hdr hdr;
-       u32 status;
-} __attribute__((packed));
-
-union c2wr_flash {
-       struct c2wr_flash_req req;
-       struct c2wr_flash_rep rep;
-} __attribute__((packed));
-
-struct c2wr_buf_alloc_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 size;
-} __attribute__((packed));
-
-struct c2wr_buf_alloc_rep {
-       struct c2wr_hdr hdr;
-       u32 offset;             /* 0 if mem not available */
-       u32 size;               /* 0 if mem not available */
-} __attribute__((packed));
-
-union c2wr_buf_alloc {
-       struct c2wr_buf_alloc_req req;
-       struct c2wr_buf_alloc_rep rep;
-} __attribute__((packed));
-
-struct c2wr_buf_free_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 offset;             /* Must match value from alloc */
-       u32 size;               /* Must match value from alloc */
-} __attribute__((packed));
-
-struct c2wr_buf_free_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed));
-
-union c2wr_buf_free {
-       struct c2wr_buf_free_req req;
-       struct c2wr_ce rep;
-} __attribute__((packed));
-
-struct c2wr_flash_write_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 offset;
-       u32 size;
-       u32 type;
-       u32 flags;
-} __attribute__((packed));
-
-struct c2wr_flash_write_rep {
-       struct c2wr_hdr hdr;
-       u32 status;
-} __attribute__((packed));
-
-union c2wr_flash_write {
-       struct c2wr_flash_write_req req;
-       struct c2wr_flash_write_rep rep;
-} __attribute__((packed));
-
-/*
- * Messages for LLP connection setup.
- */
-
-/*
- * Listen Request.  This allocates a listening endpoint to allow passive
- * connection setup.  Newly established LLP connections are passed up
- * via an AE.  See c2wr_ae_connection_request_t
- */
-struct c2wr_ep_listen_create_req {
-       struct c2wr_hdr hdr;
-       u64 user_context;       /* returned in AEs. */
-       u32 rnic_handle;
-       __be32 local_addr;              /* local addr, or 0  */
-       __be16 local_port;              /* 0 means "pick one" */
-       u16 pad;
-       __be32 backlog;         /* tradional tcp listen bl */
-} __attribute__((packed));
-
-struct c2wr_ep_listen_create_rep {
-       struct c2wr_hdr hdr;
-       u32 ep_handle;          /* handle to new listening ep */
-       u16 local_port;         /* resulting port... */
-       u16 pad;
-} __attribute__((packed));
-
-union c2wr_ep_listen_create {
-       struct c2wr_ep_listen_create_req req;
-       struct c2wr_ep_listen_create_rep rep;
-} __attribute__((packed));
-
-struct c2wr_ep_listen_destroy_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 ep_handle;
-} __attribute__((packed));
-
-struct c2wr_ep_listen_destroy_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed));
-
-union c2wr_ep_listen_destroy {
-       struct c2wr_ep_listen_destroy_req req;
-       struct c2wr_ep_listen_destroy_rep rep;
-} __attribute__((packed));
-
-struct c2wr_ep_query_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 ep_handle;
-} __attribute__((packed));
-
-struct c2wr_ep_query_rep {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 local_addr;
-       u32 remote_addr;
-       u16 local_port;
-       u16 remote_port;
-} __attribute__((packed));
-
-union c2wr_ep_query {
-       struct c2wr_ep_query_req req;
-       struct c2wr_ep_query_rep rep;
-} __attribute__((packed));
-
-
-/*
- * The host passes this down to indicate acceptance of a pending iWARP
- * connection.  The cr_handle was obtained from the CONNECTION_REQUEST
- * AE passed up by the adapter.  See c2wr_ae_connection_request_t.
- */
-struct c2wr_cr_accept_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 qp_handle;          /* QP to bind to this LLP conn */
-       u32 ep_handle;          /* LLP  handle to accept */
-       __be32 private_data_length;
-       u8 private_data[0];     /* data in-line in msg. */
-} __attribute__((packed));
-
-/*
- * adapter sends reply when private data is successfully submitted to
- * the LLP.
- */
-struct c2wr_cr_accept_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed));
-
-union c2wr_cr_accept {
-       struct c2wr_cr_accept_req req;
-       struct c2wr_cr_accept_rep rep;
-} __attribute__((packed));
-
-/*
- * The host sends this down if a given iWARP connection request was
- * rejected by the consumer.  The cr_handle was obtained from a
- * previous c2wr_ae_connection_request_t AE sent by the adapter.
- */
-struct  c2wr_cr_reject_req {
-       struct c2wr_hdr hdr;
-       u32 rnic_handle;
-       u32 ep_handle;          /* LLP handle to reject */
-} __attribute__((packed));
-
-/*
- * Dunno if this is needed, but we'll add it for now.  The adapter will
- * send the reject_reply after the LLP endpoint has been destroyed.
- */
-struct  c2wr_cr_reject_rep {
-       struct c2wr_hdr hdr;
-} __attribute__((packed));
-
-union c2wr_cr_reject {
-       struct c2wr_cr_reject_req req;
-       struct c2wr_cr_reject_rep rep;
-} __attribute__((packed));
-
-/*
- * console command.  Used to implement a debug console over the verbs
- * request and reply queues.
- */
-
-/*
- * Console request message.  It contains:
- *     - message hdr with id = CCWR_CONSOLE
- *     - the physaddr/len of host memory to be used for the reply.
- *     - the command string.  eg:  "netstat -s" or "zoneinfo"
- */
-struct c2wr_console_req {
-       struct c2wr_hdr hdr;            /* id = CCWR_CONSOLE */
-       u64 reply_buf;          /* pinned host buf for reply */
-       u32 reply_buf_len;      /* length of reply buffer */
-       u8 command[0];          /* NUL terminated ascii string */
-       /* containing the command req */
-} __attribute__((packed));
-
-/*
- * flags used in the console reply.
- */
-enum c2_console_flags {
-       CONS_REPLY_TRUNCATED = 0x00000001       /* reply was truncated */
-} __attribute__((packed));
-
-/*
- * Console reply message.
- * hdr.result contains the c2_status_t error if the reply was _not_ generated,
- * or C2_OK if the reply was generated.
- */
-struct c2wr_console_rep {
-       struct c2wr_hdr hdr;            /* id = CCWR_CONSOLE */
-       u32 flags;
-} __attribute__((packed));
-
-union c2wr_console {
-       struct c2wr_console_req req;
-       struct c2wr_console_rep rep;
-} __attribute__((packed));
-
-
-/*
- * Giant union with all WRs.  Makes life easier...
- */
-union c2wr {
-       struct c2wr_hdr hdr;
-       struct c2wr_user_hdr user_hdr;
-       union c2wr_rnic_open rnic_open;
-       union c2wr_rnic_query rnic_query;
-       union c2wr_rnic_getconfig rnic_getconfig;
-       union c2wr_rnic_setconfig rnic_setconfig;
-       union c2wr_rnic_close rnic_close;
-       union c2wr_cq_create cq_create;
-       union c2wr_cq_modify cq_modify;
-       union c2wr_cq_destroy cq_destroy;
-       union c2wr_pd_alloc pd_alloc;
-       union c2wr_pd_dealloc pd_dealloc;
-       union c2wr_srq_create srq_create;
-       union c2wr_srq_destroy srq_destroy;
-       union c2wr_qp_create qp_create;
-       union c2wr_qp_query qp_query;
-       union c2wr_qp_modify qp_modify;
-       union c2wr_qp_destroy qp_destroy;
-       struct c2wr_qp_connect qp_connect;
-       union c2wr_nsmr_stag_alloc nsmr_stag_alloc;
-       union c2wr_nsmr_register nsmr_register;
-       union c2wr_nsmr_pbl nsmr_pbl;
-       union c2wr_mr_query mr_query;
-       union c2wr_mw_query mw_query;
-       union c2wr_stag_dealloc stag_dealloc;
-       union c2wr_sqwr sqwr;
-       struct c2wr_rqwr rqwr;
-       struct c2wr_ce ce;
-       union c2wr_ae ae;
-       union c2wr_init init;
-       union c2wr_ep_listen_create ep_listen_create;
-       union c2wr_ep_listen_destroy ep_listen_destroy;
-       union c2wr_cr_accept cr_accept;
-       union c2wr_cr_reject cr_reject;
-       union c2wr_console console;
-       union c2wr_flash_init flash_init;
-       union c2wr_flash flash;
-       union c2wr_buf_alloc buf_alloc;
-       union c2wr_buf_free buf_free;
-       union c2wr_flash_write flash_write;
-} __attribute__((packed));
-
-
-/*
- * Accessors for the wr fields that are packed together tightly to
- * reduce the wr message size.  The wr arguments are void* so that
- * either a struct c2wr*, a struct c2wr_hdr*, or a pointer to any of the types
- * in the struct c2wr union can be passed in.
- */
-static __inline__ u8 c2_wr_get_id(void *wr)
-{
-       return ((struct c2wr_hdr *) wr)->id;
-}
-static __inline__ void c2_wr_set_id(void *wr, u8 id)
-{
-       ((struct c2wr_hdr *) wr)->id = id;
-}
-static __inline__ u8 c2_wr_get_result(void *wr)
-{
-       return ((struct c2wr_hdr *) wr)->result;
-}
-static __inline__ void c2_wr_set_result(void *wr, u8 result)
-{
-       ((struct c2wr_hdr *) wr)->result = result;
-}
-static __inline__ u8 c2_wr_get_flags(void *wr)
-{
-       return ((struct c2wr_hdr *) wr)->flags;
-}
-static __inline__ void c2_wr_set_flags(void *wr, u8 flags)
-{
-       ((struct c2wr_hdr *) wr)->flags = flags;
-}
-static __inline__ u8 c2_wr_get_sge_count(void *wr)
-{
-       return ((struct c2wr_hdr *) wr)->sge_count;
-}
-static __inline__ void c2_wr_set_sge_count(void *wr, u8 sge_count)
-{
-       ((struct c2wr_hdr *) wr)->sge_count = sge_count;
-}
-static __inline__ __be32 c2_wr_get_wqe_count(void *wr)
-{
-       return ((struct c2wr_hdr *) wr)->wqe_count;
-}
-static __inline__ void c2_wr_set_wqe_count(void *wr, u32 wqe_count)
-{
-       ((struct c2wr_hdr *) wr)->wqe_count = wqe_count;
-}
-
-#endif                         /* _C2_WR_H_ */
diff --git a/drivers/staging/rdma/ehca/Kconfig b/drivers/staging/rdma/ehca/Kconfig
deleted file mode 100644 (file)
index 3fadd2a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-config INFINIBAND_EHCA
-       tristate "eHCA support"
-       depends on IBMEBUS
-       ---help---
-       This driver supports the deprecated IBM pSeries eHCA InfiniBand
-       adapter.
-
-       To compile the driver as a module, choose M here. The module
-       will be called ib_ehca.
-
diff --git a/drivers/staging/rdma/ehca/Makefile b/drivers/staging/rdma/ehca/Makefile
deleted file mode 100644 (file)
index 74d284e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#  Authors: Heiko J Schick <schickhj@de.ibm.com>
-#           Christoph Raisch <raisch@de.ibm.com>
-#           Joachim Fenkes <fenkes@de.ibm.com>
-#
-#  Copyright (c) 2005 IBM Corporation
-#
-#  All rights reserved.
-#
-#  This source code is distributed under a dual license of GPL v2.0 and OpenIB BSD.
-
-obj-$(CONFIG_INFINIBAND_EHCA) += ib_ehca.o
-
-ib_ehca-objs  = ehca_main.o ehca_hca.o ehca_mcast.o ehca_pd.o ehca_av.o ehca_eq.o \
-               ehca_cq.o ehca_qp.o ehca_sqp.o ehca_mrmw.o ehca_reqs.o ehca_irq.o \
-               ehca_uverbs.o ipz_pt_fn.o hcp_if.o hcp_phyp.o
-
diff --git a/drivers/staging/rdma/ehca/TODO b/drivers/staging/rdma/ehca/TODO
deleted file mode 100644 (file)
index 199a4a6..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-9/2015
-
-The ehca driver has been deprecated and moved to drivers/staging/rdma.
-It will be removed in the 4.6 merge window.
diff --git a/drivers/staging/rdma/ehca/ehca_av.c b/drivers/staging/rdma/ehca/ehca_av.c
deleted file mode 100644 (file)
index 94e088c..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  address vector functions
- *
- *  Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Khadija Souissi <souissik@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_tools.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-
-static struct kmem_cache *av_cache;
-
-int ehca_calc_ipd(struct ehca_shca *shca, int port,
-                 enum ib_rate path_rate, u32 *ipd)
-{
-       int path = ib_rate_to_mult(path_rate);
-       int link, ret;
-       struct ib_port_attr pa;
-
-       if (path_rate == IB_RATE_PORT_CURRENT) {
-               *ipd = 0;
-               return 0;
-       }
-
-       if (unlikely(path < 0)) {
-               ehca_err(&shca->ib_device, "Invalid static rate! path_rate=%x",
-                        path_rate);
-               return -EINVAL;
-       }
-
-       ret = ehca_query_port(&shca->ib_device, port, &pa);
-       if (unlikely(ret < 0)) {
-               ehca_err(&shca->ib_device, "Failed to query port  ret=%i", ret);
-               return ret;
-       }
-
-       link = ib_width_enum_to_int(pa.active_width) * pa.active_speed;
-
-       if (path >= link)
-               /* no need to throttle if path faster than link */
-               *ipd = 0;
-       else
-               /* IPD = round((link / path) - 1) */
-               *ipd = ((link + (path >> 1)) / path) - 1;
-
-       return 0;
-}
-
-struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
-{
-       int ret;
-       struct ehca_av *av;
-       struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
-                                             ib_device);
-
-       av = kmem_cache_alloc(av_cache, GFP_KERNEL);
-       if (!av) {
-               ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p",
-                        pd, ah_attr);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       av->av.sl = ah_attr->sl;
-       av->av.dlid = ah_attr->dlid;
-       av->av.slid_path_bits = ah_attr->src_path_bits;
-
-       if (ehca_static_rate < 0) {
-               u32 ipd;
-
-               if (ehca_calc_ipd(shca, ah_attr->port_num,
-                                 ah_attr->static_rate, &ipd)) {
-                       ret = -EINVAL;
-                       goto create_ah_exit1;
-               }
-               av->av.ipd = ipd;
-       } else
-               av->av.ipd = ehca_static_rate;
-
-       av->av.lnh = ah_attr->ah_flags;
-       av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
-       av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK,
-                                           ah_attr->grh.traffic_class);
-       av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
-                                           ah_attr->grh.flow_label);
-       av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
-                                           ah_attr->grh.hop_limit);
-       av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B);
-       /* set sgid in grh.word_1 */
-       if (ah_attr->ah_flags & IB_AH_GRH) {
-               int rc;
-               struct ib_port_attr port_attr;
-               union ib_gid gid;
-
-               memset(&port_attr, 0, sizeof(port_attr));
-               rc = ehca_query_port(pd->device, ah_attr->port_num,
-                                    &port_attr);
-               if (rc) { /* invalid port number */
-                       ret = -EINVAL;
-                       ehca_err(pd->device, "Invalid port number "
-                                "ehca_query_port() returned %x "
-                                "pd=%p ah_attr=%p", rc, pd, ah_attr);
-                       goto create_ah_exit1;
-               }
-               memset(&gid, 0, sizeof(gid));
-               rc = ehca_query_gid(pd->device,
-                                   ah_attr->port_num,
-                                   ah_attr->grh.sgid_index, &gid);
-               if (rc) {
-                       ret = -EINVAL;
-                       ehca_err(pd->device, "Failed to retrieve sgid "
-                                "ehca_query_gid() returned %x "
-                                "pd=%p ah_attr=%p", rc, pd, ah_attr);
-                       goto create_ah_exit1;
-               }
-               memcpy(&av->av.grh.word_1, &gid, sizeof(gid));
-       }
-       av->av.pmtu = shca->max_mtu;
-
-       /* dgid comes in grh.word_3 */
-       memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,
-              sizeof(ah_attr->grh.dgid));
-
-       return &av->ib_ah;
-
-create_ah_exit1:
-       kmem_cache_free(av_cache, av);
-
-       return ERR_PTR(ret);
-}
-
-int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
-{
-       struct ehca_av *av;
-       struct ehca_ud_av new_ehca_av;
-       struct ehca_shca *shca = container_of(ah->pd->device, struct ehca_shca,
-                                             ib_device);
-
-       memset(&new_ehca_av, 0, sizeof(new_ehca_av));
-       new_ehca_av.sl = ah_attr->sl;
-       new_ehca_av.dlid = ah_attr->dlid;
-       new_ehca_av.slid_path_bits = ah_attr->src_path_bits;
-       new_ehca_av.ipd = ah_attr->static_rate;
-       new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK,
-                                        (ah_attr->ah_flags & IB_AH_GRH) > 0);
-       new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK,
-                                               ah_attr->grh.traffic_class);
-       new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
-                                                ah_attr->grh.flow_label);
-       new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
-                                                ah_attr->grh.hop_limit);
-       new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b);
-
-       /* set sgid in grh.word_1 */
-       if (ah_attr->ah_flags & IB_AH_GRH) {
-               int rc;
-               struct ib_port_attr port_attr;
-               union ib_gid gid;
-
-               memset(&port_attr, 0, sizeof(port_attr));
-               rc = ehca_query_port(ah->device, ah_attr->port_num,
-                                    &port_attr);
-               if (rc) { /* invalid port number */
-                       ehca_err(ah->device, "Invalid port number "
-                                "ehca_query_port() returned %x "
-                                "ah=%p ah_attr=%p port_num=%x",
-                                rc, ah, ah_attr, ah_attr->port_num);
-                       return -EINVAL;
-               }
-               memset(&gid, 0, sizeof(gid));
-               rc = ehca_query_gid(ah->device,
-                                   ah_attr->port_num,
-                                   ah_attr->grh.sgid_index, &gid);
-               if (rc) {
-                       ehca_err(ah->device, "Failed to retrieve sgid "
-                                "ehca_query_gid() returned %x "
-                                "ah=%p ah_attr=%p port_num=%x "
-                                "sgid_index=%x",
-                                rc, ah, ah_attr, ah_attr->port_num,
-                                ah_attr->grh.sgid_index);
-                       return -EINVAL;
-               }
-               memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));
-       }
-
-       new_ehca_av.pmtu = shca->max_mtu;
-
-       memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,
-              sizeof(ah_attr->grh.dgid));
-
-       av = container_of(ah, struct ehca_av, ib_ah);
-       av->av = new_ehca_av;
-
-       return 0;
-}
-
-int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
-{
-       struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah);
-
-       memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3,
-              sizeof(ah_attr->grh.dgid));
-       ah_attr->sl = av->av.sl;
-
-       ah_attr->dlid = av->av.dlid;
-
-       ah_attr->src_path_bits = av->av.slid_path_bits;
-       ah_attr->static_rate = av->av.ipd;
-       ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh);
-       ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK,
-                                                   av->av.grh.word_0);
-       ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK,
-                                               av->av.grh.word_0);
-       ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK,
-                                                av->av.grh.word_0);
-
-       return 0;
-}
-
-int ehca_destroy_ah(struct ib_ah *ah)
-{
-       kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah));
-
-       return 0;
-}
-
-int ehca_init_av_cache(void)
-{
-       av_cache = kmem_cache_create("ehca_cache_av",
-                                  sizeof(struct ehca_av), 0,
-                                  SLAB_HWCACHE_ALIGN,
-                                  NULL);
-       if (!av_cache)
-               return -ENOMEM;
-       return 0;
-}
-
-void ehca_cleanup_av_cache(void)
-{
-       kmem_cache_destroy(av_cache);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_classes.h b/drivers/staging/rdma/ehca/ehca_classes.h
deleted file mode 100644 (file)
index e8c3387..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Struct definition for eHCA internal structures
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *           Joachim Fenkes <fenkes@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __EHCA_CLASSES_H__
-#define __EHCA_CLASSES_H__
-
-struct ehca_module;
-struct ehca_qp;
-struct ehca_cq;
-struct ehca_eq;
-struct ehca_mr;
-struct ehca_mw;
-struct ehca_pd;
-struct ehca_av;
-
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-#include <rdma/ib_verbs.h>
-#include <rdma/ib_user_verbs.h>
-
-#ifdef CONFIG_PPC64
-#include "ehca_classes_pSeries.h"
-#endif
-#include "ipz_pt_fn.h"
-#include "ehca_qes.h"
-#include "ehca_irq.h"
-
-#define EHCA_EQE_CACHE_SIZE 20
-#define EHCA_MAX_NUM_QUEUES 0xffff
-
-struct ehca_eqe_cache_entry {
-       struct ehca_eqe *eqe;
-       struct ehca_cq *cq;
-};
-
-struct ehca_eq {
-       u32 length;
-       struct ipz_queue ipz_queue;
-       struct ipz_eq_handle ipz_eq_handle;
-       struct work_struct work;
-       struct h_galpas galpas;
-       int is_initialized;
-       struct ehca_pfeq pf;
-       spinlock_t spinlock;
-       struct tasklet_struct interrupt_task;
-       u32 ist;
-       spinlock_t irq_spinlock;
-       struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
-};
-
-struct ehca_sma_attr {
-       u16 lid, lmc, sm_sl, sm_lid;
-       u16 pkey_tbl_len, pkeys[16];
-};
-
-struct ehca_sport {
-       struct ib_cq *ibcq_aqp1;
-       struct ib_qp *ibqp_sqp[2];
-       /* lock to serialze modify_qp() calls for sqp in normal
-        * and irq path (when event PORT_ACTIVE is received first time)
-        */
-       spinlock_t mod_sqp_lock;
-       enum ib_port_state port_state;
-       struct ehca_sma_attr saved_attr;
-       u32 pma_qp_nr;
-};
-
-#define HCA_CAP_MR_PGSIZE_4K  0x80000000
-#define HCA_CAP_MR_PGSIZE_64K 0x40000000
-#define HCA_CAP_MR_PGSIZE_1M  0x20000000
-#define HCA_CAP_MR_PGSIZE_16M 0x10000000
-
-struct ehca_shca {
-       struct ib_device ib_device;
-       struct platform_device *ofdev;
-       u8 num_ports;
-       int hw_level;
-       struct list_head shca_list;
-       struct ipz_adapter_handle ipz_hca_handle;
-       struct ehca_sport sport[2];
-       struct ehca_eq eq;
-       struct ehca_eq neq;
-       struct ehca_mr *maxmr;
-       struct ehca_pd *pd;
-       struct h_galpas galpas;
-       struct mutex modify_mutex;
-       u64 hca_cap;
-       /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
-       u32 hca_cap_mr_pgsize;
-       int max_mtu;
-       int max_num_qps;
-       int max_num_cqs;
-       atomic_t num_cqs;
-       atomic_t num_qps;
-};
-
-struct ehca_pd {
-       struct ib_pd ib_pd;
-       struct ipz_pd fw_pd;
-       /* small queue mgmt */
-       struct mutex lock;
-       struct list_head free[2];
-       struct list_head full[2];
-};
-
-enum ehca_ext_qp_type {
-       EQPT_NORMAL    = 0,
-       EQPT_LLQP      = 1,
-       EQPT_SRQBASE   = 2,
-       EQPT_SRQ       = 3,
-};
-
-/* struct to cache modify_qp()'s parms for GSI/SMI qp */
-struct ehca_mod_qp_parm {
-       int mask;
-       struct ib_qp_attr attr;
-};
-
-#define EHCA_MOD_QP_PARM_MAX 4
-
-#define QMAP_IDX_MASK 0xFFFFULL
-
-/* struct for tracking if cqes have been reported to the application */
-struct ehca_qmap_entry {
-       u16 app_wr_id;
-       u8 reported;
-       u8 cqe_req;
-};
-
-struct ehca_queue_map {
-       struct ehca_qmap_entry *map;
-       unsigned int entries;
-       unsigned int tail;
-       unsigned int left_to_poll;
-       unsigned int next_wqe_idx;   /* Idx to first wqe to be flushed */
-};
-
-/* function to calculate the next index for the qmap */
-static inline unsigned int next_index(unsigned int cur_index, unsigned int limit)
-{
-       unsigned int temp = cur_index + 1;
-       return (temp == limit) ? 0 : temp;
-}
-
-struct ehca_qp {
-       union {
-               struct ib_qp ib_qp;
-               struct ib_srq ib_srq;
-       };
-       u32 qp_type;
-       enum ehca_ext_qp_type ext_type;
-       enum ib_qp_state state;
-       struct ipz_queue ipz_squeue;
-       struct ehca_queue_map sq_map;
-       struct ipz_queue ipz_rqueue;
-       struct ehca_queue_map rq_map;
-       struct h_galpas galpas;
-       u32 qkey;
-       u32 real_qp_num;
-       u32 token;
-       spinlock_t spinlock_s;
-       spinlock_t spinlock_r;
-       u32 sq_max_inline_data_size;
-       struct ipz_qp_handle ipz_qp_handle;
-       struct ehca_pfqp pf;
-       struct ib_qp_init_attr init_attr;
-       struct ehca_cq *send_cq;
-       struct ehca_cq *recv_cq;
-       unsigned int sqerr_purgeflag;
-       struct hlist_node list_entries;
-       /* array to cache modify_qp()'s parms for GSI/SMI qp */
-       struct ehca_mod_qp_parm *mod_qp_parm;
-       int mod_qp_parm_idx;
-       /* mmap counter for resources mapped into user space */
-       u32 mm_count_squeue;
-       u32 mm_count_rqueue;
-       u32 mm_count_galpa;
-       /* unsolicited ack circumvention */
-       int unsol_ack_circ;
-       int mtu_shift;
-       u32 message_count;
-       u32 packet_count;
-       atomic_t nr_events; /* events seen */
-       wait_queue_head_t wait_completion;
-       int mig_armed;
-       struct list_head sq_err_node;
-       struct list_head rq_err_node;
-};
-
-#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
-#define HAS_SQ(qp) (qp->ext_type != EQPT_SRQ)
-#define HAS_RQ(qp) (qp->ext_type != EQPT_SRQBASE)
-
-/* must be power of 2 */
-#define QP_HASHTAB_LEN 8
-
-struct ehca_cq {
-       struct ib_cq ib_cq;
-       struct ipz_queue ipz_queue;
-       struct h_galpas galpas;
-       spinlock_t spinlock;
-       u32 cq_number;
-       u32 token;
-       u32 nr_of_entries;
-       struct ipz_cq_handle ipz_cq_handle;
-       struct ehca_pfcq pf;
-       spinlock_t cb_lock;
-       struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
-       struct list_head entry;
-       u32 nr_callbacks;   /* #events assigned to cpu by scaling code */
-       atomic_t nr_events; /* #events seen */
-       wait_queue_head_t wait_completion;
-       spinlock_t task_lock;
-       /* mmap counter for resources mapped into user space */
-       u32 mm_count_queue;
-       u32 mm_count_galpa;
-       struct list_head sqp_err_list;
-       struct list_head rqp_err_list;
-};
-
-enum ehca_mr_flag {
-       EHCA_MR_FLAG_FMR = 0x80000000,   /* FMR, created with ehca_alloc_fmr */
-       EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR                           */
-};
-
-struct ehca_mr {
-       union {
-               struct ib_mr ib_mr;     /* must always be first in ehca_mr */
-               struct ib_fmr ib_fmr;   /* must always be first in ehca_mr */
-       } ib;
-       struct ib_umem *umem;
-       spinlock_t mrlock;
-
-       enum ehca_mr_flag flags;
-       u32 num_kpages;         /* number of kernel pages */
-       u32 num_hwpages;        /* number of hw pages to form MR */
-       u64 hwpage_size;        /* hw page size used for this MR */
-       int acl;                /* ACL (stored here for usage in reregister) */
-       u64 *start;             /* virtual start address (stored here for */
-                               /* usage in reregister) */
-       u64 size;               /* size (stored here for usage in reregister) */
-       u32 fmr_page_size;      /* page size for FMR */
-       u32 fmr_max_pages;      /* max pages for FMR */
-       u32 fmr_max_maps;       /* max outstanding maps for FMR */
-       u32 fmr_map_cnt;        /* map counter for FMR */
-       /* fw specific data */
-       struct ipz_mrmw_handle ipz_mr_handle;   /* MR handle for h-calls */
-       struct h_galpas galpas;
-};
-
-struct ehca_mw {
-       struct ib_mw ib_mw;     /* gen2 mw, must always be first in ehca_mw */
-       spinlock_t mwlock;
-
-       u8 never_bound;         /* indication MW was never bound */
-       struct ipz_mrmw_handle ipz_mw_handle;   /* MW handle for h-calls */
-       struct h_galpas galpas;
-};
-
-enum ehca_mr_pgi_type {
-       EHCA_MR_PGI_PHYS   = 1,  /* type of ehca_reg_phys_mr,
-                                 * ehca_rereg_phys_mr,
-                                 * ehca_reg_internal_maxmr */
-       EHCA_MR_PGI_USER   = 2,  /* type of ehca_reg_user_mr */
-       EHCA_MR_PGI_FMR    = 3   /* type of ehca_map_phys_fmr */
-};
-
-struct ehca_mr_pginfo {
-       enum ehca_mr_pgi_type type;
-       u64 num_kpages;
-       u64 kpage_cnt;
-       u64 hwpage_size;     /* hw page size used for this MR */
-       u64 num_hwpages;     /* number of hw pages */
-       u64 hwpage_cnt;      /* counter for hw pages */
-       u64 next_hwpage;     /* next hw page in buffer/chunk/listelem */
-
-       union {
-               struct { /* type EHCA_MR_PGI_PHYS section */
-                       u64 addr;
-                       u16 size;
-               } phy;
-               struct { /* type EHCA_MR_PGI_USER section */
-                       struct ib_umem *region;
-                       struct scatterlist *next_sg;
-                       u64 next_nmap;
-               } usr;
-               struct { /* type EHCA_MR_PGI_FMR section */
-                       u64 fmr_pgsize;
-                       u64 *page_list;
-                       u64 next_listelem;
-               } fmr;
-       } u;
-};
-
-/* output parameters for MR/FMR hipz calls */
-struct ehca_mr_hipzout_parms {
-       struct ipz_mrmw_handle handle;
-       u32 lkey;
-       u32 rkey;
-       u64 len;
-       u64 vaddr;
-       u32 acl;
-};
-
-/* output parameters for MW hipz calls */
-struct ehca_mw_hipzout_parms {
-       struct ipz_mrmw_handle handle;
-       u32 rkey;
-};
-
-struct ehca_av {
-       struct ib_ah ib_ah;
-       struct ehca_ud_av av;
-};
-
-struct ehca_ucontext {
-       struct ib_ucontext ib_ucontext;
-};
-
-int ehca_init_pd_cache(void);
-void ehca_cleanup_pd_cache(void);
-int ehca_init_cq_cache(void);
-void ehca_cleanup_cq_cache(void);
-int ehca_init_qp_cache(void);
-void ehca_cleanup_qp_cache(void);
-int ehca_init_av_cache(void);
-void ehca_cleanup_av_cache(void);
-int ehca_init_mrmw_cache(void);
-void ehca_cleanup_mrmw_cache(void);
-int ehca_init_small_qp_cache(void);
-void ehca_cleanup_small_qp_cache(void);
-
-extern rwlock_t ehca_qp_idr_lock;
-extern rwlock_t ehca_cq_idr_lock;
-extern struct idr ehca_qp_idr;
-extern struct idr ehca_cq_idr;
-extern spinlock_t shca_list_lock;
-
-extern int ehca_static_rate;
-extern int ehca_port_act_time;
-extern bool ehca_use_hp_mr;
-extern bool ehca_scaling_code;
-extern int ehca_lock_hcalls;
-extern int ehca_nr_ports;
-extern int ehca_max_cq;
-extern int ehca_max_qp;
-
-struct ipzu_queue_resp {
-       u32 qe_size;      /* queue entry size */
-       u32 act_nr_of_sg;
-       u32 queue_length; /* queue length allocated in bytes */
-       u32 pagesize;
-       u32 toggle_state;
-       u32 offset; /* save offset within a page for small_qp */
-};
-
-struct ehca_create_cq_resp {
-       u32 cq_number;
-       u32 token;
-       struct ipzu_queue_resp ipz_queue;
-       u32 fw_handle_ofs;
-       u32 dummy;
-};
-
-struct ehca_create_qp_resp {
-       u32 qp_num;
-       u32 token;
-       u32 qp_type;
-       u32 ext_type;
-       u32 qkey;
-       /* qp_num assigned by ehca: sqp0/1 may have got different numbers */
-       u32 real_qp_num;
-       u32 fw_handle_ofs;
-       u32 dummy;
-       struct ipzu_queue_resp ipz_squeue;
-       struct ipzu_queue_resp ipz_rqueue;
-};
-
-struct ehca_alloc_cq_parms {
-       u32 nr_cqe;
-       u32 act_nr_of_entries;
-       u32 act_pages;
-       struct ipz_eq_handle eq_handle;
-};
-
-enum ehca_service_type {
-       ST_RC  = 0,
-       ST_UC  = 1,
-       ST_RD  = 2,
-       ST_UD  = 3,
-};
-
-enum ehca_ll_comp_flags {
-       LLQP_SEND_COMP = 0x20,
-       LLQP_RECV_COMP = 0x40,
-       LLQP_COMP_MASK = 0x60,
-};
-
-struct ehca_alloc_queue_parms {
-       /* input parameters */
-       int max_wr;
-       int max_sge;
-       int page_size;
-       int is_small;
-
-       /* output parameters */
-       u16 act_nr_wqes;
-       u8  act_nr_sges;
-       u32 queue_size; /* bytes for small queues, pages otherwise */
-};
-
-struct ehca_alloc_qp_parms {
-       struct ehca_alloc_queue_parms squeue;
-       struct ehca_alloc_queue_parms rqueue;
-
-       /* input parameters */
-       enum ehca_service_type servicetype;
-       int qp_storage;
-       int sigtype;
-       enum ehca_ext_qp_type ext_type;
-       enum ehca_ll_comp_flags ll_comp_flags;
-       int ud_av_l_key_ctl;
-
-       u32 token;
-       struct ipz_eq_handle eq_handle;
-       struct ipz_pd pd;
-       struct ipz_cq_handle send_cq_handle, recv_cq_handle;
-
-       u32 srq_qpn, srq_token, srq_limit;
-
-       /* output parameters */
-       u32 real_qp_num;
-       struct ipz_qp_handle qp_handle;
-       struct h_galpas galpas;
-};
-
-int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
-int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
-
-#endif
diff --git a/drivers/staging/rdma/ehca/ehca_classes_pSeries.h b/drivers/staging/rdma/ehca/ehca_classes_pSeries.h
deleted file mode 100644 (file)
index 689c357..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  pSeries interface definitions
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __EHCA_CLASSES_PSERIES_H__
-#define __EHCA_CLASSES_PSERIES_H__
-
-#include "hcp_phyp.h"
-#include "ipz_pt_fn.h"
-
-
-struct ehca_pfqp {
-       struct ipz_qpt sqpt;
-       struct ipz_qpt rqpt;
-};
-
-struct ehca_pfcq {
-       struct ipz_qpt qpt;
-       u32 cqnr;
-};
-
-struct ehca_pfeq {
-       struct ipz_qpt qpt;
-       struct h_galpa galpa;
-       u32 eqnr;
-};
-
-struct ipz_adapter_handle {
-       u64 handle;
-};
-
-struct ipz_cq_handle {
-       u64 handle;
-};
-
-struct ipz_eq_handle {
-       u64 handle;
-};
-
-struct ipz_qp_handle {
-       u64 handle;
-};
-struct ipz_mrmw_handle {
-       u64 handle;
-};
-
-struct ipz_pd {
-       u32 value;
-};
-
-struct hcp_modify_qp_control_block {
-       u32 qkey;                      /* 00 */
-       u32 rdd;                       /* reliable datagram domain */
-       u32 send_psn;                  /* 02 */
-       u32 receive_psn;               /* 03 */
-       u32 prim_phys_port;            /* 04 */
-       u32 alt_phys_port;             /* 05 */
-       u32 prim_p_key_idx;            /* 06 */
-       u32 alt_p_key_idx;             /* 07 */
-       u32 rdma_atomic_ctrl;          /* 08 */
-       u32 qp_state;                  /* 09 */
-       u32 reserved_10;               /* 10 */
-       u32 rdma_nr_atomic_resp_res;   /* 11 */
-       u32 path_migration_state;      /* 12 */
-       u32 rdma_atomic_outst_dest_qp; /* 13 */
-       u32 dest_qp_nr;                /* 14 */
-       u32 min_rnr_nak_timer_field;   /* 15 */
-       u32 service_level;             /* 16 */
-       u32 send_grh_flag;             /* 17 */
-       u32 retry_count;               /* 18 */
-       u32 timeout;                   /* 19 */
-       u32 path_mtu;                  /* 20 */
-       u32 max_static_rate;           /* 21 */
-       u32 dlid;                      /* 22 */
-       u32 rnr_retry_count;           /* 23 */
-       u32 source_path_bits;          /* 24 */
-       u32 traffic_class;             /* 25 */
-       u32 hop_limit;                 /* 26 */
-       u32 source_gid_idx;            /* 27 */
-       u32 flow_label;                /* 28 */
-       u32 reserved_29;               /* 29 */
-       union {                        /* 30 */
-               u64 dw[2];
-               u8 byte[16];
-       } dest_gid;
-       u32 service_level_al;          /* 34 */
-       u32 send_grh_flag_al;          /* 35 */
-       u32 retry_count_al;            /* 36 */
-       u32 timeout_al;                /* 37 */
-       u32 max_static_rate_al;        /* 38 */
-       u32 dlid_al;                   /* 39 */
-       u32 rnr_retry_count_al;        /* 40 */
-       u32 source_path_bits_al;       /* 41 */
-       u32 traffic_class_al;          /* 42 */
-       u32 hop_limit_al;              /* 43 */
-       u32 source_gid_idx_al;         /* 44 */
-       u32 flow_label_al;             /* 45 */
-       u32 reserved_46;               /* 46 */
-       u32 reserved_47;               /* 47 */
-       union {                        /* 48 */
-               u64 dw[2];
-               u8 byte[16];
-       } dest_gid_al;
-       u32 max_nr_outst_send_wr;      /* 52 */
-       u32 max_nr_outst_recv_wr;      /* 53 */
-       u32 disable_ete_credit_check;  /* 54 */
-       u32 qp_number;                 /* 55 */
-       u64 send_queue_handle;         /* 56 */
-       u64 recv_queue_handle;         /* 58 */
-       u32 actual_nr_sges_in_sq_wqe;  /* 60 */
-       u32 actual_nr_sges_in_rq_wqe;  /* 61 */
-       u32 qp_enable;                 /* 62 */
-       u32 curr_srq_limit;            /* 63 */
-       u64 qp_aff_asyn_ev_log_reg;    /* 64 */
-       u64 shared_rq_hndl;            /* 66 */
-       u64 trigg_doorbell_qp_hndl;    /* 68 */
-       u32 reserved_70_127[58];       /* 70 */
-};
-
-#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM( 0,  0)
-#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM( 2,  2)
-#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM( 3,  3)
-#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM( 4,  4)
-#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24, 31)
-#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM( 5,  5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM( 6,  6)
-#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24, 31)
-#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM( 7,  7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM( 8,  8)
-#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM( 9,  9)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11, 11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12, 12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13, 13)
-#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14, 14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15, 15)
-#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16, 16)
-#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17, 17)
-#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18, 18)
-#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19, 19)
-#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20, 20)
-#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21, 21)
-#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22, 22)
-#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23, 23)
-#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24, 24)
-#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25, 25)
-#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26, 26)
-#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27, 27)
-#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28, 28)
-#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30, 30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31, 31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32, 32)
-#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33, 33)
-#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34, 34)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35, 35)
-#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36, 36)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37, 37)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38, 38)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39, 39)
-#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40, 40)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41, 41)
-#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42, 42)
-#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44, 44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45, 45)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46, 46)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47, 47)
-#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48, 48)
-#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49, 49)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50, 50)
-#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51, 51)
-
-#endif /* __EHCA_CLASSES_PSERIES_H__ */
diff --git a/drivers/staging/rdma/ehca/ehca_cq.c b/drivers/staging/rdma/ehca/ehca_cq.c
deleted file mode 100644 (file)
index 1aa7931..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Completion queue handling
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Khadija Souissi <souissi@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_iverbs.h"
-#include "ehca_classes.h"
-#include "ehca_irq.h"
-#include "hcp_if.h"
-
-static struct kmem_cache *cq_cache;
-
-int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
-{
-       unsigned int qp_num = qp->real_qp_num;
-       unsigned int key = qp_num & (QP_HASHTAB_LEN-1);
-       unsigned long flags;
-
-       spin_lock_irqsave(&cq->spinlock, flags);
-       hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]);
-       spin_unlock_irqrestore(&cq->spinlock, flags);
-
-       ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x",
-                cq->cq_number, qp_num);
-
-       return 0;
-}
-
-int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
-{
-       int ret = -EINVAL;
-       unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
-       struct hlist_node *iter;
-       struct ehca_qp *qp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&cq->spinlock, flags);
-       hlist_for_each(iter, &cq->qp_hashtab[key]) {
-               qp = hlist_entry(iter, struct ehca_qp, list_entries);
-               if (qp->real_qp_num == real_qp_num) {
-                       hlist_del(iter);
-                       ehca_dbg(cq->ib_cq.device,
-                                "removed qp from cq .cq_num=%x real_qp_num=%x",
-                                cq->cq_number, real_qp_num);
-                       ret = 0;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&cq->spinlock, flags);
-       if (ret)
-               ehca_err(cq->ib_cq.device,
-                        "qp not found cq_num=%x real_qp_num=%x",
-                        cq->cq_number, real_qp_num);
-
-       return ret;
-}
-
-struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
-{
-       struct ehca_qp *ret = NULL;
-       unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
-       struct hlist_node *iter;
-       struct ehca_qp *qp;
-       hlist_for_each(iter, &cq->qp_hashtab[key]) {
-               qp = hlist_entry(iter, struct ehca_qp, list_entries);
-               if (qp->real_qp_num == real_qp_num) {
-                       ret = qp;
-                       break;
-               }
-       }
-       return ret;
-}
-
-struct ib_cq *ehca_create_cq(struct ib_device *device,
-                            const struct ib_cq_init_attr *attr,
-                            struct ib_ucontext *context,
-                            struct ib_udata *udata)
-{
-       int cqe = attr->cqe;
-       static const u32 additional_cqe = 20;
-       struct ib_cq *cq;
-       struct ehca_cq *my_cq;
-       struct ehca_shca *shca =
-               container_of(device, struct ehca_shca, ib_device);
-       struct ipz_adapter_handle adapter_handle;
-       struct ehca_alloc_cq_parms param; /* h_call's out parameters */
-       struct h_galpa gal;
-       void *vpage;
-       u32 counter;
-       u64 rpage, cqx_fec, h_ret;
-       int rc, i;
-       unsigned long flags;
-
-       if (attr->flags)
-               return ERR_PTR(-EINVAL);
-
-       if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
-               return ERR_PTR(-EINVAL);
-
-       if (!atomic_add_unless(&shca->num_cqs, 1, shca->max_num_cqs)) {
-               ehca_err(device, "Unable to create CQ, max number of %i "
-                       "CQs reached.", shca->max_num_cqs);
-               ehca_err(device, "To increase the maximum number of CQs "
-                       "use the number_of_cqs module parameter.\n");
-               return ERR_PTR(-ENOSPC);
-       }
-
-       my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL);
-       if (!my_cq) {
-               ehca_err(device, "Out of memory for ehca_cq struct device=%p",
-                        device);
-               atomic_dec(&shca->num_cqs);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       memset(&param, 0, sizeof(struct ehca_alloc_cq_parms));
-
-       spin_lock_init(&my_cq->spinlock);
-       spin_lock_init(&my_cq->cb_lock);
-       spin_lock_init(&my_cq->task_lock);
-       atomic_set(&my_cq->nr_events, 0);
-       init_waitqueue_head(&my_cq->wait_completion);
-
-       cq = &my_cq->ib_cq;
-
-       adapter_handle = shca->ipz_hca_handle;
-       param.eq_handle = shca->eq.ipz_eq_handle;
-
-       idr_preload(GFP_KERNEL);
-       write_lock_irqsave(&ehca_cq_idr_lock, flags);
-       rc = idr_alloc(&ehca_cq_idr, my_cq, 0, 0x2000000, GFP_NOWAIT);
-       write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-       idr_preload_end();
-
-       if (rc < 0) {
-               cq = ERR_PTR(-ENOMEM);
-               ehca_err(device, "Can't allocate new idr entry. device=%p",
-                        device);
-               goto create_cq_exit1;
-       }
-       my_cq->token = rc;
-
-       /*
-        * CQs maximum depth is 4GB-64, but we need additional 20 as buffer
-        * for receiving errors CQEs.
-        */
-       param.nr_cqe = cqe + additional_cqe;
-       h_ret = hipz_h_alloc_resource_cq(adapter_handle, my_cq, &param);
-
-       if (h_ret != H_SUCCESS) {
-               ehca_err(device, "hipz_h_alloc_resource_cq() failed "
-                        "h_ret=%lli device=%p", h_ret, device);
-               cq = ERR_PTR(ehca2ib_return_code(h_ret));
-               goto create_cq_exit2;
-       }
-
-       rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
-                               EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
-       if (!rc) {
-               ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p",
-                        rc, device);
-               cq = ERR_PTR(-EINVAL);
-               goto create_cq_exit3;
-       }
-
-       for (counter = 0; counter < param.act_pages; counter++) {
-               vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
-               if (!vpage) {
-                       ehca_err(device, "ipz_qpageit_get_inc() "
-                                "returns NULL device=%p", device);
-                       cq = ERR_PTR(-EAGAIN);
-                       goto create_cq_exit4;
-               }
-               rpage = __pa(vpage);
-
-               h_ret = hipz_h_register_rpage_cq(adapter_handle,
-                                                my_cq->ipz_cq_handle,
-                                                &my_cq->pf,
-                                                0,
-                                                0,
-                                                rpage,
-                                                1,
-                                                my_cq->galpas.
-                                                kernel);
-
-               if (h_ret < H_SUCCESS) {
-                       ehca_err(device, "hipz_h_register_rpage_cq() failed "
-                                "ehca_cq=%p cq_num=%x h_ret=%lli counter=%i "
-                                "act_pages=%i", my_cq, my_cq->cq_number,
-                                h_ret, counter, param.act_pages);
-                       cq = ERR_PTR(-EINVAL);
-                       goto create_cq_exit4;
-               }
-
-               if (counter == (param.act_pages - 1)) {
-                       vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
-                       if ((h_ret != H_SUCCESS) || vpage) {
-                               ehca_err(device, "Registration of pages not "
-                                        "complete ehca_cq=%p cq_num=%x "
-                                        "h_ret=%lli", my_cq, my_cq->cq_number,
-                                        h_ret);
-                               cq = ERR_PTR(-EAGAIN);
-                               goto create_cq_exit4;
-                       }
-               } else {
-                       if (h_ret != H_PAGE_REGISTERED) {
-                               ehca_err(device, "Registration of page failed "
-                                        "ehca_cq=%p cq_num=%x h_ret=%lli "
-                                        "counter=%i act_pages=%i",
-                                        my_cq, my_cq->cq_number,
-                                        h_ret, counter, param.act_pages);
-                               cq = ERR_PTR(-ENOMEM);
-                               goto create_cq_exit4;
-                       }
-               }
-       }
-
-       ipz_qeit_reset(&my_cq->ipz_queue);
-
-       gal = my_cq->galpas.kernel;
-       cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec));
-       ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%llx",
-                my_cq, my_cq->cq_number, cqx_fec);
-
-       my_cq->ib_cq.cqe = my_cq->nr_of_entries =
-               param.act_nr_of_entries - additional_cqe;
-       my_cq->cq_number = (my_cq->ipz_cq_handle.handle) & 0xffff;
-
-       for (i = 0; i < QP_HASHTAB_LEN; i++)
-               INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
-
-       INIT_LIST_HEAD(&my_cq->sqp_err_list);
-       INIT_LIST_HEAD(&my_cq->rqp_err_list);
-
-       if (context) {
-               struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
-               struct ehca_create_cq_resp resp;
-               memset(&resp, 0, sizeof(resp));
-               resp.cq_number = my_cq->cq_number;
-               resp.token = my_cq->token;
-               resp.ipz_queue.qe_size = ipz_queue->qe_size;
-               resp.ipz_queue.act_nr_of_sg = ipz_queue->act_nr_of_sg;
-               resp.ipz_queue.queue_length = ipz_queue->queue_length;
-               resp.ipz_queue.pagesize = ipz_queue->pagesize;
-               resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
-               resp.fw_handle_ofs = (u32)
-                       (my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
-               if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
-                       ehca_err(device, "Copy to udata failed.");
-                       cq = ERR_PTR(-EFAULT);
-                       goto create_cq_exit4;
-               }
-       }
-
-       return cq;
-
-create_cq_exit4:
-       ipz_queue_dtor(NULL, &my_cq->ipz_queue);
-
-create_cq_exit3:
-       h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
-       if (h_ret != H_SUCCESS)
-               ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
-                        "cq_num=%x h_ret=%lli", my_cq, my_cq->cq_number, h_ret);
-
-create_cq_exit2:
-       write_lock_irqsave(&ehca_cq_idr_lock, flags);
-       idr_remove(&ehca_cq_idr, my_cq->token);
-       write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-
-create_cq_exit1:
-       kmem_cache_free(cq_cache, my_cq);
-
-       atomic_dec(&shca->num_cqs);
-       return cq;
-}
-
-int ehca_destroy_cq(struct ib_cq *cq)
-{
-       u64 h_ret;
-       struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
-       int cq_num = my_cq->cq_number;
-       struct ib_device *device = cq->device;
-       struct ehca_shca *shca = container_of(device, struct ehca_shca,
-                                             ib_device);
-       struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
-       unsigned long flags;
-
-       if (cq->uobject) {
-               if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
-                       ehca_err(device, "Resources still referenced in "
-                                "user space cq_num=%x", my_cq->cq_number);
-                       return -EINVAL;
-               }
-       }
-
-       /*
-        * remove the CQ from the idr first to make sure
-        * no more interrupt tasklets will touch this CQ
-        */
-       write_lock_irqsave(&ehca_cq_idr_lock, flags);
-       idr_remove(&ehca_cq_idr, my_cq->token);
-       write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-
-       /* now wait until all pending events have completed */
-       wait_event(my_cq->wait_completion, !atomic_read(&my_cq->nr_events));
-
-       /* nobody's using our CQ any longer -- we can destroy it */
-       h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
-       if (h_ret == H_R_STATE) {
-               /* cq in err: read err data and destroy it forcibly */
-               ehca_dbg(device, "ehca_cq=%p cq_num=%x resource=%llx in err "
-                        "state. Try to delete it forcibly.",
-                        my_cq, cq_num, my_cq->ipz_cq_handle.handle);
-               ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle);
-               h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
-               if (h_ret == H_SUCCESS)
-                       ehca_dbg(device, "cq_num=%x deleted successfully.",
-                                cq_num);
-       }
-       if (h_ret != H_SUCCESS) {
-               ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lli "
-                        "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
-               return ehca2ib_return_code(h_ret);
-       }
-       ipz_queue_dtor(NULL, &my_cq->ipz_queue);
-       kmem_cache_free(cq_cache, my_cq);
-
-       atomic_dec(&shca->num_cqs);
-       return 0;
-}
-
-int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
-{
-       /* TODO: proper resize needs to be done */
-       ehca_err(cq->device, "not implemented yet");
-
-       return -EFAULT;
-}
-
-int ehca_init_cq_cache(void)
-{
-       cq_cache = kmem_cache_create("ehca_cache_cq",
-                                    sizeof(struct ehca_cq), 0,
-                                    SLAB_HWCACHE_ALIGN,
-                                    NULL);
-       if (!cq_cache)
-               return -ENOMEM;
-       return 0;
-}
-
-void ehca_cleanup_cq_cache(void)
-{
-       kmem_cache_destroy(cq_cache);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_eq.c b/drivers/staging/rdma/ehca/ehca_eq.c
deleted file mode 100644 (file)
index 90da674..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Event queue handling
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Khadija Souissi <souissi@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ehca_classes.h"
-#include "ehca_irq.h"
-#include "ehca_iverbs.h"
-#include "ehca_qes.h"
-#include "hcp_if.h"
-#include "ipz_pt_fn.h"
-
-int ehca_create_eq(struct ehca_shca *shca,
-                  struct ehca_eq *eq,
-                  const enum ehca_eq_type type, const u32 length)
-{
-       int ret;
-       u64 h_ret;
-       u32 nr_pages;
-       u32 i;
-       void *vpage;
-       struct ib_device *ib_dev = &shca->ib_device;
-
-       spin_lock_init(&eq->spinlock);
-       spin_lock_init(&eq->irq_spinlock);
-       eq->is_initialized = 0;
-
-       if (type != EHCA_EQ && type != EHCA_NEQ) {
-               ehca_err(ib_dev, "Invalid EQ type %x. eq=%p", type, eq);
-               return -EINVAL;
-       }
-       if (!length) {
-               ehca_err(ib_dev, "EQ length must not be zero. eq=%p", eq);
-               return -EINVAL;
-       }
-
-       h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
-                                        &eq->pf,
-                                        type,
-                                        length,
-                                        &eq->ipz_eq_handle,
-                                        &eq->length,
-                                        &nr_pages, &eq->ist);
-
-       if (h_ret != H_SUCCESS) {
-               ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq);
-               return -EINVAL;
-       }
-
-       ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
-                            EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
-       if (!ret) {
-               ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
-               goto create_eq_exit1;
-       }
-
-       for (i = 0; i < nr_pages; i++) {
-               u64 rpage;
-
-               vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
-               if (!vpage)
-                       goto create_eq_exit2;
-
-               rpage = __pa(vpage);
-               h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
-                                                eq->ipz_eq_handle,
-                                                &eq->pf,
-                                                0, 0, rpage, 1);
-
-               if (i == (nr_pages - 1)) {
-                       /* last page */
-                       vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
-                       if (h_ret != H_SUCCESS || vpage)
-                               goto create_eq_exit2;
-               } else {
-                       if (h_ret != H_PAGE_REGISTERED)
-                               goto create_eq_exit2;
-               }
-       }
-
-       ipz_qeit_reset(&eq->ipz_queue);
-
-       /* register interrupt handlers and initialize work queues */
-       if (type == EHCA_EQ) {
-               tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
-
-               ret = ibmebus_request_irq(eq->ist, ehca_interrupt_eq,
-                                         0, "ehca_eq",
-                                         (void *)shca);
-               if (ret < 0)
-                       ehca_err(ib_dev, "Can't map interrupt handler.");
-       } else if (type == EHCA_NEQ) {
-               tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
-
-               ret = ibmebus_request_irq(eq->ist, ehca_interrupt_neq,
-                                         0, "ehca_neq",
-                                         (void *)shca);
-               if (ret < 0)
-                       ehca_err(ib_dev, "Can't map interrupt handler.");
-       }
-
-       eq->is_initialized = 1;
-
-       return 0;
-
-create_eq_exit2:
-       ipz_queue_dtor(NULL, &eq->ipz_queue);
-
-create_eq_exit1:
-       hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
-
-       return -EINVAL;
-}
-
-void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq)
-{
-       unsigned long flags;
-       void *eqe;
-
-       spin_lock_irqsave(&eq->spinlock, flags);
-       eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
-       spin_unlock_irqrestore(&eq->spinlock, flags);
-
-       return eqe;
-}
-
-int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
-{
-       unsigned long flags;
-       u64 h_ret;
-
-       ibmebus_free_irq(eq->ist, (void *)shca);
-
-       spin_lock_irqsave(&shca_list_lock, flags);
-       eq->is_initialized = 0;
-       spin_unlock_irqrestore(&shca_list_lock, flags);
-
-       tasklet_kill(&eq->interrupt_task);
-
-       h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
-
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't free EQ resources.");
-               return -EINVAL;
-       }
-       ipz_queue_dtor(NULL, &eq->ipz_queue);
-
-       return 0;
-}
diff --git a/drivers/staging/rdma/ehca/ehca_hca.c b/drivers/staging/rdma/ehca/ehca_hca.c
deleted file mode 100644 (file)
index e8b1bb6..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  HCA query functions
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/gfp.h>
-
-#include "ehca_tools.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-
-static unsigned int limit_uint(unsigned int value)
-{
-       return min_t(unsigned int, value, INT_MAX);
-}
-
-int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
-                     struct ib_udata *uhw)
-{
-       int i, ret = 0;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
-                                             ib_device);
-       struct hipz_query_hca *rblock;
-
-       static const u32 cap_mapping[] = {
-               IB_DEVICE_RESIZE_MAX_WR,      HCA_CAP_WQE_RESIZE,
-               IB_DEVICE_BAD_PKEY_CNTR,      HCA_CAP_BAD_P_KEY_CTR,
-               IB_DEVICE_BAD_QKEY_CNTR,      HCA_CAP_Q_KEY_VIOL_CTR,
-               IB_DEVICE_RAW_MULTI,          HCA_CAP_RAW_PACKET_MCAST,
-               IB_DEVICE_AUTO_PATH_MIG,      HCA_CAP_AUTO_PATH_MIG,
-               IB_DEVICE_CHANGE_PHY_PORT,    HCA_CAP_SQD_RTS_PORT_CHANGE,
-               IB_DEVICE_UD_AV_PORT_ENFORCE, HCA_CAP_AH_PORT_NR_CHECK,
-               IB_DEVICE_CURR_QP_STATE_MOD,  HCA_CAP_CUR_QP_STATE_MOD,
-               IB_DEVICE_SHUTDOWN_PORT,      HCA_CAP_SHUTDOWN_PORT,
-               IB_DEVICE_INIT_TYPE,          HCA_CAP_INIT_TYPE,
-               IB_DEVICE_PORT_ACTIVE_EVENT,  HCA_CAP_PORT_ACTIVE_EVENT,
-       };
-
-       if (uhw->inlen || uhw->outlen)
-               return -EINVAL;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query device properties");
-               ret = -EINVAL;
-               goto query_device1;
-       }
-
-       memset(props, 0, sizeof(struct ib_device_attr));
-       props->page_size_cap   = shca->hca_cap_mr_pgsize;
-       props->fw_ver          = rblock->hw_ver;
-       props->max_mr_size     = rblock->max_mr_size;
-       props->vendor_id       = rblock->vendor_id >> 8;
-       props->vendor_part_id  = rblock->vendor_part_id >> 16;
-       props->hw_ver          = rblock->hw_ver;
-       props->max_qp          = limit_uint(rblock->max_qp);
-       props->max_qp_wr       = limit_uint(rblock->max_wqes_wq);
-       props->max_sge         = limit_uint(rblock->max_sge);
-       props->max_sge_rd      = limit_uint(rblock->max_sge_rd);
-       props->max_cq          = limit_uint(rblock->max_cq);
-       props->max_cqe         = limit_uint(rblock->max_cqe);
-       props->max_mr          = limit_uint(rblock->max_mr);
-       props->max_mw          = limit_uint(rblock->max_mw);
-       props->max_pd          = limit_uint(rblock->max_pd);
-       props->max_ah          = limit_uint(rblock->max_ah);
-       props->max_ee          = limit_uint(rblock->max_rd_ee_context);
-       props->max_rdd         = limit_uint(rblock->max_rd_domain);
-       props->max_fmr         = limit_uint(rblock->max_mr);
-       props->max_qp_rd_atom  = limit_uint(rblock->max_rr_qp);
-       props->max_ee_rd_atom  = limit_uint(rblock->max_rr_ee_context);
-       props->max_res_rd_atom = limit_uint(rblock->max_rr_hca);
-       props->max_qp_init_rd_atom = limit_uint(rblock->max_act_wqs_qp);
-       props->max_ee_init_rd_atom = limit_uint(rblock->max_act_wqs_ee_context);
-
-       if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
-               props->max_srq         = limit_uint(props->max_qp);
-               props->max_srq_wr      = limit_uint(props->max_qp_wr);
-               props->max_srq_sge     = 3;
-       }
-
-       props->max_pkeys           = 16;
-       /* Some FW versions say 0 here; insert sensible value in that case */
-       props->local_ca_ack_delay  = rblock->local_ca_ack_delay ?
-               min_t(u8, rblock->local_ca_ack_delay, 255) : 12;
-       props->max_raw_ipv6_qp     = limit_uint(rblock->max_raw_ipv6_qp);
-       props->max_raw_ethy_qp     = limit_uint(rblock->max_raw_ethy_qp);
-       props->max_mcast_grp       = limit_uint(rblock->max_mcast_grp);
-       props->max_mcast_qp_attach = limit_uint(rblock->max_mcast_qp_attach);
-       props->max_total_mcast_qp_attach
-               = limit_uint(rblock->max_total_mcast_qp_attach);
-
-       /* translate device capabilities */
-       props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
-               IB_DEVICE_RC_RNR_NAK_GEN | IB_DEVICE_N_NOTIFY_CQ;
-       for (i = 0; i < ARRAY_SIZE(cap_mapping); i += 2)
-               if (rblock->hca_cap_indicators & cap_mapping[i + 1])
-                       props->device_cap_flags |= cap_mapping[i];
-
-query_device1:
-       ehca_free_fw_ctrlblock(rblock);
-
-       return ret;
-}
-
-static enum ib_mtu map_mtu(struct ehca_shca *shca, u32 fw_mtu)
-{
-       switch (fw_mtu) {
-       case 0x1:
-               return IB_MTU_256;
-       case 0x2:
-               return IB_MTU_512;
-       case 0x3:
-               return IB_MTU_1024;
-       case 0x4:
-               return IB_MTU_2048;
-       case 0x5:
-               return IB_MTU_4096;
-       default:
-               ehca_err(&shca->ib_device, "Unknown MTU size: %x.",
-                        fw_mtu);
-               return 0;
-       }
-}
-
-static u8 map_number_of_vls(struct ehca_shca *shca, u32 vl_cap)
-{
-       switch (vl_cap) {
-       case 0x1:
-               return 1;
-       case 0x2:
-               return 2;
-       case 0x3:
-               return 4;
-       case 0x4:
-               return 8;
-       case 0x5:
-               return 15;
-       default:
-               ehca_err(&shca->ib_device, "invalid Vl Capability: %x.",
-                        vl_cap);
-               return 0;
-       }
-}
-
-int ehca_query_port(struct ib_device *ibdev,
-                   u8 port, struct ib_port_attr *props)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
-                                             ib_device);
-       struct hipz_query_port *rblock;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query port properties");
-               ret = -EINVAL;
-               goto query_port1;
-       }
-
-       memset(props, 0, sizeof(struct ib_port_attr));
-
-       props->active_mtu = props->max_mtu = map_mtu(shca, rblock->max_mtu);
-       props->port_cap_flags  = rblock->capability_mask;
-       props->gid_tbl_len     = rblock->gid_tbl_len;
-       if (rblock->max_msg_sz)
-               props->max_msg_sz      = rblock->max_msg_sz;
-       else
-               props->max_msg_sz      = 0x1 << 31;
-       props->bad_pkey_cntr   = rblock->bad_pkey_cntr;
-       props->qkey_viol_cntr  = rblock->qkey_viol_cntr;
-       props->pkey_tbl_len    = rblock->pkey_tbl_len;
-       props->lid             = rblock->lid;
-       props->sm_lid          = rblock->sm_lid;
-       props->lmc             = rblock->lmc;
-       props->sm_sl           = rblock->sm_sl;
-       props->subnet_timeout  = rblock->subnet_timeout;
-       props->init_type_reply = rblock->init_type_reply;
-       props->max_vl_num      = map_number_of_vls(shca, rblock->vl_cap);
-
-       if (rblock->state && rblock->phys_width) {
-               props->phys_state      = rblock->phys_pstate;
-               props->state           = rblock->phys_state;
-               props->active_width    = rblock->phys_width;
-               props->active_speed    = rblock->phys_speed;
-       } else {
-               /* old firmware releases don't report physical
-                * port info, so use default values
-                */
-               props->phys_state      = 5;
-               props->state           = rblock->state;
-               props->active_width    = IB_WIDTH_12X;
-               props->active_speed    = IB_SPEED_SDR;
-       }
-
-query_port1:
-       ehca_free_fw_ctrlblock(rblock);
-
-       return ret;
-}
-
-int ehca_query_sma_attr(struct ehca_shca *shca,
-                       u8 port, struct ehca_sma_attr *attr)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct hipz_query_port *rblock;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query port properties");
-               ret = -EINVAL;
-               goto query_sma_attr1;
-       }
-
-       memset(attr, 0, sizeof(struct ehca_sma_attr));
-
-       attr->lid    = rblock->lid;
-       attr->lmc    = rblock->lmc;
-       attr->sm_sl  = rblock->sm_sl;
-       attr->sm_lid = rblock->sm_lid;
-
-       attr->pkey_tbl_len = rblock->pkey_tbl_len;
-       memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys));
-
-query_sma_attr1:
-       ehca_free_fw_ctrlblock(rblock);
-
-       return ret;
-}
-
-int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct ehca_shca *shca;
-       struct hipz_query_port *rblock;
-
-       shca = container_of(ibdev, struct ehca_shca, ib_device);
-       if (index > 16) {
-               ehca_err(&shca->ib_device, "Invalid index: %x.", index);
-               return -EINVAL;
-       }
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device,  "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query port properties");
-               ret = -EINVAL;
-               goto query_pkey1;
-       }
-
-       memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
-
-query_pkey1:
-       ehca_free_fw_ctrlblock(rblock);
-
-       return ret;
-}
-
-int ehca_query_gid(struct ib_device *ibdev, u8 port,
-                  int index, union ib_gid *gid)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
-                                             ib_device);
-       struct hipz_query_port *rblock;
-
-       if (index < 0 || index > 255) {
-               ehca_err(&shca->ib_device, "Invalid index: %x.", index);
-               return -EINVAL;
-       }
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query port properties");
-               ret = -EINVAL;
-               goto query_gid1;
-       }
-
-       memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
-       memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
-
-query_gid1:
-       ehca_free_fw_ctrlblock(rblock);
-
-       return ret;
-}
-
-static const u32 allowed_port_caps = (
-       IB_PORT_SM | IB_PORT_LED_INFO_SUP | IB_PORT_CM_SUP |
-       IB_PORT_SNMP_TUNNEL_SUP | IB_PORT_DEVICE_MGMT_SUP |
-       IB_PORT_VENDOR_CLASS_SUP);
-
-int ehca_modify_port(struct ib_device *ibdev,
-                    u8 port, int port_modify_mask,
-                    struct ib_port_modify *props)
-{
-       int ret = 0;
-       struct ehca_shca *shca;
-       struct hipz_query_port *rblock;
-       u32 cap;
-       u64 hret;
-
-       shca = container_of(ibdev, struct ehca_shca, ib_device);
-       if ((props->set_port_cap_mask | props->clr_port_cap_mask)
-           & ~allowed_port_caps) {
-               ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
-                        "set=%x  clr=%x  allowed=%x", props->set_port_cap_mask,
-                        props->clr_port_cap_mask, allowed_port_caps);
-               return -EINVAL;
-       }
-
-       if (mutex_lock_interruptible(&shca->modify_mutex))
-               return -ERESTARTSYS;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device,  "Can't allocate rblock memory.");
-               ret = -ENOMEM;
-               goto modify_port1;
-       }
-
-       hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
-       if (hret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query port properties");
-               ret = -EINVAL;
-               goto modify_port2;
-       }
-
-       cap = (rblock->capability_mask | props->set_port_cap_mask)
-               & ~props->clr_port_cap_mask;
-
-       hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
-                                 cap, props->init_type, port_modify_mask);
-       if (hret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Modify port failed  h_ret=%lli",
-                        hret);
-               ret = -EINVAL;
-       }
-
-modify_port2:
-       ehca_free_fw_ctrlblock(rblock);
-
-modify_port1:
-       mutex_unlock(&shca->modify_mutex);
-
-       return ret;
-}
diff --git a/drivers/staging/rdma/ehca/ehca_irq.c b/drivers/staging/rdma/ehca/ehca_irq.c
deleted file mode 100644 (file)
index 8615d7c..0000000
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Functions for EQs, NEQs and interrupts
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Khadija Souissi <souissi@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Joachim Fenkes <fenkes@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-#include <linux/smpboot.h>
-
-#include "ehca_classes.h"
-#include "ehca_irq.h"
-#include "ehca_iverbs.h"
-#include "ehca_tools.h"
-#include "hcp_if.h"
-#include "hipz_fns.h"
-#include "ipz_pt_fn.h"
-
-#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM( 1,  1)
-#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM( 8, 31)
-#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM( 2,  7)
-#define EQE_CQ_NUMBER          EHCA_BMASK_IBM( 8, 31)
-#define EQE_QP_NUMBER          EHCA_BMASK_IBM( 8, 31)
-#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32, 63)
-#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32, 63)
-
-#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM( 1,  1)
-#define NEQE_EVENT_CODE        EHCA_BMASK_IBM( 2,  7)
-#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
-#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
-#define NEQE_SPECIFIC_EVENT    EHCA_BMASK_IBM(16, 23)
-
-#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
-#define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
-
-static void queue_comp_task(struct ehca_cq *__cq);
-
-static struct ehca_comp_pool *pool;
-
-static inline void comp_event_callback(struct ehca_cq *cq)
-{
-       if (!cq->ib_cq.comp_handler)
-               return;
-
-       spin_lock(&cq->cb_lock);
-       cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context);
-       spin_unlock(&cq->cb_lock);
-
-       return;
-}
-
-static void print_error_data(struct ehca_shca *shca, void *data,
-                            u64 *rblock, int length)
-{
-       u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
-       u64 resource = rblock[1];
-
-       switch (type) {
-       case 0x1: /* Queue Pair */
-       {
-               struct ehca_qp *qp = (struct ehca_qp *)data;
-
-               /* only print error data if AER is set */
-               if (rblock[6] == 0)
-                       return;
-
-               ehca_err(&shca->ib_device,
-                        "QP 0x%x (resource=%llx) has errors.",
-                        qp->ib_qp.qp_num, resource);
-               break;
-       }
-       case 0x4: /* Completion Queue */
-       {
-               struct ehca_cq *cq = (struct ehca_cq *)data;
-
-               ehca_err(&shca->ib_device,
-                        "CQ 0x%x (resource=%llx) has errors.",
-                        cq->cq_number, resource);
-               break;
-       }
-       default:
-               ehca_err(&shca->ib_device,
-                        "Unknown error type: %llx on %s.",
-                        type, shca->ib_device.name);
-               break;
-       }
-
-       ehca_err(&shca->ib_device, "Error data is available: %llx.", resource);
-       ehca_err(&shca->ib_device, "EHCA ----- error data begin "
-                "---------------------------------------------------");
-       ehca_dmp(rblock, length, "resource=%llx", resource);
-       ehca_err(&shca->ib_device, "EHCA ----- error data end "
-                "----------------------------------------------------");
-
-       return;
-}
-
-int ehca_error_data(struct ehca_shca *shca, void *data,
-                   u64 resource)
-{
-
-       unsigned long ret;
-       u64 *rblock;
-       unsigned long block_count;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Cannot allocate rblock memory.");
-               ret = -ENOMEM;
-               goto error_data1;
-       }
-
-       /* rblock must be 4K aligned and should be 4K large */
-       ret = hipz_h_error_data(shca->ipz_hca_handle,
-                               resource,
-                               rblock,
-                               &block_count);
-
-       if (ret == H_R_STATE)
-               ehca_err(&shca->ib_device,
-                        "No error data is available: %llx.", resource);
-       else if (ret == H_SUCCESS) {
-               int length;
-
-               length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]);
-
-               if (length > EHCA_PAGESIZE)
-                       length = EHCA_PAGESIZE;
-
-               print_error_data(shca, data, rblock, length);
-       } else
-               ehca_err(&shca->ib_device,
-                        "Error data could not be fetched: %llx", resource);
-
-       ehca_free_fw_ctrlblock(rblock);
-
-error_data1:
-       return ret;
-
-}
-
-static void dispatch_qp_event(struct ehca_shca *shca, struct ehca_qp *qp,
-                             enum ib_event_type event_type)
-{
-       struct ib_event event;
-
-       /* PATH_MIG without the QP ever having been armed is false alarm */
-       if (event_type == IB_EVENT_PATH_MIG && !qp->mig_armed)
-               return;
-
-       event.device = &shca->ib_device;
-       event.event = event_type;
-
-       if (qp->ext_type == EQPT_SRQ) {
-               if (!qp->ib_srq.event_handler)
-                       return;
-
-               event.element.srq = &qp->ib_srq;
-               qp->ib_srq.event_handler(&event, qp->ib_srq.srq_context);
-       } else {
-               if (!qp->ib_qp.event_handler)
-                       return;
-
-               event.element.qp = &qp->ib_qp;
-               qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
-       }
-}
-
-static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
-                             enum ib_event_type event_type, int fatal)
-{
-       struct ehca_qp *qp;
-       u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
-
-       read_lock(&ehca_qp_idr_lock);
-       qp = idr_find(&ehca_qp_idr, token);
-       if (qp)
-               atomic_inc(&qp->nr_events);
-       read_unlock(&ehca_qp_idr_lock);
-
-       if (!qp)
-               return;
-
-       if (fatal)
-               ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
-
-       dispatch_qp_event(shca, qp, fatal && qp->ext_type == EQPT_SRQ ?
-                         IB_EVENT_SRQ_ERR : event_type);
-
-       /*
-        * eHCA only processes one WQE at a time for SRQ base QPs,
-        * so the last WQE has been processed as soon as the QP enters
-        * error state.
-        */
-       if (fatal && qp->ext_type == EQPT_SRQBASE)
-               dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
-
-       if (atomic_dec_and_test(&qp->nr_events))
-               wake_up(&qp->wait_completion);
-       return;
-}
-
-static void cq_event_callback(struct ehca_shca *shca,
-                             u64 eqe)
-{
-       struct ehca_cq *cq;
-       u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
-
-       read_lock(&ehca_cq_idr_lock);
-       cq = idr_find(&ehca_cq_idr, token);
-       if (cq)
-               atomic_inc(&cq->nr_events);
-       read_unlock(&ehca_cq_idr_lock);
-
-       if (!cq)
-               return;
-
-       ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
-
-       if (atomic_dec_and_test(&cq->nr_events))
-               wake_up(&cq->wait_completion);
-
-       return;
-}
-
-static void parse_identifier(struct ehca_shca *shca, u64 eqe)
-{
-       u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe);
-
-       switch (identifier) {
-       case 0x02: /* path migrated */
-               qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG, 0);
-               break;
-       case 0x03: /* communication established */
-               qp_event_callback(shca, eqe, IB_EVENT_COMM_EST, 0);
-               break;
-       case 0x04: /* send queue drained */
-               qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED, 0);
-               break;
-       case 0x05: /* QP error */
-       case 0x06: /* QP error */
-               qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL, 1);
-               break;
-       case 0x07: /* CQ error */
-       case 0x08: /* CQ error */
-               cq_event_callback(shca, eqe);
-               break;
-       case 0x09: /* MRMWPTE error */
-               ehca_err(&shca->ib_device, "MRMWPTE error.");
-               break;
-       case 0x0A: /* port event */
-               ehca_err(&shca->ib_device, "Port event.");
-               break;
-       case 0x0B: /* MR access error */
-               ehca_err(&shca->ib_device, "MR access error.");
-               break;
-       case 0x0C: /* EQ error */
-               ehca_err(&shca->ib_device, "EQ error.");
-               break;
-       case 0x0D: /* P/Q_Key mismatch */
-               ehca_err(&shca->ib_device, "P/Q_Key mismatch.");
-               break;
-       case 0x10: /* sampling complete */
-               ehca_err(&shca->ib_device, "Sampling complete.");
-               break;
-       case 0x11: /* unaffiliated access error */
-               ehca_err(&shca->ib_device, "Unaffiliated access error.");
-               break;
-       case 0x12: /* path migrating */
-               ehca_err(&shca->ib_device, "Path migrating.");
-               break;
-       case 0x13: /* interface trace stopped */
-               ehca_err(&shca->ib_device, "Interface trace stopped.");
-               break;
-       case 0x14: /* first error capture info available */
-               ehca_info(&shca->ib_device, "First error capture available");
-               break;
-       case 0x15: /* SRQ limit reached */
-               qp_event_callback(shca, eqe, IB_EVENT_SRQ_LIMIT_REACHED, 0);
-               break;
-       default:
-               ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
-                        identifier, shca->ib_device.name);
-               break;
-       }
-
-       return;
-}
-
-static void dispatch_port_event(struct ehca_shca *shca, int port_num,
-                               enum ib_event_type type, const char *msg)
-{
-       struct ib_event event;
-
-       ehca_info(&shca->ib_device, "port %d %s.", port_num, msg);
-       event.device = &shca->ib_device;
-       event.event = type;
-       event.element.port_num = port_num;
-       ib_dispatch_event(&event);
-}
-
-static void notify_port_conf_change(struct ehca_shca *shca, int port_num)
-{
-       struct ehca_sma_attr  new_attr;
-       struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr;
-
-       ehca_query_sma_attr(shca, port_num, &new_attr);
-
-       if (new_attr.sm_sl  != old_attr->sm_sl ||
-           new_attr.sm_lid != old_attr->sm_lid)
-               dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE,
-                                   "SM changed");
-
-       if (new_attr.lid != old_attr->lid ||
-           new_attr.lmc != old_attr->lmc)
-               dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE,
-                                   "LID changed");
-
-       if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len ||
-           memcmp(new_attr.pkeys, old_attr->pkeys,
-                  sizeof(u16) * new_attr.pkey_tbl_len))
-               dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE,
-                                   "P_Key changed");
-
-       *old_attr = new_attr;
-}
-
-/* replay modify_qp for sqps -- return 0 if all is well, 1 if AQP1 destroyed */
-static int replay_modify_qp(struct ehca_sport *sport)
-{
-       int aqp1_destroyed;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-
-       aqp1_destroyed = !sport->ibqp_sqp[IB_QPT_GSI];
-
-       if (sport->ibqp_sqp[IB_QPT_SMI])
-               ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
-       if (!aqp1_destroyed)
-               ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
-
-       spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-
-       return aqp1_destroyed;
-}
-
-static void parse_ec(struct ehca_shca *shca, u64 eqe)
-{
-       u8 ec   = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
-       u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
-       u8 spec_event;
-       struct ehca_sport *sport = &shca->sport[port - 1];
-
-       switch (ec) {
-       case 0x30: /* port availability change */
-               if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
-                       /* only replay modify_qp calls in autodetect mode;
-                        * if AQP1 was destroyed, the port is already down
-                        * again and we can drop the event.
-                        */
-                       if (ehca_nr_ports < 0)
-                               if (replay_modify_qp(sport))
-                                       break;
-
-                       sport->port_state = IB_PORT_ACTIVE;
-                       dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
-                                           "is active");
-                       ehca_query_sma_attr(shca, port, &sport->saved_attr);
-               } else {
-                       sport->port_state = IB_PORT_DOWN;
-                       dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
-                                           "is inactive");
-               }
-               break;
-       case 0x31:
-               /* port configuration change
-                * disruptive change is caused by
-                * LID, PKEY or SM change
-                */
-               if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
-                       ehca_warn(&shca->ib_device, "disruptive port "
-                                 "%d configuration change", port);
-
-                       sport->port_state = IB_PORT_DOWN;
-                       dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
-                                           "is inactive");
-
-                       sport->port_state = IB_PORT_ACTIVE;
-                       dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
-                                           "is active");
-                       ehca_query_sma_attr(shca, port,
-                                           &sport->saved_attr);
-               } else
-                       notify_port_conf_change(shca, port);
-               break;
-       case 0x32: /* adapter malfunction */
-               ehca_err(&shca->ib_device, "Adapter malfunction.");
-               break;
-       case 0x33:  /* trace stopped */
-               ehca_err(&shca->ib_device, "Traced stopped.");
-               break;
-       case 0x34: /* util async event */
-               spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
-               if (spec_event == 0x80) /* client reregister required */
-                       dispatch_port_event(shca, port,
-                                           IB_EVENT_CLIENT_REREGISTER,
-                                           "client reregister req.");
-               else
-                       ehca_warn(&shca->ib_device, "Unknown util async "
-                                 "event %x on port %x", spec_event, port);
-               break;
-       default:
-               ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
-                        ec, shca->ib_device.name);
-               break;
-       }
-
-       return;
-}
-
-static inline void reset_eq_pending(struct ehca_cq *cq)
-{
-       u64 CQx_EP;
-       struct h_galpa gal = cq->galpas.kernel;
-
-       hipz_galpa_store_cq(gal, cqx_ep, 0x0);
-       CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep));
-
-       return;
-}
-
-irqreturn_t ehca_interrupt_neq(int irq, void *dev_id)
-{
-       struct ehca_shca *shca = (struct ehca_shca*)dev_id;
-
-       tasklet_hi_schedule(&shca->neq.interrupt_task);
-
-       return IRQ_HANDLED;
-}
-
-void ehca_tasklet_neq(unsigned long data)
-{
-       struct ehca_shca *shca = (struct ehca_shca*)data;
-       struct ehca_eqe *eqe;
-       u64 ret;
-
-       eqe = ehca_poll_eq(shca, &shca->neq);
-
-       while (eqe) {
-               if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
-                       parse_ec(shca, eqe->entry);
-
-               eqe = ehca_poll_eq(shca, &shca->neq);
-       }
-
-       ret = hipz_h_reset_event(shca->ipz_hca_handle,
-                                shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL);
-
-       if (ret != H_SUCCESS)
-               ehca_err(&shca->ib_device, "Can't clear notification events.");
-
-       return;
-}
-
-irqreturn_t ehca_interrupt_eq(int irq, void *dev_id)
-{
-       struct ehca_shca *shca = (struct ehca_shca*)dev_id;
-
-       tasklet_hi_schedule(&shca->eq.interrupt_task);
-
-       return IRQ_HANDLED;
-}
-
-
-static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
-{
-       u64 eqe_value;
-       u32 token;
-       struct ehca_cq *cq;
-
-       eqe_value = eqe->entry;
-       ehca_dbg(&shca->ib_device, "eqe_value=%llx", eqe_value);
-       if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
-               ehca_dbg(&shca->ib_device, "Got completion event");
-               token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
-               read_lock(&ehca_cq_idr_lock);
-               cq = idr_find(&ehca_cq_idr, token);
-               if (cq)
-                       atomic_inc(&cq->nr_events);
-               read_unlock(&ehca_cq_idr_lock);
-               if (cq == NULL) {
-                       ehca_err(&shca->ib_device,
-                                "Invalid eqe for non-existing cq token=%x",
-                                token);
-                       return;
-               }
-               reset_eq_pending(cq);
-               if (ehca_scaling_code)
-                       queue_comp_task(cq);
-               else {
-                       comp_event_callback(cq);
-                       if (atomic_dec_and_test(&cq->nr_events))
-                               wake_up(&cq->wait_completion);
-               }
-       } else {
-               ehca_dbg(&shca->ib_device, "Got non completion event");
-               parse_identifier(shca, eqe_value);
-       }
-}
-
-void ehca_process_eq(struct ehca_shca *shca, int is_irq)
-{
-       struct ehca_eq *eq = &shca->eq;
-       struct ehca_eqe_cache_entry *eqe_cache = eq->eqe_cache;
-       u64 eqe_value, ret;
-       int eqe_cnt, i;
-       int eq_empty = 0;
-
-       spin_lock(&eq->irq_spinlock);
-       if (is_irq) {
-               const int max_query_cnt = 100;
-               int query_cnt = 0;
-               int int_state = 1;
-               do {
-                       int_state = hipz_h_query_int_state(
-                               shca->ipz_hca_handle, eq->ist);
-                       query_cnt++;
-                       iosync();
-               } while (int_state && query_cnt < max_query_cnt);
-               if (unlikely((query_cnt == max_query_cnt)))
-                       ehca_dbg(&shca->ib_device, "int_state=%x query_cnt=%x",
-                                int_state, query_cnt);
-       }
-
-       /* read out all eqes */
-       eqe_cnt = 0;
-       do {
-               u32 token;
-               eqe_cache[eqe_cnt].eqe = ehca_poll_eq(shca, eq);
-               if (!eqe_cache[eqe_cnt].eqe)
-                       break;
-               eqe_value = eqe_cache[eqe_cnt].eqe->entry;
-               if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
-                       token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
-                       read_lock(&ehca_cq_idr_lock);
-                       eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token);
-                       if (eqe_cache[eqe_cnt].cq)
-                               atomic_inc(&eqe_cache[eqe_cnt].cq->nr_events);
-                       read_unlock(&ehca_cq_idr_lock);
-                       if (!eqe_cache[eqe_cnt].cq) {
-                               ehca_err(&shca->ib_device,
-                                        "Invalid eqe for non-existing cq "
-                                        "token=%x", token);
-                               continue;
-                       }
-               } else
-                       eqe_cache[eqe_cnt].cq = NULL;
-               eqe_cnt++;
-       } while (eqe_cnt < EHCA_EQE_CACHE_SIZE);
-       if (!eqe_cnt) {
-               if (is_irq)
-                       ehca_dbg(&shca->ib_device,
-                                "No eqe found for irq event");
-               goto unlock_irq_spinlock;
-       } else if (!is_irq) {
-               ret = hipz_h_eoi(eq->ist);
-               if (ret != H_SUCCESS)
-                       ehca_err(&shca->ib_device,
-                                "bad return code EOI -rc = %lld\n", ret);
-               ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt);
-       }
-       if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE))
-               ehca_dbg(&shca->ib_device, "too many eqes for one irq event");
-       /* enable irq for new packets */
-       for (i = 0; i < eqe_cnt; i++) {
-               if (eq->eqe_cache[i].cq)
-                       reset_eq_pending(eq->eqe_cache[i].cq);
-       }
-       /* check eq */
-       spin_lock(&eq->spinlock);
-       eq_empty = (!ipz_eqit_eq_peek_valid(&shca->eq.ipz_queue));
-       spin_unlock(&eq->spinlock);
-       /* call completion handler for cached eqes */
-       for (i = 0; i < eqe_cnt; i++)
-               if (eq->eqe_cache[i].cq) {
-                       if (ehca_scaling_code)
-                               queue_comp_task(eq->eqe_cache[i].cq);
-                       else {
-                               struct ehca_cq *cq = eq->eqe_cache[i].cq;
-                               comp_event_callback(cq);
-                               if (atomic_dec_and_test(&cq->nr_events))
-                                       wake_up(&cq->wait_completion);
-                       }
-               } else {
-                       ehca_dbg(&shca->ib_device, "Got non completion event");
-                       parse_identifier(shca, eq->eqe_cache[i].eqe->entry);
-               }
-       /* poll eq if not empty */
-       if (eq_empty)
-               goto unlock_irq_spinlock;
-       do {
-               struct ehca_eqe *eqe;
-               eqe = ehca_poll_eq(shca, &shca->eq);
-               if (!eqe)
-                       break;
-               process_eqe(shca, eqe);
-       } while (1);
-
-unlock_irq_spinlock:
-       spin_unlock(&eq->irq_spinlock);
-}
-
-void ehca_tasklet_eq(unsigned long data)
-{
-       ehca_process_eq((struct ehca_shca*)data, 1);
-}
-
-static int find_next_online_cpu(struct ehca_comp_pool *pool)
-{
-       int cpu;
-       unsigned long flags;
-
-       WARN_ON_ONCE(!in_interrupt());
-       if (ehca_debug_level >= 3)
-               ehca_dmp(cpu_online_mask, cpumask_size(), "");
-
-       spin_lock_irqsave(&pool->last_cpu_lock, flags);
-       do {
-               cpu = cpumask_next(pool->last_cpu, cpu_online_mask);
-               if (cpu >= nr_cpu_ids)
-                       cpu = cpumask_first(cpu_online_mask);
-               pool->last_cpu = cpu;
-       } while (!per_cpu_ptr(pool->cpu_comp_tasks, cpu)->active);
-       spin_unlock_irqrestore(&pool->last_cpu_lock, flags);
-
-       return cpu;
-}
-
-static void __queue_comp_task(struct ehca_cq *__cq,
-                             struct ehca_cpu_comp_task *cct,
-                             struct task_struct *thread)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cct->task_lock, flags);
-       spin_lock(&__cq->task_lock);
-
-       if (__cq->nr_callbacks == 0) {
-               __cq->nr_callbacks++;
-               list_add_tail(&__cq->entry, &cct->cq_list);
-               cct->cq_jobs++;
-               wake_up_process(thread);
-       } else
-               __cq->nr_callbacks++;
-
-       spin_unlock(&__cq->task_lock);
-       spin_unlock_irqrestore(&cct->task_lock, flags);
-}
-
-static void queue_comp_task(struct ehca_cq *__cq)
-{
-       int cpu_id;
-       struct ehca_cpu_comp_task *cct;
-       struct task_struct *thread;
-       int cq_jobs;
-       unsigned long flags;
-
-       cpu_id = find_next_online_cpu(pool);
-       BUG_ON(!cpu_online(cpu_id));
-
-       cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
-       thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
-       BUG_ON(!cct || !thread);
-
-       spin_lock_irqsave(&cct->task_lock, flags);
-       cq_jobs = cct->cq_jobs;
-       spin_unlock_irqrestore(&cct->task_lock, flags);
-       if (cq_jobs > 0) {
-               cpu_id = find_next_online_cpu(pool);
-               cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
-               thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu_id);
-               BUG_ON(!cct || !thread);
-       }
-       __queue_comp_task(__cq, cct, thread);
-}
-
-static void run_comp_task(struct ehca_cpu_comp_task *cct)
-{
-       struct ehca_cq *cq;
-
-       while (!list_empty(&cct->cq_list)) {
-               cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
-               spin_unlock_irq(&cct->task_lock);
-
-               comp_event_callback(cq);
-               if (atomic_dec_and_test(&cq->nr_events))
-                       wake_up(&cq->wait_completion);
-
-               spin_lock_irq(&cct->task_lock);
-               spin_lock(&cq->task_lock);
-               cq->nr_callbacks--;
-               if (!cq->nr_callbacks) {
-                       list_del_init(cct->cq_list.next);
-                       cct->cq_jobs--;
-               }
-               spin_unlock(&cq->task_lock);
-       }
-}
-
-static void comp_task_park(unsigned int cpu)
-{
-       struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-       struct ehca_cpu_comp_task *target;
-       struct task_struct *thread;
-       struct ehca_cq *cq, *tmp;
-       LIST_HEAD(list);
-
-       spin_lock_irq(&cct->task_lock);
-       cct->cq_jobs = 0;
-       cct->active = 0;
-       list_splice_init(&cct->cq_list, &list);
-       spin_unlock_irq(&cct->task_lock);
-
-       cpu = find_next_online_cpu(pool);
-       target = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-       thread = *per_cpu_ptr(pool->cpu_comp_threads, cpu);
-       spin_lock_irq(&target->task_lock);
-       list_for_each_entry_safe(cq, tmp, &list, entry) {
-               list_del(&cq->entry);
-               __queue_comp_task(cq, target, thread);
-       }
-       spin_unlock_irq(&target->task_lock);
-}
-
-static void comp_task_stop(unsigned int cpu, bool online)
-{
-       struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-
-       spin_lock_irq(&cct->task_lock);
-       cct->cq_jobs = 0;
-       cct->active = 0;
-       WARN_ON(!list_empty(&cct->cq_list));
-       spin_unlock_irq(&cct->task_lock);
-}
-
-static int comp_task_should_run(unsigned int cpu)
-{
-       struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-
-       return cct->cq_jobs;
-}
-
-static void comp_task(unsigned int cpu)
-{
-       struct ehca_cpu_comp_task *cct = this_cpu_ptr(pool->cpu_comp_tasks);
-       int cql_empty;
-
-       spin_lock_irq(&cct->task_lock);
-       cql_empty = list_empty(&cct->cq_list);
-       if (!cql_empty) {
-               __set_current_state(TASK_RUNNING);
-               run_comp_task(cct);
-       }
-       spin_unlock_irq(&cct->task_lock);
-}
-
-static struct smp_hotplug_thread comp_pool_threads = {
-       .thread_should_run      = comp_task_should_run,
-       .thread_fn              = comp_task,
-       .thread_comm            = "ehca_comp/%u",
-       .cleanup                = comp_task_stop,
-       .park                   = comp_task_park,
-};
-
-int ehca_create_comp_pool(void)
-{
-       int cpu, ret = -ENOMEM;
-
-       if (!ehca_scaling_code)
-               return 0;
-
-       pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
-       if (pool == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&pool->last_cpu_lock);
-       pool->last_cpu = cpumask_any(cpu_online_mask);
-
-       pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
-       if (!pool->cpu_comp_tasks)
-               goto out_pool;
-
-       pool->cpu_comp_threads = alloc_percpu(struct task_struct *);
-       if (!pool->cpu_comp_threads)
-               goto out_tasks;
-
-       for_each_present_cpu(cpu) {
-               struct ehca_cpu_comp_task *cct;
-
-               cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
-               spin_lock_init(&cct->task_lock);
-               INIT_LIST_HEAD(&cct->cq_list);
-       }
-
-       comp_pool_threads.store = pool->cpu_comp_threads;
-       ret = smpboot_register_percpu_thread(&comp_pool_threads);
-       if (ret)
-               goto out_threads;
-
-       pr_info("eHCA scaling code enabled\n");
-       return ret;
-
-out_threads:
-       free_percpu(pool->cpu_comp_threads);
-out_tasks:
-       free_percpu(pool->cpu_comp_tasks);
-out_pool:
-       kfree(pool);
-       return ret;
-}
-
-void ehca_destroy_comp_pool(void)
-{
-       if (!ehca_scaling_code)
-               return;
-
-       smpboot_unregister_percpu_thread(&comp_pool_threads);
-
-       free_percpu(pool->cpu_comp_threads);
-       free_percpu(pool->cpu_comp_tasks);
-       kfree(pool);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_irq.h b/drivers/staging/rdma/ehca/ehca_irq.h
deleted file mode 100644 (file)
index 5370199..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Function definitions and structs for EQs, NEQs and interrupts
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Khadija Souissi <souissi@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __EHCA_IRQ_H
-#define __EHCA_IRQ_H
-
-
-struct ehca_shca;
-
-#include <linux/interrupt.h>
-#include <linux/types.h>
-
-int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
-
-irqreturn_t ehca_interrupt_neq(int irq, void *dev_id);
-void ehca_tasklet_neq(unsigned long data);
-
-irqreturn_t ehca_interrupt_eq(int irq, void *dev_id);
-void ehca_tasklet_eq(unsigned long data);
-void ehca_process_eq(struct ehca_shca *shca, int is_irq);
-
-struct ehca_cpu_comp_task {
-       struct list_head cq_list;
-       spinlock_t task_lock;
-       int cq_jobs;
-       int active;
-};
-
-struct ehca_comp_pool {
-       struct ehca_cpu_comp_task __percpu *cpu_comp_tasks;
-       struct task_struct * __percpu *cpu_comp_threads;
-       int last_cpu;
-       spinlock_t last_cpu_lock;
-};
-
-int ehca_create_comp_pool(void);
-void ehca_destroy_comp_pool(void);
-
-#endif
diff --git a/drivers/staging/rdma/ehca/ehca_iverbs.h b/drivers/staging/rdma/ehca/ehca_iverbs.h
deleted file mode 100644 (file)
index cca5933..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Function definitions for internal functions
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Dietmar Decker <ddecker@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __EHCA_IVERBS_H__
-#define __EHCA_IVERBS_H__
-
-#include "ehca_classes.h"
-
-int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
-                     struct ib_udata *uhw);
-
-int ehca_query_port(struct ib_device *ibdev, u8 port,
-                   struct ib_port_attr *props);
-
-enum rdma_protocol_type
-ehca_query_protocol(struct ib_device *device, u8 port_num);
-
-int ehca_query_sma_attr(struct ehca_shca *shca, u8 port,
-                       struct ehca_sma_attr *attr);
-
-int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
-
-int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
-                  union ib_gid *gid);
-
-int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask,
-                    struct ib_port_modify *props);
-
-struct ib_pd *ehca_alloc_pd(struct ib_device *device,
-                           struct ib_ucontext *context,
-                           struct ib_udata *udata);
-
-int ehca_dealloc_pd(struct ib_pd *pd);
-
-struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
-
-int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
-
-int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
-
-int ehca_destroy_ah(struct ib_ah *ah);
-
-struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
-
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
-                              u64 virt, int mr_access_flags,
-                              struct ib_udata *udata);
-
-int ehca_dereg_mr(struct ib_mr *mr);
-
-struct ib_mw *ehca_alloc_mw(struct ib_pd *pd, enum ib_mw_type type);
-
-int ehca_dealloc_mw(struct ib_mw *mw);
-
-struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
-                             int mr_access_flags,
-                             struct ib_fmr_attr *fmr_attr);
-
-int ehca_map_phys_fmr(struct ib_fmr *fmr,
-                     u64 *page_list, int list_len, u64 iova);
-
-int ehca_unmap_fmr(struct list_head *fmr_list);
-
-int ehca_dealloc_fmr(struct ib_fmr *fmr);
-
-enum ehca_eq_type {
-       EHCA_EQ = 0, /* Event Queue              */
-       EHCA_NEQ     /* Notification Event Queue */
-};
-
-int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq,
-                  enum ehca_eq_type type, const u32 length);
-
-int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
-
-void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
-
-
-struct ib_cq *ehca_create_cq(struct ib_device *device,
-                            const struct ib_cq_init_attr *attr,
-                            struct ib_ucontext *context,
-                            struct ib_udata *udata);
-
-int ehca_destroy_cq(struct ib_cq *cq);
-
-int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
-
-int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
-
-int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
-
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags);
-
-struct ib_qp *ehca_create_qp(struct ib_pd *pd,
-                            struct ib_qp_init_attr *init_attr,
-                            struct ib_udata *udata);
-
-int ehca_destroy_qp(struct ib_qp *qp);
-
-int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
-                  struct ib_udata *udata);
-
-int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
-                 int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
-
-int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
-                  struct ib_send_wr **bad_send_wr);
-
-int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
-                  struct ib_recv_wr **bad_recv_wr);
-
-int ehca_post_srq_recv(struct ib_srq *srq,
-                      struct ib_recv_wr *recv_wr,
-                      struct ib_recv_wr **bad_recv_wr);
-
-struct ib_srq *ehca_create_srq(struct ib_pd *pd,
-                              struct ib_srq_init_attr *init_attr,
-                              struct ib_udata *udata);
-
-int ehca_modify_srq(struct ib_srq *srq, struct ib_srq_attr *attr,
-                   enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
-
-int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
-
-int ehca_destroy_srq(struct ib_srq *srq);
-
-u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
-                   struct ib_qp_init_attr *qp_init_attr);
-
-int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
-
-int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
-
-struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
-                                       struct ib_udata *udata);
-
-int ehca_dealloc_ucontext(struct ib_ucontext *context);
-
-int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
-
-int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
-                    const struct ib_wc *in_wc, const struct ib_grh *in_grh,
-                    const struct ib_mad_hdr *in, size_t in_mad_size,
-                    struct ib_mad_hdr *out, size_t *out_mad_size,
-                    u16 *out_mad_pkey_index);
-
-void ehca_poll_eqs(unsigned long data);
-
-int ehca_calc_ipd(struct ehca_shca *shca, int port,
-                 enum ib_rate path_rate, u32 *ipd);
-
-void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq);
-
-#ifdef CONFIG_PPC_64K_PAGES
-void *ehca_alloc_fw_ctrlblock(gfp_t flags);
-void ehca_free_fw_ctrlblock(void *ptr);
-#else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
-#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
-#endif
-
-void ehca_recover_sqp(struct ib_qp *sqp);
-
-#endif
diff --git a/drivers/staging/rdma/ehca/ehca_main.c b/drivers/staging/rdma/ehca/ehca_main.c
deleted file mode 100644 (file)
index 832f22f..0000000
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  module start stop, hca detection
- *
- *  Authors: Heiko J Schick <schickhj@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Joachim Fenkes <fenkes@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
-
-#ifdef CONFIG_PPC_64K_PAGES
-#include <linux/slab.h>
-#endif
-
-#include <linux/notifier.h>
-#include <linux/memory.h>
-#include <rdma/ib_mad.h>
-#include "ehca_classes.h"
-#include "ehca_iverbs.h"
-#include "ehca_mrmw.h"
-#include "ehca_tools.h"
-#include "hcp_if.h"
-
-#define HCAD_VERSION "0029"
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
-MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION(HCAD_VERSION);
-
-static bool ehca_open_aqp1    = 0;
-static int ehca_hw_level      = 0;
-static bool ehca_poll_all_eqs = 1;
-
-int ehca_debug_level   = 0;
-int ehca_nr_ports      = -1;
-bool ehca_use_hp_mr    = 0;
-int ehca_port_act_time = 30;
-int ehca_static_rate   = -1;
-bool ehca_scaling_code = 0;
-int ehca_lock_hcalls   = -1;
-int ehca_max_cq        = -1;
-int ehca_max_qp        = -1;
-
-module_param_named(open_aqp1,     ehca_open_aqp1,     bool, S_IRUGO);
-module_param_named(debug_level,   ehca_debug_level,   int,  S_IRUGO);
-module_param_named(hw_level,      ehca_hw_level,      int,  S_IRUGO);
-module_param_named(nr_ports,      ehca_nr_ports,      int,  S_IRUGO);
-module_param_named(use_hp_mr,     ehca_use_hp_mr,     bool, S_IRUGO);
-module_param_named(port_act_time, ehca_port_act_time, int,  S_IRUGO);
-module_param_named(poll_all_eqs,  ehca_poll_all_eqs,  bool, S_IRUGO);
-module_param_named(static_rate,   ehca_static_rate,   int,  S_IRUGO);
-module_param_named(scaling_code,  ehca_scaling_code,  bool, S_IRUGO);
-module_param_named(lock_hcalls,   ehca_lock_hcalls,   bint, S_IRUGO);
-module_param_named(number_of_cqs, ehca_max_cq,        int,  S_IRUGO);
-module_param_named(number_of_qps, ehca_max_qp,        int,  S_IRUGO);
-
-MODULE_PARM_DESC(open_aqp1,
-                "Open AQP1 on startup (default: no)");
-MODULE_PARM_DESC(debug_level,
-                "Amount of debug output (0: none (default), 1: traces, "
-                "2: some dumps, 3: lots)");
-MODULE_PARM_DESC(hw_level,
-                "Hardware level (0: autosensing (default), "
-                "0x10..0x14: eHCA, 0x20..0x23: eHCA2)");
-MODULE_PARM_DESC(nr_ports,
-                "number of connected ports (-1: autodetect (default), "
-                "1: port one only, 2: two ports)");
-MODULE_PARM_DESC(use_hp_mr,
-                "Use high performance MRs (default: no)");
-MODULE_PARM_DESC(port_act_time,
-                "Time to wait for port activation (default: 30 sec)");
-MODULE_PARM_DESC(poll_all_eqs,
-                "Poll all event queues periodically (default: yes)");
-MODULE_PARM_DESC(static_rate,
-                "Set permanent static rate (default: no static rate)");
-MODULE_PARM_DESC(scaling_code,
-                "Enable scaling code (default: no)");
-MODULE_PARM_DESC(lock_hcalls,
-                "Serialize all hCalls made by the driver "
-                "(default: autodetect)");
-MODULE_PARM_DESC(number_of_cqs,
-               "Max number of CQs which can be allocated "
-               "(default: autodetect)");
-MODULE_PARM_DESC(number_of_qps,
-               "Max number of QPs which can be allocated "
-               "(default: autodetect)");
-
-DEFINE_RWLOCK(ehca_qp_idr_lock);
-DEFINE_RWLOCK(ehca_cq_idr_lock);
-DEFINE_IDR(ehca_qp_idr);
-DEFINE_IDR(ehca_cq_idr);
-
-static LIST_HEAD(shca_list); /* list of all registered ehcas */
-DEFINE_SPINLOCK(shca_list_lock);
-
-static struct timer_list poll_eqs_timer;
-
-#ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache;
-
-void *ehca_alloc_fw_ctrlblock(gfp_t flags)
-{
-       void *ret = kmem_cache_zalloc(ctblk_cache, flags);
-       if (!ret)
-               ehca_gen_err("Out of memory for ctblk");
-       return ret;
-}
-
-void ehca_free_fw_ctrlblock(void *ptr)
-{
-       if (ptr)
-               kmem_cache_free(ctblk_cache, ptr);
-
-}
-#endif
-
-int ehca2ib_return_code(u64 ehca_rc)
-{
-       switch (ehca_rc) {
-       case H_SUCCESS:
-               return 0;
-       case H_RESOURCE:             /* Resource in use */
-       case H_BUSY:
-               return -EBUSY;
-       case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-       case H_CONSTRAINED:          /* resource constraint */
-       case H_NO_MEM:
-               return -ENOMEM;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int ehca_create_slab_caches(void)
-{
-       int ret;
-
-       ret = ehca_init_pd_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create PD SLAB cache.");
-               return ret;
-       }
-
-       ret = ehca_init_cq_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create CQ SLAB cache.");
-               goto create_slab_caches2;
-       }
-
-       ret = ehca_init_qp_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create QP SLAB cache.");
-               goto create_slab_caches3;
-       }
-
-       ret = ehca_init_av_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create AV SLAB cache.");
-               goto create_slab_caches4;
-       }
-
-       ret = ehca_init_mrmw_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create MR&MW SLAB cache.");
-               goto create_slab_caches5;
-       }
-
-       ret = ehca_init_small_qp_cache();
-       if (ret) {
-               ehca_gen_err("Cannot create small queue SLAB cache.");
-               goto create_slab_caches6;
-       }
-
-#ifdef CONFIG_PPC_64K_PAGES
-       ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
-                                       EHCA_PAGESIZE, H_CB_ALIGNMENT,
-                                       SLAB_HWCACHE_ALIGN,
-                                       NULL);
-       if (!ctblk_cache) {
-               ehca_gen_err("Cannot create ctblk SLAB cache.");
-               ehca_cleanup_small_qp_cache();
-               ret = -ENOMEM;
-               goto create_slab_caches6;
-       }
-#endif
-       return 0;
-
-create_slab_caches6:
-       ehca_cleanup_mrmw_cache();
-
-create_slab_caches5:
-       ehca_cleanup_av_cache();
-
-create_slab_caches4:
-       ehca_cleanup_qp_cache();
-
-create_slab_caches3:
-       ehca_cleanup_cq_cache();
-
-create_slab_caches2:
-       ehca_cleanup_pd_cache();
-
-       return ret;
-}
-
-static void ehca_destroy_slab_caches(void)
-{
-       ehca_cleanup_small_qp_cache();
-       ehca_cleanup_mrmw_cache();
-       ehca_cleanup_av_cache();
-       ehca_cleanup_qp_cache();
-       ehca_cleanup_cq_cache();
-       ehca_cleanup_pd_cache();
-#ifdef CONFIG_PPC_64K_PAGES
-       kmem_cache_destroy(ctblk_cache);
-#endif
-}
-
-#define EHCA_HCAAVER  EHCA_BMASK_IBM(32, 39)
-#define EHCA_REVID    EHCA_BMASK_IBM(40, 63)
-
-static struct cap_descr {
-       u64 mask;
-       char *descr;
-} hca_cap_descr[] = {
-       { HCA_CAP_AH_PORT_NR_CHECK, "HCA_CAP_AH_PORT_NR_CHECK" },
-       { HCA_CAP_ATOMIC, "HCA_CAP_ATOMIC" },
-       { HCA_CAP_AUTO_PATH_MIG, "HCA_CAP_AUTO_PATH_MIG" },
-       { HCA_CAP_BAD_P_KEY_CTR, "HCA_CAP_BAD_P_KEY_CTR" },
-       { HCA_CAP_SQD_RTS_PORT_CHANGE, "HCA_CAP_SQD_RTS_PORT_CHANGE" },
-       { HCA_CAP_CUR_QP_STATE_MOD, "HCA_CAP_CUR_QP_STATE_MOD" },
-       { HCA_CAP_INIT_TYPE, "HCA_CAP_INIT_TYPE" },
-       { HCA_CAP_PORT_ACTIVE_EVENT, "HCA_CAP_PORT_ACTIVE_EVENT" },
-       { HCA_CAP_Q_KEY_VIOL_CTR, "HCA_CAP_Q_KEY_VIOL_CTR" },
-       { HCA_CAP_WQE_RESIZE, "HCA_CAP_WQE_RESIZE" },
-       { HCA_CAP_RAW_PACKET_MCAST, "HCA_CAP_RAW_PACKET_MCAST" },
-       { HCA_CAP_SHUTDOWN_PORT, "HCA_CAP_SHUTDOWN_PORT" },
-       { HCA_CAP_RC_LL_QP, "HCA_CAP_RC_LL_QP" },
-       { HCA_CAP_SRQ, "HCA_CAP_SRQ" },
-       { HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" },
-       { HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" },
-       { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" },
-       { HCA_CAP_H_ALLOC_RES_SYNC, "HCA_CAP_H_ALLOC_RES_SYNC" },
-};
-
-static int ehca_sense_attributes(struct ehca_shca *shca)
-{
-       int i, ret = 0;
-       u64 h_ret;
-       struct hipz_query_hca *rblock;
-       struct hipz_query_port *port;
-       const char *loc_code;
-
-       static const u32 pgsize_map[] = {
-               HCA_CAP_MR_PGSIZE_4K,  0x1000,
-               HCA_CAP_MR_PGSIZE_64K, 0x10000,
-               HCA_CAP_MR_PGSIZE_1M,  0x100000,
-               HCA_CAP_MR_PGSIZE_16M, 0x1000000,
-       };
-
-       ehca_gen_dbg("Probing adapter %s...",
-                    shca->ofdev->dev.of_node->full_name);
-       loc_code = of_get_property(shca->ofdev->dev.of_node, "ibm,loc-code",
-                                  NULL);
-       if (loc_code)
-               ehca_gen_dbg(" ... location lode=%s", loc_code);
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_gen_err("Cannot allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
-       if (h_ret != H_SUCCESS) {
-               ehca_gen_err("Cannot query device properties. h_ret=%lli",
-                            h_ret);
-               ret = -EPERM;
-               goto sense_attributes1;
-       }
-
-       if (ehca_nr_ports == 1)
-               shca->num_ports = 1;
-       else
-               shca->num_ports = (u8)rblock->num_ports;
-
-       ehca_gen_dbg(" ... found %x ports", rblock->num_ports);
-
-       if (ehca_hw_level == 0) {
-               u32 hcaaver;
-               u32 revid;
-
-               hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);
-               revid   = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);
-
-               ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
-
-               if (hcaaver == 1) {
-                       if (revid <= 3)
-                               shca->hw_level = 0x10 | (revid + 1);
-                       else
-                               shca->hw_level = 0x14;
-               } else if (hcaaver == 2) {
-                       if (revid == 0)
-                               shca->hw_level = 0x21;
-                       else if (revid == 0x10)
-                               shca->hw_level = 0x22;
-                       else if (revid == 0x20 || revid == 0x21)
-                               shca->hw_level = 0x23;
-               }
-
-               if (!shca->hw_level) {
-                       ehca_gen_warn("unknown hardware version"
-                                     " - assuming default level");
-                       shca->hw_level = 0x22;
-               }
-       } else
-               shca->hw_level = ehca_hw_level;
-       ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
-
-       shca->hca_cap = rblock->hca_cap_indicators;
-       ehca_gen_dbg(" ... HCA capabilities:");
-       for (i = 0; i < ARRAY_SIZE(hca_cap_descr); i++)
-               if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
-                       ehca_gen_dbg("   %s", hca_cap_descr[i].descr);
-
-       /* Autodetect hCall locking -- the "H_ALLOC_RESOURCE synced" flag is
-        * a firmware property, so it's valid across all adapters
-        */
-       if (ehca_lock_hcalls == -1)
-               ehca_lock_hcalls = !EHCA_BMASK_GET(HCA_CAP_H_ALLOC_RES_SYNC,
-                                       shca->hca_cap);
-
-       /* translate supported MR page sizes; always support 4K */
-       shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;
-       for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)
-               if (rblock->memory_page_size_supported & pgsize_map[i])
-                       shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
-
-       /* Set maximum number of CQs and QPs to calculate EQ size */
-       if (shca->max_num_qps == -1)
-               shca->max_num_qps = min_t(int, rblock->max_qp,
-                                         EHCA_MAX_NUM_QUEUES);
-       else if (shca->max_num_qps < 1 || shca->max_num_qps > rblock->max_qp) {
-               ehca_gen_warn("The requested number of QPs is out of range "
-                             "(1 - %i) specified by HW. Value is set to %i",
-                             rblock->max_qp, rblock->max_qp);
-               shca->max_num_qps = rblock->max_qp;
-       }
-
-       if (shca->max_num_cqs == -1)
-               shca->max_num_cqs = min_t(int, rblock->max_cq,
-                                         EHCA_MAX_NUM_QUEUES);
-       else if (shca->max_num_cqs < 1 || shca->max_num_cqs > rblock->max_cq) {
-               ehca_gen_warn("The requested number of CQs is out of range "
-                             "(1 - %i) specified by HW. Value is set to %i",
-                             rblock->max_cq, rblock->max_cq);
-       }
-
-       /* query max MTU from first port -- it's the same for all ports */
-       port = (struct hipz_query_port *)rblock;
-       h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
-       if (h_ret != H_SUCCESS) {
-               ehca_gen_err("Cannot query port properties. h_ret=%lli",
-                            h_ret);
-               ret = -EPERM;
-               goto sense_attributes1;
-       }
-
-       shca->max_mtu = port->max_mtu;
-
-sense_attributes1:
-       ehca_free_fw_ctrlblock(rblock);
-       return ret;
-}
-
-static int init_node_guid(struct ehca_shca *shca)
-{
-       int ret = 0;
-       struct hipz_query_hca *rblock;
-
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!rblock) {
-               ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
-               return -ENOMEM;
-       }
-
-       if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "Can't query device properties");
-               ret = -EINVAL;
-               goto init_node_guid1;
-       }
-
-       memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64));
-
-init_node_guid1:
-       ehca_free_fw_ctrlblock(rblock);
-       return ret;
-}
-
-static int ehca_port_immutable(struct ib_device *ibdev, u8 port_num,
-                              struct ib_port_immutable *immutable)
-{
-       struct ib_port_attr attr;
-       int err;
-
-       err = ehca_query_port(ibdev, port_num, &attr);
-       if (err)
-               return err;
-
-       immutable->pkey_tbl_len = attr.pkey_tbl_len;
-       immutable->gid_tbl_len = attr.gid_tbl_len;
-       immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
-       immutable->max_mad_size = IB_MGMT_MAD_SIZE;
-
-       return 0;
-}
-
-static int ehca_init_device(struct ehca_shca *shca)
-{
-       int ret;
-
-       ret = init_node_guid(shca);
-       if (ret)
-               return ret;
-
-       strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
-       shca->ib_device.owner               = THIS_MODULE;
-
-       shca->ib_device.uverbs_abi_ver      = 8;
-       shca->ib_device.uverbs_cmd_mask     =
-               (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
-               (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
-               (1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
-               (1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
-               (1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
-               (1ull << IB_USER_VERBS_CMD_REG_MR)              |
-               (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
-               (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
-               (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
-               (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
-               (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
-               (1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
-               (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
-               (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
-
-       shca->ib_device.node_type           = RDMA_NODE_IB_CA;
-       shca->ib_device.phys_port_cnt       = shca->num_ports;
-       shca->ib_device.num_comp_vectors    = 1;
-       shca->ib_device.dma_device          = &shca->ofdev->dev;
-       shca->ib_device.query_device        = ehca_query_device;
-       shca->ib_device.query_port          = ehca_query_port;
-       shca->ib_device.query_gid           = ehca_query_gid;
-       shca->ib_device.query_pkey          = ehca_query_pkey;
-       /* shca->in_device.modify_device    = ehca_modify_device    */
-       shca->ib_device.modify_port         = ehca_modify_port;
-       shca->ib_device.alloc_ucontext      = ehca_alloc_ucontext;
-       shca->ib_device.dealloc_ucontext    = ehca_dealloc_ucontext;
-       shca->ib_device.alloc_pd            = ehca_alloc_pd;
-       shca->ib_device.dealloc_pd          = ehca_dealloc_pd;
-       shca->ib_device.create_ah           = ehca_create_ah;
-       /* shca->ib_device.modify_ah        = ehca_modify_ah;       */
-       shca->ib_device.query_ah            = ehca_query_ah;
-       shca->ib_device.destroy_ah          = ehca_destroy_ah;
-       shca->ib_device.create_qp           = ehca_create_qp;
-       shca->ib_device.modify_qp           = ehca_modify_qp;
-       shca->ib_device.query_qp            = ehca_query_qp;
-       shca->ib_device.destroy_qp          = ehca_destroy_qp;
-       shca->ib_device.post_send           = ehca_post_send;
-       shca->ib_device.post_recv           = ehca_post_recv;
-       shca->ib_device.create_cq           = ehca_create_cq;
-       shca->ib_device.destroy_cq          = ehca_destroy_cq;
-       shca->ib_device.resize_cq           = ehca_resize_cq;
-       shca->ib_device.poll_cq             = ehca_poll_cq;
-       /* shca->ib_device.peek_cq          = ehca_peek_cq;         */
-       shca->ib_device.req_notify_cq       = ehca_req_notify_cq;
-       /* shca->ib_device.req_ncomp_notif  = ehca_req_ncomp_notif; */
-       shca->ib_device.get_dma_mr          = ehca_get_dma_mr;
-       shca->ib_device.reg_user_mr         = ehca_reg_user_mr;
-       shca->ib_device.dereg_mr            = ehca_dereg_mr;
-       shca->ib_device.alloc_mw            = ehca_alloc_mw;
-       shca->ib_device.dealloc_mw          = ehca_dealloc_mw;
-       shca->ib_device.alloc_fmr           = ehca_alloc_fmr;
-       shca->ib_device.map_phys_fmr        = ehca_map_phys_fmr;
-       shca->ib_device.unmap_fmr           = ehca_unmap_fmr;
-       shca->ib_device.dealloc_fmr         = ehca_dealloc_fmr;
-       shca->ib_device.attach_mcast        = ehca_attach_mcast;
-       shca->ib_device.detach_mcast        = ehca_detach_mcast;
-       shca->ib_device.process_mad         = ehca_process_mad;
-       shca->ib_device.mmap                = ehca_mmap;
-       shca->ib_device.dma_ops             = &ehca_dma_mapping_ops;
-       shca->ib_device.get_port_immutable  = ehca_port_immutable;
-
-       if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
-               shca->ib_device.uverbs_cmd_mask |=
-                       (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
-                       (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
-                       (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
-                       (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
-
-               shca->ib_device.create_srq          = ehca_create_srq;
-               shca->ib_device.modify_srq          = ehca_modify_srq;
-               shca->ib_device.query_srq           = ehca_query_srq;
-               shca->ib_device.destroy_srq         = ehca_destroy_srq;
-               shca->ib_device.post_srq_recv       = ehca_post_srq_recv;
-       }
-
-       return ret;
-}
-
-static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
-{
-       struct ehca_sport *sport = &shca->sport[port - 1];
-       struct ib_cq *ibcq;
-       struct ib_qp *ibqp;
-       struct ib_qp_init_attr qp_init_attr;
-       struct ib_cq_init_attr cq_attr = {};
-       int ret;
-
-       if (sport->ibcq_aqp1) {
-               ehca_err(&shca->ib_device, "AQP1 CQ is already created.");
-               return -EPERM;
-       }
-
-       cq_attr.cqe = 10;
-       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1),
-                           &cq_attr);
-       if (IS_ERR(ibcq)) {
-               ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
-               return PTR_ERR(ibcq);
-       }
-       sport->ibcq_aqp1 = ibcq;
-
-       if (sport->ibqp_sqp[IB_QPT_GSI]) {
-               ehca_err(&shca->ib_device, "AQP1 QP is already created.");
-               ret = -EPERM;
-               goto create_aqp1;
-       }
-
-       memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
-       qp_init_attr.send_cq          = ibcq;
-       qp_init_attr.recv_cq          = ibcq;
-       qp_init_attr.sq_sig_type      = IB_SIGNAL_ALL_WR;
-       qp_init_attr.cap.max_send_wr  = 100;
-       qp_init_attr.cap.max_recv_wr  = 100;
-       qp_init_attr.cap.max_send_sge = 2;
-       qp_init_attr.cap.max_recv_sge = 1;
-       qp_init_attr.qp_type          = IB_QPT_GSI;
-       qp_init_attr.port_num         = port;
-       qp_init_attr.qp_context       = NULL;
-       qp_init_attr.event_handler    = NULL;
-       qp_init_attr.srq              = NULL;
-
-       ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);
-       if (IS_ERR(ibqp)) {
-               ehca_err(&shca->ib_device, "Cannot create AQP1 QP.");
-               ret = PTR_ERR(ibqp);
-               goto create_aqp1;
-       }
-       sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
-
-       return 0;
-
-create_aqp1:
-       ib_destroy_cq(sport->ibcq_aqp1);
-       return ret;
-}
-
-static int ehca_destroy_aqp1(struct ehca_sport *sport)
-{
-       int ret;
-
-       ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
-       if (ret) {
-               ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
-               return ret;
-       }
-
-       ret = ib_destroy_cq(sport->ibcq_aqp1);
-       if (ret)
-               ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret);
-
-       return ret;
-}
-
-static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d\n", ehca_debug_level);
-}
-
-static ssize_t ehca_store_debug_level(struct device_driver *ddp,
-                                     const char *buf, size_t count)
-{
-       int value = (*buf) - '0';
-       if (value >= 0 && value <= 9)
-               ehca_debug_level = value;
-       return 1;
-}
-
-static DRIVER_ATTR(debug_level, S_IRUSR | S_IWUSR,
-                  ehca_show_debug_level, ehca_store_debug_level);
-
-static struct attribute *ehca_drv_attrs[] = {
-       &driver_attr_debug_level.attr,
-       NULL
-};
-
-static struct attribute_group ehca_drv_attr_grp = {
-       .attrs = ehca_drv_attrs
-};
-
-static const struct attribute_group *ehca_drv_attr_groups[] = {
-       &ehca_drv_attr_grp,
-       NULL,
-};
-
-#define EHCA_RESOURCE_ATTR(name)                                           \
-static ssize_t  ehca_show_##name(struct device *dev,                       \
-                                struct device_attribute *attr,            \
-                                char *buf)                                \
-{                                                                         \
-       struct ehca_shca *shca;                                            \
-       struct hipz_query_hca *rblock;                                     \
-       int data;                                                          \
-                                                                          \
-       shca = dev_get_drvdata(dev);                                       \
-                                                                          \
-       rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);                      \
-       if (!rblock) {                                                     \
-               dev_err(dev, "Can't allocate rblock memory.\n");           \
-               return 0;                                                  \
-       }                                                                  \
-                                                                          \
-       if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
-               dev_err(dev, "Can't query device properties\n");           \
-               ehca_free_fw_ctrlblock(rblock);                            \
-               return 0;                                                  \
-       }                                                                  \
-                                                                          \
-       data = rblock->name;                                               \
-       ehca_free_fw_ctrlblock(rblock);                                    \
-                                                                          \
-       if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1))     \
-               return snprintf(buf, 256, "1\n");                          \
-       else                                                               \
-               return snprintf(buf, 256, "%d\n", data);                   \
-                                                                          \
-}                                                                         \
-static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);
-
-EHCA_RESOURCE_ATTR(num_ports);
-EHCA_RESOURCE_ATTR(hw_ver);
-EHCA_RESOURCE_ATTR(max_eq);
-EHCA_RESOURCE_ATTR(cur_eq);
-EHCA_RESOURCE_ATTR(max_cq);
-EHCA_RESOURCE_ATTR(cur_cq);
-EHCA_RESOURCE_ATTR(max_qp);
-EHCA_RESOURCE_ATTR(cur_qp);
-EHCA_RESOURCE_ATTR(max_mr);
-EHCA_RESOURCE_ATTR(cur_mr);
-EHCA_RESOURCE_ATTR(max_mw);
-EHCA_RESOURCE_ATTR(cur_mw);
-EHCA_RESOURCE_ATTR(max_pd);
-EHCA_RESOURCE_ATTR(max_ah);
-
-static ssize_t ehca_show_adapter_handle(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct ehca_shca *shca = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle);
-
-}
-static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
-
-static struct attribute *ehca_dev_attrs[] = {
-       &dev_attr_adapter_handle.attr,
-       &dev_attr_num_ports.attr,
-       &dev_attr_hw_ver.attr,
-       &dev_attr_max_eq.attr,
-       &dev_attr_cur_eq.attr,
-       &dev_attr_max_cq.attr,
-       &dev_attr_cur_cq.attr,
-       &dev_attr_max_qp.attr,
-       &dev_attr_cur_qp.attr,
-       &dev_attr_max_mr.attr,
-       &dev_attr_cur_mr.attr,
-       &dev_attr_max_mw.attr,
-       &dev_attr_cur_mw.attr,
-       &dev_attr_max_pd.attr,
-       &dev_attr_max_ah.attr,
-       NULL
-};
-
-static struct attribute_group ehca_dev_attr_grp = {
-       .attrs = ehca_dev_attrs
-};
-
-static int ehca_probe(struct platform_device *dev)
-{
-       struct ehca_shca *shca;
-       const u64 *handle;
-       struct ib_pd *ibpd;
-       int ret, i, eq_size;
-       unsigned long flags;
-
-       handle = of_get_property(dev->dev.of_node, "ibm,hca-handle", NULL);
-       if (!handle) {
-               ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
-                            dev->dev.of_node->full_name);
-               return -ENODEV;
-       }
-
-       if (!(*handle)) {
-               ehca_gen_err("Wrong eHCA handle for adapter: %s.",
-                            dev->dev.of_node->full_name);
-               return -ENODEV;
-       }
-
-       shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));
-       if (!shca) {
-               ehca_gen_err("Cannot allocate shca memory.");
-               return -ENOMEM;
-       }
-
-       mutex_init(&shca->modify_mutex);
-       atomic_set(&shca->num_cqs, 0);
-       atomic_set(&shca->num_qps, 0);
-       shca->max_num_qps = ehca_max_qp;
-       shca->max_num_cqs = ehca_max_cq;
-
-       for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
-               spin_lock_init(&shca->sport[i].mod_sqp_lock);
-
-       shca->ofdev = dev;
-       shca->ipz_hca_handle.handle = *handle;
-       dev_set_drvdata(&dev->dev, shca);
-
-       ret = ehca_sense_attributes(shca);
-       if (ret < 0) {
-               ehca_gen_err("Cannot sense eHCA attributes.");
-               goto probe1;
-       }
-
-       ret = ehca_init_device(shca);
-       if (ret) {
-               ehca_gen_err("Cannot init ehca  device struct");
-               goto probe1;
-       }
-
-       eq_size = 2 * shca->max_num_cqs + 4 * shca->max_num_qps;
-       /* create event queues */
-       ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);
-       if (ret) {
-               ehca_err(&shca->ib_device, "Cannot create EQ.");
-               goto probe1;
-       }
-
-       ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
-       if (ret) {
-               ehca_err(&shca->ib_device, "Cannot create NEQ.");
-               goto probe3;
-       }
-
-       /* create internal protection domain */
-       ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
-       if (IS_ERR(ibpd)) {
-               ehca_err(&shca->ib_device, "Cannot create internal PD.");
-               ret = PTR_ERR(ibpd);
-               goto probe4;
-       }
-
-       shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);
-       shca->pd->ib_pd.device = &shca->ib_device;
-
-       /* create internal max MR */
-       ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
-
-       if (ret) {
-               ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i",
-                        ret);
-               goto probe5;
-       }
-
-       ret = ib_register_device(&shca->ib_device, NULL);
-       if (ret) {
-               ehca_err(&shca->ib_device,
-                        "ib_register_device() failed ret=%i", ret);
-               goto probe6;
-       }
-
-       /* create AQP1 for port 1 */
-       if (ehca_open_aqp1 == 1) {
-               shca->sport[0].port_state = IB_PORT_DOWN;
-               ret = ehca_create_aqp1(shca, 1);
-               if (ret) {
-                       ehca_err(&shca->ib_device,
-                                "Cannot create AQP1 for port 1.");
-                       goto probe7;
-               }
-       }
-
-       /* create AQP1 for port 2 */
-       if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {
-               shca->sport[1].port_state = IB_PORT_DOWN;
-               ret = ehca_create_aqp1(shca, 2);
-               if (ret) {
-                       ehca_err(&shca->ib_device,
-                                "Cannot create AQP1 for port 2.");
-                       goto probe8;
-               }
-       }
-
-       ret = sysfs_create_group(&dev->dev.kobj, &ehca_dev_attr_grp);
-       if (ret) /* only complain; we can live without attributes */
-               ehca_err(&shca->ib_device,
-                        "Cannot create device attributes  ret=%d", ret);
-
-       spin_lock_irqsave(&shca_list_lock, flags);
-       list_add(&shca->shca_list, &shca_list);
-       spin_unlock_irqrestore(&shca_list_lock, flags);
-
-       return 0;
-
-probe8:
-       ret = ehca_destroy_aqp1(&shca->sport[0]);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy AQP1 for port 1. ret=%i", ret);
-
-probe7:
-       ib_unregister_device(&shca->ib_device);
-
-probe6:
-       ret = ehca_dereg_internal_maxmr(shca);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy internal MR. ret=%x", ret);
-
-probe5:
-       ret = ehca_dealloc_pd(&shca->pd->ib_pd);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy internal PD. ret=%x", ret);
-
-probe4:
-       ret = ehca_destroy_eq(shca, &shca->neq);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy NEQ. ret=%x", ret);
-
-probe3:
-       ret = ehca_destroy_eq(shca, &shca->eq);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy EQ. ret=%x", ret);
-
-probe1:
-       ib_dealloc_device(&shca->ib_device);
-
-       return -EINVAL;
-}
-
-static int ehca_remove(struct platform_device *dev)
-{
-       struct ehca_shca *shca = dev_get_drvdata(&dev->dev);
-       unsigned long flags;
-       int ret;
-
-       sysfs_remove_group(&dev->dev.kobj, &ehca_dev_attr_grp);
-
-       if (ehca_open_aqp1 == 1) {
-               int i;
-               for (i = 0; i < shca->num_ports; i++) {
-                       ret = ehca_destroy_aqp1(&shca->sport[i]);
-                       if (ret)
-                               ehca_err(&shca->ib_device,
-                                        "Cannot destroy AQP1 for port %x "
-                                        "ret=%i", ret, i);
-               }
-       }
-
-       ib_unregister_device(&shca->ib_device);
-
-       ret = ehca_dereg_internal_maxmr(shca);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy internal MR. ret=%i", ret);
-
-       ret = ehca_dealloc_pd(&shca->pd->ib_pd);
-       if (ret)
-               ehca_err(&shca->ib_device,
-                        "Cannot destroy internal PD. ret=%i", ret);
-
-       ret = ehca_destroy_eq(shca, &shca->eq);
-       if (ret)
-               ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret);
-
-       ret = ehca_destroy_eq(shca, &shca->neq);
-       if (ret)
-               ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret);
-
-       ib_dealloc_device(&shca->ib_device);
-
-       spin_lock_irqsave(&shca_list_lock, flags);
-       list_del(&shca->shca_list);
-       spin_unlock_irqrestore(&shca_list_lock, flags);
-
-       return ret;
-}
-
-static struct of_device_id ehca_device_table[] =
-{
-       {
-               .name       = "lhca",
-               .compatible = "IBM,lhca",
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ehca_device_table);
-
-static struct platform_driver ehca_driver = {
-       .probe       = ehca_probe,
-       .remove      = ehca_remove,
-       .driver = {
-               .name = "ehca",
-               .owner = THIS_MODULE,
-               .groups = ehca_drv_attr_groups,
-               .of_match_table = ehca_device_table,
-       },
-};
-
-void ehca_poll_eqs(unsigned long data)
-{
-       struct ehca_shca *shca;
-
-       spin_lock(&shca_list_lock);
-       list_for_each_entry(shca, &shca_list, shca_list) {
-               if (shca->eq.is_initialized) {
-                       /* call deadman proc only if eq ptr does not change */
-                       struct ehca_eq *eq = &shca->eq;
-                       int max = 3;
-                       volatile u64 q_ofs, q_ofs2;
-                       unsigned long flags;
-                       spin_lock_irqsave(&eq->spinlock, flags);
-                       q_ofs = eq->ipz_queue.current_q_offset;
-                       spin_unlock_irqrestore(&eq->spinlock, flags);
-                       do {
-                               spin_lock_irqsave(&eq->spinlock, flags);
-                               q_ofs2 = eq->ipz_queue.current_q_offset;
-                               spin_unlock_irqrestore(&eq->spinlock, flags);
-                               max--;
-                       } while (q_ofs == q_ofs2 && max > 0);
-                       if (q_ofs == q_ofs2)
-                               ehca_process_eq(shca, 0);
-               }
-       }
-       mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
-       spin_unlock(&shca_list_lock);
-}
-
-static int ehca_mem_notifier(struct notifier_block *nb,
-                            unsigned long action, void *data)
-{
-       static unsigned long ehca_dmem_warn_time;
-       unsigned long flags;
-
-       switch (action) {
-       case MEM_CANCEL_OFFLINE:
-       case MEM_CANCEL_ONLINE:
-       case MEM_ONLINE:
-       case MEM_OFFLINE:
-               return NOTIFY_OK;
-       case MEM_GOING_ONLINE:
-       case MEM_GOING_OFFLINE:
-               /* only ok if no hca is attached to the lpar */
-               spin_lock_irqsave(&shca_list_lock, flags);
-               if (list_empty(&shca_list)) {
-                       spin_unlock_irqrestore(&shca_list_lock, flags);
-                       return NOTIFY_OK;
-               } else {
-                       spin_unlock_irqrestore(&shca_list_lock, flags);
-                       if (printk_timed_ratelimit(&ehca_dmem_warn_time,
-                                                  30 * 1000))
-                               ehca_gen_err("DMEM operations are not allowed"
-                                            "in conjunction with eHCA");
-                       return NOTIFY_BAD;
-               }
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block ehca_mem_nb = {
-       .notifier_call = ehca_mem_notifier,
-};
-
-static int __init ehca_module_init(void)
-{
-       int ret;
-
-       printk(KERN_INFO "eHCA Infiniband Device Driver "
-              "(Version " HCAD_VERSION ")\n");
-
-       ret = ehca_create_comp_pool();
-       if (ret) {
-               ehca_gen_err("Cannot create comp pool.");
-               return ret;
-       }
-
-       ret = ehca_create_slab_caches();
-       if (ret) {
-               ehca_gen_err("Cannot create SLAB caches");
-               ret = -ENOMEM;
-               goto module_init1;
-       }
-
-       ret = ehca_create_busmap();
-       if (ret) {
-               ehca_gen_err("Cannot create busmap.");
-               goto module_init2;
-       }
-
-       ret = ibmebus_register_driver(&ehca_driver);
-       if (ret) {
-               ehca_gen_err("Cannot register eHCA device driver");
-               ret = -EINVAL;
-               goto module_init3;
-       }
-
-       ret = register_memory_notifier(&ehca_mem_nb);
-       if (ret) {
-               ehca_gen_err("Failed registering memory add/remove notifier");
-               goto module_init4;
-       }
-
-       if (ehca_poll_all_eqs != 1) {
-               ehca_gen_err("WARNING!!!");
-               ehca_gen_err("It is possible to lose interrupts.");
-       } else {
-               init_timer(&poll_eqs_timer);
-               poll_eqs_timer.function = ehca_poll_eqs;
-               poll_eqs_timer.expires = jiffies + HZ;
-               add_timer(&poll_eqs_timer);
-       }
-
-       return 0;
-
-module_init4:
-       ibmebus_unregister_driver(&ehca_driver);
-
-module_init3:
-       ehca_destroy_busmap();
-
-module_init2:
-       ehca_destroy_slab_caches();
-
-module_init1:
-       ehca_destroy_comp_pool();
-       return ret;
-};
-
-static void __exit ehca_module_exit(void)
-{
-       if (ehca_poll_all_eqs == 1)
-               del_timer_sync(&poll_eqs_timer);
-
-       ibmebus_unregister_driver(&ehca_driver);
-
-       unregister_memory_notifier(&ehca_mem_nb);
-
-       ehca_destroy_busmap();
-
-       ehca_destroy_slab_caches();
-
-       ehca_destroy_comp_pool();
-
-       idr_destroy(&ehca_cq_idr);
-       idr_destroy(&ehca_qp_idr);
-};
-
-module_init(ehca_module_init);
-module_exit(ehca_module_exit);
diff --git a/drivers/staging/rdma/ehca/ehca_mcast.c b/drivers/staging/rdma/ehca/ehca_mcast.c
deleted file mode 100644 (file)
index cec1815..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  mcast  functions
- *
- *  Authors: Khadija Souissi <souissik@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include "ehca_classes.h"
-#include "ehca_tools.h"
-#include "ehca_qes.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-
-#define MAX_MC_LID 0xFFFE
-#define MIN_MC_LID 0xC000      /* Multicast limits */
-#define EHCA_VALID_MULTICAST_GID(gid)  ((gid)[0] == 0xFF)
-#define EHCA_VALID_MULTICAST_LID(lid) \
-       (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID))
-
-int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
-       struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
-                                             ib_device);
-       union ib_gid my_gid;
-       u64 subnet_prefix, interface_id, h_ret;
-
-       if (ibqp->qp_type != IB_QPT_UD) {
-               ehca_err(ibqp->device, "invalid qp_type=%x", ibqp->qp_type);
-               return -EINVAL;
-       }
-
-       if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
-               ehca_err(ibqp->device, "invalid mulitcast gid");
-               return -EINVAL;
-       } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
-               ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
-               return -EINVAL;
-       }
-
-       memcpy(&my_gid, gid->raw, sizeof(union ib_gid));
-
-       subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
-       interface_id = be64_to_cpu(my_gid.global.interface_id);
-       h_ret = hipz_h_attach_mcqp(shca->ipz_hca_handle,
-                                  my_qp->ipz_qp_handle,
-                                  my_qp->galpas.kernel,
-                                  lid, subnet_prefix, interface_id);
-       if (h_ret != H_SUCCESS)
-               ehca_err(ibqp->device,
-                        "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
-                        "h_ret=%lli", my_qp, ibqp->qp_num, h_ret);
-
-       return ehca2ib_return_code(h_ret);
-}
-
-int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
-       struct ehca_shca *shca = container_of(ibqp->pd->device,
-                                             struct ehca_shca, ib_device);
-       union ib_gid my_gid;
-       u64 subnet_prefix, interface_id, h_ret;
-
-       if (ibqp->qp_type != IB_QPT_UD) {
-               ehca_err(ibqp->device, "invalid qp_type %x", ibqp->qp_type);
-               return -EINVAL;
-       }
-
-       if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
-               ehca_err(ibqp->device, "invalid mulitcast gid");
-               return -EINVAL;
-       } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
-               ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
-               return -EINVAL;
-       }
-
-       memcpy(&my_gid, gid->raw, sizeof(union ib_gid));
-
-       subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
-       interface_id = be64_to_cpu(my_gid.global.interface_id);
-       h_ret = hipz_h_detach_mcqp(shca->ipz_hca_handle,
-                                  my_qp->ipz_qp_handle,
-                                  my_qp->galpas.kernel,
-                                  lid, subnet_prefix, interface_id);
-       if (h_ret != H_SUCCESS)
-               ehca_err(ibqp->device,
-                        "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
-                        "h_ret=%lli", my_qp, ibqp->qp_num, h_ret);
-
-       return ehca2ib_return_code(h_ret);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_mrmw.c b/drivers/staging/rdma/ehca/ehca_mrmw.c
deleted file mode 100644 (file)
index 3367205..0000000
+++ /dev/null
@@ -1,2202 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  MR/MW functions
- *
- *  Authors: Dietmar Decker <ddecker@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-#include <rdma/ib_umem.h>
-
-#include "ehca_iverbs.h"
-#include "ehca_mrmw.h"
-#include "hcp_if.h"
-#include "hipz_hw.h"
-
-#define NUM_CHUNKS(length, chunk_size) \
-       (((length) + (chunk_size - 1)) / (chunk_size))
-
-/* max number of rpages (per hcall register_rpages) */
-#define MAX_RPAGES 512
-
-/* DMEM toleration management */
-#define EHCA_SECTSHIFT        SECTION_SIZE_BITS
-#define EHCA_SECTSIZE          (1UL << EHCA_SECTSHIFT)
-#define EHCA_HUGEPAGESHIFT     34
-#define EHCA_HUGEPAGE_SIZE     (1UL << EHCA_HUGEPAGESHIFT)
-#define EHCA_HUGEPAGE_PFN_MASK ((EHCA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT)
-#define EHCA_INVAL_ADDR        0xFFFFFFFFFFFFFFFFULL
-#define EHCA_DIR_INDEX_SHIFT 13                   /* 8k Entries in 64k block */
-#define EHCA_TOP_INDEX_SHIFT (EHCA_DIR_INDEX_SHIFT * 2)
-#define EHCA_MAP_ENTRIES (1 << EHCA_DIR_INDEX_SHIFT)
-#define EHCA_TOP_MAP_SIZE (0x10000)               /* currently fixed map size */
-#define EHCA_DIR_MAP_SIZE (0x10000)
-#define EHCA_ENT_MAP_SIZE (0x10000)
-#define EHCA_INDEX_MASK (EHCA_MAP_ENTRIES - 1)
-
-static unsigned long ehca_mr_len;
-
-/*
- * Memory map data structures
- */
-struct ehca_dir_bmap {
-       u64 ent[EHCA_MAP_ENTRIES];
-};
-struct ehca_top_bmap {
-       struct ehca_dir_bmap *dir[EHCA_MAP_ENTRIES];
-};
-struct ehca_bmap {
-       struct ehca_top_bmap *top[EHCA_MAP_ENTRIES];
-};
-
-static struct ehca_bmap *ehca_bmap;
-
-static struct kmem_cache *mr_cache;
-static struct kmem_cache *mw_cache;
-
-enum ehca_mr_pgsize {
-       EHCA_MR_PGSIZE4K  = 0x1000L,
-       EHCA_MR_PGSIZE64K = 0x10000L,
-       EHCA_MR_PGSIZE1M  = 0x100000L,
-       EHCA_MR_PGSIZE16M = 0x1000000L
-};
-
-#define EHCA_MR_PGSHIFT4K  12
-#define EHCA_MR_PGSHIFT64K 16
-#define EHCA_MR_PGSHIFT1M  20
-#define EHCA_MR_PGSHIFT16M 24
-
-static u64 ehca_map_vaddr(void *caddr);
-
-static u32 ehca_encode_hwpage_size(u32 pgsize)
-{
-       int log = ilog2(pgsize);
-       WARN_ON(log < 12 || log > 24 || log & 3);
-       return (log - 12) / 4;
-}
-
-static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
-{
-       return rounddown_pow_of_two(shca->hca_cap_mr_pgsize);
-}
-
-static struct ehca_mr *ehca_mr_new(void)
-{
-       struct ehca_mr *me;
-
-       me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
-       if (me)
-               spin_lock_init(&me->mrlock);
-       else
-               ehca_gen_err("alloc failed");
-
-       return me;
-}
-
-static void ehca_mr_delete(struct ehca_mr *me)
-{
-       kmem_cache_free(mr_cache, me);
-}
-
-static struct ehca_mw *ehca_mw_new(void)
-{
-       struct ehca_mw *me;
-
-       me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
-       if (me)
-               spin_lock_init(&me->mwlock);
-       else
-               ehca_gen_err("alloc failed");
-
-       return me;
-}
-
-static void ehca_mw_delete(struct ehca_mw *me)
-{
-       kmem_cache_free(mw_cache, me);
-}
-
-/*----------------------------------------------------------------------*/
-
-struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
-{
-       struct ib_mr *ib_mr;
-       int ret;
-       struct ehca_mr *e_maxmr;
-       struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_shca *shca =
-               container_of(pd->device, struct ehca_shca, ib_device);
-
-       if (shca->maxmr) {
-               e_maxmr = ehca_mr_new();
-               if (!e_maxmr) {
-                       ehca_err(&shca->ib_device, "out of memory");
-                       ib_mr = ERR_PTR(-ENOMEM);
-                       goto get_dma_mr_exit0;
-               }
-
-               ret = ehca_reg_maxmr(shca, e_maxmr,
-                                    (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)),
-                                    mr_access_flags, e_pd,
-                                    &e_maxmr->ib.ib_mr.lkey,
-                                    &e_maxmr->ib.ib_mr.rkey);
-               if (ret) {
-                       ehca_mr_delete(e_maxmr);
-                       ib_mr = ERR_PTR(ret);
-                       goto get_dma_mr_exit0;
-               }
-               ib_mr = &e_maxmr->ib.ib_mr;
-       } else {
-               ehca_err(&shca->ib_device, "no internal max-MR exist!");
-               ib_mr = ERR_PTR(-EINVAL);
-               goto get_dma_mr_exit0;
-       }
-
-get_dma_mr_exit0:
-       if (IS_ERR(ib_mr))
-               ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x",
-                        PTR_ERR(ib_mr), pd, mr_access_flags);
-       return ib_mr;
-} /* end ehca_get_dma_mr() */
-
-/*----------------------------------------------------------------------*/
-
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
-                              u64 virt, int mr_access_flags,
-                              struct ib_udata *udata)
-{
-       struct ib_mr *ib_mr;
-       struct ehca_mr *e_mr;
-       struct ehca_shca *shca =
-               container_of(pd->device, struct ehca_shca, ib_device);
-       struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo;
-       int ret, page_shift;
-       u32 num_kpages;
-       u32 num_hwpages;
-       u64 hwpage_size;
-
-       if (!pd) {
-               ehca_gen_err("bad pd=%p", pd);
-               return ERR_PTR(-EFAULT);
-       }
-
-       if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
-            !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
-           ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
-            !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
-               /*
-                * Remote Write Access requires Local Write Access
-                * Remote Atomic Access requires Local Write Access
-                */
-               ehca_err(pd->device, "bad input values: mr_access_flags=%x",
-                        mr_access_flags);
-               ib_mr = ERR_PTR(-EINVAL);
-               goto reg_user_mr_exit0;
-       }
-
-       if (length == 0 || virt + length < virt) {
-               ehca_err(pd->device, "bad input values: length=%llx "
-                        "virt_base=%llx", length, virt);
-               ib_mr = ERR_PTR(-EINVAL);
-               goto reg_user_mr_exit0;
-       }
-
-       e_mr = ehca_mr_new();
-       if (!e_mr) {
-               ehca_err(pd->device, "out of memory");
-               ib_mr = ERR_PTR(-ENOMEM);
-               goto reg_user_mr_exit0;
-       }
-
-       e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
-                                mr_access_flags, 0);
-       if (IS_ERR(e_mr->umem)) {
-               ib_mr = (void *)e_mr->umem;
-               goto reg_user_mr_exit1;
-       }
-
-       if (e_mr->umem->page_size != PAGE_SIZE) {
-               ehca_err(pd->device, "page size not supported, "
-                        "e_mr->umem->page_size=%x", e_mr->umem->page_size);
-               ib_mr = ERR_PTR(-EINVAL);
-               goto reg_user_mr_exit2;
-       }
-
-       /* determine number of MR pages */
-       num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
-       /* select proper hw_pgsize */
-       page_shift = PAGE_SHIFT;
-       if (e_mr->umem->hugetlb) {
-               /* determine page_shift, clamp between 4K and 16M */
-               page_shift = (fls64(length - 1) + 3) & ~3;
-               page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
-                                EHCA_MR_PGSHIFT16M);
-       }
-       hwpage_size = 1UL << page_shift;
-
-       /* now that we have the desired page size, shift until it's
-        * supported, too. 4K is always supported, so this terminates.
-        */
-       while (!(hwpage_size & shca->hca_cap_mr_pgsize))
-               hwpage_size >>= 4;
-
-reg_user_mr_fallback:
-       num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
-       /* register MR on HCA */
-       memset(&pginfo, 0, sizeof(pginfo));
-       pginfo.type = EHCA_MR_PGI_USER;
-       pginfo.hwpage_size = hwpage_size;
-       pginfo.num_kpages = num_kpages;
-       pginfo.num_hwpages = num_hwpages;
-       pginfo.u.usr.region = e_mr->umem;
-       pginfo.next_hwpage = ib_umem_offset(e_mr->umem) / hwpage_size;
-       pginfo.u.usr.next_sg = pginfo.u.usr.region->sg_head.sgl;
-       ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
-                         e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
-                         &e_mr->ib.ib_mr.rkey, EHCA_REG_MR);
-       if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
-               ehca_warn(pd->device, "failed to register mr "
-                         "with hwpage_size=%llx", hwpage_size);
-               ehca_info(pd->device, "try to register mr with "
-                         "kpage_size=%lx", PAGE_SIZE);
-               /*
-                * this means kpages are not contiguous for a hw page
-                * try kernel page size as fallback solution
-                */
-               hwpage_size = PAGE_SIZE;
-               goto reg_user_mr_fallback;
-       }
-       if (ret) {
-               ib_mr = ERR_PTR(ret);
-               goto reg_user_mr_exit2;
-       }
-
-       /* successful registration of all pages */
-       return &e_mr->ib.ib_mr;
-
-reg_user_mr_exit2:
-       ib_umem_release(e_mr->umem);
-reg_user_mr_exit1:
-       ehca_mr_delete(e_mr);
-reg_user_mr_exit0:
-       if (IS_ERR(ib_mr))
-               ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p",
-                        PTR_ERR(ib_mr), pd, mr_access_flags, udata);
-       return ib_mr;
-} /* end ehca_reg_user_mr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_dereg_mr(struct ib_mr *mr)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct ehca_shca *shca =
-               container_of(mr->device, struct ehca_shca, ib_device);
-       struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
-
-       if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
-               ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p "
-                        "e_mr->flags=%x", mr, e_mr, e_mr->flags);
-               ret = -EINVAL;
-               goto dereg_mr_exit0;
-       } else if (e_mr == shca->maxmr) {
-               /* should be impossible, however reject to be sure */
-               ehca_err(mr->device, "dereg internal max-MR impossible, mr=%p "
-                        "shca->maxmr=%p mr->lkey=%x",
-                        mr, shca->maxmr, mr->lkey);
-               ret = -EINVAL;
-               goto dereg_mr_exit0;
-       }
-
-       /* TODO: BUSY: MR still has bound window(s) */
-       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lli shca=%p "
-                        "e_mr=%p hca_hndl=%llx mr_hndl=%llx mr->lkey=%x",
-                        h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
-                        e_mr->ipz_mr_handle.handle, mr->lkey);
-               ret = ehca2ib_return_code(h_ret);
-               goto dereg_mr_exit0;
-       }
-
-       if (e_mr->umem)
-               ib_umem_release(e_mr->umem);
-
-       /* successful deregistration */
-       ehca_mr_delete(e_mr);
-
-dereg_mr_exit0:
-       if (ret)
-               ehca_err(mr->device, "ret=%i mr=%p", ret, mr);
-       return ret;
-} /* end ehca_dereg_mr() */
-
-/*----------------------------------------------------------------------*/
-
-struct ib_mw *ehca_alloc_mw(struct ib_pd *pd, enum ib_mw_type type)
-{
-       struct ib_mw *ib_mw;
-       u64 h_ret;
-       struct ehca_mw *e_mw;
-       struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_shca *shca =
-               container_of(pd->device, struct ehca_shca, ib_device);
-       struct ehca_mw_hipzout_parms hipzout;
-
-       if (type != IB_MW_TYPE_1)
-               return ERR_PTR(-EINVAL);
-
-       e_mw = ehca_mw_new();
-       if (!e_mw) {
-               ib_mw = ERR_PTR(-ENOMEM);
-               goto alloc_mw_exit0;
-       }
-
-       h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
-                                        e_pd->fw_pd, &hipzout);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lli "
-                        "shca=%p hca_hndl=%llx mw=%p",
-                        h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
-               ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
-               goto alloc_mw_exit1;
-       }
-       /* successful MW allocation */
-       e_mw->ipz_mw_handle = hipzout.handle;
-       e_mw->ib_mw.rkey    = hipzout.rkey;
-       return &e_mw->ib_mw;
-
-alloc_mw_exit1:
-       ehca_mw_delete(e_mw);
-alloc_mw_exit0:
-       if (IS_ERR(ib_mw))
-               ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd);
-       return ib_mw;
-} /* end ehca_alloc_mw() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_dealloc_mw(struct ib_mw *mw)
-{
-       u64 h_ret;
-       struct ehca_shca *shca =
-               container_of(mw->device, struct ehca_shca, ib_device);
-       struct ehca_mw *e_mw = container_of(mw, struct ehca_mw, ib_mw);
-
-       h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lli shca=%p "
-                        "mw=%p rkey=%x hca_hndl=%llx mw_hndl=%llx",
-                        h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
-                        e_mw->ipz_mw_handle.handle);
-               return ehca2ib_return_code(h_ret);
-       }
-       /* successful deallocation */
-       ehca_mw_delete(e_mw);
-       return 0;
-} /* end ehca_dealloc_mw() */
-
-/*----------------------------------------------------------------------*/
-
-struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
-                             int mr_access_flags,
-                             struct ib_fmr_attr *fmr_attr)
-{
-       struct ib_fmr *ib_fmr;
-       struct ehca_shca *shca =
-               container_of(pd->device, struct ehca_shca, ib_device);
-       struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_mr *e_fmr;
-       int ret;
-       u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo;
-       u64 hw_pgsize;
-
-       /* check other parameters */
-       if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
-            !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
-           ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
-            !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
-               /*
-                * Remote Write Access requires Local Write Access
-                * Remote Atomic Access requires Local Write Access
-                */
-               ehca_err(pd->device, "bad input values: mr_access_flags=%x",
-                        mr_access_flags);
-               ib_fmr = ERR_PTR(-EINVAL);
-               goto alloc_fmr_exit0;
-       }
-       if (mr_access_flags & IB_ACCESS_MW_BIND) {
-               ehca_err(pd->device, "bad input values: mr_access_flags=%x",
-                        mr_access_flags);
-               ib_fmr = ERR_PTR(-EINVAL);
-               goto alloc_fmr_exit0;
-       }
-       if ((fmr_attr->max_pages == 0) || (fmr_attr->max_maps == 0)) {
-               ehca_err(pd->device, "bad input values: fmr_attr->max_pages=%x "
-                        "fmr_attr->max_maps=%x fmr_attr->page_shift=%x",
-                        fmr_attr->max_pages, fmr_attr->max_maps,
-                        fmr_attr->page_shift);
-               ib_fmr = ERR_PTR(-EINVAL);
-               goto alloc_fmr_exit0;
-       }
-
-       hw_pgsize = 1 << fmr_attr->page_shift;
-       if (!(hw_pgsize & shca->hca_cap_mr_pgsize)) {
-               ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
-                        fmr_attr->page_shift);
-               ib_fmr = ERR_PTR(-EINVAL);
-               goto alloc_fmr_exit0;
-       }
-
-       e_fmr = ehca_mr_new();
-       if (!e_fmr) {
-               ib_fmr = ERR_PTR(-ENOMEM);
-               goto alloc_fmr_exit0;
-       }
-       e_fmr->flags |= EHCA_MR_FLAG_FMR;
-
-       /* register MR on HCA */
-       memset(&pginfo, 0, sizeof(pginfo));
-       pginfo.hwpage_size = hw_pgsize;
-       /*
-        * pginfo.num_hwpages==0, ie register_rpages() will not be called
-        * but deferred to map_phys_fmr()
-        */
-       ret = ehca_reg_mr(shca, e_fmr, NULL,
-                         fmr_attr->max_pages * (1 << fmr_attr->page_shift),
-                         mr_access_flags, e_pd, &pginfo,
-                         &tmp_lkey, &tmp_rkey, EHCA_REG_MR);
-       if (ret) {
-               ib_fmr = ERR_PTR(ret);
-               goto alloc_fmr_exit1;
-       }
-
-       /* successful */
-       e_fmr->hwpage_size = hw_pgsize;
-       e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
-       e_fmr->fmr_max_pages = fmr_attr->max_pages;
-       e_fmr->fmr_max_maps = fmr_attr->max_maps;
-       e_fmr->fmr_map_cnt = 0;
-       return &e_fmr->ib.ib_fmr;
-
-alloc_fmr_exit1:
-       ehca_mr_delete(e_fmr);
-alloc_fmr_exit0:
-       return ib_fmr;
-} /* end ehca_alloc_fmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_map_phys_fmr(struct ib_fmr *fmr,
-                     u64 *page_list,
-                     int list_len,
-                     u64 iova)
-{
-       int ret;
-       struct ehca_shca *shca =
-               container_of(fmr->device, struct ehca_shca, ib_device);
-       struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
-       struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
-       struct ehca_mr_pginfo pginfo;
-       u32 tmp_lkey, tmp_rkey;
-
-       if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
-               ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
-                        e_fmr, e_fmr->flags);
-               ret = -EINVAL;
-               goto map_phys_fmr_exit0;
-       }
-       ret = ehca_fmr_check_page_list(e_fmr, page_list, list_len);
-       if (ret)
-               goto map_phys_fmr_exit0;
-       if (iova % e_fmr->fmr_page_size) {
-               /* only whole-numbered pages */
-               ehca_err(fmr->device, "bad iova, iova=%llx fmr_page_size=%x",
-                        iova, e_fmr->fmr_page_size);
-               ret = -EINVAL;
-               goto map_phys_fmr_exit0;
-       }
-       if (e_fmr->fmr_map_cnt >= e_fmr->fmr_max_maps) {
-               /* HCAD does not limit the maps, however trace this anyway */
-               ehca_info(fmr->device, "map limit exceeded, fmr=%p "
-                         "e_fmr->fmr_map_cnt=%x e_fmr->fmr_max_maps=%x",
-                         fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
-       }
-
-       memset(&pginfo, 0, sizeof(pginfo));
-       pginfo.type = EHCA_MR_PGI_FMR;
-       pginfo.num_kpages = list_len;
-       pginfo.hwpage_size = e_fmr->hwpage_size;
-       pginfo.num_hwpages =
-               list_len * e_fmr->fmr_page_size / pginfo.hwpage_size;
-       pginfo.u.fmr.page_list = page_list;
-       pginfo.next_hwpage =
-               (iova & (e_fmr->fmr_page_size-1)) / pginfo.hwpage_size;
-       pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
-
-       ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
-                           list_len * e_fmr->fmr_page_size,
-                           e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
-       if (ret)
-               goto map_phys_fmr_exit0;
-
-       /* successful reregistration */
-       e_fmr->fmr_map_cnt++;
-       e_fmr->ib.ib_fmr.lkey = tmp_lkey;
-       e_fmr->ib.ib_fmr.rkey = tmp_rkey;
-       return 0;
-
-map_phys_fmr_exit0:
-       if (ret)
-               ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x "
-                        "iova=%llx", ret, fmr, page_list, list_len, iova);
-       return ret;
-} /* end ehca_map_phys_fmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_unmap_fmr(struct list_head *fmr_list)
-{
-       int ret = 0;
-       struct ib_fmr *ib_fmr;
-       struct ehca_shca *shca = NULL;
-       struct ehca_shca *prev_shca;
-       struct ehca_mr *e_fmr;
-       u32 num_fmr = 0;
-       u32 unmap_fmr_cnt = 0;
-
-       /* check all FMR belong to same SHCA, and check internal flag */
-       list_for_each_entry(ib_fmr, fmr_list, list) {
-               prev_shca = shca;
-               shca = container_of(ib_fmr->device, struct ehca_shca,
-                                   ib_device);
-               e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
-               if ((shca != prev_shca) && prev_shca) {
-                       ehca_err(&shca->ib_device, "SHCA mismatch, shca=%p "
-                                "prev_shca=%p e_fmr=%p",
-                                shca, prev_shca, e_fmr);
-                       ret = -EINVAL;
-                       goto unmap_fmr_exit0;
-               }
-               if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
-                       ehca_err(&shca->ib_device, "not a FMR, e_fmr=%p "
-                                "e_fmr->flags=%x", e_fmr, e_fmr->flags);
-                       ret = -EINVAL;
-                       goto unmap_fmr_exit0;
-               }
-               num_fmr++;
-       }
-
-       /* loop over all FMRs to unmap */
-       list_for_each_entry(ib_fmr, fmr_list, list) {
-               unmap_fmr_cnt++;
-               e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
-               shca = container_of(ib_fmr->device, struct ehca_shca,
-                                   ib_device);
-               ret = ehca_unmap_one_fmr(shca, e_fmr);
-               if (ret) {
-                       /* unmap failed, stop unmapping of rest of FMRs */
-                       ehca_err(&shca->ib_device, "unmap of one FMR failed, "
-                                "stop rest, e_fmr=%p num_fmr=%x "
-                                "unmap_fmr_cnt=%x lkey=%x", e_fmr, num_fmr,
-                                unmap_fmr_cnt, e_fmr->ib.ib_fmr.lkey);
-                       goto unmap_fmr_exit0;
-               }
-       }
-
-unmap_fmr_exit0:
-       if (ret)
-               ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
-                            ret, fmr_list, num_fmr, unmap_fmr_cnt);
-       return ret;
-} /* end ehca_unmap_fmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_dealloc_fmr(struct ib_fmr *fmr)
-{
-       int ret;
-       u64 h_ret;
-       struct ehca_shca *shca =
-               container_of(fmr->device, struct ehca_shca, ib_device);
-       struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
-
-       if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
-               ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
-                        e_fmr, e_fmr->flags);
-               ret = -EINVAL;
-               goto free_fmr_exit0;
-       }
-
-       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lli e_fmr=%p "
-                        "hca_hndl=%llx fmr_hndl=%llx fmr->lkey=%x",
-                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                        e_fmr->ipz_mr_handle.handle, fmr->lkey);
-               ret = ehca2ib_return_code(h_ret);
-               goto free_fmr_exit0;
-       }
-       /* successful deregistration */
-       ehca_mr_delete(e_fmr);
-       return 0;
-
-free_fmr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr);
-       return ret;
-} /* end ehca_dealloc_fmr() */
-
-/*----------------------------------------------------------------------*/
-
-static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
-                                  struct ehca_mr *e_mr,
-                                  struct ehca_mr_pginfo *pginfo);
-
-int ehca_reg_mr(struct ehca_shca *shca,
-               struct ehca_mr *e_mr,
-               u64 *iova_start,
-               u64 size,
-               int acl,
-               struct ehca_pd *e_pd,
-               struct ehca_mr_pginfo *pginfo,
-               u32 *lkey, /*OUT*/
-               u32 *rkey, /*OUT*/
-               enum ehca_reg_type reg_type)
-{
-       int ret;
-       u64 h_ret;
-       u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout;
-
-       ehca_mrmw_map_acl(acl, &hipz_acl);
-       ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
-       if (ehca_use_hp_mr == 1)
-               hipz_acl |= 0x00000001;
-
-       h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
-                                        (u64)iova_start, size, hipz_acl,
-                                        e_pd->fw_pd, &hipzout);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lli "
-                        "hca_hndl=%llx", h_ret, shca->ipz_hca_handle.handle);
-               ret = ehca2ib_return_code(h_ret);
-               goto ehca_reg_mr_exit0;
-       }
-
-       e_mr->ipz_mr_handle = hipzout.handle;
-
-       if (reg_type == EHCA_REG_BUSMAP_MR)
-               ret = ehca_reg_bmap_mr_rpages(shca, e_mr, pginfo);
-       else if (reg_type == EHCA_REG_MR)
-               ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
-       else
-               ret = -EINVAL;
-
-       if (ret)
-               goto ehca_reg_mr_exit1;
-
-       /* successful registration */
-       e_mr->num_kpages = pginfo->num_kpages;
-       e_mr->num_hwpages = pginfo->num_hwpages;
-       e_mr->hwpage_size = pginfo->hwpage_size;
-       e_mr->start = iova_start;
-       e_mr->size = size;
-       e_mr->acl = acl;
-       *lkey = hipzout.lkey;
-       *rkey = hipzout.rkey;
-       return 0;
-
-ehca_reg_mr_exit1:
-       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "h_ret=%lli shca=%p e_mr=%p "
-                        "iova_start=%p size=%llx acl=%x e_pd=%p lkey=%x "
-                        "pginfo=%p num_kpages=%llx num_hwpages=%llx ret=%i",
-                        h_ret, shca, e_mr, iova_start, size, acl, e_pd,
-                        hipzout.lkey, pginfo, pginfo->num_kpages,
-                        pginfo->num_hwpages, ret);
-               ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
-                        "not recoverable");
-       }
-ehca_reg_mr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
-                        "iova_start=%p size=%llx acl=%x e_pd=%p pginfo=%p "
-                        "num_kpages=%llx num_hwpages=%llx",
-                        ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
-                        pginfo->num_kpages, pginfo->num_hwpages);
-       return ret;
-} /* end ehca_reg_mr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_reg_mr_rpages(struct ehca_shca *shca,
-                      struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo)
-{
-       int ret = 0;
-       u64 h_ret;
-       u32 rnum;
-       u64 rpage;
-       u32 i;
-       u64 *kpage;
-
-       if (!pginfo->num_hwpages) /* in case of fmr */
-               return 0;
-
-       kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!kpage) {
-               ehca_err(&shca->ib_device, "kpage alloc failed");
-               ret = -ENOMEM;
-               goto ehca_reg_mr_rpages_exit0;
-       }
-
-       /* max MAX_RPAGES ehca mr pages per register call */
-       for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
-
-               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
-                       rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
-                       if (rnum == 0)
-                               rnum = MAX_RPAGES;      /* last shot is full */
-               } else
-                       rnum = MAX_RPAGES;
-
-               ret = ehca_set_pagebuf(pginfo, rnum, kpage);
-               if (ret) {
-                       ehca_err(&shca->ib_device, "ehca_set_pagebuf "
-                                "bad rc, ret=%i rnum=%x kpage=%p",
-                                ret, rnum, kpage);
-                       goto ehca_reg_mr_rpages_exit1;
-               }
-
-               if (rnum > 1) {
-                       rpage = __pa(kpage);
-                       if (!rpage) {
-                               ehca_err(&shca->ib_device, "kpage=%p i=%x",
-                                        kpage, i);
-                               ret = -EFAULT;
-                               goto ehca_reg_mr_rpages_exit1;
-                       }
-               } else
-                       rpage = *kpage;
-
-               h_ret = hipz_h_register_rpage_mr(
-                       shca->ipz_hca_handle, e_mr,
-                       ehca_encode_hwpage_size(pginfo->hwpage_size),
-                       0, rpage, rnum);
-
-               if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
-                       /*
-                        * check for 'registration complete'==H_SUCCESS
-                        * and for 'page registered'==H_PAGE_REGISTERED
-                        */
-                       if (h_ret != H_SUCCESS) {
-                               ehca_err(&shca->ib_device, "last "
-                                        "hipz_reg_rpage_mr failed, h_ret=%lli "
-                                        "e_mr=%p i=%x hca_hndl=%llx mr_hndl=%llx"
-                                        " lkey=%x", h_ret, e_mr, i,
-                                        shca->ipz_hca_handle.handle,
-                                        e_mr->ipz_mr_handle.handle,
-                                        e_mr->ib.ib_mr.lkey);
-                               ret = ehca2ib_return_code(h_ret);
-                               break;
-                       } else
-                               ret = 0;
-               } else if (h_ret != H_PAGE_REGISTERED) {
-                       ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
-                                "h_ret=%lli e_mr=%p i=%x lkey=%x hca_hndl=%llx "
-                                "mr_hndl=%llx", h_ret, e_mr, i,
-                                e_mr->ib.ib_mr.lkey,
-                                shca->ipz_hca_handle.handle,
-                                e_mr->ipz_mr_handle.handle);
-                       ret = ehca2ib_return_code(h_ret);
-                       break;
-               } else
-                       ret = 0;
-       } /* end for(i) */
-
-
-ehca_reg_mr_rpages_exit1:
-       ehca_free_fw_ctrlblock(kpage);
-ehca_reg_mr_rpages_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p "
-                        "num_kpages=%llx num_hwpages=%llx", ret, shca, e_mr,
-                        pginfo, pginfo->num_kpages, pginfo->num_hwpages);
-       return ret;
-} /* end ehca_reg_mr_rpages() */
-
-/*----------------------------------------------------------------------*/
-
-inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
-                               struct ehca_mr *e_mr,
-                               u64 *iova_start,
-                               u64 size,
-                               u32 acl,
-                               struct ehca_pd *e_pd,
-                               struct ehca_mr_pginfo *pginfo,
-                               u32 *lkey, /*OUT*/
-                               u32 *rkey) /*OUT*/
-{
-       int ret;
-       u64 h_ret;
-       u32 hipz_acl;
-       u64 *kpage;
-       u64 rpage;
-       struct ehca_mr_pginfo pginfo_save;
-       struct ehca_mr_hipzout_parms hipzout;
-
-       ehca_mrmw_map_acl(acl, &hipz_acl);
-       ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
-
-       kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!kpage) {
-               ehca_err(&shca->ib_device, "kpage alloc failed");
-               ret = -ENOMEM;
-               goto ehca_rereg_mr_rereg1_exit0;
-       }
-
-       pginfo_save = *pginfo;
-       ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
-       if (ret) {
-               ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
-                        "pginfo=%p type=%x num_kpages=%llx num_hwpages=%llx "
-                        "kpage=%p", e_mr, pginfo, pginfo->type,
-                        pginfo->num_kpages, pginfo->num_hwpages, kpage);
-               goto ehca_rereg_mr_rereg1_exit1;
-       }
-       rpage = __pa(kpage);
-       if (!rpage) {
-               ehca_err(&shca->ib_device, "kpage=%p", kpage);
-               ret = -EFAULT;
-               goto ehca_rereg_mr_rereg1_exit1;
-       }
-       h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_mr,
-                                     (u64)iova_start, size, hipz_acl,
-                                     e_pd->fw_pd, rpage, &hipzout);
-       if (h_ret != H_SUCCESS) {
-               /*
-                * reregistration unsuccessful, try it again with the 3 hCalls,
-                * e.g. this is required in case H_MR_CONDITION
-                * (MW bound or MR is shared)
-                */
-               ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
-                         "(Rereg1), h_ret=%lli e_mr=%p", h_ret, e_mr);
-               *pginfo = pginfo_save;
-               ret = -EAGAIN;
-       } else if ((u64 *)hipzout.vaddr != iova_start) {
-               ehca_err(&shca->ib_device, "PHYP changed iova_start in "
-                        "rereg_pmr, iova_start=%p iova_start_out=%llx e_mr=%p "
-                        "mr_handle=%llx lkey=%x lkey_out=%x", iova_start,
-                        hipzout.vaddr, e_mr, e_mr->ipz_mr_handle.handle,
-                        e_mr->ib.ib_mr.lkey, hipzout.lkey);
-               ret = -EFAULT;
-       } else {
-               /*
-                * successful reregistration
-                * note: start and start_out are identical for eServer HCAs
-                */
-               e_mr->num_kpages = pginfo->num_kpages;
-               e_mr->num_hwpages = pginfo->num_hwpages;
-               e_mr->hwpage_size = pginfo->hwpage_size;
-               e_mr->start = iova_start;
-               e_mr->size = size;
-               e_mr->acl = acl;
-               *lkey = hipzout.lkey;
-               *rkey = hipzout.rkey;
-       }
-
-ehca_rereg_mr_rereg1_exit1:
-       ehca_free_fw_ctrlblock(kpage);
-ehca_rereg_mr_rereg1_exit0:
-       if ( ret && (ret != -EAGAIN) )
-               ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x "
-                        "pginfo=%p num_kpages=%llx num_hwpages=%llx",
-                        ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
-                        pginfo->num_hwpages);
-       return ret;
-} /* end ehca_rereg_mr_rereg1() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_rereg_mr(struct ehca_shca *shca,
-                 struct ehca_mr *e_mr,
-                 u64 *iova_start,
-                 u64 size,
-                 int acl,
-                 struct ehca_pd *e_pd,
-                 struct ehca_mr_pginfo *pginfo,
-                 u32 *lkey,
-                 u32 *rkey)
-{
-       int ret = 0;
-       u64 h_ret;
-       int rereg_1_hcall = 1; /* 1: use hipz_h_reregister_pmr directly */
-       int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
-
-       /* first determine reregistration hCall(s) */
-       if ((pginfo->num_hwpages > MAX_RPAGES) ||
-           (e_mr->num_hwpages > MAX_RPAGES) ||
-           (pginfo->num_hwpages > e_mr->num_hwpages)) {
-               ehca_dbg(&shca->ib_device, "Rereg3 case, "
-                        "pginfo->num_hwpages=%llx e_mr->num_hwpages=%x",
-                        pginfo->num_hwpages, e_mr->num_hwpages);
-               rereg_1_hcall = 0;
-               rereg_3_hcall = 1;
-       }
-
-       if (e_mr->flags & EHCA_MR_FLAG_MAXMR) { /* check for max-MR */
-               rereg_1_hcall = 0;
-               rereg_3_hcall = 1;
-               e_mr->flags &= ~EHCA_MR_FLAG_MAXMR;
-               ehca_err(&shca->ib_device, "Rereg MR for max-MR! e_mr=%p",
-                        e_mr);
-       }
-
-       if (rereg_1_hcall) {
-               ret = ehca_rereg_mr_rereg1(shca, e_mr, iova_start, size,
-                                          acl, e_pd, pginfo, lkey, rkey);
-               if (ret) {
-                       if (ret == -EAGAIN)
-                               rereg_3_hcall = 1;
-                       else
-                               goto ehca_rereg_mr_exit0;
-               }
-       }
-
-       if (rereg_3_hcall) {
-               struct ehca_mr save_mr;
-
-               /* first deregister old MR */
-               h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
-               if (h_ret != H_SUCCESS) {
-                       ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-                                "h_ret=%lli e_mr=%p hca_hndl=%llx mr_hndl=%llx "
-                                "mr->lkey=%x",
-                                h_ret, e_mr, shca->ipz_hca_handle.handle,
-                                e_mr->ipz_mr_handle.handle,
-                                e_mr->ib.ib_mr.lkey);
-                       ret = ehca2ib_return_code(h_ret);
-                       goto ehca_rereg_mr_exit0;
-               }
-               /* clean ehca_mr_t, without changing struct ib_mr and lock */
-               save_mr = *e_mr;
-               ehca_mr_deletenew(e_mr);
-
-               /* set some MR values */
-               e_mr->flags = save_mr.flags;
-               e_mr->hwpage_size = save_mr.hwpage_size;
-               e_mr->fmr_page_size = save_mr.fmr_page_size;
-               e_mr->fmr_max_pages = save_mr.fmr_max_pages;
-               e_mr->fmr_max_maps = save_mr.fmr_max_maps;
-               e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
-
-               ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
-                                 e_pd, pginfo, lkey, rkey, EHCA_REG_MR);
-               if (ret) {
-                       u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
-                       memcpy(&e_mr->flags, &(save_mr.flags),
-                              sizeof(struct ehca_mr) - offset);
-                       goto ehca_rereg_mr_exit0;
-               }
-       }
-
-ehca_rereg_mr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
-                        "iova_start=%p size=%llx acl=%x e_pd=%p pginfo=%p "
-                        "num_kpages=%llx lkey=%x rkey=%x rereg_1_hcall=%x "
-                        "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
-                        acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
-                        rereg_1_hcall, rereg_3_hcall);
-       return ret;
-} /* end ehca_rereg_mr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_unmap_one_fmr(struct ehca_shca *shca,
-                      struct ehca_mr *e_fmr)
-{
-       int ret = 0;
-       u64 h_ret;
-       struct ehca_pd *e_pd =
-               container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
-       struct ehca_mr save_fmr;
-       u32 tmp_lkey, tmp_rkey;
-       struct ehca_mr_pginfo pginfo;
-       struct ehca_mr_hipzout_parms hipzout;
-       struct ehca_mr save_mr;
-
-       if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
-               /*
-                * note: after using rereg hcall with len=0,
-                * rereg hcall must be used again for registering pages
-                */
-               h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
-                                             0, 0, e_pd->fw_pd, 0, &hipzout);
-               if (h_ret == H_SUCCESS) {
-                       /* successful reregistration */
-                       e_fmr->start = NULL;
-                       e_fmr->size = 0;
-                       tmp_lkey = hipzout.lkey;
-                       tmp_rkey = hipzout.rkey;
-                       return 0;
-               }
-               /*
-                * should not happen, because length checked above,
-                * FMRs are not shared and no MW bound to FMRs
-                */
-               ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
-                        "(Rereg1), h_ret=%lli e_fmr=%p hca_hndl=%llx "
-                        "mr_hndl=%llx lkey=%x lkey_out=%x",
-                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                        e_fmr->ipz_mr_handle.handle,
-                        e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
-               /* try free and rereg */
-       }
-
-       /* first free old FMR */
-       h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-                        "h_ret=%lli e_fmr=%p hca_hndl=%llx mr_hndl=%llx "
-                        "lkey=%x",
-                        h_ret, e_fmr, shca->ipz_hca_handle.handle,
-                        e_fmr->ipz_mr_handle.handle,
-                        e_fmr->ib.ib_fmr.lkey);
-               ret = ehca2ib_return_code(h_ret);
-               goto ehca_unmap_one_fmr_exit0;
-       }
-       /* clean ehca_mr_t, without changing lock */
-       save_fmr = *e_fmr;
-       ehca_mr_deletenew(e_fmr);
-
-       /* set some MR values */
-       e_fmr->flags = save_fmr.flags;
-       e_fmr->hwpage_size = save_fmr.hwpage_size;
-       e_fmr->fmr_page_size = save_fmr.fmr_page_size;
-       e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
-       e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
-       e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
-       e_fmr->acl = save_fmr.acl;
-
-       memset(&pginfo, 0, sizeof(pginfo));
-       pginfo.type = EHCA_MR_PGI_FMR;
-       ret = ehca_reg_mr(shca, e_fmr, NULL,
-                         (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
-                         e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-                         &tmp_rkey, EHCA_REG_MR);
-       if (ret) {
-               u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
-               memcpy(&e_fmr->flags, &(save_mr.flags),
-                      sizeof(struct ehca_mr) - offset);
-       }
-
-ehca_unmap_one_fmr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x "
-                        "fmr_max_pages=%x",
-                        ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
-       return ret;
-} /* end ehca_unmap_one_fmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_reg_smr(struct ehca_shca *shca,
-                struct ehca_mr *e_origmr,
-                struct ehca_mr *e_newmr,
-                u64 *iova_start,
-                int acl,
-                struct ehca_pd *e_pd,
-                u32 *lkey, /*OUT*/
-                u32 *rkey) /*OUT*/
-{
-       int ret = 0;
-       u64 h_ret;
-       u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout;
-
-       ehca_mrmw_map_acl(acl, &hipz_acl);
-       ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
-
-       h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
-                                   (u64)iova_start, hipz_acl, e_pd->fw_pd,
-                                   &hipzout);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lli "
-                        "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
-                        "e_pd=%p hca_hndl=%llx mr_hndl=%llx lkey=%x",
-                        h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
-                        shca->ipz_hca_handle.handle,
-                        e_origmr->ipz_mr_handle.handle,
-                        e_origmr->ib.ib_mr.lkey);
-               ret = ehca2ib_return_code(h_ret);
-               goto ehca_reg_smr_exit0;
-       }
-       /* successful registration */
-       e_newmr->num_kpages = e_origmr->num_kpages;
-       e_newmr->num_hwpages = e_origmr->num_hwpages;
-       e_newmr->hwpage_size   = e_origmr->hwpage_size;
-       e_newmr->start = iova_start;
-       e_newmr->size = e_origmr->size;
-       e_newmr->acl = acl;
-       e_newmr->ipz_mr_handle = hipzout.handle;
-       *lkey = hipzout.lkey;
-       *rkey = hipzout.rkey;
-       return 0;
-
-ehca_reg_smr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p "
-                        "e_newmr=%p iova_start=%p acl=%x e_pd=%p",
-                        ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
-       return ret;
-} /* end ehca_reg_smr() */
-
-/*----------------------------------------------------------------------*/
-static inline void *ehca_calc_sectbase(int top, int dir, int idx)
-{
-       unsigned long ret = idx;
-       ret |= dir << EHCA_DIR_INDEX_SHIFT;
-       ret |= top << EHCA_TOP_INDEX_SHIFT;
-       return __va(ret << SECTION_SIZE_BITS);
-}
-
-#define ehca_bmap_valid(entry) \
-       ((u64)entry != (u64)EHCA_INVAL_ADDR)
-
-static u64 ehca_reg_mr_section(int top, int dir, int idx, u64 *kpage,
-                              struct ehca_shca *shca, struct ehca_mr *mr,
-                              struct ehca_mr_pginfo *pginfo)
-{
-       u64 h_ret = 0;
-       unsigned long page = 0;
-       u64 rpage = __pa(kpage);
-       int page_count;
-
-       void *sectbase = ehca_calc_sectbase(top, dir, idx);
-       if ((unsigned long)sectbase & (pginfo->hwpage_size - 1)) {
-               ehca_err(&shca->ib_device, "reg_mr_section will probably fail:"
-                                          "hwpage_size does not fit to "
-                                          "section start address");
-       }
-       page_count = EHCA_SECTSIZE / pginfo->hwpage_size;
-
-       while (page < page_count) {
-               u64 rnum;
-               for (rnum = 0; (rnum < MAX_RPAGES) && (page < page_count);
-                    rnum++) {
-                       void *pg = sectbase + ((page++) * pginfo->hwpage_size);
-                       kpage[rnum] = __pa(pg);
-               }
-
-               h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, mr,
-                       ehca_encode_hwpage_size(pginfo->hwpage_size),
-                       0, rpage, rnum);
-
-               if ((h_ret != H_SUCCESS) && (h_ret != H_PAGE_REGISTERED)) {
-                       ehca_err(&shca->ib_device, "register_rpage_mr failed");
-                       return h_ret;
-               }
-       }
-       return h_ret;
-}
-
-static u64 ehca_reg_mr_sections(int top, int dir, u64 *kpage,
-                               struct ehca_shca *shca, struct ehca_mr *mr,
-                               struct ehca_mr_pginfo *pginfo)
-{
-       u64 hret = H_SUCCESS;
-       int idx;
-
-       for (idx = 0; idx < EHCA_MAP_ENTRIES; idx++) {
-               if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]->ent[idx]))
-                       continue;
-
-               hret = ehca_reg_mr_section(top, dir, idx, kpage, shca, mr,
-                                          pginfo);
-               if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
-                               return hret;
-       }
-       return hret;
-}
-
-static u64 ehca_reg_mr_dir_sections(int top, u64 *kpage, struct ehca_shca *shca,
-                                   struct ehca_mr *mr,
-                                   struct ehca_mr_pginfo *pginfo)
-{
-       u64 hret = H_SUCCESS;
-       int dir;
-
-       for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
-               if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
-                       continue;
-
-               hret = ehca_reg_mr_sections(top, dir, kpage, shca, mr, pginfo);
-               if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
-                               return hret;
-       }
-       return hret;
-}
-
-/* register internal max-MR to internal SHCA */
-int ehca_reg_internal_maxmr(
-       struct ehca_shca *shca,
-       struct ehca_pd *e_pd,
-       struct ehca_mr **e_maxmr)  /*OUT*/
-{
-       int ret;
-       struct ehca_mr *e_mr;
-       u64 *iova_start;
-       u64 size_maxmr;
-       struct ehca_mr_pginfo pginfo;
-       u32 num_kpages;
-       u32 num_hwpages;
-       u64 hw_pgsize;
-
-       if (!ehca_bmap) {
-               ret = -EFAULT;
-               goto ehca_reg_internal_maxmr_exit0;
-       }
-
-       e_mr = ehca_mr_new();
-       if (!e_mr) {
-               ehca_err(&shca->ib_device, "out of memory");
-               ret = -ENOMEM;
-               goto ehca_reg_internal_maxmr_exit0;
-       }
-       e_mr->flags |= EHCA_MR_FLAG_MAXMR;
-
-       /* register internal max-MR on HCA */
-       size_maxmr = ehca_mr_len;
-       iova_start = (u64 *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START));
-       num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
-                               PAGE_SIZE);
-       hw_pgsize = ehca_get_max_hwpage_size(shca);
-       num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size_maxmr,
-                                hw_pgsize);
-
-       memset(&pginfo, 0, sizeof(pginfo));
-       pginfo.type = EHCA_MR_PGI_PHYS;
-       pginfo.num_kpages = num_kpages;
-       pginfo.num_hwpages = num_hwpages;
-       pginfo.hwpage_size = hw_pgsize;
-       pginfo.u.phy.addr = 0;
-       pginfo.u.phy.size = size_maxmr;
-
-       ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
-                         &pginfo, &e_mr->ib.ib_mr.lkey,
-                         &e_mr->ib.ib_mr.rkey, EHCA_REG_BUSMAP_MR);
-       if (ret) {
-               ehca_err(&shca->ib_device, "reg of internal max MR failed, "
-                        "e_mr=%p iova_start=%p size_maxmr=%llx num_kpages=%x "
-                        "num_hwpages=%x", e_mr, iova_start, size_maxmr,
-                        num_kpages, num_hwpages);
-               goto ehca_reg_internal_maxmr_exit1;
-       }
-
-       /* successful registration of all pages */
-       e_mr->ib.ib_mr.device = e_pd->ib_pd.device;
-       e_mr->ib.ib_mr.pd = &e_pd->ib_pd;
-       e_mr->ib.ib_mr.uobject = NULL;
-       atomic_inc(&(e_pd->ib_pd.usecnt));
-       *e_maxmr = e_mr;
-       return 0;
-
-ehca_reg_internal_maxmr_exit1:
-       ehca_mr_delete(e_mr);
-ehca_reg_internal_maxmr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p",
-                        ret, shca, e_pd, e_maxmr);
-       return ret;
-} /* end ehca_reg_internal_maxmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_reg_maxmr(struct ehca_shca *shca,
-                  struct ehca_mr *e_newmr,
-                  u64 *iova_start,
-                  int acl,
-                  struct ehca_pd *e_pd,
-                  u32 *lkey,
-                  u32 *rkey)
-{
-       u64 h_ret;
-       struct ehca_mr *e_origmr = shca->maxmr;
-       u32 hipz_acl;
-       struct ehca_mr_hipzout_parms hipzout;
-
-       ehca_mrmw_map_acl(acl, &hipz_acl);
-       ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
-
-       h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
-                                   (u64)iova_start, hipz_acl, e_pd->fw_pd,
-                                   &hipzout);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lli "
-                        "e_origmr=%p hca_hndl=%llx mr_hndl=%llx lkey=%x",
-                        h_ret, e_origmr, shca->ipz_hca_handle.handle,
-                        e_origmr->ipz_mr_handle.handle,
-                        e_origmr->ib.ib_mr.lkey);
-               return ehca2ib_return_code(h_ret);
-       }
-       /* successful registration */
-       e_newmr->num_kpages = e_origmr->num_kpages;
-       e_newmr->num_hwpages = e_origmr->num_hwpages;
-       e_newmr->hwpage_size = e_origmr->hwpage_size;
-       e_newmr->start = iova_start;
-       e_newmr->size = e_origmr->size;
-       e_newmr->acl = acl;
-       e_newmr->ipz_mr_handle = hipzout.handle;
-       *lkey = hipzout.lkey;
-       *rkey = hipzout.rkey;
-       return 0;
-} /* end ehca_reg_maxmr() */
-
-/*----------------------------------------------------------------------*/
-
-int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
-{
-       int ret;
-       struct ehca_mr *e_maxmr;
-       struct ib_pd *ib_pd;
-
-       if (!shca->maxmr) {
-               ehca_err(&shca->ib_device, "bad call, shca=%p", shca);
-               ret = -EINVAL;
-               goto ehca_dereg_internal_maxmr_exit0;
-       }
-
-       e_maxmr = shca->maxmr;
-       ib_pd = e_maxmr->ib.ib_mr.pd;
-       shca->maxmr = NULL; /* remove internal max-MR indication from SHCA */
-
-       ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
-       if (ret) {
-               ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
-                        "ret=%i e_maxmr=%p shca=%p lkey=%x",
-                        ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
-               shca->maxmr = e_maxmr;
-               goto ehca_dereg_internal_maxmr_exit0;
-       }
-
-       atomic_dec(&ib_pd->usecnt);
-
-ehca_dereg_internal_maxmr_exit0:
-       if (ret)
-               ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p",
-                        ret, shca, shca->maxmr);
-       return ret;
-} /* end ehca_dereg_internal_maxmr() */
-
-/*----------------------------------------------------------------------*/
-
-/* check page list of map FMR verb for validness */
-int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
-                            u64 *page_list,
-                            int list_len)
-{
-       u32 i;
-       u64 *page;
-
-       if ((list_len == 0) || (list_len > e_fmr->fmr_max_pages)) {
-               ehca_gen_err("bad list_len, list_len=%x "
-                            "e_fmr->fmr_max_pages=%x fmr=%p",
-                            list_len, e_fmr->fmr_max_pages, e_fmr);
-               return -EINVAL;
-       }
-
-       /* each page must be aligned */
-       page = page_list;
-       for (i = 0; i < list_len; i++) {
-               if (*page % e_fmr->fmr_page_size) {
-                       ehca_gen_err("bad page, i=%x *page=%llx page=%p fmr=%p "
-                                    "fmr_page_size=%x", i, *page, page, e_fmr,
-                                    e_fmr->fmr_page_size);
-                       return -EINVAL;
-               }
-               page++;
-       }
-
-       return 0;
-} /* end ehca_fmr_check_page_list() */
-
-/*----------------------------------------------------------------------*/
-
-/* PAGE_SIZE >= pginfo->hwpage_size */
-static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
-                                 u32 number,
-                                 u64 *kpage)
-{
-       int ret = 0;
-       u64 pgaddr;
-       u32 j = 0;
-       int hwpages_per_kpage = PAGE_SIZE / pginfo->hwpage_size;
-       struct scatterlist **sg = &pginfo->u.usr.next_sg;
-
-       while (*sg != NULL) {
-               pgaddr = page_to_pfn(sg_page(*sg))
-                       << PAGE_SHIFT;
-               *kpage = pgaddr + (pginfo->next_hwpage *
-                                  pginfo->hwpage_size);
-               if (!(*kpage)) {
-                       ehca_gen_err("pgaddr=%llx "
-                                    "sg_dma_address=%llx "
-                                    "entry=%llx next_hwpage=%llx",
-                                    pgaddr, (u64)sg_dma_address(*sg),
-                                    pginfo->u.usr.next_nmap,
-                                    pginfo->next_hwpage);
-                       return -EFAULT;
-               }
-               (pginfo->hwpage_cnt)++;
-               (pginfo->next_hwpage)++;
-               kpage++;
-               if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
-                       (pginfo->kpage_cnt)++;
-                       (pginfo->u.usr.next_nmap)++;
-                       pginfo->next_hwpage = 0;
-                       *sg = sg_next(*sg);
-               }
-               j++;
-               if (j >= number)
-                       break;
-       }
-
-       return ret;
-}
-
-/*
- * check given pages for contiguous layout
- * last page addr is returned in prev_pgaddr for further check
- */
-static int ehca_check_kpages_per_ate(struct scatterlist **sg,
-                                    int num_pages,
-                                    u64 *prev_pgaddr)
-{
-       for (; *sg && num_pages > 0; *sg = sg_next(*sg), num_pages--) {
-               u64 pgaddr = page_to_pfn(sg_page(*sg)) << PAGE_SHIFT;
-               if (ehca_debug_level >= 3)
-                       ehca_gen_dbg("chunk_page=%llx value=%016llx", pgaddr,
-                                    *(u64 *)__va(pgaddr));
-               if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
-                       ehca_gen_err("uncontiguous page found pgaddr=%llx "
-                                    "prev_pgaddr=%llx entries_left_in_hwpage=%x",
-                                    pgaddr, *prev_pgaddr, num_pages);
-                       return -EINVAL;
-               }
-               *prev_pgaddr = pgaddr;
-       }
-       return 0;
-}
-
-/* PAGE_SIZE < pginfo->hwpage_size */
-static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
-                                 u32 number,
-                                 u64 *kpage)
-{
-       int ret = 0;
-       u64 pgaddr, prev_pgaddr;
-       u32 j = 0;
-       int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
-       int nr_kpages = kpages_per_hwpage;
-       struct scatterlist **sg = &pginfo->u.usr.next_sg;
-
-       while (*sg != NULL) {
-
-               if (nr_kpages == kpages_per_hwpage) {
-                       pgaddr = (page_to_pfn(sg_page(*sg))
-                                  << PAGE_SHIFT);
-                       *kpage = pgaddr;
-                       if (!(*kpage)) {
-                               ehca_gen_err("pgaddr=%llx entry=%llx",
-                                            pgaddr, pginfo->u.usr.next_nmap);
-                               ret = -EFAULT;
-                               return ret;
-                       }
-                       /*
-                        * The first page in a hwpage must be aligned;
-                        * the first MR page is exempt from this rule.
-                        */
-                       if (pgaddr & (pginfo->hwpage_size - 1)) {
-                               if (pginfo->hwpage_cnt) {
-                                       ehca_gen_err(
-                                               "invalid alignment "
-                                               "pgaddr=%llx entry=%llx "
-                                               "mr_pgsize=%llx",
-                                               pgaddr, pginfo->u.usr.next_nmap,
-                                               pginfo->hwpage_size);
-                                       ret = -EFAULT;
-                                       return ret;
-                               }
-                               /* first MR page */
-                               pginfo->kpage_cnt =
-                                       (pgaddr &
-                                        (pginfo->hwpage_size - 1)) >>
-                                       PAGE_SHIFT;
-                               nr_kpages -= pginfo->kpage_cnt;
-                               *kpage = pgaddr &
-                                        ~(pginfo->hwpage_size - 1);
-                       }
-                       if (ehca_debug_level >= 3) {
-                               u64 val = *(u64 *)__va(pgaddr);
-                               ehca_gen_dbg("kpage=%llx page=%llx "
-                                            "value=%016llx",
-                                            *kpage, pgaddr, val);
-                       }
-                       prev_pgaddr = pgaddr;
-                       *sg = sg_next(*sg);
-                       pginfo->kpage_cnt++;
-                       pginfo->u.usr.next_nmap++;
-                       nr_kpages--;
-                       if (!nr_kpages)
-                               goto next_kpage;
-                       continue;
-               }
-
-               ret = ehca_check_kpages_per_ate(sg, nr_kpages,
-                                               &prev_pgaddr);
-               if (ret)
-                       return ret;
-               pginfo->kpage_cnt += nr_kpages;
-               pginfo->u.usr.next_nmap += nr_kpages;
-
-next_kpage:
-               nr_kpages = kpages_per_hwpage;
-               (pginfo->hwpage_cnt)++;
-               kpage++;
-               j++;
-               if (j >= number)
-                       break;
-       }
-
-       return ret;
-}
-
-static int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
-                                u32 number, u64 *kpage)
-{
-       int ret = 0;
-       u64 addr = pginfo->u.phy.addr;
-       u64 size = pginfo->u.phy.size;
-       u64 num_hw, offs_hw;
-       u32 i = 0;
-
-       num_hw  = NUM_CHUNKS((addr % pginfo->hwpage_size) + size,
-                               pginfo->hwpage_size);
-       offs_hw = (addr & ~(pginfo->hwpage_size - 1)) / pginfo->hwpage_size;
-
-       while (pginfo->next_hwpage < offs_hw + num_hw) {
-               /* sanity check */
-               if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
-                   (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
-                       ehca_gen_err("kpage_cnt >= num_kpages, "
-                                    "kpage_cnt=%llx num_kpages=%llx "
-                                    "hwpage_cnt=%llx "
-                                    "num_hwpages=%llx i=%x",
-                                    pginfo->kpage_cnt,
-                                    pginfo->num_kpages,
-                                    pginfo->hwpage_cnt,
-                                    pginfo->num_hwpages, i);
-                       return -EFAULT;
-               }
-               *kpage = (addr & ~(pginfo->hwpage_size - 1)) +
-                        (pginfo->next_hwpage * pginfo->hwpage_size);
-               if ( !(*kpage) && addr ) {
-                       ehca_gen_err("addr=%llx size=%llx "
-                                    "next_hwpage=%llx", addr,
-                                    size, pginfo->next_hwpage);
-                       return -EFAULT;
-               }
-               (pginfo->hwpage_cnt)++;
-               (pginfo->next_hwpage)++;
-               if (PAGE_SIZE >= pginfo->hwpage_size) {
-                       if (pginfo->next_hwpage %
-                           (PAGE_SIZE / pginfo->hwpage_size) == 0)
-                               (pginfo->kpage_cnt)++;
-               } else
-                       pginfo->kpage_cnt += pginfo->hwpage_size /
-                               PAGE_SIZE;
-               kpage++;
-               i++;
-               if (i >= number) break;
-       }
-       if (pginfo->next_hwpage >= offs_hw + num_hw) {
-               pginfo->next_hwpage = 0;
-       }
-
-       return ret;
-}
-
-static int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
-                               u32 number, u64 *kpage)
-{
-       int ret = 0;
-       u64 *fmrlist;
-       u32 i;
-
-       /* loop over desired page_list entries */
-       fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
-       for (i = 0; i < number; i++) {
-               *kpage = (*fmrlist & ~(pginfo->hwpage_size - 1)) +
-                          pginfo->next_hwpage * pginfo->hwpage_size;
-               if ( !(*kpage) ) {
-                       ehca_gen_err("*fmrlist=%llx fmrlist=%p "
-                                    "next_listelem=%llx next_hwpage=%llx",
-                                    *fmrlist, fmrlist,
-                                    pginfo->u.fmr.next_listelem,
-                                    pginfo->next_hwpage);
-                       return -EFAULT;
-               }
-               (pginfo->hwpage_cnt)++;
-               if (pginfo->u.fmr.fmr_pgsize >= pginfo->hwpage_size) {
-                       if (pginfo->next_hwpage %
-                           (pginfo->u.fmr.fmr_pgsize /
-                            pginfo->hwpage_size) == 0) {
-                               (pginfo->kpage_cnt)++;
-                               (pginfo->u.fmr.next_listelem)++;
-                               fmrlist++;
-                               pginfo->next_hwpage = 0;
-                       } else
-                               (pginfo->next_hwpage)++;
-               } else {
-                       unsigned int cnt_per_hwpage = pginfo->hwpage_size /
-                               pginfo->u.fmr.fmr_pgsize;
-                       unsigned int j;
-                       u64 prev = *kpage;
-                       /* check if adrs are contiguous */
-                       for (j = 1; j < cnt_per_hwpage; j++) {
-                               u64 p = fmrlist[j] & ~(pginfo->hwpage_size - 1);
-                               if (prev + pginfo->u.fmr.fmr_pgsize != p) {
-                                       ehca_gen_err("uncontiguous fmr pages "
-                                                    "found prev=%llx p=%llx "
-                                                    "idx=%x", prev, p, i + j);
-                                       return -EINVAL;
-                               }
-                               prev = p;
-                       }
-                       pginfo->kpage_cnt += cnt_per_hwpage;
-                       pginfo->u.fmr.next_listelem += cnt_per_hwpage;
-                       fmrlist += cnt_per_hwpage;
-               }
-               kpage++;
-       }
-       return ret;
-}
-
-/* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
-                    u32 number,
-                    u64 *kpage)
-{
-       int ret;
-
-       switch (pginfo->type) {
-       case EHCA_MR_PGI_PHYS:
-               ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
-               break;
-       case EHCA_MR_PGI_USER:
-               ret = PAGE_SIZE >= pginfo->hwpage_size ?
-                       ehca_set_pagebuf_user1(pginfo, number, kpage) :
-                       ehca_set_pagebuf_user2(pginfo, number, kpage);
-               break;
-       case EHCA_MR_PGI_FMR:
-               ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
-               break;
-       default:
-               ehca_gen_err("bad pginfo->type=%x", pginfo->type);
-               ret = -EFAULT;
-               break;
-       }
-       return ret;
-} /* end ehca_set_pagebuf() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * check MR if it is a max-MR, i.e. uses whole memory
- * in case it's a max-MR 1 is returned, else 0
- */
-int ehca_mr_is_maxmr(u64 size,
-                    u64 *iova_start)
-{
-       /* a MR is treated as max-MR only if it fits following: */
-       if ((size == ehca_mr_len) &&
-           (iova_start == (void *)ehca_map_vaddr((void *)(KERNELBASE + PHYSICAL_START)))) {
-               ehca_gen_dbg("this is a max-MR");
-               return 1;
-       } else
-               return 0;
-} /* end ehca_mr_is_maxmr() */
-
-/*----------------------------------------------------------------------*/
-
-/* map access control for MR/MW. This routine is used for MR and MW. */
-void ehca_mrmw_map_acl(int ib_acl,
-                      u32 *hipz_acl)
-{
-       *hipz_acl = 0;
-       if (ib_acl & IB_ACCESS_REMOTE_READ)
-               *hipz_acl |= HIPZ_ACCESSCTRL_R_READ;
-       if (ib_acl & IB_ACCESS_REMOTE_WRITE)
-               *hipz_acl |= HIPZ_ACCESSCTRL_R_WRITE;
-       if (ib_acl & IB_ACCESS_REMOTE_ATOMIC)
-               *hipz_acl |= HIPZ_ACCESSCTRL_R_ATOMIC;
-       if (ib_acl & IB_ACCESS_LOCAL_WRITE)
-               *hipz_acl |= HIPZ_ACCESSCTRL_L_WRITE;
-       if (ib_acl & IB_ACCESS_MW_BIND)
-               *hipz_acl |= HIPZ_ACCESSCTRL_MW_BIND;
-} /* end ehca_mrmw_map_acl() */
-
-/*----------------------------------------------------------------------*/
-
-/* sets page size in hipz access control for MR/MW. */
-void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl) /*INOUT*/
-{
-       *hipz_acl |= (ehca_encode_hwpage_size(pgsize) << 24);
-} /* end ehca_mrmw_set_pgsize_hipz_acl() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * reverse map access control for MR/MW.
- * This routine is used for MR and MW.
- */
-void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
-                              int *ib_acl) /*OUT*/
-{
-       *ib_acl = 0;
-       if (*hipz_acl & HIPZ_ACCESSCTRL_R_READ)
-               *ib_acl |= IB_ACCESS_REMOTE_READ;
-       if (*hipz_acl & HIPZ_ACCESSCTRL_R_WRITE)
-               *ib_acl |= IB_ACCESS_REMOTE_WRITE;
-       if (*hipz_acl & HIPZ_ACCESSCTRL_R_ATOMIC)
-               *ib_acl |= IB_ACCESS_REMOTE_ATOMIC;
-       if (*hipz_acl & HIPZ_ACCESSCTRL_L_WRITE)
-               *ib_acl |= IB_ACCESS_LOCAL_WRITE;
-       if (*hipz_acl & HIPZ_ACCESSCTRL_MW_BIND)
-               *ib_acl |= IB_ACCESS_MW_BIND;
-} /* end ehca_mrmw_reverse_map_acl() */
-
-
-/*----------------------------------------------------------------------*/
-
-/*
- * MR destructor and constructor
- * used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
- * except struct ib_mr and spinlock
- */
-void ehca_mr_deletenew(struct ehca_mr *mr)
-{
-       mr->flags = 0;
-       mr->num_kpages = 0;
-       mr->num_hwpages = 0;
-       mr->acl = 0;
-       mr->start = NULL;
-       mr->fmr_page_size = 0;
-       mr->fmr_max_pages = 0;
-       mr->fmr_max_maps = 0;
-       mr->fmr_map_cnt = 0;
-       memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
-       memset(&mr->galpas, 0, sizeof(mr->galpas));
-} /* end ehca_mr_deletenew() */
-
-int ehca_init_mrmw_cache(void)
-{
-       mr_cache = kmem_cache_create("ehca_cache_mr",
-                                    sizeof(struct ehca_mr), 0,
-                                    SLAB_HWCACHE_ALIGN,
-                                    NULL);
-       if (!mr_cache)
-               return -ENOMEM;
-       mw_cache = kmem_cache_create("ehca_cache_mw",
-                                    sizeof(struct ehca_mw), 0,
-                                    SLAB_HWCACHE_ALIGN,
-                                    NULL);
-       if (!mw_cache) {
-               kmem_cache_destroy(mr_cache);
-               mr_cache = NULL;
-               return -ENOMEM;
-       }
-       return 0;
-}
-
-void ehca_cleanup_mrmw_cache(void)
-{
-       kmem_cache_destroy(mr_cache);
-       kmem_cache_destroy(mw_cache);
-}
-
-static inline int ehca_init_top_bmap(struct ehca_top_bmap *ehca_top_bmap,
-                                    int dir)
-{
-       if (!ehca_bmap_valid(ehca_top_bmap->dir[dir])) {
-               ehca_top_bmap->dir[dir] =
-                       kmalloc(sizeof(struct ehca_dir_bmap), GFP_KERNEL);
-               if (!ehca_top_bmap->dir[dir])
-                       return -ENOMEM;
-               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
-               memset(ehca_top_bmap->dir[dir], 0xFF, EHCA_ENT_MAP_SIZE);
-       }
-       return 0;
-}
-
-static inline int ehca_init_bmap(struct ehca_bmap *ehca_bmap, int top, int dir)
-{
-       if (!ehca_bmap_valid(ehca_bmap->top[top])) {
-               ehca_bmap->top[top] =
-                       kmalloc(sizeof(struct ehca_top_bmap), GFP_KERNEL);
-               if (!ehca_bmap->top[top])
-                       return -ENOMEM;
-               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
-               memset(ehca_bmap->top[top], 0xFF, EHCA_DIR_MAP_SIZE);
-       }
-       return ehca_init_top_bmap(ehca_bmap->top[top], dir);
-}
-
-static inline int ehca_calc_index(unsigned long i, unsigned long s)
-{
-       return (i >> s) & EHCA_INDEX_MASK;
-}
-
-void ehca_destroy_busmap(void)
-{
-       int top, dir;
-
-       if (!ehca_bmap)
-               return;
-
-       for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
-               if (!ehca_bmap_valid(ehca_bmap->top[top]))
-                       continue;
-               for (dir = 0; dir < EHCA_MAP_ENTRIES; dir++) {
-                       if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
-                               continue;
-
-                       kfree(ehca_bmap->top[top]->dir[dir]);
-               }
-
-               kfree(ehca_bmap->top[top]);
-       }
-
-       kfree(ehca_bmap);
-       ehca_bmap = NULL;
-}
-
-static int ehca_update_busmap(unsigned long pfn, unsigned long nr_pages)
-{
-       unsigned long i, start_section, end_section;
-       int top, dir, idx;
-
-       if (!nr_pages)
-               return 0;
-
-       if (!ehca_bmap) {
-               ehca_bmap = kmalloc(sizeof(struct ehca_bmap), GFP_KERNEL);
-               if (!ehca_bmap)
-                       return -ENOMEM;
-               /* Set map block to 0xFF according to EHCA_INVAL_ADDR */
-               memset(ehca_bmap, 0xFF, EHCA_TOP_MAP_SIZE);
-       }
-
-       start_section = (pfn * PAGE_SIZE) / EHCA_SECTSIZE;
-       end_section = ((pfn + nr_pages) * PAGE_SIZE) / EHCA_SECTSIZE;
-       for (i = start_section; i < end_section; i++) {
-               int ret;
-               top = ehca_calc_index(i, EHCA_TOP_INDEX_SHIFT);
-               dir = ehca_calc_index(i, EHCA_DIR_INDEX_SHIFT);
-               idx = i & EHCA_INDEX_MASK;
-
-               ret = ehca_init_bmap(ehca_bmap, top, dir);
-               if (ret) {
-                       ehca_destroy_busmap();
-                       return ret;
-               }
-               ehca_bmap->top[top]->dir[dir]->ent[idx] = ehca_mr_len;
-               ehca_mr_len += EHCA_SECTSIZE;
-       }
-       return 0;
-}
-
-static int ehca_is_hugepage(unsigned long pfn)
-{
-       int page_order;
-
-       if (pfn & EHCA_HUGEPAGE_PFN_MASK)
-               return 0;
-
-       page_order = compound_order(pfn_to_page(pfn));
-       if (page_order + PAGE_SHIFT != EHCA_HUGEPAGESHIFT)
-               return 0;
-
-       return 1;
-}
-
-static int ehca_create_busmap_callback(unsigned long initial_pfn,
-                                      unsigned long total_nr_pages, void *arg)
-{
-       int ret;
-       unsigned long pfn, start_pfn, end_pfn, nr_pages;
-
-       if ((total_nr_pages * PAGE_SIZE) < EHCA_HUGEPAGE_SIZE)
-               return ehca_update_busmap(initial_pfn, total_nr_pages);
-
-       /* Given chunk is >= 16GB -> check for hugepages */
-       start_pfn = initial_pfn;
-       end_pfn = initial_pfn + total_nr_pages;
-       pfn = start_pfn;
-
-       while (pfn < end_pfn) {
-               if (ehca_is_hugepage(pfn)) {
-                       /* Add mem found in front of the hugepage */
-                       nr_pages = pfn - start_pfn;
-                       ret = ehca_update_busmap(start_pfn, nr_pages);
-                       if (ret)
-                               return ret;
-                       /* Skip the hugepage */
-                       pfn += (EHCA_HUGEPAGE_SIZE / PAGE_SIZE);
-                       start_pfn = pfn;
-               } else
-                       pfn += (EHCA_SECTSIZE / PAGE_SIZE);
-       }
-
-       /* Add mem found behind the hugepage(s)  */
-       nr_pages = pfn - start_pfn;
-       return ehca_update_busmap(start_pfn, nr_pages);
-}
-
-int ehca_create_busmap(void)
-{
-       int ret;
-
-       ehca_mr_len = 0;
-       ret = walk_system_ram_range(0, 1ULL << MAX_PHYSMEM_BITS, NULL,
-                                  ehca_create_busmap_callback);
-       return ret;
-}
-
-static int ehca_reg_bmap_mr_rpages(struct ehca_shca *shca,
-                                  struct ehca_mr *e_mr,
-                                  struct ehca_mr_pginfo *pginfo)
-{
-       int top;
-       u64 hret, *kpage;
-
-       kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!kpage) {
-               ehca_err(&shca->ib_device, "kpage alloc failed");
-               return -ENOMEM;
-       }
-       for (top = 0; top < EHCA_MAP_ENTRIES; top++) {
-               if (!ehca_bmap_valid(ehca_bmap->top[top]))
-                       continue;
-               hret = ehca_reg_mr_dir_sections(top, kpage, shca, e_mr, pginfo);
-               if ((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
-                       break;
-       }
-
-       ehca_free_fw_ctrlblock(kpage);
-
-       if (hret == H_SUCCESS)
-               return 0; /* Everything is fine */
-       else {
-               ehca_err(&shca->ib_device, "ehca_reg_bmap_mr_rpages failed, "
-                                "h_ret=%lli e_mr=%p top=%x lkey=%x "
-                                "hca_hndl=%llx mr_hndl=%llx", hret, e_mr, top,
-                                e_mr->ib.ib_mr.lkey,
-                                shca->ipz_hca_handle.handle,
-                                e_mr->ipz_mr_handle.handle);
-               return ehca2ib_return_code(hret);
-       }
-}
-
-static u64 ehca_map_vaddr(void *caddr)
-{
-       int top, dir, idx;
-       unsigned long abs_addr, offset;
-       u64 entry;
-
-       if (!ehca_bmap)
-               return EHCA_INVAL_ADDR;
-
-       abs_addr = __pa(caddr);
-       top = ehca_calc_index(abs_addr, EHCA_TOP_INDEX_SHIFT + EHCA_SECTSHIFT);
-       if (!ehca_bmap_valid(ehca_bmap->top[top]))
-               return EHCA_INVAL_ADDR;
-
-       dir = ehca_calc_index(abs_addr, EHCA_DIR_INDEX_SHIFT + EHCA_SECTSHIFT);
-       if (!ehca_bmap_valid(ehca_bmap->top[top]->dir[dir]))
-               return EHCA_INVAL_ADDR;
-
-       idx = ehca_calc_index(abs_addr, EHCA_SECTSHIFT);
-
-       entry = ehca_bmap->top[top]->dir[dir]->ent[idx];
-       if (ehca_bmap_valid(entry)) {
-               offset = (unsigned long)caddr & (EHCA_SECTSIZE - 1);
-               return entry | offset;
-       } else
-               return EHCA_INVAL_ADDR;
-}
-
-static int ehca_dma_mapping_error(struct ib_device *dev, u64 dma_addr)
-{
-       return dma_addr == EHCA_INVAL_ADDR;
-}
-
-static u64 ehca_dma_map_single(struct ib_device *dev, void *cpu_addr,
-                              size_t size, enum dma_data_direction direction)
-{
-       if (cpu_addr)
-               return ehca_map_vaddr(cpu_addr);
-       else
-               return EHCA_INVAL_ADDR;
-}
-
-static void ehca_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size,
-                                 enum dma_data_direction direction)
-{
-       /* This is only a stub; nothing to be done here */
-}
-
-static u64 ehca_dma_map_page(struct ib_device *dev, struct page *page,
-                            unsigned long offset, size_t size,
-                            enum dma_data_direction direction)
-{
-       u64 addr;
-
-       if (offset + size > PAGE_SIZE)
-               return EHCA_INVAL_ADDR;
-
-       addr = ehca_map_vaddr(page_address(page));
-       if (!ehca_dma_mapping_error(dev, addr))
-               addr += offset;
-
-       return addr;
-}
-
-static void ehca_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size,
-                               enum dma_data_direction direction)
-{
-       /* This is only a stub; nothing to be done here */
-}
-
-static int ehca_dma_map_sg(struct ib_device *dev, struct scatterlist *sgl,
-                          int nents, enum dma_data_direction direction)
-{
-       struct scatterlist *sg;
-       int i;
-
-       for_each_sg(sgl, sg, nents, i) {
-               u64 addr;
-               addr = ehca_map_vaddr(sg_virt(sg));
-               if (ehca_dma_mapping_error(dev, addr))
-                       return 0;
-
-               sg->dma_address = addr;
-               sg->dma_length = sg->length;
-       }
-       return nents;
-}
-
-static void ehca_dma_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
-                             int nents, enum dma_data_direction direction)
-{
-       /* This is only a stub; nothing to be done here */
-}
-
-static void ehca_dma_sync_single_for_cpu(struct ib_device *dev, u64 addr,
-                                        size_t size,
-                                        enum dma_data_direction dir)
-{
-       dma_sync_single_for_cpu(dev->dma_device, addr, size, dir);
-}
-
-static void ehca_dma_sync_single_for_device(struct ib_device *dev, u64 addr,
-                                           size_t size,
-                                           enum dma_data_direction dir)
-{
-       dma_sync_single_for_device(dev->dma_device, addr, size, dir);
-}
-
-static void *ehca_dma_alloc_coherent(struct ib_device *dev, size_t size,
-                                    u64 *dma_handle, gfp_t flag)
-{
-       struct page *p;
-       void *addr = NULL;
-       u64 dma_addr;
-
-       p = alloc_pages(flag, get_order(size));
-       if (p) {
-               addr = page_address(p);
-               dma_addr = ehca_map_vaddr(addr);
-               if (ehca_dma_mapping_error(dev, dma_addr)) {
-                       free_pages((unsigned long)addr, get_order(size));
-                       return NULL;
-               }
-               if (dma_handle)
-                       *dma_handle = dma_addr;
-               return addr;
-       }
-       return NULL;
-}
-
-static void ehca_dma_free_coherent(struct ib_device *dev, size_t size,
-                                  void *cpu_addr, u64 dma_handle)
-{
-       if (cpu_addr && size)
-               free_pages((unsigned long)cpu_addr, get_order(size));
-}
-
-
-struct ib_dma_mapping_ops ehca_dma_mapping_ops = {
-       .mapping_error          = ehca_dma_mapping_error,
-       .map_single             = ehca_dma_map_single,
-       .unmap_single           = ehca_dma_unmap_single,
-       .map_page               = ehca_dma_map_page,
-       .unmap_page             = ehca_dma_unmap_page,
-       .map_sg                 = ehca_dma_map_sg,
-       .unmap_sg               = ehca_dma_unmap_sg,
-       .sync_single_for_cpu    = ehca_dma_sync_single_for_cpu,
-       .sync_single_for_device = ehca_dma_sync_single_for_device,
-       .alloc_coherent         = ehca_dma_alloc_coherent,
-       .free_coherent          = ehca_dma_free_coherent,
-};
diff --git a/drivers/staging/rdma/ehca/ehca_mrmw.h b/drivers/staging/rdma/ehca/ehca_mrmw.h
deleted file mode 100644 (file)
index 52bfa95..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  MR/MW declarations and inline functions
- *
- *  Authors: Dietmar Decker <ddecker@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 _EHCA_MRMW_H_
-#define _EHCA_MRMW_H_
-
-enum ehca_reg_type {
-       EHCA_REG_MR,
-       EHCA_REG_BUSMAP_MR
-};
-
-int ehca_reg_mr(struct ehca_shca *shca,
-               struct ehca_mr *e_mr,
-               u64 *iova_start,
-               u64 size,
-               int acl,
-               struct ehca_pd *e_pd,
-               struct ehca_mr_pginfo *pginfo,
-               u32 *lkey,
-               u32 *rkey,
-               enum ehca_reg_type reg_type);
-
-int ehca_reg_mr_rpages(struct ehca_shca *shca,
-                      struct ehca_mr *e_mr,
-                      struct ehca_mr_pginfo *pginfo);
-
-int ehca_rereg_mr(struct ehca_shca *shca,
-                 struct ehca_mr *e_mr,
-                 u64 *iova_start,
-                 u64 size,
-                 int mr_access_flags,
-                 struct ehca_pd *e_pd,
-                 struct ehca_mr_pginfo *pginfo,
-                 u32 *lkey,
-                 u32 *rkey);
-
-int ehca_unmap_one_fmr(struct ehca_shca *shca,
-                      struct ehca_mr *e_fmr);
-
-int ehca_reg_smr(struct ehca_shca *shca,
-                struct ehca_mr *e_origmr,
-                struct ehca_mr *e_newmr,
-                u64 *iova_start,
-                int acl,
-                struct ehca_pd *e_pd,
-                u32 *lkey,
-                u32 *rkey);
-
-int ehca_reg_internal_maxmr(struct ehca_shca *shca,
-                           struct ehca_pd *e_pd,
-                           struct ehca_mr **maxmr);
-
-int ehca_reg_maxmr(struct ehca_shca *shca,
-                  struct ehca_mr *e_newmr,
-                  u64 *iova_start,
-                  int acl,
-                  struct ehca_pd *e_pd,
-                  u32 *lkey,
-                  u32 *rkey);
-
-int ehca_dereg_internal_maxmr(struct ehca_shca *shca);
-
-int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
-                            u64 *page_list,
-                            int list_len);
-
-int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
-                    u32 number,
-                    u64 *kpage);
-
-int ehca_mr_is_maxmr(u64 size,
-                    u64 *iova_start);
-
-void ehca_mrmw_map_acl(int ib_acl,
-                      u32 *hipz_acl);
-
-void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl);
-
-void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
-                              int *ib_acl);
-
-void ehca_mr_deletenew(struct ehca_mr *mr);
-
-int ehca_create_busmap(void);
-
-void ehca_destroy_busmap(void);
-
-extern struct ib_dma_mapping_ops ehca_dma_mapping_ops;
-#endif  /*_EHCA_MRMW_H_*/
diff --git a/drivers/staging/rdma/ehca/ehca_pd.c b/drivers/staging/rdma/ehca/ehca_pd.c
deleted file mode 100644 (file)
index 2a8aae4..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  PD functions
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_tools.h"
-#include "ehca_iverbs.h"
-
-static struct kmem_cache *pd_cache;
-
-struct ib_pd *ehca_alloc_pd(struct ib_device *device,
-                           struct ib_ucontext *context, struct ib_udata *udata)
-{
-       struct ehca_pd *pd;
-       int i;
-
-       pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
-       if (!pd) {
-               ehca_err(device, "device=%p context=%p out of memory",
-                        device, context);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       for (i = 0; i < 2; i++) {
-               INIT_LIST_HEAD(&pd->free[i]);
-               INIT_LIST_HEAD(&pd->full[i]);
-       }
-       mutex_init(&pd->lock);
-
-       /*
-        * Kernel PD: when device = -1, 0
-        * User   PD: when context != -1
-        */
-       if (!context) {
-               /*
-                * Kernel PDs after init reuses always
-                * the one created in ehca_shca_reopen()
-                */
-               struct ehca_shca *shca = container_of(device, struct ehca_shca,
-                                                     ib_device);
-               pd->fw_pd.value = shca->pd->fw_pd.value;
-       } else
-               pd->fw_pd.value = (u64)pd;
-
-       return &pd->ib_pd;
-}
-
-int ehca_dealloc_pd(struct ib_pd *pd)
-{
-       struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
-       int i, leftovers = 0;
-       struct ipz_small_queue_page *page, *tmp;
-
-       for (i = 0; i < 2; i++) {
-               list_splice(&my_pd->full[i], &my_pd->free[i]);
-               list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
-                       leftovers = 1;
-                       free_page(page->page);
-                       kmem_cache_free(small_qp_cache, page);
-               }
-       }
-
-       if (leftovers)
-               ehca_warn(pd->device,
-                         "Some small queue pages were not freed");
-
-       kmem_cache_free(pd_cache, my_pd);
-
-       return 0;
-}
-
-int ehca_init_pd_cache(void)
-{
-       pd_cache = kmem_cache_create("ehca_cache_pd",
-                                    sizeof(struct ehca_pd), 0,
-                                    SLAB_HWCACHE_ALIGN,
-                                    NULL);
-       if (!pd_cache)
-               return -ENOMEM;
-       return 0;
-}
-
-void ehca_cleanup_pd_cache(void)
-{
-       kmem_cache_destroy(pd_cache);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_qes.h b/drivers/staging/rdma/ehca/ehca_qes.h
deleted file mode 100644 (file)
index 90c4efa..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Hardware request structures
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 _EHCA_QES_H_
-#define _EHCA_QES_H_
-
-#include "ehca_tools.h"
-
-/* virtual scatter gather entry to specify remote addresses with length */
-struct ehca_vsgentry {
-       u64 vaddr;
-       u32 lkey;
-       u32 length;
-};
-
-#define GRH_FLAG_MASK        EHCA_BMASK_IBM( 7,  7)
-#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM( 0,  3)
-#define GRH_TCLASS_MASK      EHCA_BMASK_IBM( 4, 12)
-#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13, 31)
-#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32, 47)
-#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48, 55)
-#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56, 63)
-
-/*
- * Unreliable Datagram Address Vector Format
- * see IBTA Vol1 chapter 8.3 Global Routing Header
- */
-struct ehca_ud_av {
-       u8 sl;
-       u8 lnh;
-       u16 dlid;
-       u8 reserved1;
-       u8 reserved2;
-       u8 reserved3;
-       u8 slid_path_bits;
-       u8 reserved4;
-       u8 ipd;
-       u8 reserved5;
-       u8 pmtu;
-       u32 reserved6;
-       u64 reserved7;
-       union {
-               struct {
-                       u64 word_0; /* always set to 6  */
-                       /*should be 0x1B for IB transport */
-                       u64 word_1;
-                       u64 word_2;
-                       u64 word_3;
-                       u64 word_4;
-               } grh;
-               struct {
-                       u32 wd_0;
-                       u32 wd_1;
-                       /* DWord_1 --> SGID */
-
-                       u32 sgid_wd3;
-                       u32 sgid_wd2;
-
-                       u32 sgid_wd1;
-                       u32 sgid_wd0;
-                       /* DWord_3 --> DGID */
-
-                       u32 dgid_wd3;
-                       u32 dgid_wd2;
-
-                       u32 dgid_wd1;
-                       u32 dgid_wd0;
-               } grh_l;
-       };
-};
-
-/* maximum number of sg entries allowed in a WQE */
-#define MAX_WQE_SG_ENTRIES 252
-
-#define WQE_OPTYPE_SEND             0x80
-#define WQE_OPTYPE_RDMAREAD         0x40
-#define WQE_OPTYPE_RDMAWRITE        0x20
-#define WQE_OPTYPE_CMPSWAP          0x10
-#define WQE_OPTYPE_FETCHADD         0x08
-#define WQE_OPTYPE_BIND             0x04
-
-#define WQE_WRFLAG_REQ_SIGNAL_COM   0x80
-#define WQE_WRFLAG_FENCE            0x40
-#define WQE_WRFLAG_IMM_DATA_PRESENT 0x20
-#define WQE_WRFLAG_SOLIC_EVENT      0x10
-
-#define WQEF_CACHE_HINT             0x80
-#define WQEF_CACHE_HINT_RD_WR       0x40
-#define WQEF_TIMED_WQE              0x20
-#define WQEF_PURGE                  0x08
-#define WQEF_HIGH_NIBBLE            0xF0
-
-#define MW_BIND_ACCESSCTRL_R_WRITE   0x40
-#define MW_BIND_ACCESSCTRL_R_READ    0x20
-#define MW_BIND_ACCESSCTRL_R_ATOMIC  0x10
-
-struct ehca_wqe {
-       u64 work_request_id;
-       u8 optype;
-       u8 wr_flag;
-       u16 pkeyi;
-       u8 wqef;
-       u8 nr_of_data_seg;
-       u16 wqe_provided_slid;
-       u32 destination_qp_number;
-       u32 resync_psn_sqp;
-       u32 local_ee_context_qkey;
-       u32 immediate_data;
-       union {
-               struct {
-                       u64 remote_virtual_address;
-                       u32 rkey;
-                       u32 reserved;
-                       u64 atomic_1st_op_dma_len;
-                       u64 atomic_2nd_op;
-                       struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
-
-               } nud;
-               struct {
-                       u64 ehca_ud_av_ptr;
-                       u64 reserved1;
-                       u64 reserved2;
-                       u64 reserved3;
-                       struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
-               } ud_avp;
-               struct {
-                       struct ehca_ud_av ud_av;
-                       struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES -
-                                                    2];
-               } ud_av;
-               struct {
-                       u64 reserved0;
-                       u64 reserved1;
-                       u64 reserved2;
-                       u64 reserved3;
-                       struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
-               } all_rcv;
-
-               struct {
-                       u64 reserved;
-                       u32 rkey;
-                       u32 old_rkey;
-                       u64 reserved1;
-                       u64 reserved2;
-                       u64 virtual_address;
-                       u32 reserved3;
-                       u32 length;
-                       u32 reserved4;
-                       u16 reserved5;
-                       u8 reserved6;
-                       u8 lr_ctl;
-                       u32 lkey;
-                       u32 reserved7;
-                       u64 reserved8;
-                       u64 reserved9;
-                       u64 reserved10;
-                       u64 reserved11;
-               } bind;
-               struct {
-                       u64 reserved12;
-                       u64 reserved13;
-                       u32 size;
-                       u32 start;
-               } inline_data;
-       } u;
-
-};
-
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
-#define WC_IMM_DATA     EHCA_BMASK_IBM(1, 1)
-#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2, 2)
-#define WC_SE_BIT       EHCA_BMASK_IBM(3, 3)
-#define WC_STATUS_ERROR_BIT 0x80000000
-#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
-#define WC_STATUS_PURGE_BIT 0x10
-#define WC_SEND_RECEIVE_BIT 0x80
-
-struct ehca_cqe {
-       u64 work_request_id;
-       u8 optype;
-       u8 w_completion_flags;
-       u16 reserved1;
-       u32 nr_bytes_transferred;
-       u32 immediate_data;
-       u32 local_qp_number;
-       u8 freed_resource_count;
-       u8 service_level;
-       u16 wqe_count;
-       u32 qp_token;
-       u32 qkey_ee_token;
-       u32 remote_qp_number;
-       u16 dlid;
-       u16 rlid;
-       u16 reserved2;
-       u16 pkey_index;
-       u32 cqe_timestamp;
-       u32 wqe_timestamp;
-       u8 wqe_timestamp_valid;
-       u8 reserved3;
-       u8 reserved4;
-       u8 cqe_flags;
-       u32 status;
-};
-
-struct ehca_eqe {
-       u64 entry;
-};
-
-struct ehca_mrte {
-       u64 starting_va;
-       u64 length; /* length of memory region in bytes*/
-       u32 pd;
-       u8 key_instance;
-       u8 pagesize;
-       u8 mr_control;
-       u8 local_remote_access_ctrl;
-       u8 reserved[0x20 - 0x18];
-       u64 at_pointer[4];
-};
-#endif /*_EHCA_QES_H_*/
diff --git a/drivers/staging/rdma/ehca/ehca_qp.c b/drivers/staging/rdma/ehca/ehca_qp.c
deleted file mode 100644 (file)
index 896c01f..0000000
+++ /dev/null
@@ -1,2256 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  QP functions
- *
- *  Authors: Joachim Fenkes <fenkes@de.ibm.com>
- *           Stefan Roscher <stefan.roscher@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_classes.h"
-#include "ehca_tools.h"
-#include "ehca_qes.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-#include "hipz_fns.h"
-
-static struct kmem_cache *qp_cache;
-
-/*
- * attributes not supported by query qp
- */
-#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_ACCESS_FLAGS       | \
-                                    IB_QP_EN_SQD_ASYNC_NOTIFY)
-
-/*
- * ehca (internal) qp state values
- */
-enum ehca_qp_state {
-       EHCA_QPS_RESET = 1,
-       EHCA_QPS_INIT = 2,
-       EHCA_QPS_RTR = 3,
-       EHCA_QPS_RTS = 5,
-       EHCA_QPS_SQD = 6,
-       EHCA_QPS_SQE = 8,
-       EHCA_QPS_ERR = 128
-};
-
-/*
- * qp state transitions as defined by IB Arch Rel 1.1 page 431
- */
-enum ib_qp_statetrans {
-       IB_QPST_ANY2RESET,
-       IB_QPST_ANY2ERR,
-       IB_QPST_RESET2INIT,
-       IB_QPST_INIT2RTR,
-       IB_QPST_INIT2INIT,
-       IB_QPST_RTR2RTS,
-       IB_QPST_RTS2SQD,
-       IB_QPST_RTS2RTS,
-       IB_QPST_SQD2RTS,
-       IB_QPST_SQE2RTS,
-       IB_QPST_SQD2SQD,
-       IB_QPST_MAX     /* nr of transitions, this must be last!!! */
-};
-
-/*
- * ib2ehca_qp_state maps IB to ehca qp_state
- * returns ehca qp state corresponding to given ib qp state
- */
-static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state)
-{
-       switch (ib_qp_state) {
-       case IB_QPS_RESET:
-               return EHCA_QPS_RESET;
-       case IB_QPS_INIT:
-               return EHCA_QPS_INIT;
-       case IB_QPS_RTR:
-               return EHCA_QPS_RTR;
-       case IB_QPS_RTS:
-               return EHCA_QPS_RTS;
-       case IB_QPS_SQD:
-               return EHCA_QPS_SQD;
-       case IB_QPS_SQE:
-               return EHCA_QPS_SQE;
-       case IB_QPS_ERR:
-               return EHCA_QPS_ERR;
-       default:
-               ehca_gen_err("invalid ib_qp_state=%x", ib_qp_state);
-               return -EINVAL;
-       }
-}
-
-/*
- * ehca2ib_qp_state maps ehca to IB qp_state
- * returns ib qp state corresponding to given ehca qp state
- */
-static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state
-                                               ehca_qp_state)
-{
-       switch (ehca_qp_state) {
-       case EHCA_QPS_RESET:
-               return IB_QPS_RESET;
-       case EHCA_QPS_INIT:
-               return IB_QPS_INIT;
-       case EHCA_QPS_RTR:
-               return IB_QPS_RTR;
-       case EHCA_QPS_RTS:
-               return IB_QPS_RTS;
-       case EHCA_QPS_SQD:
-               return IB_QPS_SQD;
-       case EHCA_QPS_SQE:
-               return IB_QPS_SQE;
-       case EHCA_QPS_ERR:
-               return IB_QPS_ERR;
-       default:
-               ehca_gen_err("invalid ehca_qp_state=%x", ehca_qp_state);
-               return -EINVAL;
-       }
-}
-
-/*
- * ehca_qp_type used as index for req_attr and opt_attr of
- * struct ehca_modqp_statetrans
- */
-enum ehca_qp_type {
-       QPT_RC = 0,
-       QPT_UC = 1,
-       QPT_UD = 2,
-       QPT_SQP = 3,
-       QPT_MAX
-};
-
-/*
- * ib2ehcaqptype maps Ib to ehca qp_type
- * returns ehca qp type corresponding to ib qp type
- */
-static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype)
-{
-       switch (ibqptype) {
-       case IB_QPT_SMI:
-       case IB_QPT_GSI:
-               return QPT_SQP;
-       case IB_QPT_RC:
-               return QPT_RC;
-       case IB_QPT_UC:
-               return QPT_UC;
-       case IB_QPT_UD:
-               return QPT_UD;
-       default:
-               ehca_gen_err("Invalid ibqptype=%x", ibqptype);
-               return -EINVAL;
-       }
-}
-
-static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,
-                                                        int ib_tostate)
-{
-       int index = -EINVAL;
-       switch (ib_tostate) {
-       case IB_QPS_RESET:
-               index = IB_QPST_ANY2RESET;
-               break;
-       case IB_QPS_INIT:
-               switch (ib_fromstate) {
-               case IB_QPS_RESET:
-                       index = IB_QPST_RESET2INIT;
-                       break;
-               case IB_QPS_INIT:
-                       index = IB_QPST_INIT2INIT;
-                       break;
-               }
-               break;
-       case IB_QPS_RTR:
-               if (ib_fromstate == IB_QPS_INIT)
-                       index = IB_QPST_INIT2RTR;
-               break;
-       case IB_QPS_RTS:
-               switch (ib_fromstate) {
-               case IB_QPS_RTR:
-                       index = IB_QPST_RTR2RTS;
-                       break;
-               case IB_QPS_RTS:
-                       index = IB_QPST_RTS2RTS;
-                       break;
-               case IB_QPS_SQD:
-                       index = IB_QPST_SQD2RTS;
-                       break;
-               case IB_QPS_SQE:
-                       index = IB_QPST_SQE2RTS;
-                       break;
-               }
-               break;
-       case IB_QPS_SQD:
-               if (ib_fromstate == IB_QPS_RTS)
-                       index = IB_QPST_RTS2SQD;
-               break;
-       case IB_QPS_SQE:
-               break;
-       case IB_QPS_ERR:
-               index = IB_QPST_ANY2ERR;
-               break;
-       default:
-               break;
-       }
-       return index;
-}
-
-/*
- * ibqptype2servicetype returns hcp service type corresponding to given
- * ib qp type used by create_qp()
- */
-static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
-{
-       switch (ibqptype) {
-       case IB_QPT_SMI:
-       case IB_QPT_GSI:
-               return ST_UD;
-       case IB_QPT_RC:
-               return ST_RC;
-       case IB_QPT_UC:
-               return ST_UC;
-       case IB_QPT_UD:
-               return ST_UD;
-       case IB_QPT_RAW_IPV6:
-               return -EINVAL;
-       case IB_QPT_RAW_ETHERTYPE:
-               return -EINVAL;
-       default:
-               ehca_gen_err("Invalid ibqptype=%x", ibqptype);
-               return -EINVAL;
-       }
-}
-
-/*
- * init userspace queue info from ipz_queue data
- */
-static inline void queue2resp(struct ipzu_queue_resp *resp,
-                             struct ipz_queue *queue)
-{
-       resp->qe_size = queue->qe_size;
-       resp->act_nr_of_sg = queue->act_nr_of_sg;
-       resp->queue_length = queue->queue_length;
-       resp->pagesize = queue->pagesize;
-       resp->toggle_state = queue->toggle_state;
-       resp->offset = queue->offset;
-}
-
-/*
- * init_qp_queue initializes/constructs r/squeue and registers queue pages.
- */
-static inline int init_qp_queue(struct ehca_shca *shca,
-                               struct ehca_pd *pd,
-                               struct ehca_qp *my_qp,
-                               struct ipz_queue *queue,
-                               int q_type,
-                               u64 expected_hret,
-                               struct ehca_alloc_queue_parms *parms,
-                               int wqe_size)
-{
-       int ret, cnt, ipz_rc, nr_q_pages;
-       void *vpage;
-       u64 rpage, h_ret;
-       struct ib_device *ib_dev = &shca->ib_device;
-       struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
-
-       if (!parms->queue_size)
-               return 0;
-
-       if (parms->is_small) {
-               nr_q_pages = 1;
-               ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
-                                       128 << parms->page_size,
-                                       wqe_size, parms->act_nr_sges, 1);
-       } else {
-               nr_q_pages = parms->queue_size;
-               ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
-                                       EHCA_PAGESIZE, wqe_size,
-                                       parms->act_nr_sges, 0);
-       }
-
-       if (!ipz_rc) {
-               ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i",
-                        ipz_rc);
-               return -EBUSY;
-       }
-
-       /* register queue pages */
-       for (cnt = 0; cnt < nr_q_pages; cnt++) {
-               vpage = ipz_qpageit_get_inc(queue);
-               if (!vpage) {
-                       ehca_err(ib_dev, "ipz_qpageit_get_inc() "
-                                "failed p_vpage= %p", vpage);
-                       ret = -EINVAL;
-                       goto init_qp_queue1;
-               }
-               rpage = __pa(vpage);
-
-               h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
-                                                my_qp->ipz_qp_handle,
-                                                NULL, 0, q_type,
-                                                rpage, parms->is_small ? 0 : 1,
-                                                my_qp->galpas.kernel);
-               if (cnt == (nr_q_pages - 1)) {  /* last page! */
-                       if (h_ret != expected_hret) {
-                               ehca_err(ib_dev, "hipz_qp_register_rpage() "
-                                        "h_ret=%lli", h_ret);
-                               ret = ehca2ib_return_code(h_ret);
-                               goto init_qp_queue1;
-                       }
-                       vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
-                       if (vpage) {
-                               ehca_err(ib_dev, "ipz_qpageit_get_inc() "
-                                        "should not succeed vpage=%p", vpage);
-                               ret = -EINVAL;
-                               goto init_qp_queue1;
-                       }
-               } else {
-                       if (h_ret != H_PAGE_REGISTERED) {
-                               ehca_err(ib_dev, "hipz_qp_register_rpage() "
-                                        "h_ret=%lli", h_ret);
-                               ret = ehca2ib_return_code(h_ret);
-                               goto init_qp_queue1;
-                       }
-               }
-       }
-
-       ipz_qeit_reset(queue);
-
-       return 0;
-
-init_qp_queue1:
-       ipz_queue_dtor(pd, queue);
-       return ret;
-}
-
-static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
-{
-       if (is_llqp)
-               return 128 << act_nr_sge;
-       else
-               return offsetof(struct ehca_wqe,
-                               u.nud.sg_list[act_nr_sge]);
-}
-
-static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
-                                      int req_nr_sge, int is_llqp)
-{
-       u32 wqe_size, q_size;
-       int act_nr_sge = req_nr_sge;
-
-       if (!is_llqp)
-               /* round up #SGEs so WQE size is a power of 2 */
-               for (act_nr_sge = 4; act_nr_sge <= 252;
-                    act_nr_sge = 4 + 2 * act_nr_sge)
-                       if (act_nr_sge >= req_nr_sge)
-                               break;
-
-       wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
-       q_size = wqe_size * (queue->max_wr + 1);
-
-       if (q_size <= 512)
-               queue->page_size = 2;
-       else if (q_size <= 1024)
-               queue->page_size = 3;
-       else
-               queue->page_size = 0;
-
-       queue->is_small = (queue->page_size != 0);
-}
-
-/* needs to be called with cq->spinlock held */
-void ehca_add_to_err_list(struct ehca_qp *qp, int on_sq)
-{
-       struct list_head *list, *node;
-
-       /* TODO: support low latency QPs */
-       if (qp->ext_type == EQPT_LLQP)
-               return;
-
-       if (on_sq) {
-               list = &qp->send_cq->sqp_err_list;
-               node = &qp->sq_err_node;
-       } else {
-               list = &qp->recv_cq->rqp_err_list;
-               node = &qp->rq_err_node;
-       }
-
-       if (list_empty(node))
-               list_add_tail(node, list);
-
-       return;
-}
-
-static void del_from_err_list(struct ehca_cq *cq, struct list_head *node)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cq->spinlock, flags);
-
-       if (!list_empty(node))
-               list_del_init(node);
-
-       spin_unlock_irqrestore(&cq->spinlock, flags);
-}
-
-static void reset_queue_map(struct ehca_queue_map *qmap)
-{
-       int i;
-
-       qmap->tail = qmap->entries - 1;
-       qmap->left_to_poll = 0;
-       qmap->next_wqe_idx = 0;
-       for (i = 0; i < qmap->entries; i++) {
-               qmap->map[i].reported = 1;
-               qmap->map[i].cqe_req = 0;
-       }
-}
-
-/*
- * Create an ib_qp struct that is either a QP or an SRQ, depending on
- * the value of the is_srq parameter. If init_attr and srq_init_attr share
- * fields, the field out of init_attr is used.
- */
-static struct ehca_qp *internal_create_qp(
-       struct ib_pd *pd,
-       struct ib_qp_init_attr *init_attr,
-       struct ib_srq_init_attr *srq_init_attr,
-       struct ib_udata *udata, int is_srq)
-{
-       struct ehca_qp *my_qp, *my_srq = NULL;
-       struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
-       struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
-                                             ib_device);
-       struct ib_ucontext *context = NULL;
-       u64 h_ret;
-       int is_llqp = 0, has_srq = 0, is_user = 0;
-       int qp_type, max_send_sge, max_recv_sge, ret;
-
-       /* h_call's out parameters */
-       struct ehca_alloc_qp_parms parms;
-       u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;
-       unsigned long flags;
-
-       if (!atomic_add_unless(&shca->num_qps, 1, shca->max_num_qps)) {
-               ehca_err(pd->device, "Unable to create QP, max number of %i "
-                        "QPs reached.", shca->max_num_qps);
-               ehca_err(pd->device, "To increase the maximum number of QPs "
-                        "use the number_of_qps module parameter.\n");
-               return ERR_PTR(-ENOSPC);
-       }
-
-       if (init_attr->create_flags) {
-               atomic_dec(&shca->num_qps);
-               return ERR_PTR(-EINVAL);
-       }
-
-       memset(&parms, 0, sizeof(parms));
-       qp_type = init_attr->qp_type;
-
-       if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&
-               init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
-               ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
-                        init_attr->sq_sig_type);
-               atomic_dec(&shca->num_qps);
-               return ERR_PTR(-EINVAL);
-       }
-
-       /* save LLQP info */
-       if (qp_type & 0x80) {
-               is_llqp = 1;
-               parms.ext_type = EQPT_LLQP;
-               parms.ll_comp_flags = qp_type & LLQP_COMP_MASK;
-       }
-       qp_type &= 0x1F;
-       init_attr->qp_type &= 0x1F;
-
-       /* handle SRQ base QPs */
-       if (init_attr->srq) {
-               my_srq = container_of(init_attr->srq, struct ehca_qp, ib_srq);
-
-               if (qp_type == IB_QPT_UC) {
-                       ehca_err(pd->device, "UC with SRQ not supported");
-                       atomic_dec(&shca->num_qps);
-                       return ERR_PTR(-EINVAL);
-               }
-
-               has_srq = 1;
-               parms.ext_type = EQPT_SRQBASE;
-               parms.srq_qpn = my_srq->real_qp_num;
-       }
-
-       if (is_llqp && has_srq) {
-               ehca_err(pd->device, "LLQPs can't have an SRQ");
-               atomic_dec(&shca->num_qps);
-               return ERR_PTR(-EINVAL);
-       }
-
-       /* handle SRQs */
-       if (is_srq) {
-               parms.ext_type = EQPT_SRQ;
-               parms.srq_limit = srq_init_attr->attr.srq_limit;
-               if (init_attr->cap.max_recv_sge > 3) {
-                       ehca_err(pd->device, "no more than three SGEs "
-                                "supported for SRQ  pd=%p  max_sge=%x",
-                                pd, init_attr->cap.max_recv_sge);
-                       atomic_dec(&shca->num_qps);
-                       return ERR_PTR(-EINVAL);
-               }
-       }
-
-       /* check QP type */
-       if (qp_type != IB_QPT_UD &&
-           qp_type != IB_QPT_UC &&
-           qp_type != IB_QPT_RC &&
-           qp_type != IB_QPT_SMI &&
-           qp_type != IB_QPT_GSI) {
-               ehca_err(pd->device, "wrong QP Type=%x", qp_type);
-               atomic_dec(&shca->num_qps);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (is_llqp) {
-               switch (qp_type) {
-               case IB_QPT_RC:
-                       if ((init_attr->cap.max_send_wr > 255) ||
-                           (init_attr->cap.max_recv_wr > 255)) {
-                               ehca_err(pd->device,
-                                        "Invalid Number of max_sq_wr=%x "
-                                        "or max_rq_wr=%x for RC LLQP",
-                                        init_attr->cap.max_send_wr,
-                                        init_attr->cap.max_recv_wr);
-                               atomic_dec(&shca->num_qps);
-                               return ERR_PTR(-EINVAL);
-                       }
-                       break;
-               case IB_QPT_UD:
-                       if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) {
-                               ehca_err(pd->device, "UD LLQP not supported "
-                                        "by this adapter");
-                               atomic_dec(&shca->num_qps);
-                               return ERR_PTR(-ENOSYS);
-                       }
-                       if (!(init_attr->cap.max_send_sge <= 5
-                           && init_attr->cap.max_send_sge >= 1
-                           && init_attr->cap.max_recv_sge <= 5
-                           && init_attr->cap.max_recv_sge >= 1)) {
-                               ehca_err(pd->device,
-                                        "Invalid Number of max_send_sge=%x "
-                                        "or max_recv_sge=%x for UD LLQP",
-                                        init_attr->cap.max_send_sge,
-                                        init_attr->cap.max_recv_sge);
-                               atomic_dec(&shca->num_qps);
-                               return ERR_PTR(-EINVAL);
-                       } else if (init_attr->cap.max_send_wr > 255) {
-                               ehca_err(pd->device,
-                                        "Invalid Number of "
-                                        "max_send_wr=%x for UD QP_TYPE=%x",
-                                        init_attr->cap.max_send_wr, qp_type);
-                               atomic_dec(&shca->num_qps);
-                               return ERR_PTR(-EINVAL);
-                       }
-                       break;
-               default:
-                       ehca_err(pd->device, "unsupported LL QP Type=%x",
-                                qp_type);
-                       atomic_dec(&shca->num_qps);
-                       return ERR_PTR(-EINVAL);
-               }
-       } else {
-               int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
-                              || qp_type == IB_QPT_GSI) ? 250 : 252;
-
-               if (init_attr->cap.max_send_sge > max_sge
-                   || init_attr->cap.max_recv_sge > max_sge) {
-                       ehca_err(pd->device, "Invalid number of SGEs requested "
-                                "send_sge=%x recv_sge=%x max_sge=%x",
-                                init_attr->cap.max_send_sge,
-                                init_attr->cap.max_recv_sge, max_sge);
-                       atomic_dec(&shca->num_qps);
-                       return ERR_PTR(-EINVAL);
-               }
-       }
-
-       my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL);
-       if (!my_qp) {
-               ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
-               atomic_dec(&shca->num_qps);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       if (pd->uobject && udata) {
-               is_user = 1;
-               context = pd->uobject->context;
-       }
-
-       atomic_set(&my_qp->nr_events, 0);
-       init_waitqueue_head(&my_qp->wait_completion);
-       spin_lock_init(&my_qp->spinlock_s);
-       spin_lock_init(&my_qp->spinlock_r);
-       my_qp->qp_type = qp_type;
-       my_qp->ext_type = parms.ext_type;
-       my_qp->state = IB_QPS_RESET;
-
-       if (init_attr->recv_cq)
-               my_qp->recv_cq =
-                       container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
-       if (init_attr->send_cq)
-               my_qp->send_cq =
-                       container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
-
-       idr_preload(GFP_KERNEL);
-       write_lock_irqsave(&ehca_qp_idr_lock, flags);
-
-       ret = idr_alloc(&ehca_qp_idr, my_qp, 0, 0x2000000, GFP_NOWAIT);
-       if (ret >= 0)
-               my_qp->token = ret;
-
-       write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-       idr_preload_end();
-       if (ret < 0) {
-               if (ret == -ENOSPC) {
-                       ret = -EINVAL;
-                       ehca_err(pd->device, "Invalid number of qp");
-               } else {
-                       ret = -ENOMEM;
-                       ehca_err(pd->device, "Can't allocate new idr entry.");
-               }
-               goto create_qp_exit0;
-       }
-
-       if (has_srq)
-               parms.srq_token = my_qp->token;
-
-       parms.servicetype = ibqptype2servicetype(qp_type);
-       if (parms.servicetype < 0) {
-               ret = -EINVAL;
-               ehca_err(pd->device, "Invalid qp_type=%x", qp_type);
-               goto create_qp_exit1;
-       }
-
-       /* Always signal by WQE so we can hide circ. WQEs */
-       parms.sigtype = HCALL_SIGT_BY_WQE;
-
-       /* UD_AV CIRCUMVENTION */
-       max_send_sge = init_attr->cap.max_send_sge;
-       max_recv_sge = init_attr->cap.max_recv_sge;
-       if (parms.servicetype == ST_UD && !is_llqp) {
-               max_send_sge += 2;
-               max_recv_sge += 2;
-       }
-
-       parms.token = my_qp->token;
-       parms.eq_handle = shca->eq.ipz_eq_handle;
-       parms.pd = my_pd->fw_pd;
-       if (my_qp->send_cq)
-               parms.send_cq_handle = my_qp->send_cq->ipz_cq_handle;
-       if (my_qp->recv_cq)
-               parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
-
-       parms.squeue.max_wr = init_attr->cap.max_send_wr;
-       parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
-       parms.squeue.max_sge = max_send_sge;
-       parms.rqueue.max_sge = max_recv_sge;
-
-       /* RC QPs need one more SWQE for unsolicited ack circumvention */
-       if (qp_type == IB_QPT_RC)
-               parms.squeue.max_wr++;
-
-       if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
-               if (HAS_SQ(my_qp))
-                       ehca_determine_small_queue(
-                               &parms.squeue, max_send_sge, is_llqp);
-               if (HAS_RQ(my_qp))
-                       ehca_determine_small_queue(
-                               &parms.rqueue, max_recv_sge, is_llqp);
-               parms.qp_storage =
-                       (parms.squeue.is_small || parms.rqueue.is_small);
-       }
-
-       h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms, is_user);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lli",
-                        h_ret);
-               ret = ehca2ib_return_code(h_ret);
-               goto create_qp_exit1;
-       }
-
-       ib_qp_num = my_qp->real_qp_num = parms.real_qp_num;
-       my_qp->ipz_qp_handle = parms.qp_handle;
-       my_qp->galpas = parms.galpas;
-
-       swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
-       rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
-
-       switch (qp_type) {
-       case IB_QPT_RC:
-               if (is_llqp) {
-                       parms.squeue.act_nr_sges = 1;
-                       parms.rqueue.act_nr_sges = 1;
-               }
-               /* hide the extra WQE */
-               parms.squeue.act_nr_wqes--;
-               break;
-       case IB_QPT_UD:
-       case IB_QPT_GSI:
-       case IB_QPT_SMI:
-               /* UD circumvention */
-               if (is_llqp) {
-                       parms.squeue.act_nr_sges = 1;
-                       parms.rqueue.act_nr_sges = 1;
-               } else {
-                       parms.squeue.act_nr_sges -= 2;
-                       parms.rqueue.act_nr_sges -= 2;
-               }
-
-               if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
-                       parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
-                       parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
-                       parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
-                       parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
-                       ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
-               }
-
-               break;
-
-       default:
-               break;
-       }
-
-       /* initialize r/squeue and register queue pages */
-       if (HAS_SQ(my_qp)) {
-               ret = init_qp_queue(
-                       shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
-                       HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
-                       &parms.squeue, swqe_size);
-               if (ret) {
-                       ehca_err(pd->device, "Couldn't initialize squeue "
-                                "and pages ret=%i", ret);
-                       goto create_qp_exit2;
-               }
-
-               if (!is_user) {
-                       my_qp->sq_map.entries = my_qp->ipz_squeue.queue_length /
-                               my_qp->ipz_squeue.qe_size;
-                       my_qp->sq_map.map = vmalloc(my_qp->sq_map.entries *
-                                                   sizeof(struct ehca_qmap_entry));
-                       if (!my_qp->sq_map.map) {
-                               ehca_err(pd->device, "Couldn't allocate squeue "
-                                        "map ret=%i", ret);
-                               goto create_qp_exit3;
-                       }
-                       INIT_LIST_HEAD(&my_qp->sq_err_node);
-                       /* to avoid the generation of bogus flush CQEs */
-                       reset_queue_map(&my_qp->sq_map);
-               }
-       }
-
-       if (HAS_RQ(my_qp)) {
-               ret = init_qp_queue(
-                       shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
-                       H_SUCCESS, &parms.rqueue, rwqe_size);
-               if (ret) {
-                       ehca_err(pd->device, "Couldn't initialize rqueue "
-                                "and pages ret=%i", ret);
-                       goto create_qp_exit4;
-               }
-               if (!is_user) {
-                       my_qp->rq_map.entries = my_qp->ipz_rqueue.queue_length /
-                               my_qp->ipz_rqueue.qe_size;
-                       my_qp->rq_map.map = vmalloc(my_qp->rq_map.entries *
-                                                   sizeof(struct ehca_qmap_entry));
-                       if (!my_qp->rq_map.map) {
-                               ehca_err(pd->device, "Couldn't allocate squeue "
-                                        "map ret=%i", ret);
-                               goto create_qp_exit5;
-                       }
-                       INIT_LIST_HEAD(&my_qp->rq_err_node);
-                       /* to avoid the generation of bogus flush CQEs */
-                       reset_queue_map(&my_qp->rq_map);
-               }
-       } else if (init_attr->srq && !is_user) {
-               /* this is a base QP, use the queue map of the SRQ */
-               my_qp->rq_map = my_srq->rq_map;
-               INIT_LIST_HEAD(&my_qp->rq_err_node);
-
-               my_qp->ipz_rqueue = my_srq->ipz_rqueue;
-       }
-
-       if (is_srq) {
-               my_qp->ib_srq.pd = &my_pd->ib_pd;
-               my_qp->ib_srq.device = my_pd->ib_pd.device;
-
-               my_qp->ib_srq.srq_context = init_attr->qp_context;
-               my_qp->ib_srq.event_handler = init_attr->event_handler;
-       } else {
-               my_qp->ib_qp.qp_num = ib_qp_num;
-               my_qp->ib_qp.pd = &my_pd->ib_pd;
-               my_qp->ib_qp.device = my_pd->ib_pd.device;
-
-               my_qp->ib_qp.recv_cq = init_attr->recv_cq;
-               my_qp->ib_qp.send_cq = init_attr->send_cq;
-
-               my_qp->ib_qp.qp_type = qp_type;
-               my_qp->ib_qp.srq = init_attr->srq;
-
-               my_qp->ib_qp.qp_context = init_attr->qp_context;
-               my_qp->ib_qp.event_handler = init_attr->event_handler;
-       }
-
-       init_attr->cap.max_inline_data = 0; /* not supported yet */
-       init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
-       init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
-       init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
-       init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
-       my_qp->init_attr = *init_attr;
-
-       if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
-               shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
-                       &my_qp->ib_qp;
-               if (ehca_nr_ports < 0) {
-                       /* alloc array to cache subsequent modify qp parms
-                        * for autodetect mode
-                        */
-                       my_qp->mod_qp_parm =
-                               kzalloc(EHCA_MOD_QP_PARM_MAX *
-                                       sizeof(*my_qp->mod_qp_parm),
-                                       GFP_KERNEL);
-                       if (!my_qp->mod_qp_parm) {
-                               ehca_err(pd->device,
-                                        "Could not alloc mod_qp_parm");
-                               goto create_qp_exit5;
-                       }
-               }
-       }
-
-       /* NOTE: define_apq0() not supported yet */
-       if (qp_type == IB_QPT_GSI) {
-               h_ret = ehca_define_sqp(shca, my_qp, init_attr);
-               if (h_ret != H_SUCCESS) {
-                       kfree(my_qp->mod_qp_parm);
-                       my_qp->mod_qp_parm = NULL;
-                       /* the QP pointer is no longer valid */
-                       shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
-                               NULL;
-                       ret = ehca2ib_return_code(h_ret);
-                       goto create_qp_exit6;
-               }
-       }
-
-       if (my_qp->send_cq) {
-               ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
-               if (ret) {
-                       ehca_err(pd->device,
-                                "Couldn't assign qp to send_cq ret=%i", ret);
-                       goto create_qp_exit7;
-               }
-       }
-
-       /* copy queues, galpa data to user space */
-       if (context && udata) {
-               struct ehca_create_qp_resp resp;
-               memset(&resp, 0, sizeof(resp));
-
-               resp.qp_num = my_qp->real_qp_num;
-               resp.token = my_qp->token;
-               resp.qp_type = my_qp->qp_type;
-               resp.ext_type = my_qp->ext_type;
-               resp.qkey = my_qp->qkey;
-               resp.real_qp_num = my_qp->real_qp_num;
-
-               if (HAS_SQ(my_qp))
-                       queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
-               if (HAS_RQ(my_qp))
-                       queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue);
-               resp.fw_handle_ofs = (u32)
-                       (my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1));
-
-               if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
-                       ehca_err(pd->device, "Copy to udata failed");
-                       ret = -EINVAL;
-                       goto create_qp_exit8;
-               }
-       }
-
-       return my_qp;
-
-create_qp_exit8:
-       ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
-
-create_qp_exit7:
-       kfree(my_qp->mod_qp_parm);
-
-create_qp_exit6:
-       if (HAS_RQ(my_qp) && !is_user)
-               vfree(my_qp->rq_map.map);
-
-create_qp_exit5:
-       if (HAS_RQ(my_qp))
-               ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
-
-create_qp_exit4:
-       if (HAS_SQ(my_qp) && !is_user)
-               vfree(my_qp->sq_map.map);
-
-create_qp_exit3:
-       if (HAS_SQ(my_qp))
-               ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
-
-create_qp_exit2:
-       hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
-
-create_qp_exit1:
-       write_lock_irqsave(&ehca_qp_idr_lock, flags);
-       idr_remove(&ehca_qp_idr, my_qp->token);
-       write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
-create_qp_exit0:
-       kmem_cache_free(qp_cache, my_qp);
-       atomic_dec(&shca->num_qps);
-       return ERR_PTR(ret);
-}
-
-struct ib_qp *ehca_create_qp(struct ib_pd *pd,
-                            struct ib_qp_init_attr *qp_init_attr,
-                            struct ib_udata *udata)
-{
-       struct ehca_qp *ret;
-
-       ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
-       return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
-}
-
-static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
-                              struct ib_uobject *uobject);
-
-struct ib_srq *ehca_create_srq(struct ib_pd *pd,
-                              struct ib_srq_init_attr *srq_init_attr,
-                              struct ib_udata *udata)
-{
-       struct ib_qp_init_attr qp_init_attr;
-       struct ehca_qp *my_qp;
-       struct ib_srq *ret;
-       struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
-                                             ib_device);
-       struct hcp_modify_qp_control_block *mqpcb;
-       u64 hret, update_mask;
-
-       if (srq_init_attr->srq_type != IB_SRQT_BASIC)
-               return ERR_PTR(-ENOSYS);
-
-       /* For common attributes, internal_create_qp() takes its info
-        * out of qp_init_attr, so copy all common attrs there.
-        */
-       memset(&qp_init_attr, 0, sizeof(qp_init_attr));
-       qp_init_attr.event_handler = srq_init_attr->event_handler;
-       qp_init_attr.qp_context = srq_init_attr->srq_context;
-       qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
-       qp_init_attr.qp_type = IB_QPT_RC;
-       qp_init_attr.cap.max_recv_wr = srq_init_attr->attr.max_wr;
-       qp_init_attr.cap.max_recv_sge = srq_init_attr->attr.max_sge;
-
-       my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
-       if (IS_ERR(my_qp))
-               return (struct ib_srq *)my_qp;
-
-       /* copy back return values */
-       srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
-       srq_init_attr->attr.max_sge = 3;
-
-       /* drive SRQ into RTR state */
-       mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!mqpcb) {
-               ehca_err(pd->device, "Could not get zeroed page for mqpcb "
-                        "ehca_qp=%p qp_num=%x ", my_qp, my_qp->real_qp_num);
-               ret = ERR_PTR(-ENOMEM);
-               goto create_srq1;
-       }
-
-       mqpcb->qp_state = EHCA_QPS_INIT;
-       mqpcb->prim_phys_port = 1;
-       update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
-       hret = hipz_h_modify_qp(shca->ipz_hca_handle,
-                               my_qp->ipz_qp_handle,
-                               &my_qp->pf,
-                               update_mask,
-                               mqpcb, my_qp->galpas.kernel);
-       if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not modify SRQ to INIT "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, my_qp->real_qp_num, hret);
-               goto create_srq2;
-       }
-
-       mqpcb->qp_enable = 1;
-       update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
-       hret = hipz_h_modify_qp(shca->ipz_hca_handle,
-                               my_qp->ipz_qp_handle,
-                               &my_qp->pf,
-                               update_mask,
-                               mqpcb, my_qp->galpas.kernel);
-       if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not enable SRQ "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, my_qp->real_qp_num, hret);
-               goto create_srq2;
-       }
-
-       mqpcb->qp_state  = EHCA_QPS_RTR;
-       update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
-       hret = hipz_h_modify_qp(shca->ipz_hca_handle,
-                               my_qp->ipz_qp_handle,
-                               &my_qp->pf,
-                               update_mask,
-                               mqpcb, my_qp->galpas.kernel);
-       if (hret != H_SUCCESS) {
-               ehca_err(pd->device, "Could not modify SRQ to RTR "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, my_qp->real_qp_num, hret);
-               goto create_srq2;
-       }
-
-       ehca_free_fw_ctrlblock(mqpcb);
-
-       return &my_qp->ib_srq;
-
-create_srq2:
-       ret = ERR_PTR(ehca2ib_return_code(hret));
-       ehca_free_fw_ctrlblock(mqpcb);
-
-create_srq1:
-       internal_destroy_qp(pd->device, my_qp, my_qp->ib_srq.uobject);
-
-       return ret;
-}
-
-/*
- * prepare_sqe_rts called by internal_modify_qp() at trans sqe -> rts
- * set purge bit of bad wqe and subsequent wqes to avoid reentering sqe
- * returns total number of bad wqes in bad_wqe_cnt
- */
-static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
-                          int *bad_wqe_cnt)
-{
-       u64 h_ret;
-       struct ipz_queue *squeue;
-       void *bad_send_wqe_p, *bad_send_wqe_v;
-       u64 q_ofs;
-       struct ehca_wqe *wqe;
-       int qp_num = my_qp->ib_qp.qp_num;
-
-       /* get send wqe pointer */
-       h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
-                                          my_qp->ipz_qp_handle, &my_qp->pf,
-                                          &bad_send_wqe_p, NULL, 2);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
-                        " ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, qp_num, h_ret);
-               return ehca2ib_return_code(h_ret);
-       }
-       bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
-       ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
-                qp_num, bad_send_wqe_p);
-       /* convert wqe pointer to vadr */
-       bad_send_wqe_v = __va((u64)bad_send_wqe_p);
-       if (ehca_debug_level >= 2)
-               ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num);
-       squeue = &my_qp->ipz_squeue;
-       if (ipz_queue_abs_to_offset(squeue, (u64)bad_send_wqe_p, &q_ofs)) {
-               ehca_err(&shca->ib_device, "failed to get wqe offset qp_num=%x"
-                        " bad_send_wqe_p=%p", qp_num, bad_send_wqe_p);
-               return -EFAULT;
-       }
-
-       /* loop sets wqe's purge bit */
-       wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
-       *bad_wqe_cnt = 0;
-       while (wqe->optype != 0xff && wqe->wqef != 0xff) {
-               if (ehca_debug_level >= 2)
-                       ehca_dmp(wqe, 32, "qp_num=%x wqe", qp_num);
-               wqe->nr_of_data_seg = 0; /* suppress data access */
-               wqe->wqef = WQEF_PURGE; /* WQE to be purged */
-               q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
-               wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
-               *bad_wqe_cnt = (*bad_wqe_cnt)+1;
-       }
-       /*
-        * bad wqe will be reprocessed and ignored when pol_cq() is called,
-        *  i.e. nr of wqes with flush error status is one less
-        */
-       ehca_dbg(&shca->ib_device, "qp_num=%x flusherr_wqe_cnt=%x",
-                qp_num, (*bad_wqe_cnt)-1);
-       wqe->wqef = 0;
-
-       return 0;
-}
-
-static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue,
-                         struct ehca_queue_map *qmap)
-{
-       void *wqe_v;
-       u64 q_ofs;
-       u32 wqe_idx;
-       unsigned int tail_idx;
-
-       /* convert real to abs address */
-       wqe_p = wqe_p & (~(1UL << 63));
-
-       wqe_v = __va(wqe_p);
-
-       if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) {
-               ehca_gen_err("Invalid offset for calculating left cqes "
-                               "wqe_p=%#llx wqe_v=%p\n", wqe_p, wqe_v);
-               return -EFAULT;
-       }
-
-       tail_idx = next_index(qmap->tail, qmap->entries);
-       wqe_idx = q_ofs / ipz_queue->qe_size;
-
-       /* check all processed wqes, whether a cqe is requested or not */
-       while (tail_idx != wqe_idx) {
-               if (qmap->map[tail_idx].cqe_req)
-                       qmap->left_to_poll++;
-               tail_idx = next_index(tail_idx, qmap->entries);
-       }
-       /* save index in queue, where we have to start flushing */
-       qmap->next_wqe_idx = wqe_idx;
-       return 0;
-}
-
-static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca)
-{
-       u64 h_ret;
-       void *send_wqe_p, *recv_wqe_p;
-       int ret;
-       unsigned long flags;
-       int qp_num = my_qp->ib_qp.qp_num;
-
-       /* this hcall is not supported on base QPs */
-       if (my_qp->ext_type != EQPT_SRQBASE) {
-               /* get send and receive wqe pointer */
-               h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
-                               my_qp->ipz_qp_handle, &my_qp->pf,
-                               &send_wqe_p, &recv_wqe_p, 4);
-               if (h_ret != H_SUCCESS) {
-                       ehca_err(&shca->ib_device, "disable_and_get_wqe() "
-                                "failed ehca_qp=%p qp_num=%x h_ret=%lli",
-                                my_qp, qp_num, h_ret);
-                       return ehca2ib_return_code(h_ret);
-               }
-
-               /*
-                * acquire lock to ensure that nobody is polling the cq which
-                * could mean that the qmap->tail pointer is in an
-                * inconsistent state.
-                */
-               spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
-               ret = calc_left_cqes((u64)send_wqe_p, &my_qp->ipz_squeue,
-                               &my_qp->sq_map);
-               spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
-               if (ret)
-                       return ret;
-
-
-               spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
-               ret = calc_left_cqes((u64)recv_wqe_p, &my_qp->ipz_rqueue,
-                               &my_qp->rq_map);
-               spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
-               if (ret)
-                       return ret;
-       } else {
-               spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
-               my_qp->sq_map.left_to_poll = 0;
-               my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail,
-                                                       my_qp->sq_map.entries);
-               spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
-
-               spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
-               my_qp->rq_map.left_to_poll = 0;
-               my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail,
-                                                       my_qp->rq_map.entries);
-               spin_unlock_irqrestore(&my_qp->recv_cq->spinlock, flags);
-       }
-
-       /* this assures flush cqes being generated only for pending wqes */
-       if ((my_qp->sq_map.left_to_poll == 0) &&
-                               (my_qp->rq_map.left_to_poll == 0)) {
-               spin_lock_irqsave(&my_qp->send_cq->spinlock, flags);
-               ehca_add_to_err_list(my_qp, 1);
-               spin_unlock_irqrestore(&my_qp->send_cq->spinlock, flags);
-
-               if (HAS_RQ(my_qp)) {
-                       spin_lock_irqsave(&my_qp->recv_cq->spinlock, flags);
-                       ehca_add_to_err_list(my_qp, 0);
-                       spin_unlock_irqrestore(&my_qp->recv_cq->spinlock,
-                                       flags);
-               }
-       }
-
-       return 0;
-}
-
-/*
- * internal_modify_qp with circumvention to handle aqp0 properly
- * smi_reset2init indicates if this is an internal reset-to-init-call for
- * smi. This flag must always be zero if called from ehca_modify_qp()!
- * This internal func was intorduced to avoid recursion of ehca_modify_qp()!
- */
-static int internal_modify_qp(struct ib_qp *ibqp,
-                             struct ib_qp_attr *attr,
-                             int attr_mask, int smi_reset2init)
-{
-       enum ib_qp_state qp_cur_state, qp_new_state;
-       int cnt, qp_attr_idx, ret = 0;
-       enum ib_qp_statetrans statetrans;
-       struct hcp_modify_qp_control_block *mqpcb;
-       struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
-       struct ehca_shca *shca =
-               container_of(ibqp->pd->device, struct ehca_shca, ib_device);
-       u64 update_mask;
-       u64 h_ret;
-       int bad_wqe_cnt = 0;
-       int is_user = 0;
-       int squeue_locked = 0;
-       unsigned long flags = 0;
-
-       /* do query_qp to obtain current attr values */
-       mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
-       if (!mqpcb) {
-               ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
-                        "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_qp(shca->ipz_hca_handle,
-                               my_qp->ipz_qp_handle,
-                               &my_qp->pf,
-                               mqpcb, my_qp->galpas.kernel);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(ibqp->device, "hipz_h_query_qp() failed "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, ibqp->qp_num, h_ret);
-               ret = ehca2ib_return_code(h_ret);
-               goto modify_qp_exit1;
-       }
-       if (ibqp->uobject)
-               is_user = 1;
-
-       qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
-
-       if (qp_cur_state == -EINVAL) {  /* invalid qp state */
-               ret = -EINVAL;
-               ehca_err(ibqp->device, "Invalid current ehca_qp_state=%x "
-                        "ehca_qp=%p qp_num=%x",
-                        mqpcb->qp_state, my_qp, ibqp->qp_num);
-               goto modify_qp_exit1;
-       }
-       /*
-        * circumvention to set aqp0 initial state to init
-        * as expected by IB spec
-        */
-       if (smi_reset2init == 0 &&
-           ibqp->qp_type == IB_QPT_SMI &&
-           qp_cur_state == IB_QPS_RESET &&
-           (attr_mask & IB_QP_STATE) &&
-           attr->qp_state == IB_QPS_INIT) { /* RESET -> INIT */
-               struct ib_qp_attr smiqp_attr = {
-                       .qp_state = IB_QPS_INIT,
-                       .port_num = my_qp->init_attr.port_num,
-                       .pkey_index = 0,
-                       .qkey = 0
-               };
-               int smiqp_attr_mask = IB_QP_STATE | IB_QP_PORT |
-                       IB_QP_PKEY_INDEX | IB_QP_QKEY;
-               int smirc = internal_modify_qp(
-                       ibqp, &smiqp_attr, smiqp_attr_mask, 1);
-               if (smirc) {
-                       ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
-                                "ehca_modify_qp() rc=%i", smirc);
-                       ret = H_PARAMETER;
-                       goto modify_qp_exit1;
-               }
-               qp_cur_state = IB_QPS_INIT;
-               ehca_dbg(ibqp->device, "SMI RESET -> INIT succeeded");
-       }
-       /* is transmitted current state  equal to "real" current state */
-       if ((attr_mask & IB_QP_CUR_STATE) &&
-           qp_cur_state != attr->cur_qp_state) {
-               ret = -EINVAL;
-               ehca_err(ibqp->device,
-                        "Invalid IB_QP_CUR_STATE attr->curr_qp_state=%x <>"
-                        " actual cur_qp_state=%x. ehca_qp=%p qp_num=%x",
-                        attr->cur_qp_state, qp_cur_state, my_qp, ibqp->qp_num);
-               goto modify_qp_exit1;
-       }
-
-       ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
-                "new qp_state=%x attribute_mask=%x",
-                my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
-
-       qp_new_state = attr_mask & IB_QP_STATE ? attr->qp_state : qp_cur_state;
-       if (!smi_reset2init &&
-           !ib_modify_qp_is_ok(qp_cur_state, qp_new_state, ibqp->qp_type,
-                               attr_mask, IB_LINK_LAYER_UNSPECIFIED)) {
-               ret = -EINVAL;
-               ehca_err(ibqp->device,
-                        "Invalid qp transition new_state=%x cur_state=%x "
-                        "ehca_qp=%p qp_num=%x attr_mask=%x", qp_new_state,
-                        qp_cur_state, my_qp, ibqp->qp_num, attr_mask);
-               goto modify_qp_exit1;
-       }
-
-       mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
-       if (mqpcb->qp_state)
-               update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
-       else {
-               ret = -EINVAL;
-               ehca_err(ibqp->device, "Invalid new qp state=%x "
-                        "ehca_qp=%p qp_num=%x",
-                        qp_new_state, my_qp, ibqp->qp_num);
-               goto modify_qp_exit1;
-       }
-
-       /* retrieve state transition struct to get req and opt attrs */
-       statetrans = get_modqp_statetrans(qp_cur_state, qp_new_state);
-       if (statetrans < 0) {
-               ret = -EINVAL;
-               ehca_err(ibqp->device, "<INVALID STATE CHANGE> qp_cur_state=%x "
-                        "new_qp_state=%x State_xsition=%x ehca_qp=%p "
-                        "qp_num=%x", qp_cur_state, qp_new_state,
-                        statetrans, my_qp, ibqp->qp_num);
-               goto modify_qp_exit1;
-       }
-
-       qp_attr_idx = ib2ehcaqptype(ibqp->qp_type);
-
-       if (qp_attr_idx < 0) {
-               ret = qp_attr_idx;
-               ehca_err(ibqp->device,
-                        "Invalid QP type=%x ehca_qp=%p qp_num=%x",
-                        ibqp->qp_type, my_qp, ibqp->qp_num);
-               goto modify_qp_exit1;
-       }
-
-       ehca_dbg(ibqp->device,
-                "ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x",
-                my_qp, ibqp->qp_num, statetrans);
-
-       /* eHCA2 rev2 and higher require the SEND_GRH_FLAG to be set
-        * in non-LL UD QPs.
-        */
-       if ((my_qp->qp_type == IB_QPT_UD) &&
-           (my_qp->ext_type != EQPT_LLQP) &&
-           (statetrans == IB_QPST_INIT2RTR) &&
-           (shca->hw_level >= 0x22)) {
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
-               mqpcb->send_grh_flag = 1;
-       }
-
-       /* sqe -> rts: set purge bit of bad wqe before actual trans */
-       if ((my_qp->qp_type == IB_QPT_UD ||
-            my_qp->qp_type == IB_QPT_GSI ||
-            my_qp->qp_type == IB_QPT_SMI) &&
-           statetrans == IB_QPST_SQE2RTS) {
-               /* mark next free wqe if kernel */
-               if (!ibqp->uobject) {
-                       struct ehca_wqe *wqe;
-                       /* lock send queue */
-                       spin_lock_irqsave(&my_qp->spinlock_s, flags);
-                       squeue_locked = 1;
-                       /* mark next free wqe */
-                       wqe = (struct ehca_wqe *)
-                               ipz_qeit_get(&my_qp->ipz_squeue);
-                       wqe->optype = wqe->wqef = 0xff;
-                       ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
-                                ibqp->qp_num, wqe);
-               }
-               ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
-               if (ret) {
-                       ehca_err(ibqp->device, "prepare_sqe_rts() failed "
-                                "ehca_qp=%p qp_num=%x ret=%i",
-                                my_qp, ibqp->qp_num, ret);
-                       goto modify_qp_exit2;
-               }
-       }
-
-       /*
-        * enable RDMA_Atomic_Control if reset->init und reliable con
-        * this is necessary since gen2 does not provide that flag,
-        * but pHyp requires it
-        */
-       if (statetrans == IB_QPST_RESET2INIT &&
-           (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_UC)) {
-               mqpcb->rdma_atomic_ctrl = 3;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RDMA_ATOMIC_CTRL, 1);
-       }
-       /* circ. pHyp requires #RDMA/Atomic Resp Res for UC INIT -> RTR */
-       if (statetrans == IB_QPST_INIT2RTR &&
-           (ibqp->qp_type == IB_QPT_UC) &&
-           !(attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)) {
-               mqpcb->rdma_nr_atomic_resp_res = 1; /* default to 1 */
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
-       }
-
-       if (attr_mask & IB_QP_PKEY_INDEX) {
-               if (attr->pkey_index >= 16) {
-                       ret = -EINVAL;
-                       ehca_err(ibqp->device, "Invalid pkey_index=%x. "
-                                "ehca_qp=%p qp_num=%x max_pkey_index=f",
-                                attr->pkey_index, my_qp, ibqp->qp_num);
-                       goto modify_qp_exit2;
-               }
-               mqpcb->prim_p_key_idx = attr->pkey_index;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
-       }
-       if (attr_mask & IB_QP_PORT) {
-               struct ehca_sport *sport;
-               struct ehca_qp *aqp1;
-               if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
-                       ret = -EINVAL;
-                       ehca_err(ibqp->device, "Invalid port=%x. "
-                                "ehca_qp=%p qp_num=%x num_ports=%x",
-                                attr->port_num, my_qp, ibqp->qp_num,
-                                shca->num_ports);
-                       goto modify_qp_exit2;
-               }
-               sport = &shca->sport[attr->port_num - 1];
-               if (!sport->ibqp_sqp[IB_QPT_GSI]) {
-                       /* should not occur */
-                       ret = -EFAULT;
-                       ehca_err(ibqp->device, "AQP1 was not created for "
-                                "port=%x", attr->port_num);
-                       goto modify_qp_exit2;
-               }
-               aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
-                                   struct ehca_qp, ib_qp);
-               if (ibqp->qp_type != IB_QPT_GSI &&
-                   ibqp->qp_type != IB_QPT_SMI &&
-                   aqp1->mod_qp_parm) {
-                       /*
-                        * firmware will reject this modify_qp() because
-                        * port is not activated/initialized fully
-                        */
-                       ret = -EFAULT;
-                       ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
-                                 "either port is being activated (try again) "
-                                 "or cabling issue", attr->port_num);
-                       goto modify_qp_exit2;
-               }
-               mqpcb->prim_phys_port = attr->port_num;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
-       }
-       if (attr_mask & IB_QP_QKEY) {
-               mqpcb->qkey = attr->qkey;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1);
-       }
-       if (attr_mask & IB_QP_AV) {
-               mqpcb->dlid = attr->ah_attr.dlid;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1);
-               mqpcb->source_path_bits = attr->ah_attr.src_path_bits;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS, 1);
-               mqpcb->service_level = attr->ah_attr.sl;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1);
-
-               if (ehca_calc_ipd(shca, mqpcb->prim_phys_port,
-                                 attr->ah_attr.static_rate,
-                                 &mqpcb->max_static_rate)) {
-                       ret = -EINVAL;
-                       goto modify_qp_exit2;
-               }
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1);
-
-               /*
-                * Always supply the GRH flag, even if it's zero, to give the
-                * hypervisor a clear "yes" or "no" instead of a "perhaps"
-                */
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
-
-               /*
-                * only if GRH is TRUE we might consider SOURCE_GID_IDX
-                * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
-                */
-               if (attr->ah_attr.ah_flags == IB_AH_GRH) {
-                       mqpcb->send_grh_flag = 1;
-
-                       mqpcb->source_gid_idx = attr->ah_attr.grh.sgid_index;
-                       update_mask |=
-                               EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX, 1);
-
-                       for (cnt = 0; cnt < 16; cnt++)
-                               mqpcb->dest_gid.byte[cnt] =
-                                       attr->ah_attr.grh.dgid.raw[cnt];
-
-                       update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_GID, 1);
-                       mqpcb->flow_label = attr->ah_attr.grh.flow_label;
-                       update_mask |= EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL, 1);
-                       mqpcb->hop_limit = attr->ah_attr.grh.hop_limit;
-                       update_mask |= EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT, 1);
-                       mqpcb->traffic_class = attr->ah_attr.grh.traffic_class;
-                       update_mask |=
-                               EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS, 1);
-               }
-       }
-
-       if (attr_mask & IB_QP_PATH_MTU) {
-               /* store ld(MTU) */
-               my_qp->mtu_shift = attr->path_mtu + 7;
-               mqpcb->path_mtu = attr->path_mtu;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
-       }
-       if (attr_mask & IB_QP_TIMEOUT) {
-               mqpcb->timeout = attr->timeout;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT, 1);
-       }
-       if (attr_mask & IB_QP_RETRY_CNT) {
-               mqpcb->retry_count = attr->retry_cnt;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT, 1);
-       }
-       if (attr_mask & IB_QP_RNR_RETRY) {
-               mqpcb->rnr_retry_count = attr->rnr_retry;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT, 1);
-       }
-       if (attr_mask & IB_QP_RQ_PSN) {
-               mqpcb->receive_psn = attr->rq_psn;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RECEIVE_PSN, 1);
-       }
-       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
-               mqpcb->rdma_nr_atomic_resp_res = attr->max_dest_rd_atomic < 3 ?
-                       attr->max_dest_rd_atomic : 2;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
-       }
-       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
-               mqpcb->rdma_atomic_outst_dest_qp = attr->max_rd_atomic < 3 ?
-                       attr->max_rd_atomic : 2;
-               update_mask |=
-                       EHCA_BMASK_SET
-                       (MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1);
-       }
-       if (attr_mask & IB_QP_ALT_PATH) {
-               if (attr->alt_port_num < 1
-                   || attr->alt_port_num > shca->num_ports) {
-                       ret = -EINVAL;
-                       ehca_err(ibqp->device, "Invalid alt_port=%x. "
-                                "ehca_qp=%p qp_num=%x num_ports=%x",
-                                attr->alt_port_num, my_qp, ibqp->qp_num,
-                                shca->num_ports);
-                       goto modify_qp_exit2;
-               }
-               mqpcb->alt_phys_port = attr->alt_port_num;
-
-               if (attr->alt_pkey_index >= 16) {
-                       ret = -EINVAL;
-                       ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. "
-                                "ehca_qp=%p qp_num=%x max_pkey_index=f",
-                                attr->pkey_index, my_qp, ibqp->qp_num);
-                       goto modify_qp_exit2;
-               }
-               mqpcb->alt_p_key_idx = attr->alt_pkey_index;
-
-               mqpcb->timeout_al = attr->alt_timeout;
-               mqpcb->dlid_al = attr->alt_ah_attr.dlid;
-               mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
-               mqpcb->service_level_al = attr->alt_ah_attr.sl;
-
-               if (ehca_calc_ipd(shca, mqpcb->alt_phys_port,
-                                 attr->alt_ah_attr.static_rate,
-                                 &mqpcb->max_static_rate_al)) {
-                       ret = -EINVAL;
-                       goto modify_qp_exit2;
-               }
-
-               /* OpenIB doesn't support alternate retry counts - copy them */
-               mqpcb->retry_count_al = mqpcb->retry_count;
-               mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count;
-
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1);
-
-               /*
-                * Always supply the GRH flag, even if it's zero, to give the
-                * hypervisor a clear "yes" or "no" instead of a "perhaps"
-                */
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
-
-               /*
-                * only if GRH is TRUE we might consider SOURCE_GID_IDX
-                * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
-                */
-               if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
-                       mqpcb->send_grh_flag_al = 1;
-
-                       for (cnt = 0; cnt < 16; cnt++)
-                               mqpcb->dest_gid_al.byte[cnt] =
-                                       attr->alt_ah_attr.grh.dgid.raw[cnt];
-                       mqpcb->source_gid_idx_al =
-                               attr->alt_ah_attr.grh.sgid_index;
-                       mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
-                       mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
-                       mqpcb->traffic_class_al =
-                               attr->alt_ah_attr.grh.traffic_class;
-
-                       update_mask |=
-                               EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1)
-                               | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1)
-                               | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1)
-                               | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) |
-                               EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
-               }
-       }
-
-       if (attr_mask & IB_QP_MIN_RNR_TIMER) {
-               mqpcb->min_rnr_nak_timer_field = attr->min_rnr_timer;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD, 1);
-       }
-
-       if (attr_mask & IB_QP_SQ_PSN) {
-               mqpcb->send_psn = attr->sq_psn;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_PSN, 1);
-       }
-
-       if (attr_mask & IB_QP_DEST_QPN) {
-               mqpcb->dest_qp_nr = attr->dest_qp_num;
-               update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_QP_NR, 1);
-       }
-
-       if (attr_mask & IB_QP_PATH_MIG_STATE) {
-               if (attr->path_mig_state != IB_MIG_REARM
-                   && attr->path_mig_state != IB_MIG_MIGRATED) {
-                       ret = -EINVAL;
-                       ehca_err(ibqp->device, "Invalid mig_state=%x",
-                                attr->path_mig_state);
-                       goto modify_qp_exit2;
-               }
-               mqpcb->path_migration_state = attr->path_mig_state + 1;
-               if (attr->path_mig_state == IB_MIG_REARM)
-                       my_qp->mig_armed = 1;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
-       }
-
-       if (attr_mask & IB_QP_CAP) {
-               mqpcb->max_nr_outst_send_wr = attr->cap.max_send_wr+1;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_SEND_WR, 1);
-               mqpcb->max_nr_outst_recv_wr = attr->cap.max_recv_wr+1;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_RECV_WR, 1);
-               /* no support for max_send/recv_sge yet */
-       }
-
-       if (ehca_debug_level >= 2)
-               ehca_dmp(mqpcb, 4*70, "qp_num=%x", ibqp->qp_num);
-
-       h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
-                                my_qp->ipz_qp_handle,
-                                &my_qp->pf,
-                                update_mask,
-                                mqpcb, my_qp->galpas.kernel);
-
-       if (h_ret != H_SUCCESS) {
-               ret = ehca2ib_return_code(h_ret);
-               ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%lli "
-                        "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
-               goto modify_qp_exit2;
-       }
-
-       if ((my_qp->qp_type == IB_QPT_UD ||
-            my_qp->qp_type == IB_QPT_GSI ||
-            my_qp->qp_type == IB_QPT_SMI) &&
-           statetrans == IB_QPST_SQE2RTS) {
-               /* doorbell to reprocessing wqes */
-               iosync(); /* serialize GAL register access */
-               hipz_update_sqa(my_qp, bad_wqe_cnt-1);
-               ehca_gen_dbg("doorbell for %x wqes", bad_wqe_cnt);
-       }
-
-       if (statetrans == IB_QPST_RESET2INIT ||
-           statetrans == IB_QPST_INIT2INIT) {
-               mqpcb->qp_enable = 1;
-               mqpcb->qp_state = EHCA_QPS_INIT;
-               update_mask = 0;
-               update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
-
-               h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
-                                        my_qp->ipz_qp_handle,
-                                        &my_qp->pf,
-                                        update_mask,
-                                        mqpcb,
-                                        my_qp->galpas.kernel);
-
-               if (h_ret != H_SUCCESS) {
-                       ret = ehca2ib_return_code(h_ret);
-                       ehca_err(ibqp->device, "ENABLE in context of "
-                                "RESET_2_INIT failed! Maybe you didn't get "
-                                "a LID h_ret=%lli ehca_qp=%p qp_num=%x",
-                                h_ret, my_qp, ibqp->qp_num);
-                       goto modify_qp_exit2;
-               }
-       }
-       if ((qp_new_state == IB_QPS_ERR) && (qp_cur_state != IB_QPS_ERR)
-           && !is_user) {
-               ret = check_for_left_cqes(my_qp, shca);
-               if (ret)
-                       goto modify_qp_exit2;
-       }
-
-       if (statetrans == IB_QPST_ANY2RESET) {
-               ipz_qeit_reset(&my_qp->ipz_rqueue);
-               ipz_qeit_reset(&my_qp->ipz_squeue);
-
-               if (qp_cur_state == IB_QPS_ERR && !is_user) {
-                       del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
-
-                       if (HAS_RQ(my_qp))
-                               del_from_err_list(my_qp->recv_cq,
-                                                 &my_qp->rq_err_node);
-               }
-               if (!is_user)
-                       reset_queue_map(&my_qp->sq_map);
-
-               if (HAS_RQ(my_qp) && !is_user)
-                       reset_queue_map(&my_qp->rq_map);
-       }
-
-       if (attr_mask & IB_QP_QKEY)
-               my_qp->qkey = attr->qkey;
-
-modify_qp_exit2:
-       if (squeue_locked) { /* this means: sqe -> rts */
-               spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
-               my_qp->sqerr_purgeflag = 1;
-       }
-
-modify_qp_exit1:
-       ehca_free_fw_ctrlblock(mqpcb);
-
-       return ret;
-}
-
-int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
-                  struct ib_udata *udata)
-{
-       int ret = 0;
-
-       struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
-                                             ib_device);
-       struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
-
-       /* The if-block below caches qp_attr to be modified for GSI and SMI
-        * qps during the initialization by ib_mad. When the respective port
-        * is activated, ie we got an event PORT_ACTIVE, we'll replay the
-        * cached modify calls sequence, see ehca_recover_sqs() below.
-        * Why that is required:
-        * 1) If one port is connected, older code requires that port one
-        *    to be connected and module option nr_ports=1 to be given by
-        *    user, which is very inconvenient for end user.
-        * 2) Firmware accepts modify_qp() only if respective port has become
-        *    active. Older code had a wait loop of 30sec create_qp()/
-        *    define_aqp1(), which is not appropriate in practice. This
-        *    code now removes that wait loop, see define_aqp1(), and always
-        *    reports all ports to ib_mad resp. users. Only activated ports
-        *    will then usable for the users.
-        */
-       if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
-               int port = my_qp->init_attr.port_num;
-               struct ehca_sport *sport = &shca->sport[port - 1];
-               unsigned long flags;
-               spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-               /* cache qp_attr only during init */
-               if (my_qp->mod_qp_parm) {
-                       struct ehca_mod_qp_parm *p;
-                       if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
-                               ehca_err(&shca->ib_device,
-                                        "mod_qp_parm overflow state=%x port=%x"
-                                        " type=%x", attr->qp_state,
-                                        my_qp->init_attr.port_num,
-                                        ibqp->qp_type);
-                               spin_unlock_irqrestore(&sport->mod_sqp_lock,
-                                                      flags);
-                               return -EINVAL;
-                       }
-                       p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
-                       p->mask = attr_mask;
-                       p->attr = *attr;
-                       my_qp->mod_qp_parm_idx++;
-                       ehca_dbg(&shca->ib_device,
-                                "Saved qp_attr for state=%x port=%x type=%x",
-                                attr->qp_state, my_qp->init_attr.port_num,
-                                ibqp->qp_type);
-                       spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-                       goto out;
-               }
-               spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-       }
-
-       ret = internal_modify_qp(ibqp, attr, attr_mask, 0);
-
-out:
-       if ((ret == 0) && (attr_mask & IB_QP_STATE))
-               my_qp->state = attr->qp_state;
-
-       return ret;
-}
-
-void ehca_recover_sqp(struct ib_qp *sqp)
-{
-       struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
-       int port = my_sqp->init_attr.port_num;
-       struct ib_qp_attr attr;
-       struct ehca_mod_qp_parm *qp_parm;
-       int i, qp_parm_idx, ret;
-       unsigned long flags, wr_cnt;
-
-       if (!my_sqp->mod_qp_parm)
-               return;
-       ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
-
-       qp_parm = my_sqp->mod_qp_parm;
-       qp_parm_idx = my_sqp->mod_qp_parm_idx;
-       for (i = 0; i < qp_parm_idx; i++) {
-               attr = qp_parm[i].attr;
-               ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
-               if (ret) {
-                       ehca_err(sqp->device, "Could not modify SQP port=%x "
-                                "qp_num=%x ret=%x", port, sqp->qp_num, ret);
-                       goto free_qp_parm;
-               }
-               ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
-                        port, sqp->qp_num, attr.qp_state);
-       }
-
-       /* re-trigger posted recv wrs */
-       wr_cnt =  my_sqp->ipz_rqueue.current_q_offset /
-               my_sqp->ipz_rqueue.qe_size;
-       if (wr_cnt) {
-               spin_lock_irqsave(&my_sqp->spinlock_r, flags);
-               hipz_update_rqa(my_sqp, wr_cnt);
-               spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
-               ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
-                        port, sqp->qp_num, wr_cnt);
-       }
-
-free_qp_parm:
-       kfree(qp_parm);
-       /* this prevents subsequent calls to modify_qp() to cache qp_attr */
-       my_sqp->mod_qp_parm = NULL;
-}
-
-int ehca_query_qp(struct ib_qp *qp,
-                 struct ib_qp_attr *qp_attr,
-                 int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
-{
-       struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
-       struct ehca_shca *shca = container_of(qp->device, struct ehca_shca,
-                                             ib_device);
-       struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
-       struct hcp_modify_qp_control_block *qpcb;
-       int cnt, ret = 0;
-       u64 h_ret;
-
-       if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
-               ehca_err(qp->device, "Invalid attribute mask "
-                        "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
-                        my_qp, qp->qp_num, qp_attr_mask);
-               return -EINVAL;
-       }
-
-       qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!qpcb) {
-               ehca_err(qp->device, "Out of memory for qpcb "
-                        "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_qp(adapter_handle,
-                               my_qp->ipz_qp_handle,
-                               &my_qp->pf,
-                               qpcb, my_qp->galpas.kernel);
-
-       if (h_ret != H_SUCCESS) {
-               ret = ehca2ib_return_code(h_ret);
-               ehca_err(qp->device, "hipz_h_query_qp() failed "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, qp->qp_num, h_ret);
-               goto query_qp_exit1;
-       }
-
-       qp_attr->cur_qp_state = ehca2ib_qp_state(qpcb->qp_state);
-       qp_attr->qp_state = qp_attr->cur_qp_state;
-
-       if (qp_attr->cur_qp_state == -EINVAL) {
-               ret = -EINVAL;
-               ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
-                        "ehca_qp=%p qp_num=%x",
-                        qpcb->qp_state, my_qp, qp->qp_num);
-               goto query_qp_exit1;
-       }
-
-       if (qp_attr->qp_state == IB_QPS_SQD)
-               qp_attr->sq_draining = 1;
-
-       qp_attr->qkey = qpcb->qkey;
-       qp_attr->path_mtu = qpcb->path_mtu;
-       qp_attr->path_mig_state = qpcb->path_migration_state - 1;
-       qp_attr->rq_psn = qpcb->receive_psn;
-       qp_attr->sq_psn = qpcb->send_psn;
-       qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
-       qp_attr->cap.max_send_wr = qpcb->max_nr_outst_send_wr-1;
-       qp_attr->cap.max_recv_wr = qpcb->max_nr_outst_recv_wr-1;
-       /* UD_AV CIRCUMVENTION */
-       if (my_qp->qp_type == IB_QPT_UD) {
-               qp_attr->cap.max_send_sge =
-                       qpcb->actual_nr_sges_in_sq_wqe - 2;
-               qp_attr->cap.max_recv_sge =
-                       qpcb->actual_nr_sges_in_rq_wqe - 2;
-       } else {
-               qp_attr->cap.max_send_sge =
-                       qpcb->actual_nr_sges_in_sq_wqe;
-               qp_attr->cap.max_recv_sge =
-                       qpcb->actual_nr_sges_in_rq_wqe;
-       }
-
-       qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size;
-       qp_attr->dest_qp_num = qpcb->dest_qp_nr;
-
-       qp_attr->pkey_index = qpcb->prim_p_key_idx;
-       qp_attr->port_num = qpcb->prim_phys_port;
-       qp_attr->timeout = qpcb->timeout;
-       qp_attr->retry_cnt = qpcb->retry_count;
-       qp_attr->rnr_retry = qpcb->rnr_retry_count;
-
-       qp_attr->alt_pkey_index = qpcb->alt_p_key_idx;
-       qp_attr->alt_port_num = qpcb->alt_phys_port;
-       qp_attr->alt_timeout = qpcb->timeout_al;
-
-       qp_attr->max_dest_rd_atomic = qpcb->rdma_nr_atomic_resp_res;
-       qp_attr->max_rd_atomic = qpcb->rdma_atomic_outst_dest_qp;
-
-       /* primary av */
-       qp_attr->ah_attr.sl = qpcb->service_level;
-
-       if (qpcb->send_grh_flag) {
-               qp_attr->ah_attr.ah_flags = IB_AH_GRH;
-       }
-
-       qp_attr->ah_attr.static_rate = qpcb->max_static_rate;
-       qp_attr->ah_attr.dlid = qpcb->dlid;
-       qp_attr->ah_attr.src_path_bits = qpcb->source_path_bits;
-       qp_attr->ah_attr.port_num = qp_attr->port_num;
-
-       /* primary GRH */
-       qp_attr->ah_attr.grh.traffic_class = qpcb->traffic_class;
-       qp_attr->ah_attr.grh.hop_limit = qpcb->hop_limit;
-       qp_attr->ah_attr.grh.sgid_index = qpcb->source_gid_idx;
-       qp_attr->ah_attr.grh.flow_label = qpcb->flow_label;
-
-       for (cnt = 0; cnt < 16; cnt++)
-               qp_attr->ah_attr.grh.dgid.raw[cnt] =
-                       qpcb->dest_gid.byte[cnt];
-
-       /* alternate AV */
-       qp_attr->alt_ah_attr.sl = qpcb->service_level_al;
-       if (qpcb->send_grh_flag_al) {
-               qp_attr->alt_ah_attr.ah_flags = IB_AH_GRH;
-       }
-
-       qp_attr->alt_ah_attr.static_rate = qpcb->max_static_rate_al;
-       qp_attr->alt_ah_attr.dlid = qpcb->dlid_al;
-       qp_attr->alt_ah_attr.src_path_bits = qpcb->source_path_bits_al;
-
-       /* alternate GRH */
-       qp_attr->alt_ah_attr.grh.traffic_class = qpcb->traffic_class_al;
-       qp_attr->alt_ah_attr.grh.hop_limit = qpcb->hop_limit_al;
-       qp_attr->alt_ah_attr.grh.sgid_index = qpcb->source_gid_idx_al;
-       qp_attr->alt_ah_attr.grh.flow_label = qpcb->flow_label_al;
-
-       for (cnt = 0; cnt < 16; cnt++)
-               qp_attr->alt_ah_attr.grh.dgid.raw[cnt] =
-                       qpcb->dest_gid_al.byte[cnt];
-
-       /* return init attributes given in ehca_create_qp */
-       if (qp_init_attr)
-               *qp_init_attr = my_qp->init_attr;
-
-       if (ehca_debug_level >= 2)
-               ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num);
-
-query_qp_exit1:
-       ehca_free_fw_ctrlblock(qpcb);
-
-       return ret;
-}
-
-int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
-                   enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
-{
-       struct ehca_qp *my_qp =
-               container_of(ibsrq, struct ehca_qp, ib_srq);
-       struct ehca_shca *shca =
-               container_of(ibsrq->pd->device, struct ehca_shca, ib_device);
-       struct hcp_modify_qp_control_block *mqpcb;
-       u64 update_mask;
-       u64 h_ret;
-       int ret = 0;
-
-       mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!mqpcb) {
-               ehca_err(ibsrq->device, "Could not get zeroed page for mqpcb "
-                        "ehca_qp=%p qp_num=%x ", my_qp, my_qp->real_qp_num);
-               return -ENOMEM;
-       }
-
-       update_mask = 0;
-       if (attr_mask & IB_SRQ_LIMIT) {
-               attr_mask &= ~IB_SRQ_LIMIT;
-               update_mask |=
-                       EHCA_BMASK_SET(MQPCB_MASK_CURR_SRQ_LIMIT, 1)
-                       | EHCA_BMASK_SET(MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG, 1);
-               mqpcb->curr_srq_limit = attr->srq_limit;
-               mqpcb->qp_aff_asyn_ev_log_reg =
-                       EHCA_BMASK_SET(QPX_AAELOG_RESET_SRQ_LIMIT, 1);
-       }
-
-       /* by now, all bits in attr_mask should have been cleared */
-       if (attr_mask) {
-               ehca_err(ibsrq->device, "invalid attribute mask bits set  "
-                        "attr_mask=%x", attr_mask);
-               ret = -EINVAL;
-               goto modify_srq_exit0;
-       }
-
-       if (ehca_debug_level >= 2)
-               ehca_dmp(mqpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
-
-       h_ret = hipz_h_modify_qp(shca->ipz_hca_handle, my_qp->ipz_qp_handle,
-                                NULL, update_mask, mqpcb,
-                                my_qp->galpas.kernel);
-
-       if (h_ret != H_SUCCESS) {
-               ret = ehca2ib_return_code(h_ret);
-               ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%lli "
-                        "ehca_qp=%p qp_num=%x",
-                        h_ret, my_qp, my_qp->real_qp_num);
-       }
-
-modify_srq_exit0:
-       ehca_free_fw_ctrlblock(mqpcb);
-
-       return ret;
-}
-
-int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
-{
-       struct ehca_qp *my_qp = container_of(srq, struct ehca_qp, ib_srq);
-       struct ehca_shca *shca = container_of(srq->device, struct ehca_shca,
-                                             ib_device);
-       struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
-       struct hcp_modify_qp_control_block *qpcb;
-       int ret = 0;
-       u64 h_ret;
-
-       qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
-       if (!qpcb) {
-               ehca_err(srq->device, "Out of memory for qpcb "
-                        "ehca_qp=%p qp_num=%x", my_qp, my_qp->real_qp_num);
-               return -ENOMEM;
-       }
-
-       h_ret = hipz_h_query_qp(adapter_handle, my_qp->ipz_qp_handle,
-                               NULL, qpcb, my_qp->galpas.kernel);
-
-       if (h_ret != H_SUCCESS) {
-               ret = ehca2ib_return_code(h_ret);
-               ehca_err(srq->device, "hipz_h_query_qp() failed "
-                        "ehca_qp=%p qp_num=%x h_ret=%lli",
-                        my_qp, my_qp->real_qp_num, h_ret);
-               goto query_srq_exit1;
-       }
-
-       srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
-       srq_attr->max_sge = 3;
-       srq_attr->srq_limit = qpcb->curr_srq_limit;
-
-       if (ehca_debug_level >= 2)
-               ehca_dmp(qpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
-
-query_srq_exit1:
-       ehca_free_fw_ctrlblock(qpcb);
-
-       return ret;
-}
-
-static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
-                              struct ib_uobject *uobject)
-{
-       struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
-       struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
-                                            ib_pd);
-       struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
-       u32 qp_num = my_qp->real_qp_num;
-       int ret;
-       u64 h_ret;
-       u8 port_num;
-       int is_user = 0;
-       enum ib_qp_type qp_type;
-       unsigned long flags;
-
-       if (uobject) {
-               is_user = 1;
-               if (my_qp->mm_count_galpa ||
-                   my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
-                       ehca_err(dev, "Resources still referenced in "
-                                "user space qp_num=%x", qp_num);
-                       return -EINVAL;
-               }
-       }
-
-       if (my_qp->send_cq) {
-               ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num);
-               if (ret) {
-                       ehca_err(dev, "Couldn't unassign qp from "
-                                "send_cq ret=%i qp_num=%x cq_num=%x", ret,
-                                qp_num, my_qp->send_cq->cq_number);
-                       return ret;
-               }
-       }
-
-       write_lock_irqsave(&ehca_qp_idr_lock, flags);
-       idr_remove(&ehca_qp_idr, my_qp->token);
-       write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
-       /*
-        * SRQs will never get into an error list and do not have a recv_cq,
-        * so we need to skip them here.
-        */
-       if (HAS_RQ(my_qp) && !IS_SRQ(my_qp) && !is_user)
-               del_from_err_list(my_qp->recv_cq, &my_qp->rq_err_node);
-
-       if (HAS_SQ(my_qp) && !is_user)
-               del_from_err_list(my_qp->send_cq, &my_qp->sq_err_node);
-
-       /* now wait until all pending events have completed */
-       wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
-
-       h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
-       if (h_ret != H_SUCCESS) {
-               ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%lli "
-                        "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
-               return ehca2ib_return_code(h_ret);
-       }
-
-       port_num = my_qp->init_attr.port_num;
-       qp_type  = my_qp->init_attr.qp_type;
-
-       if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
-               spin_lock_irqsave(&sport->mod_sqp_lock, flags);
-               kfree(my_qp->mod_qp_parm);
-               my_qp->mod_qp_parm = NULL;
-               shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
-               spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
-       }
-
-       /* no support for IB_QPT_SMI yet */
-       if (qp_type == IB_QPT_GSI) {
-               struct ib_event event;
-               ehca_info(dev, "device %s: port %x is inactive.",
-                               shca->ib_device.name, port_num);
-               event.device = &shca->ib_device;
-               event.event = IB_EVENT_PORT_ERR;
-               event.element.port_num = port_num;
-               shca->sport[port_num - 1].port_state = IB_PORT_DOWN;
-               ib_dispatch_event(&event);
-       }
-
-       if (HAS_RQ(my_qp)) {
-               ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
-               if (!is_user)
-                       vfree(my_qp->rq_map.map);
-       }
-       if (HAS_SQ(my_qp)) {
-               ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
-               if (!is_user)
-                       vfree(my_qp->sq_map.map);
-       }
-       kmem_cache_free(qp_cache, my_qp);
-       atomic_dec(&shca->num_qps);
-       return 0;
-}
-
-int ehca_destroy_qp(struct ib_qp *qp)
-{
-       return internal_destroy_qp(qp->device,
-                                  container_of(qp, struct ehca_qp, ib_qp),
-                                  qp->uobject);
-}
-
-int ehca_destroy_srq(struct ib_srq *srq)
-{
-       return internal_destroy_qp(srq->device,
-                                  container_of(srq, struct ehca_qp, ib_srq),
-                                  srq->uobject);
-}
-
-int ehca_init_qp_cache(void)
-{
-       qp_cache = kmem_cache_create("ehca_cache_qp",
-                                    sizeof(struct ehca_qp), 0,
-                                    SLAB_HWCACHE_ALIGN,
-                                    NULL);
-       if (!qp_cache)
-               return -ENOMEM;
-       return 0;
-}
-
-void ehca_cleanup_qp_cache(void)
-{
-       kmem_cache_destroy(qp_cache);
-}
diff --git a/drivers/staging/rdma/ehca/ehca_reqs.c b/drivers/staging/rdma/ehca/ehca_reqs.c
deleted file mode 100644 (file)
index 11813b8..0000000
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  post_send/recv, poll_cq, req_notify
- *
- *  Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *           Joachim Fenkes <fenkes@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-#include "ehca_classes.h"
-#include "ehca_tools.h"
-#include "ehca_qes.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-#include "hipz_fns.h"
-
-/* in RC traffic, insert an empty RDMA READ every this many packets */
-#define ACK_CIRC_THRESHOLD 2000000
-
-static u64 replace_wr_id(u64 wr_id, u16 idx)
-{
-       u64 ret;
-
-       ret = wr_id & ~QMAP_IDX_MASK;
-       ret |= idx & QMAP_IDX_MASK;
-
-       return ret;
-}
-
-static u16 get_app_wr_id(u64 wr_id)
-{
-       return wr_id & QMAP_IDX_MASK;
-}
-
-static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
-                                 struct ehca_wqe *wqe_p,
-                                 struct ib_recv_wr *recv_wr,
-                                 u32 rq_map_idx)
-{
-       u8 cnt_ds;
-       if (unlikely((recv_wr->num_sge < 0) ||
-                    (recv_wr->num_sge > ipz_rqueue->act_nr_of_sg))) {
-               ehca_gen_err("Invalid number of WQE SGE. "
-                        "num_sqe=%x max_nr_of_sg=%x",
-                        recv_wr->num_sge, ipz_rqueue->act_nr_of_sg);
-               return -EINVAL; /* invalid SG list length */
-       }
-
-       /* clear wqe header until sglist */
-       memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
-
-       wqe_p->work_request_id = replace_wr_id(recv_wr->wr_id, rq_map_idx);
-       wqe_p->nr_of_data_seg = recv_wr->num_sge;
-
-       for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
-               wqe_p->u.all_rcv.sg_list[cnt_ds].vaddr =
-                       recv_wr->sg_list[cnt_ds].addr;
-               wqe_p->u.all_rcv.sg_list[cnt_ds].lkey =
-                       recv_wr->sg_list[cnt_ds].lkey;
-               wqe_p->u.all_rcv.sg_list[cnt_ds].length =
-                       recv_wr->sg_list[cnt_ds].length;
-       }
-
-       if (ehca_debug_level >= 3) {
-               ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
-                            ipz_rqueue);
-               ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
-       }
-
-       return 0;
-}
-
-#if defined(DEBUG_GSI_SEND_WR)
-
-/* need ib_mad struct */
-#include <rdma/ib_mad.h>
-
-static void trace_ud_wr(const struct ib_ud_wr *ud_wr)
-{
-       int idx;
-       int j;
-       while (ud_wr) {
-               struct ib_mad_hdr *mad_hdr = ud_wrmad_hdr;
-               struct ib_sge *sge = ud_wr->wr.sg_list;
-               ehca_gen_dbg("ud_wr#%x wr_id=%lx num_sge=%x "
-                            "send_flags=%x opcode=%x", idx, ud_wr->wr.wr_id,
-                            ud_wr->wr.num_sge, ud_wr->wr.send_flags,
-                            ud_wr->.wr.opcode);
-               if (mad_hdr) {
-                       ehca_gen_dbg("ud_wr#%x mad_hdr base_version=%x "
-                                    "mgmt_class=%x class_version=%x method=%x "
-                                    "status=%x class_specific=%x tid=%lx "
-                                    "attr_id=%x resv=%x attr_mod=%x",
-                                    idx, mad_hdr->base_version,
-                                    mad_hdr->mgmt_class,
-                                    mad_hdr->class_version, mad_hdr->method,
-                                    mad_hdr->status, mad_hdr->class_specific,
-                                    mad_hdr->tid, mad_hdr->attr_id,
-                                    mad_hdr->resv,
-                                    mad_hdr->attr_mod);
-               }
-               for (j = 0; j < ud_wr->wr.num_sge; j++) {
-                       u8 *data = __va(sge->addr);
-                       ehca_gen_dbg("ud_wr#%x sge#%x addr=%p length=%x "
-                                    "lkey=%x",
-                                    idx, j, data, sge->length, sge->lkey);
-                       /* assume length is n*16 */
-                       ehca_dmp(data, sge->length, "ud_wr#%x sge#%x",
-                                idx, j);
-                       sge++;
-               } /* eof for j */
-               idx++;
-               ud_wr = ud_wr(ud_wr->wr.next);
-       } /* eof while ud_wr */
-}
-
-#endif /* DEBUG_GSI_SEND_WR */
-
-static inline int ehca_write_swqe(struct ehca_qp *qp,
-                                 struct ehca_wqe *wqe_p,
-                                 struct ib_send_wr *send_wr,
-                                 u32 sq_map_idx,
-                                 int hidden)
-{
-       u32 idx;
-       u64 dma_length;
-       struct ehca_av *my_av;
-       u32 remote_qkey;
-       struct ehca_qmap_entry *qmap_entry = &qp->sq_map.map[sq_map_idx];
-
-       if (unlikely((send_wr->num_sge < 0) ||
-                    (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
-               ehca_gen_err("Invalid number of WQE SGE. "
-                        "num_sqe=%x max_nr_of_sg=%x",
-                        send_wr->num_sge, qp->ipz_squeue.act_nr_of_sg);
-               return -EINVAL; /* invalid SG list length */
-       }
-
-       /* clear wqe header until sglist */
-       memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
-
-       wqe_p->work_request_id = replace_wr_id(send_wr->wr_id, sq_map_idx);
-
-       qmap_entry->app_wr_id = get_app_wr_id(send_wr->wr_id);
-       qmap_entry->reported = 0;
-       qmap_entry->cqe_req = 0;
-
-       switch (send_wr->opcode) {
-       case IB_WR_SEND:
-       case IB_WR_SEND_WITH_IMM:
-               wqe_p->optype = WQE_OPTYPE_SEND;
-               break;
-       case IB_WR_RDMA_WRITE:
-       case IB_WR_RDMA_WRITE_WITH_IMM:
-               wqe_p->optype = WQE_OPTYPE_RDMAWRITE;
-               break;
-       case IB_WR_RDMA_READ:
-               wqe_p->optype = WQE_OPTYPE_RDMAREAD;
-               break;
-       default:
-               ehca_gen_err("Invalid opcode=%x", send_wr->opcode);
-               return -EINVAL; /* invalid opcode */
-       }
-
-       wqe_p->wqef = (send_wr->opcode) & WQEF_HIGH_NIBBLE;
-
-       wqe_p->wr_flag = 0;
-
-       if ((send_wr->send_flags & IB_SEND_SIGNALED ||
-           qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
-           && !hidden) {
-               wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
-               qmap_entry->cqe_req = 1;
-       }
-
-       if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
-           send_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
-               /* this might not work as long as HW does not support it */
-               wqe_p->immediate_data = be32_to_cpu(send_wr->ex.imm_data);
-               wqe_p->wr_flag |= WQE_WRFLAG_IMM_DATA_PRESENT;
-       }
-
-       wqe_p->nr_of_data_seg = send_wr->num_sge;
-
-       switch (qp->qp_type) {
-       case IB_QPT_SMI:
-       case IB_QPT_GSI:
-               /* no break is intential here */
-       case IB_QPT_UD:
-               /* IB 1.2 spec C10-15 compliance */
-               remote_qkey = ud_wr(send_wr)->remote_qkey;
-               if (remote_qkey & 0x80000000)
-                       remote_qkey = qp->qkey;
-
-               wqe_p->destination_qp_number = ud_wr(send_wr)->remote_qpn << 8;
-               wqe_p->local_ee_context_qkey = remote_qkey;
-               if (unlikely(!ud_wr(send_wr)->ah)) {
-                       ehca_gen_err("ud_wr(send_wr) is NULL. qp=%p", qp);
-                       return -EINVAL;
-               }
-               if (unlikely(ud_wr(send_wr)->remote_qpn == 0)) {
-                       ehca_gen_err("dest QP# is 0. qp=%x", qp->real_qp_num);
-                       return -EINVAL;
-               }
-               my_av = container_of(ud_wr(send_wr)->ah, struct ehca_av, ib_ah);
-               wqe_p->u.ud_av.ud_av = my_av->av;
-
-               /*
-                * omitted check of IB_SEND_INLINE
-                * since HW does not support it
-                */
-               for (idx = 0; idx < send_wr->num_sge; idx++) {
-                       wqe_p->u.ud_av.sg_list[idx].vaddr =
-                               send_wr->sg_list[idx].addr;
-                       wqe_p->u.ud_av.sg_list[idx].lkey =
-                               send_wr->sg_list[idx].lkey;
-                       wqe_p->u.ud_av.sg_list[idx].length =
-                               send_wr->sg_list[idx].length;
-               } /* eof for idx */
-               if (qp->qp_type == IB_QPT_SMI ||
-                   qp->qp_type == IB_QPT_GSI)
-                       wqe_p->u.ud_av.ud_av.pmtu = 1;
-               if (qp->qp_type == IB_QPT_GSI) {
-                       wqe_p->pkeyi = ud_wr(send_wr)->pkey_index;
-#ifdef DEBUG_GSI_SEND_WR
-                       trace_ud_wr(ud_wr(send_wr));
-#endif /* DEBUG_GSI_SEND_WR */
-               }
-               break;
-
-       case IB_QPT_UC:
-               if (send_wr->send_flags & IB_SEND_FENCE)
-                       wqe_p->wr_flag |= WQE_WRFLAG_FENCE;
-               /* no break is intentional here */
-       case IB_QPT_RC:
-               /* TODO: atomic not implemented */
-               wqe_p->u.nud.remote_virtual_address =
-                       rdma_wr(send_wr)->remote_addr;
-               wqe_p->u.nud.rkey = rdma_wr(send_wr)->rkey;
-
-               /*
-                * omitted checking of IB_SEND_INLINE
-                * since HW does not support it
-                */
-               dma_length = 0;
-               for (idx = 0; idx < send_wr->num_sge; idx++) {
-                       wqe_p->u.nud.sg_list[idx].vaddr =
-                               send_wr->sg_list[idx].addr;
-                       wqe_p->u.nud.sg_list[idx].lkey =
-                               send_wr->sg_list[idx].lkey;
-                       wqe_p->u.nud.sg_list[idx].length =
-                               send_wr->sg_list[idx].length;
-                       dma_length += send_wr->sg_list[idx].length;
-               } /* eof idx */
-               wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
-
-               /* unsolicited ack circumvention */
-               if (send_wr->opcode == IB_WR_RDMA_READ) {
-                       /* on RDMA read, switch on and reset counters */
-                       qp->message_count = qp->packet_count = 0;
-                       qp->unsol_ack_circ = 1;
-               } else
-                       /* else estimate #packets */
-                       qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
-
-               break;
-
-       default:
-               ehca_gen_err("Invalid qptype=%x", qp->qp_type);
-               return -EINVAL;
-       }
-
-       if (ehca_debug_level >= 3) {
-               ehca_gen_dbg("SEND WQE written into queue qp=%p ", qp);
-               ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe");
-       }
-       return 0;
-}
-
-/* map_ib_wc_status converts raw cqe_status to ib_wc_status */
-static inline void map_ib_wc_status(u32 cqe_status,
-                                   enum ib_wc_status *wc_status)
-{
-       if (unlikely(cqe_status & WC_STATUS_ERROR_BIT)) {
-               switch (cqe_status & 0x3F) {
-               case 0x01:
-               case 0x21:
-                       *wc_status = IB_WC_LOC_LEN_ERR;
-                       break;
-               case 0x02:
-               case 0x22:
-                       *wc_status = IB_WC_LOC_QP_OP_ERR;
-                       break;
-               case 0x03:
-               case 0x23:
-                       *wc_status = IB_WC_LOC_EEC_OP_ERR;
-                       break;
-               case 0x04:
-               case 0x24:
-                       *wc_status = IB_WC_LOC_PROT_ERR;
-                       break;
-               case 0x05:
-               case 0x25:
-                       *wc_status = IB_WC_WR_FLUSH_ERR;
-                       break;
-               case 0x06:
-                       *wc_status = IB_WC_MW_BIND_ERR;
-                       break;
-               case 0x07: /* remote error - look into bits 20:24 */
-                       switch ((cqe_status
-                                & WC_STATUS_REMOTE_ERROR_FLAGS) >> 11) {
-                       case 0x0:
-                               /*
-                                * PSN Sequence Error!
-                                * couldn't find a matching status!
-                                */
-                               *wc_status = IB_WC_GENERAL_ERR;
-                               break;
-                       case 0x1:
-                               *wc_status = IB_WC_REM_INV_REQ_ERR;
-                               break;
-                       case 0x2:
-                               *wc_status = IB_WC_REM_ACCESS_ERR;
-                               break;
-                       case 0x3:
-                               *wc_status = IB_WC_REM_OP_ERR;
-                               break;
-                       case 0x4:
-                               *wc_status = IB_WC_REM_INV_RD_REQ_ERR;
-                               break;
-                       }
-                       break;
-               case 0x08:
-                       *wc_status = IB_WC_RETRY_EXC_ERR;
-                       break;
-               case 0x09:
-                       *wc_status = IB_WC_RNR_RETRY_EXC_ERR;
-                       break;
-               case 0x0A:
-               case 0x2D:
-                       *wc_status = IB_WC_REM_ABORT_ERR;
-                       break;
-               case 0x0B:
-               case 0x2E:
-                       *wc_status = IB_WC_INV_EECN_ERR;
-                       break;
-               case 0x0C:
-               case 0x2F:
-                       *wc_status = IB_WC_INV_EEC_STATE_ERR;
-                       break;
-               case 0x0D:
-                       *wc_status = IB_WC_BAD_RESP_ERR;
-                       break;
-               case 0x10:
-                       /* WQE purged */
-                       *wc_status = IB_WC_WR_FLUSH_ERR;
-                       break;
-               default:
-                       *wc_status = IB_WC_FATAL_ERR;
-
-               }
-       } else
-               *wc_status = IB_WC_SUCCESS;
-}
-
-static inline int post_one_send(struct ehca_qp *my_qp,
-                        struct ib_send_wr *cur_send_wr,
-                        int hidden)
-{
-       struct ehca_wqe *wqe_p;
-       int ret;
-       u32 sq_map_idx;
-       u64 start_offset = my_qp->ipz_squeue.current_q_offset;
-
-       /* get pointer next to free WQE */
-       wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
-       if (unlikely(!wqe_p)) {
-               /* too many posted work requests: queue overflow */
-               ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
-                        "qp_num=%x", my_qp->ib_qp.qp_num);
-               return -ENOMEM;
-       }
-
-       /*
-        * Get the index of the WQE in the send queue. The same index is used
-        * for writing into the sq_map.
-        */
-       sq_map_idx = start_offset / my_qp->ipz_squeue.qe_size;
-
-       /* write a SEND WQE into the QUEUE */
-       ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, sq_map_idx, hidden);
-       /*
-        * if something failed,
-        * reset the free entry pointer to the start value
-        */
-       if (unlikely(ret)) {
-               my_qp->ipz_squeue.current_q_offset = start_offset;
-               ehca_err(my_qp->ib_qp.device, "Could not write WQE "
-                        "qp_num=%x", my_qp->ib_qp.qp_num);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int ehca_post_send(struct ib_qp *qp,
-                  struct ib_send_wr *send_wr,
-                  struct ib_send_wr **bad_send_wr)
-{
-       struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
-       int wqe_cnt = 0;
-       int ret = 0;
-       unsigned long flags;
-
-       /* Reject WR if QP is in RESET, INIT or RTR state */
-       if (unlikely(my_qp->state < IB_QPS_RTS)) {
-               ehca_err(qp->device, "Invalid QP state  qp_state=%d qpn=%x",
-                        my_qp->state, qp->qp_num);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /* LOCK the QUEUE */
-       spin_lock_irqsave(&my_qp->spinlock_s, flags);
-
-       /* Send an empty extra RDMA read if:
-        *  1) there has been an RDMA read on this connection before
-        *  2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
-        *  3) we can be sure that any previous extra RDMA read has been
-        *     processed so we don't overflow the SQ
-        */
-       if (unlikely(my_qp->unsol_ack_circ &&
-                    my_qp->packet_count > ACK_CIRC_THRESHOLD &&
-                    my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
-               /* insert an empty RDMA READ to fix up the remote QP state */
-               struct ib_send_wr circ_wr;
-               memset(&circ_wr, 0, sizeof(circ_wr));
-               circ_wr.opcode = IB_WR_RDMA_READ;
-               post_one_send(my_qp, &circ_wr, 1); /* ignore retcode */
-               wqe_cnt++;
-               ehca_dbg(qp->device, "posted circ wr  qp_num=%x", qp->qp_num);
-               my_qp->message_count = my_qp->packet_count = 0;
-       }
-
-       /* loop processes list of send reqs */
-       while (send_wr) {
-               ret = post_one_send(my_qp, send_wr, 0);
-               if (unlikely(ret)) {
-                       goto post_send_exit0;
-               }
-               wqe_cnt++;
-               send_wr = send_wr->next;
-       }
-
-post_send_exit0:
-       iosync(); /* serialize GAL register access */
-       hipz_update_sqa(my_qp, wqe_cnt);
-       if (unlikely(ret || ehca_debug_level >= 2))
-               ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d ret=%i",
-                        my_qp, qp->qp_num, wqe_cnt, ret);
-       my_qp->message_count += wqe_cnt;
-       spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
-
-out:
-       if (ret)
-               *bad_send_wr = send_wr;
-       return ret;
-}
-
-static int internal_post_recv(struct ehca_qp *my_qp,
-                             struct ib_device *dev,
-                             struct ib_recv_wr *recv_wr,
-                             struct ib_recv_wr **bad_recv_wr)
-{
-       struct ehca_wqe *wqe_p;
-       int wqe_cnt = 0;
-       int ret = 0;
-       u32 rq_map_idx;
-       unsigned long flags;
-       struct ehca_qmap_entry *qmap_entry;
-
-       if (unlikely(!HAS_RQ(my_qp))) {
-               ehca_err(dev, "QP has no RQ  ehca_qp=%p qp_num=%x ext_type=%d",
-                        my_qp, my_qp->real_qp_num, my_qp->ext_type);
-               ret = -ENODEV;
-               goto out;
-       }
-
-       /* LOCK the QUEUE */
-       spin_lock_irqsave(&my_qp->spinlock_r, flags);
-
-       /* loop processes list of recv reqs */
-       while (recv_wr) {
-               u64 start_offset = my_qp->ipz_rqueue.current_q_offset;
-               /* get pointer next to free WQE */
-               wqe_p = ipz_qeit_get_inc(&my_qp->ipz_rqueue);
-               if (unlikely(!wqe_p)) {
-                       /* too many posted work requests: queue overflow */
-                       ret = -ENOMEM;
-                       ehca_err(dev, "Too many posted WQEs "
-                               "qp_num=%x", my_qp->real_qp_num);
-                       goto post_recv_exit0;
-               }
-               /*
-                * Get the index of the WQE in the recv queue. The same index
-                * is used for writing into the rq_map.
-                */
-               rq_map_idx = start_offset / my_qp->ipz_rqueue.qe_size;
-
-               /* write a RECV WQE into the QUEUE */
-               ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, recv_wr,
-                               rq_map_idx);
-               /*
-                * if something failed,
-                * reset the free entry pointer to the start value
-                */
-               if (unlikely(ret)) {
-                       my_qp->ipz_rqueue.current_q_offset = start_offset;
-                       ret = -EINVAL;
-                       ehca_err(dev, "Could not write WQE "
-                               "qp_num=%x", my_qp->real_qp_num);
-                       goto post_recv_exit0;
-               }
-
-               qmap_entry = &my_qp->rq_map.map[rq_map_idx];
-               qmap_entry->app_wr_id = get_app_wr_id(recv_wr->wr_id);
-               qmap_entry->reported = 0;
-               qmap_entry->cqe_req = 1;
-
-               wqe_cnt++;
-               recv_wr = recv_wr->next;
-       } /* eof for recv_wr */
-
-post_recv_exit0:
-       iosync(); /* serialize GAL register access */
-       hipz_update_rqa(my_qp, wqe_cnt);
-       if (unlikely(ret || ehca_debug_level >= 2))
-           ehca_dbg(dev, "ehca_qp=%p qp_num=%x wqe_cnt=%d ret=%i",
-                    my_qp, my_qp->real_qp_num, wqe_cnt, ret);
-       spin_unlock_irqrestore(&my_qp->spinlock_r, flags);
-
-out:
-       if (ret)
-               *bad_recv_wr = recv_wr;
-
-       return ret;
-}
-
-int ehca_post_recv(struct ib_qp *qp,
-                  struct ib_recv_wr *recv_wr,
-                  struct ib_recv_wr **bad_recv_wr)
-{
-       struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
-
-       /* Reject WR if QP is in RESET state */
-       if (unlikely(my_qp->state == IB_QPS_RESET)) {
-               ehca_err(qp->device, "Invalid QP state  qp_state=%d qpn=%x",
-                        my_qp->state, qp->qp_num);
-               *bad_recv_wr = recv_wr;
-               return -EINVAL;
-       }
-
-       return internal_post_recv(my_qp, qp->device, recv_wr, bad_recv_wr);
-}
-
-int ehca_post_srq_recv(struct ib_srq *srq,
-                      struct ib_recv_wr *recv_wr,
-                      struct ib_recv_wr **bad_recv_wr)
-{
-       return internal_post_recv(container_of(srq, struct ehca_qp, ib_srq),
-                                 srq->device, recv_wr, bad_recv_wr);
-}
-
-/*
- * ib_wc_opcode table converts ehca wc opcode to ib
- * Since we use zero to indicate invalid opcode, the actual ib opcode must
- * be decremented!!!
- */
-static const u8 ib_wc_opcode[255] = {
-       [0x01] = IB_WC_RECV+1,
-       [0x02] = IB_WC_RECV_RDMA_WITH_IMM+1,
-       [0x08] = IB_WC_FETCH_ADD+1,
-       [0x10] = IB_WC_COMP_SWAP+1,
-       [0x20] = IB_WC_RDMA_WRITE+1,
-       [0x40] = IB_WC_RDMA_READ+1,
-       [0x80] = IB_WC_SEND+1
-};
-
-/* internal function to poll one entry of cq */
-static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
-{
-       int ret = 0, qmap_tail_idx;
-       struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
-       struct ehca_cqe *cqe;
-       struct ehca_qp *my_qp;
-       struct ehca_qmap_entry *qmap_entry;
-       struct ehca_queue_map *qmap;
-       int cqe_count = 0, is_error;
-
-repoll:
-       cqe = (struct ehca_cqe *)
-               ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
-       if (!cqe) {
-               ret = -EAGAIN;
-               if (ehca_debug_level >= 3)
-                       ehca_dbg(cq->device, "Completion queue is empty  "
-                                "my_cq=%p cq_num=%x", my_cq, my_cq->cq_number);
-               goto poll_cq_one_exit0;
-       }
-
-       /* prevents loads being reordered across this point */
-       rmb();
-
-       cqe_count++;
-       if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
-               struct ehca_qp *qp;
-               int purgeflag;
-               unsigned long flags;
-
-               qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
-               if (!qp) {
-                       ehca_err(cq->device, "cq_num=%x qp_num=%x "
-                                "could not find qp -> ignore cqe",
-                                my_cq->cq_number, cqe->local_qp_number);
-                       ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x",
-                                my_cq->cq_number, cqe->local_qp_number);
-                       /* ignore this purged cqe */
-                       goto repoll;
-               }
-               spin_lock_irqsave(&qp->spinlock_s, flags);
-               purgeflag = qp->sqerr_purgeflag;
-               spin_unlock_irqrestore(&qp->spinlock_s, flags);
-
-               if (purgeflag) {
-                       ehca_dbg(cq->device,
-                                "Got CQE with purged bit qp_num=%x src_qp=%x",
-                                cqe->local_qp_number, cqe->remote_qp_number);
-                       if (ehca_debug_level >= 2)
-                               ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
-                                        cqe->local_qp_number,
-                                        cqe->remote_qp_number);
-                       /*
-                        * ignore this to avoid double cqes of bad wqe
-                        * that caused sqe and turn off purge flag
-                        */
-                       qp->sqerr_purgeflag = 0;
-                       goto repoll;
-               }
-       }
-
-       is_error = cqe->status & WC_STATUS_ERROR_BIT;
-
-       /* trace error CQEs if debug_level >= 1, trace all CQEs if >= 3 */
-       if (unlikely(ehca_debug_level >= 3 || (ehca_debug_level && is_error))) {
-               ehca_dbg(cq->device,
-                        "Received %sCOMPLETION ehca_cq=%p cq_num=%x -----",
-                        is_error ? "ERROR " : "", my_cq, my_cq->cq_number);
-               ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
-                        my_cq, my_cq->cq_number);
-               ehca_dbg(cq->device,
-                        "ehca_cq=%p cq_num=%x -------------------------",
-                        my_cq, my_cq->cq_number);
-       }
-
-       read_lock(&ehca_qp_idr_lock);
-       my_qp = idr_find(&ehca_qp_idr, cqe->qp_token);
-       read_unlock(&ehca_qp_idr_lock);
-       if (!my_qp)
-               goto repoll;
-       wc->qp = &my_qp->ib_qp;
-
-       qmap_tail_idx = get_app_wr_id(cqe->work_request_id);
-       if (!(cqe->w_completion_flags & WC_SEND_RECEIVE_BIT))
-               /* We got a send completion. */
-               qmap = &my_qp->sq_map;
-       else
-               /* We got a receive completion. */
-               qmap = &my_qp->rq_map;
-
-       /* advance the tail pointer */
-       qmap->tail = qmap_tail_idx;
-
-       if (is_error) {
-               /*
-                * set left_to_poll to 0 because in error state, we will not
-                * get any additional CQEs
-                */
-               my_qp->sq_map.next_wqe_idx = next_index(my_qp->sq_map.tail,
-                                                       my_qp->sq_map.entries);
-               my_qp->sq_map.left_to_poll = 0;
-               ehca_add_to_err_list(my_qp, 1);
-
-               my_qp->rq_map.next_wqe_idx = next_index(my_qp->rq_map.tail,
-                                                       my_qp->rq_map.entries);
-               my_qp->rq_map.left_to_poll = 0;
-               if (HAS_RQ(my_qp))
-                       ehca_add_to_err_list(my_qp, 0);
-       }
-
-       qmap_entry = &qmap->map[qmap_tail_idx];
-       if (qmap_entry->reported) {
-               ehca_warn(cq->device, "Double cqe on qp_num=%#x",
-                               my_qp->real_qp_num);
-               /* found a double cqe, discard it and read next one */
-               goto repoll;
-       }
-
-       wc->wr_id = replace_wr_id(cqe->work_request_id, qmap_entry->app_wr_id);
-       qmap_entry->reported = 1;
-
-       /* if left_to_poll is decremented to 0, add the QP to the error list */
-       if (qmap->left_to_poll > 0) {
-               qmap->left_to_poll--;
-               if ((my_qp->sq_map.left_to_poll == 0) &&
-                               (my_qp->rq_map.left_to_poll == 0)) {
-                       ehca_add_to_err_list(my_qp, 1);
-                       if (HAS_RQ(my_qp))
-                               ehca_add_to_err_list(my_qp, 0);
-               }
-       }
-
-       /* eval ib_wc_opcode */
-       wc->opcode = ib_wc_opcode[cqe->optype]-1;
-       if (unlikely(wc->opcode == -1)) {
-               ehca_err(cq->device, "Invalid cqe->OPType=%x cqe->status=%x "
-                        "ehca_cq=%p cq_num=%x",
-                        cqe->optype, cqe->status, my_cq, my_cq->cq_number);
-               /* dump cqe for other infos */
-               ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
-                        my_cq, my_cq->cq_number);
-               /* update also queue adder to throw away this entry!!! */
-               goto repoll;
-       }
-
-       /* eval ib_wc_status */
-       if (unlikely(is_error)) {
-               /* complete with errors */
-               map_ib_wc_status(cqe->status, &wc->status);
-               wc->vendor_err = wc->status;
-       } else
-               wc->status = IB_WC_SUCCESS;
-
-       wc->byte_len = cqe->nr_bytes_transferred;
-       wc->pkey_index = cqe->pkey_index;
-       wc->slid = cqe->rlid;
-       wc->dlid_path_bits = cqe->dlid;
-       wc->src_qp = cqe->remote_qp_number;
-       /*
-        * HW has "Immed data present" and "GRH present" in bits 6 and 5.
-        * SW defines those in bits 1 and 0, so we can just shift and mask.
-        */
-       wc->wc_flags = (cqe->w_completion_flags >> 5) & 3;
-       wc->ex.imm_data = cpu_to_be32(cqe->immediate_data);
-       wc->sl = cqe->service_level;
-
-poll_cq_one_exit0:
-       if (cqe_count > 0)
-               hipz_update_feca(my_cq, cqe_count);
-
-       return ret;
-}
-
-static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq,
-                              struct ib_wc *wc, int num_entries,
-                              struct ipz_queue *ipz_queue, int on_sq)
-{
-       int nr = 0;
-       struct ehca_wqe *wqe;
-       u64 offset;
-       struct ehca_queue_map *qmap;
-       struct ehca_qmap_entry *qmap_entry;
-
-       if (on_sq)
-               qmap = &my_qp->sq_map;
-       else
-               qmap = &my_qp->rq_map;
-
-       qmap_entry = &qmap->map[qmap->next_wqe_idx];
-
-       while ((nr < num_entries) && (qmap_entry->reported == 0)) {
-               /* generate flush CQE */
-
-               memset(wc, 0, sizeof(*wc));
-
-               offset = qmap->next_wqe_idx * ipz_queue->qe_size;
-               wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset);
-               if (!wqe) {
-                       ehca_err(cq->device, "Invalid wqe offset=%#llx on "
-                                "qp_num=%#x", offset, my_qp->real_qp_num);
-                       return nr;
-               }
-
-               wc->wr_id = replace_wr_id(wqe->work_request_id,
-                                         qmap_entry->app_wr_id);
-
-               if (on_sq) {
-                       switch (wqe->optype) {
-                       case WQE_OPTYPE_SEND:
-                               wc->opcode = IB_WC_SEND;
-                               break;
-                       case WQE_OPTYPE_RDMAWRITE:
-                               wc->opcode = IB_WC_RDMA_WRITE;
-                               break;
-                       case WQE_OPTYPE_RDMAREAD:
-                               wc->opcode = IB_WC_RDMA_READ;
-                               break;
-                       default:
-                               ehca_err(cq->device, "Invalid optype=%x",
-                                               wqe->optype);
-                               return nr;
-                       }
-               } else
-                       wc->opcode = IB_WC_RECV;
-
-               if (wqe->wr_flag & WQE_WRFLAG_IMM_DATA_PRESENT) {
-                       wc->ex.imm_data = wqe->immediate_data;
-                       wc->wc_flags |= IB_WC_WITH_IMM;
-               }
-
-               wc->status = IB_WC_WR_FLUSH_ERR;
-
-               wc->qp = &my_qp->ib_qp;
-
-               /* mark as reported and advance next_wqe pointer */
-               qmap_entry->reported = 1;
-               qmap->next_wqe_idx = next_index(qmap->next_wqe_idx,
-                                               qmap->entries);
-               qmap_entry = &qmap->map[qmap->next_wqe_idx];
-
-               wc++; nr++;
-       }
-
-       return nr;
-
-}
-
-int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
-{
-       struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
-       int nr;
-       struct ehca_qp *err_qp;
-       struct ib_wc *current_wc = wc;
-       int ret = 0;
-       unsigned long flags;
-       int entries_left = num_entries;
-
-       if (num_entries < 1) {
-               ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
-                        "cq_num=%x", num_entries, my_cq, my_cq->cq_number);
-               ret = -EINVAL;
-               goto poll_cq_exit0;
-       }
-
-       spin_lock_irqsave(&my_cq->spinlock, flags);
-
-       /* generate flush cqes for send queues */
-       list_for_each_entry(err_qp, &my_cq->sqp_err_list, sq_err_node) {
-               nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
-                               &err_qp->ipz_squeue, 1);
-               entries_left -= nr;
-               current_wc += nr;
-
-               if (entries_left == 0)
-                       break;
-       }
-
-       /* generate flush cqes for receive queues */
-       list_for_each_entry(err_qp, &my_cq->rqp_err_list, rq_err_node) {
-               nr = generate_flush_cqes(err_qp, cq, current_wc, entries_left,
-                               &err_qp->ipz_rqueue, 0);
-               entries_left -= nr;
-               current_wc += nr;
-
-               if (entries_left == 0)
-                       break;
-       }
-
-       for (nr = 0; nr < entries_left; nr++) {
-               ret = ehca_poll_cq_one(cq, current_wc);
-               if (ret)
-                       break;
-               current_wc++;
-       } /* eof for nr */
-       entries_left -= nr;
-
-       spin_unlock_irqrestore(&my_cq->spinlock, flags);
-       if (ret == -EAGAIN  || !ret)
-               ret = num_entries - entries_left;
-
-poll_cq_exit0:
-       return ret;
-}
-
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
-{
-       struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
-       int ret = 0;
-
-       switch (notify_flags & IB_CQ_SOLICITED_MASK) {
-       case IB_CQ_SOLICITED:
-               hipz_set_cqx_n0(my_cq, 1);
-               break;
-       case IB_CQ_NEXT_COMP:
-               hipz_set_cqx_n1(my_cq, 1);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
-               unsigned long spl_flags;
-               spin_lock_irqsave(&my_cq->spinlock, spl_flags);
-               ret = ipz_qeit_is_valid(&my_cq->ipz_queue);
-               spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
-       }
-
-       return ret;
-}
diff --git a/drivers/staging/rdma/ehca/ehca_sqp.c b/drivers/staging/rdma/ehca/ehca_sqp.c
deleted file mode 100644 (file)
index 376b031..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  SQP functions
- *
- *  Authors: Khadija Souissi <souissi@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <rdma/ib_mad.h>
-
-#include "ehca_classes.h"
-#include "ehca_tools.h"
-#include "ehca_iverbs.h"
-#include "hcp_if.h"
-
-#define IB_MAD_STATUS_REDIRECT         cpu_to_be16(0x0002)
-#define IB_MAD_STATUS_UNSUP_VERSION    cpu_to_be16(0x0004)
-#define IB_MAD_STATUS_UNSUP_METHOD     cpu_to_be16(0x0008)
-
-#define IB_PMA_CLASS_PORT_INFO         cpu_to_be16(0x0001)
-
-/**
- * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
- * pair is created successfully, the corresponding port gets active.
- *
- * Define Special Queue pair 0 (SMI QP) is still not supported.
- *
- * @qp_init_attr: Queue pair init attributes with port and queue pair type
- */
-
-u64 ehca_define_sqp(struct ehca_shca *shca,
-                   struct ehca_qp *ehca_qp,
-                   struct ib_qp_init_attr *qp_init_attr)
-{
-       u32 pma_qp_nr, bma_qp_nr;
-       u64 ret;
-       u8 port = qp_init_attr->port_num;
-       int counter;
-
-       shca->sport[port - 1].port_state = IB_PORT_DOWN;
-
-       switch (qp_init_attr->qp_type) {
-       case IB_QPT_SMI:
-               /* function not supported yet */
-               break;
-       case IB_QPT_GSI:
-               ret = hipz_h_define_aqp1(shca->ipz_hca_handle,
-                                        ehca_qp->ipz_qp_handle,
-                                        ehca_qp->galpas.kernel,
-                                        (u32) qp_init_attr->port_num,
-                                        &pma_qp_nr, &bma_qp_nr);
-
-               if (ret != H_SUCCESS) {
-                       ehca_err(&shca->ib_device,
-                                "Can't define AQP1 for port %x. h_ret=%lli",
-                                port, ret);
-                       return ret;
-               }
-               shca->sport[port - 1].pma_qp_nr = pma_qp_nr;
-               ehca_dbg(&shca->ib_device, "port=%x pma_qp_nr=%x",
-                        port, pma_qp_nr);
-               break;
-       default:
-               ehca_err(&shca->ib_device, "invalid qp_type=%x",
-                        qp_init_attr->qp_type);
-               return H_PARAMETER;
-       }
-
-       if (ehca_nr_ports < 0) /* autodetect mode */
-               return H_SUCCESS;
-
-       for (counter = 0;
-            shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
-                    counter < ehca_port_act_time;
-            counter++) {
-               ehca_dbg(&shca->ib_device, "... wait until port %x is active",
-                        port);
-               msleep_interruptible(1000);
-       }
-
-       if (counter == ehca_port_act_time) {
-               ehca_err(&shca->ib_device, "Port %x is not active.", port);
-               return H_HARDWARE;
-       }
-
-       return H_SUCCESS;
-}
-
-struct ib_perf {
-       struct ib_mad_hdr mad_hdr;
-       u8 reserved[40];
-       u8 data[192];
-} __attribute__ ((packed));
-
-/* TC/SL/FL packed into 32 bits, as in ClassPortInfo */
-struct tcslfl {
-       u32 tc:8;
-       u32 sl:4;
-       u32 fl:20;
-} __attribute__ ((packed));
-
-/* IP Version/TC/FL packed into 32 bits, as in GRH */
-struct vertcfl {
-       u32 ver:4;
-       u32 tc:8;
-       u32 fl:20;
-} __attribute__ ((packed));
-
-static int ehca_process_perf(struct ib_device *ibdev, u8 port_num,
-                            const struct ib_wc *in_wc, const struct ib_grh *in_grh,
-                            const struct ib_mad *in_mad, struct ib_mad *out_mad)
-{
-       const struct ib_perf *in_perf = (const struct ib_perf *)in_mad;
-       struct ib_perf *out_perf = (struct ib_perf *)out_mad;
-       struct ib_class_port_info *poi =
-               (struct ib_class_port_info *)out_perf->data;
-       struct tcslfl *tcslfl =
-               (struct tcslfl *)&poi->redirect_tcslfl;
-       struct ehca_shca *shca =
-               container_of(ibdev, struct ehca_shca, ib_device);
-       struct ehca_sport *sport = &shca->sport[port_num - 1];
-
-       ehca_dbg(ibdev, "method=%x", in_perf->mad_hdr.method);
-
-       *out_mad = *in_mad;
-
-       if (in_perf->mad_hdr.class_version != 1) {
-               ehca_warn(ibdev, "Unsupported class_version=%x",
-                         in_perf->mad_hdr.class_version);
-               out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_VERSION;
-               goto perf_reply;
-       }
-
-       switch (in_perf->mad_hdr.method) {
-       case IB_MGMT_METHOD_GET:
-       case IB_MGMT_METHOD_SET:
-               /* set class port info for redirection */
-               out_perf->mad_hdr.attr_id = IB_PMA_CLASS_PORT_INFO;
-               out_perf->mad_hdr.status = IB_MAD_STATUS_REDIRECT;
-               memset(poi, 0, sizeof(*poi));
-               poi->base_version = 1;
-               poi->class_version = 1;
-               poi->resp_time_value = 18;
-
-               /* copy local routing information from WC where applicable */
-               tcslfl->sl         = in_wc->sl;
-               poi->redirect_lid  =
-                       sport->saved_attr.lid | in_wc->dlid_path_bits;
-               poi->redirect_qp   = sport->pma_qp_nr;
-               poi->redirect_qkey = IB_QP1_QKEY;
-
-               ehca_query_pkey(ibdev, port_num, in_wc->pkey_index,
-                               &poi->redirect_pkey);
-
-               /* if request was globally routed, copy route info */
-               if (in_grh) {
-                       const struct vertcfl *vertcfl =
-                               (const struct vertcfl *)&in_grh->version_tclass_flow;
-                       memcpy(poi->redirect_gid, in_grh->dgid.raw,
-                              sizeof(poi->redirect_gid));
-                       tcslfl->tc        = vertcfl->tc;
-                       tcslfl->fl        = vertcfl->fl;
-               } else
-                       /* else only fill in default GID */
-                       ehca_query_gid(ibdev, port_num, 0,
-                                      (union ib_gid *)&poi->redirect_gid);
-
-               ehca_dbg(ibdev, "ehca_pma_lid=%x ehca_pma_qp=%x",
-                        sport->saved_attr.lid, sport->pma_qp_nr);
-               break;
-
-       case IB_MGMT_METHOD_GET_RESP:
-               return IB_MAD_RESULT_FAILURE;
-
-       default:
-               out_perf->mad_hdr.status = IB_MAD_STATUS_UNSUP_METHOD;
-               break;
-       }
-
-perf_reply:
-       out_perf->mad_hdr.method = IB_MGMT_METHOD_GET_RESP;
-
-       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
-}
-
-int ehca_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
-                    const struct ib_wc *in_wc, const struct ib_grh *in_grh,
-                    const struct ib_mad_hdr *in, size_t in_mad_size,
-                    struct ib_mad_hdr *out, size_t *out_mad_size,
-                    u16 *out_mad_pkey_index)
-{
-       int ret;
-       const struct ib_mad *in_mad = (const struct ib_mad *)in;
-       struct ib_mad *out_mad = (struct ib_mad *)out;
-
-       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
-                        *out_mad_size != sizeof(*out_mad)))
-               return IB_MAD_RESULT_FAILURE;
-
-       if (!port_num || port_num > ibdev->phys_port_cnt || !in_wc)
-               return IB_MAD_RESULT_FAILURE;
-
-       /* accept only pma request */
-       if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT)
-               return IB_MAD_RESULT_SUCCESS;
-
-       ehca_dbg(ibdev, "port_num=%x src_qp=%x", port_num, in_wc->src_qp);
-       ret = ehca_process_perf(ibdev, port_num, in_wc, in_grh,
-                               in_mad, out_mad);
-
-       return ret;
-}
diff --git a/drivers/staging/rdma/ehca/ehca_tools.h b/drivers/staging/rdma/ehca/ehca_tools.h
deleted file mode 100644 (file)
index d280b12..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  auxiliary functions
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Khadija Souissi <souissik@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 EHCA_TOOLS_H
-#define EHCA_TOOLS_H
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/idr.h>
-#include <linux/kthread.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
-#include <linux/notifier.h>
-#include <linux/cpu.h>
-#include <linux/device.h>
-
-#include <linux/atomic.h>
-#include <asm/ibmebus.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/hvcall.h>
-
-extern int ehca_debug_level;
-
-#define ehca_dbg(ib_dev, format, arg...) \
-       do { \
-               if (unlikely(ehca_debug_level)) \
-                       dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
-                                  "PU%04x EHCA_DBG:%s " format "\n", \
-                                  raw_smp_processor_id(), __func__, \
-                                  ## arg); \
-       } while (0)
-
-#define ehca_info(ib_dev, format, arg...) \
-       dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
-                raw_smp_processor_id(), __func__, ## arg)
-
-#define ehca_warn(ib_dev, format, arg...) \
-       dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
-                raw_smp_processor_id(), __func__, ## arg)
-
-#define ehca_err(ib_dev, format, arg...) \
-       dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
-               raw_smp_processor_id(), __func__, ## arg)
-
-/* use this one only if no ib_dev available */
-#define ehca_gen_dbg(format, arg...) \
-       do { \
-               if (unlikely(ehca_debug_level)) \
-                       printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
-                              raw_smp_processor_id(), __func__, ## arg); \
-       } while (0)
-
-#define ehca_gen_warn(format, arg...) \
-       printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
-              raw_smp_processor_id(), __func__, ## arg)
-
-#define ehca_gen_err(format, arg...) \
-       printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
-              raw_smp_processor_id(), __func__, ## arg)
-
-/**
- * ehca_dmp - printk a memory block, whose length is n*8 bytes.
- * Each line has the following layout:
- * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
- */
-#define ehca_dmp(adr, len, format, args...) \
-       do { \
-               unsigned int x; \
-               unsigned int l = (unsigned int)(len); \
-               unsigned char *deb = (unsigned char *)(adr); \
-               for (x = 0; x < l; x += 16) { \
-                       printk(KERN_INFO "EHCA_DMP:%s " format \
-                              " adr=%p ofs=%04x %016llx %016llx\n", \
-                              __func__, ##args, deb, x, \
-                              *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
-                       deb += 16; \
-               } \
-       } while (0)
-
-/* define a bitmask, little endian version */
-#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
-
-/* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
-
-/* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
-
-/* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
-
-/**
- * EHCA_BMASK_SET - return value shifted and masked by mask
- * variable|=EHCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable
- * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
- * in variable
- */
-#define EHCA_BMASK_SET(mask, value) \
-       ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
-
-/**
- * EHCA_BMASK_GET - extract a parameter from value by mask
- */
-#define EHCA_BMASK_GET(mask, value) \
-       (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
-
-/* Converts ehca to ib return code */
-int ehca2ib_return_code(u64 ehca_rc);
-
-#endif /* EHCA_TOOLS_H */
diff --git a/drivers/staging/rdma/ehca/ehca_uverbs.c b/drivers/staging/rdma/ehca/ehca_uverbs.c
deleted file mode 100644 (file)
index 1a1d5d9..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  userspace support verbs
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_classes.h"
-#include "ehca_iverbs.h"
-#include "ehca_mrmw.h"
-#include "ehca_tools.h"
-#include "hcp_if.h"
-
-struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
-                                       struct ib_udata *udata)
-{
-       struct ehca_ucontext *my_context;
-
-       my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
-       if (!my_context) {
-               ehca_err(device, "Out of memory device=%p", device);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       return &my_context->ib_ucontext;
-}
-
-int ehca_dealloc_ucontext(struct ib_ucontext *context)
-{
-       kfree(container_of(context, struct ehca_ucontext, ib_ucontext));
-       return 0;
-}
-
-static void ehca_mm_open(struct vm_area_struct *vma)
-{
-       u32 *count = (u32 *)vma->vm_private_data;
-       if (!count) {
-               ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
-                            vma->vm_start, vma->vm_end);
-               return;
-       }
-       (*count)++;
-       if (!(*count))
-               ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
-                            vma->vm_start, vma->vm_end);
-       ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
-                    vma->vm_start, vma->vm_end, *count);
-}
-
-static void ehca_mm_close(struct vm_area_struct *vma)
-{
-       u32 *count = (u32 *)vma->vm_private_data;
-       if (!count) {
-               ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
-                            vma->vm_start, vma->vm_end);
-               return;
-       }
-       (*count)--;
-       ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
-                    vma->vm_start, vma->vm_end, *count);
-}
-
-static const struct vm_operations_struct vm_ops = {
-       .open = ehca_mm_open,
-       .close = ehca_mm_close,
-};
-
-static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
-                       u32 *mm_count)
-{
-       int ret;
-       u64 vsize, physical;
-
-       vsize = vma->vm_end - vma->vm_start;
-       if (vsize < EHCA_PAGESIZE) {
-               ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
-               return -EINVAL;
-       }
-
-       physical = galpas->user.fw_handle;
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       ehca_gen_dbg("vsize=%llx physical=%llx", vsize, physical);
-       /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
-       ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
-                          vma->vm_page_prot);
-       if (unlikely(ret)) {
-               ehca_gen_err("remap_pfn_range() failed ret=%i", ret);
-               return -ENOMEM;
-       }
-
-       vma->vm_private_data = mm_count;
-       (*mm_count)++;
-       vma->vm_ops = &vm_ops;
-
-       return 0;
-}
-
-static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
-                          u32 *mm_count)
-{
-       int ret;
-       u64 start, ofs;
-       struct page *page;
-
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-       start = vma->vm_start;
-       for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
-               u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
-               page = virt_to_page(virt_addr);
-               ret = vm_insert_page(vma, start, page);
-               if (unlikely(ret)) {
-                       ehca_gen_err("vm_insert_page() failed rc=%i", ret);
-                       return ret;
-               }
-               start += PAGE_SIZE;
-       }
-       vma->vm_private_data = mm_count;
-       (*mm_count)++;
-       vma->vm_ops = &vm_ops;
-
-       return 0;
-}
-
-static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
-                       u32 rsrc_type)
-{
-       int ret;
-
-       switch (rsrc_type) {
-       case 0: /* galpa fw handle */
-               ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
-               ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
-               if (unlikely(ret)) {
-                       ehca_err(cq->ib_cq.device,
-                                "ehca_mmap_fw() failed rc=%i cq_num=%x",
-                                ret, cq->cq_number);
-                       return ret;
-               }
-               break;
-
-       case 1: /* cq queue_addr */
-               ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
-               ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
-               if (unlikely(ret)) {
-                       ehca_err(cq->ib_cq.device,
-                                "ehca_mmap_queue() failed rc=%i cq_num=%x",
-                                ret, cq->cq_number);
-                       return ret;
-               }
-               break;
-
-       default:
-               ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
-                        rsrc_type, cq->cq_number);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
-                       u32 rsrc_type)
-{
-       int ret;
-
-       switch (rsrc_type) {
-       case 0: /* galpa fw handle */
-               ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
-               ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
-               if (unlikely(ret)) {
-                       ehca_err(qp->ib_qp.device,
-                                "remap_pfn_range() failed ret=%i qp_num=%x",
-                                ret, qp->ib_qp.qp_num);
-                       return -ENOMEM;
-               }
-               break;
-
-       case 1: /* qp rqueue_addr */
-               ehca_dbg(qp->ib_qp.device, "qp_num=%x rq", qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
-                                     &qp->mm_count_rqueue);
-               if (unlikely(ret)) {
-                       ehca_err(qp->ib_qp.device,
-                                "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",
-                                ret, qp->ib_qp.qp_num);
-                       return ret;
-               }
-               break;
-
-       case 2: /* qp squeue_addr */
-               ehca_dbg(qp->ib_qp.device, "qp_num=%x sq", qp->ib_qp.qp_num);
-               ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
-                                     &qp->mm_count_squeue);
-               if (unlikely(ret)) {
-                       ehca_err(qp->ib_qp.device,
-                                "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",
-                                ret, qp->ib_qp.qp_num);
-                       return ret;
-               }
-               break;
-
-       default:
-               ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
-                        rsrc_type, qp->ib_qp.qp_num);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
-{
-       u64 fileoffset = vma->vm_pgoff;
-       u32 idr_handle = fileoffset & 0x1FFFFFF;
-       u32 q_type = (fileoffset >> 27) & 0x1;    /* CQ, QP,...        */
-       u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */
-       u32 ret;
-       struct ehca_cq *cq;
-       struct ehca_qp *qp;
-       struct ib_uobject *uobject;
-
-       switch (q_type) {
-       case  0: /* CQ */
-               read_lock(&ehca_cq_idr_lock);
-               cq = idr_find(&ehca_cq_idr, idr_handle);
-               read_unlock(&ehca_cq_idr_lock);
-
-               /* make sure this mmap really belongs to the authorized user */
-               if (!cq)
-                       return -EINVAL;
-
-               if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
-                       return -EINVAL;
-
-               ret = ehca_mmap_cq(vma, cq, rsrc_type);
-               if (unlikely(ret)) {
-                       ehca_err(cq->ib_cq.device,
-                                "ehca_mmap_cq() failed rc=%i cq_num=%x",
-                                ret, cq->cq_number);
-                       return ret;
-               }
-               break;
-
-       case 1: /* QP */
-               read_lock(&ehca_qp_idr_lock);
-               qp = idr_find(&ehca_qp_idr, idr_handle);
-               read_unlock(&ehca_qp_idr_lock);
-
-               /* make sure this mmap really belongs to the authorized user */
-               if (!qp)
-                       return -EINVAL;
-
-               uobject = IS_SRQ(qp) ? qp->ib_srq.uobject : qp->ib_qp.uobject;
-               if (!uobject || uobject->context != context)
-                       return -EINVAL;
-
-               ret = ehca_mmap_qp(vma, qp, rsrc_type);
-               if (unlikely(ret)) {
-                       ehca_err(qp->ib_qp.device,
-                                "ehca_mmap_qp() failed rc=%i qp_num=%x",
-                                ret, qp->ib_qp.qp_num);
-                       return ret;
-               }
-               break;
-
-       default:
-               ehca_gen_err("bad queue type %x", q_type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/rdma/ehca/hcp_if.c b/drivers/staging/rdma/ehca/hcp_if.c
deleted file mode 100644 (file)
index 89517ff..0000000
+++ /dev/null
@@ -1,949 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Firmware Infiniband Interface code for POWER
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Joachim Fenkes <fenkes@de.ibm.com>
- *           Gerd Bayer <gerd.bayer@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <asm/hvcall.h>
-#include "ehca_tools.h"
-#include "hcp_if.h"
-#include "hcp_phyp.h"
-#include "hipz_fns.h"
-#include "ipz_pt_fn.h"
-
-#define H_ALL_RES_QP_ENHANCED_OPS       EHCA_BMASK_IBM(9, 11)
-#define H_ALL_RES_QP_PTE_PIN            EHCA_BMASK_IBM(12, 12)
-#define H_ALL_RES_QP_SERVICE_TYPE       EHCA_BMASK_IBM(13, 15)
-#define H_ALL_RES_QP_STORAGE            EHCA_BMASK_IBM(16, 17)
-#define H_ALL_RES_QP_LL_RQ_CQE_POSTING  EHCA_BMASK_IBM(18, 18)
-#define H_ALL_RES_QP_LL_SQ_CQE_POSTING  EHCA_BMASK_IBM(19, 21)
-#define H_ALL_RES_QP_SIGNALING_TYPE     EHCA_BMASK_IBM(22, 23)
-#define H_ALL_RES_QP_UD_AV_LKEY_CTRL    EHCA_BMASK_IBM(31, 31)
-#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)
-#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)
-#define H_ALL_RES_QP_RESOURCE_TYPE      EHCA_BMASK_IBM(56, 63)
-
-#define H_ALL_RES_QP_MAX_OUTST_SEND_WR  EHCA_BMASK_IBM(0, 15)
-#define H_ALL_RES_QP_MAX_OUTST_RECV_WR  EHCA_BMASK_IBM(16, 31)
-#define H_ALL_RES_QP_MAX_SEND_SGE       EHCA_BMASK_IBM(32, 39)
-#define H_ALL_RES_QP_MAX_RECV_SGE       EHCA_BMASK_IBM(40, 47)
-
-#define H_ALL_RES_QP_UD_AV_LKEY         EHCA_BMASK_IBM(32, 63)
-#define H_ALL_RES_QP_SRQ_QP_TOKEN       EHCA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_SRQ_QP_HANDLE      EHCA_BMASK_IBM(0, 64)
-#define H_ALL_RES_QP_SRQ_LIMIT          EHCA_BMASK_IBM(48, 63)
-#define H_ALL_RES_QP_SRQ_QPN            EHCA_BMASK_IBM(40, 63)
-
-#define H_ALL_RES_QP_ACT_OUTST_SEND_WR  EHCA_BMASK_IBM(16, 31)
-#define H_ALL_RES_QP_ACT_OUTST_RECV_WR  EHCA_BMASK_IBM(48, 63)
-#define H_ALL_RES_QP_ACT_SEND_SGE       EHCA_BMASK_IBM(8, 15)
-#define H_ALL_RES_QP_ACT_RECV_SGE       EHCA_BMASK_IBM(24, 31)
-
-#define H_ALL_RES_QP_SQUEUE_SIZE_PAGES  EHCA_BMASK_IBM(0, 31)
-#define H_ALL_RES_QP_RQUEUE_SIZE_PAGES  EHCA_BMASK_IBM(32, 63)
-
-#define H_MP_INIT_TYPE                  EHCA_BMASK_IBM(44, 47)
-#define H_MP_SHUTDOWN                   EHCA_BMASK_IBM(48, 48)
-#define H_MP_RESET_QKEY_CTR             EHCA_BMASK_IBM(49, 49)
-
-#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx"
-#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx"
-#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx"
-
-static DEFINE_SPINLOCK(hcall_lock);
-
-static long ehca_plpar_hcall_norets(unsigned long opcode,
-                                   unsigned long arg1,
-                                   unsigned long arg2,
-                                   unsigned long arg3,
-                                   unsigned long arg4,
-                                   unsigned long arg5,
-                                   unsigned long arg6,
-                                   unsigned long arg7)
-{
-       long ret;
-       int i, sleep_msecs;
-       unsigned long flags = 0;
-
-       if (unlikely(ehca_debug_level >= 2))
-               ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
-                            opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
-
-       for (i = 0; i < 5; i++) {
-               /* serialize hCalls to work around firmware issue */
-               if (ehca_lock_hcalls)
-                       spin_lock_irqsave(&hcall_lock, flags);
-
-               ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
-                                        arg5, arg6, arg7);
-
-               if (ehca_lock_hcalls)
-                       spin_unlock_irqrestore(&hcall_lock, flags);
-
-               if (H_IS_LONG_BUSY(ret)) {
-                       sleep_msecs = get_longbusy_msecs(ret);
-                       msleep_interruptible(sleep_msecs);
-                       continue;
-               }
-
-               if (ret < H_SUCCESS)
-                       ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT,
-                                    opcode, ret, arg1, arg2, arg3,
-                                    arg4, arg5, arg6, arg7);
-               else
-                       if (unlikely(ehca_debug_level >= 2))
-                               ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
-
-               return ret;
-       }
-
-       return H_BUSY;
-}
-
-static long ehca_plpar_hcall9(unsigned long opcode,
-                             unsigned long *outs, /* array of 9 outputs */
-                             unsigned long arg1,
-                             unsigned long arg2,
-                             unsigned long arg3,
-                             unsigned long arg4,
-                             unsigned long arg5,
-                             unsigned long arg6,
-                             unsigned long arg7,
-                             unsigned long arg8,
-                             unsigned long arg9)
-{
-       long ret;
-       int i, sleep_msecs;
-       unsigned long flags = 0;
-
-       if (unlikely(ehca_debug_level >= 2))
-               ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
-                            arg1, arg2, arg3, arg4, arg5,
-                            arg6, arg7, arg8, arg9);
-
-       for (i = 0; i < 5; i++) {
-               /* serialize hCalls to work around firmware issue */
-               if (ehca_lock_hcalls)
-                       spin_lock_irqsave(&hcall_lock, flags);
-
-               ret = plpar_hcall9(opcode, outs,
-                                  arg1, arg2, arg3, arg4, arg5,
-                                  arg6, arg7, arg8, arg9);
-
-               if (ehca_lock_hcalls)
-                       spin_unlock_irqrestore(&hcall_lock, flags);
-
-               if (H_IS_LONG_BUSY(ret)) {
-                       sleep_msecs = get_longbusy_msecs(ret);
-                       msleep_interruptible(sleep_msecs);
-                       continue;
-               }
-
-               if (ret < H_SUCCESS) {
-                       ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT,
-                                    opcode, arg1, arg2, arg3, arg4, arg5,
-                                    arg6, arg7, arg8, arg9);
-                       ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
-                                    ret, outs[0], outs[1], outs[2], outs[3],
-                                    outs[4], outs[5], outs[6], outs[7],
-                                    outs[8]);
-               } else if (unlikely(ehca_debug_level >= 2))
-                       ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
-                                    ret, outs[0], outs[1], outs[2], outs[3],
-                                    outs[4], outs[5], outs[6], outs[7],
-                                    outs[8]);
-               return ret;
-       }
-
-       return H_BUSY;
-}
-
-u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_pfeq *pfeq,
-                            const u32 neq_control,
-                            const u32 number_of_entries,
-                            struct ipz_eq_handle *eq_handle,
-                            u32 *act_nr_of_entries,
-                            u32 *act_pages,
-                            u32 *eq_ist)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-       u64 allocate_controls;
-
-       /* resource type */
-       allocate_controls = 3ULL;
-
-       /* ISN is associated */
-       if (neq_control != 1)
-               allocate_controls = (1ULL << (63 - 7)) | allocate_controls;
-       else /* notification event queue */
-               allocate_controls = (1ULL << 63) | allocate_controls;
-
-       ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
-                               adapter_handle.handle,  /* r4 */
-                               allocate_controls,      /* r5 */
-                               number_of_entries,      /* r6 */
-                               0, 0, 0, 0, 0, 0);
-       eq_handle->handle = outs[0];
-       *act_nr_of_entries = (u32)outs[3];
-       *act_pages = (u32)outs[4];
-       *eq_ist = (u32)outs[5];
-
-       if (ret == H_NOT_ENOUGH_RESOURCES)
-               ehca_gen_err("Not enough resource - ret=%lli ", ret);
-
-       return ret;
-}
-
-u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
-                      struct ipz_eq_handle eq_handle,
-                      const u64 event_mask)
-{
-       return ehca_plpar_hcall_norets(H_RESET_EVENTS,
-                                      adapter_handle.handle, /* r4 */
-                                      eq_handle.handle,      /* r5 */
-                                      event_mask,            /* r6 */
-                                      0, 0, 0, 0);
-}
-
-u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_cq *cq,
-                            struct ehca_alloc_cq_parms *param)
-{
-       int rc;
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
-                               adapter_handle.handle,   /* r4  */
-                               2,                       /* r5  */
-                               param->eq_handle.handle, /* r6  */
-                               cq->token,               /* r7  */
-                               param->nr_cqe,           /* r8  */
-                               0, 0, 0, 0);
-       cq->ipz_cq_handle.handle = outs[0];
-       param->act_nr_of_entries = (u32)outs[3];
-       param->act_pages = (u32)outs[4];
-
-       if (ret == H_SUCCESS) {
-               rc = hcp_galpas_ctor(&cq->galpas, 0, outs[5], outs[6]);
-               if (rc) {
-                       ehca_gen_err("Could not establish HW access. rc=%d paddr=%#lx",
-                                    rc, outs[5]);
-
-                       ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                               adapter_handle.handle,     /* r4 */
-                                               cq->ipz_cq_handle.handle,  /* r5 */
-                                               0, 0, 0, 0, 0);
-                       ret = H_NO_MEM;
-               }
-       }
-
-       if (ret == H_NOT_ENOUGH_RESOURCES)
-               ehca_gen_err("Not enough resources. ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_alloc_qp_parms *parms, int is_user)
-{
-       int rc;
-       u64 ret;
-       u64 allocate_controls, max_r10_reg, r11, r12;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       allocate_controls =
-               EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS, parms->ext_type)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE,
-                                parms->squeue.page_size)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE,
-                                parms->rqueue.page_size)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
-                                !!(parms->ll_comp_flags & LLQP_RECV_COMP))
-               | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
-                                !!(parms->ll_comp_flags & LLQP_SEND_COMP))
-               | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
-                                parms->ud_av_l_key_ctl)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
-
-       max_r10_reg =
-               EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
-                              parms->squeue.max_wr + 1)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
-                                parms->rqueue.max_wr + 1)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
-                                parms->squeue.max_sge)
-               | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
-                                parms->rqueue.max_sge);
-
-       r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token);
-
-       if (parms->ext_type == EQPT_SRQ)
-               r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_LIMIT, parms->srq_limit);
-       else
-               r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QPN, parms->srq_qpn);
-
-       ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
-                               adapter_handle.handle,             /* r4  */
-                               allocate_controls,                 /* r5  */
-                               parms->send_cq_handle.handle,
-                               parms->recv_cq_handle.handle,
-                               parms->eq_handle.handle,
-                               ((u64)parms->token << 32) | parms->pd.value,
-                               max_r10_reg, r11, r12);
-
-       parms->qp_handle.handle = outs[0];
-       parms->real_qp_num = (u32)outs[1];
-       parms->squeue.act_nr_wqes =
-               (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
-       parms->rqueue.act_nr_wqes =
-               (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
-       parms->squeue.act_nr_sges =
-               (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
-       parms->rqueue.act_nr_sges =
-               (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
-       parms->squeue.queue_size =
-               (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
-       parms->rqueue.queue_size =
-               (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
-
-       if (ret == H_SUCCESS) {
-               rc = hcp_galpas_ctor(&parms->galpas, is_user, outs[6], outs[6]);
-               if (rc) {
-                       ehca_gen_err("Could not establish HW access. rc=%d paddr=%#lx",
-                                    rc, outs[6]);
-
-                       ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                               adapter_handle.handle,     /* r4 */
-                                               parms->qp_handle.handle,  /* r5 */
-                                               0, 0, 0, 0, 0);
-                       ret = H_NO_MEM;
-               }
-       }
-
-       if (ret == H_NOT_ENOUGH_RESOURCES)
-               ehca_gen_err("Not enough resources. ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
-                     const u8 port_id,
-                     struct hipz_query_port *query_port_response_block)
-{
-       u64 ret;
-       u64 r_cb = __pa(query_port_response_block);
-
-       if (r_cb & (EHCA_PAGESIZE-1)) {
-               ehca_gen_err("response block not page aligned");
-               return H_PARAMETER;
-       }
-
-       ret = ehca_plpar_hcall_norets(H_QUERY_PORT,
-                                     adapter_handle.handle, /* r4 */
-                                     port_id,               /* r5 */
-                                     r_cb,                  /* r6 */
-                                     0, 0, 0, 0);
-
-       if (ehca_debug_level >= 2)
-               ehca_dmp(query_port_response_block, 64, "response_block");
-
-       return ret;
-}
-
-u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle,
-                      const u8 port_id, const u32 port_cap,
-                      const u8 init_type, const int modify_mask)
-{
-       u64 port_attributes = port_cap;
-
-       if (modify_mask & IB_PORT_SHUTDOWN)
-               port_attributes |= EHCA_BMASK_SET(H_MP_SHUTDOWN, 1);
-       if (modify_mask & IB_PORT_INIT_TYPE)
-               port_attributes |= EHCA_BMASK_SET(H_MP_INIT_TYPE, init_type);
-       if (modify_mask & IB_PORT_RESET_QKEY_CNTR)
-               port_attributes |= EHCA_BMASK_SET(H_MP_RESET_QKEY_CTR, 1);
-
-       return ehca_plpar_hcall_norets(H_MODIFY_PORT,
-                                      adapter_handle.handle, /* r4 */
-                                      port_id,               /* r5 */
-                                      port_attributes,       /* r6 */
-                                      0, 0, 0, 0);
-}
-
-u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
-                    struct hipz_query_hca *query_hca_rblock)
-{
-       u64 r_cb = __pa(query_hca_rblock);
-
-       if (r_cb & (EHCA_PAGESIZE-1)) {
-               ehca_gen_err("response_block=%p not page aligned",
-                            query_hca_rblock);
-               return H_PARAMETER;
-       }
-
-       return ehca_plpar_hcall_norets(H_QUERY_HCA,
-                                      adapter_handle.handle, /* r4 */
-                                      r_cb,                  /* r5 */
-                                      0, 0, 0, 0, 0);
-}
-
-u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
-                         const u8 pagesize,
-                         const u8 queue_type,
-                         const u64 resource_handle,
-                         const u64 logical_address_of_page,
-                         u64 count)
-{
-       return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
-                                      adapter_handle.handle,      /* r4  */
-                                      (u64)queue_type | ((u64)pagesize) << 8,
-                                      /* r5  */
-                                      resource_handle,            /* r6  */
-                                      logical_address_of_page,    /* r7  */
-                                      count,                      /* r8  */
-                                      0, 0);
-}
-
-u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_eq_handle eq_handle,
-                            struct ehca_pfeq *pfeq,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count)
-{
-       if (count != 1) {
-               ehca_gen_err("Ppage counter=%llx", count);
-               return H_PARAMETER;
-       }
-       return hipz_h_register_rpage(adapter_handle,
-                                    pagesize,
-                                    queue_type,
-                                    eq_handle.handle,
-                                    logical_address_of_page, count);
-}
-
-u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle,
-                          u32 ist)
-{
-       u64 ret;
-       ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE,
-                                     adapter_handle.handle, /* r4 */
-                                     ist,                   /* r5 */
-                                     0, 0, 0, 0, 0);
-
-       if (ret != H_SUCCESS && ret != H_BUSY)
-               ehca_gen_err("Could not query interrupt state.");
-
-       return ret;
-}
-
-u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_cq_handle cq_handle,
-                            struct ehca_pfcq *pfcq,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count,
-                            const struct h_galpa gal)
-{
-       if (count != 1) {
-               ehca_gen_err("Page counter=%llx", count);
-               return H_PARAMETER;
-       }
-
-       return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
-                                    cq_handle.handle, logical_address_of_page,
-                                    count);
-}
-
-u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_qp_handle qp_handle,
-                            struct ehca_pfqp *pfqp,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count,
-                            const struct h_galpa galpa)
-{
-       if (count > 1) {
-               ehca_gen_err("Page counter=%llx", count);
-               return H_PARAMETER;
-       }
-
-       return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
-                                    qp_handle.handle, logical_address_of_page,
-                                    count);
-}
-
-u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
-                              const struct ipz_qp_handle qp_handle,
-                              struct ehca_pfqp *pfqp,
-                              void **log_addr_next_sq_wqe2processed,
-                              void **log_addr_next_rq_wqe2processed,
-                              int dis_and_get_function_code)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
-                               adapter_handle.handle,     /* r4 */
-                               dis_and_get_function_code, /* r5 */
-                               qp_handle.handle,          /* r6 */
-                               0, 0, 0, 0, 0, 0);
-       if (log_addr_next_sq_wqe2processed)
-               *log_addr_next_sq_wqe2processed = (void *)outs[0];
-       if (log_addr_next_rq_wqe2processed)
-               *log_addr_next_rq_wqe2processed = (void *)outs[1];
-
-       return ret;
-}
-
-u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
-                    const struct ipz_qp_handle qp_handle,
-                    struct ehca_pfqp *pfqp,
-                    const u64 update_mask,
-                    struct hcp_modify_qp_control_block *mqpcb,
-                    struct h_galpa gal)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-       ret = ehca_plpar_hcall9(H_MODIFY_QP, outs,
-                               adapter_handle.handle, /* r4 */
-                               qp_handle.handle,      /* r5 */
-                               update_mask,           /* r6 */
-                               __pa(mqpcb),           /* r7 */
-                               0, 0, 0, 0, 0);
-
-       if (ret == H_NOT_ENOUGH_RESOURCES)
-               ehca_gen_err("Insufficient resources ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
-                   const struct ipz_qp_handle qp_handle,
-                   struct ehca_pfqp *pfqp,
-                   struct hcp_modify_qp_control_block *qqpcb,
-                   struct h_galpa gal)
-{
-       return ehca_plpar_hcall_norets(H_QUERY_QP,
-                                      adapter_handle.handle, /* r4 */
-                                      qp_handle.handle,      /* r5 */
-                                      __pa(qqpcb),           /* r6 */
-                                      0, 0, 0, 0);
-}
-
-u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_qp *qp)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = hcp_galpas_dtor(&qp->galpas);
-       if (ret) {
-               ehca_gen_err("Could not destruct qp->galpas");
-               return H_RESOURCE;
-       }
-       ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
-                               adapter_handle.handle,     /* r4 */
-                               /* function code */
-                               1,                         /* r5 */
-                               qp->ipz_qp_handle.handle,  /* r6 */
-                               0, 0, 0, 0, 0, 0);
-       if (ret == H_HARDWARE)
-               ehca_gen_err("HCA not operational. ret=%lli", ret);
-
-       ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                     adapter_handle.handle,     /* r4 */
-                                     qp->ipz_qp_handle.handle,  /* r5 */
-                                     0, 0, 0, 0, 0);
-
-       if (ret == H_RESOURCE)
-               ehca_gen_err("Resource still in use. ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u32 port)
-{
-       return ehca_plpar_hcall_norets(H_DEFINE_AQP0,
-                                      adapter_handle.handle, /* r4 */
-                                      qp_handle.handle,      /* r5 */
-                                      port,                  /* r6 */
-                                      0, 0, 0, 0);
-}
-
-u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u32 port, u32 * pma_qp_nr,
-                      u32 * bma_qp_nr)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs,
-                               adapter_handle.handle, /* r4 */
-                               qp_handle.handle,      /* r5 */
-                               port,                  /* r6 */
-                               0, 0, 0, 0, 0, 0);
-       *pma_qp_nr = (u32)outs[0];
-       *bma_qp_nr = (u32)outs[1];
-
-       if (ret == H_ALIAS_EXIST)
-               ehca_gen_err("AQP1 already exists. ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u16 mcg_dlid,
-                      u64 subnet_prefix, u64 interface_id)
-{
-       u64 ret;
-
-       ret = ehca_plpar_hcall_norets(H_ATTACH_MCQP,
-                                     adapter_handle.handle,  /* r4 */
-                                     qp_handle.handle,       /* r5 */
-                                     mcg_dlid,               /* r6 */
-                                     interface_id,           /* r7 */
-                                     subnet_prefix,          /* r8 */
-                                     0, 0);
-
-       if (ret == H_NOT_ENOUGH_RESOURCES)
-               ehca_gen_err("Not enough resources. ret=%lli", ret);
-
-       return ret;
-}
-
-u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u16 mcg_dlid,
-                      u64 subnet_prefix, u64 interface_id)
-{
-       return ehca_plpar_hcall_norets(H_DETACH_MCQP,
-                                      adapter_handle.handle, /* r4 */
-                                      qp_handle.handle,      /* r5 */
-                                      mcg_dlid,              /* r6 */
-                                      interface_id,          /* r7 */
-                                      subnet_prefix,         /* r8 */
-                                      0, 0);
-}
-
-u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_cq *cq,
-                     u8 force_flag)
-{
-       u64 ret;
-
-       ret = hcp_galpas_dtor(&cq->galpas);
-       if (ret) {
-               ehca_gen_err("Could not destruct cp->galpas");
-               return H_RESOURCE;
-       }
-
-       ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                     adapter_handle.handle,     /* r4 */
-                                     cq->ipz_cq_handle.handle,  /* r5 */
-                                     force_flag != 0 ? 1L : 0L, /* r6 */
-                                     0, 0, 0, 0);
-
-       if (ret == H_RESOURCE)
-               ehca_gen_err("H_FREE_RESOURCE failed ret=%lli ", ret);
-
-       return ret;
-}
-
-u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_eq *eq)
-{
-       u64 ret;
-
-       ret = hcp_galpas_dtor(&eq->galpas);
-       if (ret) {
-               ehca_gen_err("Could not destruct eq->galpas");
-               return H_RESOURCE;
-       }
-
-       ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                     adapter_handle.handle,     /* r4 */
-                                     eq->ipz_eq_handle.handle,  /* r5 */
-                                     0, 0, 0, 0, 0);
-
-       if (ret == H_RESOURCE)
-               ehca_gen_err("Resource in use. ret=%lli ", ret);
-
-       return ret;
-}
-
-u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mr *mr,
-                            const u64 vaddr,
-                            const u64 length,
-                            const u32 access_ctrl,
-                            const struct ipz_pd pd,
-                            struct ehca_mr_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
-                               adapter_handle.handle,            /* r4 */
-                               5,                                /* r5 */
-                               vaddr,                            /* r6 */
-                               length,                           /* r7 */
-                               (((u64)access_ctrl) << 32ULL),    /* r8 */
-                               pd.value,                         /* r9 */
-                               0, 0, 0);
-       outparms->handle.handle = outs[0];
-       outparms->lkey = (u32)outs[2];
-       outparms->rkey = (u32)outs[3];
-
-       return ret;
-}
-
-u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mr *mr,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count)
-{
-       u64 ret;
-
-       if (unlikely(ehca_debug_level >= 3)) {
-               if (count > 1) {
-                       u64 *kpage;
-                       int i;
-                       kpage = __va(logical_address_of_page);
-                       for (i = 0; i < count; i++)
-                               ehca_gen_dbg("kpage[%d]=%p",
-                                            i, (void *)kpage[i]);
-               } else
-                       ehca_gen_dbg("kpage=%p",
-                                    (void *)logical_address_of_page);
-       }
-
-       if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
-               ehca_gen_err("logical_address_of_page not on a 4k boundary "
-                            "adapter_handle=%llx mr=%p mr_handle=%llx "
-                            "pagesize=%x queue_type=%x "
-                            "logical_address_of_page=%llx count=%llx",
-                            adapter_handle.handle, mr,
-                            mr->ipz_mr_handle.handle, pagesize, queue_type,
-                            logical_address_of_page, count);
-               ret = H_PARAMETER;
-       } else
-               ret = hipz_h_register_rpage(adapter_handle, pagesize,
-                                           queue_type,
-                                           mr->ipz_mr_handle.handle,
-                                           logical_address_of_page, count);
-       return ret;
-}
-
-u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
-                   const struct ehca_mr *mr,
-                   struct ehca_mr_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_QUERY_MR, outs,
-                               adapter_handle.handle,     /* r4 */
-                               mr->ipz_mr_handle.handle,  /* r5 */
-                               0, 0, 0, 0, 0, 0, 0);
-       outparms->len = outs[0];
-       outparms->vaddr = outs[1];
-       outparms->acl  = outs[4] >> 32;
-       outparms->lkey = (u32)(outs[5] >> 32);
-       outparms->rkey = (u32)(outs[5] & (0xffffffff));
-
-       return ret;
-}
-
-u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
-                           const struct ehca_mr *mr)
-{
-       return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                      adapter_handle.handle,    /* r4 */
-                                      mr->ipz_mr_handle.handle, /* r5 */
-                                      0, 0, 0, 0, 0);
-}
-
-u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
-                         const struct ehca_mr *mr,
-                         const u64 vaddr_in,
-                         const u64 length,
-                         const u32 access_ctrl,
-                         const struct ipz_pd pd,
-                         const u64 mr_addr_cb,
-                         struct ehca_mr_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs,
-                               adapter_handle.handle,    /* r4 */
-                               mr->ipz_mr_handle.handle, /* r5 */
-                               vaddr_in,                 /* r6 */
-                               length,                   /* r7 */
-                               /* r8 */
-                               ((((u64)access_ctrl) << 32ULL) | pd.value),
-                               mr_addr_cb,               /* r9 */
-                               0, 0, 0);
-       outparms->vaddr = outs[1];
-       outparms->lkey = (u32)outs[2];
-       outparms->rkey = (u32)outs[3];
-
-       return ret;
-}
-
-u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
-                       const struct ehca_mr *mr,
-                       const struct ehca_mr *orig_mr,
-                       const u64 vaddr_in,
-                       const u32 access_ctrl,
-                       const struct ipz_pd pd,
-                       struct ehca_mr_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs,
-                               adapter_handle.handle,            /* r4 */
-                               orig_mr->ipz_mr_handle.handle,    /* r5 */
-                               vaddr_in,                         /* r6 */
-                               (((u64)access_ctrl) << 32ULL),    /* r7 */
-                               pd.value,                         /* r8 */
-                               0, 0, 0, 0);
-       outparms->handle.handle = outs[0];
-       outparms->lkey = (u32)outs[2];
-       outparms->rkey = (u32)outs[3];
-
-       return ret;
-}
-
-u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mw *mw,
-                            const struct ipz_pd pd,
-                            struct ehca_mw_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
-                               adapter_handle.handle,      /* r4 */
-                               6,                          /* r5 */
-                               pd.value,                   /* r6 */
-                               0, 0, 0, 0, 0, 0);
-       outparms->handle.handle = outs[0];
-       outparms->rkey = (u32)outs[3];
-
-       return ret;
-}
-
-u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
-                   const struct ehca_mw *mw,
-                   struct ehca_mw_hipzout_parms *outparms)
-{
-       u64 ret;
-       unsigned long outs[PLPAR_HCALL9_BUFSIZE];
-
-       ret = ehca_plpar_hcall9(H_QUERY_MW, outs,
-                               adapter_handle.handle,    /* r4 */
-                               mw->ipz_mw_handle.handle, /* r5 */
-                               0, 0, 0, 0, 0, 0, 0);
-       outparms->rkey = (u32)outs[3];
-
-       return ret;
-}
-
-u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
-                           const struct ehca_mw *mw)
-{
-       return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
-                                      adapter_handle.handle,    /* r4 */
-                                      mw->ipz_mw_handle.handle, /* r5 */
-                                      0, 0, 0, 0, 0);
-}
-
-u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
-                     const u64 ressource_handle,
-                     void *rblock,
-                     unsigned long *byte_count)
-{
-       u64 r_cb = __pa(rblock);
-
-       if (r_cb & (EHCA_PAGESIZE-1)) {
-               ehca_gen_err("rblock not page aligned.");
-               return H_PARAMETER;
-       }
-
-       return ehca_plpar_hcall_norets(H_ERROR_DATA,
-                                      adapter_handle.handle,
-                                      ressource_handle,
-                                      r_cb,
-                                      0, 0, 0, 0);
-}
-
-u64 hipz_h_eoi(int irq)
-{
-       unsigned long xirr;
-
-       iosync();
-       xirr = (0xffULL << 24) | irq;
-
-       return plpar_hcall_norets(H_EOI, xirr);
-}
diff --git a/drivers/staging/rdma/ehca/hcp_if.h b/drivers/staging/rdma/ehca/hcp_if.h
deleted file mode 100644 (file)
index a46e514..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Firmware Infiniband Interface code for POWER
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Gerd Bayer <gerd.bayer@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __HCP_IF_H__
-#define __HCP_IF_H__
-
-#include "ehca_classes.h"
-#include "ehca_tools.h"
-#include "hipz_hw.h"
-
-/*
- * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initialize
- * resources, create the empty EQPT (ring).
- */
-u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_pfeq *pfeq,
-                            const u32 neq_control,
-                            const u32 number_of_entries,
-                            struct ipz_eq_handle *eq_handle,
-                            u32 * act_nr_of_entries,
-                            u32 * act_pages,
-                            u32 * eq_ist);
-
-u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
-                      struct ipz_eq_handle eq_handle,
-                      const u64 event_mask);
-/*
- * hipz_h_allocate_resource_cq allocates CQ resources in HW and FW, initialize
- * resources, create the empty CQPT (ring).
- */
-u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_cq *cq,
-                            struct ehca_alloc_cq_parms *param);
-
-
-/*
- * hipz_h_alloc_resource_qp allocates QP resources in HW and FW,
- * initialize resources, create empty QPPTs (2 rings).
- */
-u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
-                            struct ehca_alloc_qp_parms *parms, int is_user);
-
-u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
-                     const u8 port_id,
-                     struct hipz_query_port *query_port_response_block);
-
-u64 hipz_h_modify_port(const struct ipz_adapter_handle adapter_handle,
-                      const u8 port_id, const u32 port_cap,
-                      const u8 init_type, const int modify_mask);
-
-u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
-                    struct hipz_query_hca *query_hca_rblock);
-
-/*
- * hipz_h_register_rpage internal function in hcp_if.h for all
- * hcp_H_REGISTER_RPAGE calls.
- */
-u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
-                         const u8 pagesize,
-                         const u8 queue_type,
-                         const u64 resource_handle,
-                         const u64 logical_address_of_page,
-                         u64 count);
-
-u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_eq_handle eq_handle,
-                            struct ehca_pfeq *pfeq,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count);
-
-u64 hipz_h_query_int_state(const struct ipz_adapter_handle
-                          hcp_adapter_handle,
-                          u32 ist);
-
-u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_cq_handle cq_handle,
-                            struct ehca_pfcq *pfcq,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count,
-                            const struct h_galpa gal);
-
-u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
-                            const struct ipz_qp_handle qp_handle,
-                            struct ehca_pfqp *pfqp,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count,
-                            const struct h_galpa galpa);
-
-u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
-                              const struct ipz_qp_handle qp_handle,
-                              struct ehca_pfqp *pfqp,
-                              void **log_addr_next_sq_wqe_tb_processed,
-                              void **log_addr_next_rq_wqe_tb_processed,
-                              int dis_and_get_function_code);
-enum hcall_sigt {
-       HCALL_SIGT_NO_CQE = 0,
-       HCALL_SIGT_BY_WQE = 1,
-       HCALL_SIGT_EVERY = 2
-};
-
-u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
-                    const struct ipz_qp_handle qp_handle,
-                    struct ehca_pfqp *pfqp,
-                    const u64 update_mask,
-                    struct hcp_modify_qp_control_block *mqpcb,
-                    struct h_galpa gal);
-
-u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
-                   const struct ipz_qp_handle qp_handle,
-                   struct ehca_pfqp *pfqp,
-                   struct hcp_modify_qp_control_block *qqpcb,
-                   struct h_galpa gal);
-
-u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_qp *qp);
-
-u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u32 port);
-
-u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u32 port, u32 * pma_qp_nr,
-                      u32 * bma_qp_nr);
-
-u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u16 mcg_dlid,
-                      u64 subnet_prefix, u64 interface_id);
-
-u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
-                      const struct ipz_qp_handle qp_handle,
-                      struct h_galpa gal,
-                      u16 mcg_dlid,
-                      u64 subnet_prefix, u64 interface_id);
-
-u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_cq *cq,
-                     u8 force_flag);
-
-u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
-                     struct ehca_eq *eq);
-
-/*
- * hipz_h_alloc_resource_mr allocates MR resources in HW and FW, initialize
- * resources.
- */
-u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mr *mr,
-                            const u64 vaddr,
-                            const u64 length,
-                            const u32 access_ctrl,
-                            const struct ipz_pd pd,
-                            struct ehca_mr_hipzout_parms *outparms);
-
-/* hipz_h_register_rpage_mr registers MR resource pages in HW and FW */
-u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mr *mr,
-                            const u8 pagesize,
-                            const u8 queue_type,
-                            const u64 logical_address_of_page,
-                            const u64 count);
-
-/* hipz_h_query_mr queries MR in HW and FW */
-u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
-                   const struct ehca_mr *mr,
-                   struct ehca_mr_hipzout_parms *outparms);
-
-/* hipz_h_free_resource_mr frees MR resources in HW and FW */
-u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
-                           const struct ehca_mr *mr);
-
-/* hipz_h_reregister_pmr reregisters MR in HW and FW */
-u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
-                         const struct ehca_mr *mr,
-                         const u64 vaddr_in,
-                         const u64 length,
-                         const u32 access_ctrl,
-                         const struct ipz_pd pd,
-                         const u64 mr_addr_cb,
-                         struct ehca_mr_hipzout_parms *outparms);
-
-/* hipz_h_register_smr register shared MR in HW and FW */
-u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
-                       const struct ehca_mr *mr,
-                       const struct ehca_mr *orig_mr,
-                       const u64 vaddr_in,
-                       const u32 access_ctrl,
-                       const struct ipz_pd pd,
-                       struct ehca_mr_hipzout_parms *outparms);
-
-/*
- * hipz_h_alloc_resource_mw allocates MW resources in HW and FW, initialize
- * resources.
- */
-u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
-                            const struct ehca_mw *mw,
-                            const struct ipz_pd pd,
-                            struct ehca_mw_hipzout_parms *outparms);
-
-/* hipz_h_query_mw queries MW in HW and FW */
-u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
-                   const struct ehca_mw *mw,
-                   struct ehca_mw_hipzout_parms *outparms);
-
-/* hipz_h_free_resource_mw frees MW resources in HW and FW */
-u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
-                           const struct ehca_mw *mw);
-
-u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
-                     const u64 ressource_handle,
-                     void *rblock,
-                     unsigned long *byte_count);
-u64 hipz_h_eoi(int irq);
-
-#endif /* __HCP_IF_H__ */
diff --git a/drivers/staging/rdma/ehca/hcp_phyp.c b/drivers/staging/rdma/ehca/hcp_phyp.c
deleted file mode 100644 (file)
index 077376f..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *   load store abstraction for ehca register access with tracing
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ehca_classes.h"
-#include "hipz_hw.h"
-
-u64 hcall_map_page(u64 physaddr)
-{
-       return (u64)ioremap(physaddr, EHCA_PAGESIZE);
-}
-
-int hcall_unmap_page(u64 mapaddr)
-{
-       iounmap((volatile void __iomem *) mapaddr);
-       return 0;
-}
-
-int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
-                   u64 paddr_kernel, u64 paddr_user)
-{
-       if (!is_user) {
-               galpas->kernel.fw_handle = hcall_map_page(paddr_kernel);
-               if (!galpas->kernel.fw_handle)
-                       return -ENOMEM;
-       } else
-               galpas->kernel.fw_handle = 0;
-
-       galpas->user.fw_handle = paddr_user;
-
-       return 0;
-}
-
-int hcp_galpas_dtor(struct h_galpas *galpas)
-{
-       if (galpas->kernel.fw_handle) {
-               int ret = hcall_unmap_page(galpas->kernel.fw_handle);
-               if (ret)
-                       return ret;
-       }
-
-       galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
-
-       return 0;
-}
diff --git a/drivers/staging/rdma/ehca/hcp_phyp.h b/drivers/staging/rdma/ehca/hcp_phyp.h
deleted file mode 100644 (file)
index d1b0299..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  Firmware calls
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Waleri Fomin <fomin@de.ibm.com>
- *           Gerd Bayer <gerd.bayer@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __HCP_PHYP_H__
-#define __HCP_PHYP_H__
-
-
-/*
- * eHCA page (mapped into memory)
- * resource to access eHCA register pages in CPU address space
-*/
-struct h_galpa {
-       u64 fw_handle;
-       /* for pSeries this is a 64bit memory address where
-          I/O memory is mapped into CPU address space (kv) */
-};
-
-/*
- * resource to access eHCA address space registers, all types
- */
-struct h_galpas {
-       u32 pid;                /*PID of userspace galpa checking */
-       struct h_galpa user;    /* user space accessible resource,
-                                  set to 0 if unused */
-       struct h_galpa kernel;  /* kernel space accessible resource,
-                                  set to 0 if unused */
-};
-
-static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
-{
-       u64 addr = galpa.fw_handle + offset;
-       return *(volatile u64 __force *)addr;
-}
-
-static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
-{
-       u64 addr = galpa.fw_handle + offset;
-       *(volatile u64 __force *)addr = value;
-}
-
-int hcp_galpas_ctor(struct h_galpas *galpas, int is_user,
-                   u64 paddr_kernel, u64 paddr_user);
-
-int hcp_galpas_dtor(struct h_galpas *galpas);
-
-u64 hcall_map_page(u64 physaddr);
-
-int hcall_unmap_page(u64 mapaddr);
-
-#endif
diff --git a/drivers/staging/rdma/ehca/hipz_fns.h b/drivers/staging/rdma/ehca/hipz_fns.h
deleted file mode 100644 (file)
index 9dac93d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  HW abstraction register functions
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __HIPZ_FNS_H__
-#define __HIPZ_FNS_H__
-
-#include "ehca_classes.h"
-#include "hipz_hw.h"
-
-#include "hipz_fns_core.h"
-
-#define hipz_galpa_store_eq(gal, offset, value) \
-       hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value)
-
-#define hipz_galpa_load_eq(gal, offset) \
-       hipz_galpa_load(gal, EQTEMM_OFFSET(offset))
-
-#define hipz_galpa_store_qped(gal, offset, value) \
-       hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value)
-
-#define hipz_galpa_load_qped(gal, offset) \
-       hipz_galpa_load(gal, QPEDMM_OFFSET(offset))
-
-#define hipz_galpa_store_mrmw(gal, offset, value) \
-       hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value)
-
-#define hipz_galpa_load_mrmw(gal, offset) \
-       hipz_galpa_load(gal, MRMWMM_OFFSET(offset))
-
-#endif
diff --git a/drivers/staging/rdma/ehca/hipz_fns_core.h b/drivers/staging/rdma/ehca/hipz_fns_core.h
deleted file mode 100644 (file)
index 868735f..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  HW abstraction register functions
- *
- *  Authors: Christoph Raisch <raisch@de.ibm.com>
- *           Heiko J Schick <schickhj@de.ibm.com>
- *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __HIPZ_FNS_CORE_H__
-#define __HIPZ_FNS_CORE_H__
-
-#include "hcp_phyp.h"
-#include "hipz_hw.h"
-
-#define hipz_galpa_store_cq(gal, offset, value) \
-       hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value)
-
-#define hipz_galpa_load_cq(gal, offset) \
-       hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
-
-#define hipz_galpa_store_qp(gal, offset, value) \
-       hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
-#define hipz_galpa_load_qp(gal, offset) \
-       hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
-
-static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
-{
-       /*  ringing doorbell :-) */
-       hipz_galpa_store_qp(qp->galpas.kernel, qpx_sqa,
-                           EHCA_BMASK_SET(QPX_SQADDER, nr_wqes));
-}
-
-static inline void hipz_update_rqa(struct ehca_qp *qp, u16 nr_wqes)
-{
-       /*  ringing doorbell :-) */
-       hipz_galpa_store_qp(qp->galpas.kernel, qpx_rqa,
-                           EHCA_BMASK_SET(QPX_RQADDER, nr_wqes));
-}
-
-static inline void hipz_update_feca(struct ehca_cq *cq, u32 nr_cqes)
-{
-       hipz_galpa_store_cq(cq->galpas.kernel, cqx_feca,
-                           EHCA_BMASK_SET(CQX_FECADDER, nr_cqes));
-}
-
-static inline void hipz_set_cqx_n0(struct ehca_cq *cq, u32 value)
-{
-       u64 cqx_n0_reg;
-
-       hipz_galpa_store_cq(cq->galpas.kernel, cqx_n0,
-                           EHCA_BMASK_SET(CQX_N0_GENERATE_SOLICITED_COMP_EVENT,
-                                          value));
-       cqx_n0_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n0);
-}
-
-static inline void hipz_set_cqx_n1(struct ehca_cq *cq, u32 value)
-{
-       u64 cqx_n1_reg;
-
-       hipz_galpa_store_cq(cq->galpas.kernel, cqx_n1,
-                           EHCA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, value));
-       cqx_n1_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n1);
-}
-
-#endif /* __HIPZ_FNC_CORE_H__ */
diff --git a/drivers/staging/rdma/ehca/hipz_hw.h b/drivers/staging/rdma/ehca/hipz_hw.h
deleted file mode 100644 (file)
index bf996c7..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  eHCA register definitions
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __HIPZ_HW_H__
-#define __HIPZ_HW_H__
-
-#include "ehca_tools.h"
-
-#define EHCA_MAX_MTU 4
-
-/* QP Table Entry Memory Map */
-struct hipz_qptemm {
-       u64 qpx_hcr;
-       u64 qpx_c;
-       u64 qpx_herr;
-       u64 qpx_aer;
-/* 0x20*/
-       u64 qpx_sqa;
-       u64 qpx_sqc;
-       u64 qpx_rqa;
-       u64 qpx_rqc;
-/* 0x40*/
-       u64 qpx_st;
-       u64 qpx_pmstate;
-       u64 qpx_pmfa;
-       u64 qpx_pkey;
-/* 0x60*/
-       u64 qpx_pkeya;
-       u64 qpx_pkeyb;
-       u64 qpx_pkeyc;
-       u64 qpx_pkeyd;
-/* 0x80*/
-       u64 qpx_qkey;
-       u64 qpx_dqp;
-       u64 qpx_dlidp;
-       u64 qpx_portp;
-/* 0xa0*/
-       u64 qpx_slidp;
-       u64 qpx_slidpp;
-       u64 qpx_dlida;
-       u64 qpx_porta;
-/* 0xc0*/
-       u64 qpx_slida;
-       u64 qpx_slidpa;
-       u64 qpx_slvl;
-       u64 qpx_ipd;
-/* 0xe0*/
-       u64 qpx_mtu;
-       u64 qpx_lato;
-       u64 qpx_rlimit;
-       u64 qpx_rnrlimit;
-/* 0x100*/
-       u64 qpx_t;
-       u64 qpx_sqhp;
-       u64 qpx_sqptp;
-       u64 qpx_nspsn;
-/* 0x120*/
-       u64 qpx_nspsnhwm;
-       u64 reserved1;
-       u64 qpx_sdsi;
-       u64 qpx_sdsbc;
-/* 0x140*/
-       u64 qpx_sqwsize;
-       u64 qpx_sqwts;
-       u64 qpx_lsn;
-       u64 qpx_nssn;
-/* 0x160 */
-       u64 qpx_mor;
-       u64 qpx_cor;
-       u64 qpx_sqsize;
-       u64 qpx_erc;
-/* 0x180*/
-       u64 qpx_rnrrc;
-       u64 qpx_ernrwt;
-       u64 qpx_rnrresp;
-       u64 qpx_lmsna;
-/* 0x1a0 */
-       u64 qpx_sqhpc;
-       u64 qpx_sqcptp;
-       u64 qpx_sigt;
-       u64 qpx_wqecnt;
-/* 0x1c0*/
-       u64 qpx_rqhp;
-       u64 qpx_rqptp;
-       u64 qpx_rqsize;
-       u64 qpx_nrr;
-/* 0x1e0*/
-       u64 qpx_rdmac;
-       u64 qpx_nrpsn;
-       u64 qpx_lapsn;
-       u64 qpx_lcr;
-/* 0x200*/
-       u64 qpx_rwc;
-       u64 qpx_rwva;
-       u64 qpx_rdsi;
-       u64 qpx_rdsbc;
-/* 0x220*/
-       u64 qpx_rqwsize;
-       u64 qpx_crmsn;
-       u64 qpx_rdd;
-       u64 qpx_larpsn;
-/* 0x240*/
-       u64 qpx_pd;
-       u64 qpx_scqn;
-       u64 qpx_rcqn;
-       u64 qpx_aeqn;
-/* 0x260*/
-       u64 qpx_aaelog;
-       u64 qpx_ram;
-       u64 qpx_rdmaqe0;
-       u64 qpx_rdmaqe1;
-/* 0x280*/
-       u64 qpx_rdmaqe2;
-       u64 qpx_rdmaqe3;
-       u64 qpx_nrpsnhwm;
-/* 0x298*/
-       u64 reserved[(0x400 - 0x298) / 8];
-/* 0x400 extended data */
-       u64 reserved_ext[(0x500 - 0x400) / 8];
-/* 0x500 */
-       u64 reserved2[(0x1000 - 0x500) / 8];
-/* 0x1000      */
-};
-
-#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
-#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
-
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
-
-/* MRMWPT Entry Memory Map */
-struct hipz_mrmwmm {
-       /* 0x00 */
-       u64 mrx_hcr;
-
-       u64 mrx_c;
-       u64 mrx_herr;
-       u64 mrx_aer;
-       /* 0x20 */
-       u64 mrx_pp;
-       u64 reserved1;
-       u64 reserved2;
-       u64 reserved3;
-       /* 0x40 */
-       u64 reserved4[(0x200 - 0x40) / 8];
-       /* 0x200 */
-       u64 mrx_ctl[64];
-
-};
-
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
-
-struct hipz_qpedmm {
-       /* 0x00 */
-       u64 reserved0[(0x400) / 8];
-       /* 0x400 */
-       u64 qpedx_phh;
-       u64 qpedx_ppsgp;
-       /* 0x410 */
-       u64 qpedx_ppsgu;
-       u64 qpedx_ppdgp;
-       /* 0x420 */
-       u64 qpedx_ppdgu;
-       u64 qpedx_aph;
-       /* 0x430 */
-       u64 qpedx_apsgp;
-       u64 qpedx_apsgu;
-       /* 0x440 */
-       u64 qpedx_apdgp;
-       u64 qpedx_apdgu;
-       /* 0x450 */
-       u64 qpedx_apav;
-       u64 qpedx_apsav;
-       /* 0x460  */
-       u64 qpedx_hcr;
-       u64 reserved1[4];
-       /* 0x488 */
-       u64 qpedx_rrl0;
-       /* 0x490 */
-       u64 qpedx_rrrkey0;
-       u64 qpedx_rrva0;
-       /* 0x4a0 */
-       u64 reserved2;
-       u64 qpedx_rrl1;
-       /* 0x4b0 */
-       u64 qpedx_rrrkey1;
-       u64 qpedx_rrva1;
-       /* 0x4c0 */
-       u64 reserved3;
-       u64 qpedx_rrl2;
-       /* 0x4d0 */
-       u64 qpedx_rrrkey2;
-       u64 qpedx_rrva2;
-       /* 0x4e0 */
-       u64 reserved4;
-       u64 qpedx_rrl3;
-       /* 0x4f0 */
-       u64 qpedx_rrrkey3;
-       u64 qpedx_rrva3;
-};
-
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
-
-/* CQ Table Entry Memory Map */
-struct hipz_cqtemm {
-       u64 cqx_hcr;
-       u64 cqx_c;
-       u64 cqx_herr;
-       u64 cqx_aer;
-/* 0x20  */
-       u64 cqx_ptp;
-       u64 cqx_tp;
-       u64 cqx_fec;
-       u64 cqx_feca;
-/* 0x40  */
-       u64 cqx_ep;
-       u64 cqx_eq;
-/* 0x50  */
-       u64 reserved1;
-       u64 cqx_n0;
-/* 0x60  */
-       u64 cqx_n1;
-       u64 reserved2[(0x1000 - 0x60) / 8];
-/* 0x1000 */
-};
-
-#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32, 63)
-#define CQX_FECADDER              EHCA_BMASK_IBM(32, 63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
-
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
-
-/* EQ Table Entry Memory Map */
-struct hipz_eqtemm {
-       u64 eqx_hcr;
-       u64 eqx_c;
-
-       u64 eqx_herr;
-       u64 eqx_aer;
-/* 0x20 */
-       u64 eqx_ptp;
-       u64 eqx_tp;
-       u64 eqx_ssba;
-       u64 eqx_psba;
-
-/* 0x40 */
-       u64 eqx_cec;
-       u64 eqx_meql;
-       u64 eqx_xisbi;
-       u64 eqx_xisc;
-/* 0x60 */
-       u64 eqx_it;
-
-};
-
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
-
-/* access control defines for MR/MW */
-#define HIPZ_ACCESSCTRL_L_WRITE  0x00800000
-#define HIPZ_ACCESSCTRL_R_WRITE  0x00400000
-#define HIPZ_ACCESSCTRL_R_READ   0x00200000
-#define HIPZ_ACCESSCTRL_R_ATOMIC 0x00100000
-#define HIPZ_ACCESSCTRL_MW_BIND  0x00080000
-
-/* query hca response block */
-struct hipz_query_hca {
-       u32 cur_reliable_dg;
-       u32 cur_qp;
-       u32 cur_cq;
-       u32 cur_eq;
-       u32 cur_mr;
-       u32 cur_mw;
-       u32 cur_ee_context;
-       u32 cur_mcast_grp;
-       u32 cur_qp_attached_mcast_grp;
-       u32 reserved1;
-       u32 cur_ipv6_qp;
-       u32 cur_eth_qp;
-       u32 cur_hp_mr;
-       u32 reserved2[3];
-       u32 max_rd_domain;
-       u32 max_qp;
-       u32 max_cq;
-       u32 max_eq;
-       u32 max_mr;
-       u32 max_hp_mr;
-       u32 max_mw;
-       u32 max_mrwpte;
-       u32 max_special_mrwpte;
-       u32 max_rd_ee_context;
-       u32 max_mcast_grp;
-       u32 max_total_mcast_qp_attach;
-       u32 max_mcast_qp_attach;
-       u32 max_raw_ipv6_qp;
-       u32 max_raw_ethy_qp;
-       u32 internal_clock_frequency;
-       u32 max_pd;
-       u32 max_ah;
-       u32 max_cqe;
-       u32 max_wqes_wq;
-       u32 max_partitions;
-       u32 max_rr_ee_context;
-       u32 max_rr_qp;
-       u32 max_rr_hca;
-       u32 max_act_wqs_ee_context;
-       u32 max_act_wqs_qp;
-       u32 max_sge;
-       u32 max_sge_rd;
-       u32 memory_page_size_supported;
-       u64 max_mr_size;
-       u32 local_ca_ack_delay;
-       u32 num_ports;
-       u32 vendor_id;
-       u32 vendor_part_id;
-       u32 hw_ver;
-       u64 node_guid;
-       u64 hca_cap_indicators;
-       u32 data_counter_register_size;
-       u32 max_shared_rq;
-       u32 max_isns_eq;
-       u32 max_neq;
-} __attribute__ ((packed));
-
-#define HCA_CAP_AH_PORT_NR_CHECK      EHCA_BMASK_IBM( 0,  0)
-#define HCA_CAP_ATOMIC                EHCA_BMASK_IBM( 1,  1)
-#define HCA_CAP_AUTO_PATH_MIG         EHCA_BMASK_IBM( 2,  2)
-#define HCA_CAP_BAD_P_KEY_CTR         EHCA_BMASK_IBM( 3,  3)
-#define HCA_CAP_SQD_RTS_PORT_CHANGE   EHCA_BMASK_IBM( 4,  4)
-#define HCA_CAP_CUR_QP_STATE_MOD      EHCA_BMASK_IBM( 5,  5)
-#define HCA_CAP_INIT_TYPE             EHCA_BMASK_IBM( 6,  6)
-#define HCA_CAP_PORT_ACTIVE_EVENT     EHCA_BMASK_IBM( 7,  7)
-#define HCA_CAP_Q_KEY_VIOL_CTR        EHCA_BMASK_IBM( 8,  8)
-#define HCA_CAP_WQE_RESIZE            EHCA_BMASK_IBM( 9,  9)
-#define HCA_CAP_RAW_PACKET_MCAST      EHCA_BMASK_IBM(10, 10)
-#define HCA_CAP_SHUTDOWN_PORT         EHCA_BMASK_IBM(11, 11)
-#define HCA_CAP_RC_LL_QP              EHCA_BMASK_IBM(12, 12)
-#define HCA_CAP_SRQ                   EHCA_BMASK_IBM(13, 13)
-#define HCA_CAP_UD_LL_QP              EHCA_BMASK_IBM(16, 16)
-#define HCA_CAP_RESIZE_MR             EHCA_BMASK_IBM(17, 17)
-#define HCA_CAP_MINI_QP               EHCA_BMASK_IBM(18, 18)
-#define HCA_CAP_H_ALLOC_RES_SYNC      EHCA_BMASK_IBM(19, 19)
-
-/* query port response block */
-struct hipz_query_port {
-       u32 state;
-       u32 bad_pkey_cntr;
-       u32 lmc;
-       u32 lid;
-       u32 subnet_timeout;
-       u32 qkey_viol_cntr;
-       u32 sm_sl;
-       u32 sm_lid;
-       u32 capability_mask;
-       u32 init_type_reply;
-       u32 pkey_tbl_len;
-       u32 gid_tbl_len;
-       u64 gid_prefix;
-       u32 port_nr;
-       u16 pkey_entries[16];
-       u8  reserved1[32];
-       u32 trent_size;
-       u32 trbuf_size;
-       u64 max_msg_sz;
-       u32 max_mtu;
-       u32 vl_cap;
-       u32 phys_pstate;
-       u32 phys_state;
-       u32 phys_speed;
-       u32 phys_width;
-       u8  reserved2[1884];
-       u64 guid_entries[255];
-} __attribute__ ((packed));
-
-#endif
diff --git a/drivers/staging/rdma/ehca/ipz_pt_fn.c b/drivers/staging/rdma/ehca/ipz_pt_fn.c
deleted file mode 100644 (file)
index 7ffc748..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  internal queue handling
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <linux/slab.h>
-
-#include "ehca_tools.h"
-#include "ipz_pt_fn.h"
-#include "ehca_classes.h"
-
-#define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT)
-
-struct kmem_cache *small_qp_cache;
-
-void *ipz_qpageit_get_inc(struct ipz_queue *queue)
-{
-       void *ret = ipz_qeit_get(queue);
-       queue->current_q_offset += queue->pagesize;
-       if (queue->current_q_offset > queue->queue_length) {
-               queue->current_q_offset -= queue->pagesize;
-               ret = NULL;
-       }
-       if (((u64)ret) % queue->pagesize) {
-               ehca_gen_err("ERROR!! not at PAGE-Boundary");
-               return NULL;
-       }
-       return ret;
-}
-
-void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
-{
-       void *ret = ipz_qeit_get(queue);
-       u64 last_entry_in_q = queue->queue_length - queue->qe_size;
-
-       queue->current_q_offset += queue->qe_size;
-       if (queue->current_q_offset > last_entry_in_q) {
-               queue->current_q_offset = 0;
-               queue->toggle_state = (~queue->toggle_state) & 1;
-       }
-
-       return ret;
-}
-
-int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset)
-{
-       int i;
-       for (i = 0; i < queue->queue_length / queue->pagesize; i++) {
-               u64 page = __pa(queue->queue_pages[i]);
-               if (addr >= page && addr < page + queue->pagesize) {
-                       *q_offset = addr - page + i * queue->pagesize;
-                       return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-#if PAGE_SHIFT < EHCA_PAGESHIFT
-#error Kernel pages must be at least as large than eHCA pages (4K) !
-#endif
-
-/*
- * allocate pages for queue:
- * outer loop allocates whole kernel pages (page aligned) and
- * inner loop divides a kernel page into smaller hca queue pages
- */
-static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages)
-{
-       int k, f = 0;
-       u8 *kpage;
-
-       while (f < nr_of_pages) {
-               kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
-               if (!kpage)
-                       goto out;
-
-               for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) {
-                       queue->queue_pages[f] = (struct ipz_page *)kpage;
-                       kpage += EHCA_PAGESIZE;
-                       f++;
-               }
-       }
-       return 1;
-
-out:
-       for (f = 0; f < nr_of_pages && queue->queue_pages[f];
-            f += PAGES_PER_KPAGE)
-               free_page((unsigned long)(queue->queue_pages)[f]);
-       return 0;
-}
-
-static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
-{
-       int order = ilog2(queue->pagesize) - 9;
-       struct ipz_small_queue_page *page;
-       unsigned long bit;
-
-       mutex_lock(&pd->lock);
-
-       if (!list_empty(&pd->free[order]))
-               page = list_entry(pd->free[order].next,
-                                 struct ipz_small_queue_page, list);
-       else {
-               page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL);
-               if (!page)
-                       goto out;
-
-               page->page = get_zeroed_page(GFP_KERNEL);
-               if (!page->page) {
-                       kmem_cache_free(small_qp_cache, page);
-                       goto out;
-               }
-
-               list_add(&page->list, &pd->free[order]);
-       }
-
-       bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order);
-       __set_bit(bit, page->bitmap);
-       page->fill++;
-
-       if (page->fill == IPZ_SPAGE_PER_KPAGE >> order)
-               list_move(&page->list, &pd->full[order]);
-
-       mutex_unlock(&pd->lock);
-
-       queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
-       queue->small_page = page;
-       queue->offset = bit << (order + 9);
-       return 1;
-
-out:
-       ehca_err(pd->ib_pd.device, "failed to allocate small queue page");
-       mutex_unlock(&pd->lock);
-       return 0;
-}
-
-static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
-{
-       int order = ilog2(queue->pagesize) - 9;
-       struct ipz_small_queue_page *page = queue->small_page;
-       unsigned long bit;
-       int free_page = 0;
-
-       bit = ((unsigned long)queue->queue_pages[0] & ~PAGE_MASK)
-               >> (order + 9);
-
-       mutex_lock(&pd->lock);
-
-       __clear_bit(bit, page->bitmap);
-       page->fill--;
-
-       if (page->fill == 0) {
-               list_del(&page->list);
-               free_page = 1;
-       }
-
-       if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1)
-               /* the page was full until we freed the chunk */
-               list_move_tail(&page->list, &pd->free[order]);
-
-       mutex_unlock(&pd->lock);
-
-       if (free_page) {
-               free_page(page->page);
-               kmem_cache_free(small_qp_cache, page);
-       }
-}
-
-int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
-                  const u32 nr_of_pages, const u32 pagesize,
-                  const u32 qe_size, const u32 nr_of_sg,
-                  int is_small)
-{
-       if (pagesize > PAGE_SIZE) {
-               ehca_gen_err("FATAL ERROR: pagesize=%x "
-                            "is greater than kernel page size", pagesize);
-               return 0;
-       }
-
-       /* init queue fields */
-       queue->queue_length = nr_of_pages * pagesize;
-       queue->pagesize = pagesize;
-       queue->qe_size = qe_size;
-       queue->act_nr_of_sg = nr_of_sg;
-       queue->current_q_offset = 0;
-       queue->toggle_state = 1;
-       queue->small_page = NULL;
-
-       /* allocate queue page pointers */
-       queue->queue_pages = kzalloc(nr_of_pages * sizeof(void *),
-                                    GFP_KERNEL | __GFP_NOWARN);
-       if (!queue->queue_pages) {
-               queue->queue_pages = vzalloc(nr_of_pages * sizeof(void *));
-               if (!queue->queue_pages) {
-                       ehca_gen_err("Couldn't allocate queue page list");
-                       return 0;
-               }
-       }
-
-       /* allocate actual queue pages */
-       if (is_small) {
-               if (!alloc_small_queue_page(queue, pd))
-                       goto ipz_queue_ctor_exit0;
-       } else
-               if (!alloc_queue_pages(queue, nr_of_pages))
-                       goto ipz_queue_ctor_exit0;
-
-       return 1;
-
-ipz_queue_ctor_exit0:
-       ehca_gen_err("Couldn't alloc pages queue=%p "
-                "nr_of_pages=%x",  queue, nr_of_pages);
-       kvfree(queue->queue_pages);
-
-       return 0;
-}
-
-int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
-{
-       int i, nr_pages;
-
-       if (!queue || !queue->queue_pages) {
-               ehca_gen_dbg("queue or queue_pages is NULL");
-               return 0;
-       }
-
-       if (queue->small_page)
-               free_small_queue_page(queue, pd);
-       else {
-               nr_pages = queue->queue_length / queue->pagesize;
-               for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE)
-                       free_page((unsigned long)queue->queue_pages[i]);
-       }
-
-       kvfree(queue->queue_pages);
-
-       return 1;
-}
-
-int ehca_init_small_qp_cache(void)
-{
-       small_qp_cache = kmem_cache_create("ehca_cache_small_qp",
-                                          sizeof(struct ipz_small_queue_page),
-                                          0, SLAB_HWCACHE_ALIGN, NULL);
-       if (!small_qp_cache)
-               return -ENOMEM;
-
-       return 0;
-}
-
-void ehca_cleanup_small_qp_cache(void)
-{
-       kmem_cache_destroy(small_qp_cache);
-}
diff --git a/drivers/staging/rdma/ehca/ipz_pt_fn.h b/drivers/staging/rdma/ehca/ipz_pt_fn.h
deleted file mode 100644 (file)
index a801274..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- *  IBM eServer eHCA Infiniband device driver for Linux on POWER
- *
- *  internal queue handling
- *
- *  Authors: Waleri Fomin <fomin@de.ibm.com>
- *           Reinhard Ernst <rernst@de.ibm.com>
- *           Christoph Raisch <raisch@de.ibm.com>
- *
- *  Copyright (c) 2005 IBM Corporation
- *
- *  All rights reserved.
- *
- *  This source code is distributed under a dual license of GPL v2.0 and OpenIB
- *  BSD.
- *
- * OpenIB BSD License
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials
- * provided with the distribution.
- *
- * 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 __IPZ_PT_FN_H__
-#define __IPZ_PT_FN_H__
-
-#define EHCA_PAGESHIFT   12
-#define EHCA_PAGESIZE   4096UL
-#define EHCA_PAGEMASK   (~(EHCA_PAGESIZE-1))
-#define EHCA_PT_ENTRIES 512UL
-
-#include "ehca_tools.h"
-#include "ehca_qes.h"
-
-struct ehca_pd;
-struct ipz_small_queue_page;
-
-extern struct kmem_cache *small_qp_cache;
-
-/* struct generic ehca page */
-struct ipz_page {
-       u8 entries[EHCA_PAGESIZE];
-};
-
-#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)
-
-struct ipz_small_queue_page {
-       unsigned long page;
-       unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];
-       int fill;
-       void *mapped_addr;
-       u32 mmap_count;
-       struct list_head list;
-};
-
-/* struct generic queue in linux kernel virtual memory (kv) */
-struct ipz_queue {
-       u64 current_q_offset;   /* current queue entry */
-
-       struct ipz_page **queue_pages;  /* array of pages belonging to queue */
-       u32 qe_size;            /* queue entry size */
-       u32 act_nr_of_sg;
-       u32 queue_length;       /* queue length allocated in bytes */
-       u32 pagesize;
-       u32 toggle_state;       /* toggle flag - per page */
-       u32 offset; /* save offset within page for small_qp */
-       struct ipz_small_queue_page *small_page;
-};
-
-/*
- * return current Queue Entry for a certain q_offset
- * returns address (kv) of Queue Entry
- */
-static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
-{
-       struct ipz_page *current_page;
-       if (q_offset >= queue->queue_length)
-               return NULL;
-       current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];
-       return &current_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
-}
-
-/*
- * return current Queue Entry
- * returns address (kv) of Queue Entry
- */
-static inline void *ipz_qeit_get(struct ipz_queue *queue)
-{
-       return ipz_qeit_calc(queue, queue->current_q_offset);
-}
-
-/*
- * return current Queue Page , increment Queue Page iterator from
- * page to page in struct ipz_queue, last increment will return 0! and
- * NOT wrap
- * returns address (kv) of Queue Page
- * warning don't use in parallel with ipz_QE_get_inc()
- */
-void *ipz_qpageit_get_inc(struct ipz_queue *queue);
-
-/*
- * return current Queue Entry, increment Queue Entry iterator by one
- * step in struct ipz_queue, will wrap in ringbuffer
- * returns address (kv) of Queue Entry BEFORE increment
- * warning don't use in parallel with ipz_qpageit_get_inc()
- */
-static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
-{
-       void *ret = ipz_qeit_get(queue);
-       queue->current_q_offset += queue->qe_size;
-       if (queue->current_q_offset >= queue->queue_length) {
-               queue->current_q_offset = 0;
-               /* toggle the valid flag */
-               queue->toggle_state = (~queue->toggle_state) & 1;
-       }
-
-       return ret;
-}
-
-/*
- * return a bool indicating whether current Queue Entry is valid
- */
-static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
-{
-       struct ehca_cqe *cqe = ipz_qeit_get(queue);
-       return ((cqe->cqe_flags >> 7) == (queue->toggle_state & 1));
-}
-
-/*
- * return current Queue Entry, increment Queue Entry iterator by one
- * step in struct ipz_queue, will wrap in ringbuffer
- * returns address (kv) of Queue Entry BEFORE increment
- * returns 0 and does not increment, if wrong valid state
- * warning don't use in parallel with ipz_qpageit_get_inc()
- */
-static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
-{
-       return ipz_qeit_is_valid(queue) ? ipz_qeit_get_inc(queue) : NULL;
-}
-
-/*
- * returns and resets Queue Entry iterator
- * returns address (kv) of first Queue Entry
- */
-static inline void *ipz_qeit_reset(struct ipz_queue *queue)
-{
-       queue->current_q_offset = 0;
-       return ipz_qeit_get(queue);
-}
-
-/*
- * return the q_offset corresponding to an absolute address
- */
-int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset);
-
-/*
- * return the next queue offset. don't modify the queue.
- */
-static inline u64 ipz_queue_advance_offset(struct ipz_queue *queue, u64 offset)
-{
-       offset += queue->qe_size;
-       if (offset >= queue->queue_length) offset = 0;
-       return offset;
-}
-
-/* struct generic page table */
-struct ipz_pt {
-       u64 entries[EHCA_PT_ENTRIES];
-};
-
-/* struct page table for a queue, only to be used in pf */
-struct ipz_qpt {
-       /* queue page tables (kv), use u64 because we know the element length */
-       u64 *qpts;
-       u32 n_qpts;
-       u32 n_ptes;       /*  number of page table entries */
-       u64 *current_pte_addr;
-};
-
-/*
- * constructor for a ipz_queue_t, placement new for ipz_queue_t,
- * new for all dependent datastructors
- * all QP Tables are the same
- * flow:
- *    allocate+pin queue
- * see ipz_qpt_ctor()
- * returns true if ok, false if out of memory
- */
-int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
-                  const u32 nr_of_pages, const u32 pagesize,
-                  const u32 qe_size, const u32 nr_of_sg,
-                  int is_small);
-
-/*
- * destructor for a ipz_queue_t
- *  -# free queue
- *  see ipz_queue_ctor()
- *  returns true if ok, false if queue was NULL-ptr of free failed
- */
-int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);
-
-/*
- * constructor for a ipz_qpt_t,
- * placement new for struct ipz_queue, new for all dependent datastructors
- * all QP Tables are the same,
- * flow:
- * -# allocate+pin queue
- * -# initialise ptcb
- * -# allocate+pin PTs
- * -# link PTs to a ring, according to HCA Arch, set bit62 id needed
- * -# the ring must have room for exactly nr_of_PTEs
- * see ipz_qpt_ctor()
- */
-void ipz_qpt_ctor(struct ipz_qpt *qpt,
-                 const u32 nr_of_qes,
-                 const u32 pagesize,
-                 const u32 qe_size,
-                 const u8 lowbyte, const u8 toggle,
-                 u32 * act_nr_of_QEs, u32 * act_nr_of_pages);
-
-/*
- * return current Queue Entry, increment Queue Entry iterator by one
- * step in struct ipz_queue, will wrap in ringbuffer
- * returns address (kv) of Queue Entry BEFORE increment
- * warning don't use in parallel with ipz_qpageit_get_inc()
- * warning unpredictable results may occur if steps>act_nr_of_queue_entries
- * fix EQ page problems
- */
-void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
-
-/*
- * return current Event Queue Entry, increment Queue Entry iterator
- * by one step in struct ipz_queue if valid, will wrap in ringbuffer
- * returns address (kv) of Queue Entry BEFORE increment
- * returns 0 and does not increment, if wrong valid state
- * warning don't use in parallel with ipz_queue_QPageit_get_inc()
- * warning unpredictable results may occur if steps>act_nr_of_queue_entries
- */
-static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
-{
-       void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *)ret;
-       if ((qe >> 7) != (queue->toggle_state & 1))
-               return NULL;
-       ipz_qeit_eq_get_inc(queue); /* this is a good one */
-       return ret;
-}
-
-static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
-{
-       void *ret = ipz_qeit_get(queue);
-       u32 qe = *(u8 *)ret;
-       if ((qe >> 7) != (queue->toggle_state & 1))
-               return NULL;
-       return ret;
-}
-
-/* returns address (GX) of first queue entry */
-static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
-{
-       return be64_to_cpu(qpt->qpts[0]);
-}
-
-/* returns address (kv) of first page of queue page table */
-static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt)
-{
-       return qpt->qpts;
-}
-
-#endif                         /* __IPZ_PT_FN_H__ */
diff --git a/drivers/staging/rdma/ipath/Kconfig b/drivers/staging/rdma/ipath/Kconfig
deleted file mode 100644 (file)
index 041ce06..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-config INFINIBAND_IPATH
-       tristate "QLogic HTX HCA support"
-       depends on 64BIT && NET && HT_IRQ
-       ---help---
-       This is a driver for the deprecated QLogic Hyper-Transport
-       IB host channel adapter (model QHT7140),
-       including InfiniBand verbs support.  This driver allows these
-       devices to be used with both kernel upper level protocols such
-       as IP-over-InfiniBand as well as with userspace applications
-       (in conjunction with InfiniBand userspace access).
-       For QLogic PCIe QLE based cards, use the QIB driver instead.
-
-       If you have this hardware you will need to boot with PAT disabled
-       on your x86-64 systems, use the nopat kernel parameter.
-
-       Note that this driver will soon be removed entirely from the kernel.
diff --git a/drivers/staging/rdma/ipath/Makefile b/drivers/staging/rdma/ipath/Makefile
deleted file mode 100644 (file)
index 4496f28..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-ccflags-y := -DIPATH_IDSTR='"QLogic kernel.org driver"' \
-       -DIPATH_KERN_TYPE=0
-
-obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
-
-ib_ipath-y := \
-       ipath_cq.o \
-       ipath_diag.o \
-       ipath_dma.o \
-       ipath_driver.o \
-       ipath_eeprom.o \
-       ipath_file_ops.o \
-       ipath_fs.o \
-       ipath_init_chip.o \
-       ipath_intr.o \
-       ipath_keys.o \
-       ipath_mad.o \
-       ipath_mmap.o \
-       ipath_mr.o \
-       ipath_qp.o \
-       ipath_rc.o \
-       ipath_ruc.o \
-       ipath_sdma.o \
-       ipath_srq.o \
-       ipath_stats.o \
-       ipath_sysfs.o \
-       ipath_uc.o \
-       ipath_ud.o \
-       ipath_user_pages.o \
-       ipath_user_sdma.o \
-       ipath_verbs_mcast.o \
-       ipath_verbs.o
-
-ib_ipath-$(CONFIG_HT_IRQ) += ipath_iba6110.o
-
-ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
-ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
diff --git a/drivers/staging/rdma/ipath/TODO b/drivers/staging/rdma/ipath/TODO
deleted file mode 100644 (file)
index cb00158..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-The ipath driver has been moved to staging in preparation for its removal in a
-few releases. The driver will be deleted during the 4.6 merge window.
-
-Contact Dennis Dalessandro <dennis.dalessandro@intel.com> and
-Cc: linux-rdma@vger.kernel.org
diff --git a/drivers/staging/rdma/ipath/ipath_common.h b/drivers/staging/rdma/ipath/ipath_common.h
deleted file mode 100644 (file)
index 28cfe97..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _IPATH_COMMON_H
-#define _IPATH_COMMON_H
-
-/*
- * This file contains defines, structures, etc. that are used
- * to communicate between kernel and user code.
- */
-
-
-/* This is the IEEE-assigned OUI for QLogic Inc. InfiniPath */
-#define IPATH_SRC_OUI_1 0x00
-#define IPATH_SRC_OUI_2 0x11
-#define IPATH_SRC_OUI_3 0x75
-
-/* version of protocol header (known to chip also). In the long run,
- * we should be able to generate and accept a range of version numbers;
- * for now we only accept one, and it's compiled in.
- */
-#define IPS_PROTO_VERSION 2
-
-/*
- * These are compile time constants that you may want to enable or disable
- * if you are trying to debug problems with code or performance.
- * IPATH_VERBOSE_TRACING define as 1 if you want additional tracing in
- * fastpath code
- * IPATH_TRACE_REGWRITES define as 1 if you want register writes to be
- * traced in faspath code
- * _IPATH_TRACING define as 0 if you want to remove all tracing in a
- * compilation unit
- * _IPATH_DEBUGGING define as 0 if you want to remove debug prints
- */
-
-/*
- * The value in the BTH QP field that InfiniPath uses to differentiate
- * an infinipath protocol IB packet vs standard IB transport
- */
-#define IPATH_KD_QP 0x656b79
-
-/*
- * valid states passed to ipath_set_linkstate() user call
- */
-#define IPATH_IB_LINKDOWN              0
-#define IPATH_IB_LINKARM               1
-#define IPATH_IB_LINKACTIVE            2
-#define IPATH_IB_LINKDOWN_ONLY         3
-#define IPATH_IB_LINKDOWN_SLEEP                4
-#define IPATH_IB_LINKDOWN_DISABLE      5
-#define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */
-#define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */
-#define IPATH_IB_LINK_NO_HRTBT 8 /* disable Heartbeat, e.g. for loopback */
-#define IPATH_IB_LINK_HRTBT    9 /* enable heartbeat, normal, non-loopback */
-
-/*
- * These 3 values (SDR and DDR may be ORed for auto-speed
- * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
- * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
- * are also the the possible values for ipath_link_speed_enabled and active
- * The values were chosen to match values used within the IB spec.
- */
-#define IPATH_IB_SDR 1
-#define IPATH_IB_DDR 2
-
-/*
- * stats maintained by the driver.  For now, at least, this is global
- * to all minor devices.
- */
-struct infinipath_stats {
-       /* number of interrupts taken */
-       __u64 sps_ints;
-       /* number of interrupts for errors */
-       __u64 sps_errints;
-       /* number of errors from chip (not incl. packet errors or CRC) */
-       __u64 sps_errs;
-       /* number of packet errors from chip other than CRC */
-       __u64 sps_pkterrs;
-       /* number of packets with CRC errors (ICRC and VCRC) */
-       __u64 sps_crcerrs;
-       /* number of hardware errors reported (parity, etc.) */
-       __u64 sps_hwerrs;
-       /* number of times IB link changed state unexpectedly */
-       __u64 sps_iblink;
-       __u64 sps_unused; /* was fastrcvint, no longer implemented */
-       /* number of kernel (port0) packets received */
-       __u64 sps_port0pkts;
-       /* number of "ethernet" packets sent by driver */
-       __u64 sps_ether_spkts;
-       /* number of "ethernet" packets received by driver */
-       __u64 sps_ether_rpkts;
-       /* number of SMA packets sent by driver. Obsolete. */
-       __u64 sps_sma_spkts;
-       /* number of SMA packets received by driver. Obsolete. */
-       __u64 sps_sma_rpkts;
-       /* number of times all ports rcvhdrq was full and packet dropped */
-       __u64 sps_hdrqfull;
-       /* number of times all ports egrtid was full and packet dropped */
-       __u64 sps_etidfull;
-       /*
-        * number of times we tried to send from driver, but no pio buffers
-        * avail
-        */
-       __u64 sps_nopiobufs;
-       /* number of ports currently open */
-       __u64 sps_ports;
-       /* list of pkeys (other than default) accepted (0 means not set) */
-       __u16 sps_pkeys[4];
-       __u16 sps_unused16[4]; /* available; maintaining compatible layout */
-       /* number of user ports per chip (not IB ports) */
-       __u32 sps_nports;
-       /* not our interrupt, or already handled */
-       __u32 sps_nullintr;
-       /* max number of packets handled per receive call */
-       __u32 sps_maxpkts_call;
-       /* avg number of packets handled per receive call */
-       __u32 sps_avgpkts_call;
-       /* total number of pages locked */
-       __u64 sps_pagelocks;
-       /* total number of pages unlocked */
-       __u64 sps_pageunlocks;
-       /*
-        * Number of packets dropped in kernel other than errors (ether
-        * packets if ipath not configured, etc.)
-        */
-       __u64 sps_krdrops;
-       __u64 sps_txeparity; /* PIO buffer parity error, recovered */
-       /* pad for future growth */
-       __u64 __sps_pad[45];
-};
-
-/*
- * These are the status bits readable (in ascii form, 64bit value)
- * from the "status" sysfs file.
- */
-#define IPATH_STATUS_INITTED       0x1 /* basic initialization done */
-#define IPATH_STATUS_DISABLED      0x2 /* hardware disabled */
-/* Device has been disabled via admin request */
-#define IPATH_STATUS_ADMIN_DISABLED    0x4
-/* Chip has been found and initted */
-#define IPATH_STATUS_CHIP_PRESENT 0x20
-/* IB link is at ACTIVE, usable for data traffic */
-#define IPATH_STATUS_IB_READY     0x40
-/* link is configured, LID, MTU, etc. have been set */
-#define IPATH_STATUS_IB_CONF      0x80
-/* no link established, probably no cable */
-#define IPATH_STATUS_IB_NOCABLE  0x100
-/* A Fatal hardware error has occurred. */
-#define IPATH_STATUS_HWERROR     0x200
-
-/*
- * The list of usermode accessible registers.  Also see Reg_* later in file.
- */
-typedef enum _ipath_ureg {
-       /* (RO)  DMA RcvHdr to be used next. */
-       ur_rcvhdrtail = 0,
-       /* (RW)  RcvHdr entry to be processed next by host. */
-       ur_rcvhdrhead = 1,
-       /* (RO)  Index of next Eager index to use. */
-       ur_rcvegrindextail = 2,
-       /* (RW)  Eager TID to be processed next */
-       ur_rcvegrindexhead = 3,
-       /* For internal use only; max register number. */
-       _IPATH_UregMax
-} ipath_ureg;
-
-/* bit values for spi_runtime_flags */
-#define IPATH_RUNTIME_HT       0x1
-#define IPATH_RUNTIME_PCIE     0x2
-#define IPATH_RUNTIME_FORCE_WC_ORDER   0x4
-#define IPATH_RUNTIME_RCVHDR_COPY      0x8
-#define IPATH_RUNTIME_MASTER   0x10
-#define IPATH_RUNTIME_NODMA_RTAIL 0x80
-#define IPATH_RUNTIME_SDMA           0x200
-#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400
-#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800
-
-/*
- * This structure is returned by ipath_userinit() immediately after
- * open to get implementation-specific info, and info specific to this
- * instance.
- *
- * This struct must have explict pad fields where type sizes
- * may result in different alignments between 32 and 64 bit
- * programs, since the 64 bit * bit kernel requires the user code
- * to have matching offsets
- */
-struct ipath_base_info {
-       /* version of hardware, for feature checking. */
-       __u32 spi_hw_version;
-       /* version of software, for feature checking. */
-       __u32 spi_sw_version;
-       /* InfiniPath port assigned, goes into sent packets */
-       __u16 spi_port;
-       __u16 spi_subport;
-       /*
-        * IB MTU, packets IB data must be less than this.
-        * The MTU is in bytes, and will be a multiple of 4 bytes.
-        */
-       __u32 spi_mtu;
-       /*
-        * Size of a PIO buffer.  Any given packet's total size must be less
-        * than this (in words).  Included is the starting control word, so
-        * if 513 is returned, then total pkt size is 512 words or less.
-        */
-       __u32 spi_piosize;
-       /* size of the TID cache in infinipath, in entries */
-       __u32 spi_tidcnt;
-       /* size of the TID Eager list in infinipath, in entries */
-       __u32 spi_tidegrcnt;
-       /* size of a single receive header queue entry in words. */
-       __u32 spi_rcvhdrent_size;
-       /*
-        * Count of receive header queue entries allocated.
-        * This may be less than the spu_rcvhdrcnt passed in!.
-        */
-       __u32 spi_rcvhdr_cnt;
-
-       /* per-chip and other runtime features bitmap (IPATH_RUNTIME_*) */
-       __u32 spi_runtime_flags;
-
-       /* address where receive buffer queue is mapped into */
-       __u64 spi_rcvhdr_base;
-
-       /* user program. */
-
-       /* base address of eager TID receive buffers. */
-       __u64 spi_rcv_egrbufs;
-
-       /* Allocated by initialization code, not by protocol. */
-
-       /*
-        * Size of each TID buffer in host memory, starting at
-        * spi_rcv_egrbufs.  The buffers are virtually contiguous.
-        */
-       __u32 spi_rcv_egrbufsize;
-       /*
-        * The special QP (queue pair) value that identifies an infinipath
-        * protocol packet from standard IB packets.  More, probably much
-        * more, to be added.
-        */
-       __u32 spi_qpair;
-
-       /*
-        * User register base for init code, not to be used directly by
-        * protocol or applications.
-        */
-       __u64 __spi_uregbase;
-       /*
-        * Maximum buffer size in bytes that can be used in a single TID
-        * entry (assuming the buffer is aligned to this boundary).  This is
-        * the minimum of what the hardware and software support Guaranteed
-        * to be a power of 2.
-        */
-       __u32 spi_tid_maxsize;
-       /*
-        * alignment of each pio send buffer (byte count
-        * to add to spi_piobufbase to get to second buffer)
-        */
-       __u32 spi_pioalign;
-       /*
-        * The index of the first pio buffer available to this process;
-        * needed to do lookup in spi_pioavailaddr; not added to
-        * spi_piobufbase.
-        */
-       __u32 spi_pioindex;
-        /* number of buffers mapped for this process */
-       __u32 spi_piocnt;
-
-       /*
-        * Base address of writeonly pio buffers for this process.
-        * Each buffer has spi_piosize words, and is aligned on spi_pioalign
-        * boundaries.  spi_piocnt buffers are mapped from this address
-        */
-       __u64 spi_piobufbase;
-
-       /*
-        * Base address of readonly memory copy of the pioavail registers.
-        * There are 2 bits for each buffer.
-        */
-       __u64 spi_pioavailaddr;
-
-       /*
-        * Address where driver updates a copy of the interface and driver
-        * status (IPATH_STATUS_*) as a 64 bit value.  It's followed by a
-        * string indicating hardware error, if there was one.
-        */
-       __u64 spi_status;
-
-       /* number of chip ports available to user processes */
-       __u32 spi_nports;
-       /* unit number of chip we are using */
-       __u32 spi_unit;
-       /* num bufs in each contiguous set */
-       __u32 spi_rcv_egrperchunk;
-       /* size in bytes of each contiguous set */
-       __u32 spi_rcv_egrchunksize;
-       /* total size of mmap to cover full rcvegrbuffers */
-       __u32 spi_rcv_egrbuftotlen;
-       __u32 spi_filler_for_align;
-       /* address of readonly memory copy of the rcvhdrq tail register. */
-       __u64 spi_rcvhdr_tailaddr;
-
-       /* shared memory pages for subports if port is shared */
-       __u64 spi_subport_uregbase;
-       __u64 spi_subport_rcvegrbuf;
-       __u64 spi_subport_rcvhdr_base;
-
-       /* shared memory page for hardware port if it is shared */
-       __u64 spi_port_uregbase;
-       __u64 spi_port_rcvegrbuf;
-       __u64 spi_port_rcvhdr_base;
-       __u64 spi_port_rcvhdr_tailaddr;
-
-} __attribute__ ((aligned(8)));
-
-
-/*
- * This version number is given to the driver by the user code during
- * initialization in the spu_userversion field of ipath_user_info, so
- * the driver can check for compatibility with user code.
- *
- * The major version changes when data structures
- * change in an incompatible way.  The driver must be the same or higher
- * for initialization to succeed.  In some cases, a higher version
- * driver will not interoperate with older software, and initialization
- * will return an error.
- */
-#define IPATH_USER_SWMAJOR 1
-
-/*
- * Minor version differences are always compatible
- * a within a major version, however if user software is larger
- * than driver software, some new features and/or structure fields
- * may not be implemented; the user code must deal with this if it
- * cares, or it must abort after initialization reports the difference.
- */
-#define IPATH_USER_SWMINOR 6
-
-#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
-
-#define IPATH_KERN_TYPE 0
-
-/*
- * Similarly, this is the kernel version going back to the user.  It's
- * slightly different, in that we want to tell if the driver was built as
- * part of a QLogic release, or from the driver from openfabrics.org,
- * kernel.org, or a standard distribution, for support reasons.
- * The high bit is 0 for non-QLogic and 1 for QLogic-built/supplied.
- *
- * It's returned by the driver to the user code during initialization in the
- * spi_sw_version field of ipath_base_info, so the user code can in turn
- * check for compatibility with the kernel.
-*/
-#define IPATH_KERN_SWVERSION ((IPATH_KERN_TYPE<<31) | IPATH_USER_SWVERSION)
-
-/*
- * This structure is passed to ipath_userinit() to tell the driver where
- * user code buffers are, sizes, etc.   The offsets and sizes of the
- * fields must remain unchanged, for binary compatibility.  It can
- * be extended, if userversion is changed so user code can tell, if needed
- */
-struct ipath_user_info {
-       /*
-        * version of user software, to detect compatibility issues.
-        * Should be set to IPATH_USER_SWVERSION.
-        */
-       __u32 spu_userversion;
-
-       /* desired number of receive header queue entries */
-       __u32 spu_rcvhdrcnt;
-
-       /* size of struct base_info to write to */
-       __u32 spu_base_info_size;
-
-       /*
-        * number of words in KD protocol header
-        * This tells InfiniPath how many words to copy to rcvhdrq.  If 0,
-        * kernel uses a default.  Once set, attempts to set any other value
-        * are an error (EAGAIN) until driver is reloaded.
-        */
-       __u32 spu_rcvhdrsize;
-
-       /*
-        * If two or more processes wish to share a port, each process
-        * must set the spu_subport_cnt and spu_subport_id to the same
-        * values.  The only restriction on the spu_subport_id is that
-        * it be unique for a given node.
-        */
-       __u16 spu_subport_cnt;
-       __u16 spu_subport_id;
-
-       __u32 spu_unused; /* kept for compatible layout */
-
-       /*
-        * address of struct base_info to write to
-        */
-       __u64 spu_base_info;
-
-} __attribute__ ((aligned(8)));
-
-/* User commands. */
-
-#define IPATH_CMD_MIN          16
-
-#define __IPATH_CMD_USER_INIT  16      /* old set up userspace (for old user code) */
-#define IPATH_CMD_PORT_INFO    17      /* find out what resources we got */
-#define IPATH_CMD_RECV_CTRL    18      /* control receipt of packets */
-#define IPATH_CMD_TID_UPDATE   19      /* update expected TID entries */
-#define IPATH_CMD_TID_FREE     20      /* free expected TID entries */
-#define IPATH_CMD_SET_PART_KEY 21      /* add partition key */
-#define __IPATH_CMD_SLAVE_INFO 22      /* return info on slave processes (for old user code) */
-#define IPATH_CMD_ASSIGN_PORT  23      /* allocate HCA and port */
-#define IPATH_CMD_USER_INIT    24      /* set up userspace */
-#define IPATH_CMD_UNUSED_1     25
-#define IPATH_CMD_UNUSED_2     26
-#define IPATH_CMD_PIOAVAILUPD  27      /* force an update of PIOAvail reg */
-#define IPATH_CMD_POLL_TYPE    28      /* set the kind of polling we want */
-#define IPATH_CMD_ARMLAUNCH_CTRL       29 /* armlaunch detection control */
-/* 30 is unused */
-#define IPATH_CMD_SDMA_INFLIGHT 31     /* sdma inflight counter request */
-#define IPATH_CMD_SDMA_COMPLETE 32     /* sdma completion counter request */
-
-/*
- * Poll types
- */
-#define IPATH_POLL_TYPE_URGENT  0x01
-#define IPATH_POLL_TYPE_OVERFLOW 0x02
-
-struct ipath_port_info {
-       __u32 num_active;       /* number of active units */
-       __u32 unit;             /* unit (chip) assigned to caller */
-       __u16 port;             /* port on unit assigned to caller */
-       __u16 subport;          /* subport on unit assigned to caller */
-       __u16 num_ports;        /* number of ports available on unit */
-       __u16 num_subports;     /* number of subports opened on port */
-};
-
-struct ipath_tid_info {
-       __u32 tidcnt;
-       /* make structure same size in 32 and 64 bit */
-       __u32 tid__unused;
-       /* virtual address of first page in transfer */
-       __u64 tidvaddr;
-       /* pointer (same size 32/64 bit) to __u16 tid array */
-       __u64 tidlist;
-
-       /*
-        * pointer (same size 32/64 bit) to bitmap of TIDs used
-        * for this call; checked for being large enough at open
-        */
-       __u64 tidmap;
-};
-
-struct ipath_cmd {
-       __u32 type;                     /* command type */
-       union {
-               struct ipath_tid_info tid_info;
-               struct ipath_user_info user_info;
-
-               /*
-                * address in userspace where we should put the sdma
-                * inflight counter
-                */
-               __u64 sdma_inflight;
-               /*
-                * address in userspace where we should put the sdma
-                * completion counter
-                */
-               __u64 sdma_complete;
-               /* address in userspace of struct ipath_port_info to
-                  write result to */
-               __u64 port_info;
-               /* enable/disable receipt of packets */
-               __u32 recv_ctrl;
-               /* enable/disable armlaunch errors (non-zero to enable) */
-               __u32 armlaunch_ctrl;
-               /* partition key to set */
-               __u16 part_key;
-               /* user address of __u32 bitmask of active slaves */
-               __u64 slave_mask_addr;
-               /* type of polling we want */
-               __u16 poll_type;
-       } cmd;
-};
-
-struct ipath_iovec {
-       /* Pointer to data, but same size 32 and 64 bit */
-       __u64 iov_base;
-
-       /*
-        * Length of data; don't need 64 bits, but want
-        * ipath_sendpkt to remain same size as before 32 bit changes, so...
-        */
-       __u64 iov_len;
-};
-
-/*
- * Describes a single packet for send.  Each packet can have one or more
- * buffers, but the total length (exclusive of IB headers) must be less
- * than the MTU, and if using the PIO method, entire packet length,
- * including IB headers, must be less than the ipath_piosize value (words).
- * Use of this necessitates including sys/uio.h
- */
-struct __ipath_sendpkt {
-       __u32 sps_flags;        /* flags for packet (TBD) */
-       __u32 sps_cnt;          /* number of entries to use in sps_iov */
-       /* array of iov's describing packet. TEMPORARY */
-       struct ipath_iovec sps_iov[4];
-};
-
-/*
- * diagnostics can send a packet by "writing" one of the following
- * two structs to diag data special file
- * The first is the legacy version for backward compatibility
- */
-struct ipath_diag_pkt {
-       __u32 unit;
-       __u64 data;
-       __u32 len;
-};
-
-/* The second diag_pkt struct is the expanded version that allows
- * more control over the packet, specifically, by allowing a custom
- * pbc (+ static rate) qword, so that special modes and deliberate
- * changes to CRCs can be used. The elements were also re-ordered
- * for better alignment and to avoid padding issues.
- */
-struct ipath_diag_xpkt {
-       __u64 data;
-       __u64 pbc_wd;
-       __u32 unit;
-       __u32 len;
-};
-
-/*
- * Data layout in I2C flash (for GUID, etc.)
- * All fields are little-endian binary unless otherwise stated
- */
-#define IPATH_FLASH_VERSION 2
-struct ipath_flash {
-       /* flash layout version (IPATH_FLASH_VERSION) */
-       __u8 if_fversion;
-       /* checksum protecting if_length bytes */
-       __u8 if_csum;
-       /*
-        * valid length (in use, protected by if_csum), including
-        * if_fversion and if_csum themselves)
-        */
-       __u8 if_length;
-       /* the GUID, in network order */
-       __u8 if_guid[8];
-       /* number of GUIDs to use, starting from if_guid */
-       __u8 if_numguid;
-       /* the (last 10 characters of) board serial number, in ASCII */
-       char if_serial[12];
-       /* board mfg date (YYYYMMDD ASCII) */
-       char if_mfgdate[8];
-       /* last board rework/test date (YYYYMMDD ASCII) */
-       char if_testdate[8];
-       /* logging of error counts, TBD */
-       __u8 if_errcntp[4];
-       /* powered on hours, updated at driver unload */
-       __u8 if_powerhour[2];
-       /* ASCII free-form comment field */
-       char if_comment[32];
-       /* Backwards compatible prefix for longer QLogic Serial Numbers */
-       char if_sprefix[4];
-       /* 82 bytes used, min flash size is 128 bytes */
-       __u8 if_future[46];
-};
-
-/*
- * These are the counters implemented in the chip, and are listed in order.
- * The InterCaps naming is taken straight from the chip spec.
- */
-struct infinipath_counters {
-       __u64 LBIntCnt;
-       __u64 LBFlowStallCnt;
-       __u64 TxSDmaDescCnt;    /* was Reserved1 */
-       __u64 TxUnsupVLErrCnt;
-       __u64 TxDataPktCnt;
-       __u64 TxFlowPktCnt;
-       __u64 TxDwordCnt;
-       __u64 TxLenErrCnt;
-       __u64 TxMaxMinLenErrCnt;
-       __u64 TxUnderrunCnt;
-       __u64 TxFlowStallCnt;
-       __u64 TxDroppedPktCnt;
-       __u64 RxDroppedPktCnt;
-       __u64 RxDataPktCnt;
-       __u64 RxFlowPktCnt;
-       __u64 RxDwordCnt;
-       __u64 RxLenErrCnt;
-       __u64 RxMaxMinLenErrCnt;
-       __u64 RxICRCErrCnt;
-       __u64 RxVCRCErrCnt;
-       __u64 RxFlowCtrlErrCnt;
-       __u64 RxBadFormatCnt;
-       __u64 RxLinkProblemCnt;
-       __u64 RxEBPCnt;
-       __u64 RxLPCRCErrCnt;
-       __u64 RxBufOvflCnt;
-       __u64 RxTIDFullErrCnt;
-       __u64 RxTIDValidErrCnt;
-       __u64 RxPKeyMismatchCnt;
-       __u64 RxP0HdrEgrOvflCnt;
-       __u64 RxP1HdrEgrOvflCnt;
-       __u64 RxP2HdrEgrOvflCnt;
-       __u64 RxP3HdrEgrOvflCnt;
-       __u64 RxP4HdrEgrOvflCnt;
-       __u64 RxP5HdrEgrOvflCnt;
-       __u64 RxP6HdrEgrOvflCnt;
-       __u64 RxP7HdrEgrOvflCnt;
-       __u64 RxP8HdrEgrOvflCnt;
-       __u64 RxP9HdrEgrOvflCnt;        /* was Reserved6 */
-       __u64 RxP10HdrEgrOvflCnt;       /* was Reserved7 */
-       __u64 RxP11HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP12HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP13HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP14HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP15HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 RxP16HdrEgrOvflCnt;       /* new for IBA7220 */
-       __u64 IBStatusChangeCnt;
-       __u64 IBLinkErrRecoveryCnt;
-       __u64 IBLinkDownedCnt;
-       __u64 IBSymbolErrCnt;
-       /* The following are new for IBA7220 */
-       __u64 RxVL15DroppedPktCnt;
-       __u64 RxOtherLocalPhyErrCnt;
-       __u64 PcieRetryBufDiagQwordCnt;
-       __u64 ExcessBufferOvflCnt;
-       __u64 LocalLinkIntegrityErrCnt;
-       __u64 RxVlErrCnt;
-       __u64 RxDlidFltrCnt;
-};
-
-/*
- * The next set of defines are for packet headers, and chip register
- * and memory bits that are visible to and/or used by user-mode software
- * The other bits that are used only by the driver or diags are in
- * ipath_registers.h
- */
-
-/* RcvHdrFlags bits */
-#define INFINIPATH_RHF_LENGTH_MASK 0x7FF
-#define INFINIPATH_RHF_LENGTH_SHIFT 0
-#define INFINIPATH_RHF_RCVTYPE_MASK 0x7
-#define INFINIPATH_RHF_RCVTYPE_SHIFT 11
-#define INFINIPATH_RHF_EGRINDEX_MASK 0xFFF
-#define INFINIPATH_RHF_EGRINDEX_SHIFT 16
-#define INFINIPATH_RHF_SEQ_MASK 0xF
-#define INFINIPATH_RHF_SEQ_SHIFT 0
-#define INFINIPATH_RHF_HDRQ_OFFSET_MASK 0x7FF
-#define INFINIPATH_RHF_HDRQ_OFFSET_SHIFT 4
-#define INFINIPATH_RHF_H_ICRCERR   0x80000000
-#define INFINIPATH_RHF_H_VCRCERR   0x40000000
-#define INFINIPATH_RHF_H_PARITYERR 0x20000000
-#define INFINIPATH_RHF_H_LENERR    0x10000000
-#define INFINIPATH_RHF_H_MTUERR    0x08000000
-#define INFINIPATH_RHF_H_IHDRERR   0x04000000
-#define INFINIPATH_RHF_H_TIDERR    0x02000000
-#define INFINIPATH_RHF_H_MKERR     0x01000000
-#define INFINIPATH_RHF_H_IBERR     0x00800000
-#define INFINIPATH_RHF_H_ERR_MASK  0xFF800000
-#define INFINIPATH_RHF_L_USE_EGR   0x80000000
-#define INFINIPATH_RHF_L_SWA       0x00008000
-#define INFINIPATH_RHF_L_SWB       0x00004000
-
-/* infinipath header fields */
-#define INFINIPATH_I_VERS_MASK 0xF
-#define INFINIPATH_I_VERS_SHIFT 28
-#define INFINIPATH_I_PORT_MASK 0xF
-#define INFINIPATH_I_PORT_SHIFT 24
-#define INFINIPATH_I_TID_MASK 0x7FF
-#define INFINIPATH_I_TID_SHIFT 13
-#define INFINIPATH_I_OFFSET_MASK 0x1FFF
-#define INFINIPATH_I_OFFSET_SHIFT 0
-
-/* K_PktFlags bits */
-#define INFINIPATH_KPF_INTR 0x1
-#define INFINIPATH_KPF_SUBPORT_MASK 0x3
-#define INFINIPATH_KPF_SUBPORT_SHIFT 1
-
-#define INFINIPATH_MAX_SUBPORT 4
-
-/* SendPIO per-buffer control */
-#define INFINIPATH_SP_TEST    0x40
-#define INFINIPATH_SP_TESTEBP 0x20
-#define INFINIPATH_SP_TRIGGER_SHIFT  15
-
-/* SendPIOAvail bits */
-#define INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT 1
-#define INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT 0
-
-/* infinipath header format */
-struct ipath_header {
-       /*
-        * Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset -
-        * 14 bits before ECO change ~28 Dec 03.  After that, Vers 4,
-        * Port 4, TID 11, offset 13.
-        */
-       __le32 ver_port_tid_offset;
-       __le16 chksum;
-       __le16 pkt_flags;
-};
-
-/* infinipath user message header format.
- * This structure contains the first 4 fields common to all protocols
- * that employ infinipath.
- */
-struct ipath_message_header {
-       __be16 lrh[4];
-       __be32 bth[3];
-       /* fields below this point are in host byte order */
-       struct ipath_header iph;
-       __u8 sub_opcode;
-};
-
-/* infinipath ethernet header format */
-struct ether_header {
-       __be16 lrh[4];
-       __be32 bth[3];
-       struct ipath_header iph;
-       __u8 sub_opcode;
-       __u8 cmd;
-       __be16 lid;
-       __u16 mac[3];
-       __u8 frag_num;
-       __u8 seq_num;
-       __le32 len;
-       /* MUST be of word size due to PIO write requirements */
-       __le32 csum;
-       __le16 csum_offset;
-       __le16 flags;
-       __u16 first_2_bytes;
-       __u8 unused[2];         /* currently unused */
-};
-
-
-/* IB - LRH header consts */
-#define IPATH_LRH_GRH 0x0003   /* 1. word of IB LRH - next header: GRH */
-#define IPATH_LRH_BTH 0x0002   /* 1. word of IB LRH - next header: BTH */
-
-/* misc. */
-#define SIZE_OF_CRC 1
-
-#define IPATH_DEFAULT_P_KEY 0xFFFF
-#define IPATH_PERMISSIVE_LID 0xFFFF
-#define IPATH_AETH_CREDIT_SHIFT 24
-#define IPATH_AETH_CREDIT_MASK 0x1F
-#define IPATH_AETH_CREDIT_INVAL 0x1F
-#define IPATH_PSN_MASK 0xFFFFFF
-#define IPATH_MSN_MASK 0xFFFFFF
-#define IPATH_QPN_MASK 0xFFFFFF
-#define IPATH_MULTICAST_LID_BASE 0xC000
-#define IPATH_EAGER_TID_ID INFINIPATH_I_TID_MASK
-#define IPATH_MULTICAST_QPN 0xFFFFFF
-
-/* Receive Header Queue: receive type (from infinipath) */
-#define RCVHQ_RCV_TYPE_EXPECTED  0
-#define RCVHQ_RCV_TYPE_EAGER     1
-#define RCVHQ_RCV_TYPE_NON_KD    2
-#define RCVHQ_RCV_TYPE_ERROR     3
-
-
-/* sub OpCodes - ith4x  */
-#define IPATH_ITH4X_OPCODE_ENCAP 0x81
-#define IPATH_ITH4X_OPCODE_LID_ARP 0x82
-
-#define IPATH_HEADER_QUEUE_WORDS 9
-
-/* functions for extracting fields from rcvhdrq entries for the driver.
- */
-static inline __u32 ipath_hdrget_err_flags(const __le32 * rbuf)
-{
-       return __le32_to_cpu(rbuf[1]) & INFINIPATH_RHF_H_ERR_MASK;
-}
-
-static inline __u32 ipath_hdrget_rcv_type(const __le32 * rbuf)
-{
-       return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_RCVTYPE_SHIFT)
-           & INFINIPATH_RHF_RCVTYPE_MASK;
-}
-
-static inline __u32 ipath_hdrget_length_in_bytes(const __le32 * rbuf)
-{
-       return ((__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_LENGTH_SHIFT)
-               & INFINIPATH_RHF_LENGTH_MASK) << 2;
-}
-
-static inline __u32 ipath_hdrget_index(const __le32 * rbuf)
-{
-       return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_EGRINDEX_SHIFT)
-           & INFINIPATH_RHF_EGRINDEX_MASK;
-}
-
-static inline __u32 ipath_hdrget_seq(const __le32 *rbuf)
-{
-       return (__le32_to_cpu(rbuf[1]) >> INFINIPATH_RHF_SEQ_SHIFT)
-               & INFINIPATH_RHF_SEQ_MASK;
-}
-
-static inline __u32 ipath_hdrget_offset(const __le32 *rbuf)
-{
-       return (__le32_to_cpu(rbuf[1]) >> INFINIPATH_RHF_HDRQ_OFFSET_SHIFT)
-               & INFINIPATH_RHF_HDRQ_OFFSET_MASK;
-}
-
-static inline __u32 ipath_hdrget_use_egr_buf(const __le32 *rbuf)
-{
-       return __le32_to_cpu(rbuf[0]) & INFINIPATH_RHF_L_USE_EGR;
-}
-
-static inline __u32 ipath_hdrget_ipath_ver(__le32 hdrword)
-{
-       return (__le32_to_cpu(hdrword) >> INFINIPATH_I_VERS_SHIFT)
-           & INFINIPATH_I_VERS_MASK;
-}
-
-#endif                         /* _IPATH_COMMON_H */
diff --git a/drivers/staging/rdma/ipath/ipath_cq.c b/drivers/staging/rdma/ipath/ipath_cq.c
deleted file mode 100644 (file)
index e9dd911..0000000
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include "ipath_verbs.h"
-
-/**
- * ipath_cq_enter - add a new entry to the completion queue
- * @cq: completion queue
- * @entry: work completion entry to add
- * @sig: true if @entry is a solicitated entry
- *
- * This may be called with qp->s_lock held.
- */
-void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
-{
-       struct ipath_cq_wc *wc;
-       unsigned long flags;
-       u32 head;
-       u32 next;
-
-       spin_lock_irqsave(&cq->lock, flags);
-
-       /*
-        * Note that the head pointer might be writable by user processes.
-        * Take care to verify it is a sane value.
-        */
-       wc = cq->queue;
-       head = wc->head;
-       if (head >= (unsigned) cq->ibcq.cqe) {
-               head = cq->ibcq.cqe;
-               next = 0;
-       } else
-               next = head + 1;
-       if (unlikely(next == wc->tail)) {
-               spin_unlock_irqrestore(&cq->lock, flags);
-               if (cq->ibcq.event_handler) {
-                       struct ib_event ev;
-
-                       ev.device = cq->ibcq.device;
-                       ev.element.cq = &cq->ibcq;
-                       ev.event = IB_EVENT_CQ_ERR;
-                       cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
-               }
-               return;
-       }
-       if (cq->ip) {
-               wc->uqueue[head].wr_id = entry->wr_id;
-               wc->uqueue[head].status = entry->status;
-               wc->uqueue[head].opcode = entry->opcode;
-               wc->uqueue[head].vendor_err = entry->vendor_err;
-               wc->uqueue[head].byte_len = entry->byte_len;
-               wc->uqueue[head].ex.imm_data = (__u32 __force) entry->ex.imm_data;
-               wc->uqueue[head].qp_num = entry->qp->qp_num;
-               wc->uqueue[head].src_qp = entry->src_qp;
-               wc->uqueue[head].wc_flags = entry->wc_flags;
-               wc->uqueue[head].pkey_index = entry->pkey_index;
-               wc->uqueue[head].slid = entry->slid;
-               wc->uqueue[head].sl = entry->sl;
-               wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
-               wc->uqueue[head].port_num = entry->port_num;
-               /* Make sure entry is written before the head index. */
-               smp_wmb();
-       } else
-               wc->kqueue[head] = *entry;
-       wc->head = next;
-
-       if (cq->notify == IB_CQ_NEXT_COMP ||
-           (cq->notify == IB_CQ_SOLICITED && solicited)) {
-               cq->notify = IB_CQ_NONE;
-               cq->triggered++;
-               /*
-                * This will cause send_complete() to be called in
-                * another thread.
-                */
-               tasklet_hi_schedule(&cq->comptask);
-       }
-
-       spin_unlock_irqrestore(&cq->lock, flags);
-
-       if (entry->status != IB_WC_SUCCESS)
-               to_idev(cq->ibcq.device)->n_wqe_errs++;
-}
-
-/**
- * ipath_poll_cq - poll for work completion entries
- * @ibcq: the completion queue to poll
- * @num_entries: the maximum number of entries to return
- * @entry: pointer to array where work completions are placed
- *
- * Returns the number of completion entries polled.
- *
- * This may be called from interrupt context.  Also called by ib_poll_cq()
- * in the generic verbs code.
- */
-int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
-{
-       struct ipath_cq *cq = to_icq(ibcq);
-       struct ipath_cq_wc *wc;
-       unsigned long flags;
-       int npolled;
-       u32 tail;
-
-       /* The kernel can only poll a kernel completion queue */
-       if (cq->ip) {
-               npolled = -EINVAL;
-               goto bail;
-       }
-
-       spin_lock_irqsave(&cq->lock, flags);
-
-       wc = cq->queue;
-       tail = wc->tail;
-       if (tail > (u32) cq->ibcq.cqe)
-               tail = (u32) cq->ibcq.cqe;
-       for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
-               if (tail == wc->head)
-                       break;
-               /* The kernel doesn't need a RMB since it has the lock. */
-               *entry = wc->kqueue[tail];
-               if (tail >= cq->ibcq.cqe)
-                       tail = 0;
-               else
-                       tail++;
-       }
-       wc->tail = tail;
-
-       spin_unlock_irqrestore(&cq->lock, flags);
-
-bail:
-       return npolled;
-}
-
-static void send_complete(unsigned long data)
-{
-       struct ipath_cq *cq = (struct ipath_cq *)data;
-
-       /*
-        * The completion handler will most likely rearm the notification
-        * and poll for all pending entries.  If a new completion entry
-        * is added while we are in this routine, tasklet_hi_schedule()
-        * won't call us again until we return so we check triggered to
-        * see if we need to call the handler again.
-        */
-       for (;;) {
-               u8 triggered = cq->triggered;
-
-               cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
-
-               if (cq->triggered == triggered)
-                       return;
-       }
-}
-
-/**
- * ipath_create_cq - create a completion queue
- * @ibdev: the device this completion queue is attached to
- * @attr: creation attributes
- * @context: unused by the InfiniPath driver
- * @udata: unused by the InfiniPath driver
- *
- * Returns a pointer to the completion queue or negative errno values
- * for failure.
- *
- * Called by ib_create_cq() in the generic verbs code.
- */
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev,
-                             const struct ib_cq_init_attr *attr,
-                             struct ib_ucontext *context,
-                             struct ib_udata *udata)
-{
-       int entries = attr->cqe;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_cq *cq;
-       struct ipath_cq_wc *wc;
-       struct ib_cq *ret;
-       u32 sz;
-
-       if (attr->flags)
-               return ERR_PTR(-EINVAL);
-
-       if (entries < 1 || entries > ib_ipath_max_cqes) {
-               ret = ERR_PTR(-EINVAL);
-               goto done;
-       }
-
-       /* Allocate the completion queue structure. */
-       cq = kmalloc(sizeof(*cq), GFP_KERNEL);
-       if (!cq) {
-               ret = ERR_PTR(-ENOMEM);
-               goto done;
-       }
-
-       /*
-        * Allocate the completion queue entries and head/tail pointers.
-        * This is allocated separately so that it can be resized and
-        * also mapped into user space.
-        * We need to use vmalloc() in order to support mmap and large
-        * numbers of entries.
-        */
-       sz = sizeof(*wc);
-       if (udata && udata->outlen >= sizeof(__u64))
-               sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
-       else
-               sz += sizeof(struct ib_wc) * (entries + 1);
-       wc = vmalloc_user(sz);
-       if (!wc) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail_cq;
-       }
-
-       /*
-        * Return the address of the WC as the offset to mmap.
-        * See ipath_mmap() for details.
-        */
-       if (udata && udata->outlen >= sizeof(__u64)) {
-               int err;
-
-               cq->ip = ipath_create_mmap_info(dev, sz, context, wc);
-               if (!cq->ip) {
-                       ret = ERR_PTR(-ENOMEM);
-                       goto bail_wc;
-               }
-
-               err = ib_copy_to_udata(udata, &cq->ip->offset,
-                                      sizeof(cq->ip->offset));
-               if (err) {
-                       ret = ERR_PTR(err);
-                       goto bail_ip;
-               }
-       } else
-               cq->ip = NULL;
-
-       spin_lock(&dev->n_cqs_lock);
-       if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
-               spin_unlock(&dev->n_cqs_lock);
-               ret = ERR_PTR(-ENOMEM);
-               goto bail_ip;
-       }
-
-       dev->n_cqs_allocated++;
-       spin_unlock(&dev->n_cqs_lock);
-
-       if (cq->ip) {
-               spin_lock_irq(&dev->pending_lock);
-               list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);
-               spin_unlock_irq(&dev->pending_lock);
-       }
-
-       /*
-        * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
-        * The number of entries should be >= the number requested or return
-        * an error.
-        */
-       cq->ibcq.cqe = entries;
-       cq->notify = IB_CQ_NONE;
-       cq->triggered = 0;
-       spin_lock_init(&cq->lock);
-       tasklet_init(&cq->comptask, send_complete, (unsigned long)cq);
-       wc->head = 0;
-       wc->tail = 0;
-       cq->queue = wc;
-
-       ret = &cq->ibcq;
-
-       goto done;
-
-bail_ip:
-       kfree(cq->ip);
-bail_wc:
-       vfree(wc);
-bail_cq:
-       kfree(cq);
-done:
-       return ret;
-}
-
-/**
- * ipath_destroy_cq - destroy a completion queue
- * @ibcq: the completion queue to destroy.
- *
- * Returns 0 for success.
- *
- * Called by ib_destroy_cq() in the generic verbs code.
- */
-int ipath_destroy_cq(struct ib_cq *ibcq)
-{
-       struct ipath_ibdev *dev = to_idev(ibcq->device);
-       struct ipath_cq *cq = to_icq(ibcq);
-
-       tasklet_kill(&cq->comptask);
-       spin_lock(&dev->n_cqs_lock);
-       dev->n_cqs_allocated--;
-       spin_unlock(&dev->n_cqs_lock);
-       if (cq->ip)
-               kref_put(&cq->ip->ref, ipath_release_mmap_info);
-       else
-               vfree(cq->queue);
-       kfree(cq);
-
-       return 0;
-}
-
-/**
- * ipath_req_notify_cq - change the notification type for a completion queue
- * @ibcq: the completion queue
- * @notify_flags: the type of notification to request
- *
- * Returns 0 for success.
- *
- * This may be called from interrupt context.  Also called by
- * ib_req_notify_cq() in the generic verbs code.
- */
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
-{
-       struct ipath_cq *cq = to_icq(ibcq);
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&cq->lock, flags);
-       /*
-        * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow
-        * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
-        */
-       if (cq->notify != IB_CQ_NEXT_COMP)
-               cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
-
-       if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
-           cq->queue->head != cq->queue->tail)
-               ret = 1;
-
-       spin_unlock_irqrestore(&cq->lock, flags);
-
-       return ret;
-}
-
-/**
- * ipath_resize_cq - change the size of the CQ
- * @ibcq: the completion queue
- *
- * Returns 0 for success.
- */
-int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
-{
-       struct ipath_cq *cq = to_icq(ibcq);
-       struct ipath_cq_wc *old_wc;
-       struct ipath_cq_wc *wc;
-       u32 head, tail, n;
-       int ret;
-       u32 sz;
-
-       if (cqe < 1 || cqe > ib_ipath_max_cqes) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       /*
-        * Need to use vmalloc() if we want to support large #s of entries.
-        */
-       sz = sizeof(*wc);
-       if (udata && udata->outlen >= sizeof(__u64))
-               sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
-       else
-               sz += sizeof(struct ib_wc) * (cqe + 1);
-       wc = vmalloc_user(sz);
-       if (!wc) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       /* Check that we can write the offset to mmap. */
-       if (udata && udata->outlen >= sizeof(__u64)) {
-               __u64 offset = 0;
-
-               ret = ib_copy_to_udata(udata, &offset, sizeof(offset));
-               if (ret)
-                       goto bail_free;
-       }
-
-       spin_lock_irq(&cq->lock);
-       /*
-        * Make sure head and tail are sane since they
-        * might be user writable.
-        */
-       old_wc = cq->queue;
-       head = old_wc->head;
-       if (head > (u32) cq->ibcq.cqe)
-               head = (u32) cq->ibcq.cqe;
-       tail = old_wc->tail;
-       if (tail > (u32) cq->ibcq.cqe)
-               tail = (u32) cq->ibcq.cqe;
-       if (head < tail)
-               n = cq->ibcq.cqe + 1 + head - tail;
-       else
-               n = head - tail;
-       if (unlikely((u32)cqe < n)) {
-               ret = -EINVAL;
-               goto bail_unlock;
-       }
-       for (n = 0; tail != head; n++) {
-               if (cq->ip)
-                       wc->uqueue[n] = old_wc->uqueue[tail];
-               else
-                       wc->kqueue[n] = old_wc->kqueue[tail];
-               if (tail == (u32) cq->ibcq.cqe)
-                       tail = 0;
-               else
-                       tail++;
-       }
-       cq->ibcq.cqe = cqe;
-       wc->head = n;
-       wc->tail = 0;
-       cq->queue = wc;
-       spin_unlock_irq(&cq->lock);
-
-       vfree(old_wc);
-
-       if (cq->ip) {
-               struct ipath_ibdev *dev = to_idev(ibcq->device);
-               struct ipath_mmap_info *ip = cq->ip;
-
-               ipath_update_mmap_info(dev, ip, sz, wc);
-
-               /*
-                * Return the offset to mmap.
-                * See ipath_mmap() for details.
-                */
-               if (udata && udata->outlen >= sizeof(__u64)) {
-                       ret = ib_copy_to_udata(udata, &ip->offset,
-                                              sizeof(ip->offset));
-                       if (ret)
-                               goto bail;
-               }
-
-               spin_lock_irq(&dev->pending_lock);
-               if (list_empty(&ip->pending_mmaps))
-                       list_add(&ip->pending_mmaps, &dev->pending_mmaps);
-               spin_unlock_irq(&dev->pending_lock);
-       }
-
-       ret = 0;
-       goto bail;
-
-bail_unlock:
-       spin_unlock_irq(&cq->lock);
-bail_free:
-       vfree(wc);
-bail:
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_debug.h b/drivers/staging/rdma/ipath/ipath_debug.h
deleted file mode 100644 (file)
index 65926cd..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _IPATH_DEBUG_H
-#define _IPATH_DEBUG_H
-
-#ifndef _IPATH_DEBUGGING       /* debugging enabled or not */
-#define _IPATH_DEBUGGING 1
-#endif
-
-#if _IPATH_DEBUGGING
-
-/*
- * Mask values for debugging.  The scheme allows us to compile out any
- * of the debug tracing stuff, and if compiled in, to enable or disable
- * dynamically.  This can be set at modprobe time also:
- *      modprobe infinipath.ko infinipath_debug=7
- */
-
-#define __IPATH_INFO        0x1        /* generic low verbosity stuff */
-#define __IPATH_DBG         0x2        /* generic debug */
-#define __IPATH_TRSAMPLE    0x8        /* generate trace buffer sample entries */
-/* leave some low verbosity spots open */
-#define __IPATH_VERBDBG     0x40       /* very verbose debug */
-#define __IPATH_PKTDBG      0x80       /* print packet data */
-/* print process startup (init)/exit messages */
-#define __IPATH_PROCDBG     0x100
-/* print mmap/fault stuff, not using VDBG any more */
-#define __IPATH_MMDBG       0x200
-#define __IPATH_ERRPKTDBG   0x400
-#define __IPATH_USER_SEND   0x1000     /* use user mode send */
-#define __IPATH_KERNEL_SEND 0x2000     /* use kernel mode send */
-#define __IPATH_EPKTDBG     0x4000     /* print ethernet packet data */
-#define __IPATH_IPATHDBG    0x10000    /* Ethernet (IPATH) gen debug */
-#define __IPATH_IPATHWARN   0x20000    /* Ethernet (IPATH) warnings */
-#define __IPATH_IPATHERR    0x40000    /* Ethernet (IPATH) errors */
-#define __IPATH_IPATHPD     0x80000    /* Ethernet (IPATH) packet dump */
-#define __IPATH_IPATHTABLE  0x100000   /* Ethernet (IPATH) table dump */
-#define __IPATH_LINKVERBDBG 0x200000   /* very verbose linkchange debug */
-
-#else                          /* _IPATH_DEBUGGING */
-
-/*
- * define all of these even with debugging off, for the few places that do
- * if(infinipath_debug & _IPATH_xyzzy), but in a way that will make the
- * compiler eliminate the code
- */
-
-#define __IPATH_INFO      0x0  /* generic low verbosity stuff */
-#define __IPATH_DBG       0x0  /* generic debug */
-#define __IPATH_TRSAMPLE  0x0  /* generate trace buffer sample entries */
-#define __IPATH_VERBDBG   0x0  /* very verbose debug */
-#define __IPATH_PKTDBG    0x0  /* print packet data */
-#define __IPATH_PROCDBG   0x0  /* process startup (init)/exit messages */
-/* print mmap/fault stuff, not using VDBG any more */
-#define __IPATH_MMDBG     0x0
-#define __IPATH_EPKTDBG   0x0  /* print ethernet packet data */
-#define __IPATH_IPATHDBG  0x0  /* Ethernet (IPATH) table dump on */
-#define __IPATH_IPATHWARN 0x0  /* Ethernet (IPATH) warnings on   */
-#define __IPATH_IPATHERR  0x0  /* Ethernet (IPATH) errors on   */
-#define __IPATH_IPATHPD   0x0  /* Ethernet (IPATH) packet dump on   */
-#define __IPATH_IPATHTABLE 0x0 /* Ethernet (IPATH) packet dump on   */
-#define __IPATH_LINKVERBDBG 0x0        /* very verbose linkchange debug */
-
-#endif                         /* _IPATH_DEBUGGING */
-
-#define __IPATH_VERBOSEDBG __IPATH_VERBDBG
-
-#endif                         /* _IPATH_DEBUG_H */
diff --git a/drivers/staging/rdma/ipath/ipath_diag.c b/drivers/staging/rdma/ipath/ipath_diag.c
deleted file mode 100644 (file)
index 45802e9..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This file contains support for diagnostic functions.  It is accessed by
- * opening the ipath_diag device, normally minor number 129.  Diagnostic use
- * of the InfiniPath chip may render the chip or board unusable until the
- * driver is unloaded, or in some cases, until the system is rebooted.
- *
- * Accesses to the chip through this interface are not similar to going
- * through the /sys/bus/pci resource mmap interface.
- */
-
-#include <linux/io.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/fs.h>
-#include <linux/export.h>
-#include <asm/uaccess.h>
-
-#include "ipath_kernel.h"
-#include "ipath_common.h"
-
-int ipath_diag_inuse;
-static int diag_set_link;
-
-static int ipath_diag_open(struct inode *in, struct file *fp);
-static int ipath_diag_release(struct inode *in, struct file *fp);
-static ssize_t ipath_diag_read(struct file *fp, char __user *data,
-                              size_t count, loff_t *off);
-static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
-                               size_t count, loff_t *off);
-
-static const struct file_operations diag_file_ops = {
-       .owner = THIS_MODULE,
-       .write = ipath_diag_write,
-       .read = ipath_diag_read,
-       .open = ipath_diag_open,
-       .release = ipath_diag_release,
-       .llseek = default_llseek,
-};
-
-static ssize_t ipath_diagpkt_write(struct file *fp,
-                                  const char __user *data,
-                                  size_t count, loff_t *off);
-
-static const struct file_operations diagpkt_file_ops = {
-       .owner = THIS_MODULE,
-       .write = ipath_diagpkt_write,
-       .llseek = noop_llseek,
-};
-
-static atomic_t diagpkt_count = ATOMIC_INIT(0);
-static struct cdev *diagpkt_cdev;
-static struct device *diagpkt_dev;
-
-int ipath_diag_add(struct ipath_devdata *dd)
-{
-       char name[16];
-       int ret = 0;
-
-       if (atomic_inc_return(&diagpkt_count) == 1) {
-               ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
-                                     "ipath_diagpkt", &diagpkt_file_ops,
-                                     &diagpkt_cdev, &diagpkt_dev);
-
-               if (ret) {
-                       ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
-                                     "device: %d", ret);
-                       goto done;
-               }
-       }
-
-       snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
-
-       ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
-                             &diag_file_ops, &dd->diag_cdev,
-                             &dd->diag_dev);
-       if (ret)
-               ipath_dev_err(dd, "Couldn't create %s device: %d",
-                             name, ret);
-
-done:
-       return ret;
-}
-
-void ipath_diag_remove(struct ipath_devdata *dd)
-{
-       if (atomic_dec_and_test(&diagpkt_count))
-               ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_dev);
-
-       ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_dev);
-}
-
-/**
- * ipath_read_umem64 - read a 64-bit quantity from the chip into user space
- * @dd: the infinipath device
- * @uaddr: the location to store the data in user memory
- * @caddr: the source chip address (full pointer, not offset)
- * @count: number of bytes to copy (multiple of 32 bits)
- *
- * This function also localizes all chip memory accesses.
- * The copy should be written such that we read full cacheline packets
- * from the chip.  This is usually used for a single qword
- *
- * NOTE:  This assumes the chip address is 64-bit aligned.
- */
-static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
-                            const void __iomem *caddr, size_t count)
-{
-       const u64 __iomem *reg_addr = caddr;
-       const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
-       int ret;
-
-       /* not very efficient, but it works for now */
-       if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       while (reg_addr < reg_end) {
-               u64 data = readq(reg_addr);
-               if (copy_to_user(uaddr, &data, sizeof(u64))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-               reg_addr++;
-               uaddr += sizeof(u64);
-       }
-       ret = 0;
-bail:
-       return ret;
-}
-
-/**
- * ipath_write_umem64 - write a 64-bit quantity to the chip from user space
- * @dd: the infinipath device
- * @caddr: the destination chip address (full pointer, not offset)
- * @uaddr: the source of the data in user memory
- * @count: the number of bytes to copy (multiple of 32 bits)
- *
- * This is usually used for a single qword
- * NOTE:  This assumes the chip address is 64-bit aligned.
- */
-
-static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
-                             const void __user *uaddr, size_t count)
-{
-       u64 __iomem *reg_addr = caddr;
-       const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64));
-       int ret;
-
-       /* not very efficient, but it works for now */
-       if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       while (reg_addr < reg_end) {
-               u64 data;
-               if (copy_from_user(&data, uaddr, sizeof(data))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-               writeq(data, reg_addr);
-
-               reg_addr++;
-               uaddr += sizeof(u64);
-       }
-       ret = 0;
-bail:
-       return ret;
-}
-
-/**
- * ipath_read_umem32 - read a 32-bit quantity from the chip into user space
- * @dd: the infinipath device
- * @uaddr: the location to store the data in user memory
- * @caddr: the source chip address (full pointer, not offset)
- * @count: number of bytes to copy
- *
- * read 32 bit values, not 64 bit; for memories that only
- * support 32 bit reads; usually a single dword.
- */
-static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr,
-                            const void __iomem *caddr, size_t count)
-{
-       const u32 __iomem *reg_addr = caddr;
-       const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
-       int ret;
-
-       if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
-           reg_end > (u32 __iomem *) dd->ipath_kregend) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       /* not very efficient, but it works for now */
-       while (reg_addr < reg_end) {
-               u32 data = readl(reg_addr);
-               if (copy_to_user(uaddr, &data, sizeof(data))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-
-               reg_addr++;
-               uaddr += sizeof(u32);
-
-       }
-       ret = 0;
-bail:
-       return ret;
-}
-
-/**
- * ipath_write_umem32 - write a 32-bit quantity to the chip from user space
- * @dd: the infinipath device
- * @caddr: the destination chip address (full pointer, not offset)
- * @uaddr: the source of the data in user memory
- * @count: number of bytes to copy
- *
- * write 32 bit values, not 64 bit; for memories that only
- * support 32 bit write; usually a single dword.
- */
-
-static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr,
-                             const void __user *uaddr, size_t count)
-{
-       u32 __iomem *reg_addr = caddr;
-       const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32));
-       int ret;
-
-       if (reg_addr < (u32 __iomem *) dd->ipath_kregbase ||
-           reg_end > (u32 __iomem *) dd->ipath_kregend) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       while (reg_addr < reg_end) {
-               u32 data;
-               if (copy_from_user(&data, uaddr, sizeof(data))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-               writel(data, reg_addr);
-
-               reg_addr++;
-               uaddr += sizeof(u32);
-       }
-       ret = 0;
-bail:
-       return ret;
-}
-
-static int ipath_diag_open(struct inode *in, struct file *fp)
-{
-       int unit = iminor(in) - IPATH_DIAG_MINOR_BASE;
-       struct ipath_devdata *dd;
-       int ret;
-
-       mutex_lock(&ipath_mutex);
-
-       if (ipath_diag_inuse) {
-               ret = -EBUSY;
-               goto bail;
-       }
-
-       dd = ipath_lookup(unit);
-
-       if (dd == NULL || !(dd->ipath_flags & IPATH_PRESENT) ||
-           !dd->ipath_kregbase) {
-               ret = -ENODEV;
-               goto bail;
-       }
-
-       fp->private_data = dd;
-       ipath_diag_inuse = -2;
-       diag_set_link = 0;
-       ret = 0;
-
-       /* Only expose a way to reset the device if we
-          make it into diag mode. */
-       ipath_expose_reset(&dd->pcidev->dev);
-
-bail:
-       mutex_unlock(&ipath_mutex);
-
-       return ret;
-}
-
-/**
- * ipath_diagpkt_write - write an IB packet
- * @fp: the diag data device file pointer
- * @data: ipath_diag_pkt structure saying where to get the packet
- * @count: size of data to write
- * @off: unused by this code
- */
-static ssize_t ipath_diagpkt_write(struct file *fp,
-                                  const char __user *data,
-                                  size_t count, loff_t *off)
-{
-       u32 __iomem *piobuf;
-       u32 plen, pbufn, maxlen_reserve;
-       struct ipath_diag_pkt odp;
-       struct ipath_diag_xpkt dp;
-       u32 *tmpbuf = NULL;
-       struct ipath_devdata *dd;
-       ssize_t ret = 0;
-       u64 val;
-       u32 l_state, lt_state; /* LinkState, LinkTrainingState */
-
-
-       if (count == sizeof(dp)) {
-               if (copy_from_user(&dp, data, sizeof(dp))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-       } else if (count == sizeof(odp)) {
-               if (copy_from_user(&odp, data, sizeof(odp))) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-               dp.len = odp.len;
-               dp.unit = odp.unit;
-               dp.data = odp.data;
-               dp.pbc_wd = 0;
-       } else {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       /* send count must be an exact number of dwords */
-       if (dp.len & 3) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       plen = dp.len >> 2;
-
-       dd = ipath_lookup(dp.unit);
-       if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
-           !dd->ipath_kregbase) {
-               ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
-                          dp.unit);
-               ret = -ENODEV;
-               goto bail;
-       }
-
-       if (ipath_diag_inuse && !diag_set_link &&
-           !(dd->ipath_flags & IPATH_LINKACTIVE)) {
-               diag_set_link = 1;
-               ipath_cdbg(VERBOSE, "Trying to set to set link active for "
-                          "diag pkt\n");
-               ipath_set_linkstate(dd, IPATH_IB_LINKARM);
-               ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
-       }
-
-       if (!(dd->ipath_flags & IPATH_INITTED)) {
-               /* no hardware, freeze, etc. */
-               ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
-               ret = -ENODEV;
-               goto bail;
-       }
-       /*
-        * Want to skip check for l_state if using custom PBC,
-        * because we might be trying to force an SM packet out.
-        * first-cut, skip _all_ state checking in that case.
-        */
-       val = ipath_ib_state(dd, dd->ipath_lastibcstat);
-       lt_state = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
-       l_state = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
-       if (!dp.pbc_wd && (lt_state != INFINIPATH_IBCS_LT_STATE_LINKUP ||
-           (val != dd->ib_init && val != dd->ib_arm &&
-           val != dd->ib_active))) {
-               ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
-                          dd->ipath_unit, (unsigned long long) val);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       /*
-        * need total length before first word written, plus 2 Dwords. One Dword
-        * is for padding so we get the full user data when not aligned on
-        * a word boundary. The other Dword is to make sure we have room for the
-        * ICRC which gets tacked on later.
-        */
-       maxlen_reserve = 2 * sizeof(u32);
-       if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
-               ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
-                         dp.len, dd->ipath_ibmaxlen);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       plen = sizeof(u32) + dp.len;
-
-       tmpbuf = vmalloc(plen);
-       if (!tmpbuf) {
-               dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
-                        "failing\n");
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       if (copy_from_user(tmpbuf,
-                          (const void __user *) (unsigned long) dp.data,
-                          dp.len)) {
-               ret = -EFAULT;
-               goto bail;
-       }
-
-       plen >>= 2;             /* in dwords */
-
-       piobuf = ipath_getpiobuf(dd, plen, &pbufn);
-       if (!piobuf) {
-               ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
-                          dd->ipath_unit);
-               ret = -EBUSY;
-               goto bail;
-       }
-       /* disarm it just to be extra sure */
-       ipath_disarm_piobufs(dd, pbufn, 1);
-
-       if (ipath_debug & __IPATH_PKTDBG)
-               ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
-                          dd->ipath_unit, plen - 1, pbufn);
-
-       if (dp.pbc_wd == 0)
-               dp.pbc_wd = plen;
-       writeq(dp.pbc_wd, piobuf);
-       /*
-        * Copy all by the trigger word, then flush, so it's written
-        * to chip before trigger word, then write trigger word, then
-        * flush again, so packet is sent.
-        */
-       if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
-               ipath_flush_wc();
-               __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
-               ipath_flush_wc();
-               __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
-       } else
-               __iowrite32_copy(piobuf + 2, tmpbuf, plen);
-
-       ipath_flush_wc();
-
-       ret = sizeof(dp);
-
-bail:
-       vfree(tmpbuf);
-       return ret;
-}
-
-static int ipath_diag_release(struct inode *in, struct file *fp)
-{
-       mutex_lock(&ipath_mutex);
-       ipath_diag_inuse = 0;
-       fp->private_data = NULL;
-       mutex_unlock(&ipath_mutex);
-       return 0;
-}
-
-static ssize_t ipath_diag_read(struct file *fp, char __user *data,
-                              size_t count, loff_t *off)
-{
-       struct ipath_devdata *dd = fp->private_data;
-       void __iomem *kreg_base;
-       ssize_t ret;
-
-       kreg_base = dd->ipath_kregbase;
-
-       if (count == 0)
-               ret = 0;
-       else if ((count % 4) || (*off % 4))
-               /* address or length is not 32-bit aligned, hence invalid */
-               ret = -EINVAL;
-       else if (ipath_diag_inuse < 1 && (*off || count != 8))
-               ret = -EINVAL;  /* prevent cat /dev/ipath_diag* */
-       else if ((count % 8) || (*off % 8))
-               /* address or length not 64-bit aligned; do 32-bit reads */
-               ret = ipath_read_umem32(dd, data, kreg_base + *off, count);
-       else
-               ret = ipath_read_umem64(dd, data, kreg_base + *off, count);
-
-       if (ret >= 0) {
-               *off += count;
-               ret = count;
-               if (ipath_diag_inuse == -2)
-                       ipath_diag_inuse++;
-       }
-
-       return ret;
-}
-
-static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
-                               size_t count, loff_t *off)
-{
-       struct ipath_devdata *dd = fp->private_data;
-       void __iomem *kreg_base;
-       ssize_t ret;
-
-       kreg_base = dd->ipath_kregbase;
-
-       if (count == 0)
-               ret = 0;
-       else if ((count % 4) || (*off % 4))
-               /* address or length is not 32-bit aligned, hence invalid */
-               ret = -EINVAL;
-       else if ((ipath_diag_inuse == -1 && (*off || count != 8)) ||
-                ipath_diag_inuse == -2)  /* read qw off 0, write qw off 0 */
-               ret = -EINVAL;  /* before any other write allowed */
-       else if ((count % 8) || (*off % 8))
-               /* address or length not 64-bit aligned; do 32-bit writes */
-               ret = ipath_write_umem32(dd, kreg_base + *off, data, count);
-       else
-               ret = ipath_write_umem64(dd, kreg_base + *off, data, count);
-
-       if (ret >= 0) {
-               *off += count;
-               ret = count;
-               if (ipath_diag_inuse == -1)
-                       ipath_diag_inuse = 1; /* all read/write OK now */
-       }
-
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_dma.c b/drivers/staging/rdma/ipath/ipath_dma.c
deleted file mode 100644 (file)
index 123a8c0..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2006 QLogic, Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/scatterlist.h>
-#include <linux/gfp.h>
-#include <rdma/ib_verbs.h>
-
-#include "ipath_verbs.h"
-
-#define BAD_DMA_ADDRESS ((u64) 0)
-
-/*
- * The following functions implement driver specific replacements
- * for the ib_dma_*() functions.
- *
- * These functions return kernel virtual addresses instead of
- * device bus addresses since the driver uses the CPU to copy
- * data instead of using hardware DMA.
- */
-
-static int ipath_mapping_error(struct ib_device *dev, u64 dma_addr)
-{
-       return dma_addr == BAD_DMA_ADDRESS;
-}
-
-static u64 ipath_dma_map_single(struct ib_device *dev,
-                               void *cpu_addr, size_t size,
-                               enum dma_data_direction direction)
-{
-       BUG_ON(!valid_dma_direction(direction));
-       return (u64) cpu_addr;
-}
-
-static void ipath_dma_unmap_single(struct ib_device *dev,
-                                  u64 addr, size_t size,
-                                  enum dma_data_direction direction)
-{
-       BUG_ON(!valid_dma_direction(direction));
-}
-
-static u64 ipath_dma_map_page(struct ib_device *dev,
-                             struct page *page,
-                             unsigned long offset,
-                             size_t size,
-                             enum dma_data_direction direction)
-{
-       u64 addr;
-
-       BUG_ON(!valid_dma_direction(direction));
-
-       if (offset + size > PAGE_SIZE) {
-               addr = BAD_DMA_ADDRESS;
-               goto done;
-       }
-
-       addr = (u64) page_address(page);
-       if (addr)
-               addr += offset;
-       /* TODO: handle highmem pages */
-
-done:
-       return addr;
-}
-
-static void ipath_dma_unmap_page(struct ib_device *dev,
-                                u64 addr, size_t size,
-                                enum dma_data_direction direction)
-{
-       BUG_ON(!valid_dma_direction(direction));
-}
-
-static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sgl,
-                       int nents, enum dma_data_direction direction)
-{
-       struct scatterlist *sg;
-       u64 addr;
-       int i;
-       int ret = nents;
-
-       BUG_ON(!valid_dma_direction(direction));
-
-       for_each_sg(sgl, sg, nents, i) {
-               addr = (u64) page_address(sg_page(sg));
-               /* TODO: handle highmem pages */
-               if (!addr) {
-                       ret = 0;
-                       break;
-               }
-               sg->dma_address = addr + sg->offset;
-#ifdef CONFIG_NEED_SG_DMA_LENGTH
-               sg->dma_length = sg->length;
-#endif
-       }
-       return ret;
-}
-
-static void ipath_unmap_sg(struct ib_device *dev,
-                          struct scatterlist *sg, int nents,
-                          enum dma_data_direction direction)
-{
-       BUG_ON(!valid_dma_direction(direction));
-}
-
-static void ipath_sync_single_for_cpu(struct ib_device *dev,
-                                     u64 addr,
-                                     size_t size,
-                                     enum dma_data_direction dir)
-{
-}
-
-static void ipath_sync_single_for_device(struct ib_device *dev,
-                                        u64 addr,
-                                        size_t size,
-                                        enum dma_data_direction dir)
-{
-}
-
-static void *ipath_dma_alloc_coherent(struct ib_device *dev, size_t size,
-                                     u64 *dma_handle, gfp_t flag)
-{
-       struct page *p;
-       void *addr = NULL;
-
-       p = alloc_pages(flag, get_order(size));
-       if (p)
-               addr = page_address(p);
-       if (dma_handle)
-               *dma_handle = (u64) addr;
-       return addr;
-}
-
-static void ipath_dma_free_coherent(struct ib_device *dev, size_t size,
-                                   void *cpu_addr, u64 dma_handle)
-{
-       free_pages((unsigned long) cpu_addr, get_order(size));
-}
-
-struct ib_dma_mapping_ops ipath_dma_mapping_ops = {
-       .mapping_error = ipath_mapping_error,
-       .map_single = ipath_dma_map_single,
-       .unmap_single = ipath_dma_unmap_single,
-       .map_page = ipath_dma_map_page,
-       .unmap_page = ipath_dma_unmap_page,
-       .map_sg = ipath_map_sg,
-       .unmap_sg = ipath_unmap_sg,
-       .sync_single_for_cpu = ipath_sync_single_for_cpu,
-       .sync_single_for_device = ipath_sync_single_for_device,
-       .alloc_coherent = ipath_dma_alloc_coherent,
-       .free_coherent = ipath_dma_free_coherent
-};
diff --git a/drivers/staging/rdma/ipath/ipath_driver.c b/drivers/staging/rdma/ipath/ipath_driver.c
deleted file mode 100644 (file)
index 2ab22f9..0000000
+++ /dev/null
@@ -1,2784 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/spinlock.h>
-#include <linux/idr.h>
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/bitmap.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#ifdef CONFIG_X86_64
-#include <asm/pat.h>
-#endif
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-
-static void ipath_update_pio_bufs(struct ipath_devdata *);
-
-const char *ipath_get_unit_name(int unit)
-{
-       static char iname[16];
-       snprintf(iname, sizeof iname, "infinipath%u", unit);
-       return iname;
-}
-
-#define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: "
-#define PFX IPATH_DRV_NAME ": "
-
-/*
- * The size has to be longer than this string, so we can append
- * board/chip information to it in the init code.
- */
-const char ib_ipath_version[] = IPATH_IDSTR "\n";
-
-static struct idr unit_table;
-DEFINE_SPINLOCK(ipath_devs_lock);
-LIST_HEAD(ipath_dev_list);
-
-wait_queue_head_t ipath_state_wait;
-
-unsigned ipath_debug = __IPATH_INFO;
-
-module_param_named(debug, ipath_debug, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(debug, "mask for debug prints");
-EXPORT_SYMBOL_GPL(ipath_debug);
-
-unsigned ipath_mtu4096 = 1; /* max 4KB IB mtu by default, if supported */
-module_param_named(mtu4096, ipath_mtu4096, uint, S_IRUGO);
-MODULE_PARM_DESC(mtu4096, "enable MTU of 4096 bytes, if supported");
-
-static unsigned ipath_hol_timeout_ms = 13000;
-module_param_named(hol_timeout_ms, ipath_hol_timeout_ms, uint, S_IRUGO);
-MODULE_PARM_DESC(hol_timeout_ms,
-       "duration of user app suspension after link failure");
-
-unsigned ipath_linkrecovery = 1;
-module_param_named(linkrecovery, ipath_linkrecovery, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(linkrecovery, "enable workaround for link recovery issue");
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("QLogic <support@qlogic.com>");
-MODULE_DESCRIPTION("QLogic InfiniPath driver");
-
-/*
- * Table to translate the LINKTRAININGSTATE portion of
- * IBCStatus to a human-readable form.
- */
-const char *ipath_ibcstatus_str[] = {
-       "Disabled",
-       "LinkUp",
-       "PollActive",
-       "PollQuiet",
-       "SleepDelay",
-       "SleepQuiet",
-       "LState6",              /* unused */
-       "LState7",              /* unused */
-       "CfgDebounce",
-       "CfgRcvfCfg",
-       "CfgWaitRmt",
-       "CfgIdle",
-       "RecovRetrain",
-       "CfgTxRevLane",         /* unused before IBA7220 */
-       "RecovWaitRmt",
-       "RecovIdle",
-       /* below were added for IBA7220 */
-       "CfgEnhanced",
-       "CfgTest",
-       "CfgWaitRmtTest",
-       "CfgWaitCfgEnhanced",
-       "SendTS_T",
-       "SendTstIdles",
-       "RcvTS_T",
-       "SendTst_TS1s",
-       "LTState18", "LTState19", "LTState1A", "LTState1B",
-       "LTState1C", "LTState1D", "LTState1E", "LTState1F"
-};
-
-static void ipath_remove_one(struct pci_dev *);
-static int ipath_init_one(struct pci_dev *, const struct pci_device_id *);
-
-/* Only needed for registration, nothing else needs this info */
-#define PCI_VENDOR_ID_PATHSCALE 0x1fc1
-#define PCI_DEVICE_ID_INFINIPATH_HT 0xd
-
-/* Number of seconds before our card status check...  */
-#define STATUS_TIMEOUT 60
-
-static const struct pci_device_id ipath_pci_tbl[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, ipath_pci_tbl);
-
-static struct pci_driver ipath_driver = {
-       .name = IPATH_DRV_NAME,
-       .probe = ipath_init_one,
-       .remove = ipath_remove_one,
-       .id_table = ipath_pci_tbl,
-       .driver = {
-               .groups = ipath_driver_attr_groups,
-       },
-};
-
-static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,
-                            u32 *bar0, u32 *bar1)
-{
-       int ret;
-
-       ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
-       if (ret)
-               ipath_dev_err(dd, "failed to read bar0 before enable: "
-                             "error %d\n", -ret);
-
-       ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, bar1);
-       if (ret)
-               ipath_dev_err(dd, "failed to read bar1 before enable: "
-                             "error %d\n", -ret);
-
-       ipath_dbg("Read bar0 %x bar1 %x\n", *bar0, *bar1);
-}
-
-static void ipath_free_devdata(struct pci_dev *pdev,
-                              struct ipath_devdata *dd)
-{
-       unsigned long flags;
-
-       pci_set_drvdata(pdev, NULL);
-
-       if (dd->ipath_unit != -1) {
-               spin_lock_irqsave(&ipath_devs_lock, flags);
-               idr_remove(&unit_table, dd->ipath_unit);
-               list_del(&dd->ipath_list);
-               spin_unlock_irqrestore(&ipath_devs_lock, flags);
-       }
-       vfree(dd);
-}
-
-static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
-{
-       unsigned long flags;
-       struct ipath_devdata *dd;
-       int ret;
-
-       dd = vzalloc(sizeof(*dd));
-       if (!dd) {
-               dd = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-       dd->ipath_unit = -1;
-
-       idr_preload(GFP_KERNEL);
-       spin_lock_irqsave(&ipath_devs_lock, flags);
-
-       ret = idr_alloc(&unit_table, dd, 0, 0, GFP_NOWAIT);
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME
-                      ": Could not allocate unit ID: error %d\n", -ret);
-               ipath_free_devdata(pdev, dd);
-               dd = ERR_PTR(ret);
-               goto bail_unlock;
-       }
-       dd->ipath_unit = ret;
-
-       dd->pcidev = pdev;
-       pci_set_drvdata(pdev, dd);
-
-       list_add(&dd->ipath_list, &ipath_dev_list);
-
-bail_unlock:
-       spin_unlock_irqrestore(&ipath_devs_lock, flags);
-       idr_preload_end();
-bail:
-       return dd;
-}
-
-static inline struct ipath_devdata *__ipath_lookup(int unit)
-{
-       return idr_find(&unit_table, unit);
-}
-
-struct ipath_devdata *ipath_lookup(int unit)
-{
-       struct ipath_devdata *dd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ipath_devs_lock, flags);
-       dd = __ipath_lookup(unit);
-       spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-       return dd;
-}
-
-int ipath_count_units(int *npresentp, int *nupp, int *maxportsp)
-{
-       int nunits, npresent, nup;
-       struct ipath_devdata *dd;
-       unsigned long flags;
-       int maxports;
-
-       nunits = npresent = nup = maxports = 0;
-
-       spin_lock_irqsave(&ipath_devs_lock, flags);
-
-       list_for_each_entry(dd, &ipath_dev_list, ipath_list) {
-               nunits++;
-               if ((dd->ipath_flags & IPATH_PRESENT) && dd->ipath_kregbase)
-                       npresent++;
-               if (dd->ipath_lid &&
-                   !(dd->ipath_flags & (IPATH_DISABLED | IPATH_LINKDOWN
-                                        | IPATH_LINKUNK)))
-                       nup++;
-               if (dd->ipath_cfgports > maxports)
-                       maxports = dd->ipath_cfgports;
-       }
-
-       spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-       if (npresentp)
-               *npresentp = npresent;
-       if (nupp)
-               *nupp = nup;
-       if (maxportsp)
-               *maxportsp = maxports;
-
-       return nunits;
-}
-
-/*
- * These next two routines are placeholders in case we don't have per-arch
- * code for controlling write combining.  If explicit control of write
- * combining is not available, performance will probably be awful.
- */
-
-int __attribute__((weak)) ipath_enable_wc(struct ipath_devdata *dd)
-{
-       return -EOPNOTSUPP;
-}
-
-void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd)
-{
-}
-
-/*
- * Perform a PIO buffer bandwidth write test, to verify proper system
- * configuration.  Even when all the setup calls work, occasionally
- * BIOS or other issues can prevent write combining from working, or
- * can cause other bandwidth problems to the chip.
- *
- * This test simply writes the same buffer over and over again, and
- * measures close to the peak bandwidth to the chip (not testing
- * data bandwidth to the wire).   On chips that use an address-based
- * trigger to send packets to the wire, this is easy.  On chips that
- * use a count to trigger, we want to make sure that the packet doesn't
- * go out on the wire, or trigger flow control checks.
- */
-static void ipath_verify_pioperf(struct ipath_devdata *dd)
-{
-       u32 pbnum, cnt, lcnt;
-       u32 __iomem *piobuf;
-       u32 *addr;
-       u64 msecs, emsecs;
-
-       piobuf = ipath_getpiobuf(dd, 0, &pbnum);
-       if (!piobuf) {
-               dev_info(&dd->pcidev->dev,
-                       "No PIObufs for checking perf, skipping\n");
-               return;
-       }
-
-       /*
-        * Enough to give us a reasonable test, less than piobuf size, and
-        * likely multiple of store buffer length.
-        */
-       cnt = 1024;
-
-       addr = vmalloc(cnt);
-       if (!addr) {
-               dev_info(&dd->pcidev->dev,
-                       "Couldn't get memory for checking PIO perf,"
-                       " skipping\n");
-               goto done;
-       }
-
-       preempt_disable();  /* we want reasonably accurate elapsed time */
-       msecs = 1 + jiffies_to_msecs(jiffies);
-       for (lcnt = 0; lcnt < 10000U; lcnt++) {
-               /* wait until we cross msec boundary */
-               if (jiffies_to_msecs(jiffies) >= msecs)
-                       break;
-               udelay(1);
-       }
-
-       ipath_disable_armlaunch(dd);
-
-       /*
-        * length 0, no dwords actually sent, and mark as VL15
-        * on chips where that may matter (due to IB flowcontrol)
-        */
-       if ((dd->ipath_flags & IPATH_HAS_PBC_CNT))
-               writeq(1UL << 63, piobuf);
-       else
-               writeq(0, piobuf);
-       ipath_flush_wc();
-
-       /*
-        * this is only roughly accurate, since even with preempt we
-        * still take interrupts that could take a while.   Running for
-        * >= 5 msec seems to get us "close enough" to accurate values
-        */
-       msecs = jiffies_to_msecs(jiffies);
-       for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {
-               __iowrite32_copy(piobuf + 64, addr, cnt >> 2);
-               emsecs = jiffies_to_msecs(jiffies) - msecs;
-       }
-
-       /* 1 GiB/sec, slightly over IB SDR line rate */
-       if (lcnt < (emsecs * 1024U))
-               ipath_dev_err(dd,
-                       "Performance problem: bandwidth to PIO buffers is "
-                       "only %u MiB/sec\n",
-                       lcnt / (u32) emsecs);
-       else
-               ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n",
-                       lcnt / (u32) emsecs);
-
-       preempt_enable();
-
-       vfree(addr);
-
-done:
-       /* disarm piobuf, so it's available again */
-       ipath_disarm_piobufs(dd, pbnum, 1);
-       ipath_enable_armlaunch(dd);
-}
-
-static void cleanup_device(struct ipath_devdata *dd);
-
-static int ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       int ret, len, j;
-       struct ipath_devdata *dd;
-       unsigned long long addr;
-       u32 bar0 = 0, bar1 = 0;
-
-#ifdef CONFIG_X86_64
-       if (pat_enabled()) {
-               pr_warn("ipath needs PAT disabled, boot with nopat kernel parameter\n");
-               ret = -ENODEV;
-               goto bail;
-       }
-#endif
-
-       dd = ipath_alloc_devdata(pdev);
-       if (IS_ERR(dd)) {
-               ret = PTR_ERR(dd);
-               printk(KERN_ERR IPATH_DRV_NAME
-                      ": Could not allocate devdata: error %d\n", -ret);
-               goto bail;
-       }
-
-       ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);
-
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               /* This can happen iff:
-                *
-                * We did a chip reset, and then failed to reprogram the
-                * BAR, or the chip reset due to an internal error.  We then
-                * unloaded the driver and reloaded it.
-                *
-                * Both reset cases set the BAR back to initial state.  For
-                * the latter case, the AER sticky error bit at offset 0x718
-                * should be set, but the Linux kernel doesn't yet know
-                * about that, it appears.  If the original BAR was retained
-                * in the kernel data structures, this may be OK.
-                */
-               ipath_dev_err(dd, "enable unit %d failed: error %d\n",
-                             dd->ipath_unit, -ret);
-               goto bail_devdata;
-       }
-       addr = pci_resource_start(pdev, 0);
-       len = pci_resource_len(pdev, 0);
-       ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %d, vend %x/%x "
-                  "driver_data %lx\n", addr, len, pdev->irq, ent->vendor,
-                  ent->device, ent->driver_data);
-
-       read_bars(dd, pdev, &bar0, &bar1);
-
-       if (!bar1 && !(bar0 & ~0xf)) {
-               if (addr) {
-                       dev_info(&pdev->dev, "BAR is 0 (probable RESET), "
-                                "rewriting as %llx\n", addr);
-                       ret = pci_write_config_dword(
-                               pdev, PCI_BASE_ADDRESS_0, addr);
-                       if (ret) {
-                               ipath_dev_err(dd, "rewrite of BAR0 "
-                                             "failed: err %d\n", -ret);
-                               goto bail_disable;
-                       }
-                       ret = pci_write_config_dword(
-                               pdev, PCI_BASE_ADDRESS_1, addr >> 32);
-                       if (ret) {
-                               ipath_dev_err(dd, "rewrite of BAR1 "
-                                             "failed: err %d\n", -ret);
-                               goto bail_disable;
-                       }
-               } else {
-                       ipath_dev_err(dd, "BAR is 0 (probable RESET), "
-                                     "not usable until reboot\n");
-                       ret = -ENODEV;
-                       goto bail_disable;
-               }
-       }
-
-       ret = pci_request_regions(pdev, IPATH_DRV_NAME);
-       if (ret) {
-               dev_info(&pdev->dev, "pci_request_regions unit %u fails: "
-                        "err %d\n", dd->ipath_unit, -ret);
-               goto bail_disable;
-       }
-
-       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-       if (ret) {
-               /*
-                * if the 64 bit setup fails, try 32 bit.  Some systems
-                * do not setup 64 bit maps on systems with 2GB or less
-                * memory installed.
-                */
-               ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-               if (ret) {
-                       dev_info(&pdev->dev,
-                               "Unable to set DMA mask for unit %u: %d\n",
-                               dd->ipath_unit, ret);
-                       goto bail_regions;
-               } else {
-                       ipath_dbg("No 64bit DMA mask, used 32 bit mask\n");
-                       ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-                       if (ret)
-                               dev_info(&pdev->dev,
-                                       "Unable to set DMA consistent mask "
-                                       "for unit %u: %d\n",
-                                       dd->ipath_unit, ret);
-
-               }
-       } else {
-               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
-               if (ret)
-                       dev_info(&pdev->dev,
-                               "Unable to set DMA consistent mask "
-                               "for unit %u: %d\n",
-                               dd->ipath_unit, ret);
-       }
-
-       pci_set_master(pdev);
-
-       /*
-        * Save BARs to rewrite after device reset.  Save all 64 bits of
-        * BAR, just in case.
-        */
-       dd->ipath_pcibar0 = addr;
-       dd->ipath_pcibar1 = addr >> 32;
-       dd->ipath_deviceid = ent->device;       /* save for later use */
-       dd->ipath_vendorid = ent->vendor;
-
-       /* setup the chip-specific functions, as early as possible. */
-       switch (ent->device) {
-       case PCI_DEVICE_ID_INFINIPATH_HT:
-               ipath_init_iba6110_funcs(dd);
-               break;
-
-       default:
-               ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
-                             "failing\n", ent->device);
-               return -ENODEV;
-       }
-
-       for (j = 0; j < 6; j++) {
-               if (!pdev->resource[j].start)
-                       continue;
-               ipath_cdbg(VERBOSE, "BAR %d %pR, len %llx\n",
-                          j, &pdev->resource[j],
-                          (unsigned long long)pci_resource_len(pdev, j));
-       }
-
-       if (!addr) {
-               ipath_dev_err(dd, "No valid address in BAR 0!\n");
-               ret = -ENODEV;
-               goto bail_regions;
-       }
-
-       dd->ipath_pcirev = pdev->revision;
-
-#if defined(__powerpc__)
-       /* There isn't a generic way to specify writethrough mappings */
-       dd->ipath_kregbase = __ioremap(addr, len,
-               (_PAGE_NO_CACHE|_PAGE_WRITETHRU));
-#else
-       /* XXX: split this properly to enable on PAT */
-       dd->ipath_kregbase = ioremap_nocache(addr, len);
-#endif
-
-       if (!dd->ipath_kregbase) {
-               ipath_dbg("Unable to map io addr %llx to kvirt, failing\n",
-                         addr);
-               ret = -ENOMEM;
-               goto bail_iounmap;
-       }
-       dd->ipath_kregend = (u64 __iomem *)
-               ((void __iomem *)dd->ipath_kregbase + len);
-       dd->ipath_physaddr = addr;      /* used for io_remap, etc. */
-       /* for user mmap */
-       ipath_cdbg(VERBOSE, "mapped io addr %llx to kregbase %p\n",
-                  addr, dd->ipath_kregbase);
-
-       if (dd->ipath_f_bus(dd, pdev))
-               ipath_dev_err(dd, "Failed to setup config space; "
-                             "continuing anyway\n");
-
-       /*
-        * set up our interrupt handler; IRQF_SHARED probably not needed,
-        * since MSI interrupts shouldn't be shared but won't  hurt for now.
-        * check 0 irq after we return from chip-specific bus setup, since
-        * that can affect this due to setup
-        */
-       if (!dd->ipath_irq)
-               ipath_dev_err(dd, "irq is 0, BIOS error?  Interrupts won't "
-                             "work\n");
-       else {
-               ret = request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED,
-                                 IPATH_DRV_NAME, dd);
-               if (ret) {
-                       ipath_dev_err(dd, "Couldn't setup irq handler, "
-                                     "irq=%d: %d\n", dd->ipath_irq, ret);
-                       goto bail_iounmap;
-               }
-       }
-
-       ret = ipath_init_chip(dd, 0);   /* do the chip-specific init */
-       if (ret)
-               goto bail_irqsetup;
-
-       ret = ipath_enable_wc(dd);
-
-       if (ret)
-               ret = 0;
-
-       ipath_verify_pioperf(dd);
-
-       ipath_device_create_group(&pdev->dev, dd);
-       ipathfs_add_device(dd);
-       ipath_user_add(dd);
-       ipath_diag_add(dd);
-       ipath_register_ib_device(dd);
-
-       goto bail;
-
-bail_irqsetup:
-       cleanup_device(dd);
-
-       if (dd->ipath_irq)
-               dd->ipath_f_free_irq(dd);
-
-       if (dd->ipath_f_cleanup)
-               dd->ipath_f_cleanup(dd);
-
-bail_iounmap:
-       iounmap((volatile void __iomem *) dd->ipath_kregbase);
-
-bail_regions:
-       pci_release_regions(pdev);
-
-bail_disable:
-       pci_disable_device(pdev);
-
-bail_devdata:
-       ipath_free_devdata(pdev, dd);
-
-bail:
-       return ret;
-}
-
-static void cleanup_device(struct ipath_devdata *dd)
-{
-       int port;
-       struct ipath_portdata **tmp;
-       unsigned long flags;
-
-       if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
-               /* can't do anything more with chip; needs re-init */
-               *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
-               if (dd->ipath_kregbase) {
-                       /*
-                        * if we haven't already cleaned up before these are
-                        * to ensure any register reads/writes "fail" until
-                        * re-init
-                        */
-                       dd->ipath_kregbase = NULL;
-                       dd->ipath_uregbase = 0;
-                       dd->ipath_sregbase = 0;
-                       dd->ipath_cregbase = 0;
-                       dd->ipath_kregsize = 0;
-               }
-               ipath_disable_wc(dd);
-       }
-
-       if (dd->ipath_spectriggerhit)
-               dev_info(&dd->pcidev->dev, "%lu special trigger hits\n",
-                        dd->ipath_spectriggerhit);
-
-       if (dd->ipath_pioavailregs_dma) {
-               dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
-                                 (void *) dd->ipath_pioavailregs_dma,
-                                 dd->ipath_pioavailregs_phys);
-               dd->ipath_pioavailregs_dma = NULL;
-       }
-       if (dd->ipath_dummy_hdrq) {
-               dma_free_coherent(&dd->pcidev->dev,
-                       dd->ipath_pd[0]->port_rcvhdrq_size,
-                       dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
-               dd->ipath_dummy_hdrq = NULL;
-       }
-
-       if (dd->ipath_pageshadow) {
-               struct page **tmpp = dd->ipath_pageshadow;
-               dma_addr_t *tmpd = dd->ipath_physshadow;
-               int i, cnt = 0;
-
-               ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
-                          "locked\n");
-               for (port = 0; port < dd->ipath_cfgports; port++) {
-                       int port_tidbase = port * dd->ipath_rcvtidcnt;
-                       int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
-                       for (i = port_tidbase; i < maxtid; i++) {
-                               if (!tmpp[i])
-                                       continue;
-                               pci_unmap_page(dd->pcidev, tmpd[i],
-                                       PAGE_SIZE, PCI_DMA_FROMDEVICE);
-                               ipath_release_user_pages(&tmpp[i], 1);
-                               tmpp[i] = NULL;
-                               cnt++;
-                       }
-               }
-               if (cnt) {
-                       ipath_stats.sps_pageunlocks += cnt;
-                       ipath_cdbg(VERBOSE, "There were still %u expTID "
-                                  "entries locked\n", cnt);
-               }
-               if (ipath_stats.sps_pagelocks ||
-                   ipath_stats.sps_pageunlocks)
-                       ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
-                                  "unlocked via ipath_m{un}lock\n",
-                                  (unsigned long long)
-                                  ipath_stats.sps_pagelocks,
-                                  (unsigned long long)
-                                  ipath_stats.sps_pageunlocks);
-
-               ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
-                          dd->ipath_pageshadow);
-               tmpp = dd->ipath_pageshadow;
-               dd->ipath_pageshadow = NULL;
-               vfree(tmpp);
-
-               dd->ipath_egrtidbase = NULL;
-       }
-
-       /*
-        * free any resources still in use (usually just kernel ports)
-        * at unload; we do for portcnt, because that's what we allocate.
-        * We acquire lock to be really paranoid that ipath_pd isn't being
-        * accessed from some interrupt-related code (that should not happen,
-        * but best to be sure).
-        */
-       spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
-       tmp = dd->ipath_pd;
-       dd->ipath_pd = NULL;
-       spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
-       for (port = 0; port < dd->ipath_portcnt; port++) {
-               struct ipath_portdata *pd = tmp[port];
-               tmp[port] = NULL; /* debugging paranoia */
-               ipath_free_pddata(dd, pd);
-       }
-       kfree(tmp);
-}
-
-static void ipath_remove_one(struct pci_dev *pdev)
-{
-       struct ipath_devdata *dd = pci_get_drvdata(pdev);
-
-       ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
-
-       /*
-        * disable the IB link early, to be sure no new packets arrive, which
-        * complicates the shutdown process
-        */
-       ipath_shutdown_device(dd);
-
-       flush_workqueue(ib_wq);
-
-       if (dd->verbs_dev)
-               ipath_unregister_ib_device(dd->verbs_dev);
-
-       ipath_diag_remove(dd);
-       ipath_user_remove(dd);
-       ipathfs_remove_device(dd);
-       ipath_device_remove_group(&pdev->dev, dd);
-
-       ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
-                  "unit %u\n", dd, (u32) dd->ipath_unit);
-
-       cleanup_device(dd);
-
-       /*
-        * turn off rcv, send, and interrupts for all ports, all drivers
-        * should also hard reset the chip here?
-        * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
-        * for all versions of the driver, if they were allocated
-        */
-       if (dd->ipath_irq) {
-               ipath_cdbg(VERBOSE, "unit %u free irq %d\n",
-                          dd->ipath_unit, dd->ipath_irq);
-               dd->ipath_f_free_irq(dd);
-       } else
-               ipath_dbg("irq is 0, not doing free_irq "
-                         "for unit %u\n", dd->ipath_unit);
-       /*
-        * we check for NULL here, because it's outside
-        * the kregbase check, and we need to call it
-        * after the free_irq.  Thus it's possible that
-        * the function pointers were never initialized.
-        */
-       if (dd->ipath_f_cleanup)
-               /* clean up chip-specific stuff */
-               dd->ipath_f_cleanup(dd);
-
-       ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", dd->ipath_kregbase);
-       iounmap((volatile void __iomem *) dd->ipath_kregbase);
-       pci_release_regions(pdev);
-       ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
-       pci_disable_device(pdev);
-
-       ipath_free_devdata(pdev, dd);
-}
-
-/* general driver use */
-DEFINE_MUTEX(ipath_mutex);
-
-static DEFINE_SPINLOCK(ipath_pioavail_lock);
-
-/**
- * ipath_disarm_piobufs - cancel a range of PIO buffers
- * @dd: the infinipath device
- * @first: the first PIO buffer to cancel
- * @cnt: the number of PIO buffers to cancel
- *
- * cancel a range of PIO buffers, used when they might be armed, but
- * not triggered.  Used at init to ensure buffer state, and also user
- * process close, in case it died while writing to a PIO buffer
- * Also after errors.
- */
-void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
-                         unsigned cnt)
-{
-       unsigned i, last = first + cnt;
-       unsigned long flags;
-
-       ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
-       for (i = first; i < last; i++) {
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               /*
-                * The disarm-related bits are write-only, so it
-                * is ok to OR them in with our copy of sendctrl
-                * while we hold the lock.
-                */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                       dd->ipath_sendctrl | INFINIPATH_S_DISARM |
-                       (i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
-               /* can't disarm bufs back-to-back per iba7220 spec */
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-       }
-       /* on some older chips, update may not happen after cancel */
-       ipath_force_pio_avail_update(dd);
-}
-
-/**
- * ipath_wait_linkstate - wait for an IB link state change to occur
- * @dd: the infinipath device
- * @state: the state to wait for
- * @msecs: the number of milliseconds to wait
- *
- * wait up to msecs milliseconds for IB link state change to occur for
- * now, take the easy polling route.  Currently used only by
- * ipath_set_linkstate.  Returns 0 if state reached, otherwise
- * -ETIMEDOUT state can have multiple states set, for any of several
- * transitions.
- */
-int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
-{
-       dd->ipath_state_wanted = state;
-       wait_event_interruptible_timeout(ipath_state_wait,
-                                        (dd->ipath_flags & state),
-                                        msecs_to_jiffies(msecs));
-       dd->ipath_state_wanted = 0;
-
-       if (!(dd->ipath_flags & state)) {
-               u64 val;
-               ipath_cdbg(VERBOSE, "Didn't reach linkstate %s within %u"
-                          " ms\n",
-                          /* test INIT ahead of DOWN, both can be set */
-                          (state & IPATH_LINKINIT) ? "INIT" :
-                          ((state & IPATH_LINKDOWN) ? "DOWN" :
-                           ((state & IPATH_LINKARMED) ? "ARM" : "ACTIVE")),
-                          msecs);
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-               ipath_cdbg(VERBOSE, "ibcc=%llx ibcstatus=%llx (%s)\n",
-                          (unsigned long long) ipath_read_kreg64(
-                                  dd, dd->ipath_kregs->kr_ibcctrl),
-                          (unsigned long long) val,
-                          ipath_ibcstatus_str[val & dd->ibcs_lts_mask]);
-       }
-       return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT;
-}
-
-static void decode_sdma_errs(struct ipath_devdata *dd, ipath_err_t err,
-       char *buf, size_t blen)
-{
-       static const struct {
-               ipath_err_t err;
-               const char *msg;
-       } errs[] = {
-               { INFINIPATH_E_SDMAGENMISMATCH, "SDmaGenMismatch" },
-               { INFINIPATH_E_SDMAOUTOFBOUND, "SDmaOutOfBound" },
-               { INFINIPATH_E_SDMATAILOUTOFBOUND, "SDmaTailOutOfBound" },
-               { INFINIPATH_E_SDMABASE, "SDmaBase" },
-               { INFINIPATH_E_SDMA1STDESC, "SDma1stDesc" },
-               { INFINIPATH_E_SDMARPYTAG, "SDmaRpyTag" },
-               { INFINIPATH_E_SDMADWEN, "SDmaDwEn" },
-               { INFINIPATH_E_SDMAMISSINGDW, "SDmaMissingDw" },
-               { INFINIPATH_E_SDMAUNEXPDATA, "SDmaUnexpData" },
-               { INFINIPATH_E_SDMADESCADDRMISALIGN, "SDmaDescAddrMisalign" },
-               { INFINIPATH_E_SENDBUFMISUSE, "SendBufMisuse" },
-               { INFINIPATH_E_SDMADISABLED, "SDmaDisabled" },
-       };
-       int i;
-       int expected;
-       size_t bidx = 0;
-
-       for (i = 0; i < ARRAY_SIZE(errs); i++) {
-               expected = (errs[i].err != INFINIPATH_E_SDMADISABLED) ? 0 :
-                       test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
-               if ((err & errs[i].err) && !expected)
-                       bidx += snprintf(buf + bidx, blen - bidx,
-                                        "%s ", errs[i].msg);
-       }
-}
-
-/*
- * Decode the error status into strings, deciding whether to always
- * print * it or not depending on "normal packet errors" vs everything
- * else.   Return 1 if "real" errors, otherwise 0 if only packet
- * errors, so caller can decide what to print with the string.
- */
-int ipath_decode_err(struct ipath_devdata *dd, char *buf, size_t blen,
-       ipath_err_t err)
-{
-       int iserr = 1;
-       *buf = '\0';
-       if (err & INFINIPATH_E_PKTERRS) {
-               if (!(err & ~INFINIPATH_E_PKTERRS))
-                       iserr = 0; // if only packet errors.
-               if (ipath_debug & __IPATH_ERRPKTDBG) {
-                       if (err & INFINIPATH_E_REBP)
-                               strlcat(buf, "EBP ", blen);
-                       if (err & INFINIPATH_E_RVCRC)
-                               strlcat(buf, "VCRC ", blen);
-                       if (err & INFINIPATH_E_RICRC) {
-                               strlcat(buf, "CRC ", blen);
-                               // clear for check below, so only once
-                               err &= INFINIPATH_E_RICRC;
-                       }
-                       if (err & INFINIPATH_E_RSHORTPKTLEN)
-                               strlcat(buf, "rshortpktlen ", blen);
-                       if (err & INFINIPATH_E_SDROPPEDDATAPKT)
-                               strlcat(buf, "sdroppeddatapkt ", blen);
-                       if (err & INFINIPATH_E_SPKTLEN)
-                               strlcat(buf, "spktlen ", blen);
-               }
-               if ((err & INFINIPATH_E_RICRC) &&
-                       !(err&(INFINIPATH_E_RVCRC|INFINIPATH_E_REBP)))
-                       strlcat(buf, "CRC ", blen);
-               if (!iserr)
-                       goto done;
-       }
-       if (err & INFINIPATH_E_RHDRLEN)
-               strlcat(buf, "rhdrlen ", blen);
-       if (err & INFINIPATH_E_RBADTID)
-               strlcat(buf, "rbadtid ", blen);
-       if (err & INFINIPATH_E_RBADVERSION)
-               strlcat(buf, "rbadversion ", blen);
-       if (err & INFINIPATH_E_RHDR)
-               strlcat(buf, "rhdr ", blen);
-       if (err & INFINIPATH_E_SENDSPECIALTRIGGER)
-               strlcat(buf, "sendspecialtrigger ", blen);
-       if (err & INFINIPATH_E_RLONGPKTLEN)
-               strlcat(buf, "rlongpktlen ", blen);
-       if (err & INFINIPATH_E_RMAXPKTLEN)
-               strlcat(buf, "rmaxpktlen ", blen);
-       if (err & INFINIPATH_E_RMINPKTLEN)
-               strlcat(buf, "rminpktlen ", blen);
-       if (err & INFINIPATH_E_SMINPKTLEN)
-               strlcat(buf, "sminpktlen ", blen);
-       if (err & INFINIPATH_E_RFORMATERR)
-               strlcat(buf, "rformaterr ", blen);
-       if (err & INFINIPATH_E_RUNSUPVL)
-               strlcat(buf, "runsupvl ", blen);
-       if (err & INFINIPATH_E_RUNEXPCHAR)
-               strlcat(buf, "runexpchar ", blen);
-       if (err & INFINIPATH_E_RIBFLOW)
-               strlcat(buf, "ribflow ", blen);
-       if (err & INFINIPATH_E_SUNDERRUN)
-               strlcat(buf, "sunderrun ", blen);
-       if (err & INFINIPATH_E_SPIOARMLAUNCH)
-               strlcat(buf, "spioarmlaunch ", blen);
-       if (err & INFINIPATH_E_SUNEXPERRPKTNUM)
-               strlcat(buf, "sunexperrpktnum ", blen);
-       if (err & INFINIPATH_E_SDROPPEDSMPPKT)
-               strlcat(buf, "sdroppedsmppkt ", blen);
-       if (err & INFINIPATH_E_SMAXPKTLEN)
-               strlcat(buf, "smaxpktlen ", blen);
-       if (err & INFINIPATH_E_SUNSUPVL)
-               strlcat(buf, "sunsupVL ", blen);
-       if (err & INFINIPATH_E_INVALIDADDR)
-               strlcat(buf, "invalidaddr ", blen);
-       if (err & INFINIPATH_E_RRCVEGRFULL)
-               strlcat(buf, "rcvegrfull ", blen);
-       if (err & INFINIPATH_E_RRCVHDRFULL)
-               strlcat(buf, "rcvhdrfull ", blen);
-       if (err & INFINIPATH_E_IBSTATUSCHANGED)
-               strlcat(buf, "ibcstatuschg ", blen);
-       if (err & INFINIPATH_E_RIBLOSTLINK)
-               strlcat(buf, "riblostlink ", blen);
-       if (err & INFINIPATH_E_HARDWARE)
-               strlcat(buf, "hardware ", blen);
-       if (err & INFINIPATH_E_RESET)
-               strlcat(buf, "reset ", blen);
-       if (err & INFINIPATH_E_SDMAERRS)
-               decode_sdma_errs(dd, err, buf, blen);
-       if (err & INFINIPATH_E_INVALIDEEPCMD)
-               strlcat(buf, "invalideepromcmd ", blen);
-done:
-       return iserr;
-}
-
-/**
- * get_rhf_errstring - decode RHF errors
- * @err: the err number
- * @msg: the output buffer
- * @len: the length of the output buffer
- *
- * only used one place now, may want more later
- */
-static void get_rhf_errstring(u32 err, char *msg, size_t len)
-{
-       /* if no errors, and so don't need to check what's first */
-       *msg = '\0';
-
-       if (err & INFINIPATH_RHF_H_ICRCERR)
-               strlcat(msg, "icrcerr ", len);
-       if (err & INFINIPATH_RHF_H_VCRCERR)
-               strlcat(msg, "vcrcerr ", len);
-       if (err & INFINIPATH_RHF_H_PARITYERR)
-               strlcat(msg, "parityerr ", len);
-       if (err & INFINIPATH_RHF_H_LENERR)
-               strlcat(msg, "lenerr ", len);
-       if (err & INFINIPATH_RHF_H_MTUERR)
-               strlcat(msg, "mtuerr ", len);
-       if (err & INFINIPATH_RHF_H_IHDRERR)
-               /* infinipath hdr checksum error */
-               strlcat(msg, "ipathhdrerr ", len);
-       if (err & INFINIPATH_RHF_H_TIDERR)
-               strlcat(msg, "tiderr ", len);
-       if (err & INFINIPATH_RHF_H_MKERR)
-               /* bad port, offset, etc. */
-               strlcat(msg, "invalid ipathhdr ", len);
-       if (err & INFINIPATH_RHF_H_IBERR)
-               strlcat(msg, "iberr ", len);
-       if (err & INFINIPATH_RHF_L_SWA)
-               strlcat(msg, "swA ", len);
-       if (err & INFINIPATH_RHF_L_SWB)
-               strlcat(msg, "swB ", len);
-}
-
-/**
- * ipath_get_egrbuf - get an eager buffer
- * @dd: the infinipath device
- * @bufnum: the eager buffer to get
- *
- * must only be called if ipath_pd[port] is known to be allocated
- */
-static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
-{
-       return dd->ipath_port0_skbinfo ?
-               (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
-}
-
-/**
- * ipath_alloc_skb - allocate an skb and buffer with possible constraints
- * @dd: the infinipath device
- * @gfp_mask: the sk_buff SFP mask
- */
-struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd,
-                               gfp_t gfp_mask)
-{
-       struct sk_buff *skb;
-       u32 len;
-
-       /*
-        * Only fully supported way to handle this is to allocate lots
-        * extra, align as needed, and then do skb_reserve().  That wastes
-        * a lot of memory...  I'll have to hack this into infinipath_copy
-        * also.
-        */
-
-       /*
-        * We need 2 extra bytes for ipath_ether data sent in the
-        * key header.  In order to keep everything dword aligned,
-        * we'll reserve 4 bytes.
-        */
-       len = dd->ipath_ibmaxlen + 4;
-
-       if (dd->ipath_flags & IPATH_4BYTE_TID) {
-               /* We need a 2KB multiple alignment, and there is no way
-                * to do it except to allocate extra and then skb_reserve
-                * enough to bring it up to the right alignment.
-                */
-               len += 2047;
-       }
-
-       skb = __dev_alloc_skb(len, gfp_mask);
-       if (!skb) {
-               ipath_dev_err(dd, "Failed to allocate skbuff, length %u\n",
-                             len);
-               goto bail;
-       }
-
-       skb_reserve(skb, 4);
-
-       if (dd->ipath_flags & IPATH_4BYTE_TID) {
-               u32 una = (unsigned long)skb->data & 2047;
-               if (una)
-                       skb_reserve(skb, 2048 - una);
-       }
-
-bail:
-       return skb;
-}
-
-static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
-                            u32 eflags,
-                            u32 l,
-                            u32 etail,
-                            __le32 *rhf_addr,
-                            struct ipath_message_header *hdr)
-{
-       char emsg[128];
-
-       get_rhf_errstring(eflags, emsg, sizeof emsg);
-       ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u "
-                  "tlen=%x opcode=%x egridx=%x: %s\n",
-                  eflags, l,
-                  ipath_hdrget_rcv_type(rhf_addr),
-                  ipath_hdrget_length_in_bytes(rhf_addr),
-                  be32_to_cpu(hdr->bth[0]) >> 24,
-                  etail, emsg);
-
-       /* Count local link integrity errors. */
-       if (eflags & (INFINIPATH_RHF_H_ICRCERR | INFINIPATH_RHF_H_VCRCERR)) {
-               u8 n = (dd->ipath_ibcctrl >>
-                       INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
-                       INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
-
-               if (++dd->ipath_lli_counter > n) {
-                       dd->ipath_lli_counter = 0;
-                       dd->ipath_lli_errors++;
-               }
-       }
-}
-
-/*
- * ipath_kreceive - receive a packet
- * @pd: the infinipath port
- *
- * called from interrupt handler for errors or receive interrupt
- */
-void ipath_kreceive(struct ipath_portdata *pd)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       __le32 *rhf_addr;
-       void *ebuf;
-       const u32 rsize = dd->ipath_rcvhdrentsize;      /* words */
-       const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
-       u32 etail = -1, l, hdrqtail;
-       struct ipath_message_header *hdr;
-       u32 eflags, i, etype, tlen, pkttot = 0, updegr = 0, reloop = 0;
-       static u64 totcalls;    /* stats, may eventually remove */
-       int last;
-
-       l = pd->port_head;
-       rhf_addr = (__le32 *) pd->port_rcvhdrq + l + dd->ipath_rhf_offset;
-       if (dd->ipath_flags & IPATH_NODMA_RTAIL) {
-               u32 seq = ipath_hdrget_seq(rhf_addr);
-
-               if (seq != pd->port_seq_cnt)
-                       goto bail;
-               hdrqtail = 0;
-       } else {
-               hdrqtail = ipath_get_rcvhdrtail(pd);
-               if (l == hdrqtail)
-                       goto bail;
-               smp_rmb();
-       }
-
-reloop:
-       for (last = 0, i = 1; !last; i += !last) {
-               hdr = dd->ipath_f_get_msgheader(dd, rhf_addr);
-               eflags = ipath_hdrget_err_flags(rhf_addr);
-               etype = ipath_hdrget_rcv_type(rhf_addr);
-               /* total length */
-               tlen = ipath_hdrget_length_in_bytes(rhf_addr);
-               ebuf = NULL;
-               if ((dd->ipath_flags & IPATH_NODMA_RTAIL) ?
-                   ipath_hdrget_use_egr_buf(rhf_addr) :
-                   (etype != RCVHQ_RCV_TYPE_EXPECTED)) {
-                       /*
-                        * It turns out that the chip uses an eager buffer
-                        * for all non-expected packets, whether it "needs"
-                        * one or not.  So always get the index, but don't
-                        * set ebuf (so we try to copy data) unless the
-                        * length requires it.
-                        */
-                       etail = ipath_hdrget_index(rhf_addr);
-                       updegr = 1;
-                       if (tlen > sizeof(*hdr) ||
-                           etype == RCVHQ_RCV_TYPE_NON_KD)
-                               ebuf = ipath_get_egrbuf(dd, etail);
-               }
-
-               /*
-                * both tiderr and ipathhdrerr are set for all plain IB
-                * packets; only ipathhdrerr should be set.
-                */
-
-               if (etype != RCVHQ_RCV_TYPE_NON_KD &&
-                   etype != RCVHQ_RCV_TYPE_ERROR &&
-                   ipath_hdrget_ipath_ver(hdr->iph.ver_port_tid_offset) !=
-                   IPS_PROTO_VERSION)
-                       ipath_cdbg(PKT, "Bad InfiniPath protocol version "
-                                  "%x\n", etype);
-
-               if (unlikely(eflags))
-                       ipath_rcv_hdrerr(dd, eflags, l, etail, rhf_addr, hdr);
-               else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
-                       ipath_ib_rcv(dd->verbs_dev, (u32 *)hdr, ebuf, tlen);
-                       if (dd->ipath_lli_counter)
-                               dd->ipath_lli_counter--;
-               } else if (etype == RCVHQ_RCV_TYPE_EAGER) {
-                       u8 opcode = be32_to_cpu(hdr->bth[0]) >> 24;
-                       u32 qp = be32_to_cpu(hdr->bth[1]) & 0xffffff;
-                       ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
-                                  "qp=%x), len %x; ignored\n",
-                                  etype, opcode, qp, tlen);
-               } else if (etype == RCVHQ_RCV_TYPE_EXPECTED) {
-                       ipath_dbg("Bug: Expected TID, opcode %x; ignored\n",
-                                 be32_to_cpu(hdr->bth[0]) >> 24);
-               } else {
-                       /*
-                        * error packet, type of error unknown.
-                        * Probably type 3, but we don't know, so don't
-                        * even try to print the opcode, etc.
-                        * Usually caused by a "bad packet", that has no
-                        * BTH, when the LRH says it should.
-                        */
-                       ipath_cdbg(ERRPKT, "Error Pkt, but no eflags! egrbuf"
-                                 " %x, len %x hdrq+%x rhf: %Lx\n",
-                                 etail, tlen, l, (unsigned long long)
-                                 le64_to_cpu(*(__le64 *) rhf_addr));
-                       if (ipath_debug & __IPATH_ERRPKTDBG) {
-                               u32 j, *d, dw = rsize-2;
-                               if (rsize > (tlen>>2))
-                                       dw = tlen>>2;
-                               d = (u32 *)hdr;
-                               printk(KERN_DEBUG "EPkt rcvhdr(%x dw):\n",
-                                       dw);
-                               for (j = 0; j < dw; j++)
-                                       printk(KERN_DEBUG "%8x%s", d[j],
-                                               (j%8) == 7 ? "\n" : " ");
-                               printk(KERN_DEBUG ".\n");
-                       }
-               }
-               l += rsize;
-               if (l >= maxcnt)
-                       l = 0;
-               rhf_addr = (__le32 *) pd->port_rcvhdrq +
-                       l + dd->ipath_rhf_offset;
-               if (dd->ipath_flags & IPATH_NODMA_RTAIL) {
-                       u32 seq = ipath_hdrget_seq(rhf_addr);
-
-                       if (++pd->port_seq_cnt > 13)
-                               pd->port_seq_cnt = 1;
-                       if (seq != pd->port_seq_cnt)
-                               last = 1;
-               } else if (l == hdrqtail) {
-                       last = 1;
-               }
-               /*
-                * update head regs on last packet, and every 16 packets.
-                * Reduce bus traffic, while still trying to prevent
-                * rcvhdrq overflows, for when the queue is nearly full
-                */
-               if (last || !(i & 0xf)) {
-                       u64 lval = l;
-
-                       /* request IBA6120 and 7220 interrupt only on last */
-                       if (last)
-                               lval |= dd->ipath_rhdrhead_intr_off;
-                       ipath_write_ureg(dd, ur_rcvhdrhead, lval,
-                               pd->port_port);
-                       if (updegr) {
-                               ipath_write_ureg(dd, ur_rcvegrindexhead,
-                                                etail, pd->port_port);
-                               updegr = 0;
-                       }
-               }
-       }
-
-       if (!dd->ipath_rhdrhead_intr_off && !reloop &&
-           !(dd->ipath_flags & IPATH_NODMA_RTAIL)) {
-               /* IBA6110 workaround; we can have a race clearing chip
-                * interrupt with another interrupt about to be delivered,
-                * and can clear it before it is delivered on the GPIO
-                * workaround.  By doing the extra check here for the
-                * in-memory tail register updating while we were doing
-                * earlier packets, we "almost" guarantee we have covered
-                * that case.
-                */
-               u32 hqtail = ipath_get_rcvhdrtail(pd);
-               if (hqtail != hdrqtail) {
-                       hdrqtail = hqtail;
-                       reloop = 1; /* loop 1 extra time at most */
-                       goto reloop;
-               }
-       }
-
-       pkttot += i;
-
-       pd->port_head = l;
-
-       if (pkttot > ipath_stats.sps_maxpkts_call)
-               ipath_stats.sps_maxpkts_call = pkttot;
-       ipath_stats.sps_port0pkts += pkttot;
-       ipath_stats.sps_avgpkts_call =
-               ipath_stats.sps_port0pkts / ++totcalls;
-
-bail:;
-}
-
-/**
- * ipath_update_pio_bufs - update shadow copy of the PIO availability map
- * @dd: the infinipath device
- *
- * called whenever our local copy indicates we have run out of send buffers
- * NOTE: This can be called from interrupt context by some code
- * and from non-interrupt context by ipath_getpiobuf().
- */
-
-static void ipath_update_pio_bufs(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-       int i;
-       const unsigned piobregs = (unsigned)dd->ipath_pioavregs;
-
-       /* If the generation (check) bits have changed, then we update the
-        * busy bit for the corresponding PIO buffer.  This algorithm will
-        * modify positions to the value they already have in some cases
-        * (i.e., no change), but it's faster than changing only the bits
-        * that have changed.
-        *
-        * We would like to do this atomicly, to avoid spinlocks in the
-        * critical send path, but that's not really possible, given the
-        * type of changes, and that this routine could be called on
-        * multiple cpu's simultaneously, so we lock in this routine only,
-        * to avoid conflicting updates; all we change is the shadow, and
-        * it's a single 64 bit memory location, so by definition the update
-        * is atomic in terms of what other cpu's can see in testing the
-        * bits.  The spin_lock overhead isn't too bad, since it only
-        * happens when all buffers are in use, so only cpu overhead, not
-        * latency or bandwidth is affected.
-        */
-       if (!dd->ipath_pioavailregs_dma) {
-               ipath_dbg("Update shadow pioavail, but regs_dma NULL!\n");
-               return;
-       }
-       if (ipath_debug & __IPATH_VERBDBG) {
-               /* only if packet debug and verbose */
-               volatile __le64 *dma = dd->ipath_pioavailregs_dma;
-               unsigned long *shadow = dd->ipath_pioavailshadow;
-
-               ipath_cdbg(PKT, "Refill avail, dma0=%llx shad0=%lx, "
-                          "d1=%llx s1=%lx, d2=%llx s2=%lx, d3=%llx "
-                          "s3=%lx\n",
-                          (unsigned long long) le64_to_cpu(dma[0]),
-                          shadow[0],
-                          (unsigned long long) le64_to_cpu(dma[1]),
-                          shadow[1],
-                          (unsigned long long) le64_to_cpu(dma[2]),
-                          shadow[2],
-                          (unsigned long long) le64_to_cpu(dma[3]),
-                          shadow[3]);
-               if (piobregs > 4)
-                       ipath_cdbg(
-                               PKT, "2nd group, dma4=%llx shad4=%lx, "
-                               "d5=%llx s5=%lx, d6=%llx s6=%lx, "
-                               "d7=%llx s7=%lx\n",
-                               (unsigned long long) le64_to_cpu(dma[4]),
-                               shadow[4],
-                               (unsigned long long) le64_to_cpu(dma[5]),
-                               shadow[5],
-                               (unsigned long long) le64_to_cpu(dma[6]),
-                               shadow[6],
-                               (unsigned long long) le64_to_cpu(dma[7]),
-                               shadow[7]);
-       }
-       spin_lock_irqsave(&ipath_pioavail_lock, flags);
-       for (i = 0; i < piobregs; i++) {
-               u64 pchbusy, pchg, piov, pnew;
-               /*
-                * Chip Errata: bug 6641; even and odd qwords>3 are swapped
-                */
-               if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
-                       piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
-               else
-                       piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
-               pchg = dd->ipath_pioavailkernel[i] &
-                       ~(dd->ipath_pioavailshadow[i] ^ piov);
-               pchbusy = pchg << INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT;
-               if (pchg && (pchbusy & dd->ipath_pioavailshadow[i])) {
-                       pnew = dd->ipath_pioavailshadow[i] & ~pchbusy;
-                       pnew |= piov & pchbusy;
-                       dd->ipath_pioavailshadow[i] = pnew;
-               }
-       }
-       spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
-}
-
-/*
- * used to force update of pioavailshadow if we can't get a pio buffer.
- * Needed primarily due to exitting freeze mode after recovering
- * from errors.  Done lazily, because it's safer (known to not
- * be writing pio buffers).
- */
-static void ipath_reset_availshadow(struct ipath_devdata *dd)
-{
-       int i, im;
-       unsigned long flags;
-
-       spin_lock_irqsave(&ipath_pioavail_lock, flags);
-       for (i = 0; i < dd->ipath_pioavregs; i++) {
-               u64 val, oldval;
-               /* deal with 6110 chip bug on high register #s */
-               im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
-                       i ^ 1 : i;
-               val = le64_to_cpu(dd->ipath_pioavailregs_dma[im]);
-               /*
-                * busy out the buffers not in the kernel avail list,
-                * without changing the generation bits.
-                */
-               oldval = dd->ipath_pioavailshadow[i];
-               dd->ipath_pioavailshadow[i] = val |
-                       ((~dd->ipath_pioavailkernel[i] <<
-                       INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT) &
-                       0xaaaaaaaaaaaaaaaaULL); /* All BUSY bits in qword */
-               if (oldval != dd->ipath_pioavailshadow[i])
-                       ipath_dbg("shadow[%d] was %Lx, now %lx\n",
-                               i, (unsigned long long) oldval,
-                               dd->ipath_pioavailshadow[i]);
-       }
-       spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
-}
-
-/**
- * ipath_setrcvhdrsize - set the receive header size
- * @dd: the infinipath device
- * @rhdrsize: the receive header size
- *
- * called from user init code, and also layered driver init
- */
-int ipath_setrcvhdrsize(struct ipath_devdata *dd, unsigned rhdrsize)
-{
-       int ret = 0;
-
-       if (dd->ipath_flags & IPATH_RCVHDRSZ_SET) {
-               if (dd->ipath_rcvhdrsize != rhdrsize) {
-                       dev_info(&dd->pcidev->dev,
-                                "Error: can't set protocol header "
-                                "size %u, already %u\n",
-                                rhdrsize, dd->ipath_rcvhdrsize);
-                       ret = -EAGAIN;
-               } else
-                       ipath_cdbg(VERBOSE, "Reuse same protocol header "
-                                  "size %u\n", dd->ipath_rcvhdrsize);
-       } else if (rhdrsize > (dd->ipath_rcvhdrentsize -
-                              (sizeof(u64) / sizeof(u32)))) {
-               ipath_dbg("Error: can't set protocol header size %u "
-                         "(> max %u)\n", rhdrsize,
-                         dd->ipath_rcvhdrentsize -
-                         (u32) (sizeof(u64) / sizeof(u32)));
-               ret = -EOVERFLOW;
-       } else {
-               dd->ipath_flags |= IPATH_RCVHDRSZ_SET;
-               dd->ipath_rcvhdrsize = rhdrsize;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrsize,
-                                dd->ipath_rcvhdrsize);
-               ipath_cdbg(VERBOSE, "Set protocol header size to %u\n",
-                          dd->ipath_rcvhdrsize);
-       }
-       return ret;
-}
-
-/*
- * debugging code and stats updates if no pio buffers available.
- */
-static noinline void no_pio_bufs(struct ipath_devdata *dd)
-{
-       unsigned long *shadow = dd->ipath_pioavailshadow;
-       __le64 *dma = (__le64 *)dd->ipath_pioavailregs_dma;
-
-       dd->ipath_upd_pio_shadow = 1;
-
-       /*
-        * not atomic, but if we lose a stat count in a while, that's OK
-        */
-       ipath_stats.sps_nopiobufs++;
-       if (!(++dd->ipath_consec_nopiobuf % 100000)) {
-               ipath_force_pio_avail_update(dd); /* at start */
-               ipath_dbg("%u tries no piobufavail ts%lx; dmacopy: "
-                       "%llx %llx %llx %llx\n"
-                       "ipath  shadow:  %lx %lx %lx %lx\n",
-                       dd->ipath_consec_nopiobuf,
-                       (unsigned long)get_cycles(),
-                       (unsigned long long) le64_to_cpu(dma[0]),
-                       (unsigned long long) le64_to_cpu(dma[1]),
-                       (unsigned long long) le64_to_cpu(dma[2]),
-                       (unsigned long long) le64_to_cpu(dma[3]),
-                       shadow[0], shadow[1], shadow[2], shadow[3]);
-               /*
-                * 4 buffers per byte, 4 registers above, cover rest
-                * below
-                */
-               if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) >
-                   (sizeof(shadow[0]) * 4 * 4))
-                       ipath_dbg("2nd group: dmacopy: "
-                                 "%llx %llx %llx %llx\n"
-                                 "ipath  shadow:  %lx %lx %lx %lx\n",
-                                 (unsigned long long)le64_to_cpu(dma[4]),
-                                 (unsigned long long)le64_to_cpu(dma[5]),
-                                 (unsigned long long)le64_to_cpu(dma[6]),
-                                 (unsigned long long)le64_to_cpu(dma[7]),
-                                 shadow[4], shadow[5], shadow[6], shadow[7]);
-
-               /* at end, so update likely happened */
-               ipath_reset_availshadow(dd);
-       }
-}
-
-/*
- * common code for normal driver pio buffer allocation, and reserved
- * allocation.
- *
- * do appropriate marking as busy, etc.
- * returns buffer number if one found (>=0), negative number is error.
- */
-static u32 __iomem *ipath_getpiobuf_range(struct ipath_devdata *dd,
-       u32 *pbufnum, u32 first, u32 last, u32 firsti)
-{
-       int i, j, updated = 0;
-       unsigned piobcnt;
-       unsigned long flags;
-       unsigned long *shadow = dd->ipath_pioavailshadow;
-       u32 __iomem *buf;
-
-       piobcnt = last - first;
-       if (dd->ipath_upd_pio_shadow) {
-               /*
-                * Minor optimization.  If we had no buffers on last call,
-                * start out by doing the update; continue and do scan even
-                * if no buffers were updated, to be paranoid
-                */
-               ipath_update_pio_bufs(dd);
-               updated++;
-               i = first;
-       } else
-               i = firsti;
-rescan:
-       /*
-        * while test_and_set_bit() is atomic, we do that and then the
-        * change_bit(), and the pair is not.  See if this is the cause
-        * of the remaining armlaunch errors.
-        */
-       spin_lock_irqsave(&ipath_pioavail_lock, flags);
-       for (j = 0; j < piobcnt; j++, i++) {
-               if (i >= last)
-                       i = first;
-               if (__test_and_set_bit((2 * i) + 1, shadow))
-                       continue;
-               /* flip generation bit */
-               __change_bit(2 * i, shadow);
-               break;
-       }
-       spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
-
-       if (j == piobcnt) {
-               if (!updated) {
-                       /*
-                        * first time through; shadow exhausted, but may be
-                        * buffers available, try an update and then rescan.
-                        */
-                       ipath_update_pio_bufs(dd);
-                       updated++;
-                       i = first;
-                       goto rescan;
-               } else if (updated == 1 && piobcnt <=
-                       ((dd->ipath_sendctrl
-                       >> INFINIPATH_S_UPDTHRESH_SHIFT) &
-                       INFINIPATH_S_UPDTHRESH_MASK)) {
-                       /*
-                        * for chips supporting and using the update
-                        * threshold we need to force an update of the
-                        * in-memory copy if the count is less than the
-                        * thershold, then check one more time.
-                        */
-                       ipath_force_pio_avail_update(dd);
-                       ipath_update_pio_bufs(dd);
-                       updated++;
-                       i = first;
-                       goto rescan;
-               }
-
-               no_pio_bufs(dd);
-               buf = NULL;
-       } else {
-               if (i < dd->ipath_piobcnt2k)
-                       buf = (u32 __iomem *) (dd->ipath_pio2kbase +
-                                              i * dd->ipath_palign);
-               else
-                       buf = (u32 __iomem *)
-                               (dd->ipath_pio4kbase +
-                                (i - dd->ipath_piobcnt2k) * dd->ipath_4kalign);
-               if (pbufnum)
-                       *pbufnum = i;
-       }
-
-       return buf;
-}
-
-/**
- * ipath_getpiobuf - find an available pio buffer
- * @dd: the infinipath device
- * @plen: the size of the PIO buffer needed in 32-bit words
- * @pbufnum: the buffer number is placed here
- */
-u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 plen, u32 *pbufnum)
-{
-       u32 __iomem *buf;
-       u32 pnum, nbufs;
-       u32 first, lasti;
-
-       if (plen + 1 >= IPATH_SMALLBUF_DWORDS) {
-               first = dd->ipath_piobcnt2k;
-               lasti = dd->ipath_lastpioindexl;
-       } else {
-               first = 0;
-               lasti = dd->ipath_lastpioindex;
-       }
-       nbufs = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
-       buf = ipath_getpiobuf_range(dd, &pnum, first, nbufs, lasti);
-
-       if (buf) {
-               /*
-                * Set next starting place.  It's just an optimization,
-                * it doesn't matter who wins on this, so no locking
-                */
-               if (plen + 1 >= IPATH_SMALLBUF_DWORDS)
-                       dd->ipath_lastpioindexl = pnum + 1;
-               else
-                       dd->ipath_lastpioindex = pnum + 1;
-               if (dd->ipath_upd_pio_shadow)
-                       dd->ipath_upd_pio_shadow = 0;
-               if (dd->ipath_consec_nopiobuf)
-                       dd->ipath_consec_nopiobuf = 0;
-               ipath_cdbg(VERBOSE, "Return piobuf%u %uk @ %p\n",
-                          pnum, (pnum < dd->ipath_piobcnt2k) ? 2 : 4, buf);
-               if (pbufnum)
-                       *pbufnum = pnum;
-
-       }
-       return buf;
-}
-
-/**
- * ipath_chg_pioavailkernel - change which send buffers are available for kernel
- * @dd: the infinipath device
- * @start: the starting send buffer number
- * @len: the number of send buffers
- * @avail: true if the buffers are available for kernel use, false otherwise
- */
-void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
-                             unsigned len, int avail)
-{
-       unsigned long flags;
-       unsigned end, cnt = 0;
-
-       /* There are two bits per send buffer (busy and generation) */
-       start *= 2;
-       end = start + len * 2;
-
-       spin_lock_irqsave(&ipath_pioavail_lock, flags);
-       /* Set or clear the busy bit in the shadow. */
-       while (start < end) {
-               if (avail) {
-                       unsigned long dma;
-                       int i, im;
-                       /*
-                        * the BUSY bit will never be set, because we disarm
-                        * the user buffers before we hand them back to the
-                        * kernel.  We do have to make sure the generation
-                        * bit is set correctly in shadow, since it could
-                        * have changed many times while allocated to user.
-                        * We can't use the bitmap functions on the full
-                        * dma array because it is always little-endian, so
-                        * we have to flip to host-order first.
-                        * BITS_PER_LONG is slightly wrong, since it's
-                        * always 64 bits per register in chip...
-                        * We only work on 64 bit kernels, so that's OK.
-                        */
-                       /* deal with 6110 chip bug on high register #s */
-                       i = start / BITS_PER_LONG;
-                       im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
-                               i ^ 1 : i;
-                       __clear_bit(INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT
-                               + start, dd->ipath_pioavailshadow);
-                       dma = (unsigned long) le64_to_cpu(
-                               dd->ipath_pioavailregs_dma[im]);
-                       if (test_bit((INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
-                               + start) % BITS_PER_LONG, &dma))
-                               __set_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
-                                       + start, dd->ipath_pioavailshadow);
-                       else
-                               __clear_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
-                                       + start, dd->ipath_pioavailshadow);
-                       __set_bit(start, dd->ipath_pioavailkernel);
-               } else {
-                       __set_bit(start + INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT,
-                               dd->ipath_pioavailshadow);
-                       __clear_bit(start, dd->ipath_pioavailkernel);
-               }
-               start += 2;
-       }
-
-       if (dd->ipath_pioupd_thresh) {
-               end = 2 * (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
-               cnt = bitmap_weight(dd->ipath_pioavailkernel, end);
-       }
-       spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
-
-       /*
-        * When moving buffers from kernel to user, if number assigned to
-        * the user is less than the pio update threshold, and threshold
-        * is supported (cnt was computed > 0), drop the update threshold
-        * so we update at least once per allocated number of buffers.
-        * In any case, if the kernel buffers are less than the threshold,
-        * drop the threshold.  We don't bother increasing it, having once
-        * decreased it, since it would typically just cycle back and forth.
-        * If we don't decrease below buffers in use, we can wait a long
-        * time for an update, until some other context uses PIO buffers.
-        */
-       if (!avail && len < cnt)
-               cnt = len;
-       if (cnt < dd->ipath_pioupd_thresh) {
-               dd->ipath_pioupd_thresh = cnt;
-               ipath_dbg("Decreased pio update threshold to %u\n",
-                       dd->ipath_pioupd_thresh);
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               dd->ipath_sendctrl &= ~(INFINIPATH_S_UPDTHRESH_MASK
-                       << INFINIPATH_S_UPDTHRESH_SHIFT);
-               dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
-                       << INFINIPATH_S_UPDTHRESH_SHIFT;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                       dd->ipath_sendctrl);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-       }
-}
-
-/**
- * ipath_create_rcvhdrq - create a receive header queue
- * @dd: the infinipath device
- * @pd: the port data
- *
- * this must be contiguous memory (from an i/o perspective), and must be
- * DMA'able (which means for some systems, it will go through an IOMMU,
- * or be forced into a low address range).
- */
-int ipath_create_rcvhdrq(struct ipath_devdata *dd,
-                        struct ipath_portdata *pd)
-{
-       int ret = 0;
-
-       if (!pd->port_rcvhdrq) {
-               dma_addr_t phys_hdrqtail;
-               gfp_t gfp_flags = GFP_USER | __GFP_COMP;
-               int amt = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
-                               sizeof(u32), PAGE_SIZE);
-
-               pd->port_rcvhdrq = dma_alloc_coherent(
-                       &dd->pcidev->dev, amt, &pd->port_rcvhdrq_phys,
-                       gfp_flags);
-
-               if (!pd->port_rcvhdrq) {
-                       ipath_dev_err(dd, "attempt to allocate %d bytes "
-                                     "for port %u rcvhdrq failed\n",
-                                     amt, pd->port_port);
-                       ret = -ENOMEM;
-                       goto bail;
-               }
-
-               if (!(dd->ipath_flags & IPATH_NODMA_RTAIL)) {
-                       pd->port_rcvhdrtail_kvaddr = dma_alloc_coherent(
-                               &dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail,
-                               GFP_KERNEL);
-                       if (!pd->port_rcvhdrtail_kvaddr) {
-                               ipath_dev_err(dd, "attempt to allocate 1 page "
-                                       "for port %u rcvhdrqtailaddr "
-                                       "failed\n", pd->port_port);
-                               ret = -ENOMEM;
-                               dma_free_coherent(&dd->pcidev->dev, amt,
-                                       pd->port_rcvhdrq,
-                                       pd->port_rcvhdrq_phys);
-                               pd->port_rcvhdrq = NULL;
-                               goto bail;
-                       }
-                       pd->port_rcvhdrqtailaddr_phys = phys_hdrqtail;
-                       ipath_cdbg(VERBOSE, "port %d hdrtailaddr, %llx "
-                                  "physical\n", pd->port_port,
-                                  (unsigned long long) phys_hdrqtail);
-               }
-
-               pd->port_rcvhdrq_size = amt;
-
-               ipath_cdbg(VERBOSE, "%d pages at %p (phys %lx) size=%lu "
-                          "for port %u rcvhdr Q\n",
-                          amt >> PAGE_SHIFT, pd->port_rcvhdrq,
-                          (unsigned long) pd->port_rcvhdrq_phys,
-                          (unsigned long) pd->port_rcvhdrq_size,
-                          pd->port_port);
-       } else {
-               ipath_cdbg(VERBOSE, "reuse port %d rcvhdrq @%p %llx phys; "
-                          "hdrtailaddr@%p %llx physical\n",
-                          pd->port_port, pd->port_rcvhdrq,
-                          (unsigned long long) pd->port_rcvhdrq_phys,
-                          pd->port_rcvhdrtail_kvaddr, (unsigned long long)
-                          pd->port_rcvhdrqtailaddr_phys);
-       }
-       /* clear for security and sanity on each use */
-       memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
-       if (pd->port_rcvhdrtail_kvaddr)
-               memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
-
-       /*
-        * tell chip each time we init it, even if we are re-using previous
-        * memory (we zero the register at process close)
-        */
-       ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
-                             pd->port_port, pd->port_rcvhdrqtailaddr_phys);
-       ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
-                             pd->port_port, pd->port_rcvhdrq_phys);
-
-bail:
-       return ret;
-}
-
-
-/*
- * Flush all sends that might be in the ready to send state, as well as any
- * that are in the process of being sent.   Used whenever we need to be
- * sure the send side is idle.  Cleans up all buffer state by canceling
- * all pio buffers, and issuing an abort, which cleans up anything in the
- * launch fifo.  The cancel is superfluous on some chip versions, but
- * it's safer to always do it.
- * PIOAvail bits are updated by the chip as if normal send had happened.
- */
-void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
-{
-       unsigned long flags;
-
-       if (dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) {
-               ipath_cdbg(VERBOSE, "Ignore while in autonegotiation\n");
-               goto bail;
-       }
-       /*
-        * If we have SDMA, and it's not disabled, we have to kick off the
-        * abort state machine, provided we aren't already aborting.
-        * If we are in the process of aborting SDMA (!DISABLED, but ABORTING),
-        * we skip the rest of this routine. It is already "in progress"
-        */
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA) {
-               int skip_cancel;
-               unsigned long *statp = &dd->ipath_sdma_status;
-
-               spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-               skip_cancel =
-                       test_and_set_bit(IPATH_SDMA_ABORTING, statp)
-                       && !test_bit(IPATH_SDMA_DISABLED, statp);
-               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-               if (skip_cancel)
-                       goto bail;
-       }
-
-       ipath_dbg("Cancelling all in-progress send buffers\n");
-
-       /* skip armlaunch errs for a while */
-       dd->ipath_lastcancel = jiffies + HZ / 2;
-
-       /*
-        * The abort bit is auto-clearing.  We also don't want pioavail
-        * update happening during this, and we don't want any other
-        * sends going out, so turn those off for the duration.  We read
-        * the scratch register to be sure that cancels and the abort
-        * have taken effect in the chip.  Otherwise two parts are same
-        * as ipath_force_pio_avail_update()
-        */
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl &= ~(INFINIPATH_S_PIOBUFAVAILUPD
-               | INFINIPATH_S_PIOENABLE);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-               dd->ipath_sendctrl | INFINIPATH_S_ABORT);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       /* disarm all send buffers */
-       ipath_disarm_piobufs(dd, 0,
-               dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
-
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-               set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
-
-       if (restore_sendctrl) {
-               /* else done by caller later if needed */
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               dd->ipath_sendctrl |= INFINIPATH_S_PIOBUFAVAILUPD |
-                       INFINIPATH_S_PIOENABLE;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                       dd->ipath_sendctrl);
-               /* and again, be sure all have hit the chip */
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-       }
-
-       if ((dd->ipath_flags & IPATH_HAS_SEND_DMA) &&
-           !test_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status) &&
-           test_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status)) {
-               spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-               /* only wait so long for intr */
-               dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
-               dd->ipath_sdma_reset_wait = 200;
-               if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-                       tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
-               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-       }
-bail:;
-}
-
-/*
- * Force an update of in-memory copy of the pioavail registers, when
- * needed for any of a variety of reasons.  We read the scratch register
- * to make it highly likely that the update will have happened by the
- * time we return.  If already off (as in cancel_sends above), this
- * routine is a nop, on the assumption that the caller will "do the
- * right thing".
- */
-void ipath_force_pio_avail_update(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       if (dd->ipath_sendctrl & INFINIPATH_S_PIOBUFAVAILUPD) {
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                       dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                       dd->ipath_sendctrl);
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       }
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-}
-
-static void ipath_set_ib_lstate(struct ipath_devdata *dd, int linkcmd,
-                               int linitcmd)
-{
-       u64 mod_wd;
-       static const char *what[4] = {
-               [0] = "NOP",
-               [INFINIPATH_IBCC_LINKCMD_DOWN] = "DOWN",
-               [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED",
-               [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE"
-       };
-
-       if (linitcmd == INFINIPATH_IBCC_LINKINITCMD_DISABLE) {
-               /*
-                * If we are told to disable, note that so link-recovery
-                * code does not attempt to bring us back up.
-                */
-               preempt_disable();
-               dd->ipath_flags |= IPATH_IB_LINK_DISABLED;
-               preempt_enable();
-       } else if (linitcmd) {
-               /*
-                * Any other linkinitcmd will lead to LINKDOWN and then
-                * to INIT (if all is well), so clear flag to let
-                * link-recovery code attempt to bring us back up.
-                */
-               preempt_disable();
-               dd->ipath_flags &= ~IPATH_IB_LINK_DISABLED;
-               preempt_enable();
-       }
-
-       mod_wd = (linkcmd << dd->ibcc_lc_shift) |
-               (linitcmd << INFINIPATH_IBCC_LINKINITCMD_SHIFT);
-       ipath_cdbg(VERBOSE,
-               "Moving unit %u to %s (initcmd=0x%x), current ltstate is %s\n",
-               dd->ipath_unit, what[linkcmd], linitcmd,
-               ipath_ibcstatus_str[ipath_ib_linktrstate(dd,
-                       ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus))]);
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                        dd->ipath_ibcctrl | mod_wd);
-       /* read from chip so write is flushed */
-       (void) ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-}
-
-int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
-{
-       u32 lstate;
-       int ret;
-
-       switch (newstate) {
-       case IPATH_IB_LINKDOWN_ONLY:
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN, 0);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       case IPATH_IB_LINKDOWN:
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
-                                       INFINIPATH_IBCC_LINKINITCMD_POLL);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       case IPATH_IB_LINKDOWN_SLEEP:
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
-                                       INFINIPATH_IBCC_LINKINITCMD_SLEEP);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       case IPATH_IB_LINKDOWN_DISABLE:
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_DOWN,
-                                       INFINIPATH_IBCC_LINKINITCMD_DISABLE);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       case IPATH_IB_LINKARM:
-               if (dd->ipath_flags & IPATH_LINKARMED) {
-                       ret = 0;
-                       goto bail;
-               }
-               if (!(dd->ipath_flags &
-                     (IPATH_LINKINIT | IPATH_LINKACTIVE))) {
-                       ret = -EINVAL;
-                       goto bail;
-               }
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED, 0);
-
-               /*
-                * Since the port can transition to ACTIVE by receiving
-                * a non VL 15 packet, wait for either state.
-                */
-               lstate = IPATH_LINKARMED | IPATH_LINKACTIVE;
-               break;
-
-       case IPATH_IB_LINKACTIVE:
-               if (dd->ipath_flags & IPATH_LINKACTIVE) {
-                       ret = 0;
-                       goto bail;
-               }
-               if (!(dd->ipath_flags & IPATH_LINKARMED)) {
-                       ret = -EINVAL;
-                       goto bail;
-               }
-               ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE, 0);
-               lstate = IPATH_LINKACTIVE;
-               break;
-
-       case IPATH_IB_LINK_LOOPBACK:
-               dev_info(&dd->pcidev->dev, "Enabling IB local loopback\n");
-               dd->ipath_ibcctrl |= INFINIPATH_IBCC_LOOPBACK;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                                dd->ipath_ibcctrl);
-
-               /* turn heartbeat off, as it causes loopback to fail */
-               dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
-                                      IPATH_IB_HRTBT_OFF);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       case IPATH_IB_LINK_EXTERNAL:
-               dev_info(&dd->pcidev->dev,
-                       "Disabling IB local loopback (normal)\n");
-               dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
-                                      IPATH_IB_HRTBT_ON);
-               dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LOOPBACK;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                                dd->ipath_ibcctrl);
-               /* don't wait */
-               ret = 0;
-               goto bail;
-
-       /*
-        * Heartbeat can be explicitly enabled by the user via
-        * "hrtbt_enable" "file", and if disabled, trying to enable here
-        * will have no effect.  Implicit changes (heartbeat off when
-        * loopback on, and vice versa) are included to ease testing.
-        */
-       case IPATH_IB_LINK_HRTBT:
-               ret = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
-                       IPATH_IB_HRTBT_ON);
-               goto bail;
-
-       case IPATH_IB_LINK_NO_HRTBT:
-               ret = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT,
-                       IPATH_IB_HRTBT_OFF);
-               goto bail;
-
-       default:
-               ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
-               ret = -EINVAL;
-               goto bail;
-       }
-       ret = ipath_wait_linkstate(dd, lstate, 2000);
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_set_mtu - set the MTU
- * @dd: the infinipath device
- * @arg: the new MTU
- *
- * we can handle "any" incoming size, the issue here is whether we
- * need to restrict our outgoing size.   For now, we don't do any
- * sanity checking on this, and we don't deal with what happens to
- * programs that are already running when the size changes.
- * NOTE: changing the MTU will usually cause the IBC to go back to
- * link INIT state...
- */
-int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
-{
-       u32 piosize;
-       int changed = 0;
-       int ret;
-
-       /*
-        * mtu is IB data payload max.  It's the largest power of 2 less
-        * than piosize (or even larger, since it only really controls the
-        * largest we can receive; we can send the max of the mtu and
-        * piosize).  We check that it's one of the valid IB sizes.
-        */
-       if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
-           (arg != 4096 || !ipath_mtu4096)) {
-               ipath_dbg("Trying to set invalid mtu %u, failing\n", arg);
-               ret = -EINVAL;
-               goto bail;
-       }
-       if (dd->ipath_ibmtu == arg) {
-               ret = 0;        /* same as current */
-               goto bail;
-       }
-
-       piosize = dd->ipath_ibmaxlen;
-       dd->ipath_ibmtu = arg;
-
-       if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) {
-               /* Only if it's not the initial value (or reset to it) */
-               if (piosize != dd->ipath_init_ibmaxlen) {
-                       if (arg > piosize && arg <= dd->ipath_init_ibmaxlen)
-                               piosize = dd->ipath_init_ibmaxlen;
-                       dd->ipath_ibmaxlen = piosize;
-                       changed = 1;
-               }
-       } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) {
-               piosize = arg + IPATH_PIO_MAXIBHDR;
-               ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x "
-                          "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize,
-                          arg);
-               dd->ipath_ibmaxlen = piosize;
-               changed = 1;
-       }
-
-       if (changed) {
-               u64 ibc = dd->ipath_ibcctrl, ibdw;
-               /*
-                * update our housekeeping variables, and set IBC max
-                * size, same as init code; max IBC is max we allow in
-                * buffer, less the qword pbc, plus 1 for ICRC, in dwords
-                */
-               dd->ipath_ibmaxlen = piosize - 2 * sizeof(u32);
-               ibdw = (dd->ipath_ibmaxlen >> 2) + 1;
-               ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<
-                        dd->ibcc_mpl_shift);
-               ibc |= ibdw << dd->ibcc_mpl_shift;
-               dd->ipath_ibcctrl = ibc;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                                dd->ipath_ibcctrl);
-               dd->ipath_f_tidtemplate(dd);
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-int ipath_set_lid(struct ipath_devdata *dd, u32 lid, u8 lmc)
-{
-       dd->ipath_lid = lid;
-       dd->ipath_lmc = lmc;
-
-       dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LIDLMC, lid |
-               (~((1U << lmc) - 1)) << 16);
-
-       dev_info(&dd->pcidev->dev, "We got a lid: 0x%x\n", lid);
-
-       return 0;
-}
-
-
-/**
- * ipath_write_kreg_port - write a device's per-port 64-bit kernel register
- * @dd: the infinipath device
- * @regno: the register number to write
- * @port: the port containing the register
- * @value: the value to write
- *
- * Registers that vary with the chip implementation constants (port)
- * use this routine.
- */
-void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
-                         unsigned port, u64 value)
-{
-       u16 where;
-
-       if (port < dd->ipath_portcnt &&
-           (regno == dd->ipath_kregs->kr_rcvhdraddr ||
-            regno == dd->ipath_kregs->kr_rcvhdrtailaddr))
-               where = regno + port;
-       else
-               where = -1;
-
-       ipath_write_kreg(dd, where, value);
-}
-
-/*
- * Following deal with the "obviously simple" task of overriding the state
- * of the LEDS, which normally indicate link physical and logical status.
- * The complications arise in dealing with different hardware mappings
- * and the board-dependent routine being called from interrupts.
- * and then there's the requirement to _flash_ them.
- */
-#define LED_OVER_FREQ_SHIFT 8
-#define LED_OVER_FREQ_MASK (0xFF<<LED_OVER_FREQ_SHIFT)
-/* Below is "non-zero" to force override, but both actual LEDs are off */
-#define LED_OVER_BOTH_OFF (8)
-
-static void ipath_run_led_override(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
-       int timeoff;
-       int pidx;
-       u64 lstate, ltstate, val;
-
-       if (!(dd->ipath_flags & IPATH_INITTED))
-               return;
-
-       pidx = dd->ipath_led_override_phase++ & 1;
-       dd->ipath_led_override = dd->ipath_led_override_vals[pidx];
-       timeoff = dd->ipath_led_override_timeoff;
-
-       /*
-        * below potentially restores the LED values per current status,
-        * should also possibly setup the traffic-blink register,
-        * but leave that to per-chip functions.
-        */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-       ltstate = ipath_ib_linktrstate(dd, val);
-       lstate = ipath_ib_linkstate(dd, val);
-
-       dd->ipath_f_setextled(dd, lstate, ltstate);
-       mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
-}
-
-void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
-{
-       int timeoff, freq;
-
-       if (!(dd->ipath_flags & IPATH_INITTED))
-               return;
-
-       /* First check if we are blinking. If not, use 1HZ polling */
-       timeoff = HZ;
-       freq = (val & LED_OVER_FREQ_MASK) >> LED_OVER_FREQ_SHIFT;
-
-       if (freq) {
-               /* For blink, set each phase from one nybble of val */
-               dd->ipath_led_override_vals[0] = val & 0xF;
-               dd->ipath_led_override_vals[1] = (val >> 4) & 0xF;
-               timeoff = (HZ << 4)/freq;
-       } else {
-               /* Non-blink set both phases the same. */
-               dd->ipath_led_override_vals[0] = val & 0xF;
-               dd->ipath_led_override_vals[1] = val & 0xF;
-       }
-       dd->ipath_led_override_timeoff = timeoff;
-
-       /*
-        * If the timer has not already been started, do so. Use a "quick"
-        * timeout so the function will be called soon, to look at our request.
-        */
-       if (atomic_inc_return(&dd->ipath_led_override_timer_active) == 1) {
-               /* Need to start timer */
-               setup_timer(&dd->ipath_led_override_timer,
-                               ipath_run_led_override, (unsigned long)dd);
-
-               dd->ipath_led_override_timer.expires = jiffies + 1;
-               add_timer(&dd->ipath_led_override_timer);
-       } else
-               atomic_dec(&dd->ipath_led_override_timer_active);
-}
-
-/**
- * ipath_shutdown_device - shut down a device
- * @dd: the infinipath device
- *
- * This is called to make the device quiet when we are about to
- * unload the driver, and also when the device is administratively
- * disabled.   It does not free any data structures.
- * Everything it does has to be setup again by ipath_init_chip(dd,1)
- */
-void ipath_shutdown_device(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-
-       ipath_dbg("Shutting down the device\n");
-
-       ipath_hol_up(dd); /* make sure user processes aren't suspended */
-
-       dd->ipath_flags |= IPATH_LINKUNK;
-       dd->ipath_flags &= ~(IPATH_INITTED | IPATH_LINKDOWN |
-                            IPATH_LINKINIT | IPATH_LINKARMED |
-                            IPATH_LINKACTIVE);
-       *dd->ipath_statusp &= ~(IPATH_STATUS_IB_CONF |
-                               IPATH_STATUS_IB_READY);
-
-       /* mask interrupts, but not errors */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
-
-       dd->ipath_rcvctrl = 0;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-               teardown_sdma(dd);
-
-       /*
-        * gracefully stop all sends allowing any in progress to trickle out
-        * first.
-        */
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl = 0;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       /* flush it */
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       /*
-        * enough for anything that's going to trickle out to have actually
-        * done so.
-        */
-       udelay(5);
-
-       dd->ipath_f_setextled(dd, 0, 0); /* make sure LEDs are off */
-
-       ipath_set_ib_lstate(dd, 0, INFINIPATH_IBCC_LINKINITCMD_DISABLE);
-       ipath_cancel_sends(dd, 0);
-
-       /*
-        * we are shutting down, so tell components that care.  We don't do
-        * this on just a link state change, much like ethernet, a cable
-        * unplug, etc. doesn't change driver state
-        */
-       signal_ib_event(dd, IB_EVENT_PORT_ERR);
-
-       /* disable IBC */
-       dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control | INFINIPATH_C_FREEZEMODE);
-
-       /*
-        * clear SerdesEnable and turn the leds off; do this here because
-        * we are unloading, so don't count on interrupts to move along
-        * Turn the LEDs off explicitly for the same reason.
-        */
-       dd->ipath_f_quiet_serdes(dd);
-
-       /* stop all the timers that might still be running */
-       del_timer_sync(&dd->ipath_hol_timer);
-       if (dd->ipath_stats_timer_active) {
-               del_timer_sync(&dd->ipath_stats_timer);
-               dd->ipath_stats_timer_active = 0;
-       }
-       if (dd->ipath_intrchk_timer.data) {
-               del_timer_sync(&dd->ipath_intrchk_timer);
-               dd->ipath_intrchk_timer.data = 0;
-       }
-       if (atomic_read(&dd->ipath_led_override_timer_active)) {
-               del_timer_sync(&dd->ipath_led_override_timer);
-               atomic_set(&dd->ipath_led_override_timer_active, 0);
-       }
-
-       /*
-        * clear all interrupts and errors, so that the next time the driver
-        * is loaded or device is enabled, we know that whatever is set
-        * happened while we were unloaded
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        ~0ULL & ~INFINIPATH_HWE_MEMBISTFAILED);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
-
-       ipath_cdbg(VERBOSE, "Flush time and errors to EEPROM\n");
-       ipath_update_eeprom_log(dd);
-}
-
-/**
- * ipath_free_pddata - free a port's allocated data
- * @dd: the infinipath device
- * @pd: the portdata structure
- *
- * free up any allocated data for a port
- * This should not touch anything that would affect a simultaneous
- * re-allocation of port data, because it is called after ipath_mutex
- * is released (and can be called from reinit as well).
- * It should never change any chip state, or global driver state.
- * (The only exception to global state is freeing the port0 port0_skbs.)
- */
-void ipath_free_pddata(struct ipath_devdata *dd, struct ipath_portdata *pd)
-{
-       if (!pd)
-               return;
-
-       if (pd->port_rcvhdrq) {
-               ipath_cdbg(VERBOSE, "free closed port %d rcvhdrq @ %p "
-                          "(size=%lu)\n", pd->port_port, pd->port_rcvhdrq,
-                          (unsigned long) pd->port_rcvhdrq_size);
-               dma_free_coherent(&dd->pcidev->dev, pd->port_rcvhdrq_size,
-                                 pd->port_rcvhdrq, pd->port_rcvhdrq_phys);
-               pd->port_rcvhdrq = NULL;
-               if (pd->port_rcvhdrtail_kvaddr) {
-                       dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
-                                        pd->port_rcvhdrtail_kvaddr,
-                                        pd->port_rcvhdrqtailaddr_phys);
-                       pd->port_rcvhdrtail_kvaddr = NULL;
-               }
-       }
-       if (pd->port_port && pd->port_rcvegrbuf) {
-               unsigned e;
-
-               for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {
-                       void *base = pd->port_rcvegrbuf[e];
-                       size_t size = pd->port_rcvegrbuf_size;
-
-                       ipath_cdbg(VERBOSE, "egrbuf free(%p, %lu), "
-                                  "chunk %u/%u\n", base,
-                                  (unsigned long) size,
-                                  e, pd->port_rcvegrbuf_chunks);
-                       dma_free_coherent(&dd->pcidev->dev, size,
-                               base, pd->port_rcvegrbuf_phys[e]);
-               }
-               kfree(pd->port_rcvegrbuf);
-               pd->port_rcvegrbuf = NULL;
-               kfree(pd->port_rcvegrbuf_phys);
-               pd->port_rcvegrbuf_phys = NULL;
-               pd->port_rcvegrbuf_chunks = 0;
-       } else if (pd->port_port == 0 && dd->ipath_port0_skbinfo) {
-               unsigned e;
-               struct ipath_skbinfo *skbinfo = dd->ipath_port0_skbinfo;
-
-               dd->ipath_port0_skbinfo = NULL;
-               ipath_cdbg(VERBOSE, "free closed port %d "
-                          "ipath_port0_skbinfo @ %p\n", pd->port_port,
-                          skbinfo);
-               for (e = 0; e < dd->ipath_p0_rcvegrcnt; e++)
-                       if (skbinfo[e].skb) {
-                               pci_unmap_single(dd->pcidev, skbinfo[e].phys,
-                                                dd->ipath_ibmaxlen,
-                                                PCI_DMA_FROMDEVICE);
-                               dev_kfree_skb(skbinfo[e].skb);
-                       }
-               vfree(skbinfo);
-       }
-       kfree(pd->port_tid_pg_list);
-       vfree(pd->subport_uregbase);
-       vfree(pd->subport_rcvegrbuf);
-       vfree(pd->subport_rcvhdr_base);
-       kfree(pd);
-}
-
-static int __init infinipath_init(void)
-{
-       int ret;
-
-       if (ipath_debug & __IPATH_DBG)
-               printk(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version);
-
-       /*
-        * These must be called before the driver is registered with
-        * the PCI subsystem.
-        */
-       idr_init(&unit_table);
-
-       ret = pci_register_driver(&ipath_driver);
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME
-                      ": Unable to register driver: error %d\n", -ret);
-               goto bail_unit;
-       }
-
-       ret = ipath_init_ipathfs();
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
-                      "ipathfs: error %d\n", -ret);
-               goto bail_pci;
-       }
-
-       goto bail;
-
-bail_pci:
-       pci_unregister_driver(&ipath_driver);
-
-bail_unit:
-       idr_destroy(&unit_table);
-
-bail:
-       return ret;
-}
-
-static void __exit infinipath_cleanup(void)
-{
-       ipath_exit_ipathfs();
-
-       ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
-       pci_unregister_driver(&ipath_driver);
-
-       idr_destroy(&unit_table);
-}
-
-/**
- * ipath_reset_device - reset the chip if possible
- * @unit: the device to reset
- *
- * Whether or not reset is successful, we attempt to re-initialize the chip
- * (that is, much like a driver unload/reload).  We clear the INITTED flag
- * so that the various entry points will fail until we reinitialize.  For
- * now, we only allow this if no user ports are open that use chip resources
- */
-int ipath_reset_device(int unit)
-{
-       int ret, i;
-       struct ipath_devdata *dd = ipath_lookup(unit);
-       unsigned long flags;
-
-       if (!dd) {
-               ret = -ENODEV;
-               goto bail;
-       }
-
-       if (atomic_read(&dd->ipath_led_override_timer_active)) {
-               /* Need to stop LED timer, _then_ shut off LEDs */
-               del_timer_sync(&dd->ipath_led_override_timer);
-               atomic_set(&dd->ipath_led_override_timer_active, 0);
-       }
-
-       /* Shut off LEDs after we are sure timer is not running */
-       dd->ipath_led_override = LED_OVER_BOTH_OFF;
-       dd->ipath_f_setextled(dd, 0, 0);
-
-       dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit);
-
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) {
-               dev_info(&dd->pcidev->dev, "Invalid unit number %u or "
-                        "not initialized or not present\n", unit);
-               ret = -ENXIO;
-               goto bail;
-       }
-
-       spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
-       if (dd->ipath_pd)
-               for (i = 1; i < dd->ipath_cfgports; i++) {
-                       if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
-                               continue;
-                       spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
-                       ipath_dbg("unit %u port %d is in use "
-                                 "(PID %u cmd %s), can't reset\n",
-                                 unit, i,
-                                 pid_nr(dd->ipath_pd[i]->port_pid),
-                                 dd->ipath_pd[i]->port_comm);
-                       ret = -EBUSY;
-                       goto bail;
-               }
-       spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
-
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-               teardown_sdma(dd);
-
-       dd->ipath_flags &= ~IPATH_INITTED;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
-       ret = dd->ipath_f_reset(dd);
-       if (ret == 1) {
-               ipath_dbg("Reinitializing unit %u after reset attempt\n",
-                         unit);
-               ret = ipath_init_chip(dd, 1);
-       } else
-               ret = -EAGAIN;
-       if (ret)
-               ipath_dev_err(dd, "Reinitialize unit %u after "
-                             "reset failed with %d\n", unit, ret);
-       else
-               dev_info(&dd->pcidev->dev, "Reinitialized unit %u after "
-                        "resetting\n", unit);
-
-bail:
-       return ret;
-}
-
-/*
- * send a signal to all the processes that have the driver open
- * through the normal interfaces (i.e., everything other than diags
- * interface).  Returns number of signalled processes.
- */
-static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
-{
-       int i, sub, any = 0;
-       struct pid *pid;
-       unsigned long flags;
-
-       if (!dd->ipath_pd)
-               return 0;
-
-       spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
-       for (i = 1; i < dd->ipath_cfgports; i++) {
-               if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt)
-                       continue;
-               pid = dd->ipath_pd[i]->port_pid;
-               if (!pid)
-                       continue;
-
-               dev_info(&dd->pcidev->dev, "context %d in use "
-                         "(PID %u), sending signal %d\n",
-                         i, pid_nr(pid), sig);
-               kill_pid(pid, sig, 1);
-               any++;
-               for (sub = 0; sub < INFINIPATH_MAX_SUBPORT; sub++) {
-                       pid = dd->ipath_pd[i]->port_subpid[sub];
-                       if (!pid)
-                               continue;
-                       dev_info(&dd->pcidev->dev, "sub-context "
-                               "%d:%d in use (PID %u), sending "
-                               "signal %d\n", i, sub, pid_nr(pid), sig);
-                       kill_pid(pid, sig, 1);
-                       any++;
-               }
-       }
-       spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
-       return any;
-}
-
-static void ipath_hol_signal_down(struct ipath_devdata *dd)
-{
-       if (ipath_signal_procs(dd, SIGSTOP))
-               ipath_dbg("Stopped some processes\n");
-       ipath_cancel_sends(dd, 1);
-}
-
-
-static void ipath_hol_signal_up(struct ipath_devdata *dd)
-{
-       if (ipath_signal_procs(dd, SIGCONT))
-               ipath_dbg("Continued some processes\n");
-}
-
-/*
- * link is down, stop any users processes, and flush pending sends
- * to prevent HoL blocking, then start the HoL timer that
- * periodically continues, then stop procs, so they can detect
- * link down if they want, and do something about it.
- * Timer may already be running, so use mod_timer, not add_timer.
- */
-void ipath_hol_down(struct ipath_devdata *dd)
-{
-       dd->ipath_hol_state = IPATH_HOL_DOWN;
-       ipath_hol_signal_down(dd);
-       dd->ipath_hol_next = IPATH_HOL_DOWNCONT;
-       dd->ipath_hol_timer.expires = jiffies +
-               msecs_to_jiffies(ipath_hol_timeout_ms);
-       mod_timer(&dd->ipath_hol_timer, dd->ipath_hol_timer.expires);
-}
-
-/*
- * link is up, continue any user processes, and ensure timer
- * is a nop, if running.  Let timer keep running, if set; it
- * will nop when it sees the link is up
- */
-void ipath_hol_up(struct ipath_devdata *dd)
-{
-       ipath_hol_signal_up(dd);
-       dd->ipath_hol_state = IPATH_HOL_UP;
-}
-
-/*
- * toggle the running/not running state of user proceses
- * to prevent HoL blocking on chip resources, but still allow
- * user processes to do link down special case handling.
- * Should only be called via the timer
- */
-void ipath_hol_event(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
-
-       if (dd->ipath_hol_next == IPATH_HOL_DOWNSTOP
-               && dd->ipath_hol_state != IPATH_HOL_UP) {
-               dd->ipath_hol_next = IPATH_HOL_DOWNCONT;
-               ipath_dbg("Stopping processes\n");
-               ipath_hol_signal_down(dd);
-       } else { /* may do "extra" if also in ipath_hol_up() */
-               dd->ipath_hol_next = IPATH_HOL_DOWNSTOP;
-               ipath_dbg("Continuing processes\n");
-               ipath_hol_signal_up(dd);
-       }
-       if (dd->ipath_hol_state == IPATH_HOL_UP)
-               ipath_dbg("link's up, don't resched timer\n");
-       else {
-               dd->ipath_hol_timer.expires = jiffies +
-                       msecs_to_jiffies(ipath_hol_timeout_ms);
-               mod_timer(&dd->ipath_hol_timer,
-                       dd->ipath_hol_timer.expires);
-       }
-}
-
-int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
-{
-       u64 val;
-
-       if (new_pol_inv > INFINIPATH_XGXS_RX_POL_MASK)
-               return -1;
-       if (dd->ipath_rx_pol_inv != new_pol_inv) {
-               dd->ipath_rx_pol_inv = new_pol_inv;
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-               val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
-                        INFINIPATH_XGXS_RX_POL_SHIFT);
-               val |= ((u64)dd->ipath_rx_pol_inv) <<
-                       INFINIPATH_XGXS_RX_POL_SHIFT;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-       }
-       return 0;
-}
-
-/*
- * Disable and enable the armlaunch error.  Used for PIO bandwidth testing on
- * the 7220, which is count-based, rather than trigger-based.  Safe for the
- * driver check, since it's at init.   Not completely safe when used for
- * user-mode checking, since some error checking can be lost, but not
- * particularly risky, and only has problematic side-effects in the face of
- * very buggy user code.  There is no reference counting, but that's also
- * fine, given the intended use.
- */
-void ipath_enable_armlaunch(struct ipath_devdata *dd)
-{
-       dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
-               INFINIPATH_E_SPIOARMLAUNCH);
-       dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-               dd->ipath_errormask);
-}
-
-void ipath_disable_armlaunch(struct ipath_devdata *dd)
-{
-       /* so don't re-enable if already set */
-       dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
-       dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-               dd->ipath_errormask);
-}
-
-module_init(infinipath_init);
-module_exit(infinipath_cleanup);
diff --git a/drivers/staging/rdma/ipath/ipath_eeprom.c b/drivers/staging/rdma/ipath/ipath_eeprom.c
deleted file mode 100644 (file)
index ef84107..0000000
+++ /dev/null
@@ -1,1183 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-
-#include "ipath_kernel.h"
-
-/*
- * InfiniPath I2C driver for a serial eeprom.  This is not a generic
- * I2C interface.  For a start, the device we're using (Atmel AT24C11)
- * doesn't work like a regular I2C device.  It looks like one
- * electrically, but not logically.  Normal I2C devices have a single
- * 7-bit or 10-bit I2C address that they respond to.  Valid 7-bit
- * addresses range from 0x03 to 0x77.  Addresses 0x00 to 0x02 and 0x78
- * to 0x7F are special reserved addresses (e.g. 0x00 is the "general
- * call" address.)  The Atmel device, on the other hand, responds to ALL
- * 7-bit addresses.  It's designed to be the only device on a given I2C
- * bus.  A 7-bit address corresponds to the memory address within the
- * Atmel device itself.
- *
- * Also, the timing requirements mean more than simple software
- * bitbanging, with readbacks from chip to ensure timing (simple udelay
- * is not enough).
- *
- * This all means that accessing the device is specialized enough
- * that using the standard kernel I2C bitbanging interface would be
- * impossible.  For example, the core I2C eeprom driver expects to find
- * a device at one or more of a limited set of addresses only.  It doesn't
- * allow writing to an eeprom.  It also doesn't provide any means of
- * accessing eeprom contents from within the kernel, only via sysfs.
- */
-
-/* Added functionality for IBA7220-based cards */
-#define IPATH_EEPROM_DEV_V1 0xA0
-#define IPATH_EEPROM_DEV_V2 0xA2
-#define IPATH_TEMP_DEV 0x98
-#define IPATH_BAD_DEV (IPATH_EEPROM_DEV_V2+2)
-#define IPATH_NO_DEV (0xFF)
-
-/*
- * The number of I2C chains is proliferating. Table below brings
- * some order to the madness. The basic principle is that the
- * table is scanned from the top, and a "probe" is made to the
- * device probe_dev. If that succeeds, the chain is considered
- * to be of that type, and dd->i2c_chain_type is set to the index+1
- * of the entry.
- * The +1 is so static initialization can mean "unknown, do probe."
- */
-static struct i2c_chain_desc {
-       u8 probe_dev;   /* If seen at probe, chain is this type */
-       u8 eeprom_dev;  /* Dev addr (if any) for EEPROM */
-       u8 temp_dev;    /* Dev Addr (if any) for Temp-sense */
-} i2c_chains[] = {
-       { IPATH_BAD_DEV, IPATH_NO_DEV, IPATH_NO_DEV }, /* pre-iba7220 bds */
-       { IPATH_EEPROM_DEV_V1, IPATH_EEPROM_DEV_V1, IPATH_TEMP_DEV}, /* V1 */
-       { IPATH_EEPROM_DEV_V2, IPATH_EEPROM_DEV_V2, IPATH_TEMP_DEV}, /* V2 */
-       { IPATH_NO_DEV }
-};
-
-enum i2c_type {
-       i2c_line_scl = 0,
-       i2c_line_sda
-};
-
-enum i2c_state {
-       i2c_line_low = 0,
-       i2c_line_high
-};
-
-#define READ_CMD 1
-#define WRITE_CMD 0
-
-/**
- * i2c_gpio_set - set a GPIO line
- * @dd: the infinipath device
- * @line: the line to set
- * @new_line_state: the state to set
- *
- * Returns 0 if the line was set to the new state successfully, non-zero
- * on error.
- */
-static int i2c_gpio_set(struct ipath_devdata *dd,
-                       enum i2c_type line,
-                       enum i2c_state new_line_state)
-{
-       u64 out_mask, dir_mask, *gpioval;
-       unsigned long flags = 0;
-
-       gpioval = &dd->ipath_gpio_out;
-
-       if (line == i2c_line_scl) {
-               dir_mask = dd->ipath_gpio_scl;
-               out_mask = (1UL << dd->ipath_gpio_scl_num);
-       } else {
-               dir_mask = dd->ipath_gpio_sda;
-               out_mask = (1UL << dd->ipath_gpio_sda_num);
-       }
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       if (new_line_state == i2c_line_high) {
-               /* tri-state the output rather than force high */
-               dd->ipath_extctrl &= ~dir_mask;
-       } else {
-               /* config line to be an output */
-               dd->ipath_extctrl |= dir_mask;
-       }
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
-
-       /* set output as well (no real verify) */
-       if (new_line_state == i2c_line_high)
-               *gpioval |= out_mask;
-       else
-               *gpioval &= ~out_mask;
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-
-       return 0;
-}
-
-/**
- * i2c_gpio_get - get a GPIO line state
- * @dd: the infinipath device
- * @line: the line to get
- * @curr_statep: where to put the line state
- *
- * Returns 0 if the line was set to the new state successfully, non-zero
- * on error.  curr_state is not set on error.
- */
-static int i2c_gpio_get(struct ipath_devdata *dd,
-                       enum i2c_type line,
-                       enum i2c_state *curr_statep)
-{
-       u64 read_val, mask;
-       int ret;
-       unsigned long flags = 0;
-
-       /* check args */
-       if (curr_statep == NULL) {
-               ret = 1;
-               goto bail;
-       }
-
-       /* config line to be an input */
-       if (line == i2c_line_scl)
-               mask = dd->ipath_gpio_scl;
-       else
-               mask = dd->ipath_gpio_sda;
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       dd->ipath_extctrl &= ~mask;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
-       /*
-        * Below is very unlikely to reflect true input state if Output
-        * Enable actually changed.
-        */
-       read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-
-       if (read_val & mask)
-               *curr_statep = i2c_line_high;
-       else
-               *curr_statep = i2c_line_low;
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * i2c_wait_for_writes - wait for a write
- * @dd: the infinipath device
- *
- * We use this instead of udelay directly, so we can make sure
- * that previous register writes have been flushed all the way
- * to the chip.  Since we are delaying anyway, the cost doesn't
- * hurt, and makes the bit twiddling more regular
- */
-static void i2c_wait_for_writes(struct ipath_devdata *dd)
-{
-       (void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       rmb();
-}
-
-static void scl_out(struct ipath_devdata *dd, u8 bit)
-{
-       udelay(1);
-       i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low);
-
-       i2c_wait_for_writes(dd);
-}
-
-static void sda_out(struct ipath_devdata *dd, u8 bit)
-{
-       i2c_gpio_set(dd, i2c_line_sda, bit ? i2c_line_high : i2c_line_low);
-
-       i2c_wait_for_writes(dd);
-}
-
-static u8 sda_in(struct ipath_devdata *dd, int wait)
-{
-       enum i2c_state bit;
-
-       if (i2c_gpio_get(dd, i2c_line_sda, &bit))
-               ipath_dbg("get bit failed!\n");
-
-       if (wait)
-               i2c_wait_for_writes(dd);
-
-       return bit == i2c_line_high ? 1U : 0;
-}
-
-/**
- * i2c_ackrcv - see if ack following write is true
- * @dd: the infinipath device
- */
-static int i2c_ackrcv(struct ipath_devdata *dd)
-{
-       u8 ack_received;
-
-       /* AT ENTRY SCL = LOW */
-       /* change direction, ignore data */
-       ack_received = sda_in(dd, 1);
-       scl_out(dd, i2c_line_high);
-       ack_received = sda_in(dd, 1) == 0;
-       scl_out(dd, i2c_line_low);
-       return ack_received;
-}
-
-/**
- * rd_byte - read a byte, leaving ACK, STOP, etc up to caller
- * @dd: the infinipath device
- *
- * Returns byte shifted out of device
- */
-static int rd_byte(struct ipath_devdata *dd)
-{
-       int bit_cntr, data;
-
-       data = 0;
-
-       for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) {
-               data <<= 1;
-               scl_out(dd, i2c_line_high);
-               data |= sda_in(dd, 0);
-               scl_out(dd, i2c_line_low);
-       }
-       return data;
-}
-
-/**
- * wr_byte - write a byte, one bit at a time
- * @dd: the infinipath device
- * @data: the byte to write
- *
- * Returns 0 if we got the following ack, otherwise 1
- */
-static int wr_byte(struct ipath_devdata *dd, u8 data)
-{
-       int bit_cntr;
-       u8 bit;
-
-       for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) {
-               bit = (data >> bit_cntr) & 1;
-               sda_out(dd, bit);
-               scl_out(dd, i2c_line_high);
-               scl_out(dd, i2c_line_low);
-       }
-       return (!i2c_ackrcv(dd)) ? 1 : 0;
-}
-
-static void send_ack(struct ipath_devdata *dd)
-{
-       sda_out(dd, i2c_line_low);
-       scl_out(dd, i2c_line_high);
-       scl_out(dd, i2c_line_low);
-       sda_out(dd, i2c_line_high);
-}
-
-/**
- * i2c_startcmd - transmit the start condition, followed by address/cmd
- * @dd: the infinipath device
- * @offset_dir: direction byte
- *
- *      (both clock/data high, clock high, data low while clock is high)
- */
-static int i2c_startcmd(struct ipath_devdata *dd, u8 offset_dir)
-{
-       int res;
-
-       /* issue start sequence */
-       sda_out(dd, i2c_line_high);
-       scl_out(dd, i2c_line_high);
-       sda_out(dd, i2c_line_low);
-       scl_out(dd, i2c_line_low);
-
-       /* issue length and direction byte */
-       res = wr_byte(dd, offset_dir);
-
-       if (res)
-               ipath_cdbg(VERBOSE, "No ack to complete start\n");
-
-       return res;
-}
-
-/**
- * stop_cmd - transmit the stop condition
- * @dd: the infinipath device
- *
- * (both clock/data low, clock high, data high while clock is high)
- */
-static void stop_cmd(struct ipath_devdata *dd)
-{
-       scl_out(dd, i2c_line_low);
-       sda_out(dd, i2c_line_low);
-       scl_out(dd, i2c_line_high);
-       sda_out(dd, i2c_line_high);
-       udelay(2);
-}
-
-/**
- * eeprom_reset - reset I2C communication
- * @dd: the infinipath device
- */
-
-static int eeprom_reset(struct ipath_devdata *dd)
-{
-       int clock_cycles_left = 9;
-       u64 *gpioval = &dd->ipath_gpio_out;
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       /* Make sure shadows are consistent */
-       dd->ipath_extctrl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
-       *gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-
-       ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg "
-                  "is %llx\n", (unsigned long long) *gpioval);
-
-       /*
-        * This is to get the i2c into a known state, by first going low,
-        * then tristate sda (and then tristate scl as first thing
-        * in loop)
-        */
-       scl_out(dd, i2c_line_low);
-       sda_out(dd, i2c_line_high);
-
-       /* Clock up to 9 cycles looking for SDA hi, then issue START and STOP */
-       while (clock_cycles_left--) {
-               scl_out(dd, i2c_line_high);
-
-               /* SDA seen high, issue START by dropping it while SCL high */
-               if (sda_in(dd, 0)) {
-                       sda_out(dd, i2c_line_low);
-                       scl_out(dd, i2c_line_low);
-                       /* ATMEL spec says must be followed by STOP. */
-                       scl_out(dd, i2c_line_high);
-                       sda_out(dd, i2c_line_high);
-                       ret = 0;
-                       goto bail;
-               }
-
-               scl_out(dd, i2c_line_low);
-       }
-
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/*
- * Probe for I2C device at specified address. Returns 0 for "success"
- * to match rest of this file.
- * Leave bus in "reasonable" state for further commands.
- */
-static int i2c_probe(struct ipath_devdata *dd, int devaddr)
-{
-       int ret;
-
-       ret = eeprom_reset(dd);
-       if (ret) {
-               ipath_dev_err(dd, "Failed reset probing device 0x%02X\n",
-                             devaddr);
-               return ret;
-       }
-       /*
-        * Reset no longer leaves bus in start condition, so normal
-        * i2c_startcmd() will do.
-        */
-       ret = i2c_startcmd(dd, devaddr | READ_CMD);
-       if (ret)
-               ipath_cdbg(VERBOSE, "Failed startcmd for device 0x%02X\n",
-                          devaddr);
-       else {
-               /*
-                * Device did respond. Complete a single-byte read, because some
-                * devices apparently cannot handle STOP immediately after they
-                * ACK the start-cmd.
-                */
-               int data;
-               data = rd_byte(dd);
-               stop_cmd(dd);
-               ipath_cdbg(VERBOSE, "Response from device 0x%02X\n", devaddr);
-       }
-       return ret;
-}
-
-/*
- * Returns the "i2c type". This is a pointer to a struct that describes
- * the I2C chain on this board. To minimize impact on struct ipath_devdata,
- * the (small integer) index into the table is actually memoized, rather
- * then the pointer.
- * Memoization is because the type is determined on the first call per chip.
- * An alternative would be to move type determination to early
- * init code.
- */
-static struct i2c_chain_desc *ipath_i2c_type(struct ipath_devdata *dd)
-{
-       int idx;
-
-       /* Get memoized index, from previous successful probes */
-       idx = dd->ipath_i2c_chain_type - 1;
-       if (idx >= 0 && idx < (ARRAY_SIZE(i2c_chains) - 1))
-               goto done;
-
-       idx = 0;
-       while (i2c_chains[idx].probe_dev != IPATH_NO_DEV) {
-               /* if probe succeeds, this is type */
-               if (!i2c_probe(dd, i2c_chains[idx].probe_dev))
-                       break;
-               ++idx;
-       }
-
-       /*
-        * Old EEPROM (first entry) may require a reset after probe,
-        * rather than being able to "start" after "stop"
-        */
-       if (idx == 0)
-               eeprom_reset(dd);
-
-       if (i2c_chains[idx].probe_dev == IPATH_NO_DEV)
-               idx = -1;
-       else
-               dd->ipath_i2c_chain_type = idx + 1;
-done:
-       return (idx >= 0) ? i2c_chains + idx : NULL;
-}
-
-static int ipath_eeprom_internal_read(struct ipath_devdata *dd,
-                                       u8 eeprom_offset, void *buffer, int len)
-{
-       int ret;
-       struct i2c_chain_desc *icd;
-       u8 *bp = buffer;
-
-       ret = 1;
-       icd = ipath_i2c_type(dd);
-       if (!icd)
-               goto bail;
-
-       if (icd->eeprom_dev == IPATH_NO_DEV) {
-               /* legacy not-really-I2C */
-               ipath_cdbg(VERBOSE, "Start command only address\n");
-               eeprom_offset = (eeprom_offset << 1) | READ_CMD;
-               ret = i2c_startcmd(dd, eeprom_offset);
-       } else {
-               /* Actual I2C */
-               ipath_cdbg(VERBOSE, "Start command uses devaddr\n");
-               if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) {
-                       ipath_dbg("Failed EEPROM startcmd\n");
-                       stop_cmd(dd);
-                       ret = 1;
-                       goto bail;
-               }
-               ret = wr_byte(dd, eeprom_offset);
-               stop_cmd(dd);
-               if (ret) {
-                       ipath_dev_err(dd, "Failed to write EEPROM address\n");
-                       ret = 1;
-                       goto bail;
-               }
-               ret = i2c_startcmd(dd, icd->eeprom_dev | READ_CMD);
-       }
-       if (ret) {
-               ipath_dbg("Failed startcmd for dev %02X\n", icd->eeprom_dev);
-               stop_cmd(dd);
-               ret = 1;
-               goto bail;
-       }
-
-       /*
-        * eeprom keeps clocking data out as long as we ack, automatically
-        * incrementing the address.
-        */
-       while (len-- > 0) {
-               /* get and store data */
-               *bp++ = rd_byte(dd);
-               /* send ack if not the last byte */
-               if (len)
-                       send_ack(dd);
-       }
-
-       stop_cmd(dd);
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
-                                      const void *buffer, int len)
-{
-       int sub_len;
-       const u8 *bp = buffer;
-       int max_wait_time, i;
-       int ret;
-       struct i2c_chain_desc *icd;
-
-       ret = 1;
-       icd = ipath_i2c_type(dd);
-       if (!icd)
-               goto bail;
-
-       while (len > 0) {
-               if (icd->eeprom_dev == IPATH_NO_DEV) {
-                       if (i2c_startcmd(dd,
-                                        (eeprom_offset << 1) | WRITE_CMD)) {
-                               ipath_dbg("Failed to start cmd offset %u\n",
-                                       eeprom_offset);
-                               goto failed_write;
-                       }
-               } else {
-                       /* Real I2C */
-                       if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) {
-                               ipath_dbg("Failed EEPROM startcmd\n");
-                               goto failed_write;
-                       }
-                       ret = wr_byte(dd, eeprom_offset);
-                       if (ret) {
-                               ipath_dev_err(dd, "Failed to write EEPROM "
-                                             "address\n");
-                               goto failed_write;
-                       }
-               }
-
-               sub_len = min(len, 4);
-               eeprom_offset += sub_len;
-               len -= sub_len;
-
-               for (i = 0; i < sub_len; i++) {
-                       if (wr_byte(dd, *bp++)) {
-                               ipath_dbg("no ack after byte %u/%u (%u "
-                                         "total remain)\n", i, sub_len,
-                                         len + sub_len - i);
-                               goto failed_write;
-                       }
-               }
-
-               stop_cmd(dd);
-
-               /*
-                * wait for write complete by waiting for a successful
-                * read (the chip replies with a zero after the write
-                * cmd completes, and before it writes to the eeprom.
-                * The startcmd for the read will fail the ack until
-                * the writes have completed.   We do this inline to avoid
-                * the debug prints that are in the real read routine
-                * if the startcmd fails.
-                * We also use the proper device address, so it doesn't matter
-                * whether we have real eeprom_dev. legacy likes any address.
-                */
-               max_wait_time = 100;
-               while (i2c_startcmd(dd, icd->eeprom_dev | READ_CMD)) {
-                       stop_cmd(dd);
-                       if (!--max_wait_time) {
-                               ipath_dbg("Did not get successful read to "
-                                         "complete write\n");
-                               goto failed_write;
-                       }
-               }
-               /* now read (and ignore) the resulting byte */
-               rd_byte(dd);
-               stop_cmd(dd);
-       }
-
-       ret = 0;
-       goto bail;
-
-failed_write:
-       stop_cmd(dd);
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_eeprom_read - receives bytes from the eeprom via I2C
- * @dd: the infinipath device
- * @eeprom_offset: address to read from
- * @buffer: where to store result
- * @len: number of bytes to receive
- */
-int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
-                       void *buff, int len)
-{
-       int ret;
-
-       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
-       if (!ret) {
-               ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
-               mutex_unlock(&dd->ipath_eep_lock);
-       }
-
-       return ret;
-}
-
-/**
- * ipath_eeprom_write - writes data to the eeprom via I2C
- * @dd: the infinipath device
- * @eeprom_offset: where to place data
- * @buffer: data to write
- * @len: number of bytes to write
- */
-int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
-                       const void *buff, int len)
-{
-       int ret;
-
-       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
-       if (!ret) {
-               ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
-               mutex_unlock(&dd->ipath_eep_lock);
-       }
-
-       return ret;
-}
-
-static u8 flash_csum(struct ipath_flash *ifp, int adjust)
-{
-       u8 *ip = (u8 *) ifp;
-       u8 csum = 0, len;
-
-       /*
-        * Limit length checksummed to max length of actual data.
-        * Checksum of erased eeprom will still be bad, but we avoid
-        * reading past the end of the buffer we were passed.
-        */
-       len = ifp->if_length;
-       if (len > sizeof(struct ipath_flash))
-               len = sizeof(struct ipath_flash);
-       while (len--)
-               csum += *ip++;
-       csum -= ifp->if_csum;
-       csum = ~csum;
-       if (adjust)
-               ifp->if_csum = csum;
-
-       return csum;
-}
-
-/**
- * ipath_get_guid - get the GUID from the i2c device
- * @dd: the infinipath device
- *
- * We have the capability to use the ipath_nguid field, and get
- * the guid from the first chip's flash, to use for all of them.
- */
-void ipath_get_eeprom_info(struct ipath_devdata *dd)
-{
-       void *buf;
-       struct ipath_flash *ifp;
-       __be64 guid;
-       int len, eep_stat;
-       u8 csum, *bguid;
-       int t = dd->ipath_unit;
-       struct ipath_devdata *dd0 = ipath_lookup(0);
-
-       if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
-               u8 oguid;
-               dd->ipath_guid = dd0->ipath_guid;
-               bguid = (u8 *) & dd->ipath_guid;
-
-               oguid = bguid[7];
-               bguid[7] += t;
-               if (oguid > bguid[7]) {
-                       if (bguid[6] == 0xff) {
-                               if (bguid[5] == 0xff) {
-                                       ipath_dev_err(
-                                               dd,
-                                               "Can't set %s GUID from "
-                                               "base, wraps to OUI!\n",
-                                               ipath_get_unit_name(t));
-                                       dd->ipath_guid = 0;
-                                       goto bail;
-                               }
-                               bguid[5]++;
-                       }
-                       bguid[6]++;
-               }
-               dd->ipath_nguid = 1;
-
-               ipath_dbg("nguid %u, so adding %u to device 0 guid, "
-                         "for %llx\n",
-                         dd0->ipath_nguid, t,
-                         (unsigned long long) be64_to_cpu(dd->ipath_guid));
-               goto bail;
-       }
-
-       /*
-        * read full flash, not just currently used part, since it may have
-        * been written with a newer definition
-        * */
-       len = sizeof(struct ipath_flash);
-       buf = vmalloc(len);
-       if (!buf) {
-               ipath_dev_err(dd, "Couldn't allocate memory to read %u "
-                             "bytes from eeprom for GUID\n", len);
-               goto bail;
-       }
-
-       mutex_lock(&dd->ipath_eep_lock);
-       eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
-       mutex_unlock(&dd->ipath_eep_lock);
-
-       if (eep_stat) {
-               ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
-               goto done;
-       }
-       ifp = (struct ipath_flash *)buf;
-
-       csum = flash_csum(ifp, 0);
-       if (csum != ifp->if_csum) {
-               dev_info(&dd->pcidev->dev, "Bad I2C flash checksum: "
-                        "0x%x, not 0x%x\n", csum, ifp->if_csum);
-               goto done;
-       }
-       if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) ||
-           *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) {
-               ipath_dev_err(dd, "Invalid GUID %llx from flash; "
-                             "ignoring\n",
-                             *(unsigned long long *) ifp->if_guid);
-               /* don't allow GUID if all 0 or all 1's */
-               goto done;
-       }
-
-       /* complain, but allow it */
-       if (*(u64 *) ifp->if_guid == 0x100007511000000ULL)
-               dev_info(&dd->pcidev->dev, "Warning, GUID %llx is "
-                        "default, probably not correct!\n",
-                        *(unsigned long long *) ifp->if_guid);
-
-       bguid = ifp->if_guid;
-       if (!bguid[0] && !bguid[1] && !bguid[2]) {
-               /* original incorrect GUID format in flash; fix in
-                * core copy, by shifting up 2 octets; don't need to
-                * change top octet, since both it and shifted are
-                * 0.. */
-               bguid[1] = bguid[3];
-               bguid[2] = bguid[4];
-               bguid[3] = bguid[4] = 0;
-               guid = *(__be64 *) ifp->if_guid;
-               ipath_cdbg(VERBOSE, "Old GUID format in flash, top 3 zero, "
-                          "shifting 2 octets\n");
-       } else
-               guid = *(__be64 *) ifp->if_guid;
-       dd->ipath_guid = guid;
-       dd->ipath_nguid = ifp->if_numguid;
-       /*
-        * Things are slightly complicated by the desire to transparently
-        * support both the Pathscale 10-digit serial number and the QLogic
-        * 13-character version.
-        */
-       if ((ifp->if_fversion > 1) && ifp->if_sprefix[0]
-               && ((u8 *)ifp->if_sprefix)[0] != 0xFF) {
-               /* This board has a Serial-prefix, which is stored
-                * elsewhere for backward-compatibility.
-                */
-               char *snp = dd->ipath_serial;
-               memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
-               snp[sizeof ifp->if_sprefix] = '\0';
-               len = strlen(snp);
-               snp += len;
-               len = (sizeof dd->ipath_serial) - len;
-               if (len > sizeof ifp->if_serial) {
-                       len = sizeof ifp->if_serial;
-               }
-               memcpy(snp, ifp->if_serial, len);
-       } else
-               memcpy(dd->ipath_serial, ifp->if_serial,
-                      sizeof ifp->if_serial);
-       if (!strstr(ifp->if_comment, "Tested successfully"))
-               ipath_dev_err(dd, "Board SN %s did not pass functional "
-                       "test: %s\n", dd->ipath_serial,
-                       ifp->if_comment);
-
-       ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n",
-                  (unsigned long long) be64_to_cpu(dd->ipath_guid));
-
-       memcpy(&dd->ipath_eep_st_errs, &ifp->if_errcntp, IPATH_EEP_LOG_CNT);
-       /*
-        * Power-on (actually "active") hours are kept as little-endian value
-        * in EEPROM, but as seconds in a (possibly as small as 24-bit)
-        * atomic_t while running.
-        */
-       atomic_set(&dd->ipath_active_time, 0);
-       dd->ipath_eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
-
-done:
-       vfree(buf);
-
-bail:;
-}
-
-/**
- * ipath_update_eeprom_log - copy active-time and error counters to eeprom
- * @dd: the infinipath device
- *
- * Although the time is kept as seconds in the ipath_devdata struct, it is
- * rounded to hours for re-write, as we have only 16 bits in EEPROM.
- * First-cut code reads whole (expected) struct ipath_flash, modifies,
- * re-writes. Future direction: read/write only what we need, assuming
- * that the EEPROM had to have been "good enough" for driver init, and
- * if not, we aren't making it worse.
- *
- */
-
-int ipath_update_eeprom_log(struct ipath_devdata *dd)
-{
-       void *buf;
-       struct ipath_flash *ifp;
-       int len, hi_water;
-       uint32_t new_time, new_hrs;
-       u8 csum;
-       int ret, idx;
-       unsigned long flags;
-
-       /* first, check if we actually need to do anything. */
-       ret = 0;
-       for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
-               if (dd->ipath_eep_st_new_errs[idx]) {
-                       ret = 1;
-                       break;
-               }
-       }
-       new_time = atomic_read(&dd->ipath_active_time);
-
-       if (ret == 0 && new_time < 3600)
-               return 0;
-
-       /*
-        * The quick-check above determined that there is something worthy
-        * of logging, so get current contents and do a more detailed idea.
-        * read full flash, not just currently used part, since it may have
-        * been written with a newer definition
-        */
-       len = sizeof(struct ipath_flash);
-       buf = vmalloc(len);
-       ret = 1;
-       if (!buf) {
-               ipath_dev_err(dd, "Couldn't allocate memory to read %u "
-                               "bytes from eeprom for logging\n", len);
-               goto bail;
-       }
-
-       /* Grab semaphore and read current EEPROM. If we get an
-        * error, let go, but if not, keep it until we finish write.
-        */
-       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
-       if (ret) {
-               ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
-               goto free_bail;
-       }
-       ret = ipath_eeprom_internal_read(dd, 0, buf, len);
-       if (ret) {
-               mutex_unlock(&dd->ipath_eep_lock);
-               ipath_dev_err(dd, "Unable read EEPROM for logging\n");
-               goto free_bail;
-       }
-       ifp = (struct ipath_flash *)buf;
-
-       csum = flash_csum(ifp, 0);
-       if (csum != ifp->if_csum) {
-               mutex_unlock(&dd->ipath_eep_lock);
-               ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
-                               csum, ifp->if_csum);
-               ret = 1;
-               goto free_bail;
-       }
-       hi_water = 0;
-       spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-       for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
-               int new_val = dd->ipath_eep_st_new_errs[idx];
-               if (new_val) {
-                       /*
-                        * If we have seen any errors, add to EEPROM values
-                        * We need to saturate at 0xFF (255) and we also
-                        * would need to adjust the checksum if we were
-                        * trying to minimize EEPROM traffic
-                        * Note that we add to actual current count in EEPROM,
-                        * in case it was altered while we were running.
-                        */
-                       new_val += ifp->if_errcntp[idx];
-                       if (new_val > 0xFF)
-                               new_val = 0xFF;
-                       if (ifp->if_errcntp[idx] != new_val) {
-                               ifp->if_errcntp[idx] = new_val;
-                               hi_water = offsetof(struct ipath_flash,
-                                               if_errcntp) + idx;
-                       }
-                       /*
-                        * update our shadow (used to minimize EEPROM
-                        * traffic), to match what we are about to write.
-                        */
-                       dd->ipath_eep_st_errs[idx] = new_val;
-                       dd->ipath_eep_st_new_errs[idx] = 0;
-               }
-       }
-       /*
-        * now update active-time. We would like to round to the nearest hour
-        * but unless atomic_t are sure to be proper signed ints we cannot,
-        * because we need to account for what we "transfer" to EEPROM and
-        * if we log an hour at 31 minutes, then we would need to set
-        * active_time to -29 to accurately count the _next_ hour.
-        */
-       if (new_time >= 3600) {
-               new_hrs = new_time / 3600;
-               atomic_sub((new_hrs * 3600), &dd->ipath_active_time);
-               new_hrs += dd->ipath_eep_hrs;
-               if (new_hrs > 0xFFFF)
-                       new_hrs = 0xFFFF;
-               dd->ipath_eep_hrs = new_hrs;
-               if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
-                       ifp->if_powerhour[0] = new_hrs & 0xFF;
-                       hi_water = offsetof(struct ipath_flash, if_powerhour);
-               }
-               if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
-                       ifp->if_powerhour[1] = new_hrs >> 8;
-                       hi_water = offsetof(struct ipath_flash, if_powerhour)
-                                       + 1;
-               }
-       }
-       /*
-        * There is a tiny possibility that we could somehow fail to write
-        * the EEPROM after updating our shadows, but problems from holding
-        * the spinlock too long are a much bigger issue.
-        */
-       spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
-       if (hi_water) {
-               /* we made some change to the data, uopdate cksum and write */
-               csum = flash_csum(ifp, 1);
-               ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
-       }
-       mutex_unlock(&dd->ipath_eep_lock);
-       if (ret)
-               ipath_dev_err(dd, "Failed updating EEPROM\n");
-
-free_bail:
-       vfree(buf);
-bail:
-       return ret;
-
-}
-
-/**
- * ipath_inc_eeprom_err - increment one of the four error counters
- * that are logged to EEPROM.
- * @dd: the infinipath device
- * @eidx: 0..3, the counter to increment
- * @incr: how much to add
- *
- * Each counter is 8-bits, and saturates at 255 (0xFF). They
- * are copied to the EEPROM (aka flash) whenever ipath_update_eeprom_log()
- * is called, but it can only be called in a context that allows sleep.
- * This function can be called even at interrupt level.
- */
-
-void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr)
-{
-       uint new_val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-       new_val = dd->ipath_eep_st_new_errs[eidx] + incr;
-       if (new_val > 255)
-               new_val = 255;
-       dd->ipath_eep_st_new_errs[eidx] = new_val;
-       spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
-       return;
-}
-
-static int ipath_tempsense_internal_read(struct ipath_devdata *dd, u8 regnum)
-{
-       int ret;
-       struct i2c_chain_desc *icd;
-
-       ret = -ENOENT;
-
-       icd = ipath_i2c_type(dd);
-       if (!icd)
-               goto bail;
-
-       if (icd->temp_dev == IPATH_NO_DEV) {
-               /* tempsense only exists on new, real-I2C boards */
-               ret = -ENXIO;
-               goto bail;
-       }
-
-       if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) {
-               ipath_dbg("Failed tempsense startcmd\n");
-               stop_cmd(dd);
-               ret = -ENXIO;
-               goto bail;
-       }
-       ret = wr_byte(dd, regnum);
-       stop_cmd(dd);
-       if (ret) {
-               ipath_dev_err(dd, "Failed tempsense WR command %02X\n",
-                             regnum);
-               ret = -ENXIO;
-               goto bail;
-       }
-       if (i2c_startcmd(dd, icd->temp_dev | READ_CMD)) {
-               ipath_dbg("Failed tempsense RD startcmd\n");
-               stop_cmd(dd);
-               ret = -ENXIO;
-               goto bail;
-       }
-       /*
-        * We can only clock out one byte per command, sensibly
-        */
-       ret = rd_byte(dd);
-       stop_cmd(dd);
-
-bail:
-       return ret;
-}
-
-#define VALID_TS_RD_REG_MASK 0xBF
-
-/**
- * ipath_tempsense_read - read register of temp sensor via I2C
- * @dd: the infinipath device
- * @regnum: register to read from
- *
- * returns reg contents (0..255) or < 0 for error
- */
-int ipath_tempsense_read(struct ipath_devdata *dd, u8 regnum)
-{
-       int ret;
-
-       if (regnum > 7)
-               return -EINVAL;
-
-       /* return a bogus value for (the one) register we do not have */
-       if (!((1 << regnum) & VALID_TS_RD_REG_MASK))
-               return 0;
-
-       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
-       if (!ret) {
-               ret = ipath_tempsense_internal_read(dd, regnum);
-               mutex_unlock(&dd->ipath_eep_lock);
-       }
-
-       /*
-        * There are three possibilities here:
-        * ret is actual value (0..255)
-        * ret is -ENXIO or -EINVAL from code in this file
-        * ret is -EINTR from mutex_lock_interruptible.
-        */
-       return ret;
-}
-
-static int ipath_tempsense_internal_write(struct ipath_devdata *dd,
-                                         u8 regnum, u8 data)
-{
-       int ret = -ENOENT;
-       struct i2c_chain_desc *icd;
-
-       icd = ipath_i2c_type(dd);
-       if (!icd)
-               goto bail;
-
-       if (icd->temp_dev == IPATH_NO_DEV) {
-               /* tempsense only exists on new, real-I2C boards */
-               ret = -ENXIO;
-               goto bail;
-       }
-       if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) {
-               ipath_dbg("Failed tempsense startcmd\n");
-               stop_cmd(dd);
-               ret = -ENXIO;
-               goto bail;
-       }
-       ret = wr_byte(dd, regnum);
-       if (ret) {
-               stop_cmd(dd);
-               ipath_dev_err(dd, "Failed to write tempsense command %02X\n",
-                             regnum);
-               ret = -ENXIO;
-               goto bail;
-       }
-       ret = wr_byte(dd, data);
-       stop_cmd(dd);
-       ret = i2c_startcmd(dd, icd->temp_dev | READ_CMD);
-       if (ret) {
-               ipath_dev_err(dd, "Failed tempsense data wrt to %02X\n",
-                             regnum);
-               ret = -ENXIO;
-       }
-
-bail:
-       return ret;
-}
-
-#define VALID_TS_WR_REG_MASK ((1 << 9) | (1 << 0xB) | (1 << 0xD))
-
-/**
- * ipath_tempsense_write - write register of temp sensor via I2C
- * @dd: the infinipath device
- * @regnum: register to write
- * @data: data to write
- *
- * returns 0 for success or < 0 for error
- */
-int ipath_tempsense_write(struct ipath_devdata *dd, u8 regnum, u8 data)
-{
-       int ret;
-
-       if (regnum > 15 || !((1 << regnum) & VALID_TS_WR_REG_MASK))
-               return -EINVAL;
-
-       ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
-       if (!ret) {
-               ret = ipath_tempsense_internal_write(dd, regnum, data);
-               mutex_unlock(&dd->ipath_eep_lock);
-       }
-
-       /*
-        * There are three possibilities here:
-        * ret is 0 for success
-        * ret is -ENXIO or -EINVAL from code in this file
-        * ret is -EINTR from mutex_lock_interruptible.
-        */
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_file_ops.c b/drivers/staging/rdma/ipath/ipath_file_ops.c
deleted file mode 100644 (file)
index 6187b84..0000000
+++ /dev/null
@@ -1,2619 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/pci.h>
-#include <linux/poll.h>
-#include <linux/cdev.h>
-#include <linux/swap.h>
-#include <linux/export.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-#include <linux/io.h>
-#include <linux/jiffies.h>
-#include <linux/cpu.h>
-#include <linux/uio.h>
-#include <asm/pgtable.h>
-
-#include "ipath_kernel.h"
-#include "ipath_common.h"
-#include "ipath_user_sdma.h"
-
-static int ipath_open(struct inode *, struct file *);
-static int ipath_close(struct inode *, struct file *);
-static ssize_t ipath_write(struct file *, const char __user *, size_t,
-                          loff_t *);
-static ssize_t ipath_write_iter(struct kiocb *, struct iov_iter *from);
-static unsigned int ipath_poll(struct file *, struct poll_table_struct *);
-static int ipath_mmap(struct file *, struct vm_area_struct *);
-
-/*
- * This is really, really weird shit - write() and writev() here
- * have completely unrelated semantics.  Sucky userland ABI,
- * film at 11.
- */
-static const struct file_operations ipath_file_ops = {
-       .owner = THIS_MODULE,
-       .write = ipath_write,
-       .write_iter = ipath_write_iter,
-       .open = ipath_open,
-       .release = ipath_close,
-       .poll = ipath_poll,
-       .mmap = ipath_mmap,
-       .llseek = noop_llseek,
-};
-
-/*
- * Convert kernel virtual addresses to physical addresses so they don't
- * potentially conflict with the chip addresses used as mmap offsets.
- * It doesn't really matter what mmap offset we use as long as we can
- * interpret it correctly.
- */
-static u64 cvt_kvaddr(void *p)
-{
-       struct page *page;
-       u64 paddr = 0;
-
-       page = vmalloc_to_page(p);
-       if (page)
-               paddr = page_to_pfn(page) << PAGE_SHIFT;
-
-       return paddr;
-}
-
-static int ipath_get_base_info(struct file *fp,
-                              void __user *ubase, size_t ubase_size)
-{
-       struct ipath_portdata *pd = port_fp(fp);
-       int ret = 0;
-       struct ipath_base_info *kinfo = NULL;
-       struct ipath_devdata *dd = pd->port_dd;
-       unsigned subport_cnt;
-       int shared, master;
-       size_t sz;
-
-       subport_cnt = pd->port_subport_cnt;
-       if (!subport_cnt) {
-               shared = 0;
-               master = 0;
-               subport_cnt = 1;
-       } else {
-               shared = 1;
-               master = !subport_fp(fp);
-       }
-
-       sz = sizeof(*kinfo);
-       /* If port sharing is not requested, allow the old size structure */
-       if (!shared)
-               sz -= 7 * sizeof(u64);
-       if (ubase_size < sz) {
-               ipath_cdbg(PROC,
-                          "Base size %zu, need %zu (version mismatch?)\n",
-                          ubase_size, sz);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       kinfo = kzalloc(sizeof(*kinfo), GFP_KERNEL);
-       if (kinfo == NULL) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       ret = dd->ipath_f_get_base_info(pd, kinfo);
-       if (ret < 0)
-               goto bail;
-
-       kinfo->spi_rcvhdr_cnt = dd->ipath_rcvhdrcnt;
-       kinfo->spi_rcvhdrent_size = dd->ipath_rcvhdrentsize;
-       kinfo->spi_tidegrcnt = dd->ipath_rcvegrcnt;
-       kinfo->spi_rcv_egrbufsize = dd->ipath_rcvegrbufsize;
-       /*
-        * have to mmap whole thing
-        */
-       kinfo->spi_rcv_egrbuftotlen =
-               pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
-       kinfo->spi_rcv_egrperchunk = pd->port_rcvegrbufs_perchunk;
-       kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
-               pd->port_rcvegrbuf_chunks;
-       kinfo->spi_tidcnt = dd->ipath_rcvtidcnt / subport_cnt;
-       if (master)
-               kinfo->spi_tidcnt += dd->ipath_rcvtidcnt % subport_cnt;
-       /*
-        * for this use, may be ipath_cfgports summed over all chips that
-        * are are configured and present
-        */
-       kinfo->spi_nports = dd->ipath_cfgports;
-       /* unit (chip/board) our port is on */
-       kinfo->spi_unit = dd->ipath_unit;
-       /* for now, only a single page */
-       kinfo->spi_tid_maxsize = PAGE_SIZE;
-
-       /*
-        * Doing this per port, and based on the skip value, etc.  This has
-        * to be the actual buffer size, since the protocol code treats it
-        * as an array.
-        *
-        * These have to be set to user addresses in the user code via mmap.
-        * These values are used on return to user code for the mmap target
-        * addresses only.  For 32 bit, same 44 bit address problem, so use
-        * the physical address, not virtual.  Before 2.6.11, using the
-        * page_address() macro worked, but in 2.6.11, even that returns the
-        * full 64 bit address (upper bits all 1's).  So far, using the
-        * physical addresses (or chip offsets, for chip mapping) works, but
-        * no doubt some future kernel release will change that, and we'll be
-        * on to yet another method of dealing with this.
-        */
-       kinfo->spi_rcvhdr_base = (u64) pd->port_rcvhdrq_phys;
-       kinfo->spi_rcvhdr_tailaddr = (u64) pd->port_rcvhdrqtailaddr_phys;
-       kinfo->spi_rcv_egrbufs = (u64) pd->port_rcvegr_phys;
-       kinfo->spi_pioavailaddr = (u64) dd->ipath_pioavailregs_phys;
-       kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
-               (void *) dd->ipath_statusp -
-               (void *) dd->ipath_pioavailregs_dma;
-       if (!shared) {
-               kinfo->spi_piocnt = pd->port_piocnt;
-               kinfo->spi_piobufbase = (u64) pd->port_piobufs;
-               kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
-                       dd->ipath_ureg_align * pd->port_port;
-       } else if (master) {
-               kinfo->spi_piocnt = (pd->port_piocnt / subport_cnt) +
-                                   (pd->port_piocnt % subport_cnt);
-               /* Master's PIO buffers are after all the slave's */
-               kinfo->spi_piobufbase = (u64) pd->port_piobufs +
-                       dd->ipath_palign *
-                       (pd->port_piocnt - kinfo->spi_piocnt);
-       } else {
-               unsigned slave = subport_fp(fp) - 1;
-
-               kinfo->spi_piocnt = pd->port_piocnt / subport_cnt;
-               kinfo->spi_piobufbase = (u64) pd->port_piobufs +
-                       dd->ipath_palign * kinfo->spi_piocnt * slave;
-       }
-
-       if (shared) {
-               kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
-                       dd->ipath_ureg_align * pd->port_port;
-               kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
-               kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
-               kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
-
-               kinfo->__spi_uregbase = cvt_kvaddr(pd->subport_uregbase +
-                       PAGE_SIZE * subport_fp(fp));
-
-               kinfo->spi_rcvhdr_base = cvt_kvaddr(pd->subport_rcvhdr_base +
-                       pd->port_rcvhdrq_size * subport_fp(fp));
-               kinfo->spi_rcvhdr_tailaddr = 0;
-               kinfo->spi_rcv_egrbufs = cvt_kvaddr(pd->subport_rcvegrbuf +
-                       pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size *
-                       subport_fp(fp));
-
-               kinfo->spi_subport_uregbase =
-                       cvt_kvaddr(pd->subport_uregbase);
-               kinfo->spi_subport_rcvegrbuf =
-                       cvt_kvaddr(pd->subport_rcvegrbuf);
-               kinfo->spi_subport_rcvhdr_base =
-                       cvt_kvaddr(pd->subport_rcvhdr_base);
-               ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n",
-                       kinfo->spi_port, kinfo->spi_runtime_flags,
-                       (unsigned long long) kinfo->spi_subport_uregbase,
-                       (unsigned long long) kinfo->spi_subport_rcvegrbuf,
-                       (unsigned long long) kinfo->spi_subport_rcvhdr_base);
-       }
-
-       /*
-        * All user buffers are 2KB buffers.  If we ever support
-        * giving 4KB buffers to user processes, this will need some
-        * work.
-        */
-       kinfo->spi_pioindex = (kinfo->spi_piobufbase -
-               (dd->ipath_piobufbase & 0xffffffff)) / dd->ipath_palign;
-       kinfo->spi_pioalign = dd->ipath_palign;
-
-       kinfo->spi_qpair = IPATH_KD_QP;
-       /*
-        * user mode PIO buffers are always 2KB, even when 4KB can
-        * be received, and sent via the kernel; this is ibmaxlen
-        * for 2K MTU.
-        */
-       kinfo->spi_piosize = dd->ipath_piosize2k - 2 * sizeof(u32);
-       kinfo->spi_mtu = dd->ipath_ibmaxlen;    /* maxlen, not ibmtu */
-       kinfo->spi_port = pd->port_port;
-       kinfo->spi_subport = subport_fp(fp);
-       kinfo->spi_sw_version = IPATH_KERN_SWVERSION;
-       kinfo->spi_hw_version = dd->ipath_revision;
-
-       if (master) {
-               kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER;
-       }
-
-       sz = (ubase_size < sizeof(*kinfo)) ? ubase_size : sizeof(*kinfo);
-       if (copy_to_user(ubase, kinfo, sz))
-               ret = -EFAULT;
-
-bail:
-       kfree(kinfo);
-       return ret;
-}
-
-/**
- * ipath_tid_update - update a port TID
- * @pd: the port
- * @fp: the ipath device file
- * @ti: the TID information
- *
- * The new implementation as of Oct 2004 is that the driver assigns
- * the tid and returns it to the caller.   To make it easier to
- * catch bugs, and to reduce search time, we keep a cursor for
- * each port, walking the shadow tid array to find one that's not
- * in use.
- *
- * For now, if we can't allocate the full list, we fail, although
- * in the long run, we'll allocate as many as we can, and the
- * caller will deal with that by trying the remaining pages later.
- * That means that when we fail, we have to mark the tids as not in
- * use again, in our shadow copy.
- *
- * It's up to the caller to free the tids when they are done.
- * We'll unlock the pages as they free them.
- *
- * Also, right now we are locking one page at a time, but since
- * the intended use of this routine is for a single group of
- * virtually contiguous pages, that should change to improve
- * performance.
- */
-static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
-                           const struct ipath_tid_info *ti)
-{
-       int ret = 0, ntids;
-       u32 tid, porttid, cnt, i, tidcnt, tidoff;
-       u16 *tidlist;
-       struct ipath_devdata *dd = pd->port_dd;
-       u64 physaddr;
-       unsigned long vaddr;
-       u64 __iomem *tidbase;
-       unsigned long tidmap[8];
-       struct page **pagep = NULL;
-       unsigned subport = subport_fp(fp);
-
-       if (!dd->ipath_pageshadow) {
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       cnt = ti->tidcnt;
-       if (!cnt) {
-               ipath_dbg("After copyin, tidcnt 0, tidlist %llx\n",
-                         (unsigned long long) ti->tidlist);
-               /*
-                * Should we treat as success?  likely a bug
-                */
-               ret = -EFAULT;
-               goto done;
-       }
-       porttid = pd->port_port * dd->ipath_rcvtidcnt;
-       if (!pd->port_subport_cnt) {
-               tidcnt = dd->ipath_rcvtidcnt;
-               tid = pd->port_tidcursor;
-               tidoff = 0;
-       } else if (!subport) {
-               tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
-                        (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
-               tidoff = dd->ipath_rcvtidcnt - tidcnt;
-               porttid += tidoff;
-               tid = tidcursor_fp(fp);
-       } else {
-               tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
-               tidoff = tidcnt * (subport - 1);
-               porttid += tidoff;
-               tid = tidcursor_fp(fp);
-       }
-       if (cnt > tidcnt) {
-               /* make sure it all fits in port_tid_pg_list */
-               dev_info(&dd->pcidev->dev, "Process tried to allocate %u "
-                        "TIDs, only trying max (%u)\n", cnt, tidcnt);
-               cnt = tidcnt;
-       }
-       pagep = &((struct page **) pd->port_tid_pg_list)[tidoff];
-       tidlist = &((u16 *) &pagep[dd->ipath_rcvtidcnt])[tidoff];
-
-       memset(tidmap, 0, sizeof(tidmap));
-       /* before decrement; chip actual # */
-       ntids = tidcnt;
-       tidbase = (u64 __iomem *) (((char __iomem *) dd->ipath_kregbase) +
-                                  dd->ipath_rcvtidbase +
-                                  porttid * sizeof(*tidbase));
-
-       ipath_cdbg(VERBOSE, "Port%u %u tids, cursor %u, tidbase %p\n",
-                  pd->port_port, cnt, tid, tidbase);
-
-       /* virtual address of first page in transfer */
-       vaddr = ti->tidvaddr;
-       if (!access_ok(VERIFY_WRITE, (void __user *) vaddr,
-                      cnt * PAGE_SIZE)) {
-               ipath_dbg("Fail vaddr %p, %u pages, !access_ok\n",
-                         (void *)vaddr, cnt);
-               ret = -EFAULT;
-               goto done;
-       }
-       ret = ipath_get_user_pages(vaddr, cnt, pagep);
-       if (ret) {
-               if (ret == -EBUSY) {
-                       ipath_dbg("Failed to lock addr %p, %u pages "
-                                 "(already locked)\n",
-                                 (void *) vaddr, cnt);
-                       /*
-                        * for now, continue, and see what happens but with
-                        * the new implementation, this should never happen,
-                        * unless perhaps the user has mpin'ed the pages
-                        * themselves (something we need to test)
-                        */
-                       ret = 0;
-               } else {
-                       dev_info(&dd->pcidev->dev,
-                                "Failed to lock addr %p, %u pages: "
-                                "errno %d\n", (void *) vaddr, cnt, -ret);
-                       goto done;
-               }
-       }
-       for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
-               for (; ntids--; tid++) {
-                       if (tid == tidcnt)
-                               tid = 0;
-                       if (!dd->ipath_pageshadow[porttid + tid])
-                               break;
-               }
-               if (ntids < 0) {
-                       /*
-                        * oops, wrapped all the way through their TIDs,
-                        * and didn't have enough free; see comments at
-                        * start of routine
-                        */
-                       ipath_dbg("Not enough free TIDs for %u pages "
-                                 "(index %d), failing\n", cnt, i);
-                       i--;    /* last tidlist[i] not filled in */
-                       ret = -ENOMEM;
-                       break;
-               }
-               tidlist[i] = tid + tidoff;
-               ipath_cdbg(VERBOSE, "Updating idx %u to TID %u, "
-                          "vaddr %lx\n", i, tid + tidoff, vaddr);
-               /* we "know" system pages and TID pages are same size */
-               dd->ipath_pageshadow[porttid + tid] = pagep[i];
-               dd->ipath_physshadow[porttid + tid] = ipath_map_page(
-                       dd->pcidev, pagep[i], 0, PAGE_SIZE,
-                       PCI_DMA_FROMDEVICE);
-               /*
-                * don't need atomic or it's overhead
-                */
-               __set_bit(tid, tidmap);
-               physaddr = dd->ipath_physshadow[porttid + tid];
-               ipath_stats.sps_pagelocks++;
-               ipath_cdbg(VERBOSE,
-                          "TID %u, vaddr %lx, physaddr %llx pgp %p\n",
-                          tid, vaddr, (unsigned long long) physaddr,
-                          pagep[i]);
-               dd->ipath_f_put_tid(dd, &tidbase[tid], RCVHQ_RCV_TYPE_EXPECTED,
-                                   physaddr);
-               /*
-                * don't check this tid in ipath_portshadow, since we
-                * just filled it in; start with the next one.
-                */
-               tid++;
-       }
-
-       if (ret) {
-               u32 limit;
-       cleanup:
-               /* jump here if copy out of updated info failed... */
-               ipath_dbg("After failure (ret=%d), undo %d of %d entries\n",
-                         -ret, i, cnt);
-               /* same code that's in ipath_free_tid() */
-               limit = sizeof(tidmap) * BITS_PER_BYTE;
-               if (limit > tidcnt)
-                       /* just in case size changes in future */
-                       limit = tidcnt;
-               tid = find_first_bit((const unsigned long *)tidmap, limit);
-               for (; tid < limit; tid++) {
-                       if (!test_bit(tid, tidmap))
-                               continue;
-                       if (dd->ipath_pageshadow[porttid + tid]) {
-                               ipath_cdbg(VERBOSE, "Freeing TID %u\n",
-                                          tid);
-                               dd->ipath_f_put_tid(dd, &tidbase[tid],
-                                                   RCVHQ_RCV_TYPE_EXPECTED,
-                                                   dd->ipath_tidinvalid);
-                               pci_unmap_page(dd->pcidev,
-                                       dd->ipath_physshadow[porttid + tid],
-                                       PAGE_SIZE, PCI_DMA_FROMDEVICE);
-                               dd->ipath_pageshadow[porttid + tid] = NULL;
-                               ipath_stats.sps_pageunlocks++;
-                       }
-               }
-               ipath_release_user_pages(pagep, cnt);
-       } else {
-               /*
-                * Copy the updated array, with ipath_tid's filled in, back
-                * to user.  Since we did the copy in already, this "should
-                * never fail" If it does, we have to clean up...
-                */
-               if (copy_to_user((void __user *)
-                                (unsigned long) ti->tidlist,
-                                tidlist, cnt * sizeof(*tidlist))) {
-                       ret = -EFAULT;
-                       goto cleanup;
-               }
-               if (copy_to_user((void __user *) (unsigned long) ti->tidmap,
-                                tidmap, sizeof tidmap)) {
-                       ret = -EFAULT;
-                       goto cleanup;
-               }
-               if (tid == tidcnt)
-                       tid = 0;
-               if (!pd->port_subport_cnt)
-                       pd->port_tidcursor = tid;
-               else
-                       tidcursor_fp(fp) = tid;
-       }
-
-done:
-       if (ret)
-               ipath_dbg("Failed to map %u TID pages, failing with %d\n",
-                         ti->tidcnt, -ret);
-       return ret;
-}
-
-/**
- * ipath_tid_free - free a port TID
- * @pd: the port
- * @subport: the subport
- * @ti: the TID info
- *
- * right now we are unlocking one page at a time, but since
- * the intended use of this routine is for a single group of
- * virtually contiguous pages, that should change to improve
- * performance.  We check that the TID is in range for this port
- * but otherwise don't check validity; if user has an error and
- * frees the wrong tid, it's only their own data that can thereby
- * be corrupted.  We do check that the TID was in use, for sanity
- * We always use our idea of the saved address, not the address that
- * they pass in to us.
- */
-
-static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
-                         const struct ipath_tid_info *ti)
-{
-       int ret = 0;
-       u32 tid, porttid, cnt, limit, tidcnt;
-       struct ipath_devdata *dd = pd->port_dd;
-       u64 __iomem *tidbase;
-       unsigned long tidmap[8];
-
-       if (!dd->ipath_pageshadow) {
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       if (copy_from_user(tidmap, (void __user *)(unsigned long)ti->tidmap,
-                          sizeof tidmap)) {
-               ret = -EFAULT;
-               goto done;
-       }
-
-       porttid = pd->port_port * dd->ipath_rcvtidcnt;
-       if (!pd->port_subport_cnt)
-               tidcnt = dd->ipath_rcvtidcnt;
-       else if (!subport) {
-               tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
-                        (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
-               porttid += dd->ipath_rcvtidcnt - tidcnt;
-       } else {
-               tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
-               porttid += tidcnt * (subport - 1);
-       }
-       tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
-                                  dd->ipath_rcvtidbase +
-                                  porttid * sizeof(*tidbase));
-
-       limit = sizeof(tidmap) * BITS_PER_BYTE;
-       if (limit > tidcnt)
-               /* just in case size changes in future */
-               limit = tidcnt;
-       tid = find_first_bit(tidmap, limit);
-       ipath_cdbg(VERBOSE, "Port%u free %u tids; first bit (max=%d) "
-                  "set is %d, porttid %u\n", pd->port_port, ti->tidcnt,
-                  limit, tid, porttid);
-       for (cnt = 0; tid < limit; tid++) {
-               /*
-                * small optimization; if we detect a run of 3 or so without
-                * any set, use find_first_bit again.  That's mainly to
-                * accelerate the case where we wrapped, so we have some at
-                * the beginning, and some at the end, and a big gap
-                * in the middle.
-                */
-               if (!test_bit(tid, tidmap))
-                       continue;
-               cnt++;
-               if (dd->ipath_pageshadow[porttid + tid]) {
-                       struct page *p;
-                       p = dd->ipath_pageshadow[porttid + tid];
-                       dd->ipath_pageshadow[porttid + tid] = NULL;
-                       ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n",
-                                  pid_nr(pd->port_pid), tid);
-                       dd->ipath_f_put_tid(dd, &tidbase[tid],
-                                           RCVHQ_RCV_TYPE_EXPECTED,
-                                           dd->ipath_tidinvalid);
-                       pci_unmap_page(dd->pcidev,
-                               dd->ipath_physshadow[porttid + tid],
-                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
-                       ipath_release_user_pages(&p, 1);
-                       ipath_stats.sps_pageunlocks++;
-               } else
-                       ipath_dbg("Unused tid %u, ignoring\n", tid);
-       }
-       if (cnt != ti->tidcnt)
-               ipath_dbg("passed in tidcnt %d, only %d bits set in map\n",
-                         ti->tidcnt, cnt);
-done:
-       if (ret)
-               ipath_dbg("Failed to unmap %u TID pages, failing with %d\n",
-                         ti->tidcnt, -ret);
-       return ret;
-}
-
-/**
- * ipath_set_part_key - set a partition key
- * @pd: the port
- * @key: the key
- *
- * We can have up to 4 active at a time (other than the default, which is
- * always allowed).  This is somewhat tricky, since multiple ports may set
- * the same key, so we reference count them, and clean up at exit.  All 4
- * partition keys are packed into a single infinipath register.  It's an
- * error for a process to set the same pkey multiple times.  We provide no
- * mechanism to de-allocate a pkey at this time, we may eventually need to
- * do that.  I've used the atomic operations, and no locking, and only make
- * a single pass through what's available.  This should be more than
- * adequate for some time. I'll think about spinlocks or the like if and as
- * it's necessary.
- */
-static int ipath_set_part_key(struct ipath_portdata *pd, u16 key)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       int i, any = 0, pidx = -1;
-       u16 lkey = key & 0x7FFF;
-       int ret;
-
-       if (lkey == (IPATH_DEFAULT_P_KEY & 0x7FFF)) {
-               /* nothing to do; this key always valid */
-               ret = 0;
-               goto bail;
-       }
-
-       ipath_cdbg(VERBOSE, "p%u try to set pkey %hx, current keys "
-                  "%hx:%x %hx:%x %hx:%x %hx:%x\n",
-                  pd->port_port, key, dd->ipath_pkeys[0],
-                  atomic_read(&dd->ipath_pkeyrefs[0]), dd->ipath_pkeys[1],
-                  atomic_read(&dd->ipath_pkeyrefs[1]), dd->ipath_pkeys[2],
-                  atomic_read(&dd->ipath_pkeyrefs[2]), dd->ipath_pkeys[3],
-                  atomic_read(&dd->ipath_pkeyrefs[3]));
-
-       if (!lkey) {
-               ipath_cdbg(PROC, "p%u tries to set key 0, not allowed\n",
-                          pd->port_port);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       /*
-        * Set the full membership bit, because it has to be
-        * set in the register or the packet, and it seems
-        * cleaner to set in the register than to force all
-        * callers to set it. (see bug 4331)
-        */
-       key |= 0x8000;
-
-       for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
-               if (!pd->port_pkeys[i] && pidx == -1)
-                       pidx = i;
-               if (pd->port_pkeys[i] == key) {
-                       ipath_cdbg(VERBOSE, "p%u tries to set same pkey "
-                                  "(%x) more than once\n",
-                                  pd->port_port, key);
-                       ret = -EEXIST;
-                       goto bail;
-               }
-       }
-       if (pidx == -1) {
-               ipath_dbg("All pkeys for port %u already in use, "
-                         "can't set %x\n", pd->port_port, key);
-               ret = -EBUSY;
-               goto bail;
-       }
-       for (any = i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
-               if (!dd->ipath_pkeys[i]) {
-                       any++;
-                       continue;
-               }
-               if (dd->ipath_pkeys[i] == key) {
-                       atomic_t *pkrefs = &dd->ipath_pkeyrefs[i];
-
-                       if (atomic_inc_return(pkrefs) > 1) {
-                               pd->port_pkeys[pidx] = key;
-                               ipath_cdbg(VERBOSE, "p%u set key %x "
-                                          "matches #%d, count now %d\n",
-                                          pd->port_port, key, i,
-                                          atomic_read(pkrefs));
-                               ret = 0;
-                               goto bail;
-                       } else {
-                               /*
-                                * lost race, decrement count, catch below
-                                */
-                               atomic_dec(pkrefs);
-                               ipath_cdbg(VERBOSE, "Lost race, count was "
-                                          "0, after dec, it's %d\n",
-                                          atomic_read(pkrefs));
-                               any++;
-                       }
-               }
-               if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
-                       /*
-                        * It makes no sense to have both the limited and
-                        * full membership PKEY set at the same time since
-                        * the unlimited one will disable the limited one.
-                        */
-                       ret = -EEXIST;
-                       goto bail;
-               }
-       }
-       if (!any) {
-               ipath_dbg("port %u, all pkeys already in use, "
-                         "can't set %x\n", pd->port_port, key);
-               ret = -EBUSY;
-               goto bail;
-       }
-       for (any = i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
-               if (!dd->ipath_pkeys[i] &&
-                   atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
-                       u64 pkey;
-
-                       /* for ipathstats, etc. */
-                       ipath_stats.sps_pkeys[i] = lkey;
-                       pd->port_pkeys[pidx] = dd->ipath_pkeys[i] = key;
-                       pkey =
-                               (u64) dd->ipath_pkeys[0] |
-                               ((u64) dd->ipath_pkeys[1] << 16) |
-                               ((u64) dd->ipath_pkeys[2] << 32) |
-                               ((u64) dd->ipath_pkeys[3] << 48);
-                       ipath_cdbg(PROC, "p%u set key %x in #%d, "
-                                  "portidx %d, new pkey reg %llx\n",
-                                  pd->port_port, key, i, pidx,
-                                  (unsigned long long) pkey);
-                       ipath_write_kreg(
-                               dd, dd->ipath_kregs->kr_partitionkey, pkey);
-
-                       ret = 0;
-                       goto bail;
-               }
-       }
-       ipath_dbg("port %u, all pkeys already in use 2nd pass, "
-                 "can't set %x\n", pd->port_port, key);
-       ret = -EBUSY;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_manage_rcvq - manage a port's receive queue
- * @pd: the port
- * @subport: the subport
- * @start_stop: action to carry out
- *
- * start_stop == 0 disables receive on the port, for use in queue
- * overflow conditions.  start_stop==1 re-enables, to be used to
- * re-init the software copy of the head register
- */
-static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
-                            int start_stop)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-
-       ipath_cdbg(PROC, "%sabling rcv for unit %u port %u:%u\n",
-                  start_stop ? "en" : "dis", dd->ipath_unit,
-                  pd->port_port, subport);
-       if (subport)
-               goto bail;
-       /* atomically clear receive enable port. */
-       if (start_stop) {
-               /*
-                * On enable, force in-memory copy of the tail register to
-                * 0, so that protocol code doesn't have to worry about
-                * whether or not the chip has yet updated the in-memory
-                * copy or not on return from the system call. The chip
-                * always resets it's tail register back to 0 on a
-                * transition from disabled to enabled.  This could cause a
-                * problem if software was broken, and did the enable w/o
-                * the disable, but eventually the in-memory copy will be
-                * updated and correct itself, even in the face of software
-                * bugs.
-                */
-               if (pd->port_rcvhdrtail_kvaddr)
-                       ipath_clear_rcvhdrtail(pd);
-               set_bit(dd->ipath_r_portenable_shift + pd->port_port,
-                       &dd->ipath_rcvctrl);
-       } else
-               clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
-                         &dd->ipath_rcvctrl);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-       /* now be sure chip saw it before we return */
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       if (start_stop) {
-               /*
-                * And try to be sure that tail reg update has happened too.
-                * This should in theory interlock with the RXE changes to
-                * the tail register.  Don't assign it to the tail register
-                * in memory copy, since we could overwrite an update by the
-                * chip if we did.
-                */
-               ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
-       }
-       /* always; new head should be equal to new tail; see above */
-bail:
-       return 0;
-}
-
-static void ipath_clean_part_key(struct ipath_portdata *pd,
-                                struct ipath_devdata *dd)
-{
-       int i, j, pchanged = 0;
-       u64 oldpkey;
-
-       /* for debugging only */
-       oldpkey = (u64) dd->ipath_pkeys[0] |
-               ((u64) dd->ipath_pkeys[1] << 16) |
-               ((u64) dd->ipath_pkeys[2] << 32) |
-               ((u64) dd->ipath_pkeys[3] << 48);
-
-       for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
-               if (!pd->port_pkeys[i])
-                       continue;
-               ipath_cdbg(VERBOSE, "look for key[%d] %hx in pkeys\n", i,
-                          pd->port_pkeys[i]);
-               for (j = 0; j < ARRAY_SIZE(dd->ipath_pkeys); j++) {
-                       /* check for match independent of the global bit */
-                       if ((dd->ipath_pkeys[j] & 0x7fff) !=
-                           (pd->port_pkeys[i] & 0x7fff))
-                               continue;
-                       if (atomic_dec_and_test(&dd->ipath_pkeyrefs[j])) {
-                               ipath_cdbg(VERBOSE, "p%u clear key "
-                                          "%x matches #%d\n",
-                                          pd->port_port,
-                                          pd->port_pkeys[i], j);
-                               ipath_stats.sps_pkeys[j] =
-                                       dd->ipath_pkeys[j] = 0;
-                               pchanged++;
-                       } else {
-                               ipath_cdbg(VERBOSE, "p%u key %x matches #%d, "
-                                          "but ref still %d\n", pd->port_port,
-                                          pd->port_pkeys[i], j,
-                                          atomic_read(&dd->ipath_pkeyrefs[j]));
-                               break;
-                       }
-               }
-               pd->port_pkeys[i] = 0;
-       }
-       if (pchanged) {
-               u64 pkey = (u64) dd->ipath_pkeys[0] |
-                       ((u64) dd->ipath_pkeys[1] << 16) |
-                       ((u64) dd->ipath_pkeys[2] << 32) |
-                       ((u64) dd->ipath_pkeys[3] << 48);
-               ipath_cdbg(VERBOSE, "p%u old pkey reg %llx, "
-                          "new pkey reg %llx\n", pd->port_port,
-                          (unsigned long long) oldpkey,
-                          (unsigned long long) pkey);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
-                                pkey);
-       }
-}
-
-/*
- * Initialize the port data with the receive buffer sizes
- * so this can be done while the master port is locked.
- * Otherwise, there is a race with a slave opening the port
- * and seeing these fields uninitialized.
- */
-static void init_user_egr_sizes(struct ipath_portdata *pd)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       unsigned egrperchunk, egrcnt, size;
-
-       /*
-        * to avoid wasting a lot of memory, we allocate 32KB chunks of
-        * physically contiguous memory, advance through it until used up
-        * and then allocate more.  Of course, we need memory to store those
-        * extra pointers, now.  Started out with 256KB, but under heavy
-        * memory pressure (creating large files and then copying them over
-        * NFS while doing lots of MPI jobs), we hit some allocation
-        * failures, even though we can sleep...  (2.6.10) Still get
-        * failures at 64K.  32K is the lowest we can go without wasting
-        * additional memory.
-        */
-       size = 0x8000;
-       egrperchunk = size / dd->ipath_rcvegrbufsize;
-       egrcnt = dd->ipath_rcvegrcnt;
-       pd->port_rcvegrbuf_chunks = (egrcnt + egrperchunk - 1) / egrperchunk;
-       pd->port_rcvegrbufs_perchunk = egrperchunk;
-       pd->port_rcvegrbuf_size = size;
-}
-
-/**
- * ipath_create_user_egr - allocate eager TID buffers
- * @pd: the port to allocate TID buffers for
- *
- * This routine is now quite different for user and kernel, because
- * the kernel uses skb's, for the accelerated network performance
- * This is the user port version
- *
- * Allocate the eager TID buffers and program them into infinipath
- * They are no longer completely contiguous, we do multiple allocation
- * calls.
- */
-static int ipath_create_user_egr(struct ipath_portdata *pd)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
-       size_t size;
-       int ret;
-       gfp_t gfp_flags;
-
-       /*
-        * GFP_USER, but without GFP_FS, so buffer cache can be
-        * coalesced (we hope); otherwise, even at order 4,
-        * heavy filesystem activity makes these fail, and we can
-        * use compound pages.
-        */
-       gfp_flags = __GFP_RECLAIM | __GFP_IO | __GFP_COMP;
-
-       egrcnt = dd->ipath_rcvegrcnt;
-       /* TID number offset for this port */
-       egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
-       egrsize = dd->ipath_rcvegrbufsize;
-       ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
-                  "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
-
-       chunk = pd->port_rcvegrbuf_chunks;
-       egrperchunk = pd->port_rcvegrbufs_perchunk;
-       size = pd->port_rcvegrbuf_size;
-       pd->port_rcvegrbuf = kmalloc_array(chunk, sizeof(pd->port_rcvegrbuf[0]),
-                                          GFP_KERNEL);
-       if (!pd->port_rcvegrbuf) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-       pd->port_rcvegrbuf_phys =
-               kmalloc_array(chunk, sizeof(pd->port_rcvegrbuf_phys[0]),
-                             GFP_KERNEL);
-       if (!pd->port_rcvegrbuf_phys) {
-               ret = -ENOMEM;
-               goto bail_rcvegrbuf;
-       }
-       for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {
-
-               pd->port_rcvegrbuf[e] = dma_alloc_coherent(
-                       &dd->pcidev->dev, size, &pd->port_rcvegrbuf_phys[e],
-                       gfp_flags);
-
-               if (!pd->port_rcvegrbuf[e]) {
-                       ret = -ENOMEM;
-                       goto bail_rcvegrbuf_phys;
-               }
-       }
-
-       pd->port_rcvegr_phys = pd->port_rcvegrbuf_phys[0];
-
-       for (e = chunk = 0; chunk < pd->port_rcvegrbuf_chunks; chunk++) {
-               dma_addr_t pa = pd->port_rcvegrbuf_phys[chunk];
-               unsigned i;
-
-               for (i = 0; e < egrcnt && i < egrperchunk; e++, i++) {
-                       dd->ipath_f_put_tid(dd, e + egroff +
-                                           (u64 __iomem *)
-                                           ((char __iomem *)
-                                            dd->ipath_kregbase +
-                                            dd->ipath_rcvegrbase),
-                                           RCVHQ_RCV_TYPE_EAGER, pa);
-                       pa += egrsize;
-               }
-               cond_resched(); /* don't hog the cpu */
-       }
-
-       ret = 0;
-       goto bail;
-
-bail_rcvegrbuf_phys:
-       for (e = 0; e < pd->port_rcvegrbuf_chunks &&
-               pd->port_rcvegrbuf[e]; e++) {
-               dma_free_coherent(&dd->pcidev->dev, size,
-                                 pd->port_rcvegrbuf[e],
-                                 pd->port_rcvegrbuf_phys[e]);
-
-       }
-       kfree(pd->port_rcvegrbuf_phys);
-       pd->port_rcvegrbuf_phys = NULL;
-bail_rcvegrbuf:
-       kfree(pd->port_rcvegrbuf);
-       pd->port_rcvegrbuf = NULL;
-bail:
-       return ret;
-}
-
-
-/* common code for the mappings on dma_alloc_coherent mem */
-static int ipath_mmap_mem(struct vm_area_struct *vma,
-       struct ipath_portdata *pd, unsigned len, int write_ok,
-       void *kvaddr, char *what)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       unsigned long pfn;
-       int ret;
-
-       if ((vma->vm_end - vma->vm_start) > len) {
-               dev_info(&dd->pcidev->dev,
-                        "FAIL on %s: len %lx > %x\n", what,
-                        vma->vm_end - vma->vm_start, len);
-               ret = -EFAULT;
-               goto bail;
-       }
-
-       if (!write_ok) {
-               if (vma->vm_flags & VM_WRITE) {
-                       dev_info(&dd->pcidev->dev,
-                                "%s must be mapped readonly\n", what);
-                       ret = -EPERM;
-                       goto bail;
-               }
-
-               /* don't allow them to later change with mprotect */
-               vma->vm_flags &= ~VM_MAYWRITE;
-       }
-
-       pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
-       ret = remap_pfn_range(vma, vma->vm_start, pfn,
-                             len, vma->vm_page_prot);
-       if (ret)
-               dev_info(&dd->pcidev->dev, "%s port%u mmap of %lx, %x "
-                        "bytes r%c failed: %d\n", what, pd->port_port,
-                        pfn, len, write_ok?'w':'o', ret);
-       else
-               ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes "
-                          "r%c\n", what, pd->port_port, pfn, len,
-                          write_ok?'w':'o');
-bail:
-       return ret;
-}
-
-static int mmap_ureg(struct vm_area_struct *vma, struct ipath_devdata *dd,
-                    u64 ureg)
-{
-       unsigned long phys;
-       int ret;
-
-       /*
-        * This is real hardware, so use io_remap.  This is the mechanism
-        * for the user process to update the head registers for their port
-        * in the chip.
-        */
-       if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) {
-               dev_info(&dd->pcidev->dev, "FAIL mmap userreg: reqlen "
-                        "%lx > PAGE\n", vma->vm_end - vma->vm_start);
-               ret = -EFAULT;
-       } else {
-               phys = dd->ipath_physaddr + ureg;
-               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
-               vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
-               ret = io_remap_pfn_range(vma, vma->vm_start,
-                                        phys >> PAGE_SHIFT,
-                                        vma->vm_end - vma->vm_start,
-                                        vma->vm_page_prot);
-       }
-       return ret;
-}
-
-static int mmap_piobufs(struct vm_area_struct *vma,
-                       struct ipath_devdata *dd,
-                       struct ipath_portdata *pd,
-                       unsigned piobufs, unsigned piocnt)
-{
-       unsigned long phys;
-       int ret;
-
-       /*
-        * When we map the PIO buffers in the chip, we want to map them as
-        * writeonly, no read possible.   This prevents access to previous
-        * process data, and catches users who might try to read the i/o
-        * space due to a bug.
-        */
-       if ((vma->vm_end - vma->vm_start) > (piocnt * dd->ipath_palign)) {
-               dev_info(&dd->pcidev->dev, "FAIL mmap piobufs: "
-                        "reqlen %lx > PAGE\n",
-                        vma->vm_end - vma->vm_start);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       phys = dd->ipath_physaddr + piobufs;
-
-#if defined(__powerpc__)
-       /* There isn't a generic way to specify writethrough mappings */
-       pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-       pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
-       pgprot_val(vma->vm_page_prot) &= ~_PAGE_GUARDED;
-#endif
-
-       /*
-        * don't allow them to later change to readable with mprotect (for when
-        * not initially mapped readable, as is normally the case)
-        */
-       vma->vm_flags &= ~VM_MAYREAD;
-       vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
-
-       ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
-                                vma->vm_end - vma->vm_start,
-                                vma->vm_page_prot);
-bail:
-       return ret;
-}
-
-static int mmap_rcvegrbufs(struct vm_area_struct *vma,
-                          struct ipath_portdata *pd)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       unsigned long start, size;
-       size_t total_size, i;
-       unsigned long pfn;
-       int ret;
-
-       size = pd->port_rcvegrbuf_size;
-       total_size = pd->port_rcvegrbuf_chunks * size;
-       if ((vma->vm_end - vma->vm_start) > total_size) {
-               dev_info(&dd->pcidev->dev, "FAIL on egr bufs: "
-                        "reqlen %lx > actual %lx\n",
-                        vma->vm_end - vma->vm_start,
-                        (unsigned long) total_size);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       if (vma->vm_flags & VM_WRITE) {
-               dev_info(&dd->pcidev->dev, "Can't map eager buffers as "
-                        "writable (flags=%lx)\n", vma->vm_flags);
-               ret = -EPERM;
-               goto bail;
-       }
-       /* don't allow them to later change to writeable with mprotect */
-       vma->vm_flags &= ~VM_MAYWRITE;
-
-       start = vma->vm_start;
-
-       for (i = 0; i < pd->port_rcvegrbuf_chunks; i++, start += size) {
-               pfn = virt_to_phys(pd->port_rcvegrbuf[i]) >> PAGE_SHIFT;
-               ret = remap_pfn_range(vma, start, pfn, size,
-                                     vma->vm_page_prot);
-               if (ret < 0)
-                       goto bail;
-       }
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/*
- * ipath_file_vma_fault - handle a VMA page fault.
- */
-static int ipath_file_vma_fault(struct vm_area_struct *vma,
-                                       struct vm_fault *vmf)
-{
-       struct page *page;
-
-       page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
-       if (!page)
-               return VM_FAULT_SIGBUS;
-       get_page(page);
-       vmf->page = page;
-
-       return 0;
-}
-
-static const struct vm_operations_struct ipath_file_vm_ops = {
-       .fault = ipath_file_vma_fault,
-};
-
-static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
-                      struct ipath_portdata *pd, unsigned subport)
-{
-       unsigned long len;
-       struct ipath_devdata *dd;
-       void *addr;
-       size_t size;
-       int ret = 0;
-
-       /* If the port is not shared, all addresses should be physical */
-       if (!pd->port_subport_cnt)
-               goto bail;
-
-       dd = pd->port_dd;
-       size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
-
-       /*
-        * Each process has all the subport uregbase, rcvhdrq, and
-        * rcvegrbufs mmapped - as an array for all the processes,
-        * and also separately for this process.
-        */
-       if (pgaddr == cvt_kvaddr(pd->subport_uregbase)) {
-               addr = pd->subport_uregbase;
-               size = PAGE_SIZE * pd->port_subport_cnt;
-       } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base)) {
-               addr = pd->subport_rcvhdr_base;
-               size = pd->port_rcvhdrq_size * pd->port_subport_cnt;
-       } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf)) {
-               addr = pd->subport_rcvegrbuf;
-               size *= pd->port_subport_cnt;
-        } else if (pgaddr == cvt_kvaddr(pd->subport_uregbase +
-                                        PAGE_SIZE * subport)) {
-                addr = pd->subport_uregbase + PAGE_SIZE * subport;
-                size = PAGE_SIZE;
-        } else if (pgaddr == cvt_kvaddr(pd->subport_rcvhdr_base +
-                                pd->port_rcvhdrq_size * subport)) {
-                addr = pd->subport_rcvhdr_base +
-                        pd->port_rcvhdrq_size * subport;
-                size = pd->port_rcvhdrq_size;
-        } else if (pgaddr == cvt_kvaddr(pd->subport_rcvegrbuf +
-                               size * subport)) {
-                addr = pd->subport_rcvegrbuf + size * subport;
-                /* rcvegrbufs are read-only on the slave */
-                if (vma->vm_flags & VM_WRITE) {
-                        dev_info(&dd->pcidev->dev,
-                                 "Can't map eager buffers as "
-                                 "writable (flags=%lx)\n", vma->vm_flags);
-                        ret = -EPERM;
-                        goto bail;
-                }
-                /*
-                 * Don't allow permission to later change to writeable
-                 * with mprotect.
-                 */
-                vma->vm_flags &= ~VM_MAYWRITE;
-       } else {
-               goto bail;
-       }
-       len = vma->vm_end - vma->vm_start;
-       if (len > size) {
-               ipath_cdbg(MM, "FAIL: reqlen %lx > %zx\n", len, size);
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
-       vma->vm_ops = &ipath_file_vm_ops;
-       vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_mmap - mmap various structures into user space
- * @fp: the file pointer
- * @vma: the VM area
- *
- * We use this to have a shared buffer between the kernel and the user code
- * for the rcvhdr queue, egr buffers, and the per-port user regs and pio
- * buffers in the chip.  We have the open and close entries so we can bump
- * the ref count and keep the driver from being unloaded while still mapped.
- */
-static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
-{
-       struct ipath_portdata *pd;
-       struct ipath_devdata *dd;
-       u64 pgaddr, ureg;
-       unsigned piobufs, piocnt;
-       int ret;
-
-       pd = port_fp(fp);
-       if (!pd) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       dd = pd->port_dd;
-
-       /*
-        * This is the ipath_do_user_init() code, mapping the shared buffers
-        * into the user process. The address referred to by vm_pgoff is the
-        * file offset passed via mmap().  For shared ports, this is the
-        * kernel vmalloc() address of the pages to share with the master.
-        * For non-shared or master ports, this is a physical address.
-        * We only do one mmap for each space mapped.
-        */
-       pgaddr = vma->vm_pgoff << PAGE_SHIFT;
-
-       /*
-        * Check for 0 in case one of the allocations failed, but user
-        * called mmap anyway.
-        */
-       if (!pgaddr)  {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       ipath_cdbg(MM, "pgaddr %llx vm_start=%lx len %lx port %u:%u:%u\n",
-                  (unsigned long long) pgaddr, vma->vm_start,
-                  vma->vm_end - vma->vm_start, dd->ipath_unit,
-                  pd->port_port, subport_fp(fp));
-
-       /*
-        * Physical addresses must fit in 40 bits for our hardware.
-        * Check for kernel virtual addresses first, anything else must
-        * match a HW or memory address.
-        */
-       ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
-       if (ret) {
-               if (ret > 0)
-                       ret = 0;
-               goto bail;
-       }
-
-       ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
-       if (!pd->port_subport_cnt) {
-               /* port is not shared */
-               piocnt = pd->port_piocnt;
-               piobufs = pd->port_piobufs;
-       } else if (!subport_fp(fp)) {
-               /* caller is the master */
-               piocnt = (pd->port_piocnt / pd->port_subport_cnt) +
-                        (pd->port_piocnt % pd->port_subport_cnt);
-               piobufs = pd->port_piobufs +
-                       dd->ipath_palign * (pd->port_piocnt - piocnt);
-       } else {
-               unsigned slave = subport_fp(fp) - 1;
-
-               /* caller is a slave */
-               piocnt = pd->port_piocnt / pd->port_subport_cnt;
-               piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
-       }
-
-       if (pgaddr == ureg)
-               ret = mmap_ureg(vma, dd, ureg);
-       else if (pgaddr == piobufs)
-               ret = mmap_piobufs(vma, dd, pd, piobufs, piocnt);
-       else if (pgaddr == dd->ipath_pioavailregs_phys)
-               /* in-memory copy of pioavail registers */
-               ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
-                                    (void *) dd->ipath_pioavailregs_dma,
-                                    "pioavail registers");
-       else if (pgaddr == pd->port_rcvegr_phys)
-               ret = mmap_rcvegrbufs(vma, pd);
-       else if (pgaddr == (u64) pd->port_rcvhdrq_phys)
-               /*
-                * The rcvhdrq itself; readonly except on HT (so have
-                * to allow writable mapping), multiple pages, contiguous
-                * from an i/o perspective.
-                */
-               ret = ipath_mmap_mem(vma, pd, pd->port_rcvhdrq_size, 1,
-                                    pd->port_rcvhdrq,
-                                    "rcvhdrq");
-       else if (pgaddr == (u64) pd->port_rcvhdrqtailaddr_phys)
-               /* in-memory copy of rcvhdrq tail register */
-               ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
-                                    pd->port_rcvhdrtail_kvaddr,
-                                    "rcvhdrq tail");
-       else
-               ret = -EINVAL;
-
-       vma->vm_private_data = NULL;
-
-       if (ret < 0)
-               dev_info(&dd->pcidev->dev,
-                        "Failure %d on off %llx len %lx\n",
-                        -ret, (unsigned long long)pgaddr,
-                        vma->vm_end - vma->vm_start);
-bail:
-       return ret;
-}
-
-static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
-{
-       unsigned pollflag = 0;
-
-       if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
-           pd->port_hdrqfull != pd->port_hdrqfull_poll) {
-               pollflag |= POLLIN | POLLRDNORM;
-               pd->port_hdrqfull_poll = pd->port_hdrqfull;
-       }
-
-       return pollflag;
-}
-
-static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
-                                     struct file *fp,
-                                     struct poll_table_struct *pt)
-{
-       unsigned pollflag = 0;
-       struct ipath_devdata *dd;
-
-       dd = pd->port_dd;
-
-       /* variable access in ipath_poll_hdrqfull() needs this */
-       rmb();
-       pollflag = ipath_poll_hdrqfull(pd);
-
-       if (pd->port_urgent != pd->port_urgent_poll) {
-               pollflag |= POLLIN | POLLRDNORM;
-               pd->port_urgent_poll = pd->port_urgent;
-       }
-
-       if (!pollflag) {
-               /* this saves a spin_lock/unlock in interrupt handler... */
-               set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
-               /* flush waiting flag so don't miss an event... */
-               wmb();
-               poll_wait(fp, &pd->port_wait, pt);
-       }
-
-       return pollflag;
-}
-
-static unsigned int ipath_poll_next(struct ipath_portdata *pd,
-                                   struct file *fp,
-                                   struct poll_table_struct *pt)
-{
-       u32 head;
-       u32 tail;
-       unsigned pollflag = 0;
-       struct ipath_devdata *dd;
-
-       dd = pd->port_dd;
-
-       /* variable access in ipath_poll_hdrqfull() needs this */
-       rmb();
-       pollflag = ipath_poll_hdrqfull(pd);
-
-       head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
-       if (pd->port_rcvhdrtail_kvaddr)
-               tail = ipath_get_rcvhdrtail(pd);
-       else
-               tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
-
-       if (head != tail)
-               pollflag |= POLLIN | POLLRDNORM;
-       else {
-               /* this saves a spin_lock/unlock in interrupt handler */
-               set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
-               /* flush waiting flag so we don't miss an event */
-               wmb();
-
-               set_bit(pd->port_port + dd->ipath_r_intravail_shift,
-                       &dd->ipath_rcvctrl);
-
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                                dd->ipath_rcvctrl);
-
-               if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
-                       ipath_write_ureg(dd, ur_rcvhdrhead,
-                                        dd->ipath_rhdrhead_intr_off | head,
-                                        pd->port_port);
-
-               poll_wait(fp, &pd->port_wait, pt);
-       }
-
-       return pollflag;
-}
-
-static unsigned int ipath_poll(struct file *fp,
-                              struct poll_table_struct *pt)
-{
-       struct ipath_portdata *pd;
-       unsigned pollflag;
-
-       pd = port_fp(fp);
-       if (!pd)
-               pollflag = 0;
-       else if (pd->poll_type & IPATH_POLL_TYPE_URGENT)
-               pollflag = ipath_poll_urgent(pd, fp, pt);
-       else
-               pollflag = ipath_poll_next(pd, fp, pt);
-
-       return pollflag;
-}
-
-static int ipath_supports_subports(int user_swmajor, int user_swminor)
-{
-       /* no subport implementation prior to software version 1.3 */
-       return (user_swmajor > 1) || (user_swminor >= 3);
-}
-
-static int ipath_compatible_subports(int user_swmajor, int user_swminor)
-{
-       /* this code is written long-hand for clarity */
-       if (IPATH_USER_SWMAJOR != user_swmajor) {
-               /* no promise of compatibility if major mismatch */
-               return 0;
-       }
-       if (IPATH_USER_SWMAJOR == 1) {
-               switch (IPATH_USER_SWMINOR) {
-               case 0:
-               case 1:
-               case 2:
-                       /* no subport implementation so cannot be compatible */
-                       return 0;
-               case 3:
-                       /* 3 is only compatible with itself */
-                       return user_swminor == 3;
-               default:
-                       /* >= 4 are compatible (or are expected to be) */
-                       return user_swminor >= 4;
-               }
-       }
-       /* make no promises yet for future major versions */
-       return 0;
-}
-
-static int init_subports(struct ipath_devdata *dd,
-                        struct ipath_portdata *pd,
-                        const struct ipath_user_info *uinfo)
-{
-       int ret = 0;
-       unsigned num_subports;
-       size_t size;
-
-       /*
-        * If the user is requesting zero subports,
-        * skip the subport allocation.
-        */
-       if (uinfo->spu_subport_cnt <= 0)
-               goto bail;
-
-       /* Self-consistency check for ipath_compatible_subports() */
-       if (ipath_supports_subports(IPATH_USER_SWMAJOR, IPATH_USER_SWMINOR) &&
-           !ipath_compatible_subports(IPATH_USER_SWMAJOR,
-                                      IPATH_USER_SWMINOR)) {
-               dev_info(&dd->pcidev->dev,
-                        "Inconsistent ipath_compatible_subports()\n");
-               goto bail;
-       }
-
-       /* Check for subport compatibility */
-       if (!ipath_compatible_subports(uinfo->spu_userversion >> 16,
-                                      uinfo->spu_userversion & 0xffff)) {
-               dev_info(&dd->pcidev->dev,
-                        "Mismatched user version (%d.%d) and driver "
-                        "version (%d.%d) while port sharing. Ensure "
-                         "that driver and library are from the same "
-                         "release.\n",
-                        (int) (uinfo->spu_userversion >> 16),
-                         (int) (uinfo->spu_userversion & 0xffff),
-                        IPATH_USER_SWMAJOR,
-                        IPATH_USER_SWMINOR);
-               goto bail;
-       }
-       if (uinfo->spu_subport_cnt > INFINIPATH_MAX_SUBPORT) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       num_subports = uinfo->spu_subport_cnt;
-       pd->subport_uregbase = vzalloc(PAGE_SIZE * num_subports);
-       if (!pd->subport_uregbase) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-       /* Note: pd->port_rcvhdrq_size isn't initialized yet. */
-       size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
-                    sizeof(u32), PAGE_SIZE) * num_subports;
-       pd->subport_rcvhdr_base = vzalloc(size);
-       if (!pd->subport_rcvhdr_base) {
-               ret = -ENOMEM;
-               goto bail_ureg;
-       }
-
-       pd->subport_rcvegrbuf = vzalloc(pd->port_rcvegrbuf_chunks *
-                                       pd->port_rcvegrbuf_size *
-                                       num_subports);
-       if (!pd->subport_rcvegrbuf) {
-               ret = -ENOMEM;
-               goto bail_rhdr;
-       }
-
-       pd->port_subport_cnt = uinfo->spu_subport_cnt;
-       pd->port_subport_id = uinfo->spu_subport_id;
-       pd->active_slaves = 1;
-       set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag);
-       goto bail;
-
-bail_rhdr:
-       vfree(pd->subport_rcvhdr_base);
-bail_ureg:
-       vfree(pd->subport_uregbase);
-       pd->subport_uregbase = NULL;
-bail:
-       return ret;
-}
-
-static int try_alloc_port(struct ipath_devdata *dd, int port,
-                         struct file *fp,
-                         const struct ipath_user_info *uinfo)
-{
-       struct ipath_portdata *pd;
-       int ret;
-
-       if (!(pd = dd->ipath_pd[port])) {
-               void *ptmp;
-
-               pd = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
-
-               /*
-                * Allocate memory for use in ipath_tid_update() just once
-                * at open, not per call.  Reduces cost of expected send
-                * setup.
-                */
-               ptmp = kmalloc(dd->ipath_rcvtidcnt * sizeof(u16) +
-                              dd->ipath_rcvtidcnt * sizeof(struct page **),
-                              GFP_KERNEL);
-               if (!pd || !ptmp) {
-                       ipath_dev_err(dd, "Unable to allocate portdata "
-                                     "memory, failing open\n");
-                       ret = -ENOMEM;
-                       kfree(pd);
-                       kfree(ptmp);
-                       goto bail;
-               }
-               dd->ipath_pd[port] = pd;
-               dd->ipath_pd[port]->port_port = port;
-               dd->ipath_pd[port]->port_dd = dd;
-               dd->ipath_pd[port]->port_tid_pg_list = ptmp;
-               init_waitqueue_head(&dd->ipath_pd[port]->port_wait);
-       }
-       if (!pd->port_cnt) {
-               pd->userversion = uinfo->spu_userversion;
-               init_user_egr_sizes(pd);
-               if ((ret = init_subports(dd, pd, uinfo)) != 0)
-                       goto bail;
-               ipath_cdbg(PROC, "%s[%u] opened unit:port %u:%u\n",
-                          current->comm, current->pid, dd->ipath_unit,
-                          port);
-               pd->port_cnt = 1;
-               port_fp(fp) = pd;
-               pd->port_pid = get_pid(task_pid(current));
-               strlcpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
-               ipath_stats.sps_ports++;
-               ret = 0;
-       } else
-               ret = -EBUSY;
-
-bail:
-       return ret;
-}
-
-static inline int usable(struct ipath_devdata *dd)
-{
-       return dd &&
-               (dd->ipath_flags & IPATH_PRESENT) &&
-               dd->ipath_kregbase &&
-               dd->ipath_lid &&
-               !(dd->ipath_flags & (IPATH_LINKDOWN | IPATH_DISABLED
-                                    | IPATH_LINKUNK));
-}
-
-static int find_free_port(int unit, struct file *fp,
-                         const struct ipath_user_info *uinfo)
-{
-       struct ipath_devdata *dd = ipath_lookup(unit);
-       int ret, i;
-
-       if (!dd) {
-               ret = -ENODEV;
-               goto bail;
-       }
-
-       if (!usable(dd)) {
-               ret = -ENETDOWN;
-               goto bail;
-       }
-
-       for (i = 1; i < dd->ipath_cfgports; i++) {
-               ret = try_alloc_port(dd, i, fp, uinfo);
-               if (ret != -EBUSY)
-                       goto bail;
-       }
-       ret = -EBUSY;
-
-bail:
-       return ret;
-}
-
-static int find_best_unit(struct file *fp,
-                         const struct ipath_user_info *uinfo)
-{
-       int ret = 0, i, prefunit = -1, devmax;
-       int maxofallports, npresent, nup;
-       int ndev;
-
-       devmax = ipath_count_units(&npresent, &nup, &maxofallports);
-
-       /*
-        * This code is present to allow a knowledgeable person to
-        * specify the layout of processes to processors before opening
-        * this driver, and then we'll assign the process to the "closest"
-        * InfiniPath chip to that processor (we assume reasonable connectivity,
-        * for now).  This code assumes that if affinity has been set
-        * before this point, that at most one cpu is set; for now this
-        * is reasonable.  I check for both cpumask_empty() and cpumask_full(),
-        * in case some kernel variant sets none of the bits when no
-        * affinity is set.  2.6.11 and 12 kernels have all present
-        * cpus set.  Some day we'll have to fix it up further to handle
-        * a cpu subset.  This algorithm fails for two HT chips connected
-        * in tunnel fashion.  Eventually this needs real topology
-        * information.  There may be some issues with dual core numbering
-        * as well.  This needs more work prior to release.
-        */
-       if (!cpumask_empty(tsk_cpus_allowed(current)) &&
-           !cpumask_full(tsk_cpus_allowed(current))) {
-               int ncpus = num_online_cpus(), curcpu = -1, nset = 0;
-               get_online_cpus();
-               for_each_online_cpu(i)
-                       if (cpumask_test_cpu(i, tsk_cpus_allowed(current))) {
-                               ipath_cdbg(PROC, "%s[%u] affinity set for "
-                                          "cpu %d/%d\n", current->comm,
-                                          current->pid, i, ncpus);
-                               curcpu = i;
-                               nset++;
-                       }
-               put_online_cpus();
-               if (curcpu != -1 && nset != ncpus) {
-                       if (npresent) {
-                               prefunit = curcpu / (ncpus / npresent);
-                               ipath_cdbg(PROC,"%s[%u] %d chips, %d cpus, "
-                                         "%d cpus/chip, select unit %d\n",
-                                         current->comm, current->pid,
-                                         npresent, ncpus, ncpus / npresent,
-                                         prefunit);
-                       }
-               }
-       }
-
-       /*
-        * user ports start at 1, kernel port is 0
-        * For now, we do round-robin access across all chips
-        */
-
-       if (prefunit != -1)
-               devmax = prefunit + 1;
-recheck:
-       for (i = 1; i < maxofallports; i++) {
-               for (ndev = prefunit != -1 ? prefunit : 0; ndev < devmax;
-                    ndev++) {
-                       struct ipath_devdata *dd = ipath_lookup(ndev);
-
-                       if (!usable(dd))
-                               continue; /* can't use this unit */
-                       if (i >= dd->ipath_cfgports)
-                               /*
-                                * Maxed out on users of this unit. Try
-                                * next.
-                                */
-                               continue;
-                       ret = try_alloc_port(dd, i, fp, uinfo);
-                       if (!ret)
-                               goto done;
-               }
-       }
-
-       if (npresent) {
-               if (nup == 0) {
-                       ret = -ENETDOWN;
-                       ipath_dbg("No ports available (none initialized "
-                                 "and ready)\n");
-               } else {
-                       if (prefunit > 0) {
-                               /* if started above 0, retry from 0 */
-                               ipath_cdbg(PROC,
-                                          "%s[%u] no ports on prefunit "
-                                          "%d, clear and re-check\n",
-                                          current->comm, current->pid,
-                                          prefunit);
-                               devmax = ipath_count_units(NULL, NULL,
-                                                          NULL);
-                               prefunit = -1;
-                               goto recheck;
-                       }
-                       ret = -EBUSY;
-                       ipath_dbg("No ports available\n");
-               }
-       } else {
-               ret = -ENXIO;
-               ipath_dbg("No boards found\n");
-       }
-
-done:
-       return ret;
-}
-
-static int find_shared_port(struct file *fp,
-                           const struct ipath_user_info *uinfo)
-{
-       int devmax, ndev, i;
-       int ret = 0;
-
-       devmax = ipath_count_units(NULL, NULL, NULL);
-
-       for (ndev = 0; ndev < devmax; ndev++) {
-               struct ipath_devdata *dd = ipath_lookup(ndev);
-
-               if (!usable(dd))
-                       continue;
-               for (i = 1; i < dd->ipath_cfgports; i++) {
-                       struct ipath_portdata *pd = dd->ipath_pd[i];
-
-                       /* Skip ports which are not yet open */
-                       if (!pd || !pd->port_cnt)
-                               continue;
-                       /* Skip port if it doesn't match the requested one */
-                       if (pd->port_subport_id != uinfo->spu_subport_id)
-                               continue;
-                       /* Verify the sharing process matches the master */
-                       if (pd->port_subport_cnt != uinfo->spu_subport_cnt ||
-                           pd->userversion != uinfo->spu_userversion ||
-                           pd->port_cnt >= pd->port_subport_cnt) {
-                               ret = -EINVAL;
-                               goto done;
-                       }
-                       port_fp(fp) = pd;
-                       subport_fp(fp) = pd->port_cnt++;
-                       pd->port_subpid[subport_fp(fp)] =
-                               get_pid(task_pid(current));
-                       tidcursor_fp(fp) = 0;
-                       pd->active_slaves |= 1 << subport_fp(fp);
-                       ipath_cdbg(PROC,
-                                  "%s[%u] %u sharing %s[%u] unit:port %u:%u\n",
-                                  current->comm, current->pid,
-                                  subport_fp(fp),
-                                  pd->port_comm, pid_nr(pd->port_pid),
-                                  dd->ipath_unit, pd->port_port);
-                       ret = 1;
-                       goto done;
-               }
-       }
-
-done:
-       return ret;
-}
-
-static int ipath_open(struct inode *in, struct file *fp)
-{
-       /* The real work is performed later in ipath_assign_port() */
-       fp->private_data = kzalloc(sizeof(struct ipath_filedata), GFP_KERNEL);
-       return fp->private_data ? 0 : -ENOMEM;
-}
-
-/* Get port early, so can set affinity prior to memory allocation */
-static int ipath_assign_port(struct file *fp,
-                             const struct ipath_user_info *uinfo)
-{
-       int ret;
-       int i_minor;
-       unsigned swmajor, swminor;
-
-       /* Check to be sure we haven't already initialized this file */
-       if (port_fp(fp)) {
-               ret = -EINVAL;
-               goto done;
-       }
-
-       /* for now, if major version is different, bail */
-       swmajor = uinfo->spu_userversion >> 16;
-       if (swmajor != IPATH_USER_SWMAJOR) {
-               ipath_dbg("User major version %d not same as driver "
-                         "major %d\n", uinfo->spu_userversion >> 16,
-                         IPATH_USER_SWMAJOR);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       swminor = uinfo->spu_userversion & 0xffff;
-       if (swminor != IPATH_USER_SWMINOR)
-               ipath_dbg("User minor version %d not same as driver "
-                         "minor %d\n", swminor, IPATH_USER_SWMINOR);
-
-       mutex_lock(&ipath_mutex);
-
-       if (ipath_compatible_subports(swmajor, swminor) &&
-           uinfo->spu_subport_cnt &&
-           (ret = find_shared_port(fp, uinfo))) {
-               if (ret > 0)
-                       ret = 0;
-               goto done_chk_sdma;
-       }
-
-       i_minor = iminor(file_inode(fp)) - IPATH_USER_MINOR_BASE;
-       ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
-                  (long)file_inode(fp)->i_rdev, i_minor);
-
-       if (i_minor)
-               ret = find_free_port(i_minor - 1, fp, uinfo);
-       else
-               ret = find_best_unit(fp, uinfo);
-
-done_chk_sdma:
-       if (!ret) {
-               struct ipath_filedata *fd = fp->private_data;
-               const struct ipath_portdata *pd = fd->pd;
-               const struct ipath_devdata *dd = pd->port_dd;
-
-               fd->pq = ipath_user_sdma_queue_create(&dd->pcidev->dev,
-                                                     dd->ipath_unit,
-                                                     pd->port_port,
-                                                     fd->subport);
-
-               if (!fd->pq)
-                       ret = -ENOMEM;
-       }
-
-       mutex_unlock(&ipath_mutex);
-
-done:
-       return ret;
-}
-
-
-static int ipath_do_user_init(struct file *fp,
-                             const struct ipath_user_info *uinfo)
-{
-       int ret;
-       struct ipath_portdata *pd = port_fp(fp);
-       struct ipath_devdata *dd;
-       u32 head32;
-
-       /* Subports don't need to initialize anything since master did it. */
-       if (subport_fp(fp)) {
-               ret = wait_event_interruptible(pd->port_wait,
-                       !test_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag));
-               goto done;
-       }
-
-       dd = pd->port_dd;
-
-       if (uinfo->spu_rcvhdrsize) {
-               ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
-               if (ret)
-                       goto done;
-       }
-
-       /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
-
-       /* some ports may get extra buffers, calculate that here */
-       if (pd->port_port <= dd->ipath_ports_extrabuf)
-               pd->port_piocnt = dd->ipath_pbufsport + 1;
-       else
-               pd->port_piocnt = dd->ipath_pbufsport;
-
-       /* for right now, kernel piobufs are at end, so port 1 is at 0 */
-       if (pd->port_port <= dd->ipath_ports_extrabuf)
-               pd->port_pio_base = (dd->ipath_pbufsport + 1)
-                       * (pd->port_port - 1);
-       else
-               pd->port_pio_base = dd->ipath_ports_extrabuf +
-                       dd->ipath_pbufsport * (pd->port_port - 1);
-       pd->port_piobufs = dd->ipath_piobufbase +
-               pd->port_pio_base * dd->ipath_palign;
-       ipath_cdbg(VERBOSE, "piobuf base for port %u is 0x%x, piocnt %u,"
-               " first pio %u\n", pd->port_port, pd->port_piobufs,
-               pd->port_piocnt, pd->port_pio_base);
-       ipath_chg_pioavailkernel(dd, pd->port_pio_base, pd->port_piocnt, 0);
-
-       /*
-        * Now allocate the rcvhdr Q and eager TIDs; skip the TID
-        * array for time being.  If pd->port_port > chip-supported,
-        * we need to do extra stuff here to handle by handling overflow
-        * through port 0, someday
-        */
-       ret = ipath_create_rcvhdrq(dd, pd);
-       if (!ret)
-               ret = ipath_create_user_egr(pd);
-       if (ret)
-               goto done;
-
-       /*
-        * set the eager head register for this port to the current values
-        * of the tail pointers, since we don't know if they were
-        * updated on last use of the port.
-        */
-       head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
-       ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
-       pd->port_lastrcvhdrqtail = -1;
-       ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
-               pd->port_port, head32);
-       pd->port_tidcursor = 0; /* start at beginning after open */
-
-       /* initialize poll variables... */
-       pd->port_urgent = 0;
-       pd->port_urgent_poll = 0;
-       pd->port_hdrqfull_poll = pd->port_hdrqfull;
-
-       /*
-        * Now enable the port for receive.
-        * For chips that are set to DMA the tail register to memory
-        * when they change (and when the update bit transitions from
-        * 0 to 1.  So for those chips, we turn it off and then back on.
-        * This will (very briefly) affect any other open ports, but the
-        * duration is very short, and therefore isn't an issue.  We
-        * explicitly set the in-memory tail copy to 0 beforehand, so we
-        * don't have to wait to be sure the DMA update has happened
-        * (chip resets head/tail to 0 on transition to enable).
-        */
-       set_bit(dd->ipath_r_portenable_shift + pd->port_port,
-               &dd->ipath_rcvctrl);
-       if (!(dd->ipath_flags & IPATH_NODMA_RTAIL)) {
-               if (pd->port_rcvhdrtail_kvaddr)
-                       ipath_clear_rcvhdrtail(pd);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                       dd->ipath_rcvctrl &
-                       ~(1ULL << dd->ipath_r_tailupd_shift));
-       }
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-       /* Notify any waiting slaves */
-       if (pd->port_subport_cnt) {
-               clear_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag);
-               wake_up(&pd->port_wait);
-       }
-done:
-       return ret;
-}
-
-/**
- * unlock_exptid - unlock any expected TID entries port still had in use
- * @pd: port
- *
- * We don't actually update the chip here, because we do a bulk update
- * below, using ipath_f_clear_tids.
- */
-static void unlock_expected_tids(struct ipath_portdata *pd)
-{
-       struct ipath_devdata *dd = pd->port_dd;
-       int port_tidbase = pd->port_port * dd->ipath_rcvtidcnt;
-       int i, cnt = 0, maxtid = port_tidbase + dd->ipath_rcvtidcnt;
-
-       ipath_cdbg(VERBOSE, "Port %u unlocking any locked expTID pages\n",
-                  pd->port_port);
-       for (i = port_tidbase; i < maxtid; i++) {
-               struct page *ps = dd->ipath_pageshadow[i];
-
-               if (!ps)
-                       continue;
-
-               dd->ipath_pageshadow[i] = NULL;
-               pci_unmap_page(dd->pcidev, dd->ipath_physshadow[i],
-                       PAGE_SIZE, PCI_DMA_FROMDEVICE);
-               ipath_release_user_pages_on_close(&ps, 1);
-               cnt++;
-               ipath_stats.sps_pageunlocks++;
-       }
-       if (cnt)
-               ipath_cdbg(VERBOSE, "Port %u locked %u expTID entries\n",
-                          pd->port_port, cnt);
-
-       if (ipath_stats.sps_pagelocks || ipath_stats.sps_pageunlocks)
-               ipath_cdbg(VERBOSE, "%llu pages locked, %llu unlocked\n",
-                          (unsigned long long) ipath_stats.sps_pagelocks,
-                          (unsigned long long)
-                          ipath_stats.sps_pageunlocks);
-}
-
-static int ipath_close(struct inode *in, struct file *fp)
-{
-       struct ipath_filedata *fd;
-       struct ipath_portdata *pd;
-       struct ipath_devdata *dd;
-       unsigned long flags;
-       unsigned port;
-       struct pid *pid;
-
-       ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n",
-                  (long)in->i_rdev, fp->private_data);
-
-       mutex_lock(&ipath_mutex);
-
-       fd = fp->private_data;
-       fp->private_data = NULL;
-       pd = fd->pd;
-       if (!pd) {
-               mutex_unlock(&ipath_mutex);
-               goto bail;
-       }
-
-       dd = pd->port_dd;
-
-       /* drain user sdma queue */
-       ipath_user_sdma_queue_drain(dd, fd->pq);
-       ipath_user_sdma_queue_destroy(fd->pq);
-
-       if (--pd->port_cnt) {
-               /*
-                * XXX If the master closes the port before the slave(s),
-                * revoke the mmap for the eager receive queue so
-                * the slave(s) don't wait for receive data forever.
-                */
-               pd->active_slaves &= ~(1 << fd->subport);
-               put_pid(pd->port_subpid[fd->subport]);
-               pd->port_subpid[fd->subport] = NULL;
-               mutex_unlock(&ipath_mutex);
-               goto bail;
-       }
-       /* early; no interrupt users after this */
-       spin_lock_irqsave(&dd->ipath_uctxt_lock, flags);
-       port = pd->port_port;
-       dd->ipath_pd[port] = NULL;
-       pid = pd->port_pid;
-       pd->port_pid = NULL;
-       spin_unlock_irqrestore(&dd->ipath_uctxt_lock, flags);
-
-       if (pd->port_rcvwait_to || pd->port_piowait_to
-           || pd->port_rcvnowait || pd->port_pionowait) {
-               ipath_cdbg(VERBOSE, "port%u, %u rcv, %u pio wait timeo; "
-                          "%u rcv %u, pio already\n",
-                          pd->port_port, pd->port_rcvwait_to,
-                          pd->port_piowait_to, pd->port_rcvnowait,
-                          pd->port_pionowait);
-               pd->port_rcvwait_to = pd->port_piowait_to =
-                       pd->port_rcvnowait = pd->port_pionowait = 0;
-       }
-       if (pd->port_flag) {
-               ipath_cdbg(PROC, "port %u port_flag set: 0x%lx\n",
-                         pd->port_port, pd->port_flag);
-               pd->port_flag = 0;
-       }
-
-       if (dd->ipath_kregbase) {
-               /* atomically clear receive enable port and intr avail. */
-               clear_bit(dd->ipath_r_portenable_shift + port,
-                         &dd->ipath_rcvctrl);
-               clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
-                         &dd->ipath_rcvctrl);
-               ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
-                       dd->ipath_rcvctrl);
-               /* and read back from chip to be sure that nothing
-                * else is in flight when we do the rest */
-               (void)ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-
-               /* clean up the pkeys for this port user */
-               ipath_clean_part_key(pd, dd);
-               /*
-                * be paranoid, and never write 0's to these, just use an
-                * unused part of the port 0 tail page.  Of course,
-                * rcvhdraddr points to a large chunk of memory, so this
-                * could still trash things, but at least it won't trash
-                * page 0, and by disabling the port, it should stop "soon",
-                * even if a packet or two is in already in flight after we
-                * disabled the port.
-                */
-               ipath_write_kreg_port(dd,
-                       dd->ipath_kregs->kr_rcvhdrtailaddr, port,
-                       dd->ipath_dummy_hdrq_phys);
-               ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
-                       pd->port_port, dd->ipath_dummy_hdrq_phys);
-
-               ipath_disarm_piobufs(dd, pd->port_pio_base, pd->port_piocnt);
-               ipath_chg_pioavailkernel(dd, pd->port_pio_base,
-                       pd->port_piocnt, 1);
-
-               dd->ipath_f_clear_tids(dd, pd->port_port);
-
-               if (dd->ipath_pageshadow)
-                       unlock_expected_tids(pd);
-               ipath_stats.sps_ports--;
-               ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
-                          pd->port_comm, pid_nr(pid),
-                          dd->ipath_unit, port);
-       }
-
-       put_pid(pid);
-       mutex_unlock(&ipath_mutex);
-       ipath_free_pddata(dd, pd); /* after releasing the mutex */
-
-bail:
-       kfree(fd);
-       return 0;
-}
-
-static int ipath_port_info(struct ipath_portdata *pd, u16 subport,
-                          struct ipath_port_info __user *uinfo)
-{
-       struct ipath_port_info info;
-       int nup;
-       int ret;
-       size_t sz;
-
-       (void) ipath_count_units(NULL, &nup, NULL);
-       info.num_active = nup;
-       info.unit = pd->port_dd->ipath_unit;
-       info.port = pd->port_port;
-       info.subport = subport;
-       /* Don't return new fields if old library opened the port. */
-       if (ipath_supports_subports(pd->userversion >> 16,
-                                   pd->userversion & 0xffff)) {
-               /* Number of user ports available for this device. */
-               info.num_ports = pd->port_dd->ipath_cfgports - 1;
-               info.num_subports = pd->port_subport_cnt;
-               sz = sizeof(info);
-       } else
-               sz = sizeof(info) - 2 * sizeof(u16);
-
-       if (copy_to_user(uinfo, &info, sz)) {
-               ret = -EFAULT;
-               goto bail;
-       }
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-static int ipath_get_slave_info(struct ipath_portdata *pd,
-                               void __user *slave_mask_addr)
-{
-       int ret = 0;
-
-       if (copy_to_user(slave_mask_addr, &pd->active_slaves, sizeof(u32)))
-               ret = -EFAULT;
-       return ret;
-}
-
-static int ipath_sdma_get_inflight(struct ipath_user_sdma_queue *pq,
-                                  u32 __user *inflightp)
-{
-       const u32 val = ipath_user_sdma_inflight_counter(pq);
-
-       if (put_user(val, inflightp))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int ipath_sdma_get_complete(struct ipath_devdata *dd,
-                                  struct ipath_user_sdma_queue *pq,
-                                  u32 __user *completep)
-{
-       u32 val;
-       int err;
-
-       err = ipath_user_sdma_make_progress(dd, pq);
-       if (err < 0)
-               return err;
-
-       val = ipath_user_sdma_complete_counter(pq);
-       if (put_user(val, completep))
-               return -EFAULT;
-
-       return 0;
-}
-
-static ssize_t ipath_write(struct file *fp, const char __user *data,
-                          size_t count, loff_t *off)
-{
-       const struct ipath_cmd __user *ucmd;
-       struct ipath_portdata *pd;
-       const void __user *src;
-       size_t consumed, copy;
-       struct ipath_cmd cmd;
-       ssize_t ret = 0;
-       void *dest;
-
-       if (count < sizeof(cmd.type)) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       ucmd = (const struct ipath_cmd __user *) data;
-
-       if (copy_from_user(&cmd.type, &ucmd->type, sizeof(cmd.type))) {
-               ret = -EFAULT;
-               goto bail;
-       }
-
-       consumed = sizeof(cmd.type);
-
-       switch (cmd.type) {
-       case IPATH_CMD_ASSIGN_PORT:
-       case __IPATH_CMD_USER_INIT:
-       case IPATH_CMD_USER_INIT:
-               copy = sizeof(cmd.cmd.user_info);
-               dest = &cmd.cmd.user_info;
-               src = &ucmd->cmd.user_info;
-               break;
-       case IPATH_CMD_RECV_CTRL:
-               copy = sizeof(cmd.cmd.recv_ctrl);
-               dest = &cmd.cmd.recv_ctrl;
-               src = &ucmd->cmd.recv_ctrl;
-               break;
-       case IPATH_CMD_PORT_INFO:
-               copy = sizeof(cmd.cmd.port_info);
-               dest = &cmd.cmd.port_info;
-               src = &ucmd->cmd.port_info;
-               break;
-       case IPATH_CMD_TID_UPDATE:
-       case IPATH_CMD_TID_FREE:
-               copy = sizeof(cmd.cmd.tid_info);
-               dest = &cmd.cmd.tid_info;
-               src = &ucmd->cmd.tid_info;
-               break;
-       case IPATH_CMD_SET_PART_KEY:
-               copy = sizeof(cmd.cmd.part_key);
-               dest = &cmd.cmd.part_key;
-               src = &ucmd->cmd.part_key;
-               break;
-       case __IPATH_CMD_SLAVE_INFO:
-               copy = sizeof(cmd.cmd.slave_mask_addr);
-               dest = &cmd.cmd.slave_mask_addr;
-               src = &ucmd->cmd.slave_mask_addr;
-               break;
-       case IPATH_CMD_PIOAVAILUPD:     // force an update of PIOAvail reg
-               copy = 0;
-               src = NULL;
-               dest = NULL;
-               break;
-       case IPATH_CMD_POLL_TYPE:
-               copy = sizeof(cmd.cmd.poll_type);
-               dest = &cmd.cmd.poll_type;
-               src = &ucmd->cmd.poll_type;
-               break;
-       case IPATH_CMD_ARMLAUNCH_CTRL:
-               copy = sizeof(cmd.cmd.armlaunch_ctrl);
-               dest = &cmd.cmd.armlaunch_ctrl;
-               src = &ucmd->cmd.armlaunch_ctrl;
-               break;
-       case IPATH_CMD_SDMA_INFLIGHT:
-               copy = sizeof(cmd.cmd.sdma_inflight);
-               dest = &cmd.cmd.sdma_inflight;
-               src = &ucmd->cmd.sdma_inflight;
-               break;
-       case IPATH_CMD_SDMA_COMPLETE:
-               copy = sizeof(cmd.cmd.sdma_complete);
-               dest = &cmd.cmd.sdma_complete;
-               src = &ucmd->cmd.sdma_complete;
-               break;
-       default:
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       if (copy) {
-               if ((count - consumed) < copy) {
-                       ret = -EINVAL;
-                       goto bail;
-               }
-
-               if (copy_from_user(dest, src, copy)) {
-                       ret = -EFAULT;
-                       goto bail;
-               }
-
-               consumed += copy;
-       }
-
-       pd = port_fp(fp);
-       if (!pd && cmd.type != __IPATH_CMD_USER_INIT &&
-               cmd.type != IPATH_CMD_ASSIGN_PORT) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       switch (cmd.type) {
-       case IPATH_CMD_ASSIGN_PORT:
-               ret = ipath_assign_port(fp, &cmd.cmd.user_info);
-               if (ret)
-                       goto bail;
-               break;
-       case __IPATH_CMD_USER_INIT:
-               /* backwards compatibility, get port first */
-               ret = ipath_assign_port(fp, &cmd.cmd.user_info);
-               if (ret)
-                       goto bail;
-               /* and fall through to current version. */
-       case IPATH_CMD_USER_INIT:
-               ret = ipath_do_user_init(fp, &cmd.cmd.user_info);
-               if (ret)
-                       goto bail;
-               ret = ipath_get_base_info(
-                       fp, (void __user *) (unsigned long)
-                       cmd.cmd.user_info.spu_base_info,
-                       cmd.cmd.user_info.spu_base_info_size);
-               break;
-       case IPATH_CMD_RECV_CTRL:
-               ret = ipath_manage_rcvq(pd, subport_fp(fp), cmd.cmd.recv_ctrl);
-               break;
-       case IPATH_CMD_PORT_INFO:
-               ret = ipath_port_info(pd, subport_fp(fp),
-                                     (struct ipath_port_info __user *)
-                                     (unsigned long) cmd.cmd.port_info);
-               break;
-       case IPATH_CMD_TID_UPDATE:
-               ret = ipath_tid_update(pd, fp, &cmd.cmd.tid_info);
-               break;
-       case IPATH_CMD_TID_FREE:
-               ret = ipath_tid_free(pd, subport_fp(fp), &cmd.cmd.tid_info);
-               break;
-       case IPATH_CMD_SET_PART_KEY:
-               ret = ipath_set_part_key(pd, cmd.cmd.part_key);
-               break;
-       case __IPATH_CMD_SLAVE_INFO:
-               ret = ipath_get_slave_info(pd,
-                                          (void __user *) (unsigned long)
-                                          cmd.cmd.slave_mask_addr);
-               break;
-       case IPATH_CMD_PIOAVAILUPD:
-               ipath_force_pio_avail_update(pd->port_dd);
-               break;
-       case IPATH_CMD_POLL_TYPE:
-               pd->poll_type = cmd.cmd.poll_type;
-               break;
-       case IPATH_CMD_ARMLAUNCH_CTRL:
-               if (cmd.cmd.armlaunch_ctrl)
-                       ipath_enable_armlaunch(pd->port_dd);
-               else
-                       ipath_disable_armlaunch(pd->port_dd);
-               break;
-       case IPATH_CMD_SDMA_INFLIGHT:
-               ret = ipath_sdma_get_inflight(user_sdma_queue_fp(fp),
-                                             (u32 __user *) (unsigned long)
-                                             cmd.cmd.sdma_inflight);
-               break;
-       case IPATH_CMD_SDMA_COMPLETE:
-               ret = ipath_sdma_get_complete(pd->port_dd,
-                                             user_sdma_queue_fp(fp),
-                                             (u32 __user *) (unsigned long)
-                                             cmd.cmd.sdma_complete);
-               break;
-       }
-
-       if (ret >= 0)
-               ret = consumed;
-
-bail:
-       return ret;
-}
-
-static ssize_t ipath_write_iter(struct kiocb *iocb, struct iov_iter *from)
-{
-       struct file *filp = iocb->ki_filp;
-       struct ipath_filedata *fp = filp->private_data;
-       struct ipath_portdata *pd = port_fp(filp);
-       struct ipath_user_sdma_queue *pq = fp->pq;
-
-       if (!iter_is_iovec(from) || !from->nr_segs)
-               return -EINVAL;
-
-       return ipath_user_sdma_writev(pd->port_dd, pq, from->iov, from->nr_segs);
-}
-
-static struct class *ipath_class;
-
-static int init_cdev(int minor, char *name, const struct file_operations *fops,
-                    struct cdev **cdevp, struct device **devp)
-{
-       const dev_t dev = MKDEV(IPATH_MAJOR, minor);
-       struct cdev *cdev = NULL;
-       struct device *device = NULL;
-       int ret;
-
-       cdev = cdev_alloc();
-       if (!cdev) {
-               printk(KERN_ERR IPATH_DRV_NAME
-                      ": Could not allocate cdev for minor %d, %s\n",
-                      minor, name);
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       cdev->owner = THIS_MODULE;
-       cdev->ops = fops;
-       kobject_set_name(&cdev->kobj, name);
-
-       ret = cdev_add(cdev, dev, 1);
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME
-                      ": Could not add cdev for minor %d, %s (err %d)\n",
-                      minor, name, -ret);
-               goto err_cdev;
-       }
-
-       device = device_create(ipath_class, NULL, dev, NULL, name);
-
-       if (IS_ERR(device)) {
-               ret = PTR_ERR(device);
-               printk(KERN_ERR IPATH_DRV_NAME ": Could not create "
-                      "device for minor %d, %s (err %d)\n",
-                      minor, name, -ret);
-               goto err_cdev;
-       }
-
-       goto done;
-
-err_cdev:
-       cdev_del(cdev);
-       cdev = NULL;
-
-done:
-       if (ret >= 0) {
-               *cdevp = cdev;
-               *devp = device;
-       } else {
-               *cdevp = NULL;
-               *devp = NULL;
-       }
-
-       return ret;
-}
-
-int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,
-                   struct cdev **cdevp, struct device **devp)
-{
-       return init_cdev(minor, name, fops, cdevp, devp);
-}
-
-static void cleanup_cdev(struct cdev **cdevp,
-                        struct device **devp)
-{
-       struct device *dev = *devp;
-
-       if (dev) {
-               device_unregister(dev);
-               *devp = NULL;
-       }
-
-       if (*cdevp) {
-               cdev_del(*cdevp);
-               *cdevp = NULL;
-       }
-}
-
-void ipath_cdev_cleanup(struct cdev **cdevp,
-                       struct device **devp)
-{
-       cleanup_cdev(cdevp, devp);
-}
-
-static struct cdev *wildcard_cdev;
-static struct device *wildcard_dev;
-
-static const dev_t dev = MKDEV(IPATH_MAJOR, 0);
-
-static int user_init(void)
-{
-       int ret;
-
-       ret = register_chrdev_region(dev, IPATH_NMINORS, IPATH_DRV_NAME);
-       if (ret < 0) {
-               printk(KERN_ERR IPATH_DRV_NAME ": Could not register "
-                      "chrdev region (err %d)\n", -ret);
-               goto done;
-       }
-
-       ipath_class = class_create(THIS_MODULE, IPATH_DRV_NAME);
-
-       if (IS_ERR(ipath_class)) {
-               ret = PTR_ERR(ipath_class);
-               printk(KERN_ERR IPATH_DRV_NAME ": Could not create "
-                      "device class (err %d)\n", -ret);
-               goto bail;
-       }
-
-       goto done;
-bail:
-       unregister_chrdev_region(dev, IPATH_NMINORS);
-done:
-       return ret;
-}
-
-static void user_cleanup(void)
-{
-       if (ipath_class) {
-               class_destroy(ipath_class);
-               ipath_class = NULL;
-       }
-
-       unregister_chrdev_region(dev, IPATH_NMINORS);
-}
-
-static atomic_t user_count = ATOMIC_INIT(0);
-static atomic_t user_setup = ATOMIC_INIT(0);
-
-int ipath_user_add(struct ipath_devdata *dd)
-{
-       char name[10];
-       int ret;
-
-       if (atomic_inc_return(&user_count) == 1) {
-               ret = user_init();
-               if (ret < 0) {
-                       ipath_dev_err(dd, "Unable to set up user support: "
-                                     "error %d\n", -ret);
-                       goto bail;
-               }
-               ret = init_cdev(0, "ipath", &ipath_file_ops, &wildcard_cdev,
-                               &wildcard_dev);
-               if (ret < 0) {
-                       ipath_dev_err(dd, "Could not create wildcard "
-                                     "minor: error %d\n", -ret);
-                       goto bail_user;
-               }
-
-               atomic_set(&user_setup, 1);
-       }
-
-       snprintf(name, sizeof(name), "ipath%d", dd->ipath_unit);
-
-       ret = init_cdev(dd->ipath_unit + 1, name, &ipath_file_ops,
-                       &dd->user_cdev, &dd->user_dev);
-       if (ret < 0)
-               ipath_dev_err(dd, "Could not create user minor %d, %s\n",
-                             dd->ipath_unit + 1, name);
-
-       goto bail;
-
-bail_user:
-       user_cleanup();
-bail:
-       return ret;
-}
-
-void ipath_user_remove(struct ipath_devdata *dd)
-{
-       cleanup_cdev(&dd->user_cdev, &dd->user_dev);
-
-       if (atomic_dec_return(&user_count) == 0) {
-               if (atomic_read(&user_setup) == 0)
-                       goto bail;
-
-               cleanup_cdev(&wildcard_cdev, &wildcard_dev);
-               user_cleanup();
-
-               atomic_set(&user_setup, 0);
-       }
-bail:
-       return;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_fs.c b/drivers/staging/rdma/ipath/ipath_fs.c
deleted file mode 100644 (file)
index 476fcdf..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/namei.h>
-#include <linux/slab.h>
-
-#include "ipath_kernel.h"
-
-#define IPATHFS_MAGIC 0x726a77
-
-static struct super_block *ipath_super;
-
-static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
-                        umode_t mode, const struct file_operations *fops,
-                        void *data)
-{
-       int error;
-       struct inode *inode = new_inode(dir->i_sb);
-
-       if (!inode) {
-               error = -EPERM;
-               goto bail;
-       }
-
-       inode->i_ino = get_next_ino();
-       inode->i_mode = mode;
-       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-       inode->i_private = data;
-       if (S_ISDIR(mode)) {
-               inode->i_op = &simple_dir_inode_operations;
-               inc_nlink(inode);
-               inc_nlink(dir);
-       }
-
-       inode->i_fop = fops;
-
-       d_instantiate(dentry, inode);
-       error = 0;
-
-bail:
-       return error;
-}
-
-static int create_file(const char *name, umode_t mode,
-                      struct dentry *parent, struct dentry **dentry,
-                      const struct file_operations *fops, void *data)
-{
-       int error;
-
-       inode_lock(d_inode(parent));
-       *dentry = lookup_one_len(name, parent, strlen(name));
-       if (!IS_ERR(*dentry))
-               error = ipathfs_mknod(d_inode(parent), *dentry,
-                                     mode, fops, data);
-       else
-               error = PTR_ERR(*dentry);
-       inode_unlock(d_inode(parent));
-
-       return error;
-}
-
-static ssize_t atomic_stats_read(struct file *file, char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return simple_read_from_buffer(buf, count, ppos, &ipath_stats,
-                                      sizeof ipath_stats);
-}
-
-static const struct file_operations atomic_stats_ops = {
-       .read = atomic_stats_read,
-       .llseek = default_llseek,
-};
-
-static ssize_t atomic_counters_read(struct file *file, char __user *buf,
-                                   size_t count, loff_t *ppos)
-{
-       struct infinipath_counters counters;
-       struct ipath_devdata *dd;
-
-       dd = file_inode(file)->i_private;
-       dd->ipath_f_read_counters(dd, &counters);
-
-       return simple_read_from_buffer(buf, count, ppos, &counters,
-                                      sizeof counters);
-}
-
-static const struct file_operations atomic_counters_ops = {
-       .read = atomic_counters_read,
-       .llseek = default_llseek,
-};
-
-static ssize_t flash_read(struct file *file, char __user *buf,
-                         size_t count, loff_t *ppos)
-{
-       struct ipath_devdata *dd;
-       ssize_t ret;
-       loff_t pos;
-       char *tmp;
-
-       pos = *ppos;
-
-       if ( pos < 0) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       if (pos >= sizeof(struct ipath_flash)) {
-               ret = 0;
-               goto bail;
-       }
-
-       if (count > sizeof(struct ipath_flash) - pos)
-               count = sizeof(struct ipath_flash) - pos;
-
-       tmp = kmalloc(count, GFP_KERNEL);
-       if (!tmp) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       dd = file_inode(file)->i_private;
-       if (ipath_eeprom_read(dd, pos, tmp, count)) {
-               ipath_dev_err(dd, "failed to read from flash\n");
-               ret = -ENXIO;
-               goto bail_tmp;
-       }
-
-       if (copy_to_user(buf, tmp, count)) {
-               ret = -EFAULT;
-               goto bail_tmp;
-       }
-
-       *ppos = pos + count;
-       ret = count;
-
-bail_tmp:
-       kfree(tmp);
-
-bail:
-       return ret;
-}
-
-static ssize_t flash_write(struct file *file, const char __user *buf,
-                          size_t count, loff_t *ppos)
-{
-       struct ipath_devdata *dd;
-       ssize_t ret;
-       loff_t pos;
-       char *tmp;
-
-       pos = *ppos;
-
-       if (pos != 0) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       if (count != sizeof(struct ipath_flash)) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       tmp = memdup_user(buf, count);
-       if (IS_ERR(tmp))
-               return PTR_ERR(tmp);
-
-       dd = file_inode(file)->i_private;
-       if (ipath_eeprom_write(dd, pos, tmp, count)) {
-               ret = -ENXIO;
-               ipath_dev_err(dd, "failed to write to flash\n");
-               goto bail_tmp;
-       }
-
-       *ppos = pos + count;
-       ret = count;
-
-bail_tmp:
-       kfree(tmp);
-
-bail:
-       return ret;
-}
-
-static const struct file_operations flash_ops = {
-       .read = flash_read,
-       .write = flash_write,
-       .llseek = default_llseek,
-};
-
-static int create_device_files(struct super_block *sb,
-                              struct ipath_devdata *dd)
-{
-       struct dentry *dir, *tmp;
-       char unit[10];
-       int ret;
-
-       snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
-       ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
-                         &simple_dir_operations, dd);
-       if (ret) {
-               printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
-               goto bail;
-       }
-
-       ret = create_file("atomic_counters", S_IFREG|S_IRUGO, dir, &tmp,
-                         &atomic_counters_ops, dd);
-       if (ret) {
-               printk(KERN_ERR "create_file(%s/atomic_counters) "
-                      "failed: %d\n", unit, ret);
-               goto bail;
-       }
-
-       ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
-                         &flash_ops, dd);
-       if (ret) {
-               printk(KERN_ERR "create_file(%s/flash) "
-                      "failed: %d\n", unit, ret);
-               goto bail;
-       }
-
-bail:
-       return ret;
-}
-
-static int remove_file(struct dentry *parent, char *name)
-{
-       struct dentry *tmp;
-       int ret;
-
-       tmp = lookup_one_len(name, parent, strlen(name));
-
-       if (IS_ERR(tmp)) {
-               ret = PTR_ERR(tmp);
-               goto bail;
-       }
-
-       spin_lock(&tmp->d_lock);
-       if (simple_positive(tmp)) {
-               dget_dlock(tmp);
-               __d_drop(tmp);
-               spin_unlock(&tmp->d_lock);
-               simple_unlink(d_inode(parent), tmp);
-       } else
-               spin_unlock(&tmp->d_lock);
-
-       ret = 0;
-bail:
-       /*
-        * We don't expect clients to care about the return value, but
-        * it's there if they need it.
-        */
-       return ret;
-}
-
-static int remove_device_files(struct super_block *sb,
-                              struct ipath_devdata *dd)
-{
-       struct dentry *dir, *root;
-       char unit[10];
-       int ret;
-
-       root = dget(sb->s_root);
-       inode_lock(d_inode(root));
-       snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
-       dir = lookup_one_len(unit, root, strlen(unit));
-
-       if (IS_ERR(dir)) {
-               ret = PTR_ERR(dir);
-               printk(KERN_ERR "Lookup of %s failed\n", unit);
-               goto bail;
-       }
-
-       remove_file(dir, "flash");
-       remove_file(dir, "atomic_counters");
-       d_delete(dir);
-       ret = simple_rmdir(d_inode(root), dir);
-
-bail:
-       inode_unlock(d_inode(root));
-       dput(root);
-       return ret;
-}
-
-static int ipathfs_fill_super(struct super_block *sb, void *data,
-                             int silent)
-{
-       struct ipath_devdata *dd, *tmp;
-       unsigned long flags;
-       int ret;
-
-       static struct tree_descr files[] = {
-               [2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
-               {""},
-       };
-
-       ret = simple_fill_super(sb, IPATHFS_MAGIC, files);
-       if (ret) {
-               printk(KERN_ERR "simple_fill_super failed: %d\n", ret);
-               goto bail;
-       }
-
-       spin_lock_irqsave(&ipath_devs_lock, flags);
-
-       list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
-               spin_unlock_irqrestore(&ipath_devs_lock, flags);
-               ret = create_device_files(sb, dd);
-               if (ret)
-                       goto bail;
-               spin_lock_irqsave(&ipath_devs_lock, flags);
-       }
-
-       spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-bail:
-       return ret;
-}
-
-static struct dentry *ipathfs_mount(struct file_system_type *fs_type,
-                       int flags, const char *dev_name, void *data)
-{
-       struct dentry *ret;
-       ret = mount_single(fs_type, flags, data, ipathfs_fill_super);
-       if (!IS_ERR(ret))
-               ipath_super = ret->d_sb;
-       return ret;
-}
-
-static void ipathfs_kill_super(struct super_block *s)
-{
-       kill_litter_super(s);
-       ipath_super = NULL;
-}
-
-int ipathfs_add_device(struct ipath_devdata *dd)
-{
-       int ret;
-
-       if (ipath_super == NULL) {
-               ret = 0;
-               goto bail;
-       }
-
-       ret = create_device_files(ipath_super, dd);
-
-bail:
-       return ret;
-}
-
-int ipathfs_remove_device(struct ipath_devdata *dd)
-{
-       int ret;
-
-       if (ipath_super == NULL) {
-               ret = 0;
-               goto bail;
-       }
-
-       ret = remove_device_files(ipath_super, dd);
-
-bail:
-       return ret;
-}
-
-static struct file_system_type ipathfs_fs_type = {
-       .owner =        THIS_MODULE,
-       .name =         "ipathfs",
-       .mount =        ipathfs_mount,
-       .kill_sb =      ipathfs_kill_super,
-};
-MODULE_ALIAS_FS("ipathfs");
-
-int __init ipath_init_ipathfs(void)
-{
-       return register_filesystem(&ipathfs_fs_type);
-}
-
-void __exit ipath_exit_ipathfs(void)
-{
-       unregister_filesystem(&ipathfs_fs_type);
-}
diff --git a/drivers/staging/rdma/ipath/ipath_iba6110.c b/drivers/staging/rdma/ipath/ipath_iba6110.c
deleted file mode 100644 (file)
index 5f13572..0000000
+++ /dev/null
@@ -1,1939 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This file contains all of the code that is specific to the InfiniPath
- * HT chip.
- */
-
-#include <linux/vmalloc.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/htirq.h>
-#include <rdma/ib_verbs.h>
-
-#include "ipath_kernel.h"
-#include "ipath_registers.h"
-
-static void ipath_setup_ht_setextled(struct ipath_devdata *, u64, u64);
-
-
-/*
- * This lists the InfiniPath registers, in the actual chip layout.
- * This structure should never be directly accessed.
- *
- * The names are in InterCap form because they're taken straight from
- * the chip specification.  Since they're only used in this file, they
- * don't pollute the rest of the source.
-*/
-
-struct _infinipath_do_not_use_kernel_regs {
-       unsigned long long Revision;
-       unsigned long long Control;
-       unsigned long long PageAlign;
-       unsigned long long PortCnt;
-       unsigned long long DebugPortSelect;
-       unsigned long long DebugPort;
-       unsigned long long SendRegBase;
-       unsigned long long UserRegBase;
-       unsigned long long CounterRegBase;
-       unsigned long long Scratch;
-       unsigned long long ReservedMisc1;
-       unsigned long long InterruptConfig;
-       unsigned long long IntBlocked;
-       unsigned long long IntMask;
-       unsigned long long IntStatus;
-       unsigned long long IntClear;
-       unsigned long long ErrorMask;
-       unsigned long long ErrorStatus;
-       unsigned long long ErrorClear;
-       unsigned long long HwErrMask;
-       unsigned long long HwErrStatus;
-       unsigned long long HwErrClear;
-       unsigned long long HwDiagCtrl;
-       unsigned long long MDIO;
-       unsigned long long IBCStatus;
-       unsigned long long IBCCtrl;
-       unsigned long long ExtStatus;
-       unsigned long long ExtCtrl;
-       unsigned long long GPIOOut;
-       unsigned long long GPIOMask;
-       unsigned long long GPIOStatus;
-       unsigned long long GPIOClear;
-       unsigned long long RcvCtrl;
-       unsigned long long RcvBTHQP;
-       unsigned long long RcvHdrSize;
-       unsigned long long RcvHdrCnt;
-       unsigned long long RcvHdrEntSize;
-       unsigned long long RcvTIDBase;
-       unsigned long long RcvTIDCnt;
-       unsigned long long RcvEgrBase;
-       unsigned long long RcvEgrCnt;
-       unsigned long long RcvBufBase;
-       unsigned long long RcvBufSize;
-       unsigned long long RxIntMemBase;
-       unsigned long long RxIntMemSize;
-       unsigned long long RcvPartitionKey;
-       unsigned long long ReservedRcv[10];
-       unsigned long long SendCtrl;
-       unsigned long long SendPIOBufBase;
-       unsigned long long SendPIOSize;
-       unsigned long long SendPIOBufCnt;
-       unsigned long long SendPIOAvailAddr;
-       unsigned long long TxIntMemBase;
-       unsigned long long TxIntMemSize;
-       unsigned long long ReservedSend[9];
-       unsigned long long SendBufferError;
-       unsigned long long SendBufferErrorCONT1;
-       unsigned long long SendBufferErrorCONT2;
-       unsigned long long SendBufferErrorCONT3;
-       unsigned long long ReservedSBE[4];
-       unsigned long long RcvHdrAddr0;
-       unsigned long long RcvHdrAddr1;
-       unsigned long long RcvHdrAddr2;
-       unsigned long long RcvHdrAddr3;
-       unsigned long long RcvHdrAddr4;
-       unsigned long long RcvHdrAddr5;
-       unsigned long long RcvHdrAddr6;
-       unsigned long long RcvHdrAddr7;
-       unsigned long long RcvHdrAddr8;
-       unsigned long long ReservedRHA[7];
-       unsigned long long RcvHdrTailAddr0;
-       unsigned long long RcvHdrTailAddr1;
-       unsigned long long RcvHdrTailAddr2;
-       unsigned long long RcvHdrTailAddr3;
-       unsigned long long RcvHdrTailAddr4;
-       unsigned long long RcvHdrTailAddr5;
-       unsigned long long RcvHdrTailAddr6;
-       unsigned long long RcvHdrTailAddr7;
-       unsigned long long RcvHdrTailAddr8;
-       unsigned long long ReservedRHTA[7];
-       unsigned long long Sync;        /* Software only */
-       unsigned long long Dump;        /* Software only */
-       unsigned long long SimVer;      /* Software only */
-       unsigned long long ReservedSW[5];
-       unsigned long long SerdesConfig0;
-       unsigned long long SerdesConfig1;
-       unsigned long long SerdesStatus;
-       unsigned long long XGXSConfig;
-       unsigned long long ReservedSW2[4];
-};
-
-struct _infinipath_do_not_use_counters {
-       __u64 LBIntCnt;
-       __u64 LBFlowStallCnt;
-       __u64 Reserved1;
-       __u64 TxUnsupVLErrCnt;
-       __u64 TxDataPktCnt;
-       __u64 TxFlowPktCnt;
-       __u64 TxDwordCnt;
-       __u64 TxLenErrCnt;
-       __u64 TxMaxMinLenErrCnt;
-       __u64 TxUnderrunCnt;
-       __u64 TxFlowStallCnt;
-       __u64 TxDroppedPktCnt;
-       __u64 RxDroppedPktCnt;
-       __u64 RxDataPktCnt;
-       __u64 RxFlowPktCnt;
-       __u64 RxDwordCnt;
-       __u64 RxLenErrCnt;
-       __u64 RxMaxMinLenErrCnt;
-       __u64 RxICRCErrCnt;
-       __u64 RxVCRCErrCnt;
-       __u64 RxFlowCtrlErrCnt;
-       __u64 RxBadFormatCnt;
-       __u64 RxLinkProblemCnt;
-       __u64 RxEBPCnt;
-       __u64 RxLPCRCErrCnt;
-       __u64 RxBufOvflCnt;
-       __u64 RxTIDFullErrCnt;
-       __u64 RxTIDValidErrCnt;
-       __u64 RxPKeyMismatchCnt;
-       __u64 RxP0HdrEgrOvflCnt;
-       __u64 RxP1HdrEgrOvflCnt;
-       __u64 RxP2HdrEgrOvflCnt;
-       __u64 RxP3HdrEgrOvflCnt;
-       __u64 RxP4HdrEgrOvflCnt;
-       __u64 RxP5HdrEgrOvflCnt;
-       __u64 RxP6HdrEgrOvflCnt;
-       __u64 RxP7HdrEgrOvflCnt;
-       __u64 RxP8HdrEgrOvflCnt;
-       __u64 Reserved6;
-       __u64 Reserved7;
-       __u64 IBStatusChangeCnt;
-       __u64 IBLinkErrRecoveryCnt;
-       __u64 IBLinkDownedCnt;
-       __u64 IBSymbolErrCnt;
-};
-
-#define IPATH_KREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
-#define IPATH_CREG_OFFSET(field) (offsetof( \
-       struct _infinipath_do_not_use_counters, field) / sizeof(u64))
-
-static const struct ipath_kregs ipath_ht_kregs = {
-       .kr_control = IPATH_KREG_OFFSET(Control),
-       .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase),
-       .kr_debugport = IPATH_KREG_OFFSET(DebugPort),
-       .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect),
-       .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear),
-       .kr_errormask = IPATH_KREG_OFFSET(ErrorMask),
-       .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus),
-       .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl),
-       .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus),
-       .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear),
-       .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask),
-       .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut),
-       .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus),
-       .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl),
-       .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear),
-       .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask),
-       .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus),
-       .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl),
-       .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus),
-       .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked),
-       .kr_intclear = IPATH_KREG_OFFSET(IntClear),
-       .kr_interruptconfig = IPATH_KREG_OFFSET(InterruptConfig),
-       .kr_intmask = IPATH_KREG_OFFSET(IntMask),
-       .kr_intstatus = IPATH_KREG_OFFSET(IntStatus),
-       .kr_mdio = IPATH_KREG_OFFSET(MDIO),
-       .kr_pagealign = IPATH_KREG_OFFSET(PageAlign),
-       .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey),
-       .kr_portcnt = IPATH_KREG_OFFSET(PortCnt),
-       .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP),
-       .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase),
-       .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize),
-       .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl),
-       .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase),
-       .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt),
-       .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt),
-       .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize),
-       .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize),
-       .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase),
-       .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize),
-       .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase),
-       .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt),
-       .kr_revision = IPATH_KREG_OFFSET(Revision),
-       .kr_scratch = IPATH_KREG_OFFSET(Scratch),
-       .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError),
-       .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl),
-       .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr),
-       .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase),
-       .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt),
-       .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize),
-       .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase),
-       .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase),
-       .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize),
-       .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase),
-       .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0),
-       .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1),
-       .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus),
-       .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig),
-       /*
-        * These should not be used directly via ipath_write_kreg64(),
-        * use them with ipath_write_kreg64_port(),
-        */
-       .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
-       .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0)
-};
-
-static const struct ipath_cregs ipath_ht_cregs = {
-       .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt),
-       .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt),
-       .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt),
-       .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt),
-       .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt),
-       .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt),
-       .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt),
-       .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt),
-       .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt),
-       .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt),
-       .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt),
-       .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt),
-       /* calc from Reg_CounterRegBase + offset */
-       .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt),
-       .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt),
-       .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt),
-       .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt),
-       .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt),
-       .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt),
-       .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt),
-       .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt),
-       .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt),
-       .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt),
-       .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt),
-       .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt),
-       .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt),
-       .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt),
-       .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt),
-       .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt),
-       .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt),
-       .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt),
-       .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt),
-       .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt),
-       .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt)
-};
-
-/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK ((1U<<9)-1)
-#define INFINIPATH_I_RCVURG_SHIFT 0
-#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<9)-1)
-#define INFINIPATH_I_RCVAVAIL_SHIFT 12
-
-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
-#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
-#define INFINIPATH_HWE_HTCMEMPARITYERR_MASK 0x3FFFFFULL
-#define INFINIPATH_HWE_HTCLNKABYTE0CRCERR   0x0000000000800000ULL
-#define INFINIPATH_HWE_HTCLNKABYTE1CRCERR   0x0000000001000000ULL
-#define INFINIPATH_HWE_HTCLNKBBYTE0CRCERR   0x0000000002000000ULL
-#define INFINIPATH_HWE_HTCLNKBBYTE1CRCERR   0x0000000004000000ULL
-#define INFINIPATH_HWE_HTCMISCERR4          0x0000000008000000ULL
-#define INFINIPATH_HWE_HTCMISCERR5          0x0000000010000000ULL
-#define INFINIPATH_HWE_HTCMISCERR6          0x0000000020000000ULL
-#define INFINIPATH_HWE_HTCMISCERR7          0x0000000040000000ULL
-#define INFINIPATH_HWE_HTCBUSTREQPARITYERR  0x0000000080000000ULL
-#define INFINIPATH_HWE_HTCBUSTRESPPARITYERR 0x0000000100000000ULL
-#define INFINIPATH_HWE_HTCBUSIREQPARITYERR  0x0000000200000000ULL
-#define INFINIPATH_HWE_COREPLL_FBSLIP       0x0080000000000000ULL
-#define INFINIPATH_HWE_COREPLL_RFSLIP       0x0100000000000000ULL
-#define INFINIPATH_HWE_HTBPLL_FBSLIP        0x0200000000000000ULL
-#define INFINIPATH_HWE_HTBPLL_RFSLIP        0x0400000000000000ULL
-#define INFINIPATH_HWE_HTAPLL_FBSLIP        0x0800000000000000ULL
-#define INFINIPATH_HWE_HTAPLL_RFSLIP        0x1000000000000000ULL
-#define INFINIPATH_HWE_SERDESPLLFAILED      0x2000000000000000ULL
-
-#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
-#define IBA6110_IBCS_LINKSTATE_SHIFT 4
-
-/* kr_extstatus bits */
-#define INFINIPATH_EXTS_FREQSEL 0x2
-#define INFINIPATH_EXTS_SERDESSEL 0x4
-#define INFINIPATH_EXTS_MEMBIST_ENDTEST     0x0000000000004000
-#define INFINIPATH_EXTS_MEMBIST_CORRECT     0x0000000000008000
-
-
-/* TID entries (memory), HT-only */
-#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL        /* 40 bits valid */
-#define INFINIPATH_RT_VALID 0x8000000000000000ULL
-#define INFINIPATH_RT_ADDR_SHIFT 0
-#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
-#define INFINIPATH_RT_BUFSIZE_SHIFT 48
-
-#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-#define INFINIPATH_R_TAILUPD_SHIFT 31
-
-/* kr_xgxsconfig bits */
-#define INFINIPATH_XGXS_RESET          0x7ULL
-
-/*
- * masks and bits that are different in different chips, or present only
- * in one
- */
-static const ipath_err_t infinipath_hwe_htcmemparityerr_mask =
-    INFINIPATH_HWE_HTCMEMPARITYERR_MASK;
-static const ipath_err_t infinipath_hwe_htcmemparityerr_shift =
-    INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT;
-
-static const ipath_err_t infinipath_hwe_htclnkabyte0crcerr =
-    INFINIPATH_HWE_HTCLNKABYTE0CRCERR;
-static const ipath_err_t infinipath_hwe_htclnkabyte1crcerr =
-    INFINIPATH_HWE_HTCLNKABYTE1CRCERR;
-static const ipath_err_t infinipath_hwe_htclnkbbyte0crcerr =
-    INFINIPATH_HWE_HTCLNKBBYTE0CRCERR;
-static const ipath_err_t infinipath_hwe_htclnkbbyte1crcerr =
-    INFINIPATH_HWE_HTCLNKBBYTE1CRCERR;
-
-#define _IPATH_GPIO_SDA_NUM 1
-#define _IPATH_GPIO_SCL_NUM 0
-
-#define IPATH_GPIO_SDA \
-       (1ULL << (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-#define IPATH_GPIO_SCL \
-       (1ULL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-
-/* keep the code below somewhat more readable; not used elsewhere */
-#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr |    \
-                               infinipath_hwe_htclnkabyte1crcerr)
-#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr |    \
-                               infinipath_hwe_htclnkbbyte1crcerr)
-#define _IPATH_HTLANE0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr |    \
-                               infinipath_hwe_htclnkbbyte0crcerr)
-#define _IPATH_HTLANE1_CRCBITS (infinipath_hwe_htclnkabyte1crcerr |    \
-                               infinipath_hwe_htclnkbbyte1crcerr)
-
-static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
-                         char *msg, size_t msgl)
-{
-       char bitsmsg[64];
-       ipath_err_t crcbits = hwerrs &
-               (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS);
-       /* don't check if 8bit HT */
-       if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
-               crcbits &= ~infinipath_hwe_htclnkabyte1crcerr;
-       /* don't check if 8bit HT */
-       if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
-               crcbits &= ~infinipath_hwe_htclnkbbyte1crcerr;
-       /*
-        * we'll want to ignore link errors on link that is
-        * not in use, if any.  For now, complain about both
-        */
-       if (crcbits) {
-               u16 ctrl0, ctrl1;
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[HT%s lane %s CRC (%llx); powercycle to completely clear]",
-                        !(crcbits & _IPATH_HTLINK1_CRCBITS) ?
-                        "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
-                                   ? "1 (B)" : "0+1 (A+B)"),
-                        !(crcbits & _IPATH_HTLANE1_CRCBITS) ? "0"
-                        : (!(crcbits & _IPATH_HTLANE0_CRCBITS) ? "1" :
-                           "0+1"), (unsigned long long) crcbits);
-               strlcat(msg, bitsmsg, msgl);
-
-               /*
-                * print extra info for debugging.  slave/primary
-                * config word 4, 8 (link control 0, 1)
-                */
-
-               if (pci_read_config_word(dd->pcidev,
-                                        dd->ipath_ht_slave_off + 0x4,
-                                        &ctrl0))
-                       dev_info(&dd->pcidev->dev, "Couldn't read "
-                                "linkctrl0 of slave/primary "
-                                "config block\n");
-               else if (!(ctrl0 & 1 << 6))
-                       /* not if EOC bit set */
-                       ipath_dbg("HT linkctrl0 0x%x%s%s\n", ctrl0,
-                                 ((ctrl0 >> 8) & 7) ? " CRC" : "",
-                                 ((ctrl0 >> 4) & 1) ? "linkfail" :
-                                 "");
-               if (pci_read_config_word(dd->pcidev,
-                                        dd->ipath_ht_slave_off + 0x8,
-                                        &ctrl1))
-                       dev_info(&dd->pcidev->dev, "Couldn't read "
-                                "linkctrl1 of slave/primary "
-                                "config block\n");
-               else if (!(ctrl1 & 1 << 6))
-                       /* not if EOC bit set */
-                       ipath_dbg("HT linkctrl1 0x%x%s%s\n", ctrl1,
-                                 ((ctrl1 >> 8) & 7) ? " CRC" : "",
-                                 ((ctrl1 >> 4) & 1) ? "linkfail" :
-                                 "");
-
-               /* disable until driver reloaded */
-               dd->ipath_hwerrmask &= ~crcbits;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-               ipath_dbg("HT crc errs: %s\n", msg);
-       } else
-               ipath_dbg("ignoring HT crc errors 0x%llx, "
-                         "not in use\n", (unsigned long long)
-                         (hwerrs & (_IPATH_HTLINK0_CRCBITS |
-                                    _IPATH_HTLINK1_CRCBITS)));
-}
-
-/* 6110 specific hardware errors... */
-static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = {
-       INFINIPATH_HWE_MSG(HTCBUSIREQPARITYERR, "HTC Ireq Parity"),
-       INFINIPATH_HWE_MSG(HTCBUSTREQPARITYERR, "HTC Treq Parity"),
-       INFINIPATH_HWE_MSG(HTCBUSTRESPPARITYERR, "HTC Tresp Parity"),
-       INFINIPATH_HWE_MSG(HTCMISCERR5, "HT core Misc5"),
-       INFINIPATH_HWE_MSG(HTCMISCERR6, "HT core Misc6"),
-       INFINIPATH_HWE_MSG(HTCMISCERR7, "HT core Misc7"),
-       INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
-       INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
-};
-
-#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \
-                       INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
-                       << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
-#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \
-                         << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)
-
-static void ipath_ht_txe_recover(struct ipath_devdata *dd)
-{
-       ++ipath_stats.sps_txeparity;
-       dev_info(&dd->pcidev->dev,
-               "Recovering from TXE PIO parity error\n");
-}
-
-
-/**
- * ipath_ht_handle_hwerrors - display hardware errors.
- * @dd: the infinipath device
- * @msg: the output buffer
- * @msgl: the size of the output buffer
- *
- * Use same msg buffer as regular errors to avoid excessive stack
- * use.  Most hardware errors are catastrophic, but for right now,
- * we'll print them and continue.  We reuse the same message buffer as
- * ipath_handle_errors() to avoid excessive stack usage.
- */
-static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
-                                    size_t msgl)
-{
-       ipath_err_t hwerrs;
-       u32 bits, ctrl;
-       int isfatal = 0;
-       char bitsmsg[64];
-       int log_idx;
-
-       hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
-
-       if (!hwerrs) {
-               ipath_cdbg(VERBOSE, "Called but no hardware errors set\n");
-               /*
-                * better than printing cofusing messages
-                * This seems to be related to clearing the crc error, or
-                * the pll error during init.
-                */
-               goto bail;
-       } else if (hwerrs == -1LL) {
-               ipath_dev_err(dd, "Read of hardware error status failed "
-                             "(all bits set); ignoring\n");
-               goto bail;
-       }
-       ipath_stats.sps_hwerrs++;
-
-       /* Always clear the error status register, except MEMBISTFAIL,
-        * regardless of whether we continue or stop using the chip.
-        * We want that set so we know it failed, even across driver reload.
-        * We'll still ignore it in the hwerrmask.  We do this partly for
-        * diagnostics, but also for support */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        hwerrs&~INFINIPATH_HWE_MEMBISTFAILED);
-
-       hwerrs &= dd->ipath_hwerrmask;
-
-       /* We log some errors to EEPROM, check if we have any of those. */
-       for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx)
-               if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log)
-                       ipath_inc_eeprom_err(dd, log_idx, 1);
-
-       /*
-        * make sure we get this much out, unless told to be quiet,
-        * it's a parity error we may recover from,
-        * or it's occurred within the last 5 seconds
-        */
-       if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY |
-               RXE_EAGER_PARITY)) ||
-               (ipath_debug & __IPATH_VERBDBG))
-               dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
-                        "(cleared)\n", (unsigned long long) hwerrs);
-       dd->ipath_lasthwerror |= hwerrs;
-
-       if (hwerrs & ~dd->ipath_hwe_bitsextant)
-               ipath_dev_err(dd, "hwerror interrupt with unknown errors "
-                             "%llx set\n", (unsigned long long)
-                             (hwerrs & ~dd->ipath_hwe_bitsextant));
-
-       ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-       if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
-               /*
-                * parity errors in send memory are recoverable,
-                * just cancel the send (if indicated in * sendbuffererror),
-                * count the occurrence, unfreeze (if no other handled
-                * hardware error bits are set), and continue. They can
-                * occur if a processor speculative read is done to the PIO
-                * buffer while we are sending a packet, for example.
-                */
-               if (hwerrs & TXE_PIO_PARITY) {
-                       ipath_ht_txe_recover(dd);
-                       hwerrs &= ~TXE_PIO_PARITY;
-               }
-
-               if (!hwerrs) {
-                       ipath_dbg("Clearing freezemode on ignored or "
-                                 "recovered hardware error\n");
-                       ipath_clear_freeze(dd);
-               }
-       }
-
-       *msg = '\0';
-
-       /*
-        * may someday want to decode into which bits are which
-        * functional area for parity errors, etc.
-        */
-       if (hwerrs & (infinipath_hwe_htcmemparityerr_mask
-                     << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) {
-               bits = (u32) ((hwerrs >>
-                              INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) &
-                             INFINIPATH_HWE_HTCMEMPARITYERR_MASK);
-               snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ",
-                        bits);
-               strlcat(msg, bitsmsg, msgl);
-       }
-
-       ipath_format_hwerrors(hwerrs,
-                             ipath_6110_hwerror_msgs,
-                             ARRAY_SIZE(ipath_6110_hwerror_msgs),
-                             msg, msgl);
-
-       if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
-               hwerr_crcbits(dd, hwerrs, msg, msgl);
-
-       if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
-               strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
-                       msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP |       \
-                        INFINIPATH_HWE_COREPLL_RFSLIP |        \
-                        INFINIPATH_HWE_HTBPLL_FBSLIP |         \
-                        INFINIPATH_HWE_HTBPLL_RFSLIP |         \
-                        INFINIPATH_HWE_HTAPLL_FBSLIP |         \
-                        INFINIPATH_HWE_HTAPLL_RFSLIP)
-
-       if (hwerrs & _IPATH_PLL_FAIL) {
-               snprintf(bitsmsg, sizeof bitsmsg,
-                        "[PLL failed (%llx), InfiniPath hardware unusable]",
-                        (unsigned long long) (hwerrs & _IPATH_PLL_FAIL));
-               strlcat(msg, bitsmsg, msgl);
-               /* ignore from now on, so disable until driver reloaded */
-               dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
-               /*
-                * If it occurs, it is left masked since the eternal
-                * interface is unused
-                */
-               dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                                dd->ipath_hwerrmask);
-       }
-
-       if (hwerrs) {
-               /*
-                * if any set that we aren't ignoring; only
-                * make the complaint once, in case it's stuck
-                * or recurring, and we get here multiple
-                * times.
-                * force link down, so switch knows, and
-                * LEDs are turned off
-                */
-               if (dd->ipath_flags & IPATH_INITTED) {
-                       ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-                       ipath_setup_ht_setextled(dd,
-                               INFINIPATH_IBCS_L_STATE_DOWN,
-                               INFINIPATH_IBCS_LT_STATE_DISABLED);
-                       ipath_dev_err(dd, "Fatal Hardware Error (freeze "
-                                         "mode), no longer usable, SN %.16s\n",
-                                         dd->ipath_serial);
-                       isfatal = 1;
-               }
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-               /* mark as having had error */
-               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-               /*
-                * mark as not usable, at a minimum until driver
-                * is reloaded, probably until reboot, since no
-                * other reset is possible.
-                */
-               dd->ipath_flags &= ~IPATH_INITTED;
-       } else {
-               *msg = 0; /* recovered from all of them */
-       }
-       if (*msg)
-               ipath_dev_err(dd, "%s hardware error\n", msg);
-       if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
-               /*
-                * for status file; if no trailing brace is copied,
-                * we'll know it was truncated.
-                */
-               snprintf(dd->ipath_freezemsg,
-                        dd->ipath_freezelen, "{%s}", msg);
-
-bail:;
-}
-
-/**
- * ipath_ht_boardname - fill in the board name
- * @dd: the infinipath device
- * @name: the output buffer
- * @namelen: the size of the output buffer
- *
- * fill in the board name, based on the board revision register
- */
-static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
-                             size_t namelen)
-{
-       char *n = NULL;
-       u8 boardrev = dd->ipath_boardrev;
-       int ret = 0;
-
-       switch (boardrev) {
-       case 5:
-               /*
-                * original production board; two production levels, with
-                * different serial number ranges.   See ipath_ht_early_init() for
-                * case where we enable IPATH_GPIO_INTR for later serial # range.
-                * Original 112* serial number is no longer supported.
-                */
-               n = "InfiniPath_QHT7040";
-               break;
-       case 7:
-               /* small form factor production board */
-               n = "InfiniPath_QHT7140";
-               break;
-       default:                /* don't know, just print the number */
-               ipath_dev_err(dd, "Don't yet know about board "
-                             "with ID %u\n", boardrev);
-               snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
-                        boardrev);
-               break;
-       }
-       if (n)
-               snprintf(name, namelen, "%s", n);
-
-       if (ret) {
-               ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name);
-               goto bail;
-       }
-       if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
-               dd->ipath_minrev > 4)) {
-               /*
-                * This version of the driver only supports Rev 3.2 - 3.4
-                */
-               ipath_dev_err(dd,
-                             "Unsupported InfiniPath hardware revision %u.%u!\n",
-                             dd->ipath_majrev, dd->ipath_minrev);
-               ret = 1;
-               goto bail;
-       }
-       /*
-        * pkt/word counters are 32 bit, and therefore wrap fast enough
-        * that we snapshot them from a timer, and maintain 64 bit shadow
-        * copies
-        */
-       dd->ipath_flags |= IPATH_32BITCOUNTERS;
-       dd->ipath_flags |= IPATH_GPIO_INTR;
-       if (dd->ipath_lbus_speed != 800)
-               ipath_dev_err(dd,
-                             "Incorrectly configured for HT @ %uMHz\n",
-                             dd->ipath_lbus_speed);
-
-       /*
-        * set here, not in ipath_init_*_funcs because we have to do
-        * it after we can read chip registers.
-        */
-       dd->ipath_ureg_align =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
-
-bail:
-       return ret;
-}
-
-static void ipath_check_htlink(struct ipath_devdata *dd)
-{
-       u8 linkerr, link_off, i;
-
-       for (i = 0; i < 2; i++) {
-               link_off = dd->ipath_ht_slave_off + i * 4 + 0xd;
-               if (pci_read_config_byte(dd->pcidev, link_off, &linkerr))
-                       dev_info(&dd->pcidev->dev, "Couldn't read "
-                                "linkerror%d of HT slave/primary block\n",
-                                i);
-               else if (linkerr & 0xf0) {
-                       ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
-                                  "clearing\n", linkerr >> 4, i);
-                       /*
-                        * writing the linkerr bits that are set should
-                        * clear them
-                        */
-                       if (pci_write_config_byte(dd->pcidev, link_off,
-                                                 linkerr))
-                               ipath_dbg("Failed write to clear HT "
-                                         "linkerror%d\n", i);
-                       if (pci_read_config_byte(dd->pcidev, link_off,
-                                                &linkerr))
-                               dev_info(&dd->pcidev->dev,
-                                        "Couldn't reread linkerror%d of "
-                                        "HT slave/primary block\n", i);
-                       else if (linkerr & 0xf0)
-                               dev_info(&dd->pcidev->dev,
-                                        "HT linkerror%d bits 0x%x "
-                                        "couldn't be cleared\n",
-                                        i, linkerr >> 4);
-               }
-       }
-}
-
-static int ipath_setup_ht_reset(struct ipath_devdata *dd)
-{
-       ipath_dbg("No reset possible for this InfiniPath hardware\n");
-       return 0;
-}
-
-#define HT_INTR_DISC_CONFIG  0x80      /* HT interrupt and discovery cap */
-#define HT_INTR_REG_INDEX    2 /* intconfig requires indirect accesses */
-
-/*
- * Bits 13-15 of command==0 is slave/primary block.  Clear any HT CRC
- * errors.  We only bother to do this at load time, because it's OK if
- * it happened before we were loaded (first time after boot/reset),
- * but any time after that, it's fatal anyway.  Also need to not check
- * for upper byte errors if we are in 8 bit mode, so figure out
- * our width.  For now, at least, also complain if it's 8 bit.
- */
-static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev,
-                            int pos, u8 cap_type)
-{
-       u8 linkwidth = 0, linkerr, link_a_b_off, link_off;
-       u16 linkctrl = 0;
-       int i;
-
-       dd->ipath_ht_slave_off = pos;
-       /* command word, master_host bit */
-       /* master host || slave */
-       if ((cap_type >> 2) & 1)
-               link_a_b_off = 4;
-       else
-               link_a_b_off = 0;
-       ipath_cdbg(VERBOSE, "HT%u (Link %c) connected to processor\n",
-                  link_a_b_off ? 1 : 0,
-                  link_a_b_off ? 'B' : 'A');
-
-       link_a_b_off += pos;
-
-       /*
-        * check both link control registers; clear both HT CRC sets if
-        * necessary.
-        */
-       for (i = 0; i < 2; i++) {
-               link_off = pos + i * 4 + 0x4;
-               if (pci_read_config_word(pdev, link_off, &linkctrl))
-                       ipath_dev_err(dd, "Couldn't read HT link control%d "
-                                     "register\n", i);
-               else if (linkctrl & (0xf << 8)) {
-                       ipath_cdbg(VERBOSE, "Clear linkctrl%d CRC Error "
-                                  "bits %x\n", i, linkctrl & (0xf << 8));
-                       /*
-                        * now write them back to clear the error.
-                        */
-                       pci_write_config_word(pdev, link_off,
-                                             linkctrl & (0xf << 8));
-               }
-       }
-
-       /*
-        * As with HT CRC bits, same for protocol errors that might occur
-        * during boot.
-        */
-       for (i = 0; i < 2; i++) {
-               link_off = pos + i * 4 + 0xd;
-               if (pci_read_config_byte(pdev, link_off, &linkerr))
-                       dev_info(&pdev->dev, "Couldn't read linkerror%d "
-                                "of HT slave/primary block\n", i);
-               else if (linkerr & 0xf0) {
-                       ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, "
-                                  "clearing\n", linkerr >> 4, i);
-                       /*
-                        * writing the linkerr bits that are set will clear
-                        * them
-                        */
-                       if (pci_write_config_byte
-                           (pdev, link_off, linkerr))
-                               ipath_dbg("Failed write to clear HT "
-                                         "linkerror%d\n", i);
-                       if (pci_read_config_byte(pdev, link_off, &linkerr))
-                               dev_info(&pdev->dev, "Couldn't reread "
-                                        "linkerror%d of HT slave/primary "
-                                        "block\n", i);
-                       else if (linkerr & 0xf0)
-                               dev_info(&pdev->dev, "HT linkerror%d bits "
-                                        "0x%x couldn't be cleared\n",
-                                        i, linkerr >> 4);
-               }
-       }
-
-       /*
-        * this is just for our link to the host, not devices connected
-        * through tunnel.
-        */
-
-       if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth))
-               ipath_dev_err(dd, "Couldn't read HT link width "
-                             "config register\n");
-       else {
-               u32 width;
-               switch (linkwidth & 7) {
-               case 5:
-                       width = 4;
-                       break;
-               case 4:
-                       width = 2;
-                       break;
-               case 3:
-                       width = 32;
-                       break;
-               case 1:
-                       width = 16;
-                       break;
-               case 0:
-               default:        /* if wrong, assume 8 bit */
-                       width = 8;
-                       break;
-               }
-
-               dd->ipath_lbus_width = width;
-
-               if (linkwidth != 0x11) {
-                       ipath_dev_err(dd, "Not configured for 16 bit HT "
-                                     "(%x)\n", linkwidth);
-                       if (!(linkwidth & 0xf)) {
-                               ipath_dbg("Will ignore HT lane1 errors\n");
-                               dd->ipath_flags |= IPATH_8BIT_IN_HT0;
-                       }
-               }
-       }
-
-       /*
-        * this is just for our link to the host, not devices connected
-        * through tunnel.
-        */
-       if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth))
-               ipath_dev_err(dd, "Couldn't read HT link frequency "
-                             "config register\n");
-       else {
-               u32 speed;
-               switch (linkwidth & 0xf) {
-               case 6:
-                       speed = 1000;
-                       break;
-               case 5:
-                       speed = 800;
-                       break;
-               case 4:
-                       speed = 600;
-                       break;
-               case 3:
-                       speed = 500;
-                       break;
-               case 2:
-                       speed = 400;
-                       break;
-               case 1:
-                       speed = 300;
-                       break;
-               default:
-                       /*
-                        * assume reserved and vendor-specific are 200...
-                        */
-               case 0:
-                       speed = 200;
-                       break;
-               }
-               dd->ipath_lbus_speed = speed;
-       }
-
-       snprintf(dd->ipath_lbus_info, sizeof(dd->ipath_lbus_info),
-               "HyperTransport,%uMHz,x%u\n",
-               dd->ipath_lbus_speed,
-               dd->ipath_lbus_width);
-}
-
-static int ipath_ht_intconfig(struct ipath_devdata *dd)
-{
-       int ret;
-
-       if (dd->ipath_intconfig) {
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig,
-                                dd->ipath_intconfig);  /* interrupt address */
-               ret = 0;
-       } else {
-               ipath_dev_err(dd, "No interrupts enabled, couldn't setup "
-                             "interrupt address\n");
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static void ipath_ht_irq_update(struct pci_dev *dev, int irq,
-                               struct ht_irq_msg *msg)
-{
-       struct ipath_devdata *dd = pci_get_drvdata(dev);
-       u64 prev_intconfig = dd->ipath_intconfig;
-
-       dd->ipath_intconfig = msg->address_lo;
-       dd->ipath_intconfig |= ((u64) msg->address_hi) << 32;
-
-       /*
-        * If the previous value of dd->ipath_intconfig is zero, we're
-        * getting configured for the first time, and must not program the
-        * intconfig register here (it will be programmed later, when the
-        * hardware is ready).  Otherwise, we should.
-        */
-       if (prev_intconfig)
-               ipath_ht_intconfig(dd);
-}
-
-/**
- * ipath_setup_ht_config - setup the interruptconfig register
- * @dd: the infinipath device
- * @pdev: the PCI device
- *
- * setup the interruptconfig register from the HT config info.
- * Also clear CRC errors in HT linkcontrol, if necessary.
- * This is done only for the real hardware.  It is done before
- * chip address space is initted, so can't touch infinipath registers
- */
-static int ipath_setup_ht_config(struct ipath_devdata *dd,
-                                struct pci_dev *pdev)
-{
-       int pos, ret;
-
-       ret = __ht_create_irq(pdev, 0, ipath_ht_irq_update);
-       if (ret < 0) {
-               ipath_dev_err(dd, "Couldn't create interrupt handler: "
-                             "err %d\n", ret);
-               goto bail;
-       }
-       dd->ipath_irq = ret;
-       ret = 0;
-
-       /*
-        * Handle clearing CRC errors in linkctrl register if necessary.  We
-        * do this early, before we ever enable errors or hardware errors,
-        * mostly to avoid causing the chip to enter freeze mode.
-        */
-       pos = pci_find_capability(pdev, PCI_CAP_ID_HT);
-       if (!pos) {
-               ipath_dev_err(dd, "Couldn't find HyperTransport "
-                             "capability; no interrupts\n");
-               ret = -ENODEV;
-               goto bail;
-       }
-       do {
-               u8 cap_type;
-
-               /*
-                * The HT capability type byte is 3 bytes after the
-                * capability byte.
-                */
-               if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
-                       dev_info(&pdev->dev, "Couldn't read config "
-                                "command @ %d\n", pos);
-                       continue;
-               }
-               if (!(cap_type & 0xE0))
-                       slave_or_pri_blk(dd, pdev, pos, cap_type);
-       } while ((pos = pci_find_next_capability(pdev, pos,
-                                                PCI_CAP_ID_HT)));
-
-       dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff
- * @dd: the infinipath device
- *
- * Called during driver unload.
- * This is currently a nop for the HT chip, not for all chips
- */
-static void ipath_setup_ht_cleanup(struct ipath_devdata *dd)
-{
-}
-
-/**
- * ipath_setup_ht_setextled - set the state of the two external LEDs
- * @dd: the infinipath device
- * @lst: the L state
- * @ltst: the LT state
- *
- * Set the state of the two external LEDs, to indicate physical and
- * logical state of IB link.   For this chip (at least with recommended
- * board pinouts), LED1 is Green (physical state), and LED2 is Yellow
- * (logical state)
- *
- * Note:  We try to match the Mellanox HCA LED behavior as best
- * we can.  Green indicates physical link state is OK (something is
- * plugged in, and we can train).
- * Amber indicates the link is logically up (ACTIVE).
- * Mellanox further blinks the amber LED to indicate data packet
- * activity, but we have no hardware support for that, so it would
- * require waking up every 10-20 msecs and checking the counters
- * on the chip, and then turning the LED off if appropriate.  That's
- * visible overhead, so not something we will do.
- *
- */
-static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
-                                    u64 lst, u64 ltst)
-{
-       u64 extctl;
-       unsigned long flags = 0;
-
-       /* the diags use the LED to indicate diag info, so we leave
-        * the external LED alone when the diags are running */
-       if (ipath_diag_inuse)
-               return;
-
-       /* Allow override of LED display for, e.g. Locating system in rack */
-       if (dd->ipath_led_override) {
-               ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
-                       ? INFINIPATH_IBCS_LT_STATE_LINKUP
-                       : INFINIPATH_IBCS_LT_STATE_DISABLED;
-               lst = (dd->ipath_led_override & IPATH_LED_LOG)
-                       ? INFINIPATH_IBCS_L_STATE_ACTIVE
-                       : INFINIPATH_IBCS_L_STATE_DOWN;
-       }
-
-       spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
-       /*
-        * start by setting both LED control bits to off, then turn
-        * on the appropriate bit(s).
-        */
-       if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */
-               /*
-                * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF
-                * is inverted,  because it is normally used to indicate
-                * a hardware fault at reset, if there were errors
-                */
-               extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON)
-                       | INFINIPATH_EXTC_LEDGBLERR_OFF;
-               if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
-                       extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF;
-               if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
-                       extctl |= INFINIPATH_EXTC_LEDGBLOK_ON;
-       } else {
-               extctl = dd->ipath_extctrl &
-                       ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
-                         INFINIPATH_EXTC_LED2PRIPORT_ON);
-               if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)
-                       extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
-               if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)
-                       extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;
-       }
-       dd->ipath_extctrl = extctl;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
-       spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
-}
-
-static void ipath_init_ht_variables(struct ipath_devdata *dd)
-{
-       /*
-        * setup the register offsets, since they are different for each
-        * chip
-        */
-       dd->ipath_kregs = &ipath_ht_kregs;
-       dd->ipath_cregs = &ipath_ht_cregs;
-
-       dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
-       dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
-       dd->ipath_gpio_sda = IPATH_GPIO_SDA;
-       dd->ipath_gpio_scl = IPATH_GPIO_SCL;
-
-       /*
-        * Fill in data for field-values that change in newer chips.
-        * We dynamically specify only the mask for LINKTRAININGSTATE
-        * and only the shift for LINKSTATE, as they are the only ones
-        * that change.  Also precalculate the 3 link states of interest
-        * and the combined mask.
-        */
-       dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
-       dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
-       dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
-               dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
-       dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
-       dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
-       dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
-               INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
-               (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
-
-       /*
-        * Fill in data for ibcc field-values that change in newer chips.
-        * We dynamically specify only the mask for LINKINITCMD
-        * and only the shift for LINKCMD and MAXPKTLEN, as they are
-        * the only ones that change.
-        */
-       dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
-       dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
-       dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
-
-       /* Fill in shifts for RcvCtrl. */
-       dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
-       dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
-       dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
-       dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
-
-       dd->ipath_i_bitsextant =
-               (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
-               (INFINIPATH_I_RCVAVAIL_MASK <<
-                INFINIPATH_I_RCVAVAIL_SHIFT) |
-               INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
-               INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
-
-       dd->ipath_e_bitsextant =
-               INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
-               INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
-               INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
-               INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |
-               INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |
-               INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |
-               INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-               INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |
-               INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |
-               INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |
-               INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |
-               INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |
-               INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |
-               INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |
-               INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
-               INFINIPATH_E_HARDWARE;
-
-       dd->ipath_hwe_bitsextant =
-               (INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
-               (INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-                INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
-               INFINIPATH_HWE_HTCLNKABYTE0CRCERR |
-               INFINIPATH_HWE_HTCLNKABYTE1CRCERR |
-               INFINIPATH_HWE_HTCLNKBBYTE0CRCERR |
-               INFINIPATH_HWE_HTCLNKBBYTE1CRCERR |
-               INFINIPATH_HWE_HTCMISCERR4 |
-               INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 |
-               INFINIPATH_HWE_HTCMISCERR7 |
-               INFINIPATH_HWE_HTCBUSTREQPARITYERR |
-               INFINIPATH_HWE_HTCBUSTRESPPARITYERR |
-               INFINIPATH_HWE_HTCBUSIREQPARITYERR |
-               INFINIPATH_HWE_RXDSYNCMEMPARITYERR |
-               INFINIPATH_HWE_MEMBISTFAILED |
-               INFINIPATH_HWE_COREPLL_FBSLIP |
-               INFINIPATH_HWE_COREPLL_RFSLIP |
-               INFINIPATH_HWE_HTBPLL_FBSLIP |
-               INFINIPATH_HWE_HTBPLL_RFSLIP |
-               INFINIPATH_HWE_HTAPLL_FBSLIP |
-               INFINIPATH_HWE_HTAPLL_RFSLIP |
-               INFINIPATH_HWE_SERDESPLLFAILED |
-               INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
-               INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
-
-       dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
-       dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
-       dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
-       dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
-
-       /*
-        * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
-        * 2 is Some Misc, 3 is reserved for future.
-        */
-       dd->ipath_eep_st_masks[0].hwerrs_to_log =
-               INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT;
-
-       dd->ipath_eep_st_masks[1].hwerrs_to_log =
-               INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
-               INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
-
-       dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
-
-       dd->delay_mult = 2; /* SDR, 4X, can't change */
-
-       dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
-       dd->ipath_link_speed_supported = IPATH_IB_SDR;
-       dd->ipath_link_width_enabled = IB_WIDTH_4X;
-       dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
-       /* these can't change for this chip, so set once */
-       dd->ipath_link_width_active = dd->ipath_link_width_enabled;
-       dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
-}
-
-/**
- * ipath_ht_init_hwerrors - enable hardware errors
- * @dd: the infinipath device
- *
- * now that we have finished initializing everything that might reasonably
- * cause a hardware error, and cleared those errors bits as they occur,
- * we can enable hardware errors in the mask (potentially enabling
- * freeze mode), and enable hardware errors as errors (along with
- * everything else) in errormask
- */
-static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
-{
-       ipath_err_t val;
-       u64 extsval;
-
-       extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
-
-       if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST))
-               ipath_dev_err(dd, "MemBIST did not complete!\n");
-       if (extsval & INFINIPATH_EXTS_MEMBIST_CORRECT)
-               ipath_dbg("MemBIST corrected\n");
-
-       ipath_check_htlink(dd);
-
-       /* barring bugs, all hwerrors become interrupts, which can */
-       val = -1LL;
-       /* don't look at crc lane1 if 8 bit */
-       if (dd->ipath_flags & IPATH_8BIT_IN_HT0)
-               val &= ~infinipath_hwe_htclnkabyte1crcerr;
-       /* don't look at crc lane1 if 8 bit */
-       if (dd->ipath_flags & IPATH_8BIT_IN_HT1)
-               val &= ~infinipath_hwe_htclnkbbyte1crcerr;
-
-       /*
-        * disable RXDSYNCMEMPARITY because external serdes is unused,
-        * and therefore the logic will never be used or initialized,
-        * and uninitialized state will normally result in this error
-        * being asserted.  Similarly for the external serdess pll
-        * lock signal.
-        */
-       val &= ~(INFINIPATH_HWE_SERDESPLLFAILED |
-                INFINIPATH_HWE_RXDSYNCMEMPARITYERR);
-
-       /*
-        * Disable MISCERR4 because of an inversion in the HT core
-        * logic checking for errors that cause this bit to be set.
-        * The errata can also cause the protocol error bit to be set
-        * in the HT config space linkerror register(s).
-        */
-       val &= ~INFINIPATH_HWE_HTCMISCERR4;
-
-       /*
-        * PLL ignored because unused MDIO interface has a logic problem
-        */
-       if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
-               val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
-       dd->ipath_hwerrmask = val;
-}
-
-
-
-
-/**
- * ipath_ht_bringup_serdes - bring up the serdes
- * @dd: the infinipath device
- */
-static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
-{
-       u64 val, config1;
-       int ret = 0, change = 0;
-
-       ipath_dbg("Trying to bringup serdes\n");
-
-       if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) &
-           INFINIPATH_HWE_SERDESPLLFAILED)
-       {
-               ipath_dbg("At start, serdes PLL failed bit set in "
-                         "hwerrstatus, clearing and continuing\n");
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                                INFINIPATH_HWE_SERDESPLLFAILED);
-       }
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-       config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);
-
-       ipath_cdbg(VERBOSE, "Initial serdes status is config0=%llx "
-                  "config1=%llx, sstatus=%llx xgxs %llx\n",
-                  (unsigned long long) val, (unsigned long long) config1,
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
-
-       /* force reset on */
-       val |= INFINIPATH_SERDC0_RESET_PLL
-               /* | INFINIPATH_SERDC0_RESET_MASK */
-               ;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-       udelay(15);             /* need pll reset set at least for a bit */
-
-       if (val & INFINIPATH_SERDC0_RESET_PLL) {
-               u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL;
-               /* set lane resets, and tx idle, during pll reset */
-               val2 |= INFINIPATH_SERDC0_RESET_MASK |
-                       INFINIPATH_SERDC0_TXIDLE;
-               ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing "
-                          "%llx)\n", (unsigned long long) val2);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
-                                val2);
-               /*
-                * be sure chip saw it
-                */
-               val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               /*
-                * need pll reset clear at least 11 usec before lane
-                * resets cleared; give it a few more
-                */
-               udelay(15);
-               val = val2;     /* for check below */
-       }
-
-       if (val & (INFINIPATH_SERDC0_RESET_PLL |
-                  INFINIPATH_SERDC0_RESET_MASK |
-                  INFINIPATH_SERDC0_TXIDLE)) {
-               val &= ~(INFINIPATH_SERDC0_RESET_PLL |
-                        INFINIPATH_SERDC0_RESET_MASK |
-                        INFINIPATH_SERDC0_TXIDLE);
-               /* clear them */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,
-                                val);
-       }
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       if (val & INFINIPATH_XGXS_RESET) {
-               /* normally true after boot */
-               val &= ~INFINIPATH_XGXS_RESET;
-               change = 1;
-       }
-       if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
-            INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
-               /* need to compensate for Tx inversion in partner */
-               val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
-                        INFINIPATH_XGXS_RX_POL_SHIFT);
-               val |= dd->ipath_rx_pol_inv <<
-                       INFINIPATH_XGXS_RX_POL_SHIFT;
-               change = 1;
-       }
-       if (change)
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-
-       /* clear current and de-emphasis bits */
-       config1 &= ~0x0ffffffff00ULL;
-       /* set current to 20ma */
-       config1 |= 0x00000000000ULL;
-       /* set de-emphasis to -5.68dB */
-       config1 |= 0x0cccc000000ULL;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1);
-
-       ipath_cdbg(VERBOSE, "After setup: serdes status is config0=%llx "
-                  "config1=%llx, sstatus=%llx xgxs %llx\n",
-                  (unsigned long long) val, (unsigned long long) config1,
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus),
-                  (unsigned long long)
-                  ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
-
-       return ret;             /* for now, say we always succeeded */
-}
-
-/**
- * ipath_ht_quiet_serdes - set serdes to txidle
- * @dd: the infinipath device
- * driver is being unloaded
- */
-static void ipath_ht_quiet_serdes(struct ipath_devdata *dd)
-{
-       u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
-
-       val |= INFINIPATH_SERDC0_TXIDLE;
-       ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",
-                 (unsigned long long) val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
-}
-
-/**
- * ipath_pe_put_tid - write a TID in chip
- * @dd: the infinipath device
- * @tidptr: pointer to the expected TID (in chip) to update
- * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
- * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
- *
- * This exists as a separate routine to allow for special locking etc.
- * It's used for both the full cleanup on exit, as well as the normal
- * setup and teardown.
- */
-static void ipath_ht_put_tid(struct ipath_devdata *dd,
-                            u64 __iomem *tidptr, u32 type,
-                            unsigned long pa)
-{
-       if (!dd->ipath_kregbase)
-               return;
-
-       if (pa != dd->ipath_tidinvalid) {
-               if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {
-                       dev_info(&dd->pcidev->dev,
-                                "physaddr %lx has more than "
-                                "40 bits, using only 40!!!\n", pa);
-                       pa &= INFINIPATH_RT_ADDR_MASK;
-               }
-               if (type == RCVHQ_RCV_TYPE_EAGER)
-                       pa |= dd->ipath_tidtemplate;
-               else {
-                       /* in words (fixed, full page).  */
-                       u64 lenvalid = PAGE_SIZE >> 2;
-                       lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT;
-                       pa |= lenvalid | INFINIPATH_RT_VALID;
-               }
-       }
-
-       writeq(pa, tidptr);
-}
-
-
-/**
- * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager
- * @dd: the infinipath device
- * @port: the port
- *
- * Used from ipath_close(), and at chip initialization.
- */
-static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port)
-{
-       u64 __iomem *tidbase;
-       int i;
-
-       if (!dd->ipath_kregbase)
-               return;
-
-       ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);
-
-       /*
-        * need to invalidate all of the expected TID entries for this
-        * port, so we don't have valid entries that might somehow get
-        * used (early in next use of this port, or through some bug)
-        */
-       tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
-                                  dd->ipath_rcvtidbase +
-                                  port * dd->ipath_rcvtidcnt *
-                                  sizeof(*tidbase));
-       for (i = 0; i < dd->ipath_rcvtidcnt; i++)
-               ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
-                                dd->ipath_tidinvalid);
-
-       tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
-                                  dd->ipath_rcvegrbase +
-                                  port * dd->ipath_rcvegrcnt *
-                                  sizeof(*tidbase));
-
-       for (i = 0; i < dd->ipath_rcvegrcnt; i++)
-               ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
-                                dd->ipath_tidinvalid);
-}
-
-/**
- * ipath_ht_tidtemplate - setup constants for TID updates
- * @dd: the infinipath device
- *
- * We setup stuff that we use a lot, to avoid calculating each time
- */
-static void ipath_ht_tidtemplate(struct ipath_devdata *dd)
-{
-       dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2;
-       dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT;
-       dd->ipath_tidtemplate |= INFINIPATH_RT_VALID;
-
-       /*
-        * work around chip errata bug 7358, by marking invalid tids
-        * as having max length
-        */
-       dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) <<
-               INFINIPATH_RT_BUFSIZE_SHIFT;
-}
-
-static int ipath_ht_early_init(struct ipath_devdata *dd)
-{
-       u32 __iomem *piobuf;
-       u32 pioincr, val32;
-       int i;
-
-       /*
-        * one cache line; long IB headers will spill over into received
-        * buffer
-        */
-       dd->ipath_rcvhdrentsize = 16;
-       dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
-
-       /*
-        * For HT, we allocate a somewhat overly large eager buffer,
-        * such that we can guarantee that we can receive the largest
-        * packet that we can send out.  To truly support a 4KB MTU,
-        * we need to bump this to a large value.  To date, other than
-        * testing, we have never encountered an HCA that can really
-        * send 4KB MTU packets, so we do not handle that (we'll get
-        * errors interrupts if we ever see one).
-        */
-       dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;
-
-       /*
-        * the min() check here is currently a nop, but it may not
-        * always be, depending on just how we do ipath_rcvegrbufsize
-        */
-       dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,
-                                dd->ipath_rcvegrbufsize);
-       dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
-       ipath_ht_tidtemplate(dd);
-
-       /*
-        * zero all the TID entries at startup.  We do this for sanity,
-        * in case of a previous driver crash of some kind, and also
-        * because the chip powers up with these memories in an unknown
-        * state.  Use portcnt, not cfgports, since this is for the
-        * full chip, not for current (possibly different) configuration
-        * value.
-        * Chip Errata bug 6447
-        */
-       for (val32 = 0; val32 < dd->ipath_portcnt; val32++)
-               ipath_ht_clear_tids(dd, val32);
-
-       /*
-        * write the pbc of each buffer, to be sure it's initialized, then
-        * cancel all the buffers, and also abort any packets that might
-        * have been in flight for some reason (the latter is for driver
-        * unload/reload, but isn't a bad idea at first init).  PIO send
-        * isn't enabled at this point, so there is no danger of sending
-        * these out on the wire.
-        * Chip Errata bug 6610
-        */
-       piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) +
-                                 dd->ipath_piobufbase);
-       pioincr = dd->ipath_palign / sizeof(*piobuf);
-       for (i = 0; i < dd->ipath_piobcnt2k; i++) {
-               /*
-                * reasonable word count, just to init pbc
-                */
-               writel(16, piobuf);
-               piobuf += pioincr;
-       }
-
-       ipath_get_eeprom_info(dd);
-       if (dd->ipath_boardrev == 5) {
-               /*
-                * Later production QHT7040 has same changes as QHT7140, so
-                * can use GPIO interrupts.  They have serial #'s starting
-                * with 128, rather than 112.
-                */
-               if (dd->ipath_serial[0] == '1' &&
-                   dd->ipath_serial[1] == '2' &&
-                   dd->ipath_serial[2] == '8')
-                       dd->ipath_flags |= IPATH_GPIO_INTR;
-               else {
-                       ipath_dev_err(dd, "Unsupported InfiniPath board "
-                               "(serial number %.16s)!\n",
-                               dd->ipath_serial);
-                       return 1;
-               }
-       }
-
-       if (dd->ipath_minrev >= 4) {
-               /* Rev4+ reports extra errors via internal GPIO pins */
-               dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
-               dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
-                                dd->ipath_gpio_mask);
-       }
-
-       return 0;
-}
-
-
-/**
- * ipath_init_ht_get_base_info - set chip-specific flags for user code
- * @dd: the infinipath device
- * @kbase: ipath_base_info pointer
- *
- * We set the PCIE flag because the lower bandwidth on PCIe vs
- * HyperTransport can affect some user packet algorithms.
- */
-static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
-{
-       struct ipath_base_info *kinfo = kbase;
-
-       kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
-               IPATH_RUNTIME_PIO_REGSWAPPED;
-
-       if (pd->port_dd->ipath_minrev < 4)
-               kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY;
-
-       return 0;
-}
-
-static void ipath_ht_free_irq(struct ipath_devdata *dd)
-{
-       free_irq(dd->ipath_irq, dd);
-       ht_destroy_irq(dd->ipath_irq);
-       dd->ipath_irq = 0;
-       dd->ipath_intconfig = 0;
-}
-
-static struct ipath_message_header *
-ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
-{
-       return (struct ipath_message_header *)
-               &rhf_addr[sizeof(u64) / sizeof(u32)];
-}
-
-static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
-{
-       dd->ipath_portcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
-       dd->ipath_p0_rcvegrcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-}
-
-static void ipath_ht_read_counters(struct ipath_devdata *dd,
-                                  struct infinipath_counters *cntrs)
-{
-       cntrs->LBIntCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
-       cntrs->LBFlowStallCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
-       cntrs->TxSDmaDescCnt = 0;
-       cntrs->TxUnsupVLErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
-       cntrs->TxDataPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
-       cntrs->TxFlowPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
-       cntrs->TxDwordCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
-       cntrs->TxLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
-       cntrs->TxMaxMinLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
-       cntrs->TxUnderrunCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
-       cntrs->TxFlowStallCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
-       cntrs->TxDroppedPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
-       cntrs->RxDroppedPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
-       cntrs->RxDataPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
-       cntrs->RxFlowPktCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
-       cntrs->RxDwordCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
-       cntrs->RxLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
-       cntrs->RxMaxMinLenErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
-       cntrs->RxICRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
-       cntrs->RxVCRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
-       cntrs->RxFlowCtrlErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
-       cntrs->RxBadFormatCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
-       cntrs->RxLinkProblemCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
-       cntrs->RxEBPCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
-       cntrs->RxLPCRCErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
-       cntrs->RxBufOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
-       cntrs->RxTIDFullErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
-       cntrs->RxTIDValidErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
-       cntrs->RxPKeyMismatchCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
-       cntrs->RxP0HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
-       cntrs->RxP1HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
-       cntrs->RxP2HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
-       cntrs->RxP3HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
-       cntrs->RxP4HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
-       cntrs->RxP5HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
-       cntrs->RxP6HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
-       cntrs->RxP7HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
-       cntrs->RxP8HdrEgrOvflCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
-       cntrs->RxP9HdrEgrOvflCnt = 0;
-       cntrs->RxP10HdrEgrOvflCnt = 0;
-       cntrs->RxP11HdrEgrOvflCnt = 0;
-       cntrs->RxP12HdrEgrOvflCnt = 0;
-       cntrs->RxP13HdrEgrOvflCnt = 0;
-       cntrs->RxP14HdrEgrOvflCnt = 0;
-       cntrs->RxP15HdrEgrOvflCnt = 0;
-       cntrs->RxP16HdrEgrOvflCnt = 0;
-       cntrs->IBStatusChangeCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
-       cntrs->IBLinkErrRecoveryCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
-       cntrs->IBLinkDownedCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
-       cntrs->IBSymbolErrCnt =
-               ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
-       cntrs->RxVL15DroppedPktCnt = 0;
-       cntrs->RxOtherLocalPhyErrCnt = 0;
-       cntrs->PcieRetryBufDiagQwordCnt = 0;
-       cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
-       cntrs->LocalLinkIntegrityErrCnt =
-               (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
-               dd->ipath_lli_errs : dd->ipath_lli_errors;
-       cntrs->RxVlErrCnt = 0;
-       cntrs->RxDlidFltrCnt = 0;
-}
-
-
-/* no interrupt fallback for these chips */
-static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
-{
-       return 0;
-}
-
-
-/*
- * reset the XGXS (between serdes and IBC).  Slightly less intrusive
- * than resetting the IBC or external link state, and useful in some
- * cases to cause some retraining.  To do this right, we reset IBC
- * as well.
- */
-static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
-{
-       u64 val, prev_val;
-
-       prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-       val = prev_val | INFINIPATH_XGXS_RESET;
-       prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
-       ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control);
-}
-
-
-static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
-{
-       int ret;
-
-       switch (which) {
-       case IPATH_IB_CFG_LWID:
-               ret = dd->ipath_link_width_active;
-               break;
-       case IPATH_IB_CFG_SPD:
-               ret = dd->ipath_link_speed_active;
-               break;
-       case IPATH_IB_CFG_LWID_ENB:
-               ret = dd->ipath_link_width_enabled;
-               break;
-       case IPATH_IB_CFG_SPD_ENB:
-               ret = dd->ipath_link_speed_enabled;
-               break;
-       default:
-               ret =  -ENOTSUPP;
-               break;
-       }
-       return ret;
-}
-
-
-/* we assume range checking is already done, if needed */
-static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
-{
-       int ret = 0;
-
-       if (which == IPATH_IB_CFG_LWID_ENB)
-               dd->ipath_link_width_enabled = val;
-       else if (which == IPATH_IB_CFG_SPD_ENB)
-               dd->ipath_link_speed_enabled = val;
-       else
-               ret = -ENOTSUPP;
-       return ret;
-}
-
-
-static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
-{
-}
-
-
-static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
-{
-       ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
-               ipath_ib_linktrstate(dd, ibcs));
-       return 0;
-}
-
-
-/**
- * ipath_init_iba6110_funcs - set up the chip-specific function pointers
- * @dd: the infinipath device
- *
- * This is global, and is called directly at init to set up the
- * chip-specific function pointers for later use.
- */
-void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
-{
-       dd->ipath_f_intrsetup = ipath_ht_intconfig;
-       dd->ipath_f_bus = ipath_setup_ht_config;
-       dd->ipath_f_reset = ipath_setup_ht_reset;
-       dd->ipath_f_get_boardname = ipath_ht_boardname;
-       dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;
-       dd->ipath_f_early_init = ipath_ht_early_init;
-       dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors;
-       dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes;
-       dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes;
-       dd->ipath_f_clear_tids = ipath_ht_clear_tids;
-       dd->ipath_f_put_tid = ipath_ht_put_tid;
-       dd->ipath_f_cleanup = ipath_setup_ht_cleanup;
-       dd->ipath_f_setextled = ipath_setup_ht_setextled;
-       dd->ipath_f_get_base_info = ipath_ht_get_base_info;
-       dd->ipath_f_free_irq = ipath_ht_free_irq;
-       dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
-       dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
-       dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
-       dd->ipath_f_config_ports = ipath_ht_config_ports;
-       dd->ipath_f_read_counters = ipath_ht_read_counters;
-       dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
-       dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
-       dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
-       dd->ipath_f_config_jint = ipath_ht_config_jint;
-       dd->ipath_f_ib_updown = ipath_ht_ib_updown;
-
-       /*
-        * initialize chip-specific variables
-        */
-       ipath_init_ht_variables(dd);
-}
diff --git a/drivers/staging/rdma/ipath/ipath_init_chip.c b/drivers/staging/rdma/ipath/ipath_init_chip.c
deleted file mode 100644 (file)
index a5eea19..0000000
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/moduleparam.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/vmalloc.h>
-
-#include "ipath_kernel.h"
-#include "ipath_common.h"
-
-/*
- * min buffers we want to have per port, after driver
- */
-#define IPATH_MIN_USER_PORT_BUFCNT 7
-
-/*
- * Number of ports we are configured to use (to allow for more pio
- * buffers per port, etc.)  Zero means use chip value.
- */
-static ushort ipath_cfgports;
-
-module_param_named(cfgports, ipath_cfgports, ushort, S_IRUGO);
-MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
-
-/*
- * Number of buffers reserved for driver (verbs and layered drivers.)
- * Initialized based on number of PIO buffers if not set via module interface.
- * The problem with this is that it's global, but we'll use different
- * numbers for different chip types.
- */
-static ushort ipath_kpiobufs;
-
-static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp);
-
-module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_ushort,
-                 &ipath_kpiobufs, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver");
-
-/**
- * create_port0_egr - allocate the eager TID buffers
- * @dd: the infinipath device
- *
- * This code is now quite different for user and kernel, because
- * the kernel uses skb's, for the accelerated network performance.
- * This is the kernel (port0) version.
- *
- * Allocate the eager TID buffers and program them into infinipath.
- * We use the network layer alloc_skb() allocator to allocate the
- * memory, and either use the buffers as is for things like verbs
- * packets, or pass the buffers up to the ipath layered driver and
- * thence the network layer, replacing them as we do so (see
- * ipath_rcv_layer()).
- */
-static int create_port0_egr(struct ipath_devdata *dd)
-{
-       unsigned e, egrcnt;
-       struct ipath_skbinfo *skbinfo;
-       int ret;
-
-       egrcnt = dd->ipath_p0_rcvegrcnt;
-
-       skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
-       if (skbinfo == NULL) {
-               ipath_dev_err(dd, "allocation error for eager TID "
-                             "skb array\n");
-               ret = -ENOMEM;
-               goto bail;
-       }
-       for (e = 0; e < egrcnt; e++) {
-               /*
-                * This is a bit tricky in that we allocate extra
-                * space for 2 bytes of the 14 byte ethernet header.
-                * These two bytes are passed in the ipath header so
-                * the rest of the data is word aligned.  We allocate
-                * 4 bytes so that the data buffer stays word aligned.
-                * See ipath_kreceive() for more details.
-                */
-               skbinfo[e].skb = ipath_alloc_skb(dd, GFP_KERNEL);
-               if (!skbinfo[e].skb) {
-                       ipath_dev_err(dd, "SKB allocation error for "
-                                     "eager TID %u\n", e);
-                       while (e != 0)
-                               dev_kfree_skb(skbinfo[--e].skb);
-                       vfree(skbinfo);
-                       ret = -ENOMEM;
-                       goto bail;
-               }
-       }
-       /*
-        * After loop above, so we can test non-NULL to see if ready
-        * to use at receive, etc.
-        */
-       dd->ipath_port0_skbinfo = skbinfo;
-
-       for (e = 0; e < egrcnt; e++) {
-               dd->ipath_port0_skbinfo[e].phys =
-                 ipath_map_single(dd->pcidev,
-                                  dd->ipath_port0_skbinfo[e].skb->data,
-                                  dd->ipath_ibmaxlen, PCI_DMA_FROMDEVICE);
-               dd->ipath_f_put_tid(dd, e + (u64 __iomem *)
-                                   ((char __iomem *) dd->ipath_kregbase +
-                                    dd->ipath_rcvegrbase),
-                                   RCVHQ_RCV_TYPE_EAGER,
-                                   dd->ipath_port0_skbinfo[e].phys);
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-static int bringup_link(struct ipath_devdata *dd)
-{
-       u64 val, ibc;
-       int ret = 0;
-
-       /* hold IBC in reset */
-       dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control);
-
-       /*
-        * set initial max size pkt IBC will send, including ICRC; it's the
-        * PIO buffer size in dwords, less 1; also see ipath_set_mtu()
-        */
-       val = (dd->ipath_ibmaxlen >> 2) + 1;
-       ibc = val << dd->ibcc_mpl_shift;
-
-       /* flowcontrolwatermark is in units of KBytes */
-       ibc |= 0x5ULL << INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT;
-       /*
-        * How often flowctrl sent.  More or less in usecs; balance against
-        * watermark value, so that in theory senders always get a flow
-        * control update in time to not let the IB link go idle.
-        */
-       ibc |= 0x3ULL << INFINIPATH_IBCC_FLOWCTRLPERIOD_SHIFT;
-       /* max error tolerance */
-       ibc |= 0xfULL << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
-       /* use "real" buffer space for */
-       ibc |= 4ULL << INFINIPATH_IBCC_CREDITSCALE_SHIFT;
-       /* IB credit flow control. */
-       ibc |= 0xfULL << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
-       /* initially come up waiting for TS1, without sending anything. */
-       dd->ipath_ibcctrl = ibc;
-       /*
-        * Want to start out with both LINKCMD and LINKINITCMD in NOP
-        * (0 and 0).  Don't put linkinitcmd in ipath_ibcctrl, want that
-        * to stay a NOP. Flag that we are disabled, for the (unlikely)
-        * case that some recovery path is trying to bring the link up
-        * before we are ready.
-        */
-       ibc |= INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
-               INFINIPATH_IBCC_LINKINITCMD_SHIFT;
-       dd->ipath_flags |= IPATH_IB_LINK_DISABLED;
-       ipath_cdbg(VERBOSE, "Writing 0x%llx to ibcctrl\n",
-                  (unsigned long long) ibc);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, ibc);
-
-       // be sure chip saw it
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-
-       ret = dd->ipath_f_bringup_serdes(dd);
-
-       if (ret)
-               dev_info(&dd->pcidev->dev, "Could not initialize SerDes, "
-                        "not usable\n");
-       else {
-               /* enable IBC */
-               dd->ipath_control |= INFINIPATH_C_LINKENABLE;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                                dd->ipath_control);
-       }
-
-       return ret;
-}
-
-static struct ipath_portdata *create_portdata0(struct ipath_devdata *dd)
-{
-       struct ipath_portdata *pd;
-
-       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
-       if (pd) {
-               pd->port_dd = dd;
-               pd->port_cnt = 1;
-               /* The port 0 pkey table is used by the layer interface. */
-               pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
-               pd->port_seq_cnt = 1;
-       }
-       return pd;
-}
-
-static int init_chip_first(struct ipath_devdata *dd)
-{
-       struct ipath_portdata *pd;
-       int ret = 0;
-       u64 val;
-
-       spin_lock_init(&dd->ipath_kernel_tid_lock);
-       spin_lock_init(&dd->ipath_user_tid_lock);
-       spin_lock_init(&dd->ipath_sendctrl_lock);
-       spin_lock_init(&dd->ipath_uctxt_lock);
-       spin_lock_init(&dd->ipath_sdma_lock);
-       spin_lock_init(&dd->ipath_gpio_lock);
-       spin_lock_init(&dd->ipath_eep_st_lock);
-       spin_lock_init(&dd->ipath_sdepb_lock);
-       mutex_init(&dd->ipath_eep_lock);
-
-       /*
-        * skip cfgports stuff because we are not allocating memory,
-        * and we don't want problems if the portcnt changed due to
-        * cfgports.  We do still check and report a difference, if
-        * not same (should be impossible).
-        */
-       dd->ipath_f_config_ports(dd, ipath_cfgports);
-       if (!ipath_cfgports)
-               dd->ipath_cfgports = dd->ipath_portcnt;
-       else if (ipath_cfgports <= dd->ipath_portcnt) {
-               dd->ipath_cfgports = ipath_cfgports;
-               ipath_dbg("Configured to use %u ports out of %u in chip\n",
-                         dd->ipath_cfgports, ipath_read_kreg32(dd,
-                         dd->ipath_kregs->kr_portcnt));
-       } else {
-               dd->ipath_cfgports = dd->ipath_portcnt;
-               ipath_dbg("Tried to configured to use %u ports; chip "
-                         "only supports %u\n", ipath_cfgports,
-                         ipath_read_kreg32(dd,
-                                 dd->ipath_kregs->kr_portcnt));
-       }
-       /*
-        * Allocate full portcnt array, rather than just cfgports, because
-        * cleanup iterates across all possible ports.
-        */
-       dd->ipath_pd = kcalloc(dd->ipath_portcnt, sizeof(*dd->ipath_pd),
-                              GFP_KERNEL);
-
-       if (!dd->ipath_pd) {
-               ipath_dev_err(dd, "Unable to allocate portdata array, "
-                             "failing\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       pd = create_portdata0(dd);
-       if (!pd) {
-               ipath_dev_err(dd, "Unable to allocate portdata for port "
-                             "0, failing\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-       dd->ipath_pd[0] = pd;
-
-       dd->ipath_rcvtidcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
-       dd->ipath_rcvtidbase =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidbase);
-       dd->ipath_rcvegrcnt =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-       dd->ipath_rcvegrbase =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrbase);
-       dd->ipath_palign =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
-       dd->ipath_piobufbase =
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiobufbase);
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiosize);
-       dd->ipath_piosize2k = val & ~0U;
-       dd->ipath_piosize4k = val >> 32;
-       if (dd->ipath_piosize4k == 0 && ipath_mtu4096)
-               ipath_mtu4096 = 0; /* 4KB not supported by this chip */
-       dd->ipath_ibmtu = ipath_mtu4096 ? 4096 : 2048;
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiobufcnt);
-       dd->ipath_piobcnt2k = val & ~0U;
-       dd->ipath_piobcnt4k = val >> 32;
-       dd->ipath_pio2kbase =
-               (u32 __iomem *) (((char __iomem *) dd->ipath_kregbase) +
-                                (dd->ipath_piobufbase & 0xffffffff));
-       if (dd->ipath_piobcnt4k) {
-               dd->ipath_pio4kbase = (u32 __iomem *)
-                       (((char __iomem *) dd->ipath_kregbase) +
-                        (dd->ipath_piobufbase >> 32));
-               /*
-                * 4K buffers take 2 pages; we use roundup just to be
-                * paranoid; we calculate it once here, rather than on
-                * ever buf allocate
-                */
-               dd->ipath_4kalign = ALIGN(dd->ipath_piosize4k,
-                                         dd->ipath_palign);
-               ipath_dbg("%u 2k(%x) piobufs @ %p, %u 4k(%x) @ %p "
-                         "(%x aligned)\n",
-                         dd->ipath_piobcnt2k, dd->ipath_piosize2k,
-                         dd->ipath_pio2kbase, dd->ipath_piobcnt4k,
-                         dd->ipath_piosize4k, dd->ipath_pio4kbase,
-                         dd->ipath_4kalign);
-       } else {
-               ipath_dbg("%u 2k piobufs @ %p\n",
-                         dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
-       }
-done:
-       return ret;
-}
-
-/**
- * init_chip_reset - re-initialize after a reset, or enable
- * @dd: the infinipath device
- *
- * sanity check at least some of the values after reset, and
- * ensure no receive or transmit (explicitly, in case reset
- * failed
- */
-static int init_chip_reset(struct ipath_devdata *dd)
-{
-       u32 rtmp;
-       int i;
-       unsigned long flags;
-
-       /*
-        * ensure chip does no sends or receives, tail updates, or
-        * pioavail updates while we re-initialize
-        */
-       dd->ipath_rcvctrl &= ~(1ULL << dd->ipath_r_tailupd_shift);
-       for (i = 0; i < dd->ipath_portcnt; i++) {
-               clear_bit(dd->ipath_r_portenable_shift + i,
-                         &dd->ipath_rcvctrl);
-               clear_bit(dd->ipath_r_intravail_shift + i,
-                         &dd->ipath_rcvctrl);
-       }
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-               dd->ipath_rcvctrl);
-
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl = 0U; /* no sdma, etc */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
-
-       rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
-       if (rtmp != dd->ipath_rcvtidcnt)
-               dev_info(&dd->pcidev->dev, "tidcnt was %u before "
-                        "reset, now %u, using original\n",
-                        dd->ipath_rcvtidcnt, rtmp);
-       rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidbase);
-       if (rtmp != dd->ipath_rcvtidbase)
-               dev_info(&dd->pcidev->dev, "tidbase was %u before "
-                        "reset, now %u, using original\n",
-                        dd->ipath_rcvtidbase, rtmp);
-       rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
-       if (rtmp != dd->ipath_rcvegrcnt)
-               dev_info(&dd->pcidev->dev, "egrcnt was %u before "
-                        "reset, now %u, using original\n",
-                        dd->ipath_rcvegrcnt, rtmp);
-       rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrbase);
-       if (rtmp != dd->ipath_rcvegrbase)
-               dev_info(&dd->pcidev->dev, "egrbase was %u before "
-                        "reset, now %u, using original\n",
-                        dd->ipath_rcvegrbase, rtmp);
-
-       return 0;
-}
-
-static int init_pioavailregs(struct ipath_devdata *dd)
-{
-       int ret;
-
-       dd->ipath_pioavailregs_dma = dma_alloc_coherent(
-               &dd->pcidev->dev, PAGE_SIZE, &dd->ipath_pioavailregs_phys,
-               GFP_KERNEL);
-       if (!dd->ipath_pioavailregs_dma) {
-               ipath_dev_err(dd, "failed to allocate PIOavail reg area "
-                             "in memory\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       /*
-        * we really want L2 cache aligned, but for current CPUs of
-        * interest, they are the same.
-        */
-       dd->ipath_statusp = (u64 *)
-               ((char *)dd->ipath_pioavailregs_dma +
-                ((2 * L1_CACHE_BYTES +
-                  dd->ipath_pioavregs * sizeof(u64)) & ~L1_CACHE_BYTES));
-       /* copy the current value now that it's really allocated */
-       *dd->ipath_statusp = dd->_ipath_status;
-       /*
-        * setup buffer to hold freeze msg, accessible to apps,
-        * following statusp
-        */
-       dd->ipath_freezemsg = (char *)&dd->ipath_statusp[1];
-       /* and its length */
-       dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]);
-
-       ret = 0;
-
-done:
-       return ret;
-}
-
-/**
- * init_shadow_tids - allocate the shadow TID array
- * @dd: the infinipath device
- *
- * allocate the shadow TID array, so we can ipath_munlock previous
- * entries.  It may make more sense to move the pageshadow to the
- * port data structure, so we only allocate memory for ports actually
- * in use, since we at 8k per port, now.
- */
-static void init_shadow_tids(struct ipath_devdata *dd)
-{
-       struct page **pages;
-       dma_addr_t *addrs;
-
-       pages = vzalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
-                       sizeof(struct page *));
-       if (!pages) {
-               ipath_dev_err(dd, "failed to allocate shadow page * "
-                             "array, no expected sends!\n");
-               dd->ipath_pageshadow = NULL;
-               return;
-       }
-
-       addrs = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
-                       sizeof(dma_addr_t));
-       if (!addrs) {
-               ipath_dev_err(dd, "failed to allocate shadow dma handle "
-                             "array, no expected sends!\n");
-               vfree(pages);
-               dd->ipath_pageshadow = NULL;
-               return;
-       }
-
-       dd->ipath_pageshadow = pages;
-       dd->ipath_physshadow = addrs;
-}
-
-static void enable_chip(struct ipath_devdata *dd, int reinit)
-{
-       u32 val;
-       u64 rcvmask;
-       unsigned long flags;
-       int i;
-
-       if (!reinit)
-               init_waitqueue_head(&ipath_state_wait);
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       /* Enable PIO send, and update of PIOavail regs to memory. */
-       dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
-               INFINIPATH_S_PIOBUFAVAILUPD;
-
-       /*
-        * Set the PIO avail update threshold to host memory
-        * on chips that support it.
-        */
-       if (dd->ipath_pioupd_thresh)
-               dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
-                       << INFINIPATH_S_UPDTHRESH_SHIFT;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       /*
-        * Enable kernel ports' receive and receive interrupt.
-        * Other ports done as user opens and inits them.
-        */
-       rcvmask = 1ULL;
-       dd->ipath_rcvctrl |= (rcvmask << dd->ipath_r_portenable_shift) |
-               (rcvmask << dd->ipath_r_intravail_shift);
-       if (!(dd->ipath_flags & IPATH_NODMA_RTAIL))
-               dd->ipath_rcvctrl |= (1ULL << dd->ipath_r_tailupd_shift);
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                        dd->ipath_rcvctrl);
-
-       /*
-        * now ready for use.  this should be cleared whenever we
-        * detect a reset, or initiate one.
-        */
-       dd->ipath_flags |= IPATH_INITTED;
-
-       /*
-        * Init our shadow copies of head from tail values,
-        * and write head values to match.
-        */
-       val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
-       ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
-
-       /* Initialize so we interrupt on next packet received */
-       ipath_write_ureg(dd, ur_rcvhdrhead,
-                        dd->ipath_rhdrhead_intr_off |
-                        dd->ipath_pd[0]->port_head, 0);
-
-       /*
-        * by now pioavail updates to memory should have occurred, so
-        * copy them into our working/shadow registers; this is in
-        * case something went wrong with abort, but mostly to get the
-        * initial values of the generation bit correct.
-        */
-       for (i = 0; i < dd->ipath_pioavregs; i++) {
-               __le64 pioavail;
-
-               /*
-                * Chip Errata bug 6641; even and odd qwords>3 are swapped.
-                */
-               if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
-                       pioavail = dd->ipath_pioavailregs_dma[i ^ 1];
-               else
-                       pioavail = dd->ipath_pioavailregs_dma[i];
-               /*
-                * don't need to worry about ipath_pioavailkernel here
-                * because we will call ipath_chg_pioavailkernel() later
-                * in initialization, to busy out buffers as needed
-                */
-               dd->ipath_pioavailshadow[i] = le64_to_cpu(pioavail);
-       }
-       /* can get counters, stats, etc. */
-       dd->ipath_flags |= IPATH_PRESENT;
-}
-
-static int init_housekeeping(struct ipath_devdata *dd, int reinit)
-{
-       char boardn[40];
-       int ret = 0;
-
-       /*
-        * have to clear shadow copies of registers at init that are
-        * not otherwise set here, or all kinds of bizarre things
-        * happen with driver on chip reset
-        */
-       dd->ipath_rcvhdrsize = 0;
-
-       /*
-        * Don't clear ipath_flags as 8bit mode was set before
-        * entering this func. However, we do set the linkstate to
-        * unknown, so we can watch for a transition.
-        * PRESENT is set because we want register reads to work,
-        * and the kernel infrastructure saw it in config space;
-        * We clear it if we have failures.
-        */
-       dd->ipath_flags |= IPATH_LINKUNK | IPATH_PRESENT;
-       dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED |
-                            IPATH_LINKDOWN | IPATH_LINKINIT);
-
-       ipath_cdbg(VERBOSE, "Try to read spc chip revision\n");
-       dd->ipath_revision =
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);
-
-       /*
-        * set up fundamental info we need to use the chip; we assume
-        * if the revision reg and these regs are OK, we don't need to
-        * special case the rest
-        */
-       dd->ipath_sregbase =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_sendregbase);
-       dd->ipath_cregbase =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_counterregbase);
-       dd->ipath_uregbase =
-               ipath_read_kreg32(dd, dd->ipath_kregs->kr_userregbase);
-       ipath_cdbg(VERBOSE, "ipath_kregbase %p, sendbase %x usrbase %x, "
-                  "cntrbase %x\n", dd->ipath_kregbase, dd->ipath_sregbase,
-                  dd->ipath_uregbase, dd->ipath_cregbase);
-       if ((dd->ipath_revision & 0xffffffff) == 0xffffffff
-           || (dd->ipath_sregbase & 0xffffffff) == 0xffffffff
-           || (dd->ipath_cregbase & 0xffffffff) == 0xffffffff
-           || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) {
-               ipath_dev_err(dd, "Register read failures from chip, "
-                             "giving up initialization\n");
-               dd->ipath_flags &= ~IPATH_PRESENT;
-               ret = -ENODEV;
-               goto done;
-       }
-
-
-       /* clear diagctrl register, in case diags were running and crashed */
-       ipath_write_kreg (dd, dd->ipath_kregs->kr_hwdiagctrl, 0);
-
-       /* clear the initial reset flag, in case first driver load */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
-                        INFINIPATH_E_RESET);
-
-       ipath_cdbg(VERBOSE, "Revision %llx (PCI %x)\n",
-                  (unsigned long long) dd->ipath_revision,
-                  dd->ipath_pcirev);
-
-       if (((dd->ipath_revision >> INFINIPATH_R_SOFTWARE_SHIFT) &
-            INFINIPATH_R_SOFTWARE_MASK) != IPATH_CHIP_SWVERSION) {
-               ipath_dev_err(dd, "Driver only handles version %d, "
-                             "chip swversion is %d (%llx), failng\n",
-                             IPATH_CHIP_SWVERSION,
-                             (int)(dd->ipath_revision >>
-                                   INFINIPATH_R_SOFTWARE_SHIFT) &
-                             INFINIPATH_R_SOFTWARE_MASK,
-                             (unsigned long long) dd->ipath_revision);
-               ret = -ENOSYS;
-               goto done;
-       }
-       dd->ipath_majrev = (u8) ((dd->ipath_revision >>
-                                 INFINIPATH_R_CHIPREVMAJOR_SHIFT) &
-                                INFINIPATH_R_CHIPREVMAJOR_MASK);
-       dd->ipath_minrev = (u8) ((dd->ipath_revision >>
-                                 INFINIPATH_R_CHIPREVMINOR_SHIFT) &
-                                INFINIPATH_R_CHIPREVMINOR_MASK);
-       dd->ipath_boardrev = (u8) ((dd->ipath_revision >>
-                                   INFINIPATH_R_BOARDID_SHIFT) &
-                                  INFINIPATH_R_BOARDID_MASK);
-
-       ret = dd->ipath_f_get_boardname(dd, boardn, sizeof boardn);
-
-       snprintf(dd->ipath_boardversion, sizeof(dd->ipath_boardversion),
-                "ChipABI %u.%u, %s, InfiniPath%u %u.%u, PCI %u, "
-                "SW Compat %u\n",
-                IPATH_CHIP_VERS_MAJ, IPATH_CHIP_VERS_MIN, boardn,
-                (unsigned)(dd->ipath_revision >> INFINIPATH_R_ARCH_SHIFT) &
-                INFINIPATH_R_ARCH_MASK,
-                dd->ipath_majrev, dd->ipath_minrev, dd->ipath_pcirev,
-                (unsigned)(dd->ipath_revision >>
-                           INFINIPATH_R_SOFTWARE_SHIFT) &
-                INFINIPATH_R_SOFTWARE_MASK);
-
-       ipath_dbg("%s", dd->ipath_boardversion);
-
-       if (ret)
-               goto done;
-
-       if (reinit)
-               ret = init_chip_reset(dd);
-       else
-               ret = init_chip_first(dd);
-
-done:
-       return ret;
-}
-
-static void verify_interrupt(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
-
-       if (!dd)
-               return; /* being torn down */
-
-       /*
-        * If we don't have any interrupts, let the user know and
-        * don't bother checking again.
-        */
-       if (dd->ipath_int_counter == 0) {
-               if (!dd->ipath_f_intr_fallback(dd))
-                       dev_err(&dd->pcidev->dev, "No interrupts detected, "
-                               "not usable.\n");
-               else /* re-arm the timer to see if fallback works */
-                       mod_timer(&dd->ipath_intrchk_timer, jiffies + HZ/2);
-       } else
-               ipath_cdbg(VERBOSE, "%u interrupts at timer check\n",
-                       dd->ipath_int_counter);
-}
-
-/**
- * ipath_init_chip - do the actual initialization sequence on the chip
- * @dd: the infinipath device
- * @reinit: reinitializing, so don't allocate new memory
- *
- * Do the actual initialization sequence on the chip.  This is done
- * both from the init routine called from the PCI infrastructure, and
- * when we reset the chip, or detect that it was reset internally,
- * or it's administratively re-enabled.
- *
- * Memory allocation here and in called routines is only done in
- * the first case (reinit == 0).  We have to be careful, because even
- * without memory allocation, we need to re-write all the chip registers
- * TIDs, etc. after the reset or enable has completed.
- */
-int ipath_init_chip(struct ipath_devdata *dd, int reinit)
-{
-       int ret = 0;
-       u32 kpiobufs, defkbufs;
-       u32 piobufs, uports;
-       u64 val;
-       struct ipath_portdata *pd;
-       gfp_t gfp_flags = GFP_USER | __GFP_COMP;
-
-       ret = init_housekeeping(dd, reinit);
-       if (ret)
-               goto done;
-
-       /*
-        * We could bump this to allow for full rcvegrcnt + rcvtidcnt,
-        * but then it no longer nicely fits power of two, and since
-        * we now use routines that backend onto __get_free_pages, the
-        * rest would be wasted.
-        */
-       dd->ipath_rcvhdrcnt = max(dd->ipath_p0_rcvegrcnt, dd->ipath_rcvegrcnt);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrcnt,
-                        dd->ipath_rcvhdrcnt);
-
-       /*
-        * Set up the shadow copies of the piobufavail registers,
-        * which we compare against the chip registers for now, and
-        * the in memory DMA'ed copies of the registers.  This has to
-        * be done early, before we calculate lastport, etc.
-        */
-       piobufs = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
-       /*
-        * calc number of pioavail registers, and save it; we have 2
-        * bits per buffer.
-        */
-       dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2)
-               / (sizeof(u64) * BITS_PER_BYTE / 2);
-       uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
-       if (piobufs > 144)
-               defkbufs = 32 + dd->ipath_pioreserved;
-       else
-               defkbufs = 16 + dd->ipath_pioreserved;
-
-       if (ipath_kpiobufs && (ipath_kpiobufs +
-               (uports * IPATH_MIN_USER_PORT_BUFCNT)) > piobufs) {
-               int i = (int) piobufs -
-                       (int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
-               if (i < 1)
-                       i = 1;
-               dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of "
-                        "%d for kernel leaves too few for %d user ports "
-                        "(%d each); using %u\n", ipath_kpiobufs,
-                        piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i);
-               /*
-                * shouldn't change ipath_kpiobufs, because could be
-                * different for different devices...
-                */
-               kpiobufs = i;
-       } else if (ipath_kpiobufs)
-               kpiobufs = ipath_kpiobufs;
-       else
-               kpiobufs = defkbufs;
-       dd->ipath_lastport_piobuf = piobufs - kpiobufs;
-       dd->ipath_pbufsport =
-               uports ? dd->ipath_lastport_piobuf / uports : 0;
-       /* if not an even divisor, some user ports get extra buffers */
-       dd->ipath_ports_extrabuf = dd->ipath_lastport_piobuf -
-               (dd->ipath_pbufsport * uports);
-       if (dd->ipath_ports_extrabuf)
-               ipath_dbg("%u pbufs/port leaves some unused, add 1 buffer to "
-                       "ports <= %u\n", dd->ipath_pbufsport,
-                       dd->ipath_ports_extrabuf);
-       dd->ipath_lastpioindex = 0;
-       dd->ipath_lastpioindexl = dd->ipath_piobcnt2k;
-       /* ipath_pioavailshadow initialized earlier */
-       ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
-                  "each for %u user ports\n", kpiobufs,
-                  piobufs, dd->ipath_pbufsport, uports);
-       ret = dd->ipath_f_early_init(dd);
-       if (ret) {
-               ipath_dev_err(dd, "Early initialization failure\n");
-               goto done;
-       }
-
-       /*
-        * Early_init sets rcvhdrentsize and rcvhdrsize, so this must be
-        * done after early_init.
-        */
-       dd->ipath_hdrqlast =
-               dd->ipath_rcvhdrentsize * (dd->ipath_rcvhdrcnt - 1);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrentsize,
-                        dd->ipath_rcvhdrentsize);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrsize,
-                        dd->ipath_rcvhdrsize);
-
-       if (!reinit) {
-               ret = init_pioavailregs(dd);
-               init_shadow_tids(dd);
-               if (ret)
-                       goto done;
-       }
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendpioavailaddr,
-                        dd->ipath_pioavailregs_phys);
-
-       /*
-        * this is to detect s/w errors, which the h/w works around by
-        * ignoring the low 6 bits of address, if it wasn't aligned.
-        */
-       val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpioavailaddr);
-       if (val != dd->ipath_pioavailregs_phys) {
-               ipath_dev_err(dd, "Catastrophic software error, "
-                             "SendPIOAvailAddr written as %lx, "
-                             "read back as %llx\n",
-                             (unsigned long) dd->ipath_pioavailregs_phys,
-                             (unsigned long long) val);
-               ret = -EINVAL;
-               goto done;
-       }
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvbthqp, IPATH_KD_QP);
-
-       /*
-        * make sure we are not in freeze, and PIO send enabled, so
-        * writes to pbc happen
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, 0ULL);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
-
-       /*
-        * before error clears, since we expect serdes pll errors during
-        * this, the first time after reset
-        */
-       if (bringup_link(dd)) {
-               dev_info(&dd->pcidev->dev, "Failed to bringup IB link\n");
-               ret = -ENETDOWN;
-               goto done;
-       }
-
-       /*
-        * clear any "expected" hwerrs from reset and/or initialization
-        * clear any that aren't enabled (at least this once), and then
-        * set the enable mask
-        */
-       dd->ipath_f_init_hwerrors(dd);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
-                        ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
-                        dd->ipath_hwerrmask);
-
-       /* clear all */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);
-       /* enable errors that are masked, at least this first time. */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-                        ~dd->ipath_maskederrs);
-       dd->ipath_maskederrs = 0; /* don't re-enable ignored in timer */
-       dd->ipath_errormask =
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_errormask);
-       /* clear any interrupts up to this point (ints still not enabled) */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
-
-       dd->ipath_f_tidtemplate(dd);
-
-       /*
-        * Set up the port 0 (kernel) rcvhdr q and egr TIDs.  If doing
-        * re-init, the simplest way to handle this is to free
-        * existing, and re-allocate.
-        * Need to re-create rest of port 0 portdata as well.
-        */
-       pd = dd->ipath_pd[0];
-       if (reinit) {
-               struct ipath_portdata *npd;
-
-               /*
-                * Alloc and init new ipath_portdata for port0,
-                * Then free old pd. Could lead to fragmentation, but also
-                * makes later support for hot-swap easier.
-                */
-               npd = create_portdata0(dd);
-               if (npd) {
-                       ipath_free_pddata(dd, pd);
-                       dd->ipath_pd[0] = npd;
-                       pd = npd;
-               } else {
-                       ipath_dev_err(dd, "Unable to allocate portdata"
-                                     " for port 0, failing\n");
-                       ret = -ENOMEM;
-                       goto done;
-               }
-       }
-       ret = ipath_create_rcvhdrq(dd, pd);
-       if (!ret)
-               ret = create_port0_egr(dd);
-       if (ret) {
-               ipath_dev_err(dd, "failed to allocate kernel port's "
-                             "rcvhdrq and/or egr bufs\n");
-               goto done;
-       } else {
-               enable_chip(dd, reinit);
-       }
-
-       /* after enable_chip, so pioavailshadow setup */
-       ipath_chg_pioavailkernel(dd, 0, piobufs, 1);
-
-       /*
-        * Cancel any possible active sends from early driver load.
-        * Follows early_init because some chips have to initialize
-        * PIO buffers in early_init to avoid false parity errors.
-        * After enable and ipath_chg_pioavailkernel so we can safely
-        * enable pioavail updates and PIOENABLE; packets are now
-        * ready to go out.
-        */
-       ipath_cancel_sends(dd, 1);
-
-       if (!reinit) {
-               /*
-                * Used when we close a port, for DMA already in flight
-                * at close.
-                */
-               dd->ipath_dummy_hdrq = dma_alloc_coherent(
-                       &dd->pcidev->dev, dd->ipath_pd[0]->port_rcvhdrq_size,
-                       &dd->ipath_dummy_hdrq_phys,
-                       gfp_flags);
-               if (!dd->ipath_dummy_hdrq) {
-                       dev_info(&dd->pcidev->dev,
-                               "Couldn't allocate 0x%lx bytes for dummy hdrq\n",
-                               dd->ipath_pd[0]->port_rcvhdrq_size);
-                       /* fallback to just 0'ing */
-                       dd->ipath_dummy_hdrq_phys = 0UL;
-               }
-       }
-
-       /*
-        * cause retrigger of pending interrupts ignored during init,
-        * even if we had errors
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
-
-       if (!dd->ipath_stats_timer_active) {
-               /*
-                * first init, or after an admin disable/enable
-                * set up stats retrieval timer, even if we had errors
-                * in last portion of setup
-                */
-               setup_timer(&dd->ipath_stats_timer, ipath_get_faststats,
-                               (unsigned long)dd);
-               /* every 5 seconds; */
-               dd->ipath_stats_timer.expires = jiffies + 5 * HZ;
-               /* takes ~16 seconds to overflow at full IB 4x bandwdith */
-               add_timer(&dd->ipath_stats_timer);
-               dd->ipath_stats_timer_active = 1;
-       }
-
-       /* Set up SendDMA if chip supports it */
-       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-               ret = setup_sdma(dd);
-
-       /* Set up HoL state */
-       setup_timer(&dd->ipath_hol_timer, ipath_hol_event, (unsigned long)dd);
-
-       dd->ipath_hol_state = IPATH_HOL_UP;
-
-done:
-       if (!ret) {
-               *dd->ipath_statusp |= IPATH_STATUS_CHIP_PRESENT;
-               if (!dd->ipath_f_intrsetup(dd)) {
-                       /* now we can enable all interrupts from the chip */
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask,
-                                        -1LL);
-                       /* force re-interrupt of any pending interrupts. */
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear,
-                                        0ULL);
-                       /* chip is usable; mark it as initialized */
-                       *dd->ipath_statusp |= IPATH_STATUS_INITTED;
-
-                       /*
-                        * setup to verify we get an interrupt, and fallback
-                        * to an alternate if necessary and possible
-                        */
-                       if (!reinit) {
-                               setup_timer(&dd->ipath_intrchk_timer,
-                                               verify_interrupt,
-                                               (unsigned long)dd);
-                       }
-                       dd->ipath_intrchk_timer.expires = jiffies + HZ/2;
-                       add_timer(&dd->ipath_intrchk_timer);
-               } else
-                       ipath_dev_err(dd, "No interrupts enabled, couldn't "
-                                     "setup interrupt address\n");
-
-               if (dd->ipath_cfgports > ipath_stats.sps_nports)
-                       /*
-                        * sps_nports is a global, so, we set it to
-                        * the highest number of ports of any of the
-                        * chips we find; we never decrement it, at
-                        * least for now.  Since this might have changed
-                        * over disable/enable or prior to reset, always
-                        * do the check and potentially adjust.
-                        */
-                       ipath_stats.sps_nports = dd->ipath_cfgports;
-       } else
-               ipath_dbg("Failed (%d) to initialize chip\n", ret);
-
-       /* if ret is non-zero, we probably should do some cleanup
-          here... */
-       return ret;
-}
-
-static int ipath_set_kpiobufs(const char *str, struct kernel_param *kp)
-{
-       struct ipath_devdata *dd;
-       unsigned long flags;
-       unsigned short val;
-       int ret;
-
-       ret = ipath_parse_ushort(str, &val);
-
-       spin_lock_irqsave(&ipath_devs_lock, flags);
-
-       if (ret < 0)
-               goto bail;
-
-       if (val == 0) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       list_for_each_entry(dd, &ipath_dev_list, ipath_list) {
-               if (dd->ipath_kregbase)
-                       continue;
-               if (val > (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k -
-                          (dd->ipath_cfgports *
-                           IPATH_MIN_USER_PORT_BUFCNT)))
-               {
-                       ipath_dev_err(
-                               dd,
-                               "Allocating %d PIO bufs for kernel leaves "
-                               "too few for %d user ports (%d each)\n",
-                               val, dd->ipath_cfgports - 1,
-                               IPATH_MIN_USER_PORT_BUFCNT);
-                       ret = -EINVAL;
-                       goto bail;
-               }
-               dd->ipath_lastport_piobuf =
-                       dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val;
-       }
-
-       ipath_kpiobufs = val;
-       ret = 0;
-bail:
-       spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_intr.c b/drivers/staging/rdma/ipath/ipath_intr.c
deleted file mode 100644 (file)
index 0403fa2..0000000
+++ /dev/null
@@ -1,1271 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-
-/*
- * Called when we might have an error that is specific to a particular
- * PIO buffer, and may need to cancel that buffer, so it can be re-used.
- */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
-{
-       u32 piobcnt;
-       unsigned long sbuf[4];
-       /*
-        * it's possible that sendbuffererror could have bits set; might
-        * have already done this as a result of hardware error handling
-        */
-       piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
-       /* read these before writing errorclear */
-       sbuf[0] = ipath_read_kreg64(
-               dd, dd->ipath_kregs->kr_sendbuffererror);
-       sbuf[1] = ipath_read_kreg64(
-               dd, dd->ipath_kregs->kr_sendbuffererror + 1);
-       if (piobcnt > 128)
-               sbuf[2] = ipath_read_kreg64(
-                       dd, dd->ipath_kregs->kr_sendbuffererror + 2);
-       if (piobcnt > 192)
-               sbuf[3] = ipath_read_kreg64(
-                       dd, dd->ipath_kregs->kr_sendbuffererror + 3);
-       else
-               sbuf[3] = 0;
-
-       if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
-               int i;
-               if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) &&
-                       time_after(dd->ipath_lastcancel, jiffies)) {
-                       __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
-                                         "SendbufErrs %lx %lx", sbuf[0],
-                                         sbuf[1]);
-                       if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
-                               printk(" %lx %lx ", sbuf[2], sbuf[3]);
-                       printk("\n");
-               }
-
-               for (i = 0; i < piobcnt; i++)
-                       if (test_bit(i, sbuf))
-                               ipath_disarm_piobufs(dd, i, 1);
-               /* ignore armlaunch errs for a bit */
-               dd->ipath_lastcancel = jiffies+3;
-       }
-}
-
-
-/* These are all rcv-related errors which we want to count for stats */
-#define E_SUM_PKTERRS \
-       (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
-        INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \
-        INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | \
-        INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RMINPKTLEN | \
-        INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \
-        INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP)
-
-/* These are all send-related errors which we want to count for stats */
-#define E_SUM_ERRS \
-       (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \
-        INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
-        INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNSUPVL | \
-        INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
-        INFINIPATH_E_INVALIDADDR)
-
-/*
- * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
- * errors not related to freeze and cancelling buffers.  Can't ignore
- * armlaunch because could get more while still cleaning up, and need
- * to cancel those as they happen.
- */
-#define E_SPKT_ERRS_IGNORE \
-        (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
-        INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SMINPKTLEN | \
-        INFINIPATH_E_SPKTLEN)
-
-/*
- * these are errors that can occur when the link changes state while
- * a packet is being sent or received.  This doesn't cover things
- * like EBP or VCRC that can be the result of a sending having the
- * link change state, so we receive a "known bad" packet.
- */
-#define E_SUM_LINK_PKTERRS \
-       (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
-        INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
-        INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RMINPKTLEN | \
-        INFINIPATH_E_RUNEXPCHAR)
-
-static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
-{
-       u64 ignore_this_time = 0;
-
-       ipath_disarm_senderrbufs(dd);
-       if ((errs & E_SUM_LINK_PKTERRS) &&
-           !(dd->ipath_flags & IPATH_LINKACTIVE)) {
-               /*
-                * This can happen when SMA is trying to bring the link
-                * up, but the IB link changes state at the "wrong" time.
-                * The IB logic then complains that the packet isn't
-                * valid.  We don't want to confuse people, so we just
-                * don't print them, except at debug
-                */
-               ipath_dbg("Ignoring packet errors %llx, because link not "
-                         "ACTIVE\n", (unsigned long long) errs);
-               ignore_this_time = errs & E_SUM_LINK_PKTERRS;
-       }
-
-       return ignore_this_time;
-}
-
-/* generic hw error messages... */
-#define INFINIPATH_HWE_TXEMEMPARITYERR_MSG(a) \
-       { \
-               .mask = ( INFINIPATH_HWE_TXEMEMPARITYERR_##a <<    \
-                         INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT ),   \
-               .msg = "TXE " #a " Memory Parity"            \
-       }
-#define INFINIPATH_HWE_RXEMEMPARITYERR_MSG(a) \
-       { \
-               .mask = ( INFINIPATH_HWE_RXEMEMPARITYERR_##a <<    \
-                         INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT ),   \
-               .msg = "RXE " #a " Memory Parity"            \
-       }
-
-static const struct ipath_hwerror_msgs ipath_generic_hwerror_msgs[] = {
-       INFINIPATH_HWE_MSG(IBCBUSFRSPCPARITYERR, "IPATH2IB Parity"),
-       INFINIPATH_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2IPATH Parity"),
-
-       INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOBUF),
-       INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOPBC),
-       INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOLAUNCHFIFO),
-
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(RCVBUF),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(LOOKUPQ),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EAGERTID),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EXPTID),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(FLAGBUF),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(DATAINFO),
-       INFINIPATH_HWE_RXEMEMPARITYERR_MSG(HDRINFO),
-};
-
-/**
- * ipath_format_hwmsg - format a single hwerror message
- * @msg message buffer
- * @msgl length of message buffer
- * @hwmsg message to add to message buffer
- */
-static void ipath_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
-{
-       strlcat(msg, "[", msgl);
-       strlcat(msg, hwmsg, msgl);
-       strlcat(msg, "]", msgl);
-}
-
-/**
- * ipath_format_hwerrors - format hardware error messages for display
- * @hwerrs hardware errors bit vector
- * @hwerrmsgs hardware error descriptions
- * @nhwerrmsgs number of hwerrmsgs
- * @msg message buffer
- * @msgl message buffer length
- */
-void ipath_format_hwerrors(u64 hwerrs,
-                          const struct ipath_hwerror_msgs *hwerrmsgs,
-                          size_t nhwerrmsgs,
-                          char *msg, size_t msgl)
-{
-       int i;
-       const int glen =
-           ARRAY_SIZE(ipath_generic_hwerror_msgs);
-
-       for (i=0; i<glen; i++) {
-               if (hwerrs & ipath_generic_hwerror_msgs[i].mask) {
-                       ipath_format_hwmsg(msg, msgl,
-                                          ipath_generic_hwerror_msgs[i].msg);
-               }
-       }
-
-       for (i=0; i<nhwerrmsgs; i++) {
-               if (hwerrs & hwerrmsgs[i].mask) {
-                       ipath_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
-               }
-       }
-}
-
-/* return the strings for the most common link states */
-static char *ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
-{
-       char *ret;
-       u32 state;
-
-       state = ipath_ib_state(dd, ibcs);
-       if (state == dd->ib_init)
-               ret = "Init";
-       else if (state == dd->ib_arm)
-               ret = "Arm";
-       else if (state == dd->ib_active)
-               ret = "Active";
-       else
-               ret = "Down";
-       return ret;
-}
-
-void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
-{
-       struct ib_event event;
-
-       event.device = &dd->verbs_dev->ibdev;
-       event.element.port_num = 1;
-       event.event = ev;
-       ib_dispatch_event(&event);
-}
-
-static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
-                                    ipath_err_t errs)
-{
-       u32 ltstate, lstate, ibstate, lastlstate;
-       u32 init = dd->ib_init;
-       u32 arm = dd->ib_arm;
-       u32 active = dd->ib_active;
-       const u64 ibcs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
-
-       lstate = ipath_ib_linkstate(dd, ibcs); /* linkstate */
-       ibstate = ipath_ib_state(dd, ibcs);
-       /* linkstate at last interrupt */
-       lastlstate = ipath_ib_linkstate(dd, dd->ipath_lastibcstat);
-       ltstate = ipath_ib_linktrstate(dd, ibcs); /* linktrainingtate */
-
-       /*
-        * Since going into a recovery state causes the link state to go
-        * down and since recovery is transitory, it is better if we "miss"
-        * ever seeing the link training state go into recovery (i.e.,
-        * ignore this transition for link state special handling purposes)
-        * without even updating ipath_lastibcstat.
-        */
-       if ((ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN) ||
-           (ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT) ||
-           (ltstate == INFINIPATH_IBCS_LT_STATE_RECOVERIDLE))
-               goto done;
-
-       /*
-        * if linkstate transitions into INIT from any of the various down
-        * states, or if it transitions from any of the up (INIT or better)
-        * states into any of the down states (except link recovery), then
-        * call the chip-specific code to take appropriate actions.
-        */
-       if (lstate >= INFINIPATH_IBCS_L_STATE_INIT &&
-               lastlstate == INFINIPATH_IBCS_L_STATE_DOWN) {
-               /* transitioned to UP */
-               if (dd->ipath_f_ib_updown(dd, 1, ibcs)) {
-                       /* link came up, so we must no longer be disabled */
-                       dd->ipath_flags &= ~IPATH_IB_LINK_DISABLED;
-                       ipath_cdbg(LINKVERB, "LinkUp handled, skipped\n");
-                       goto skip_ibchange; /* chip-code handled */
-               }
-       } else if ((lastlstate >= INFINIPATH_IBCS_L_STATE_INIT ||
-               (dd->ipath_flags & IPATH_IB_FORCE_NOTIFY)) &&
-               ltstate <= INFINIPATH_IBCS_LT_STATE_CFGWAITRMT &&
-               ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
-               int handled;
-               handled = dd->ipath_f_ib_updown(dd, 0, ibcs);
-               dd->ipath_flags &= ~IPATH_IB_FORCE_NOTIFY;
-               if (handled) {
-                       ipath_cdbg(LINKVERB, "LinkDown handled, skipped\n");
-                       goto skip_ibchange; /* chip-code handled */
-               }
-       }
-
-       /*
-        * Significant enough to always print and get into logs, if it was
-        * unexpected.  If it was a requested state change, we'll have
-        * already cleared the flags, so we won't print this warning
-        */
-       if ((ibstate != arm && ibstate != active) &&
-           (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) {
-               dev_info(&dd->pcidev->dev, "Link state changed from %s "
-                        "to %s\n", (dd->ipath_flags & IPATH_LINKARMED) ?
-                        "ARM" : "ACTIVE", ib_linkstate(dd, ibcs));
-       }
-
-       if (ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE ||
-           ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
-               u32 lastlts;
-               lastlts = ipath_ib_linktrstate(dd, dd->ipath_lastibcstat);
-               /*
-                * Ignore cycling back and forth from Polling.Active to
-                * Polling.Quiet while waiting for the other end of the link
-                * to come up, except to try and decide if we are connected
-                * to a live IB device or not.  We will cycle back and
-                * forth between them if no cable is plugged in, the other
-                * device is powered off or disabled, etc.
-                */
-               if (lastlts == INFINIPATH_IBCS_LT_STATE_POLLACTIVE ||
-                   lastlts == INFINIPATH_IBCS_LT_STATE_POLLQUIET) {
-                       if (!(dd->ipath_flags & IPATH_IB_AUTONEG_INPROG) &&
-                            (++dd->ipath_ibpollcnt == 40)) {
-                               dd->ipath_flags |= IPATH_NOCABLE;
-                               *dd->ipath_statusp |=
-                                       IPATH_STATUS_IB_NOCABLE;
-                               ipath_cdbg(LINKVERB, "Set NOCABLE\n");
-                       }
-                       ipath_cdbg(LINKVERB, "POLL change to %s (%x)\n",
-                               ipath_ibcstatus_str[ltstate], ibstate);
-                       goto skip_ibchange;
-               }
-       }
-
-       dd->ipath_ibpollcnt = 0; /* not poll*, now */
-       ipath_stats.sps_iblink++;
-
-       if (ibstate != init && dd->ipath_lastlinkrecov && ipath_linkrecovery) {
-               u64 linkrecov;
-               linkrecov = ipath_snap_cntr(dd,
-                       dd->ipath_cregs->cr_iblinkerrrecovcnt);
-               if (linkrecov != dd->ipath_lastlinkrecov) {
-                       ipath_dbg("IB linkrecov up %Lx (%s %s) recov %Lu\n",
-                               (unsigned long long) ibcs,
-                               ib_linkstate(dd, ibcs),
-                               ipath_ibcstatus_str[ltstate],
-                               (unsigned long long) linkrecov);
-                       /* and no more until active again */
-                       dd->ipath_lastlinkrecov = 0;
-                       ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-                       goto skip_ibchange;
-               }
-       }
-
-       if (ibstate == init || ibstate == arm || ibstate == active) {
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_NOCABLE;
-               if (ibstate == init || ibstate == arm) {
-                       *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-                       if (dd->ipath_flags & IPATH_LINKACTIVE)
-                               signal_ib_event(dd, IB_EVENT_PORT_ERR);
-               }
-               if (ibstate == arm) {
-                       dd->ipath_flags |= IPATH_LINKARMED;
-                       dd->ipath_flags &= ~(IPATH_LINKUNK |
-                               IPATH_LINKINIT | IPATH_LINKDOWN |
-                               IPATH_LINKACTIVE | IPATH_NOCABLE);
-                       ipath_hol_down(dd);
-               } else  if (ibstate == init) {
-                       /*
-                        * set INIT and DOWN.  Down is checked by
-                        * most of the other code, but INIT is
-                        * useful to know in a few places.
-                        */
-                       dd->ipath_flags |= IPATH_LINKINIT |
-                               IPATH_LINKDOWN;
-                       dd->ipath_flags &= ~(IPATH_LINKUNK |
-                               IPATH_LINKARMED | IPATH_LINKACTIVE |
-                               IPATH_NOCABLE);
-                       ipath_hol_down(dd);
-               } else {  /* active */
-                       dd->ipath_lastlinkrecov = ipath_snap_cntr(dd,
-                               dd->ipath_cregs->cr_iblinkerrrecovcnt);
-                       *dd->ipath_statusp |=
-                               IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
-                       dd->ipath_flags |= IPATH_LINKACTIVE;
-                       dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
-                               | IPATH_LINKDOWN | IPATH_LINKARMED |
-                               IPATH_NOCABLE);
-                       if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
-                               ipath_restart_sdma(dd);
-                       signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
-                       /* LED active not handled in chip _f_updown */
-                       dd->ipath_f_setextled(dd, lstate, ltstate);
-                       ipath_hol_up(dd);
-               }
-
-               /*
-                * print after we've already done the work, so as not to
-                * delay the state changes and notifications, for debugging
-                */
-               if (lstate == lastlstate)
-                       ipath_cdbg(LINKVERB, "Unchanged from last: %s "
-                               "(%x)\n", ib_linkstate(dd, ibcs), ibstate);
-               else
-                       ipath_cdbg(VERBOSE, "Unit %u: link up to %s %s (%x)\n",
-                                 dd->ipath_unit, ib_linkstate(dd, ibcs),
-                                 ipath_ibcstatus_str[ltstate],  ibstate);
-       } else { /* down */
-               if (dd->ipath_flags & IPATH_LINKACTIVE)
-                       signal_ib_event(dd, IB_EVENT_PORT_ERR);
-               dd->ipath_flags |= IPATH_LINKDOWN;
-               dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
-                                    | IPATH_LINKACTIVE |
-                                    IPATH_LINKARMED);
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-               dd->ipath_lli_counter = 0;
-
-               if (lastlstate != INFINIPATH_IBCS_L_STATE_DOWN)
-                       ipath_cdbg(VERBOSE, "Unit %u link state down "
-                                  "(state 0x%x), from %s\n",
-                                  dd->ipath_unit, lstate,
-                                  ib_linkstate(dd, dd->ipath_lastibcstat));
-               else
-                       ipath_cdbg(LINKVERB, "Unit %u link state changed "
-                                  "to %s (0x%x) from down (%x)\n",
-                                  dd->ipath_unit,
-                                  ipath_ibcstatus_str[ltstate],
-                                  ibstate, lastlstate);
-       }
-
-skip_ibchange:
-       dd->ipath_lastibcstat = ibcs;
-done:
-       return;
-}
-
-static void handle_supp_msgs(struct ipath_devdata *dd,
-                            unsigned supp_msgs, char *msg, u32 msgsz)
-{
-       /*
-        * Print the message unless it's ibc status change only, which
-        * happens so often we never want to count it.
-        */
-       if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
-               int iserr;
-               ipath_err_t mask;
-               iserr = ipath_decode_err(dd, msg, msgsz,
-                                        dd->ipath_lasterror &
-                                        ~INFINIPATH_E_IBSTATUSCHANGED);
-
-               mask = INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-                       INFINIPATH_E_PKTERRS | INFINIPATH_E_SDMADISABLED;
-
-               /* if we're in debug, then don't mask SDMADISABLED msgs */
-               if (ipath_debug & __IPATH_DBG)
-                       mask &= ~INFINIPATH_E_SDMADISABLED;
-
-               if (dd->ipath_lasterror & ~mask)
-                       ipath_dev_err(dd, "Suppressed %u messages for "
-                                     "fast-repeating errors (%s) (%llx)\n",
-                                     supp_msgs, msg,
-                                     (unsigned long long)
-                                     dd->ipath_lasterror);
-               else {
-                       /*
-                        * rcvegrfull and rcvhdrqfull are "normal", for some
-                        * types of processes (mostly benchmarks) that send
-                        * huge numbers of messages, while not processing
-                        * them. So only complain about these at debug
-                        * level.
-                        */
-                       if (iserr)
-                               ipath_dbg("Suppressed %u messages for %s\n",
-                                         supp_msgs, msg);
-                       else
-                               ipath_cdbg(ERRPKT,
-                                       "Suppressed %u messages for %s\n",
-                                         supp_msgs, msg);
-               }
-       }
-}
-
-static unsigned handle_frequent_errors(struct ipath_devdata *dd,
-                                      ipath_err_t errs, char *msg,
-                                      u32 msgsz, int *noprint)
-{
-       unsigned long nc;
-       static unsigned long nextmsg_time;
-       static unsigned nmsgs, supp_msgs;
-
-       /*
-        * Throttle back "fast" messages to no more than 10 per 5 seconds.
-        * This isn't perfect, but it's a reasonable heuristic. If we get
-        * more than 10, give a 6x longer delay.
-        */
-       nc = jiffies;
-       if (nmsgs > 10) {
-               if (time_before(nc, nextmsg_time)) {
-                       *noprint = 1;
-                       if (!supp_msgs++)
-                               nextmsg_time = nc + HZ * 3;
-               } else if (supp_msgs) {
-                       handle_supp_msgs(dd, supp_msgs, msg, msgsz);
-                       supp_msgs = 0;
-                       nmsgs = 0;
-               }
-       } else if (!nmsgs++ || time_after(nc, nextmsg_time)) {
-               nextmsg_time = nc + HZ / 2;
-       }
-
-       return supp_msgs;
-}
-
-static void handle_sdma_errors(struct ipath_devdata *dd, ipath_err_t errs)
-{
-       unsigned long flags;
-       int expected;
-
-       if (ipath_debug & __IPATH_DBG) {
-               char msg[128];
-               ipath_decode_err(dd, msg, sizeof msg, errs &
-                       INFINIPATH_E_SDMAERRS);
-               ipath_dbg("errors %lx (%s)\n", (unsigned long)errs, msg);
-       }
-       if (ipath_debug & __IPATH_VERBDBG) {
-               unsigned long tl, hd, status, lengen;
-               tl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmatail);
-               hd = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmahead);
-               status = ipath_read_kreg64(dd
-                       , dd->ipath_kregs->kr_senddmastatus);
-               lengen = ipath_read_kreg64(dd,
-                       dd->ipath_kregs->kr_senddmalengen);
-               ipath_cdbg(VERBOSE, "sdma tl 0x%lx hd 0x%lx status 0x%lx "
-                       "lengen 0x%lx\n", tl, hd, status, lengen);
-       }
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-       __set_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
-       expected = test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-       if (!expected)
-               ipath_cancel_sends(dd, 1);
-}
-
-static void handle_sdma_intr(struct ipath_devdata *dd, u64 istat)
-{
-       unsigned long flags;
-       int expected;
-
-       if ((istat & INFINIPATH_I_SDMAINT) &&
-           !test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-               ipath_sdma_intr(dd);
-
-       if (istat & INFINIPATH_I_SDMADISABLED) {
-               expected = test_bit(IPATH_SDMA_ABORTING,
-                       &dd->ipath_sdma_status);
-               ipath_dbg("%s SDmaDisabled intr\n",
-                       expected ? "expected" : "unexpected");
-               spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-               __set_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
-               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-               if (!expected)
-                       ipath_cancel_sends(dd, 1);
-               if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-                       tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
-       }
-}
-
-static int handle_hdrq_full(struct ipath_devdata *dd)
-{
-       int chkerrpkts = 0;
-       u32 hd, tl;
-       u32 i;
-
-       ipath_stats.sps_hdrqfull++;
-       for (i = 0; i < dd->ipath_cfgports; i++) {
-               struct ipath_portdata *pd = dd->ipath_pd[i];
-
-               if (i == 0) {
-                       /*
-                        * For kernel receive queues, we just want to know
-                        * if there are packets in the queue that we can
-                        * process.
-                        */
-                       if (pd->port_head != ipath_get_hdrqtail(pd))
-                               chkerrpkts |= 1 << i;
-                       continue;
-               }
-
-               /* Skip if user context is not open */
-               if (!pd || !pd->port_cnt)
-                       continue;
-
-               /* Don't report the same point multiple times. */
-               if (dd->ipath_flags & IPATH_NODMA_RTAIL)
-                       tl = ipath_read_ureg32(dd, ur_rcvhdrtail, i);
-               else
-                       tl = ipath_get_rcvhdrtail(pd);
-               if (tl == pd->port_lastrcvhdrqtail)
-                       continue;
-
-               hd = ipath_read_ureg32(dd, ur_rcvhdrhead, i);
-               if (hd == (tl + 1) || (!hd && tl == dd->ipath_hdrqlast)) {
-                       pd->port_lastrcvhdrqtail = tl;
-                       pd->port_hdrqfull++;
-                       /* flush hdrqfull so that poll() sees it */
-                       wmb();
-                       wake_up_interruptible(&pd->port_wait);
-               }
-       }
-
-       return chkerrpkts;
-}
-
-static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
-{
-       char msg[128];
-       u64 ignore_this_time = 0;
-       u64 iserr = 0;
-       int chkerrpkts = 0, noprint = 0;
-       unsigned supp_msgs;
-       int log_idx;
-
-       /*
-        * don't report errors that are masked, either at init
-        * (not set in ipath_errormask), or temporarily (set in
-        * ipath_maskederrs)
-        */
-       errs &= dd->ipath_errormask & ~dd->ipath_maskederrs;
-
-       supp_msgs = handle_frequent_errors(dd, errs, msg, (u32)sizeof msg,
-               &noprint);
-
-       /* do these first, they are most important */
-       if (errs & INFINIPATH_E_HARDWARE) {
-               /* reuse same msg buf */
-               dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
-       } else {
-               u64 mask;
-               for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx) {
-                       mask = dd->ipath_eep_st_masks[log_idx].errs_to_log;
-                       if (errs & mask)
-                               ipath_inc_eeprom_err(dd, log_idx, 1);
-               }
-       }
-
-       if (errs & INFINIPATH_E_SDMAERRS)
-               handle_sdma_errors(dd, errs);
-
-       if (!noprint && (errs & ~dd->ipath_e_bitsextant))
-               ipath_dev_err(dd, "error interrupt with unknown errors "
-                             "%llx set\n", (unsigned long long)
-                             (errs & ~dd->ipath_e_bitsextant));
-
-       if (errs & E_SUM_ERRS)
-               ignore_this_time = handle_e_sum_errs(dd, errs);
-       else if ((errs & E_SUM_LINK_PKTERRS) &&
-           !(dd->ipath_flags & IPATH_LINKACTIVE)) {
-               /*
-                * This can happen when SMA is trying to bring the link
-                * up, but the IB link changes state at the "wrong" time.
-                * The IB logic then complains that the packet isn't
-                * valid.  We don't want to confuse people, so we just
-                * don't print them, except at debug
-                */
-               ipath_dbg("Ignoring packet errors %llx, because link not "
-                         "ACTIVE\n", (unsigned long long) errs);
-               ignore_this_time = errs & E_SUM_LINK_PKTERRS;
-       }
-
-       if (supp_msgs == 250000) {
-               int s_iserr;
-               /*
-                * It's not entirely reasonable assuming that the errors set
-                * in the last clear period are all responsible for the
-                * problem, but the alternative is to assume it's the only
-                * ones on this particular interrupt, which also isn't great
-                */
-               dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
-
-               dd->ipath_errormask &= ~dd->ipath_maskederrs;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-                                dd->ipath_errormask);
-               s_iserr = ipath_decode_err(dd, msg, sizeof msg,
-                                          dd->ipath_maskederrs);
-
-               if (dd->ipath_maskederrs &
-                   ~(INFINIPATH_E_RRCVEGRFULL |
-                     INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
-                       ipath_dev_err(dd, "Temporarily disabling "
-                           "error(s) %llx reporting; too frequent (%s)\n",
-                               (unsigned long long) dd->ipath_maskederrs,
-                               msg);
-               else {
-                       /*
-                        * rcvegrfull and rcvhdrqfull are "normal",
-                        * for some types of processes (mostly benchmarks)
-                        * that send huge numbers of messages, while not
-                        * processing them.  So only complain about
-                        * these at debug level.
-                        */
-                       if (s_iserr)
-                               ipath_dbg("Temporarily disabling reporting "
-                                   "too frequent queue full errors (%s)\n",
-                                   msg);
-                       else
-                               ipath_cdbg(ERRPKT,
-                                   "Temporarily disabling reporting too"
-                                   " frequent packet errors (%s)\n",
-                                   msg);
-               }
-
-               /*
-                * Re-enable the masked errors after around 3 minutes.  in
-                * ipath_get_faststats().  If we have a series of fast
-                * repeating but different errors, the interval will keep
-                * stretching out, but that's OK, as that's pretty
-                * catastrophic.
-                */
-               dd->ipath_unmasktime = jiffies + HZ * 180;
-       }
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, errs);
-       if (ignore_this_time)
-               errs &= ~ignore_this_time;
-       if (errs & ~dd->ipath_lasterror) {
-               errs &= ~dd->ipath_lasterror;
-               /* never suppress duplicate hwerrors or ibstatuschange */
-               dd->ipath_lasterror |= errs &
-                       ~(INFINIPATH_E_HARDWARE |
-                         INFINIPATH_E_IBSTATUSCHANGED);
-       }
-
-       if (errs & INFINIPATH_E_SENDSPECIALTRIGGER) {
-               dd->ipath_spectriggerhit++;
-               ipath_dbg("%lu special trigger hits\n",
-                       dd->ipath_spectriggerhit);
-       }
-
-       /* likely due to cancel; so suppress message unless verbose */
-       if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) &&
-               time_after(dd->ipath_lastcancel, jiffies)) {
-               /* armlaunch takes precedence; it often causes both. */
-               ipath_cdbg(VERBOSE,
-                       "Suppressed %s error (%llx) after sendbuf cancel\n",
-                       (errs &  INFINIPATH_E_SPIOARMLAUNCH) ?
-                       "armlaunch" : "sendpktlen", (unsigned long long)errs);
-               errs &= ~(INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SPKTLEN);
-       }
-
-       if (!errs)
-               return 0;
-
-       if (!noprint) {
-               ipath_err_t mask;
-               /*
-                * The ones we mask off are handled specially below
-                * or above.  Also mask SDMADISABLED by default as it
-                * is too chatty.
-                */
-               mask = INFINIPATH_E_IBSTATUSCHANGED |
-                       INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-                       INFINIPATH_E_HARDWARE | INFINIPATH_E_SDMADISABLED;
-
-               /* if we're in debug, then don't mask SDMADISABLED msgs */
-               if (ipath_debug & __IPATH_DBG)
-                       mask &= ~INFINIPATH_E_SDMADISABLED;
-
-               ipath_decode_err(dd, msg, sizeof msg, errs & ~mask);
-       } else
-               /* so we don't need if (!noprint) at strlcat's below */
-               *msg = 0;
-
-       if (errs & E_SUM_PKTERRS) {
-               ipath_stats.sps_pkterrs++;
-               chkerrpkts = 1;
-       }
-       if (errs & E_SUM_ERRS)
-               ipath_stats.sps_errs++;
-
-       if (errs & (INFINIPATH_E_RICRC | INFINIPATH_E_RVCRC)) {
-               ipath_stats.sps_crcerrs++;
-               chkerrpkts = 1;
-       }
-       iserr = errs & ~(E_SUM_PKTERRS | INFINIPATH_E_PKTERRS);
-
-
-       /*
-        * We don't want to print these two as they happen, or we can make
-        * the situation even worse, because it takes so long to print
-        * messages to serial consoles.  Kernel ports get printed from
-        * fast_stats, no more than every 5 seconds, user ports get printed
-        * on close
-        */
-       if (errs & INFINIPATH_E_RRCVHDRFULL)
-               chkerrpkts |= handle_hdrq_full(dd);
-       if (errs & INFINIPATH_E_RRCVEGRFULL) {
-               struct ipath_portdata *pd = dd->ipath_pd[0];
-
-               /*
-                * since this is of less importance and not likely to
-                * happen without also getting hdrfull, only count
-                * occurrences; don't check each port (or even the kernel
-                * vs user)
-                */
-               ipath_stats.sps_etidfull++;
-               if (pd->port_head != ipath_get_hdrqtail(pd))
-                       chkerrpkts |= 1;
-       }
-
-       /*
-        * do this before IBSTATUSCHANGED, in case both bits set in a single
-        * interrupt; we want the STATUSCHANGE to "win", so we do our
-        * internal copy of state machine correctly
-        */
-       if (errs & INFINIPATH_E_RIBLOSTLINK) {
-               /*
-                * force through block below
-                */
-               errs |= INFINIPATH_E_IBSTATUSCHANGED;
-               ipath_stats.sps_iblink++;
-               dd->ipath_flags |= IPATH_LINKDOWN;
-               dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
-                                    | IPATH_LINKARMED | IPATH_LINKACTIVE);
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-
-               ipath_dbg("Lost link, link now down (%s)\n",
-                       ipath_ibcstatus_str[ipath_read_kreg64(dd,
-                       dd->ipath_kregs->kr_ibcstatus) & 0xf]);
-       }
-       if (errs & INFINIPATH_E_IBSTATUSCHANGED)
-               handle_e_ibstatuschanged(dd, errs);
-
-       if (errs & INFINIPATH_E_RESET) {
-               if (!noprint)
-                       ipath_dev_err(dd, "Got reset, requires re-init "
-                                     "(unload and reload driver)\n");
-               dd->ipath_flags &= ~IPATH_INITTED;      /* needs re-init */
-               /* mark as having had error */
-               *dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-               *dd->ipath_statusp &= ~IPATH_STATUS_IB_CONF;
-       }
-
-       if (!noprint && *msg) {
-               if (iserr)
-                       ipath_dev_err(dd, "%s error\n", msg);
-       }
-       if (dd->ipath_state_wanted & dd->ipath_flags) {
-               ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, "
-                          "waking\n", dd->ipath_state_wanted,
-                          dd->ipath_flags);
-               wake_up_interruptible(&ipath_state_wait);
-       }
-
-       return chkerrpkts;
-}
-
-/*
- * try to cleanup as much as possible for anything that might have gone
- * wrong while in freeze mode, such as pio buffers being written by user
- * processes (causing armlaunch), send errors due to going into freeze mode,
- * etc., and try to avoid causing extra interrupts while doing so.
- * Forcibly update the in-memory pioavail register copies after cleanup
- * because the chip won't do it while in freeze mode (the register values
- * themselves are kept correct).
- * Make sure that we don't lose any important interrupts by using the chip
- * feature that says that writing 0 to a bit in *clear that is set in
- * *status will cause an interrupt to be generated again (if allowed by
- * the *mask value).
- */
-void ipath_clear_freeze(struct ipath_devdata *dd)
-{
-       /* disable error interrupts, to avoid confusion */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
-
-       /* also disable interrupts; errormask is sometimes overwriten */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
-
-       ipath_cancel_sends(dd, 1);
-
-       /* clear the freeze, and be sure chip saw it */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
-                        dd->ipath_control);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-
-       /* force in-memory update now we are out of freeze */
-       ipath_force_pio_avail_update(dd);
-
-       /*
-        * force new interrupt if any hwerr, error or interrupt bits are
-        * still set, and clear "safe" send packet errors related to freeze
-        * and cancelling sends.  Re-enable error interrupts before possible
-        * force of re-interrupt on pending interrupts.
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
-               E_SPKT_ERRS_IGNORE);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-               dd->ipath_errormask);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, -1LL);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
-}
-
-
-/* this is separate to allow for better optimization of ipath_intr() */
-
-static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
-{
-       /*
-        * sometimes happen during driver init and unload, don't want
-        * to process any interrupts at that point
-        */
-
-       /* this is just a bandaid, not a fix, if something goes badly
-        * wrong */
-       if (++*unexpectp > 100) {
-               if (++*unexpectp > 105) {
-                       /*
-                        * ok, we must be taking somebody else's interrupts,
-                        * due to a messed up mptable and/or PIRQ table, so
-                        * unregister the interrupt.  We've seen this during
-                        * linuxbios development work, and it may happen in
-                        * the future again.
-                        */
-                       if (dd->pcidev && dd->ipath_irq) {
-                               ipath_dev_err(dd, "Now %u unexpected "
-                                             "interrupts, unregistering "
-                                             "interrupt handler\n",
-                                             *unexpectp);
-                               ipath_dbg("free_irq of irq %d\n",
-                                         dd->ipath_irq);
-                               dd->ipath_f_free_irq(dd);
-                       }
-               }
-               if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
-                       ipath_dev_err(dd, "%u unexpected interrupts, "
-                                     "disabling interrupts completely\n",
-                                     *unexpectp);
-                       /*
-                        * disable all interrupts, something is very wrong
-                        */
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask,
-                                        0ULL);
-               }
-       } else if (*unexpectp > 1)
-               ipath_dbg("Interrupt when not ready, should not happen, "
-                         "ignoring\n");
-}
-
-static noinline void ipath_bad_regread(struct ipath_devdata *dd)
-{
-       static int allbits;
-
-       /* separate routine, for better optimization of ipath_intr() */
-
-       /*
-        * We print the message and disable interrupts, in hope of
-        * having a better chance of debugging the problem.
-        */
-       ipath_dev_err(dd,
-                     "Read of interrupt status failed (all bits set)\n");
-       if (allbits++) {
-               /* disable all interrupts, something is very wrong */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
-               if (allbits == 2) {
-                       ipath_dev_err(dd, "Still bad interrupt status, "
-                                     "unregistering interrupt\n");
-                       dd->ipath_f_free_irq(dd);
-               } else if (allbits > 2) {
-                       if ((allbits % 10000) == 0)
-                               printk(".");
-               } else
-                       ipath_dev_err(dd, "Disabling interrupts, "
-                                     "multiple errors\n");
-       }
-}
-
-static void handle_layer_pioavail(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-       int ret;
-
-       ret = ipath_ib_piobufavail(dd->verbs_dev);
-       if (ret > 0)
-               goto set;
-
-       return;
-set:
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                        dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-}
-
-/*
- * Handle receive interrupts for user ports; this means a user
- * process was waiting for a packet to arrive, and didn't want
- * to poll
- */
-static void handle_urcv(struct ipath_devdata *dd, u64 istat)
-{
-       u64 portr;
-       int i;
-       int rcvdint = 0;
-
-       /*
-        * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
-        * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
-        * would both like timely updates of the bits so that
-        * we don't pass them by unnecessarily.  the rmb()
-        * here ensures that we see them promptly -- the
-        * corresponding wmb()'s are in ipath_poll_urgent()
-        * and ipath_poll_next()...
-        */
-       rmb();
-       portr = ((istat >> dd->ipath_i_rcvavail_shift) &
-                dd->ipath_i_rcvavail_mask) |
-               ((istat >> dd->ipath_i_rcvurg_shift) &
-                dd->ipath_i_rcvurg_mask);
-       for (i = 1; i < dd->ipath_cfgports; i++) {
-               struct ipath_portdata *pd = dd->ipath_pd[i];
-
-               if (portr & (1 << i) && pd && pd->port_cnt) {
-                       if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
-                                              &pd->port_flag)) {
-                               clear_bit(i + dd->ipath_r_intravail_shift,
-                                         &dd->ipath_rcvctrl);
-                               wake_up_interruptible(&pd->port_wait);
-                               rcvdint = 1;
-                       } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG,
-                                                     &pd->port_flag)) {
-                               pd->port_urgent++;
-                               wake_up_interruptible(&pd->port_wait);
-                       }
-               }
-       }
-       if (rcvdint) {
-               /* only want to take one interrupt, so turn off the rcv
-                * interrupt for all the ports that we set the rcv_waiting
-                * (but never for kernel port)
-                */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-                                dd->ipath_rcvctrl);
-       }
-}
-
-irqreturn_t ipath_intr(int irq, void *data)
-{
-       struct ipath_devdata *dd = data;
-       u64 istat, chk0rcv = 0;
-       ipath_err_t estat = 0;
-       irqreturn_t ret;
-       static unsigned unexpected = 0;
-       u64 kportrbits;
-
-       ipath_stats.sps_ints++;
-
-       if (dd->ipath_int_counter != (u32) -1)
-               dd->ipath_int_counter++;
-
-       if (!(dd->ipath_flags & IPATH_PRESENT)) {
-               /*
-                * This return value is not great, but we do not want the
-                * interrupt core code to remove our interrupt handler
-                * because we don't appear to be handling an interrupt
-                * during a chip reset.
-                */
-               return IRQ_HANDLED;
-       }
-
-       /*
-        * this needs to be flags&initted, not statusp, so we keep
-        * taking interrupts even after link goes down, etc.
-        * Also, we *must* clear the interrupt at some point, or we won't
-        * take it again, which can be real bad for errors, etc...
-        */
-
-       if (!(dd->ipath_flags & IPATH_INITTED)) {
-               ipath_bad_intr(dd, &unexpected);
-               ret = IRQ_NONE;
-               goto bail;
-       }
-
-       istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
-
-       if (unlikely(!istat)) {
-               ipath_stats.sps_nullintr++;
-               ret = IRQ_NONE; /* not our interrupt, or already handled */
-               goto bail;
-       }
-       if (unlikely(istat == -1)) {
-               ipath_bad_regread(dd);
-               /* don't know if it was our interrupt or not */
-               ret = IRQ_NONE;
-               goto bail;
-       }
-
-       if (unexpected)
-               unexpected = 0;
-
-       if (unlikely(istat & ~dd->ipath_i_bitsextant))
-               ipath_dev_err(dd,
-                             "interrupt with unknown interrupts %Lx set\n",
-                             (unsigned long long)
-                             istat & ~dd->ipath_i_bitsextant);
-       else if (istat & ~INFINIPATH_I_ERROR) /* errors do own printing */
-               ipath_cdbg(VERBOSE, "intr stat=0x%Lx\n",
-                       (unsigned long long) istat);
-
-       if (istat & INFINIPATH_I_ERROR) {
-               ipath_stats.sps_errints++;
-               estat = ipath_read_kreg64(dd,
-                                         dd->ipath_kregs->kr_errorstatus);
-               if (!estat)
-                       dev_info(&dd->pcidev->dev, "error interrupt (%Lx), "
-                                "but no error bits set!\n",
-                                (unsigned long long) istat);
-               else if (estat == -1LL)
-                       /*
-                        * should we try clearing all, or hope next read
-                        * works?
-                        */
-                       ipath_dev_err(dd, "Read of error status failed "
-                                     "(all bits set); ignoring\n");
-               else
-                       chk0rcv |= handle_errors(dd, estat);
-       }
-
-       if (istat & INFINIPATH_I_GPIO) {
-               /*
-                * GPIO interrupts fall in two broad classes:
-                * GPIO_2 indicates (on some HT4xx boards) that a packet
-                *        has arrived for Port 0. Checking for this
-                *        is controlled by flag IPATH_GPIO_INTR.
-                * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate
-                *        errors that we need to count. Checking for this
-                *        is controlled by flag IPATH_GPIO_ERRINTRS.
-                */
-               u32 gpiostatus;
-               u32 to_clear = 0;
-
-               gpiostatus = ipath_read_kreg32(
-                       dd, dd->ipath_kregs->kr_gpio_status);
-               /* First the error-counter case. */
-               if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) &&
-                   (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) {
-                       /* want to clear the bits we see asserted. */
-                       to_clear |= (gpiostatus & IPATH_GPIO_ERRINTR_MASK);
-
-                       /*
-                        * Count appropriately, clear bits out of our copy,
-                        * as they have been "handled".
-                        */
-                       if (gpiostatus & (1 << IPATH_GPIO_RXUVL_BIT)) {
-                               ipath_dbg("FlowCtl on UnsupVL\n");
-                               dd->ipath_rxfc_unsupvl_errs++;
-                       }
-                       if (gpiostatus & (1 << IPATH_GPIO_OVRUN_BIT)) {
-                               ipath_dbg("Overrun Threshold exceeded\n");
-                               dd->ipath_overrun_thresh_errs++;
-                       }
-                       if (gpiostatus & (1 << IPATH_GPIO_LLI_BIT)) {
-                               ipath_dbg("Local Link Integrity error\n");
-                               dd->ipath_lli_errs++;
-                       }
-                       gpiostatus &= ~IPATH_GPIO_ERRINTR_MASK;
-               }
-               /* Now the Port0 Receive case */
-               if ((gpiostatus & (1 << IPATH_GPIO_PORT0_BIT)) &&
-                   (dd->ipath_flags & IPATH_GPIO_INTR)) {
-                       /*
-                        * GPIO status bit 2 is set, and we expected it.
-                        * clear it and indicate in p0bits.
-                        * This probably only happens if a Port0 pkt
-                        * arrives at _just_ the wrong time, and we
-                        * handle that by seting chk0rcv;
-                        */
-                       to_clear |= (1 << IPATH_GPIO_PORT0_BIT);
-                       gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT);
-                       chk0rcv = 1;
-               }
-               if (gpiostatus) {
-                       /*
-                        * Some unexpected bits remain. If they could have
-                        * caused the interrupt, complain and clear.
-                        * To avoid repetition of this condition, also clear
-                        * the mask. It is almost certainly due to error.
-                        */
-                       const u32 mask = (u32) dd->ipath_gpio_mask;
-
-                       if (mask & gpiostatus) {
-                               ipath_dbg("Unexpected GPIO IRQ bits %x\n",
-                                 gpiostatus & mask);
-                               to_clear |= (gpiostatus & mask);
-                               dd->ipath_gpio_mask &= ~(gpiostatus & mask);
-                               ipath_write_kreg(dd,
-                                       dd->ipath_kregs->kr_gpio_mask,
-                                       dd->ipath_gpio_mask);
-                       }
-               }
-               if (to_clear) {
-                       ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
-                                       (u64) to_clear);
-               }
-       }
-
-       /*
-        * Clear the interrupt bits we found set, unless they are receive
-        * related, in which case we already cleared them above, and don't
-        * want to clear them again, because we might lose an interrupt.
-        * Clear it early, so we "know" know the chip will have seen this by
-        * the time we process the queue, and will re-interrupt if necessary.
-        * The processor itself won't take the interrupt again until we return.
-        */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
-
-       /*
-        * Handle kernel receive queues before checking for pio buffers
-        * available since receives can overflow; piobuf waiters can afford
-        * a few extra cycles, since they were waiting anyway, and user's
-        * waiting for receive are at the bottom.
-        */
-       kportrbits = (1ULL << dd->ipath_i_rcvavail_shift) |
-               (1ULL << dd->ipath_i_rcvurg_shift);
-       if (chk0rcv || (istat & kportrbits)) {
-               istat &= ~kportrbits;
-               ipath_kreceive(dd->ipath_pd[0]);
-       }
-
-       if (istat & ((dd->ipath_i_rcvavail_mask << dd->ipath_i_rcvavail_shift) |
-                    (dd->ipath_i_rcvurg_mask << dd->ipath_i_rcvurg_shift)))
-               handle_urcv(dd, istat);
-
-       if (istat & (INFINIPATH_I_SDMAINT | INFINIPATH_I_SDMADISABLED))
-               handle_sdma_intr(dd, istat);
-
-       if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                dd->ipath_sendctrl);
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-               /* always process; sdma verbs uses PIO for acks and VL15  */
-               handle_layer_pioavail(dd);
-       }
-
-       ret = IRQ_HANDLED;
-
-bail:
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_kernel.h b/drivers/staging/rdma/ipath/ipath_kernel.h
deleted file mode 100644 (file)
index 66c934a..0000000
+++ /dev/null
@@ -1,1374 +0,0 @@
-#ifndef _IPATH_KERNEL_H
-#define _IPATH_KERNEL_H
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This header file is the base header file for infinipath kernel code
- * ipath_user.h serves a similar purpose for user code.
- */
-
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/scatterlist.h>
-#include <linux/sched.h>
-#include <asm/io.h>
-#include <rdma/ib_verbs.h>
-
-#include "ipath_common.h"
-#include "ipath_debug.h"
-#include "ipath_registers.h"
-
-/* only s/w major version of InfiniPath we can handle */
-#define IPATH_CHIP_VERS_MAJ 2U
-
-/* don't care about this except printing */
-#define IPATH_CHIP_VERS_MIN 0U
-
-/* temporary, maybe always */
-extern struct infinipath_stats ipath_stats;
-
-#define IPATH_CHIP_SWVERSION IPATH_CHIP_VERS_MAJ
-/*
- * First-cut critierion for "device is active" is
- * two thousand dwords combined Tx, Rx traffic per
- * 5-second interval. SMA packets are 64 dwords,
- * and occur "a few per second", presumably each way.
- */
-#define IPATH_TRAFFIC_ACTIVE_THRESHOLD (2000)
-/*
- * Struct used to indicate which errors are logged in each of the
- * error-counters that are logged to EEPROM. A counter is incremented
- * _once_ (saturating at 255) for each event with any bits set in
- * the error or hwerror register masks below.
- */
-#define IPATH_EEP_LOG_CNT (4)
-struct ipath_eep_log_mask {
-       u64 errs_to_log;
-       u64 hwerrs_to_log;
-};
-
-struct ipath_portdata {
-       void **port_rcvegrbuf;
-       dma_addr_t *port_rcvegrbuf_phys;
-       /* rcvhdrq base, needs mmap before useful */
-       void *port_rcvhdrq;
-       /* kernel virtual address where hdrqtail is updated */
-       void *port_rcvhdrtail_kvaddr;
-       /*
-        * temp buffer for expected send setup, allocated at open, instead
-        * of each setup call
-        */
-       void *port_tid_pg_list;
-       /* when waiting for rcv or pioavail */
-       wait_queue_head_t port_wait;
-       /*
-        * rcvegr bufs base, physical, must fit
-        * in 44 bits so 32 bit programs mmap64 44 bit works)
-        */
-       dma_addr_t port_rcvegr_phys;
-       /* mmap of hdrq, must fit in 44 bits */
-       dma_addr_t port_rcvhdrq_phys;
-       dma_addr_t port_rcvhdrqtailaddr_phys;
-       /*
-        * number of opens (including slave subports) on this instance
-        * (ignoring forks, dup, etc. for now)
-        */
-       int port_cnt;
-       /*
-        * how much space to leave at start of eager TID entries for
-        * protocol use, on each TID
-        */
-       /* instead of calculating it */
-       unsigned port_port;
-       /* non-zero if port is being shared. */
-       u16 port_subport_cnt;
-       /* non-zero if port is being shared. */
-       u16 port_subport_id;
-       /* number of pio bufs for this port (all procs, if shared) */
-       u32 port_piocnt;
-       /* first pio buffer for this port */
-       u32 port_pio_base;
-       /* chip offset of PIO buffers for this port */
-       u32 port_piobufs;
-       /* how many alloc_pages() chunks in port_rcvegrbuf_pages */
-       u32 port_rcvegrbuf_chunks;
-       /* how many egrbufs per chunk */
-       u32 port_rcvegrbufs_perchunk;
-       /* order for port_rcvegrbuf_pages */
-       size_t port_rcvegrbuf_size;
-       /* rcvhdrq size (for freeing) */
-       size_t port_rcvhdrq_size;
-       /* next expected TID to check when looking for free */
-       u32 port_tidcursor;
-       /* next expected TID to check */
-       unsigned long port_flag;
-       /* what happened */
-       unsigned long int_flag;
-       /* WAIT_RCV that timed out, no interrupt */
-       u32 port_rcvwait_to;
-       /* WAIT_PIO that timed out, no interrupt */
-       u32 port_piowait_to;
-       /* WAIT_RCV already happened, no wait */
-       u32 port_rcvnowait;
-       /* WAIT_PIO already happened, no wait */
-       u32 port_pionowait;
-       /* total number of rcvhdrqfull errors */
-       u32 port_hdrqfull;
-       /*
-        * Used to suppress multiple instances of same
-        * port staying stuck at same point.
-        */
-       u32 port_lastrcvhdrqtail;
-       /* saved total number of rcvhdrqfull errors for poll edge trigger */
-       u32 port_hdrqfull_poll;
-       /* total number of polled urgent packets */
-       u32 port_urgent;
-       /* saved total number of polled urgent packets for poll edge trigger */
-       u32 port_urgent_poll;
-       /* pid of process using this port */
-       struct pid *port_pid;
-       struct pid *port_subpid[INFINIPATH_MAX_SUBPORT];
-       /* same size as task_struct .comm[] */
-       char port_comm[TASK_COMM_LEN];
-       /* pkeys set by this use of this port */
-       u16 port_pkeys[4];
-       /* so file ops can get at unit */
-       struct ipath_devdata *port_dd;
-       /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */
-       void *subport_uregbase;
-       /* An array of pages for the eager receive buffers * N */
-       void *subport_rcvegrbuf;
-       /* An array of pages for the eager header queue entries * N */
-       void *subport_rcvhdr_base;
-       /* The version of the library which opened this port */
-       u32 userversion;
-       /* Bitmask of active slaves */
-       u32 active_slaves;
-       /* Type of packets or conditions we want to poll for */
-       u16 poll_type;
-       /* port rcvhdrq head offset */
-       u32 port_head;
-       /* receive packet sequence counter */
-       u32 port_seq_cnt;
-};
-
-struct sk_buff;
-struct ipath_sge_state;
-struct ipath_verbs_txreq;
-
-/*
- * control information for layered drivers
- */
-struct _ipath_layer {
-       void *l_arg;
-};
-
-struct ipath_skbinfo {
-       struct sk_buff *skb;
-       dma_addr_t phys;
-};
-
-struct ipath_sdma_txreq {
-       int                 flags;
-       int                 sg_count;
-       union {
-               struct scatterlist *sg;
-               void *map_addr;
-       };
-       void              (*callback)(void *, int);
-       void               *callback_cookie;
-       int                 callback_status;
-       u16                 start_idx;  /* sdma private */
-       u16                 next_descq_idx;  /* sdma private */
-       struct list_head    list;       /* sdma private */
-};
-
-struct ipath_sdma_desc {
-       __le64 qw[2];
-};
-
-#define IPATH_SDMA_TXREQ_F_USELARGEBUF  0x1
-#define IPATH_SDMA_TXREQ_F_HEADTOHOST   0x2
-#define IPATH_SDMA_TXREQ_F_INTREQ       0x4
-#define IPATH_SDMA_TXREQ_F_FREEBUF      0x8
-#define IPATH_SDMA_TXREQ_F_FREEDESC     0x10
-#define IPATH_SDMA_TXREQ_F_VL15         0x20
-
-#define IPATH_SDMA_TXREQ_S_OK        0
-#define IPATH_SDMA_TXREQ_S_SENDERROR 1
-#define IPATH_SDMA_TXREQ_S_ABORTED   2
-#define IPATH_SDMA_TXREQ_S_SHUTDOWN  3
-
-#define IPATH_SDMA_STATUS_SCORE_BOARD_DRAIN_IN_PROG    (1ull << 63)
-#define IPATH_SDMA_STATUS_ABORT_IN_PROG                        (1ull << 62)
-#define IPATH_SDMA_STATUS_INTERNAL_SDMA_ENABLE         (1ull << 61)
-#define IPATH_SDMA_STATUS_SCB_EMPTY                    (1ull << 30)
-
-/* max dwords in small buffer packet */
-#define IPATH_SMALLBUF_DWORDS (dd->ipath_piosize2k >> 2)
-
-/*
- * Possible IB config parameters for ipath_f_get/set_ib_cfg()
- */
-#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
-#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
-#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
-#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
-#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
-#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
-#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
-#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
-#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
-#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
-#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
-
-
-struct ipath_devdata {
-       struct list_head ipath_list;
-
-       struct ipath_kregs const *ipath_kregs;
-       struct ipath_cregs const *ipath_cregs;
-
-       /* mem-mapped pointer to base of chip regs */
-       u64 __iomem *ipath_kregbase;
-       /* end of mem-mapped chip space; range checking */
-       u64 __iomem *ipath_kregend;
-       /* physical address of chip for io_remap, etc. */
-       unsigned long ipath_physaddr;
-       /* base of memory alloced for ipath_kregbase, for free */
-       u64 *ipath_kregalloc;
-       /* ipath_cfgports pointers */
-       struct ipath_portdata **ipath_pd;
-       /* sk_buffs used by port 0 eager receive queue */
-       struct ipath_skbinfo *ipath_port0_skbinfo;
-       /* kvirt address of 1st 2k pio buffer */
-       void __iomem *ipath_pio2kbase;
-       /* kvirt address of 1st 4k pio buffer */
-       void __iomem *ipath_pio4kbase;
-       /*
-        * points to area where PIOavail registers will be DMA'ed.
-        * Has to be on a page of it's own, because the page will be
-        * mapped into user program space.  This copy is *ONLY* ever
-        * written by DMA, not by the driver!  Need a copy per device
-        * when we get to multiple devices
-        */
-       volatile __le64 *ipath_pioavailregs_dma;
-       /* physical address where updates occur */
-       dma_addr_t ipath_pioavailregs_phys;
-       struct _ipath_layer ipath_layer;
-       /* setup intr */
-       int (*ipath_f_intrsetup)(struct ipath_devdata *);
-       /* fallback to alternate interrupt type if possible */
-       int (*ipath_f_intr_fallback)(struct ipath_devdata *);
-       /* setup on-chip bus config */
-       int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
-       /* hard reset chip */
-       int (*ipath_f_reset)(struct ipath_devdata *);
-       int (*ipath_f_get_boardname)(struct ipath_devdata *, char *,
-                                    size_t);
-       void (*ipath_f_init_hwerrors)(struct ipath_devdata *);
-       void (*ipath_f_handle_hwerrors)(struct ipath_devdata *, char *,
-                                       size_t);
-       void (*ipath_f_quiet_serdes)(struct ipath_devdata *);
-       int (*ipath_f_bringup_serdes)(struct ipath_devdata *);
-       int (*ipath_f_early_init)(struct ipath_devdata *);
-       void (*ipath_f_clear_tids)(struct ipath_devdata *, unsigned);
-       void (*ipath_f_put_tid)(struct ipath_devdata *, u64 __iomem*,
-                               u32, unsigned long);
-       void (*ipath_f_tidtemplate)(struct ipath_devdata *);
-       void (*ipath_f_cleanup)(struct ipath_devdata *);
-       void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64);
-       /* fill out chip-specific fields */
-       int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
-       /* free irq */
-       void (*ipath_f_free_irq)(struct ipath_devdata *);
-       struct ipath_message_header *(*ipath_f_get_msgheader)
-                                       (struct ipath_devdata *, __le32 *);
-       void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
-       int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
-       int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
-       void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
-       void (*ipath_f_read_counters)(struct ipath_devdata *,
-                                       struct infinipath_counters *);
-       void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
-       /* per chip actions needed for IB Link up/down changes */
-       int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
-
-       unsigned ipath_lastegr_idx;
-       struct ipath_ibdev *verbs_dev;
-       struct timer_list verbs_timer;
-       /* total dwords sent (summed from counter) */
-       u64 ipath_sword;
-       /* total dwords rcvd (summed from counter) */
-       u64 ipath_rword;
-       /* total packets sent (summed from counter) */
-       u64 ipath_spkts;
-       /* total packets rcvd (summed from counter) */
-       u64 ipath_rpkts;
-       /* ipath_statusp initially points to this. */
-       u64 _ipath_status;
-       /* GUID for this interface, in network order */
-       __be64 ipath_guid;
-       /*
-        * aggregrate of error bits reported since last cleared, for
-        * limiting of error reporting
-        */
-       ipath_err_t ipath_lasterror;
-       /*
-        * aggregrate of error bits reported since last cleared, for
-        * limiting of hwerror reporting
-        */
-       ipath_err_t ipath_lasthwerror;
-       /* errors masked because they occur too fast */
-       ipath_err_t ipath_maskederrs;
-       u64 ipath_lastlinkrecov; /* link recoveries at last ACTIVE */
-       /* these 5 fields are used to establish deltas for IB Symbol
-        * errors and linkrecovery errors. They can be reported on
-        * some chips during link negotiation prior to INIT, and with
-        * DDR when faking DDR negotiations with non-IBTA switches.
-        * The chip counters are adjusted at driver unload if there is
-        * a non-zero delta.
-        */
-       u64 ibdeltainprog;
-       u64 ibsymdelta;
-       u64 ibsymsnap;
-       u64 iblnkerrdelta;
-       u64 iblnkerrsnap;
-
-       /* time in jiffies at which to re-enable maskederrs */
-       unsigned long ipath_unmasktime;
-       /* count of egrfull errors, combined for all ports */
-       u64 ipath_last_tidfull;
-       /* for ipath_qcheck() */
-       u64 ipath_lastport0rcv_cnt;
-       /* template for writing TIDs  */
-       u64 ipath_tidtemplate;
-       /* value to write to free TIDs */
-       u64 ipath_tidinvalid;
-       /* IBA6120 rcv interrupt setup */
-       u64 ipath_rhdrhead_intr_off;
-
-       /* size of memory at ipath_kregbase */
-       u32 ipath_kregsize;
-       /* number of registers used for pioavail */
-       u32 ipath_pioavregs;
-       /* IPATH_POLL, etc. */
-       u32 ipath_flags;
-       /* ipath_flags driver is waiting for */
-       u32 ipath_state_wanted;
-       /* last buffer for user use, first buf for kernel use is this
-        * index. */
-       u32 ipath_lastport_piobuf;
-       /* is a stats timer active */
-       u32 ipath_stats_timer_active;
-       /* number of interrupts for this device -- saturates... */
-       u32 ipath_int_counter;
-       /* dwords sent read from counter */
-       u32 ipath_lastsword;
-       /* dwords received read from counter */
-       u32 ipath_lastrword;
-       /* sent packets read from counter */
-       u32 ipath_lastspkts;
-       /* received packets read from counter */
-       u32 ipath_lastrpkts;
-       /* pio bufs allocated per port */
-       u32 ipath_pbufsport;
-       /* if remainder on bufs/port, ports < extrabuf get 1 extra */
-       u32 ipath_ports_extrabuf;
-       u32 ipath_pioupd_thresh; /* update threshold, some chips */
-       /*
-        * number of ports configured as max; zero is set to number chip
-        * supports, less gives more pio bufs/port, etc.
-        */
-       u32 ipath_cfgports;
-       /* count of port 0 hdrqfull errors */
-       u32 ipath_p0_hdrqfull;
-       /* port 0 number of receive eager buffers */
-       u32 ipath_p0_rcvegrcnt;
-
-       /*
-        * index of last piobuffer we used.  Speeds up searching, by
-        * starting at this point.  Doesn't matter if multiple cpu's use and
-        * update, last updater is only write that matters.  Whenever it
-        * wraps, we update shadow copies.  Need a copy per device when we
-        * get to multiple devices
-        */
-       u32 ipath_lastpioindex;
-       u32 ipath_lastpioindexl;
-       /* max length of freezemsg */
-       u32 ipath_freezelen;
-       /*
-        * consecutive times we wanted a PIO buffer but were unable to
-        * get one
-        */
-       u32 ipath_consec_nopiobuf;
-       /*
-        * hint that we should update ipath_pioavailshadow before
-        * looking for a PIO buffer
-        */
-       u32 ipath_upd_pio_shadow;
-       /* so we can rewrite it after a chip reset */
-       u32 ipath_pcibar0;
-       /* so we can rewrite it after a chip reset */
-       u32 ipath_pcibar1;
-       u32 ipath_x1_fix_tries;
-       u32 ipath_autoneg_tries;
-       u32 serdes_first_init_done;
-
-       struct ipath_relock {
-               atomic_t ipath_relock_timer_active;
-               struct timer_list ipath_relock_timer;
-               unsigned int ipath_relock_interval; /* in jiffies */
-       } ipath_relock_singleton;
-
-       /* interrupt number */
-       int ipath_irq;
-       /* HT/PCI Vendor ID (here for NodeInfo) */
-       u16 ipath_vendorid;
-       /* HT/PCI Device ID (here for NodeInfo) */
-       u16 ipath_deviceid;
-       /* offset in HT config space of slave/primary interface block */
-       u8 ipath_ht_slave_off;
-       /* for write combining settings */
-       int wc_cookie;
-       /* ref count for each pkey */
-       atomic_t ipath_pkeyrefs[4];
-       /* shadow copy of struct page *'s for exp tid pages */
-       struct page **ipath_pageshadow;
-       /* shadow copy of dma handles for exp tid pages */
-       dma_addr_t *ipath_physshadow;
-       u64 __iomem *ipath_egrtidbase;
-       /* lock to workaround chip bug 9437 and others */
-       spinlock_t ipath_kernel_tid_lock;
-       spinlock_t ipath_user_tid_lock;
-       spinlock_t ipath_sendctrl_lock;
-       /* around ipath_pd and (user ports) port_cnt use (intr vs free) */
-       spinlock_t ipath_uctxt_lock;
-
-       /*
-        * IPATH_STATUS_*,
-        * this address is mapped readonly into user processes so they can
-        * get status cheaply, whenever they want.
-        */
-       u64 *ipath_statusp;
-       /* freeze msg if hw error put chip in freeze */
-       char *ipath_freezemsg;
-       /* pci access data structure */
-       struct pci_dev *pcidev;
-       struct cdev *user_cdev;
-       struct cdev *diag_cdev;
-       struct device *user_dev;
-       struct device *diag_dev;
-       /* timer used to prevent stats overflow, error throttling, etc. */
-       struct timer_list ipath_stats_timer;
-       /* timer to verify interrupts work, and fallback if possible */
-       struct timer_list ipath_intrchk_timer;
-       void *ipath_dummy_hdrq; /* used after port close */
-       dma_addr_t ipath_dummy_hdrq_phys;
-
-       /* SendDMA related entries */
-       spinlock_t            ipath_sdma_lock;
-       unsigned long         ipath_sdma_status;
-       unsigned long         ipath_sdma_abort_jiffies;
-       unsigned long         ipath_sdma_abort_intr_timeout;
-       unsigned long         ipath_sdma_buf_jiffies;
-       struct ipath_sdma_desc *ipath_sdma_descq;
-       u64                   ipath_sdma_descq_added;
-       u64                   ipath_sdma_descq_removed;
-       int                   ipath_sdma_desc_nreserved;
-       u16                   ipath_sdma_descq_cnt;
-       u16                   ipath_sdma_descq_tail;
-       u16                   ipath_sdma_descq_head;
-       u16                   ipath_sdma_next_intr;
-       u16                   ipath_sdma_reset_wait;
-       u8                    ipath_sdma_generation;
-       struct tasklet_struct ipath_sdma_abort_task;
-       struct tasklet_struct ipath_sdma_notify_task;
-       struct list_head      ipath_sdma_activelist;
-       struct list_head      ipath_sdma_notifylist;
-       atomic_t              ipath_sdma_vl15_count;
-       struct timer_list     ipath_sdma_vl15_timer;
-
-       dma_addr_t       ipath_sdma_descq_phys;
-       volatile __le64 *ipath_sdma_head_dma;
-       dma_addr_t       ipath_sdma_head_phys;
-
-       unsigned long ipath_ureg_align; /* user register alignment */
-
-       struct delayed_work ipath_autoneg_work;
-       wait_queue_head_t ipath_autoneg_wait;
-
-       /* HoL blocking / user app forward-progress state */
-       unsigned          ipath_hol_state;
-       unsigned          ipath_hol_next;
-       struct timer_list ipath_hol_timer;
-
-       /*
-        * Shadow copies of registers; size indicates read access size.
-        * Most of them are readonly, but some are write-only register,
-        * where we manipulate the bits in the shadow copy, and then write
-        * the shadow copy to infinipath.
-        *
-        * We deliberately make most of these 32 bits, since they have
-        * restricted range.  For any that we read, we won't to generate 32
-        * bit accesses, since Opteron will generate 2 separate 32 bit HT
-        * transactions for a 64 bit read, and we want to avoid unnecessary
-        * HT transactions.
-        */
-
-       /* This is the 64 bit group */
-
-       /*
-        * shadow of pioavail, check to be sure it's large enough at
-        * init time.
-        */
-       unsigned long ipath_pioavailshadow[8];
-       /* bitmap of send buffers available for the kernel to use with PIO. */
-       unsigned long ipath_pioavailkernel[8];
-       /* shadow of kr_gpio_out, for rmw ops */
-       u64 ipath_gpio_out;
-       /* shadow the gpio mask register */
-       u64 ipath_gpio_mask;
-       /* shadow the gpio output enable, etc... */
-       u64 ipath_extctrl;
-       /* kr_revision shadow */
-       u64 ipath_revision;
-       /*
-        * shadow of ibcctrl, for interrupt handling of link changes,
-        * etc.
-        */
-       u64 ipath_ibcctrl;
-       /*
-        * last ibcstatus, to suppress "duplicate" status change messages,
-        * mostly from 2 to 3
-        */
-       u64 ipath_lastibcstat;
-       /* hwerrmask shadow */
-       ipath_err_t ipath_hwerrmask;
-       ipath_err_t ipath_errormask; /* errormask shadow */
-       /* interrupt config reg shadow */
-       u64 ipath_intconfig;
-       /* kr_sendpiobufbase value */
-       u64 ipath_piobufbase;
-       /* kr_ibcddrctrl shadow */
-       u64 ipath_ibcddrctrl;
-
-       /* these are the "32 bit" regs */
-
-       /*
-        * number of GUIDs in the flash for this interface; may need some
-        * rethinking for setting on other ifaces
-        */
-       u32 ipath_nguid;
-       /*
-        * the following two are 32-bit bitmasks, but {test,clear,set}_bit
-        * all expect bit fields to be "unsigned long"
-        */
-       /* shadow kr_rcvctrl */
-       unsigned long ipath_rcvctrl;
-       /* shadow kr_sendctrl */
-       unsigned long ipath_sendctrl;
-       /* to not count armlaunch after cancel */
-       unsigned long ipath_lastcancel;
-       /* count cases where special trigger was needed (double write) */
-       unsigned long ipath_spectriggerhit;
-
-       /* value we put in kr_rcvhdrcnt */
-       u32 ipath_rcvhdrcnt;
-       /* value we put in kr_rcvhdrsize */
-       u32 ipath_rcvhdrsize;
-       /* value we put in kr_rcvhdrentsize */
-       u32 ipath_rcvhdrentsize;
-       /* offset of last entry in rcvhdrq */
-       u32 ipath_hdrqlast;
-       /* kr_portcnt value */
-       u32 ipath_portcnt;
-       /* kr_pagealign value */
-       u32 ipath_palign;
-       /* number of "2KB" PIO buffers */
-       u32 ipath_piobcnt2k;
-       /* size in bytes of "2KB" PIO buffers */
-       u32 ipath_piosize2k;
-       /* number of "4KB" PIO buffers */
-       u32 ipath_piobcnt4k;
-       /* size in bytes of "4KB" PIO buffers */
-       u32 ipath_piosize4k;
-       u32 ipath_pioreserved; /* reserved special-inkernel; */
-       /* kr_rcvegrbase value */
-       u32 ipath_rcvegrbase;
-       /* kr_rcvegrcnt value */
-       u32 ipath_rcvegrcnt;
-       /* kr_rcvtidbase value */
-       u32 ipath_rcvtidbase;
-       /* kr_rcvtidcnt value */
-       u32 ipath_rcvtidcnt;
-       /* kr_sendregbase */
-       u32 ipath_sregbase;
-       /* kr_userregbase */
-       u32 ipath_uregbase;
-       /* kr_counterregbase */
-       u32 ipath_cregbase;
-       /* shadow the control register contents */
-       u32 ipath_control;
-       /* PCI revision register (HTC rev on FPGA) */
-       u32 ipath_pcirev;
-
-       /* chip address space used by 4k pio buffers */
-       u32 ipath_4kalign;
-       /* The MTU programmed for this unit */
-       u32 ipath_ibmtu;
-       /*
-        * The max size IB packet, included IB headers that we can send.
-        * Starts same as ipath_piosize, but is affected when ibmtu is
-        * changed, or by size of eager buffers
-        */
-       u32 ipath_ibmaxlen;
-       /*
-        * ibmaxlen at init time, limited by chip and by receive buffer
-        * size.  Not changed after init.
-        */
-       u32 ipath_init_ibmaxlen;
-       /* size of each rcvegrbuffer */
-       u32 ipath_rcvegrbufsize;
-       /* localbus width (1, 2,4,8,16,32) from config space  */
-       u32 ipath_lbus_width;
-       /* localbus speed (HT: 200,400,800,1000; PCIe 2500) */
-       u32 ipath_lbus_speed;
-       /*
-        * number of sequential ibcstatus change for polling active/quiet
-        * (i.e., link not coming up).
-        */
-       u32 ipath_ibpollcnt;
-       /* low and high portions of MSI capability/vector */
-       u32 ipath_msi_lo;
-       /* saved after PCIe init for restore after reset */
-       u32 ipath_msi_hi;
-       /* MSI data (vector) saved for restore */
-       u16 ipath_msi_data;
-       /* MLID programmed for this instance */
-       u16 ipath_mlid;
-       /* LID programmed for this instance */
-       u16 ipath_lid;
-       /* list of pkeys programmed; 0 if not set */
-       u16 ipath_pkeys[4];
-       /*
-        * ASCII serial number, from flash, large enough for original
-        * all digit strings, and longer QLogic serial number format
-        */
-       u8 ipath_serial[16];
-       /* human readable board version */
-       u8 ipath_boardversion[96];
-       u8 ipath_lbus_info[32]; /* human readable localbus info */
-       /* chip major rev, from ipath_revision */
-       u8 ipath_majrev;
-       /* chip minor rev, from ipath_revision */
-       u8 ipath_minrev;
-       /* board rev, from ipath_revision */
-       u8 ipath_boardrev;
-       /* saved for restore after reset */
-       u8 ipath_pci_cacheline;
-       /* LID mask control */
-       u8 ipath_lmc;
-       /* link width supported */
-       u8 ipath_link_width_supported;
-       /* link speed supported */
-       u8 ipath_link_speed_supported;
-       u8 ipath_link_width_enabled;
-       u8 ipath_link_speed_enabled;
-       u8 ipath_link_width_active;
-       u8 ipath_link_speed_active;
-       /* Rx Polarity inversion (compensate for ~tx on partner) */
-       u8 ipath_rx_pol_inv;
-
-       u8 ipath_r_portenable_shift;
-       u8 ipath_r_intravail_shift;
-       u8 ipath_r_tailupd_shift;
-       u8 ipath_r_portcfg_shift;
-
-       /* unit # of this chip, if present */
-       int ipath_unit;
-
-       /* local link integrity counter */
-       u32 ipath_lli_counter;
-       /* local link integrity errors */
-       u32 ipath_lli_errors;
-       /*
-        * Above counts only cases where _successive_ LocalLinkIntegrity
-        * errors were seen in the receive headers of kern-packets.
-        * Below are the three (monotonically increasing) counters
-        * maintained via GPIO interrupts on iba6120-rev2.
-        */
-       u32 ipath_rxfc_unsupvl_errs;
-       u32 ipath_overrun_thresh_errs;
-       u32 ipath_lli_errs;
-
-       /*
-        * Not all devices managed by a driver instance are the same
-        * type, so these fields must be per-device.
-        */
-       u64 ipath_i_bitsextant;
-       ipath_err_t ipath_e_bitsextant;
-       ipath_err_t ipath_hwe_bitsextant;
-
-       /*
-        * Below should be computable from number of ports,
-        * since they are never modified.
-        */
-       u64 ipath_i_rcvavail_mask;
-       u64 ipath_i_rcvurg_mask;
-       u16 ipath_i_rcvurg_shift;
-       u16 ipath_i_rcvavail_shift;
-
-       /*
-        * Register bits for selecting i2c direction and values, used for
-        * I2C serial flash.
-        */
-       u8 ipath_gpio_sda_num;
-       u8 ipath_gpio_scl_num;
-       u8 ipath_i2c_chain_type;
-       u64 ipath_gpio_sda;
-       u64 ipath_gpio_scl;
-
-       /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
-       spinlock_t ipath_gpio_lock;
-
-       /*
-        * IB link and linktraining states and masks that vary per chip in
-        * some way.  Set at init, to avoid each IB status change interrupt
-        */
-       u8 ibcs_ls_shift;
-       u8 ibcs_lts_mask;
-       u32 ibcs_mask;
-       u32 ib_init;
-       u32 ib_arm;
-       u32 ib_active;
-
-       u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
-
-       /*
-        * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
-        * reg. Changes for IBA7220
-        */
-       u8 ibcc_lic_mask; /* LinkInitCmd */
-       u8 ibcc_lc_shift; /* LinkCmd */
-       u8 ibcc_mpl_shift; /* Maxpktlen */
-
-       u8 delay_mult;
-
-       /* used to override LED behavior */
-       u8 ipath_led_override;  /* Substituted for normal value, if non-zero */
-       u16 ipath_led_override_timeoff; /* delta to next timer event */
-       u8 ipath_led_override_vals[2]; /* Alternates per blink-frame */
-       u8 ipath_led_override_phase; /* Just counts, LSB picks from vals[] */
-       atomic_t ipath_led_override_timer_active;
-       /* Used to flash LEDs in override mode */
-       struct timer_list ipath_led_override_timer;
-
-       /* Support (including locks) for EEPROM logging of errors and time */
-       /* control access to actual counters, timer */
-       spinlock_t ipath_eep_st_lock;
-       /* control high-level access to EEPROM */
-       struct mutex ipath_eep_lock;
-       /* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
-       uint64_t ipath_traffic_wds;
-       /* active time is kept in seconds, but logged in hours */
-       atomic_t ipath_active_time;
-       /* Below are nominal shadow of EEPROM, new since last EEPROM update */
-       uint8_t ipath_eep_st_errs[IPATH_EEP_LOG_CNT];
-       uint8_t ipath_eep_st_new_errs[IPATH_EEP_LOG_CNT];
-       uint16_t ipath_eep_hrs;
-       /*
-        * masks for which bits of errs, hwerrs that cause
-        * each of the counters to increment.
-        */
-       struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
-
-       /* interrupt mitigation reload register info */
-       u16 ipath_jint_idle_ticks;      /* idle clock ticks */
-       u16 ipath_jint_max_packets;     /* max packets across all ports */
-
-       /*
-        * lock for access to SerDes, and flags to sequence preset
-        * versus steady-state. 7220-only at the moment.
-        */
-       spinlock_t ipath_sdepb_lock;
-       u8 ipath_presets_needed; /* Set if presets to be restored next DOWN */
-};
-
-/* ipath_hol_state values (stopping/starting user proc, send flushing) */
-#define IPATH_HOL_UP       0
-#define IPATH_HOL_DOWN     1
-/* ipath_hol_next toggle values, used when hol_state IPATH_HOL_DOWN */
-#define IPATH_HOL_DOWNSTOP 0
-#define IPATH_HOL_DOWNCONT 1
-
-/* bit positions for sdma_status */
-#define IPATH_SDMA_ABORTING  0
-#define IPATH_SDMA_DISARMED  1
-#define IPATH_SDMA_DISABLED  2
-#define IPATH_SDMA_LAYERBUF  3
-#define IPATH_SDMA_RUNNING  30
-#define IPATH_SDMA_SHUTDOWN 31
-
-/* bit combinations that correspond to abort states */
-#define IPATH_SDMA_ABORT_NONE 0
-#define IPATH_SDMA_ABORT_ABORTING (1UL << IPATH_SDMA_ABORTING)
-#define IPATH_SDMA_ABORT_DISARMED ((1UL << IPATH_SDMA_ABORTING) | \
-       (1UL << IPATH_SDMA_DISARMED))
-#define IPATH_SDMA_ABORT_DISABLED ((1UL << IPATH_SDMA_ABORTING) | \
-       (1UL << IPATH_SDMA_DISABLED))
-#define IPATH_SDMA_ABORT_ABORTED ((1UL << IPATH_SDMA_ABORTING) | \
-       (1UL << IPATH_SDMA_DISARMED) | (1UL << IPATH_SDMA_DISABLED))
-#define IPATH_SDMA_ABORT_MASK ((1UL<<IPATH_SDMA_ABORTING) | \
-       (1UL << IPATH_SDMA_DISARMED) | (1UL << IPATH_SDMA_DISABLED))
-
-#define IPATH_SDMA_BUF_NONE 0
-#define IPATH_SDMA_BUF_MASK (1UL<<IPATH_SDMA_LAYERBUF)
-
-/* Private data for file operations */
-struct ipath_filedata {
-       struct ipath_portdata *pd;
-       unsigned subport;
-       unsigned tidcursor;
-       struct ipath_user_sdma_queue *pq;
-};
-extern struct list_head ipath_dev_list;
-extern spinlock_t ipath_devs_lock;
-extern struct ipath_devdata *ipath_lookup(int unit);
-
-int ipath_init_chip(struct ipath_devdata *, int);
-int ipath_enable_wc(struct ipath_devdata *dd);
-void ipath_disable_wc(struct ipath_devdata *dd);
-int ipath_count_units(int *npresentp, int *nupp, int *maxportsp);
-void ipath_shutdown_device(struct ipath_devdata *);
-void ipath_clear_freeze(struct ipath_devdata *);
-
-struct file_operations;
-int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,
-                   struct cdev **cdevp, struct device **devp);
-void ipath_cdev_cleanup(struct cdev **cdevp,
-                       struct device **devp);
-
-int ipath_diag_add(struct ipath_devdata *);
-void ipath_diag_remove(struct ipath_devdata *);
-
-extern wait_queue_head_t ipath_state_wait;
-
-int ipath_user_add(struct ipath_devdata *dd);
-void ipath_user_remove(struct ipath_devdata *dd);
-
-struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t);
-
-extern int ipath_diag_inuse;
-
-irqreturn_t ipath_intr(int irq, void *devid);
-int ipath_decode_err(struct ipath_devdata *dd, char *buf, size_t blen,
-                    ipath_err_t err);
-#if __IPATH_INFO || __IPATH_DBG
-extern const char *ipath_ibcstatus_str[];
-#endif
-
-/* clean up any per-chip chip-specific stuff */
-void ipath_chip_cleanup(struct ipath_devdata *);
-/* clean up any chip type-specific stuff */
-void ipath_chip_done(void);
-
-void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
-                         unsigned cnt);
-void ipath_cancel_sends(struct ipath_devdata *, int);
-
-int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
-void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
-
-int ipath_parse_ushort(const char *str, unsigned short *valp);
-
-void ipath_kreceive(struct ipath_portdata *);
-int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
-int ipath_reset_device(int);
-void ipath_get_faststats(unsigned long);
-int ipath_wait_linkstate(struct ipath_devdata *, u32, int);
-int ipath_set_linkstate(struct ipath_devdata *, u8);
-int ipath_set_mtu(struct ipath_devdata *, u16);
-int ipath_set_lid(struct ipath_devdata *, u32, u8);
-int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
-void ipath_enable_armlaunch(struct ipath_devdata *);
-void ipath_disable_armlaunch(struct ipath_devdata *);
-void ipath_hol_down(struct ipath_devdata *);
-void ipath_hol_up(struct ipath_devdata *);
-void ipath_hol_event(unsigned long);
-void ipath_toggle_rclkrls(struct ipath_devdata *);
-void ipath_sd7220_clr_ibpar(struct ipath_devdata *);
-void ipath_set_relock_poll(struct ipath_devdata *, int);
-void ipath_shutdown_relock_poll(struct ipath_devdata *);
-
-/* for use in system calls, where we want to know device type, etc. */
-#define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
-#define subport_fp(fp) \
-       ((struct ipath_filedata *)(fp)->private_data)->subport
-#define tidcursor_fp(fp) \
-       ((struct ipath_filedata *)(fp)->private_data)->tidcursor
-#define user_sdma_queue_fp(fp) \
-       ((struct ipath_filedata *)(fp)->private_data)->pq
-
-/*
- * values for ipath_flags
- */
-               /* chip can report link latency (IB 1.2) */
-#define IPATH_HAS_LINK_LATENCY 0x1
-               /* The chip is up and initted */
-#define IPATH_INITTED       0x2
-               /* set if any user code has set kr_rcvhdrsize */
-#define IPATH_RCVHDRSZ_SET  0x4
-               /* The chip is present and valid for accesses */
-#define IPATH_PRESENT       0x8
-               /* HT link0 is only 8 bits wide, ignore upper byte crc
-                * errors, etc. */
-#define IPATH_8BIT_IN_HT0   0x10
-               /* HT link1 is only 8 bits wide, ignore upper byte crc
-                * errors, etc. */
-#define IPATH_8BIT_IN_HT1   0x20
-               /* The link is down */
-#define IPATH_LINKDOWN      0x40
-               /* The link level is up (0x11) */
-#define IPATH_LINKINIT      0x80
-               /* The link is in the armed (0x21) state */
-#define IPATH_LINKARMED     0x100
-               /* The link is in the active (0x31) state */
-#define IPATH_LINKACTIVE    0x200
-               /* link current state is unknown */
-#define IPATH_LINKUNK       0x400
-               /* Write combining flush needed for PIO */
-#define IPATH_PIO_FLUSH_WC  0x1000
-               /* DMA Receive tail pointer */
-#define IPATH_NODMA_RTAIL   0x2000
-               /* no IB cable, or no device on IB cable */
-#define IPATH_NOCABLE       0x4000
-               /* Supports port zero per packet receive interrupts via
-                * GPIO */
-#define IPATH_GPIO_INTR     0x8000
-               /* uses the coded 4byte TID, not 8 byte */
-#define IPATH_4BYTE_TID     0x10000
-               /* packet/word counters are 32 bit, else those 4 counters
-                * are 64bit */
-#define IPATH_32BITCOUNTERS 0x20000
-               /* Interrupt register is 64 bits */
-#define IPATH_INTREG_64     0x40000
-               /* can miss port0 rx interrupts */
-#define IPATH_DISABLED      0x80000 /* administratively disabled */
-               /* Use GPIO interrupts for new counters */
-#define IPATH_GPIO_ERRINTRS 0x100000
-#define IPATH_SWAP_PIOBUFS  0x200000
-               /* Supports Send DMA */
-#define IPATH_HAS_SEND_DMA  0x400000
-               /* Supports Send Count (not just word count) in PBC */
-#define IPATH_HAS_PBC_CNT   0x800000
-               /* Suppress heartbeat, even if turning off loopback */
-#define IPATH_NO_HRTBT      0x1000000
-#define IPATH_HAS_THRESH_UPDATE 0x4000000
-#define IPATH_HAS_MULT_IB_SPEED 0x8000000
-#define IPATH_IB_AUTONEG_INPROG 0x10000000
-#define IPATH_IB_AUTONEG_FAILED 0x20000000
-               /* Linkdown-disable intentionally, Do not attempt to bring up */
-#define IPATH_IB_LINK_DISABLED 0x40000000
-#define IPATH_IB_FORCE_NOTIFY 0x80000000 /* force notify on next ib change */
-
-/* Bits in GPIO for the added interrupts */
-#define IPATH_GPIO_PORT0_BIT 2
-#define IPATH_GPIO_RXUVL_BIT 3
-#define IPATH_GPIO_OVRUN_BIT 4
-#define IPATH_GPIO_LLI_BIT 5
-#define IPATH_GPIO_ERRINTR_MASK 0x38
-
-/* portdata flag bit offsets */
-               /* waiting for a packet to arrive */
-#define IPATH_PORT_WAITING_RCV   2
-               /* master has not finished initializing */
-#define IPATH_PORT_MASTER_UNINIT 4
-               /* waiting for an urgent packet to arrive */
-#define IPATH_PORT_WAITING_URG 5
-
-/* free up any allocated data at closes */
-void ipath_free_data(struct ipath_portdata *dd);
-u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32, u32 *);
-void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
-                               unsigned len, int avail);
-void ipath_init_iba6110_funcs(struct ipath_devdata *);
-void ipath_get_eeprom_info(struct ipath_devdata *);
-int ipath_update_eeprom_log(struct ipath_devdata *dd);
-void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
-u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *);
-void ipath_force_pio_avail_update(struct ipath_devdata *);
-void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
-
-/*
- * Set LED override, only the two LSBs have "public" meaning, but
- * any non-zero value substitutes them for the Link and LinkTrain
- * LED states.
- */
-#define IPATH_LED_PHYS 1 /* Physical (linktraining) GREEN LED */
-#define IPATH_LED_LOG 2  /* Logical (link) YELLOW LED */
-void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
-
-/* send dma routines */
-int setup_sdma(struct ipath_devdata *);
-void teardown_sdma(struct ipath_devdata *);
-void ipath_restart_sdma(struct ipath_devdata *);
-void ipath_sdma_intr(struct ipath_devdata *);
-int ipath_sdma_verbs_send(struct ipath_devdata *, struct ipath_sge_state *,
-                         u32, struct ipath_verbs_txreq *);
-/* ipath_sdma_lock should be locked before calling this. */
-int ipath_sdma_make_progress(struct ipath_devdata *dd);
-
-/* must be called under ipath_sdma_lock */
-static inline u16 ipath_sdma_descq_freecnt(const struct ipath_devdata *dd)
-{
-       return dd->ipath_sdma_descq_cnt -
-               (dd->ipath_sdma_descq_added - dd->ipath_sdma_descq_removed) -
-               1 - dd->ipath_sdma_desc_nreserved;
-}
-
-static inline void ipath_sdma_desc_reserve(struct ipath_devdata *dd, u16 cnt)
-{
-       dd->ipath_sdma_desc_nreserved += cnt;
-}
-
-static inline void ipath_sdma_desc_unreserve(struct ipath_devdata *dd, u16 cnt)
-{
-       dd->ipath_sdma_desc_nreserved -= cnt;
-}
-
-/*
- * number of words used for protocol header if not set by ipath_userinit();
- */
-#define IPATH_DFLT_RCVHDRSIZE 9
-
-int ipath_get_user_pages(unsigned long, size_t, struct page **);
-void ipath_release_user_pages(struct page **, size_t);
-void ipath_release_user_pages_on_close(struct page **, size_t);
-int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
-int ipath_eeprom_write(struct ipath_devdata *, u8, const void *, int);
-int ipath_tempsense_read(struct ipath_devdata *, u8 regnum);
-int ipath_tempsense_write(struct ipath_devdata *, u8 regnum, u8 data);
-
-/* these are used for the registers that vary with port */
-void ipath_write_kreg_port(const struct ipath_devdata *, ipath_kreg,
-                          unsigned, u64);
-
-/*
- * We could have a single register get/put routine, that takes a group type,
- * but this is somewhat clearer and cleaner.  It also gives us some error
- * checking.  64 bit register reads should always work, but are inefficient
- * on opteron (the northbridge always generates 2 separate HT 32 bit reads),
- * so we use kreg32 wherever possible.  User register and counter register
- * reads are always 32 bit reads, so only one form of those routines.
- */
-
-/*
- * At the moment, none of the s-registers are writable, so no
- * ipath_write_sreg().
- */
-
-/**
- * ipath_read_ureg32 - read 32-bit virtualized per-port register
- * @dd: device
- * @regno: register number
- * @port: port number
- *
- * Return the contents of a register that is virtualized to be per port.
- * Returns -1 on errors (not distinguishable from valid contents at
- * runtime; we may add a separate error variable at some point).
- */
-static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
-                                   ipath_ureg regno, int port)
-{
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
-               return 0;
-
-       return readl(regno + (u64 __iomem *)
-                    (dd->ipath_uregbase +
-                     (char __iomem *)dd->ipath_kregbase +
-                     dd->ipath_ureg_align * port));
-}
-
-/**
- * ipath_write_ureg - write 32-bit virtualized per-port register
- * @dd: device
- * @regno: register number
- * @value: value
- * @port: port
- *
- * Write the contents of a register that is virtualized to be per port.
- */
-static inline void ipath_write_ureg(const struct ipath_devdata *dd,
-                                   ipath_ureg regno, u64 value, int port)
-{
-       u64 __iomem *ubase = (u64 __iomem *)
-               (dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
-                dd->ipath_ureg_align * port);
-       if (dd->ipath_kregbase)
-               writeq(value, &ubase[regno]);
-}
-
-static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd,
-                                   ipath_kreg regno)
-{
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
-               return -1;
-       return readl((u32 __iomem *) & dd->ipath_kregbase[regno]);
-}
-
-static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd,
-                                   ipath_kreg regno)
-{
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
-               return -1;
-
-       return readq(&dd->ipath_kregbase[regno]);
-}
-
-static inline void ipath_write_kreg(const struct ipath_devdata *dd,
-                                   ipath_kreg regno, u64 value)
-{
-       if (dd->ipath_kregbase)
-               writeq(value, &dd->ipath_kregbase[regno]);
-}
-
-static inline u64 ipath_read_creg(const struct ipath_devdata *dd,
-                                 ipath_sreg regno)
-{
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
-               return 0;
-
-       return readq(regno + (u64 __iomem *)
-                    (dd->ipath_cregbase +
-                     (char __iomem *)dd->ipath_kregbase));
-}
-
-static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
-                                        ipath_sreg regno)
-{
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT))
-               return 0;
-       return readl(regno + (u64 __iomem *)
-                    (dd->ipath_cregbase +
-                     (char __iomem *)dd->ipath_kregbase));
-}
-
-static inline void ipath_write_creg(const struct ipath_devdata *dd,
-                                   ipath_creg regno, u64 value)
-{
-       if (dd->ipath_kregbase)
-               writeq(value, regno + (u64 __iomem *)
-                      (dd->ipath_cregbase +
-                       (char __iomem *)dd->ipath_kregbase));
-}
-
-static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
-{
-       *((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
-}
-
-static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
-{
-       return (u32) le64_to_cpu(*((volatile __le64 *)
-                               pd->port_rcvhdrtail_kvaddr));
-}
-
-static inline u32 ipath_get_hdrqtail(const struct ipath_portdata *pd)
-{
-       const struct ipath_devdata *dd = pd->port_dd;
-       u32 hdrqtail;
-
-       if (dd->ipath_flags & IPATH_NODMA_RTAIL) {
-               __le32 *rhf_addr;
-               u32 seq;
-
-               rhf_addr = (__le32 *) pd->port_rcvhdrq +
-                       pd->port_head + dd->ipath_rhf_offset;
-               seq = ipath_hdrget_seq(rhf_addr);
-               hdrqtail = pd->port_head;
-               if (seq == pd->port_seq_cnt)
-                       hdrqtail++;
-       } else
-               hdrqtail = ipath_get_rcvhdrtail(pd);
-
-       return hdrqtail;
-}
-
-static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
-{
-       return (dd->ipath_flags & IPATH_INTREG_64) ?
-               ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
-}
-
-/*
- * from contents of IBCStatus (or a saved copy), return linkstate
- * Report ACTIVE_DEFER as ACTIVE, because we treat them the same
- * everywhere, anyway (and should be, for almost all purposes).
- */
-static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
-{
-       u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
-               INFINIPATH_IBCS_LINKSTATE_MASK;
-       if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
-               state = INFINIPATH_IBCS_L_STATE_ACTIVE;
-       return state;
-}
-
-/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
-static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
-{
-       return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
-               dd->ibcs_lts_mask;
-}
-
-/*
- * from contents of IBCStatus (or a saved copy), return logical link state
- * combination of link state and linktraining state (down, active, init,
- * arm, etc.
- */
-static inline u32 ipath_ib_state(struct ipath_devdata *dd, u64 ibcs)
-{
-       u32 ibs;
-       ibs = (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
-               dd->ibcs_lts_mask;
-       ibs |= (u32)(ibcs &
-               (INFINIPATH_IBCS_LINKSTATE_MASK << dd->ibcs_ls_shift));
-       return ibs;
-}
-
-/*
- * sysfs interface.
- */
-
-struct device_driver;
-
-extern const char ib_ipath_version[];
-
-extern const struct attribute_group *ipath_driver_attr_groups[];
-
-int ipath_device_create_group(struct device *, struct ipath_devdata *);
-void ipath_device_remove_group(struct device *, struct ipath_devdata *);
-int ipath_expose_reset(struct device *);
-
-int ipath_init_ipathfs(void);
-void ipath_exit_ipathfs(void);
-int ipathfs_add_device(struct ipath_devdata *);
-int ipathfs_remove_device(struct ipath_devdata *);
-
-/*
- * dma_addr wrappers - all 0's invalid for hw
- */
-dma_addr_t ipath_map_page(struct pci_dev *, struct page *, unsigned long,
-                         size_t, int);
-dma_addr_t ipath_map_single(struct pci_dev *, void *, size_t, int);
-const char *ipath_get_unit_name(int unit);
-
-/*
- * Flush write combining store buffers (if present) and perform a write
- * barrier.
- */
-#if defined(CONFIG_X86_64)
-#define ipath_flush_wc() asm volatile("sfence" ::: "memory")
-#else
-#define ipath_flush_wc() wmb()
-#endif
-
-extern unsigned ipath_debug; /* debugging bit mask */
-extern unsigned ipath_linkrecovery;
-extern unsigned ipath_mtu4096;
-extern struct mutex ipath_mutex;
-
-#define IPATH_DRV_NAME         "ib_ipath"
-#define IPATH_MAJOR            233
-#define IPATH_USER_MINOR_BASE  0
-#define IPATH_DIAGPKT_MINOR    127
-#define IPATH_DIAG_MINOR_BASE  129
-#define IPATH_NMINORS          255
-
-#define ipath_dev_err(dd,fmt,...) \
-       do { \
-               const struct ipath_devdata *__dd = (dd); \
-               if (__dd->pcidev) \
-                       dev_err(&__dd->pcidev->dev, "%s: " fmt, \
-                               ipath_get_unit_name(__dd->ipath_unit), \
-                               ##__VA_ARGS__); \
-               else \
-                       printk(KERN_ERR IPATH_DRV_NAME ": %s: " fmt, \
-                              ipath_get_unit_name(__dd->ipath_unit), \
-                              ##__VA_ARGS__); \
-       } while (0)
-
-#if _IPATH_DEBUGGING
-
-# define __IPATH_DBG_WHICH(which,fmt,...) \
-       do { \
-               if (unlikely(ipath_debug & (which))) \
-                       printk(KERN_DEBUG IPATH_DRV_NAME ": %s: " fmt, \
-                              __func__,##__VA_ARGS__); \
-       } while(0)
-
-# define ipath_dbg(fmt,...) \
-       __IPATH_DBG_WHICH(__IPATH_DBG,fmt,##__VA_ARGS__)
-# define ipath_cdbg(which,fmt,...) \
-       __IPATH_DBG_WHICH(__IPATH_##which##DBG,fmt,##__VA_ARGS__)
-
-#else /* ! _IPATH_DEBUGGING */
-
-# define ipath_dbg(fmt,...)
-# define ipath_cdbg(which,fmt,...)
-
-#endif /* _IPATH_DEBUGGING */
-
-/*
- * this is used for formatting hw error messages...
- */
-struct ipath_hwerror_msgs {
-       u64 mask;
-       const char *msg;
-};
-
-#define INFINIPATH_HWE_MSG(a, b) { .mask = INFINIPATH_HWE_##a, .msg = b }
-
-/* in ipath_intr.c... */
-void ipath_format_hwerrors(u64 hwerrs,
-                          const struct ipath_hwerror_msgs *hwerrmsgs,
-                          size_t nhwerrmsgs,
-                          char *msg, size_t lmsg);
-
-#endif                         /* _IPATH_KERNEL_H */
diff --git a/drivers/staging/rdma/ipath/ipath_keys.c b/drivers/staging/rdma/ipath/ipath_keys.c
deleted file mode 100644 (file)
index c0e933f..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <asm/io.h>
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-/**
- * ipath_alloc_lkey - allocate an lkey
- * @rkt: lkey table in which to allocate the lkey
- * @mr: memory region that this lkey protects
- *
- * Returns 1 if successful, otherwise returns 0.
- */
-
-int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr)
-{
-       unsigned long flags;
-       u32 r;
-       u32 n;
-       int ret;
-
-       spin_lock_irqsave(&rkt->lock, flags);
-
-       /* Find the next available LKEY */
-       r = n = rkt->next;
-       for (;;) {
-               if (rkt->table[r] == NULL)
-                       break;
-               r = (r + 1) & (rkt->max - 1);
-               if (r == n) {
-                       spin_unlock_irqrestore(&rkt->lock, flags);
-                       ipath_dbg("LKEY table full\n");
-                       ret = 0;
-                       goto bail;
-               }
-       }
-       rkt->next = (r + 1) & (rkt->max - 1);
-       /*
-        * Make sure lkey is never zero which is reserved to indicate an
-        * unrestricted LKEY.
-        */
-       rkt->gen++;
-       mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) |
-               ((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen)
-                << 8);
-       if (mr->lkey == 0) {
-               mr->lkey |= 1 << 8;
-               rkt->gen++;
-       }
-       rkt->table[r] = mr;
-       spin_unlock_irqrestore(&rkt->lock, flags);
-
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_free_lkey - free an lkey
- * @rkt: table from which to free the lkey
- * @lkey: lkey id to free
- */
-void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey)
-{
-       unsigned long flags;
-       u32 r;
-
-       if (lkey == 0)
-               return;
-       r = lkey >> (32 - ib_ipath_lkey_table_size);
-       spin_lock_irqsave(&rkt->lock, flags);
-       rkt->table[r] = NULL;
-       spin_unlock_irqrestore(&rkt->lock, flags);
-}
-
-/**
- * ipath_lkey_ok - check IB SGE for validity and initialize
- * @rkt: table containing lkey to check SGE against
- * @isge: outgoing internal SGE
- * @sge: SGE to check
- * @acc: access flags
- *
- * Return 1 if valid and successful, otherwise returns 0.
- *
- * Check the IB SGE for validity and initialize our internal version
- * of it.
- */
-int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
-                 struct ib_sge *sge, int acc)
-{
-       struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
-       struct ipath_mregion *mr;
-       unsigned n, m;
-       size_t off;
-       int ret;
-
-       /*
-        * We use LKEY == zero for kernel virtual addresses
-        * (see ipath_get_dma_mr and ipath_dma.c).
-        */
-       if (sge->lkey == 0) {
-               /* always a kernel port, no locking needed */
-               struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
-
-               if (pd->user) {
-                       ret = 0;
-                       goto bail;
-               }
-               isge->mr = NULL;
-               isge->vaddr = (void *) sge->addr;
-               isge->length = sge->length;
-               isge->sge_length = sge->length;
-               ret = 1;
-               goto bail;
-       }
-       mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
-       if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
-                    qp->ibqp.pd != mr->pd)) {
-               ret = 0;
-               goto bail;
-       }
-
-       off = sge->addr - mr->user_base;
-       if (unlikely(sge->addr < mr->user_base ||
-                    off + sge->length > mr->length ||
-                    (mr->access_flags & acc) != acc)) {
-               ret = 0;
-               goto bail;
-       }
-
-       off += mr->offset;
-       m = 0;
-       n = 0;
-       while (off >= mr->map[m]->segs[n].length) {
-               off -= mr->map[m]->segs[n].length;
-               n++;
-               if (n >= IPATH_SEGSZ) {
-                       m++;
-                       n = 0;
-               }
-       }
-       isge->mr = mr;
-       isge->vaddr = mr->map[m]->segs[n].vaddr + off;
-       isge->length = mr->map[m]->segs[n].length - off;
-       isge->sge_length = sge->length;
-       isge->m = m;
-       isge->n = n;
-
-       ret = 1;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_rkey_ok - check the IB virtual address, length, and RKEY
- * @dev: infiniband device
- * @ss: SGE state
- * @len: length of data
- * @vaddr: virtual address to place data
- * @rkey: rkey to check
- * @acc: access flags
- *
- * Return 1 if successful, otherwise 0.
- */
-int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
-                 u32 len, u64 vaddr, u32 rkey, int acc)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ipath_lkey_table *rkt = &dev->lk_table;
-       struct ipath_sge *sge = &ss->sge;
-       struct ipath_mregion *mr;
-       unsigned n, m;
-       size_t off;
-       int ret;
-
-       /*
-        * We use RKEY == zero for kernel virtual addresses
-        * (see ipath_get_dma_mr and ipath_dma.c).
-        */
-       if (rkey == 0) {
-               /* always a kernel port, no locking needed */
-               struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
-
-               if (pd->user) {
-                       ret = 0;
-                       goto bail;
-               }
-               sge->mr = NULL;
-               sge->vaddr = (void *) vaddr;
-               sge->length = len;
-               sge->sge_length = len;
-               ss->sg_list = NULL;
-               ss->num_sge = 1;
-               ret = 1;
-               goto bail;
-       }
-
-       mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
-       if (unlikely(mr == NULL || mr->lkey != rkey ||
-                    qp->ibqp.pd != mr->pd)) {
-               ret = 0;
-               goto bail;
-       }
-
-       off = vaddr - mr->iova;
-       if (unlikely(vaddr < mr->iova || off + len > mr->length ||
-                    (mr->access_flags & acc) == 0)) {
-               ret = 0;
-               goto bail;
-       }
-
-       off += mr->offset;
-       m = 0;
-       n = 0;
-       while (off >= mr->map[m]->segs[n].length) {
-               off -= mr->map[m]->segs[n].length;
-               n++;
-               if (n >= IPATH_SEGSZ) {
-                       m++;
-                       n = 0;
-               }
-       }
-       sge->mr = mr;
-       sge->vaddr = mr->map[m]->segs[n].vaddr + off;
-       sge->length = mr->map[m]->segs[n].length - off;
-       sge->sge_length = len;
-       sge->m = m;
-       sge->n = n;
-       ss->sg_list = NULL;
-       ss->num_sge = 1;
-
-       ret = 1;
-
-bail:
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_mad.c b/drivers/staging/rdma/ipath/ipath_mad.c
deleted file mode 100644 (file)
index ad3a926..0000000
+++ /dev/null
@@ -1,1521 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <rdma/ib_smi.h>
-#include <rdma/ib_pma.h>
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-#define IB_SMP_UNSUP_VERSION   cpu_to_be16(0x0004)
-#define IB_SMP_UNSUP_METHOD    cpu_to_be16(0x0008)
-#define IB_SMP_UNSUP_METH_ATTR cpu_to_be16(0x000C)
-#define IB_SMP_INVALID_FIELD   cpu_to_be16(0x001C)
-
-static int reply(struct ib_smp *smp)
-{
-       /*
-        * The verbs framework will handle the directed/LID route
-        * packet changes.
-        */
-       smp->method = IB_MGMT_METHOD_GET_RESP;
-       if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
-               smp->status |= IB_SMP_DIRECTION;
-       return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
-}
-
-static int recv_subn_get_nodedescription(struct ib_smp *smp,
-                                        struct ib_device *ibdev)
-{
-       if (smp->attr_mod)
-               smp->status |= IB_SMP_INVALID_FIELD;
-
-       memcpy(smp->data, ibdev->node_desc, sizeof(smp->data));
-
-       return reply(smp);
-}
-
-struct nodeinfo {
-       u8 base_version;
-       u8 class_version;
-       u8 node_type;
-       u8 num_ports;
-       __be64 sys_guid;
-       __be64 node_guid;
-       __be64 port_guid;
-       __be16 partition_cap;
-       __be16 device_id;
-       __be32 revision;
-       u8 local_port_num;
-       u8 vendor_id[3];
-} __attribute__ ((packed));
-
-static int recv_subn_get_nodeinfo(struct ib_smp *smp,
-                                 struct ib_device *ibdev, u8 port)
-{
-       struct nodeinfo *nip = (struct nodeinfo *)&smp->data;
-       struct ipath_devdata *dd = to_idev(ibdev)->dd;
-       u32 vendor, majrev, minrev;
-
-       /* GUID 0 is illegal */
-       if (smp->attr_mod || (dd->ipath_guid == 0))
-               smp->status |= IB_SMP_INVALID_FIELD;
-
-       nip->base_version = 1;
-       nip->class_version = 1;
-       nip->node_type = 1;     /* channel adapter */
-       /*
-        * XXX The num_ports value will need a layer function to get
-        * the value if we ever have more than one IB port on a chip.
-        * We will also need to get the GUID for the port.
-        */
-       nip->num_ports = ibdev->phys_port_cnt;
-       /* This is already in network order */
-       nip->sys_guid = to_idev(ibdev)->sys_image_guid;
-       nip->node_guid = dd->ipath_guid;
-       nip->port_guid = dd->ipath_guid;
-       nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
-       nip->device_id = cpu_to_be16(dd->ipath_deviceid);
-       majrev = dd->ipath_majrev;
-       minrev = dd->ipath_minrev;
-       nip->revision = cpu_to_be32((majrev << 16) | minrev);
-       nip->local_port_num = port;
-       vendor = dd->ipath_vendorid;
-       nip->vendor_id[0] = IPATH_SRC_OUI_1;
-       nip->vendor_id[1] = IPATH_SRC_OUI_2;
-       nip->vendor_id[2] = IPATH_SRC_OUI_3;
-
-       return reply(smp);
-}
-
-static int recv_subn_get_guidinfo(struct ib_smp *smp,
-                                 struct ib_device *ibdev)
-{
-       u32 startgx = 8 * be32_to_cpu(smp->attr_mod);
-       __be64 *p = (__be64 *) smp->data;
-
-       /* 32 blocks of 8 64-bit GUIDs per block */
-
-       memset(smp->data, 0, sizeof(smp->data));
-
-       /*
-        * We only support one GUID for now.  If this changes, the
-        * portinfo.guid_cap field needs to be updated too.
-        */
-       if (startgx == 0) {
-               __be64 g = to_idev(ibdev)->dd->ipath_guid;
-               if (g == 0)
-                       /* GUID 0 is illegal */
-                       smp->status |= IB_SMP_INVALID_FIELD;
-               else
-                       /* The first is a copy of the read-only HW GUID. */
-                       *p = g;
-       } else
-               smp->status |= IB_SMP_INVALID_FIELD;
-
-       return reply(smp);
-}
-
-static void set_link_width_enabled(struct ipath_devdata *dd, u32 w)
-{
-       (void) dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, w);
-}
-
-static void set_link_speed_enabled(struct ipath_devdata *dd, u32 s)
-{
-       (void) dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, s);
-}
-
-static int get_overrunthreshold(struct ipath_devdata *dd)
-{
-       return (dd->ipath_ibcctrl >>
-               INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
-               INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
-}
-
-/**
- * set_overrunthreshold - set the overrun threshold
- * @dd: the infinipath device
- * @n: the new threshold
- *
- * Note that this will only take effect when the link state changes.
- */
-static int set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
-{
-       unsigned v;
-
-       v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
-               INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
-       if (v != n) {
-               dd->ipath_ibcctrl &=
-                       ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
-                         INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
-               dd->ipath_ibcctrl |=
-                       (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                                dd->ipath_ibcctrl);
-       }
-       return 0;
-}
-
-static int get_phyerrthreshold(struct ipath_devdata *dd)
-{
-       return (dd->ipath_ibcctrl >>
-               INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
-               INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
-}
-
-/**
- * set_phyerrthreshold - set the physical error threshold
- * @dd: the infinipath device
- * @n: the new threshold
- *
- * Note that this will only take effect when the link state changes.
- */
-static int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
-{
-       unsigned v;
-
-       v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
-               INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
-       if (v != n) {
-               dd->ipath_ibcctrl &=
-                       ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
-                         INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
-               dd->ipath_ibcctrl |=
-                       (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                                dd->ipath_ibcctrl);
-       }
-       return 0;
-}
-
-/**
- * get_linkdowndefaultstate - get the default linkdown state
- * @dd: the infinipath device
- *
- * Returns zero if the default is POLL, 1 if the default is SLEEP.
- */
-static int get_linkdowndefaultstate(struct ipath_devdata *dd)
-{
-       return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
-}
-
-static int recv_subn_get_portinfo(struct ib_smp *smp,
-                                 struct ib_device *ibdev, u8 port)
-{
-       struct ipath_ibdev *dev;
-       struct ipath_devdata *dd;
-       struct ib_port_info *pip = (struct ib_port_info *)smp->data;
-       u16 lid;
-       u8 ibcstat;
-       u8 mtu;
-       int ret;
-
-       if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) {
-               smp->status |= IB_SMP_INVALID_FIELD;
-               ret = reply(smp);
-               goto bail;
-       }
-
-       dev = to_idev(ibdev);
-       dd = dev->dd;
-
-       /* Clear all fields.  Only set the non-zero fields. */
-       memset(smp->data, 0, sizeof(smp->data));
-
-       /* Only return the mkey if the protection field allows it. */
-       if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
-           dev->mkeyprot == 0)
-               pip->mkey = dev->mkey;
-       pip->gid_prefix = dev->gid_prefix;
-       lid = dd->ipath_lid;
-       pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
-       pip->sm_lid = cpu_to_be16(dev->sm_lid);
-       pip->cap_mask = cpu_to_be32(dev->port_cap_flags);
-       /* pip->diag_code; */
-       pip->mkey_lease_period = cpu_to_be16(dev->mkey_lease_period);
-       pip->local_port_num = port;
-       pip->link_width_enabled = dd->ipath_link_width_enabled;
-       pip->link_width_supported = dd->ipath_link_width_supported;
-       pip->link_width_active = dd->ipath_link_width_active;
-       pip->linkspeed_portstate = dd->ipath_link_speed_supported << 4;
-       ibcstat = dd->ipath_lastibcstat;
-       /* map LinkState to IB portinfo values.  */
-       pip->linkspeed_portstate |= ipath_ib_linkstate(dd, ibcstat) + 1;
-
-       pip->portphysstate_linkdown =
-               (ipath_cvt_physportstate[ibcstat & dd->ibcs_lts_mask] << 4) |
-               (get_linkdowndefaultstate(dd) ? 1 : 2);
-       pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dd->ipath_lmc;
-       pip->linkspeedactive_enabled = (dd->ipath_link_speed_active << 4) |
-               dd->ipath_link_speed_enabled;
-       switch (dd->ipath_ibmtu) {
-       case 4096:
-               mtu = IB_MTU_4096;
-               break;
-       case 2048:
-               mtu = IB_MTU_2048;
-               break;
-       case 1024:
-               mtu = IB_MTU_1024;
-               break;
-       case 512:
-               mtu = IB_MTU_512;
-               break;
-       case 256:
-               mtu = IB_MTU_256;
-               break;
-       default:                /* oops, something is wrong */
-               mtu = IB_MTU_2048;
-               break;
-       }
-       pip->neighbormtu_mastersmsl = (mtu << 4) | dev->sm_sl;
-       pip->vlcap_inittype = 0x10;     /* VLCap = VL0, InitType = 0 */
-       pip->vl_high_limit = dev->vl_high_limit;
-       /* pip->vl_arb_high_cap; // only one VL */
-       /* pip->vl_arb_low_cap; // only one VL */
-       /* InitTypeReply = 0 */
-       /* our mtu cap depends on whether 4K MTU enabled or not */
-       pip->inittypereply_mtucap = ipath_mtu4096 ? IB_MTU_4096 : IB_MTU_2048;
-       /* HCAs ignore VLStallCount and HOQLife */
-       /* pip->vlstallcnt_hoqlife; */
-       pip->operationalvl_pei_peo_fpi_fpo = 0x10;      /* OVLs = 1 */
-       pip->mkey_violations = cpu_to_be16(dev->mkey_violations);
-       /* P_KeyViolations are counted by hardware. */
-       pip->pkey_violations =
-               cpu_to_be16((ipath_get_cr_errpkey(dd) -
-                            dev->z_pkey_violations) & 0xFFFF);
-       pip->qkey_violations = cpu_to_be16(dev->qkey_violations);
-       /* Only the hardware GUID is supported for now */
-       pip->guid_cap = 1;
-       pip->clientrereg_resv_subnetto = dev->subnet_timeout;
-       /* 32.768 usec. response time (guessing) */
-       pip->resv_resptimevalue = 3;
-       pip->localphyerrors_overrunerrors =
-               (get_phyerrthreshold(dd) << 4) |
-               get_overrunthreshold(dd);
-       /* pip->max_credit_hint; */
-       if (dev->port_cap_flags & IB_PORT_LINK_LATENCY_SUP) {
-               u32 v;
-
-               v = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LINKLATENCY);
-               pip->link_roundtrip_latency[0] = v >> 16;
-               pip->link_roundtrip_latency[1] = v >> 8;
-               pip->link_roundtrip_latency[2] = v;
-       }
-
-       ret = reply(smp);
-
-bail:
-       return ret;
-}
-
-/**
- * get_pkeys - return the PKEY table for port 0
- * @dd: the infinipath device
- * @pkeys: the pkey table is placed here
- */
-static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
-{
-       /* always a kernel port, no locking needed */
-       struct ipath_portdata *pd = dd->ipath_pd[0];
-
-       memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
-
-       return 0;
-}
-
-static int recv_subn_get_pkeytable(struct ib_smp *smp,
-                                  struct ib_device *ibdev)
-{
-       u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
-       u16 *p = (u16 *) smp->data;
-       __be16 *q = (__be16 *) smp->data;
-
-       /* 64 blocks of 32 16-bit P_Key entries */
-
-       memset(smp->data, 0, sizeof(smp->data));
-       if (startpx == 0) {
-               struct ipath_ibdev *dev = to_idev(ibdev);
-               unsigned i, n = ipath_get_npkeys(dev->dd);
-
-               get_pkeys(dev->dd, p);
-
-               for (i = 0; i < n; i++)
-                       q[i] = cpu_to_be16(p[i]);
-       } else
-               smp->status |= IB_SMP_INVALID_FIELD;
-
-       return reply(smp);
-}
-
-static int recv_subn_set_guidinfo(struct ib_smp *smp,
-                                 struct ib_device *ibdev)
-{
-       /* The only GUID we support is the first read-only entry. */
-       return recv_subn_get_guidinfo(smp, ibdev);
-}
-
-/**
- * set_linkdowndefaultstate - set the default linkdown state
- * @dd: the infinipath device
- * @sleep: the new state
- *
- * Note that this will only take effect when the link state changes.
- */
-static int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep)
-{
-       if (sleep)
-               dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
-       else
-               dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
-                        dd->ipath_ibcctrl);
-       return 0;
-}
-
-/**
- * recv_subn_set_portinfo - set port information
- * @smp: the incoming SM packet
- * @ibdev: the infiniband device
- * @port: the port on the device
- *
- * Set Portinfo (see ch. 14.2.5.6).
- */
-static int recv_subn_set_portinfo(struct ib_smp *smp,
-                                 struct ib_device *ibdev, u8 port)
-{
-       struct ib_port_info *pip = (struct ib_port_info *)smp->data;
-       struct ib_event event;
-       struct ipath_ibdev *dev;
-       struct ipath_devdata *dd;
-       char clientrereg = 0;
-       u16 lid, smlid;
-       u8 lwe;
-       u8 lse;
-       u8 state;
-       u16 lstate;
-       u32 mtu;
-       int ret, ore;
-
-       if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt)
-               goto err;
-
-       dev = to_idev(ibdev);
-       dd = dev->dd;
-       event.device = ibdev;
-       event.element.port_num = port;
-
-       dev->mkey = pip->mkey;
-       dev->gid_prefix = pip->gid_prefix;
-       dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
-
-       lid = be16_to_cpu(pip->lid);
-       if (dd->ipath_lid != lid ||
-           dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) {
-               /* Must be a valid unicast LID address. */
-               if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
-                       goto err;
-               ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7);
-               event.event = IB_EVENT_LID_CHANGE;
-               ib_dispatch_event(&event);
-       }
-
-       smlid = be16_to_cpu(pip->sm_lid);
-       if (smlid != dev->sm_lid) {
-               /* Must be a valid unicast LID address. */
-               if (smlid == 0 || smlid >= IPATH_MULTICAST_LID_BASE)
-                       goto err;
-               dev->sm_lid = smlid;
-               event.event = IB_EVENT_SM_CHANGE;
-               ib_dispatch_event(&event);
-       }
-
-       /* Allow 1x or 4x to be set (see 14.2.6.6). */
-       lwe = pip->link_width_enabled;
-       if (lwe) {
-               if (lwe == 0xFF)
-                       lwe = dd->ipath_link_width_supported;
-               else if (lwe >= 16 || (lwe & ~dd->ipath_link_width_supported))
-                       goto err;
-               set_link_width_enabled(dd, lwe);
-       }
-
-       /* Allow 2.5 or 5.0 Gbs. */
-       lse = pip->linkspeedactive_enabled & 0xF;
-       if (lse) {
-               if (lse == 15)
-                       lse = dd->ipath_link_speed_supported;
-               else if (lse >= 8 || (lse & ~dd->ipath_link_speed_supported))
-                       goto err;
-               set_link_speed_enabled(dd, lse);
-       }
-
-       /* Set link down default state. */
-       switch (pip->portphysstate_linkdown & 0xF) {
-       case 0: /* NOP */
-               break;
-       case 1: /* SLEEP */
-               if (set_linkdowndefaultstate(dd, 1))
-                       goto err;
-               break;
-       case 2: /* POLL */
-               if (set_linkdowndefaultstate(dd, 0))
-                       goto err;
-               break;
-       default:
-               goto err;
-       }
-
-       dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
-       dev->vl_high_limit = pip->vl_high_limit;
-
-       switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
-       case IB_MTU_256:
-               mtu = 256;
-               break;
-       case IB_MTU_512:
-               mtu = 512;
-               break;
-       case IB_MTU_1024:
-               mtu = 1024;
-               break;
-       case IB_MTU_2048:
-               mtu = 2048;
-               break;
-       case IB_MTU_4096:
-               if (!ipath_mtu4096)
-                       goto err;
-               mtu = 4096;
-               break;
-       default:
-               /* XXX We have already partially updated our state! */
-               goto err;
-       }
-       ipath_set_mtu(dd, mtu);
-
-       dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
-
-       /* We only support VL0 */
-       if (((pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF) > 1)
-               goto err;
-
-       if (pip->mkey_violations == 0)
-               dev->mkey_violations = 0;
-
-       /*
-        * Hardware counter can't be reset so snapshot and subtract
-        * later.
-        */
-       if (pip->pkey_violations == 0)
-               dev->z_pkey_violations = ipath_get_cr_errpkey(dd);
-
-       if (pip->qkey_violations == 0)
-               dev->qkey_violations = 0;
-
-       ore = pip->localphyerrors_overrunerrors;
-       if (set_phyerrthreshold(dd, (ore >> 4) & 0xF))
-               goto err;
-
-       if (set_overrunthreshold(dd, (ore & 0xF)))
-               goto err;
-
-       dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
-
-       if (pip->clientrereg_resv_subnetto & 0x80) {
-               clientrereg = 1;
-               event.event = IB_EVENT_CLIENT_REREGISTER;
-               ib_dispatch_event(&event);
-       }
-
-       /*
-        * Do the port state change now that the other link parameters
-        * have been set.
-        * Changing the port physical state only makes sense if the link
-        * is down or is being set to down.
-        */
-       state = pip->linkspeed_portstate & 0xF;
-       lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
-       if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
-               goto err;
-
-       /*
-        * Only state changes of DOWN, ARM, and ACTIVE are valid
-        * and must be in the correct state to take effect (see 7.2.6).
-        */
-       switch (state) {
-       case IB_PORT_NOP:
-               if (lstate == 0)
-                       break;
-               /* FALLTHROUGH */
-       case IB_PORT_DOWN:
-               if (lstate == 0)
-                       lstate = IPATH_IB_LINKDOWN_ONLY;
-               else if (lstate == 1)
-                       lstate = IPATH_IB_LINKDOWN_SLEEP;
-               else if (lstate == 2)
-                       lstate = IPATH_IB_LINKDOWN;
-               else if (lstate == 3)
-                       lstate = IPATH_IB_LINKDOWN_DISABLE;
-               else
-                       goto err;
-               ipath_set_linkstate(dd, lstate);
-               if (lstate == IPATH_IB_LINKDOWN_DISABLE) {
-                       ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
-                       goto done;
-               }
-               ipath_wait_linkstate(dd, IPATH_LINKINIT | IPATH_LINKARMED |
-                               IPATH_LINKACTIVE, 1000);
-               break;
-       case IB_PORT_ARMED:
-               ipath_set_linkstate(dd, IPATH_IB_LINKARM);
-               break;
-       case IB_PORT_ACTIVE:
-               ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
-               break;
-       default:
-               /* XXX We have already partially updated our state! */
-               goto err;
-       }
-
-       ret = recv_subn_get_portinfo(smp, ibdev, port);
-
-       if (clientrereg)
-               pip->clientrereg_resv_subnetto |= 0x80;
-
-       goto done;
-
-err:
-       smp->status |= IB_SMP_INVALID_FIELD;
-       ret = recv_subn_get_portinfo(smp, ibdev, port);
-
-done:
-       return ret;
-}
-
-/**
- * rm_pkey - decrecment the reference count for the given PKEY
- * @dd: the infinipath device
- * @key: the PKEY index
- *
- * Return true if this was the last reference and the hardware table entry
- * needs to be changed.
- */
-static int rm_pkey(struct ipath_devdata *dd, u16 key)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
-               if (dd->ipath_pkeys[i] != key)
-                       continue;
-               if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
-                       dd->ipath_pkeys[i] = 0;
-                       ret = 1;
-                       goto bail;
-               }
-               break;
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * add_pkey - add the given PKEY to the hardware table
- * @dd: the infinipath device
- * @key: the PKEY
- *
- * Return an error code if unable to add the entry, zero if no change,
- * or 1 if the hardware PKEY register needs to be updated.
- */
-static int add_pkey(struct ipath_devdata *dd, u16 key)
-{
-       int i;
-       u16 lkey = key & 0x7FFF;
-       int any = 0;
-       int ret;
-
-       if (lkey == 0x7FFF) {
-               ret = 0;
-               goto bail;
-       }
-
-       /* Look for an empty slot or a matching PKEY. */
-       for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
-               if (!dd->ipath_pkeys[i]) {
-                       any++;
-                       continue;
-               }
-               /* If it matches exactly, try to increment the ref count */
-               if (dd->ipath_pkeys[i] == key) {
-                       if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
-                               ret = 0;
-                               goto bail;
-                       }
-                       /* Lost the race. Look for an empty slot below. */
-                       atomic_dec(&dd->ipath_pkeyrefs[i]);
-                       any++;
-               }
-               /*
-                * It makes no sense to have both the limited and unlimited
-                * PKEY set at the same time since the unlimited one will
-                * disable the limited one.
-                */
-               if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
-                       ret = -EEXIST;
-                       goto bail;
-               }
-       }
-       if (!any) {
-               ret = -EBUSY;
-               goto bail;
-       }
-       for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
-               if (!dd->ipath_pkeys[i] &&
-                   atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
-                       /* for ipathstats, etc. */
-                       ipath_stats.sps_pkeys[i] = lkey;
-                       dd->ipath_pkeys[i] = key;
-                       ret = 1;
-                       goto bail;
-               }
-       }
-       ret = -EBUSY;
-
-bail:
-       return ret;
-}
-
-/**
- * set_pkeys - set the PKEY table for port 0
- * @dd: the infinipath device
- * @pkeys: the PKEY table
- */
-static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys, u8 port)
-{
-       struct ipath_portdata *pd;
-       int i;
-       int changed = 0;
-
-       /* always a kernel port, no locking needed */
-       pd = dd->ipath_pd[0];
-
-       for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
-               u16 key = pkeys[i];
-               u16 okey = pd->port_pkeys[i];
-
-               if (key == okey)
-                       continue;
-               /*
-                * The value of this PKEY table entry is changing.
-                * Remove the old entry in the hardware's array of PKEYs.
-                */
-               if (okey & 0x7FFF)
-                       changed |= rm_pkey(dd, okey);
-               if (key & 0x7FFF) {
-                       int ret = add_pkey(dd, key);
-
-                       if (ret < 0)
-                               key = 0;
-                       else
-                               changed |= ret;
-               }
-               pd->port_pkeys[i] = key;
-       }
-       if (changed) {
-               u64 pkey;
-               struct ib_event event;
-
-               pkey = (u64) dd->ipath_pkeys[0] |
-                       ((u64) dd->ipath_pkeys[1] << 16) |
-                       ((u64) dd->ipath_pkeys[2] << 32) |
-                       ((u64) dd->ipath_pkeys[3] << 48);
-               ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
-                          (unsigned long long) pkey);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
-                                pkey);
-
-               event.event = IB_EVENT_PKEY_CHANGE;
-               event.device = &dd->verbs_dev->ibdev;
-               event.element.port_num = port;
-               ib_dispatch_event(&event);
-       }
-       return 0;
-}
-
-static int recv_subn_set_pkeytable(struct ib_smp *smp,
-                                  struct ib_device *ibdev, u8 port)
-{
-       u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff);
-       __be16 *p = (__be16 *) smp->data;
-       u16 *q = (u16 *) smp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       unsigned i, n = ipath_get_npkeys(dev->dd);
-
-       for (i = 0; i < n; i++)
-               q[i] = be16_to_cpu(p[i]);
-
-       if (startpx != 0 || set_pkeys(dev->dd, q, port) != 0)
-               smp->status |= IB_SMP_INVALID_FIELD;
-
-       return recv_subn_get_pkeytable(smp, ibdev);
-}
-
-static int recv_pma_get_classportinfo(struct ib_pma_mad *pmp)
-{
-       struct ib_class_port_info *p =
-               (struct ib_class_port_info *)pmp->data;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-
-       if (pmp->mad_hdr.attr_mod != 0)
-               pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
-
-       /* Indicate AllPortSelect is valid (only one port anyway) */
-       p->capability_mask = cpu_to_be16(1 << 8);
-       p->base_version = 1;
-       p->class_version = 1;
-       /*
-        * Expected response time is 4.096 usec. * 2^18 == 1.073741824
-        * sec.
-        */
-       p->resp_time_value = 18;
-
-       return reply((struct ib_smp *) pmp);
-}
-
-/*
- * The PortSamplesControl.CounterMasks field is an array of 3 bit fields
- * which specify the N'th counter's capabilities. See ch. 16.1.3.2.
- * We support 5 counters which only count the mandatory quantities.
- */
-#define COUNTER_MASK(q, n) (q << ((9 - n) * 3))
-#define COUNTER_MASK0_9 cpu_to_be32(COUNTER_MASK(1, 0) | \
-                                   COUNTER_MASK(1, 1) | \
-                                   COUNTER_MASK(1, 2) | \
-                                   COUNTER_MASK(1, 3) | \
-                                   COUNTER_MASK(1, 4))
-
-static int recv_pma_get_portsamplescontrol(struct ib_pma_mad *pmp,
-                                          struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portsamplescontrol *p =
-               (struct ib_pma_portsamplescontrol *)pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-       unsigned long flags;
-       u8 port_select = p->port_select;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-
-       p->port_select = port_select;
-       if (pmp->mad_hdr.attr_mod != 0 ||
-           (port_select != port && port_select != 0xFF))
-               pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
-       /*
-        * Ticks are 10x the link transfer period which for 2.5Gbs is 4
-        * nsec.  0 == 4 nsec., 1 == 8 nsec., ..., 255 == 1020 nsec.  Sample
-        * intervals are counted in ticks.  Since we use Linux timers, that
-        * count in jiffies, we can't sample for less than 1000 ticks if HZ
-        * == 1000 (4000 ticks if HZ is 250).  link_speed_active returns 2 for
-        * DDR, 1 for SDR, set the tick to 1 for DDR, 0 for SDR on chips that
-        * have hardware support for delaying packets.
-        */
-       if (crp->cr_psstat)
-               p->tick = dev->dd->ipath_link_speed_active - 1;
-       else
-               p->tick = 250;          /* 1 usec. */
-       p->counter_width = 4;   /* 32 bit counters */
-       p->counter_mask0_9 = COUNTER_MASK0_9;
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       if (crp->cr_psstat)
-               p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-       else
-               p->sample_status = dev->pma_sample_status;
-       p->sample_start = cpu_to_be32(dev->pma_sample_start);
-       p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
-       p->tag = cpu_to_be16(dev->pma_tag);
-       p->counter_select[0] = dev->pma_counter_select[0];
-       p->counter_select[1] = dev->pma_counter_select[1];
-       p->counter_select[2] = dev->pma_counter_select[2];
-       p->counter_select[3] = dev->pma_counter_select[3];
-       p->counter_select[4] = dev->pma_counter_select[4];
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-
-       return reply((struct ib_smp *) pmp);
-}
-
-static int recv_pma_set_portsamplescontrol(struct ib_pma_mad *pmp,
-                                          struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portsamplescontrol *p =
-               (struct ib_pma_portsamplescontrol *)pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-       unsigned long flags;
-       u8 status;
-       int ret;
-
-       if (pmp->mad_hdr.attr_mod != 0 ||
-           (p->port_select != port && p->port_select != 0xFF)) {
-               pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
-               ret = reply((struct ib_smp *) pmp);
-               goto bail;
-       }
-
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       if (crp->cr_psstat)
-               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-       else
-               status = dev->pma_sample_status;
-       if (status == IB_PMA_SAMPLE_STATUS_DONE) {
-               dev->pma_sample_start = be32_to_cpu(p->sample_start);
-               dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
-               dev->pma_tag = be16_to_cpu(p->tag);
-               dev->pma_counter_select[0] = p->counter_select[0];
-               dev->pma_counter_select[1] = p->counter_select[1];
-               dev->pma_counter_select[2] = p->counter_select[2];
-               dev->pma_counter_select[3] = p->counter_select[3];
-               dev->pma_counter_select[4] = p->counter_select[4];
-               if (crp->cr_psstat) {
-                       ipath_write_creg(dev->dd, crp->cr_psinterval,
-                                        dev->pma_sample_interval);
-                       ipath_write_creg(dev->dd, crp->cr_psstart,
-                                        dev->pma_sample_start);
-               } else
-                       dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
-       }
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-
-       ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
-
-bail:
-       return ret;
-}
-
-static u64 get_counter(struct ipath_ibdev *dev,
-                      struct ipath_cregs const *crp,
-                      __be16 sel)
-{
-       u64 ret;
-
-       switch (sel) {
-       case IB_PMA_PORT_XMIT_DATA:
-               ret = (crp->cr_psxmitdatacount) ?
-                       ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
-                       dev->ipath_sword;
-               break;
-       case IB_PMA_PORT_RCV_DATA:
-               ret = (crp->cr_psrcvdatacount) ?
-                       ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
-                       dev->ipath_rword;
-               break;
-       case IB_PMA_PORT_XMIT_PKTS:
-               ret = (crp->cr_psxmitpktscount) ?
-                       ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
-                       dev->ipath_spkts;
-               break;
-       case IB_PMA_PORT_RCV_PKTS:
-               ret = (crp->cr_psrcvpktscount) ?
-                       ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
-                       dev->ipath_rpkts;
-               break;
-       case IB_PMA_PORT_XMIT_WAIT:
-               ret = (crp->cr_psxmitwaitcount) ?
-                       ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
-                       dev->ipath_xmit_wait;
-               break;
-       default:
-               ret = 0;
-       }
-
-       return ret;
-}
-
-static int recv_pma_get_portsamplesresult(struct ib_pma_mad *pmp,
-                                         struct ib_device *ibdev)
-{
-       struct ib_pma_portsamplesresult *p =
-               (struct ib_pma_portsamplesresult *)pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-       u8 status;
-       int i;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-       p->tag = cpu_to_be16(dev->pma_tag);
-       if (crp->cr_psstat)
-               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-       else
-               status = dev->pma_sample_status;
-       p->sample_status = cpu_to_be16(status);
-       for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-               p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
-                   cpu_to_be32(
-                       get_counter(dev, crp, dev->pma_counter_select[i]));
-
-       return reply((struct ib_smp *) pmp);
-}
-
-static int recv_pma_get_portsamplesresult_ext(struct ib_pma_mad *pmp,
-                                             struct ib_device *ibdev)
-{
-       struct ib_pma_portsamplesresult_ext *p =
-               (struct ib_pma_portsamplesresult_ext *)pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_cregs const *crp = dev->dd->ipath_cregs;
-       u8 status;
-       int i;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-       p->tag = cpu_to_be16(dev->pma_tag);
-       if (crp->cr_psstat)
-               status = ipath_read_creg32(dev->dd, crp->cr_psstat);
-       else
-               status = dev->pma_sample_status;
-       p->sample_status = cpu_to_be16(status);
-       /* 64 bits */
-       p->extended_width = cpu_to_be32(0x80000000);
-       for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-               p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
-                   cpu_to_be64(
-                       get_counter(dev, crp, dev->pma_counter_select[i]));
-
-       return reply((struct ib_smp *) pmp);
-}
-
-static int recv_pma_get_portcounters(struct ib_pma_mad *pmp,
-                                    struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
-               pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_verbs_counters cntrs;
-       u8 port_select = p->port_select;
-
-       ipath_get_counters(dev->dd, &cntrs);
-
-       /* Adjust counters for any resets done. */
-       cntrs.symbol_error_counter -= dev->z_symbol_error_counter;
-       cntrs.link_error_recovery_counter -=
-               dev->z_link_error_recovery_counter;
-       cntrs.link_downed_counter -= dev->z_link_downed_counter;
-       cntrs.port_rcv_errors += dev->rcv_errors;
-       cntrs.port_rcv_errors -= dev->z_port_rcv_errors;
-       cntrs.port_rcv_remphys_errors -= dev->z_port_rcv_remphys_errors;
-       cntrs.port_xmit_discards -= dev->z_port_xmit_discards;
-       cntrs.port_xmit_data -= dev->z_port_xmit_data;
-       cntrs.port_rcv_data -= dev->z_port_rcv_data;
-       cntrs.port_xmit_packets -= dev->z_port_xmit_packets;
-       cntrs.port_rcv_packets -= dev->z_port_rcv_packets;
-       cntrs.local_link_integrity_errors -=
-               dev->z_local_link_integrity_errors;
-       cntrs.excessive_buffer_overrun_errors -=
-               dev->z_excessive_buffer_overrun_errors;
-       cntrs.vl15_dropped -= dev->z_vl15_dropped;
-       cntrs.vl15_dropped += dev->n_vl15_dropped;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-
-       p->port_select = port_select;
-       if (pmp->mad_hdr.attr_mod != 0 ||
-           (port_select != port && port_select != 0xFF))
-               pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
-
-       if (cntrs.symbol_error_counter > 0xFFFFUL)
-               p->symbol_error_counter = cpu_to_be16(0xFFFF);
-       else
-               p->symbol_error_counter =
-                       cpu_to_be16((u16)cntrs.symbol_error_counter);
-       if (cntrs.link_error_recovery_counter > 0xFFUL)
-               p->link_error_recovery_counter = 0xFF;
-       else
-               p->link_error_recovery_counter =
-                       (u8)cntrs.link_error_recovery_counter;
-       if (cntrs.link_downed_counter > 0xFFUL)
-               p->link_downed_counter = 0xFF;
-       else
-               p->link_downed_counter = (u8)cntrs.link_downed_counter;
-       if (cntrs.port_rcv_errors > 0xFFFFUL)
-               p->port_rcv_errors = cpu_to_be16(0xFFFF);
-       else
-               p->port_rcv_errors =
-                       cpu_to_be16((u16) cntrs.port_rcv_errors);
-       if (cntrs.port_rcv_remphys_errors > 0xFFFFUL)
-               p->port_rcv_remphys_errors = cpu_to_be16(0xFFFF);
-       else
-               p->port_rcv_remphys_errors =
-                       cpu_to_be16((u16)cntrs.port_rcv_remphys_errors);
-       if (cntrs.port_xmit_discards > 0xFFFFUL)
-               p->port_xmit_discards = cpu_to_be16(0xFFFF);
-       else
-               p->port_xmit_discards =
-                       cpu_to_be16((u16)cntrs.port_xmit_discards);
-       if (cntrs.local_link_integrity_errors > 0xFUL)
-               cntrs.local_link_integrity_errors = 0xFUL;
-       if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
-               cntrs.excessive_buffer_overrun_errors = 0xFUL;
-       p->link_overrun_errors = (cntrs.local_link_integrity_errors << 4) |
-               cntrs.excessive_buffer_overrun_errors;
-       if (cntrs.vl15_dropped > 0xFFFFUL)
-               p->vl15_dropped = cpu_to_be16(0xFFFF);
-       else
-               p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
-       if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
-               p->port_xmit_data = cpu_to_be32(0xFFFFFFFF);
-       else
-               p->port_xmit_data = cpu_to_be32((u32)cntrs.port_xmit_data);
-       if (cntrs.port_rcv_data > 0xFFFFFFFFUL)
-               p->port_rcv_data = cpu_to_be32(0xFFFFFFFF);
-       else
-               p->port_rcv_data = cpu_to_be32((u32)cntrs.port_rcv_data);
-       if (cntrs.port_xmit_packets > 0xFFFFFFFFUL)
-               p->port_xmit_packets = cpu_to_be32(0xFFFFFFFF);
-       else
-               p->port_xmit_packets =
-                       cpu_to_be32((u32)cntrs.port_xmit_packets);
-       if (cntrs.port_rcv_packets > 0xFFFFFFFFUL)
-               p->port_rcv_packets = cpu_to_be32(0xFFFFFFFF);
-       else
-               p->port_rcv_packets =
-                       cpu_to_be32((u32) cntrs.port_rcv_packets);
-
-       return reply((struct ib_smp *) pmp);
-}
-
-static int recv_pma_get_portcounters_ext(struct ib_pma_mad *pmp,
-                                        struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portcounters_ext *p =
-               (struct ib_pma_portcounters_ext *)pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       u64 swords, rwords, spkts, rpkts, xwait;
-       u8 port_select = p->port_select;
-
-       ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
-                               &rpkts, &xwait);
-
-       /* Adjust counters for any resets done. */
-       swords -= dev->z_port_xmit_data;
-       rwords -= dev->z_port_rcv_data;
-       spkts -= dev->z_port_xmit_packets;
-       rpkts -= dev->z_port_rcv_packets;
-
-       memset(pmp->data, 0, sizeof(pmp->data));
-
-       p->port_select = port_select;
-       if (pmp->mad_hdr.attr_mod != 0 ||
-           (port_select != port && port_select != 0xFF))
-               pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD;
-
-       p->port_xmit_data = cpu_to_be64(swords);
-       p->port_rcv_data = cpu_to_be64(rwords);
-       p->port_xmit_packets = cpu_to_be64(spkts);
-       p->port_rcv_packets = cpu_to_be64(rpkts);
-       p->port_unicast_xmit_packets = cpu_to_be64(dev->n_unicast_xmit);
-       p->port_unicast_rcv_packets = cpu_to_be64(dev->n_unicast_rcv);
-       p->port_multicast_xmit_packets = cpu_to_be64(dev->n_multicast_xmit);
-       p->port_multicast_rcv_packets = cpu_to_be64(dev->n_multicast_rcv);
-
-       return reply((struct ib_smp *) pmp);
-}
-
-static int recv_pma_set_portcounters(struct ib_pma_mad *pmp,
-                                    struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
-               pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_verbs_counters cntrs;
-
-       /*
-        * Since the HW doesn't support clearing counters, we save the
-        * current count and subtract it from future responses.
-        */
-       ipath_get_counters(dev->dd, &cntrs);
-
-       if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
-               dev->z_symbol_error_counter = cntrs.symbol_error_counter;
-
-       if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY)
-               dev->z_link_error_recovery_counter =
-                       cntrs.link_error_recovery_counter;
-
-       if (p->counter_select & IB_PMA_SEL_LINK_DOWNED)
-               dev->z_link_downed_counter = cntrs.link_downed_counter;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS)
-               dev->z_port_rcv_errors =
-                       cntrs.port_rcv_errors + dev->rcv_errors;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS)
-               dev->z_port_rcv_remphys_errors =
-                       cntrs.port_rcv_remphys_errors;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS)
-               dev->z_port_xmit_discards = cntrs.port_xmit_discards;
-
-       if (p->counter_select & IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS)
-               dev->z_local_link_integrity_errors =
-                       cntrs.local_link_integrity_errors;
-
-       if (p->counter_select & IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS)
-               dev->z_excessive_buffer_overrun_errors =
-                       cntrs.excessive_buffer_overrun_errors;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
-               dev->n_vl15_dropped = 0;
-               dev->z_vl15_dropped = cntrs.vl15_dropped;
-       }
-
-       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
-               dev->z_port_xmit_data = cntrs.port_xmit_data;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA)
-               dev->z_port_rcv_data = cntrs.port_rcv_data;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS)
-               dev->z_port_xmit_packets = cntrs.port_xmit_packets;
-
-       if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS)
-               dev->z_port_rcv_packets = cntrs.port_rcv_packets;
-
-       return recv_pma_get_portcounters(pmp, ibdev, port);
-}
-
-static int recv_pma_set_portcounters_ext(struct ib_pma_mad *pmp,
-                                        struct ib_device *ibdev, u8 port)
-{
-       struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
-               pmp->data;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       u64 swords, rwords, spkts, rpkts, xwait;
-
-       ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
-                               &rpkts, &xwait);
-
-       if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
-               dev->z_port_xmit_data = swords;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA)
-               dev->z_port_rcv_data = rwords;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS)
-               dev->z_port_xmit_packets = spkts;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
-               dev->z_port_rcv_packets = rpkts;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
-               dev->n_unicast_xmit = 0;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS)
-               dev->n_unicast_rcv = 0;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS)
-               dev->n_multicast_xmit = 0;
-
-       if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS)
-               dev->n_multicast_rcv = 0;
-
-       return recv_pma_get_portcounters_ext(pmp, ibdev, port);
-}
-
-static int process_subn(struct ib_device *ibdev, int mad_flags,
-                       u8 port_num, const struct ib_mad *in_mad,
-                       struct ib_mad *out_mad)
-{
-       struct ib_smp *smp = (struct ib_smp *)out_mad;
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       int ret;
-
-       *out_mad = *in_mad;
-       if (smp->class_version != 1) {
-               smp->status |= IB_SMP_UNSUP_VERSION;
-               ret = reply(smp);
-               goto bail;
-       }
-
-       /* Is the mkey in the process of expiring? */
-       if (dev->mkey_lease_timeout &&
-           time_after_eq(jiffies, dev->mkey_lease_timeout)) {
-               /* Clear timeout and mkey protection field. */
-               dev->mkey_lease_timeout = 0;
-               dev->mkeyprot = 0;
-       }
-
-       /*
-        * M_Key checking depends on
-        * Portinfo:M_Key_protect_bits
-        */
-       if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && dev->mkey != 0 &&
-           dev->mkey != smp->mkey &&
-           (smp->method == IB_MGMT_METHOD_SET ||
-            (smp->method == IB_MGMT_METHOD_GET &&
-             dev->mkeyprot >= 2))) {
-               if (dev->mkey_violations != 0xFFFF)
-                       ++dev->mkey_violations;
-               if (dev->mkey_lease_timeout ||
-                   dev->mkey_lease_period == 0) {
-                       ret = IB_MAD_RESULT_SUCCESS |
-                               IB_MAD_RESULT_CONSUMED;
-                       goto bail;
-               }
-               dev->mkey_lease_timeout = jiffies +
-                       dev->mkey_lease_period * HZ;
-               /* Future: Generate a trap notice. */
-               ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED;
-               goto bail;
-       } else if (dev->mkey_lease_timeout)
-               dev->mkey_lease_timeout = 0;
-
-       switch (smp->method) {
-       case IB_MGMT_METHOD_GET:
-               switch (smp->attr_id) {
-               case IB_SMP_ATTR_NODE_DESC:
-                       ret = recv_subn_get_nodedescription(smp, ibdev);
-                       goto bail;
-               case IB_SMP_ATTR_NODE_INFO:
-                       ret = recv_subn_get_nodeinfo(smp, ibdev, port_num);
-                       goto bail;
-               case IB_SMP_ATTR_GUID_INFO:
-                       ret = recv_subn_get_guidinfo(smp, ibdev);
-                       goto bail;
-               case IB_SMP_ATTR_PORT_INFO:
-                       ret = recv_subn_get_portinfo(smp, ibdev, port_num);
-                       goto bail;
-               case IB_SMP_ATTR_PKEY_TABLE:
-                       ret = recv_subn_get_pkeytable(smp, ibdev);
-                       goto bail;
-               case IB_SMP_ATTR_SM_INFO:
-                       if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
-                               ret = IB_MAD_RESULT_SUCCESS |
-                                       IB_MAD_RESULT_CONSUMED;
-                               goto bail;
-                       }
-                       if (dev->port_cap_flags & IB_PORT_SM) {
-                               ret = IB_MAD_RESULT_SUCCESS;
-                               goto bail;
-                       }
-                       /* FALLTHROUGH */
-               default:
-                       smp->status |= IB_SMP_UNSUP_METH_ATTR;
-                       ret = reply(smp);
-                       goto bail;
-               }
-
-       case IB_MGMT_METHOD_SET:
-               switch (smp->attr_id) {
-               case IB_SMP_ATTR_GUID_INFO:
-                       ret = recv_subn_set_guidinfo(smp, ibdev);
-                       goto bail;
-               case IB_SMP_ATTR_PORT_INFO:
-                       ret = recv_subn_set_portinfo(smp, ibdev, port_num);
-                       goto bail;
-               case IB_SMP_ATTR_PKEY_TABLE:
-                       ret = recv_subn_set_pkeytable(smp, ibdev, port_num);
-                       goto bail;
-               case IB_SMP_ATTR_SM_INFO:
-                       if (dev->port_cap_flags & IB_PORT_SM_DISABLED) {
-                               ret = IB_MAD_RESULT_SUCCESS |
-                                       IB_MAD_RESULT_CONSUMED;
-                               goto bail;
-                       }
-                       if (dev->port_cap_flags & IB_PORT_SM) {
-                               ret = IB_MAD_RESULT_SUCCESS;
-                               goto bail;
-                       }
-                       /* FALLTHROUGH */
-               default:
-                       smp->status |= IB_SMP_UNSUP_METH_ATTR;
-                       ret = reply(smp);
-                       goto bail;
-               }
-
-       case IB_MGMT_METHOD_TRAP:
-       case IB_MGMT_METHOD_REPORT:
-       case IB_MGMT_METHOD_REPORT_RESP:
-       case IB_MGMT_METHOD_TRAP_REPRESS:
-       case IB_MGMT_METHOD_GET_RESP:
-               /*
-                * The ib_mad module will call us to process responses
-                * before checking for other consumers.
-                * Just tell the caller to process it normally.
-                */
-               ret = IB_MAD_RESULT_SUCCESS;
-               goto bail;
-       default:
-               smp->status |= IB_SMP_UNSUP_METHOD;
-               ret = reply(smp);
-       }
-
-bail:
-       return ret;
-}
-
-static int process_perf(struct ib_device *ibdev, u8 port_num,
-                       const struct ib_mad *in_mad,
-                       struct ib_mad *out_mad)
-{
-       struct ib_pma_mad *pmp = (struct ib_pma_mad *)out_mad;
-       int ret;
-
-       *out_mad = *in_mad;
-       if (pmp->mad_hdr.class_version != 1) {
-               pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION;
-               ret = reply((struct ib_smp *) pmp);
-               goto bail;
-       }
-
-       switch (pmp->mad_hdr.method) {
-       case IB_MGMT_METHOD_GET:
-               switch (pmp->mad_hdr.attr_id) {
-               case IB_PMA_CLASS_PORT_INFO:
-                       ret = recv_pma_get_classportinfo(pmp);
-                       goto bail;
-               case IB_PMA_PORT_SAMPLES_CONTROL:
-                       ret = recv_pma_get_portsamplescontrol(pmp, ibdev,
-                                                             port_num);
-                       goto bail;
-               case IB_PMA_PORT_SAMPLES_RESULT:
-                       ret = recv_pma_get_portsamplesresult(pmp, ibdev);
-                       goto bail;
-               case IB_PMA_PORT_SAMPLES_RESULT_EXT:
-                       ret = recv_pma_get_portsamplesresult_ext(pmp,
-                                                                ibdev);
-                       goto bail;
-               case IB_PMA_PORT_COUNTERS:
-                       ret = recv_pma_get_portcounters(pmp, ibdev,
-                                                       port_num);
-                       goto bail;
-               case IB_PMA_PORT_COUNTERS_EXT:
-                       ret = recv_pma_get_portcounters_ext(pmp, ibdev,
-                                                           port_num);
-                       goto bail;
-               default:
-                       pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR;
-                       ret = reply((struct ib_smp *) pmp);
-                       goto bail;
-               }
-
-       case IB_MGMT_METHOD_SET:
-               switch (pmp->mad_hdr.attr_id) {
-               case IB_PMA_PORT_SAMPLES_CONTROL:
-                       ret = recv_pma_set_portsamplescontrol(pmp, ibdev,
-                                                             port_num);
-                       goto bail;
-               case IB_PMA_PORT_COUNTERS:
-                       ret = recv_pma_set_portcounters(pmp, ibdev,
-                                                       port_num);
-                       goto bail;
-               case IB_PMA_PORT_COUNTERS_EXT:
-                       ret = recv_pma_set_portcounters_ext(pmp, ibdev,
-                                                           port_num);
-                       goto bail;
-               default:
-                       pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR;
-                       ret = reply((struct ib_smp *) pmp);
-                       goto bail;
-               }
-
-       case IB_MGMT_METHOD_GET_RESP:
-               /*
-                * The ib_mad module will call us to process responses
-                * before checking for other consumers.
-                * Just tell the caller to process it normally.
-                */
-               ret = IB_MAD_RESULT_SUCCESS;
-               goto bail;
-       default:
-               pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD;
-               ret = reply((struct ib_smp *) pmp);
-       }
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_process_mad - process an incoming MAD packet
- * @ibdev: the infiniband device this packet came in on
- * @mad_flags: MAD flags
- * @port_num: the port number this packet came in on
- * @in_wc: the work completion entry for this packet
- * @in_grh: the global route header for this packet
- * @in_mad: the incoming MAD
- * @out_mad: any outgoing MAD reply
- *
- * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not
- * interested in processing.
- *
- * Note that the verbs framework has already done the MAD sanity checks,
- * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
- * MADs.
- *
- * This is called by the ib_mad module.
- */
-int ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
-                     const struct ib_wc *in_wc, const struct ib_grh *in_grh,
-                     const struct ib_mad_hdr *in, size_t in_mad_size,
-                     struct ib_mad_hdr *out, size_t *out_mad_size,
-                     u16 *out_mad_pkey_index)
-{
-       int ret;
-       const struct ib_mad *in_mad = (const struct ib_mad *)in;
-       struct ib_mad *out_mad = (struct ib_mad *)out;
-
-       if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
-                        *out_mad_size != sizeof(*out_mad)))
-               return IB_MAD_RESULT_FAILURE;
-
-       switch (in_mad->mad_hdr.mgmt_class) {
-       case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
-       case IB_MGMT_CLASS_SUBN_LID_ROUTED:
-               ret = process_subn(ibdev, mad_flags, port_num,
-                                  in_mad, out_mad);
-               goto bail;
-       case IB_MGMT_CLASS_PERF_MGMT:
-               ret = process_perf(ibdev, port_num, in_mad, out_mad);
-               goto bail;
-       default:
-               ret = IB_MAD_RESULT_SUCCESS;
-       }
-
-bail:
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_mmap.c b/drivers/staging/rdma/ipath/ipath_mmap.c
deleted file mode 100644 (file)
index e732742..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <asm/pgtable.h>
-
-#include "ipath_verbs.h"
-
-/**
- * ipath_release_mmap_info - free mmap info structure
- * @ref: a pointer to the kref within struct ipath_mmap_info
- */
-void ipath_release_mmap_info(struct kref *ref)
-{
-       struct ipath_mmap_info *ip =
-               container_of(ref, struct ipath_mmap_info, ref);
-       struct ipath_ibdev *dev = to_idev(ip->context->device);
-
-       spin_lock_irq(&dev->pending_lock);
-       list_del(&ip->pending_mmaps);
-       spin_unlock_irq(&dev->pending_lock);
-
-       vfree(ip->obj);
-       kfree(ip);
-}
-
-/*
- * open and close keep track of how many times the CQ is mapped,
- * to avoid releasing it.
- */
-static void ipath_vma_open(struct vm_area_struct *vma)
-{
-       struct ipath_mmap_info *ip = vma->vm_private_data;
-
-       kref_get(&ip->ref);
-}
-
-static void ipath_vma_close(struct vm_area_struct *vma)
-{
-       struct ipath_mmap_info *ip = vma->vm_private_data;
-
-       kref_put(&ip->ref, ipath_release_mmap_info);
-}
-
-static const struct vm_operations_struct ipath_vm_ops = {
-       .open =     ipath_vma_open,
-       .close =    ipath_vma_close,
-};
-
-/**
- * ipath_mmap - create a new mmap region
- * @context: the IB user context of the process making the mmap() call
- * @vma: the VMA to be initialized
- * Return zero if the mmap is OK. Otherwise, return an errno.
- */
-int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
-{
-       struct ipath_ibdev *dev = to_idev(context->device);
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       unsigned long size = vma->vm_end - vma->vm_start;
-       struct ipath_mmap_info *ip, *pp;
-       int ret = -EINVAL;
-
-       /*
-        * Search the device's list of objects waiting for a mmap call.
-        * Normally, this list is very short since a call to create a
-        * CQ, QP, or SRQ is soon followed by a call to mmap().
-        */
-       spin_lock_irq(&dev->pending_lock);
-       list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
-                                pending_mmaps) {
-               /* Only the creator is allowed to mmap the object */
-               if (context != ip->context || (__u64) offset != ip->offset)
-                       continue;
-               /* Don't allow a mmap larger than the object. */
-               if (size > ip->size)
-                       break;
-
-               list_del_init(&ip->pending_mmaps);
-               spin_unlock_irq(&dev->pending_lock);
-
-               ret = remap_vmalloc_range(vma, ip->obj, 0);
-               if (ret)
-                       goto done;
-               vma->vm_ops = &ipath_vm_ops;
-               vma->vm_private_data = ip;
-               ipath_vma_open(vma);
-               goto done;
-       }
-       spin_unlock_irq(&dev->pending_lock);
-done:
-       return ret;
-}
-
-/*
- * Allocate information for ipath_mmap
- */
-struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
-                                              u32 size,
-                                              struct ib_ucontext *context,
-                                              void *obj) {
-       struct ipath_mmap_info *ip;
-
-       ip = kmalloc(sizeof *ip, GFP_KERNEL);
-       if (!ip)
-               goto bail;
-
-       size = PAGE_ALIGN(size);
-
-       spin_lock_irq(&dev->mmap_offset_lock);
-       if (dev->mmap_offset == 0)
-               dev->mmap_offset = PAGE_SIZE;
-       ip->offset = dev->mmap_offset;
-       dev->mmap_offset += size;
-       spin_unlock_irq(&dev->mmap_offset_lock);
-
-       INIT_LIST_HEAD(&ip->pending_mmaps);
-       ip->size = size;
-       ip->context = context;
-       ip->obj = obj;
-       kref_init(&ip->ref);
-
-bail:
-       return ip;
-}
-
-void ipath_update_mmap_info(struct ipath_ibdev *dev,
-                           struct ipath_mmap_info *ip,
-                           u32 size, void *obj) {
-       size = PAGE_ALIGN(size);
-
-       spin_lock_irq(&dev->mmap_offset_lock);
-       if (dev->mmap_offset == 0)
-               dev->mmap_offset = PAGE_SIZE;
-       ip->offset = dev->mmap_offset;
-       dev->mmap_offset += size;
-       spin_unlock_irq(&dev->mmap_offset_lock);
-
-       ip->size = size;
-       ip->obj = obj;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_mr.c b/drivers/staging/rdma/ipath/ipath_mr.c
deleted file mode 100644 (file)
index b76b0ce..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/slab.h>
-
-#include <rdma/ib_umem.h>
-#include <rdma/ib_pack.h>
-#include <rdma/ib_smi.h>
-
-#include "ipath_verbs.h"
-
-/* Fast memory region */
-struct ipath_fmr {
-       struct ib_fmr ibfmr;
-       u8 page_shift;
-       struct ipath_mregion mr;        /* must be last */
-};
-
-static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
-{
-       return container_of(ibfmr, struct ipath_fmr, ibfmr);
-}
-
-/**
- * ipath_get_dma_mr - get a DMA memory region
- * @pd: protection domain for this memory region
- * @acc: access flags
- *
- * Returns the memory region on success, otherwise returns an errno.
- * Note that all DMA addresses should be created via the
- * struct ib_dma_mapping_ops functions (see ipath_dma.c).
- */
-struct ib_mr *ipath_get_dma_mr(struct ib_pd *pd, int acc)
-{
-       struct ipath_mr *mr;
-       struct ib_mr *ret;
-
-       mr = kzalloc(sizeof *mr, GFP_KERNEL);
-       if (!mr) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       mr->mr.access_flags = acc;
-       ret = &mr->ibmr;
-
-bail:
-       return ret;
-}
-
-static struct ipath_mr *alloc_mr(int count,
-                                struct ipath_lkey_table *lk_table)
-{
-       struct ipath_mr *mr;
-       int m, i = 0;
-
-       /* Allocate struct plus pointers to first level page tables. */
-       m = (count + IPATH_SEGSZ - 1) / IPATH_SEGSZ;
-       mr = kmalloc(sizeof *mr + m * sizeof mr->mr.map[0], GFP_KERNEL);
-       if (!mr)
-               goto done;
-
-       /* Allocate first level page tables. */
-       for (; i < m; i++) {
-               mr->mr.map[i] = kmalloc(sizeof *mr->mr.map[0], GFP_KERNEL);
-               if (!mr->mr.map[i])
-                       goto bail;
-       }
-       mr->mr.mapsz = m;
-
-       if (!ipath_alloc_lkey(lk_table, &mr->mr))
-               goto bail;
-       mr->ibmr.rkey = mr->ibmr.lkey = mr->mr.lkey;
-
-       goto done;
-
-bail:
-       while (i) {
-               i--;
-               kfree(mr->mr.map[i]);
-       }
-       kfree(mr);
-       mr = NULL;
-
-done:
-       return mr;
-}
-
-/**
- * ipath_reg_user_mr - register a userspace memory region
- * @pd: protection domain for this memory region
- * @start: starting userspace address
- * @length: length of region to register
- * @virt_addr: virtual address to use (from HCA's point of view)
- * @mr_access_flags: access flags for this memory region
- * @udata: unused by the InfiniPath driver
- *
- * Returns the memory region on success, otherwise returns an errno.
- */
-struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
-                               u64 virt_addr, int mr_access_flags,
-                               struct ib_udata *udata)
-{
-       struct ipath_mr *mr;
-       struct ib_umem *umem;
-       int n, m, entry;
-       struct scatterlist *sg;
-       struct ib_mr *ret;
-
-       if (length == 0) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       umem = ib_umem_get(pd->uobject->context, start, length,
-                          mr_access_flags, 0);
-       if (IS_ERR(umem))
-               return (void *) umem;
-
-       n = umem->nmap;
-       mr = alloc_mr(n, &to_idev(pd->device)->lk_table);
-       if (!mr) {
-               ret = ERR_PTR(-ENOMEM);
-               ib_umem_release(umem);
-               goto bail;
-       }
-
-       mr->mr.pd = pd;
-       mr->mr.user_base = start;
-       mr->mr.iova = virt_addr;
-       mr->mr.length = length;
-       mr->mr.offset = ib_umem_offset(umem);
-       mr->mr.access_flags = mr_access_flags;
-       mr->mr.max_segs = n;
-       mr->umem = umem;
-
-       m = 0;
-       n = 0;
-       for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) {
-               void *vaddr;
-
-               vaddr = page_address(sg_page(sg));
-               if (!vaddr) {
-                       ret = ERR_PTR(-EINVAL);
-                       goto bail;
-               }
-               mr->mr.map[m]->segs[n].vaddr = vaddr;
-               mr->mr.map[m]->segs[n].length = umem->page_size;
-               n++;
-               if (n == IPATH_SEGSZ) {
-                       m++;
-                       n = 0;
-               }
-       }
-       ret = &mr->ibmr;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_dereg_mr - unregister and free a memory region
- * @ibmr: the memory region to free
- *
- * Returns 0 on success.
- *
- * Note that this is called to free MRs created by ipath_get_dma_mr()
- * or ipath_reg_user_mr().
- */
-int ipath_dereg_mr(struct ib_mr *ibmr)
-{
-       struct ipath_mr *mr = to_imr(ibmr);
-       int i;
-
-       ipath_free_lkey(&to_idev(ibmr->device)->lk_table, ibmr->lkey);
-       i = mr->mr.mapsz;
-       while (i) {
-               i--;
-               kfree(mr->mr.map[i]);
-       }
-
-       if (mr->umem)
-               ib_umem_release(mr->umem);
-
-       kfree(mr);
-       return 0;
-}
-
-/**
- * ipath_alloc_fmr - allocate a fast memory region
- * @pd: the protection domain for this memory region
- * @mr_access_flags: access flags for this memory region
- * @fmr_attr: fast memory region attributes
- *
- * Returns the memory region on success, otherwise returns an errno.
- */
-struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
-                              struct ib_fmr_attr *fmr_attr)
-{
-       struct ipath_fmr *fmr;
-       int m, i = 0;
-       struct ib_fmr *ret;
-
-       /* Allocate struct plus pointers to first level page tables. */
-       m = (fmr_attr->max_pages + IPATH_SEGSZ - 1) / IPATH_SEGSZ;
-       fmr = kmalloc(sizeof *fmr + m * sizeof fmr->mr.map[0], GFP_KERNEL);
-       if (!fmr)
-               goto bail;
-
-       /* Allocate first level page tables. */
-       for (; i < m; i++) {
-               fmr->mr.map[i] = kmalloc(sizeof *fmr->mr.map[0],
-                                        GFP_KERNEL);
-               if (!fmr->mr.map[i])
-                       goto bail;
-       }
-       fmr->mr.mapsz = m;
-
-       /*
-        * ib_alloc_fmr() will initialize fmr->ibfmr except for lkey &
-        * rkey.
-        */
-       if (!ipath_alloc_lkey(&to_idev(pd->device)->lk_table, &fmr->mr))
-               goto bail;
-       fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mr.lkey;
-       /*
-        * Resources are allocated but no valid mapping (RKEY can't be
-        * used).
-        */
-       fmr->mr.pd = pd;
-       fmr->mr.user_base = 0;
-       fmr->mr.iova = 0;
-       fmr->mr.length = 0;
-       fmr->mr.offset = 0;
-       fmr->mr.access_flags = mr_access_flags;
-       fmr->mr.max_segs = fmr_attr->max_pages;
-       fmr->page_shift = fmr_attr->page_shift;
-
-       ret = &fmr->ibfmr;
-       goto done;
-
-bail:
-       while (i)
-               kfree(fmr->mr.map[--i]);
-       kfree(fmr);
-       ret = ERR_PTR(-ENOMEM);
-
-done:
-       return ret;
-}
-
-/**
- * ipath_map_phys_fmr - set up a fast memory region
- * @ibmfr: the fast memory region to set up
- * @page_list: the list of pages to associate with the fast memory region
- * @list_len: the number of pages to associate with the fast memory region
- * @iova: the virtual address of the start of the fast memory region
- *
- * This may be called from interrupt context.
- */
-
-int ipath_map_phys_fmr(struct ib_fmr *ibfmr, u64 * page_list,
-                      int list_len, u64 iova)
-{
-       struct ipath_fmr *fmr = to_ifmr(ibfmr);
-       struct ipath_lkey_table *rkt;
-       unsigned long flags;
-       int m, n, i;
-       u32 ps;
-       int ret;
-
-       if (list_len > fmr->mr.max_segs) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       rkt = &to_idev(ibfmr->device)->lk_table;
-       spin_lock_irqsave(&rkt->lock, flags);
-       fmr->mr.user_base = iova;
-       fmr->mr.iova = iova;
-       ps = 1 << fmr->page_shift;
-       fmr->mr.length = list_len * ps;
-       m = 0;
-       n = 0;
-       ps = 1 << fmr->page_shift;
-       for (i = 0; i < list_len; i++) {
-               fmr->mr.map[m]->segs[n].vaddr = (void *) page_list[i];
-               fmr->mr.map[m]->segs[n].length = ps;
-               if (++n == IPATH_SEGSZ) {
-                       m++;
-                       n = 0;
-               }
-       }
-       spin_unlock_irqrestore(&rkt->lock, flags);
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_unmap_fmr - unmap fast memory regions
- * @fmr_list: the list of fast memory regions to unmap
- *
- * Returns 0 on success.
- */
-int ipath_unmap_fmr(struct list_head *fmr_list)
-{
-       struct ipath_fmr *fmr;
-       struct ipath_lkey_table *rkt;
-       unsigned long flags;
-
-       list_for_each_entry(fmr, fmr_list, ibfmr.list) {
-               rkt = &to_idev(fmr->ibfmr.device)->lk_table;
-               spin_lock_irqsave(&rkt->lock, flags);
-               fmr->mr.user_base = 0;
-               fmr->mr.iova = 0;
-               fmr->mr.length = 0;
-               spin_unlock_irqrestore(&rkt->lock, flags);
-       }
-       return 0;
-}
-
-/**
- * ipath_dealloc_fmr - deallocate a fast memory region
- * @ibfmr: the fast memory region to deallocate
- *
- * Returns 0 on success.
- */
-int ipath_dealloc_fmr(struct ib_fmr *ibfmr)
-{
-       struct ipath_fmr *fmr = to_ifmr(ibfmr);
-       int i;
-
-       ipath_free_lkey(&to_idev(ibfmr->device)->lk_table, ibfmr->lkey);
-       i = fmr->mr.mapsz;
-       while (i)
-               kfree(fmr->mr.map[--i]);
-       kfree(fmr);
-       return 0;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_qp.c b/drivers/staging/rdma/ipath/ipath_qp.c
deleted file mode 100644 (file)
index 280cd2d..0000000
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-#define BITS_PER_PAGE          (PAGE_SIZE*BITS_PER_BYTE)
-#define BITS_PER_PAGE_MASK     (BITS_PER_PAGE-1)
-#define mk_qpn(qpt, map, off)  (((map) - (qpt)->map) * BITS_PER_PAGE + \
-                                (off))
-#define find_next_offset(map, off) find_next_zero_bit((map)->page, \
-                                                     BITS_PER_PAGE, off)
-
-/*
- * Convert the AETH credit code into the number of credits.
- */
-static u32 credit_table[31] = {
-       0,                      /* 0 */
-       1,                      /* 1 */
-       2,                      /* 2 */
-       3,                      /* 3 */
-       4,                      /* 4 */
-       6,                      /* 5 */
-       8,                      /* 6 */
-       12,                     /* 7 */
-       16,                     /* 8 */
-       24,                     /* 9 */
-       32,                     /* A */
-       48,                     /* B */
-       64,                     /* C */
-       96,                     /* D */
-       128,                    /* E */
-       192,                    /* F */
-       256,                    /* 10 */
-       384,                    /* 11 */
-       512,                    /* 12 */
-       768,                    /* 13 */
-       1024,                   /* 14 */
-       1536,                   /* 15 */
-       2048,                   /* 16 */
-       3072,                   /* 17 */
-       4096,                   /* 18 */
-       6144,                   /* 19 */
-       8192,                   /* 1A */
-       12288,                  /* 1B */
-       16384,                  /* 1C */
-       24576,                  /* 1D */
-       32768                   /* 1E */
-};
-
-
-static void get_map_page(struct ipath_qp_table *qpt, struct qpn_map *map)
-{
-       unsigned long page = get_zeroed_page(GFP_KERNEL);
-       unsigned long flags;
-
-       /*
-        * Free the page if someone raced with us installing it.
-        */
-
-       spin_lock_irqsave(&qpt->lock, flags);
-       if (map->page)
-               free_page(page);
-       else
-               map->page = (void *)page;
-       spin_unlock_irqrestore(&qpt->lock, flags);
-}
-
-
-static int alloc_qpn(struct ipath_qp_table *qpt, enum ib_qp_type type)
-{
-       u32 i, offset, max_scan, qpn;
-       struct qpn_map *map;
-       u32 ret = -1;
-
-       if (type == IB_QPT_SMI)
-               ret = 0;
-       else if (type == IB_QPT_GSI)
-               ret = 1;
-
-       if (ret != -1) {
-               map = &qpt->map[0];
-               if (unlikely(!map->page)) {
-                       get_map_page(qpt, map);
-                       if (unlikely(!map->page)) {
-                               ret = -ENOMEM;
-                               goto bail;
-                       }
-               }
-               if (!test_and_set_bit(ret, map->page))
-                       atomic_dec(&map->n_free);
-               else
-                       ret = -EBUSY;
-               goto bail;
-       }
-
-       qpn = qpt->last + 1;
-       if (qpn >= QPN_MAX)
-               qpn = 2;
-       offset = qpn & BITS_PER_PAGE_MASK;
-       map = &qpt->map[qpn / BITS_PER_PAGE];
-       max_scan = qpt->nmaps - !offset;
-       for (i = 0;;) {
-               if (unlikely(!map->page)) {
-                       get_map_page(qpt, map);
-                       if (unlikely(!map->page))
-                               break;
-               }
-               if (likely(atomic_read(&map->n_free))) {
-                       do {
-                               if (!test_and_set_bit(offset, map->page)) {
-                                       atomic_dec(&map->n_free);
-                                       qpt->last = qpn;
-                                       ret = qpn;
-                                       goto bail;
-                               }
-                               offset = find_next_offset(map, offset);
-                               qpn = mk_qpn(qpt, map, offset);
-                               /*
-                                * This test differs from alloc_pidmap().
-                                * If find_next_offset() does find a zero
-                                * bit, we don't need to check for QPN
-                                * wrapping around past our starting QPN.
-                                * We just need to be sure we don't loop
-                                * forever.
-                                */
-                       } while (offset < BITS_PER_PAGE && qpn < QPN_MAX);
-               }
-               /*
-                * In order to keep the number of pages allocated to a
-                * minimum, we scan the all existing pages before increasing
-                * the size of the bitmap table.
-                */
-               if (++i > max_scan) {
-                       if (qpt->nmaps == QPNMAP_ENTRIES)
-                               break;
-                       map = &qpt->map[qpt->nmaps++];
-                       offset = 0;
-               } else if (map < &qpt->map[qpt->nmaps]) {
-                       ++map;
-                       offset = 0;
-               } else {
-                       map = &qpt->map[0];
-                       offset = 2;
-               }
-               qpn = mk_qpn(qpt, map, offset);
-       }
-
-       ret = -ENOMEM;
-
-bail:
-       return ret;
-}
-
-static void free_qpn(struct ipath_qp_table *qpt, u32 qpn)
-{
-       struct qpn_map *map;
-
-       map = qpt->map + qpn / BITS_PER_PAGE;
-       if (map->page)
-               clear_bit(qpn & BITS_PER_PAGE_MASK, map->page);
-       atomic_inc(&map->n_free);
-}
-
-/**
- * ipath_alloc_qpn - allocate a QP number
- * @qpt: the QP table
- * @qp: the QP
- * @type: the QP type (IB_QPT_SMI and IB_QPT_GSI are special)
- *
- * Allocate the next available QPN and put the QP into the hash table.
- * The hash table holds a reference to the QP.
- */
-static int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp,
-                          enum ib_qp_type type)
-{
-       unsigned long flags;
-       int ret;
-
-       ret = alloc_qpn(qpt, type);
-       if (ret < 0)
-               goto bail;
-       qp->ibqp.qp_num = ret;
-
-       /* Add the QP to the hash table. */
-       spin_lock_irqsave(&qpt->lock, flags);
-
-       ret %= qpt->max;
-       qp->next = qpt->table[ret];
-       qpt->table[ret] = qp;
-       atomic_inc(&qp->refcount);
-
-       spin_unlock_irqrestore(&qpt->lock, flags);
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_free_qp - remove a QP from the QP table
- * @qpt: the QP table
- * @qp: the QP to remove
- *
- * Remove the QP from the table so it can't be found asynchronously by
- * the receive interrupt routine.
- */
-static void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp)
-{
-       struct ipath_qp *q, **qpp;
-       unsigned long flags;
-
-       spin_lock_irqsave(&qpt->lock, flags);
-
-       /* Remove QP from the hash table. */
-       qpp = &qpt->table[qp->ibqp.qp_num % qpt->max];
-       for (; (q = *qpp) != NULL; qpp = &q->next) {
-               if (q == qp) {
-                       *qpp = qp->next;
-                       qp->next = NULL;
-                       atomic_dec(&qp->refcount);
-                       break;
-               }
-       }
-
-       spin_unlock_irqrestore(&qpt->lock, flags);
-}
-
-/**
- * ipath_free_all_qps - check for QPs still in use
- * @qpt: the QP table to empty
- *
- * There should not be any QPs still in use.
- * Free memory for table.
- */
-unsigned ipath_free_all_qps(struct ipath_qp_table *qpt)
-{
-       unsigned long flags;
-       struct ipath_qp *qp;
-       u32 n, qp_inuse = 0;
-
-       spin_lock_irqsave(&qpt->lock, flags);
-       for (n = 0; n < qpt->max; n++) {
-               qp = qpt->table[n];
-               qpt->table[n] = NULL;
-
-               for (; qp; qp = qp->next)
-                       qp_inuse++;
-       }
-       spin_unlock_irqrestore(&qpt->lock, flags);
-
-       for (n = 0; n < ARRAY_SIZE(qpt->map); n++)
-               if (qpt->map[n].page)
-                       free_page((unsigned long) qpt->map[n].page);
-       return qp_inuse;
-}
-
-/**
- * ipath_lookup_qpn - return the QP with the given QPN
- * @qpt: the QP table
- * @qpn: the QP number to look up
- *
- * The caller is responsible for decrementing the QP reference count
- * when done.
- */
-struct ipath_qp *ipath_lookup_qpn(struct ipath_qp_table *qpt, u32 qpn)
-{
-       unsigned long flags;
-       struct ipath_qp *qp;
-
-       spin_lock_irqsave(&qpt->lock, flags);
-
-       for (qp = qpt->table[qpn % qpt->max]; qp; qp = qp->next) {
-               if (qp->ibqp.qp_num == qpn) {
-                       atomic_inc(&qp->refcount);
-                       break;
-               }
-       }
-
-       spin_unlock_irqrestore(&qpt->lock, flags);
-       return qp;
-}
-
-/**
- * ipath_reset_qp - initialize the QP state to the reset state
- * @qp: the QP to reset
- * @type: the QP type
- */
-static void ipath_reset_qp(struct ipath_qp *qp, enum ib_qp_type type)
-{
-       qp->remote_qpn = 0;
-       qp->qkey = 0;
-       qp->qp_access_flags = 0;
-       atomic_set(&qp->s_dma_busy, 0);
-       qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
-       qp->s_hdrwords = 0;
-       qp->s_wqe = NULL;
-       qp->s_pkt_delay = 0;
-       qp->s_draining = 0;
-       qp->s_psn = 0;
-       qp->r_psn = 0;
-       qp->r_msn = 0;
-       if (type == IB_QPT_RC) {
-               qp->s_state = IB_OPCODE_RC_SEND_LAST;
-               qp->r_state = IB_OPCODE_RC_SEND_LAST;
-       } else {
-               qp->s_state = IB_OPCODE_UC_SEND_LAST;
-               qp->r_state = IB_OPCODE_UC_SEND_LAST;
-       }
-       qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
-       qp->r_nak_state = 0;
-       qp->r_aflags = 0;
-       qp->r_flags = 0;
-       qp->s_rnr_timeout = 0;
-       qp->s_head = 0;
-       qp->s_tail = 0;
-       qp->s_cur = 0;
-       qp->s_last = 0;
-       qp->s_ssn = 1;
-       qp->s_lsn = 0;
-       memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue));
-       qp->r_head_ack_queue = 0;
-       qp->s_tail_ack_queue = 0;
-       qp->s_num_rd_atomic = 0;
-       if (qp->r_rq.wq) {
-               qp->r_rq.wq->head = 0;
-               qp->r_rq.wq->tail = 0;
-       }
-}
-
-/**
- * ipath_error_qp - put a QP into the error state
- * @qp: the QP to put into the error state
- * @err: the receive completion error to signal if a RWQE is active
- *
- * Flushes both send and receive work queues.
- * Returns true if last WQE event should be generated.
- * The QP s_lock should be held and interrupts disabled.
- * If we are already in error state, just return.
- */
-
-int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ib_wc wc;
-       int ret = 0;
-
-       if (qp->state == IB_QPS_ERR)
-               goto bail;
-
-       qp->state = IB_QPS_ERR;
-
-       spin_lock(&dev->pending_lock);
-       if (!list_empty(&qp->timerwait))
-               list_del_init(&qp->timerwait);
-       if (!list_empty(&qp->piowait))
-               list_del_init(&qp->piowait);
-       spin_unlock(&dev->pending_lock);
-
-       /* Schedule the sending tasklet to drain the send work queue. */
-       if (qp->s_last != qp->s_head)
-               ipath_schedule_send(qp);
-
-       memset(&wc, 0, sizeof(wc));
-       wc.qp = &qp->ibqp;
-       wc.opcode = IB_WC_RECV;
-
-       if (test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags)) {
-               wc.wr_id = qp->r_wr_id;
-               wc.status = err;
-               ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
-       }
-       wc.status = IB_WC_WR_FLUSH_ERR;
-
-       if (qp->r_rq.wq) {
-               struct ipath_rwq *wq;
-               u32 head;
-               u32 tail;
-
-               spin_lock(&qp->r_rq.lock);
-
-               /* sanity check pointers before trusting them */
-               wq = qp->r_rq.wq;
-               head = wq->head;
-               if (head >= qp->r_rq.size)
-                       head = 0;
-               tail = wq->tail;
-               if (tail >= qp->r_rq.size)
-                       tail = 0;
-               while (tail != head) {
-                       wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id;
-                       if (++tail >= qp->r_rq.size)
-                               tail = 0;
-                       ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
-               }
-               wq->tail = tail;
-
-               spin_unlock(&qp->r_rq.lock);
-       } else if (qp->ibqp.event_handler)
-               ret = 1;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_modify_qp - modify the attributes of a queue pair
- * @ibqp: the queue pair who's attributes we're modifying
- * @attr: the new attributes
- * @attr_mask: the mask of attributes to modify
- * @udata: user data for ipathverbs.so
- *
- * Returns 0 on success, otherwise returns an errno.
- */
-int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
-                   int attr_mask, struct ib_udata *udata)
-{
-       struct ipath_ibdev *dev = to_idev(ibqp->device);
-       struct ipath_qp *qp = to_iqp(ibqp);
-       enum ib_qp_state cur_state, new_state;
-       int lastwqe = 0;
-       int ret;
-
-       spin_lock_irq(&qp->s_lock);
-
-       cur_state = attr_mask & IB_QP_CUR_STATE ?
-               attr->cur_qp_state : qp->state;
-       new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state;
-
-       if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type,
-                               attr_mask, IB_LINK_LAYER_UNSPECIFIED))
-               goto inval;
-
-       if (attr_mask & IB_QP_AV) {
-               if (attr->ah_attr.dlid == 0 ||
-                   attr->ah_attr.dlid >= IPATH_MULTICAST_LID_BASE)
-                       goto inval;
-
-               if ((attr->ah_attr.ah_flags & IB_AH_GRH) &&
-                   (attr->ah_attr.grh.sgid_index > 1))
-                       goto inval;
-       }
-
-       if (attr_mask & IB_QP_PKEY_INDEX)
-               if (attr->pkey_index >= ipath_get_npkeys(dev->dd))
-                       goto inval;
-
-       if (attr_mask & IB_QP_MIN_RNR_TIMER)
-               if (attr->min_rnr_timer > 31)
-                       goto inval;
-
-       if (attr_mask & IB_QP_PORT)
-               if (attr->port_num == 0 ||
-                   attr->port_num > ibqp->device->phys_port_cnt)
-                       goto inval;
-
-       /*
-        * don't allow invalid Path MTU values or greater than 2048
-        * unless we are configured for a 4KB MTU
-        */
-       if ((attr_mask & IB_QP_PATH_MTU) &&
-               (ib_mtu_enum_to_int(attr->path_mtu) == -1 ||
-               (attr->path_mtu > IB_MTU_2048 && !ipath_mtu4096)))
-               goto inval;
-
-       if (attr_mask & IB_QP_PATH_MIG_STATE)
-               if (attr->path_mig_state != IB_MIG_MIGRATED &&
-                   attr->path_mig_state != IB_MIG_REARM)
-                       goto inval;
-
-       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
-               if (attr->max_dest_rd_atomic > IPATH_MAX_RDMA_ATOMIC)
-                       goto inval;
-
-       switch (new_state) {
-       case IB_QPS_RESET:
-               if (qp->state != IB_QPS_RESET) {
-                       qp->state = IB_QPS_RESET;
-                       spin_lock(&dev->pending_lock);
-                       if (!list_empty(&qp->timerwait))
-                               list_del_init(&qp->timerwait);
-                       if (!list_empty(&qp->piowait))
-                               list_del_init(&qp->piowait);
-                       spin_unlock(&dev->pending_lock);
-                       qp->s_flags &= ~IPATH_S_ANY_WAIT;
-                       spin_unlock_irq(&qp->s_lock);
-                       /* Stop the sending tasklet */
-                       tasklet_kill(&qp->s_task);
-                       wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
-                       spin_lock_irq(&qp->s_lock);
-               }
-               ipath_reset_qp(qp, ibqp->qp_type);
-               break;
-
-       case IB_QPS_SQD:
-               qp->s_draining = qp->s_last != qp->s_cur;
-               qp->state = new_state;
-               break;
-
-       case IB_QPS_SQE:
-               if (qp->ibqp.qp_type == IB_QPT_RC)
-                       goto inval;
-               qp->state = new_state;
-               break;
-
-       case IB_QPS_ERR:
-               lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
-               break;
-
-       default:
-               qp->state = new_state;
-               break;
-       }
-
-       if (attr_mask & IB_QP_PKEY_INDEX)
-               qp->s_pkey_index = attr->pkey_index;
-
-       if (attr_mask & IB_QP_DEST_QPN)
-               qp->remote_qpn = attr->dest_qp_num;
-
-       if (attr_mask & IB_QP_SQ_PSN) {
-               qp->s_psn = qp->s_next_psn = attr->sq_psn;
-               qp->s_last_psn = qp->s_next_psn - 1;
-       }
-
-       if (attr_mask & IB_QP_RQ_PSN)
-               qp->r_psn = attr->rq_psn;
-
-       if (attr_mask & IB_QP_ACCESS_FLAGS)
-               qp->qp_access_flags = attr->qp_access_flags;
-
-       if (attr_mask & IB_QP_AV) {
-               qp->remote_ah_attr = attr->ah_attr;
-               qp->s_dmult = ipath_ib_rate_to_mult(attr->ah_attr.static_rate);
-       }
-
-       if (attr_mask & IB_QP_PATH_MTU)
-               qp->path_mtu = attr->path_mtu;
-
-       if (attr_mask & IB_QP_RETRY_CNT)
-               qp->s_retry = qp->s_retry_cnt = attr->retry_cnt;
-
-       if (attr_mask & IB_QP_RNR_RETRY) {
-               qp->s_rnr_retry = attr->rnr_retry;
-               if (qp->s_rnr_retry > 7)
-                       qp->s_rnr_retry = 7;
-               qp->s_rnr_retry_cnt = qp->s_rnr_retry;
-       }
-
-       if (attr_mask & IB_QP_MIN_RNR_TIMER)
-               qp->r_min_rnr_timer = attr->min_rnr_timer;
-
-       if (attr_mask & IB_QP_TIMEOUT)
-               qp->timeout = attr->timeout;
-
-       if (attr_mask & IB_QP_QKEY)
-               qp->qkey = attr->qkey;
-
-       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
-               qp->r_max_rd_atomic = attr->max_dest_rd_atomic;
-
-       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
-               qp->s_max_rd_atomic = attr->max_rd_atomic;
-
-       spin_unlock_irq(&qp->s_lock);
-
-       if (lastwqe) {
-               struct ib_event ev;
-
-               ev.device = qp->ibqp.device;
-               ev.element.qp = &qp->ibqp;
-               ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
-               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
-       }
-       ret = 0;
-       goto bail;
-
-inval:
-       spin_unlock_irq(&qp->s_lock);
-       ret = -EINVAL;
-
-bail:
-       return ret;
-}
-
-int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
-                  int attr_mask, struct ib_qp_init_attr *init_attr)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-
-       attr->qp_state = qp->state;
-       attr->cur_qp_state = attr->qp_state;
-       attr->path_mtu = qp->path_mtu;
-       attr->path_mig_state = 0;
-       attr->qkey = qp->qkey;
-       attr->rq_psn = qp->r_psn;
-       attr->sq_psn = qp->s_next_psn;
-       attr->dest_qp_num = qp->remote_qpn;
-       attr->qp_access_flags = qp->qp_access_flags;
-       attr->cap.max_send_wr = qp->s_size - 1;
-       attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1;
-       attr->cap.max_send_sge = qp->s_max_sge;
-       attr->cap.max_recv_sge = qp->r_rq.max_sge;
-       attr->cap.max_inline_data = 0;
-       attr->ah_attr = qp->remote_ah_attr;
-       memset(&attr->alt_ah_attr, 0, sizeof(attr->alt_ah_attr));
-       attr->pkey_index = qp->s_pkey_index;
-       attr->alt_pkey_index = 0;
-       attr->en_sqd_async_notify = 0;
-       attr->sq_draining = qp->s_draining;
-       attr->max_rd_atomic = qp->s_max_rd_atomic;
-       attr->max_dest_rd_atomic = qp->r_max_rd_atomic;
-       attr->min_rnr_timer = qp->r_min_rnr_timer;
-       attr->port_num = 1;
-       attr->timeout = qp->timeout;
-       attr->retry_cnt = qp->s_retry_cnt;
-       attr->rnr_retry = qp->s_rnr_retry_cnt;
-       attr->alt_port_num = 0;
-       attr->alt_timeout = 0;
-
-       init_attr->event_handler = qp->ibqp.event_handler;
-       init_attr->qp_context = qp->ibqp.qp_context;
-       init_attr->send_cq = qp->ibqp.send_cq;
-       init_attr->recv_cq = qp->ibqp.recv_cq;
-       init_attr->srq = qp->ibqp.srq;
-       init_attr->cap = attr->cap;
-       if (qp->s_flags & IPATH_S_SIGNAL_REQ_WR)
-               init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
-       else
-               init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
-       init_attr->qp_type = qp->ibqp.qp_type;
-       init_attr->port_num = 1;
-       return 0;
-}
-
-/**
- * ipath_compute_aeth - compute the AETH (syndrome + MSN)
- * @qp: the queue pair to compute the AETH for
- *
- * Returns the AETH.
- */
-__be32 ipath_compute_aeth(struct ipath_qp *qp)
-{
-       u32 aeth = qp->r_msn & IPATH_MSN_MASK;
-
-       if (qp->ibqp.srq) {
-               /*
-                * Shared receive queues don't generate credits.
-                * Set the credit field to the invalid value.
-                */
-               aeth |= IPATH_AETH_CREDIT_INVAL << IPATH_AETH_CREDIT_SHIFT;
-       } else {
-               u32 min, max, x;
-               u32 credits;
-               struct ipath_rwq *wq = qp->r_rq.wq;
-               u32 head;
-               u32 tail;
-
-               /* sanity check pointers before trusting them */
-               head = wq->head;
-               if (head >= qp->r_rq.size)
-                       head = 0;
-               tail = wq->tail;
-               if (tail >= qp->r_rq.size)
-                       tail = 0;
-               /*
-                * Compute the number of credits available (RWQEs).
-                * XXX Not holding the r_rq.lock here so there is a small
-                * chance that the pair of reads are not atomic.
-                */
-               credits = head - tail;
-               if ((int)credits < 0)
-                       credits += qp->r_rq.size;
-               /*
-                * Binary search the credit table to find the code to
-                * use.
-                */
-               min = 0;
-               max = 31;
-               for (;;) {
-                       x = (min + max) / 2;
-                       if (credit_table[x] == credits)
-                               break;
-                       if (credit_table[x] > credits)
-                               max = x;
-                       else if (min == x)
-                               break;
-                       else
-                               min = x;
-               }
-               aeth |= x << IPATH_AETH_CREDIT_SHIFT;
-       }
-       return cpu_to_be32(aeth);
-}
-
-/**
- * ipath_create_qp - create a queue pair for a device
- * @ibpd: the protection domain who's device we create the queue pair for
- * @init_attr: the attributes of the queue pair
- * @udata: unused by InfiniPath
- *
- * Returns the queue pair on success, otherwise returns an errno.
- *
- * Called by the ib_create_qp() core verbs function.
- */
-struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
-                             struct ib_qp_init_attr *init_attr,
-                             struct ib_udata *udata)
-{
-       struct ipath_qp *qp;
-       int err;
-       struct ipath_swqe *swq = NULL;
-       struct ipath_ibdev *dev;
-       size_t sz;
-       size_t sg_list_sz;
-       struct ib_qp *ret;
-
-       if (init_attr->create_flags) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       if (init_attr->cap.max_send_sge > ib_ipath_max_sges ||
-           init_attr->cap.max_send_wr > ib_ipath_max_qp_wrs) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       /* Check receive queue parameters if no SRQ is specified. */
-       if (!init_attr->srq) {
-               if (init_attr->cap.max_recv_sge > ib_ipath_max_sges ||
-                   init_attr->cap.max_recv_wr > ib_ipath_max_qp_wrs) {
-                       ret = ERR_PTR(-EINVAL);
-                       goto bail;
-               }
-               if (init_attr->cap.max_send_sge +
-                   init_attr->cap.max_send_wr +
-                   init_attr->cap.max_recv_sge +
-                   init_attr->cap.max_recv_wr == 0) {
-                       ret = ERR_PTR(-EINVAL);
-                       goto bail;
-               }
-       }
-
-       switch (init_attr->qp_type) {
-       case IB_QPT_UC:
-       case IB_QPT_RC:
-       case IB_QPT_UD:
-       case IB_QPT_SMI:
-       case IB_QPT_GSI:
-               sz = sizeof(struct ipath_sge) *
-                       init_attr->cap.max_send_sge +
-                       sizeof(struct ipath_swqe);
-               swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz);
-               if (swq == NULL) {
-                       ret = ERR_PTR(-ENOMEM);
-                       goto bail;
-               }
-               sz = sizeof(*qp);
-               sg_list_sz = 0;
-               if (init_attr->srq) {
-                       struct ipath_srq *srq = to_isrq(init_attr->srq);
-
-                       if (srq->rq.max_sge > 1)
-                               sg_list_sz = sizeof(*qp->r_sg_list) *
-                                       (srq->rq.max_sge - 1);
-               } else if (init_attr->cap.max_recv_sge > 1)
-                       sg_list_sz = sizeof(*qp->r_sg_list) *
-                               (init_attr->cap.max_recv_sge - 1);
-               qp = kmalloc(sz + sg_list_sz, GFP_KERNEL);
-               if (!qp) {
-                       ret = ERR_PTR(-ENOMEM);
-                       goto bail_swq;
-               }
-               if (sg_list_sz && (init_attr->qp_type == IB_QPT_UD ||
-                   init_attr->qp_type == IB_QPT_SMI ||
-                   init_attr->qp_type == IB_QPT_GSI)) {
-                       qp->r_ud_sg_list = kmalloc(sg_list_sz, GFP_KERNEL);
-                       if (!qp->r_ud_sg_list) {
-                               ret = ERR_PTR(-ENOMEM);
-                               goto bail_qp;
-                       }
-               } else
-                       qp->r_ud_sg_list = NULL;
-               if (init_attr->srq) {
-                       sz = 0;
-                       qp->r_rq.size = 0;
-                       qp->r_rq.max_sge = 0;
-                       qp->r_rq.wq = NULL;
-                       init_attr->cap.max_recv_wr = 0;
-                       init_attr->cap.max_recv_sge = 0;
-               } else {
-                       qp->r_rq.size = init_attr->cap.max_recv_wr + 1;
-                       qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
-                       sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
-                               sizeof(struct ipath_rwqe);
-                       qp->r_rq.wq = vmalloc_user(sizeof(struct ipath_rwq) +
-                                             qp->r_rq.size * sz);
-                       if (!qp->r_rq.wq) {
-                               ret = ERR_PTR(-ENOMEM);
-                               goto bail_sg_list;
-                       }
-               }
-
-               /*
-                * ib_create_qp() will initialize qp->ibqp
-                * except for qp->ibqp.qp_num.
-                */
-               spin_lock_init(&qp->s_lock);
-               spin_lock_init(&qp->r_rq.lock);
-               atomic_set(&qp->refcount, 0);
-               init_waitqueue_head(&qp->wait);
-               init_waitqueue_head(&qp->wait_dma);
-               tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
-               INIT_LIST_HEAD(&qp->piowait);
-               INIT_LIST_HEAD(&qp->timerwait);
-               qp->state = IB_QPS_RESET;
-               qp->s_wq = swq;
-               qp->s_size = init_attr->cap.max_send_wr + 1;
-               qp->s_max_sge = init_attr->cap.max_send_sge;
-               if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
-                       qp->s_flags = IPATH_S_SIGNAL_REQ_WR;
-               else
-                       qp->s_flags = 0;
-               dev = to_idev(ibpd->device);
-               err = ipath_alloc_qpn(&dev->qp_table, qp,
-                                     init_attr->qp_type);
-               if (err) {
-                       ret = ERR_PTR(err);
-                       vfree(qp->r_rq.wq);
-                       goto bail_sg_list;
-               }
-               qp->ip = NULL;
-               qp->s_tx = NULL;
-               ipath_reset_qp(qp, init_attr->qp_type);
-               break;
-
-       default:
-               /* Don't support raw QPs */
-               ret = ERR_PTR(-ENOSYS);
-               goto bail;
-       }
-
-       init_attr->cap.max_inline_data = 0;
-
-       /*
-        * Return the address of the RWQ as the offset to mmap.
-        * See ipath_mmap() for details.
-        */
-       if (udata && udata->outlen >= sizeof(__u64)) {
-               if (!qp->r_rq.wq) {
-                       __u64 offset = 0;
-
-                       err = ib_copy_to_udata(udata, &offset,
-                                              sizeof(offset));
-                       if (err) {
-                               ret = ERR_PTR(err);
-                               goto bail_ip;
-                       }
-               } else {
-                       u32 s = sizeof(struct ipath_rwq) +
-                               qp->r_rq.size * sz;
-
-                       qp->ip =
-                           ipath_create_mmap_info(dev, s,
-                                                  ibpd->uobject->context,
-                                                  qp->r_rq.wq);
-                       if (!qp->ip) {
-                               ret = ERR_PTR(-ENOMEM);
-                               goto bail_ip;
-                       }
-
-                       err = ib_copy_to_udata(udata, &(qp->ip->offset),
-                                              sizeof(qp->ip->offset));
-                       if (err) {
-                               ret = ERR_PTR(err);
-                               goto bail_ip;
-                       }
-               }
-       }
-
-       spin_lock(&dev->n_qps_lock);
-       if (dev->n_qps_allocated == ib_ipath_max_qps) {
-               spin_unlock(&dev->n_qps_lock);
-               ret = ERR_PTR(-ENOMEM);
-               goto bail_ip;
-       }
-
-       dev->n_qps_allocated++;
-       spin_unlock(&dev->n_qps_lock);
-
-       if (qp->ip) {
-               spin_lock_irq(&dev->pending_lock);
-               list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps);
-               spin_unlock_irq(&dev->pending_lock);
-       }
-
-       ret = &qp->ibqp;
-       goto bail;
-
-bail_ip:
-       if (qp->ip)
-               kref_put(&qp->ip->ref, ipath_release_mmap_info);
-       else
-               vfree(qp->r_rq.wq);
-       ipath_free_qp(&dev->qp_table, qp);
-       free_qpn(&dev->qp_table, qp->ibqp.qp_num);
-bail_sg_list:
-       kfree(qp->r_ud_sg_list);
-bail_qp:
-       kfree(qp);
-bail_swq:
-       vfree(swq);
-bail:
-       return ret;
-}
-
-/**
- * ipath_destroy_qp - destroy a queue pair
- * @ibqp: the queue pair to destroy
- *
- * Returns 0 on success.
- *
- * Note that this can be called while the QP is actively sending or
- * receiving!
- */
-int ipath_destroy_qp(struct ib_qp *ibqp)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-       struct ipath_ibdev *dev = to_idev(ibqp->device);
-
-       /* Make sure HW and driver activity is stopped. */
-       spin_lock_irq(&qp->s_lock);
-       if (qp->state != IB_QPS_RESET) {
-               qp->state = IB_QPS_RESET;
-               spin_lock(&dev->pending_lock);
-               if (!list_empty(&qp->timerwait))
-                       list_del_init(&qp->timerwait);
-               if (!list_empty(&qp->piowait))
-                       list_del_init(&qp->piowait);
-               spin_unlock(&dev->pending_lock);
-               qp->s_flags &= ~IPATH_S_ANY_WAIT;
-               spin_unlock_irq(&qp->s_lock);
-               /* Stop the sending tasklet */
-               tasklet_kill(&qp->s_task);
-               wait_event(qp->wait_dma, !atomic_read(&qp->s_dma_busy));
-       } else
-               spin_unlock_irq(&qp->s_lock);
-
-       ipath_free_qp(&dev->qp_table, qp);
-
-       if (qp->s_tx) {
-               atomic_dec(&qp->refcount);
-               if (qp->s_tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEBUF)
-                       kfree(qp->s_tx->txreq.map_addr);
-               spin_lock_irq(&dev->pending_lock);
-               list_add(&qp->s_tx->txreq.list, &dev->txreq_free);
-               spin_unlock_irq(&dev->pending_lock);
-               qp->s_tx = NULL;
-       }
-
-       wait_event(qp->wait, !atomic_read(&qp->refcount));
-
-       /* all user's cleaned up, mark it available */
-       free_qpn(&dev->qp_table, qp->ibqp.qp_num);
-       spin_lock(&dev->n_qps_lock);
-       dev->n_qps_allocated--;
-       spin_unlock(&dev->n_qps_lock);
-
-       if (qp->ip)
-               kref_put(&qp->ip->ref, ipath_release_mmap_info);
-       else
-               vfree(qp->r_rq.wq);
-       kfree(qp->r_ud_sg_list);
-       vfree(qp->s_wq);
-       kfree(qp);
-       return 0;
-}
-
-/**
- * ipath_init_qp_table - initialize the QP table for a device
- * @idev: the device who's QP table we're initializing
- * @size: the size of the QP table
- *
- * Returns 0 on success, otherwise returns an errno.
- */
-int ipath_init_qp_table(struct ipath_ibdev *idev, int size)
-{
-       int i;
-       int ret;
-
-       idev->qp_table.last = 1;        /* QPN 0 and 1 are special. */
-       idev->qp_table.max = size;
-       idev->qp_table.nmaps = 1;
-       idev->qp_table.table = kcalloc(size, sizeof(*idev->qp_table.table),
-                                      GFP_KERNEL);
-       if (idev->qp_table.table == NULL) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(idev->qp_table.map); i++) {
-               atomic_set(&idev->qp_table.map[i].n_free, BITS_PER_PAGE);
-               idev->qp_table.map[i].page = NULL;
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_get_credit - flush the send work queue of a QP
- * @qp: the qp who's send work queue to flush
- * @aeth: the Acknowledge Extended Transport Header
- *
- * The QP s_lock should be held.
- */
-void ipath_get_credit(struct ipath_qp *qp, u32 aeth)
-{
-       u32 credit = (aeth >> IPATH_AETH_CREDIT_SHIFT) & IPATH_AETH_CREDIT_MASK;
-
-       /*
-        * If the credit is invalid, we can send
-        * as many packets as we like.  Otherwise, we have to
-        * honor the credit field.
-        */
-       if (credit == IPATH_AETH_CREDIT_INVAL)
-               qp->s_lsn = (u32) -1;
-       else if (qp->s_lsn != (u32) -1) {
-               /* Compute new LSN (i.e., MSN + credit) */
-               credit = (aeth + credit_table[credit]) & IPATH_MSN_MASK;
-               if (ipath_cmp24(credit, qp->s_lsn) > 0)
-                       qp->s_lsn = credit;
-       }
-
-       /* Restart sending if it was blocked due to lack of credits. */
-       if ((qp->s_flags & IPATH_S_WAIT_SSN_CREDIT) &&
-           qp->s_cur != qp->s_head &&
-           (qp->s_lsn == (u32) -1 ||
-            ipath_cmp24(get_swqe_ptr(qp, qp->s_cur)->ssn,
-                        qp->s_lsn + 1) <= 0))
-               ipath_schedule_send(qp);
-}
diff --git a/drivers/staging/rdma/ipath/ipath_rc.c b/drivers/staging/rdma/ipath/ipath_rc.c
deleted file mode 100644 (file)
index d4aa535..0000000
+++ /dev/null
@@ -1,1969 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/io.h>
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-/* cut down ridiculously long IB macro names */
-#define OP(x) IB_OPCODE_RC_##x
-
-static u32 restart_sge(struct ipath_sge_state *ss, struct ipath_swqe *wqe,
-                      u32 psn, u32 pmtu)
-{
-       u32 len;
-
-       len = ((psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
-       ss->sge = wqe->sg_list[0];
-       ss->sg_list = wqe->sg_list + 1;
-       ss->num_sge = wqe->wr.num_sge;
-       ipath_skip_sge(ss, len);
-       return wqe->length - len;
-}
-
-/**
- * ipath_init_restart- initialize the qp->s_sge after a restart
- * @qp: the QP who's SGE we're restarting
- * @wqe: the work queue to initialize the QP's SGE from
- *
- * The QP s_lock should be held and interrupts disabled.
- */
-static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
-{
-       struct ipath_ibdev *dev;
-
-       qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn,
-                               ib_mtu_enum_to_int(qp->path_mtu));
-       dev = to_idev(qp->ibqp.device);
-       spin_lock(&dev->pending_lock);
-       if (list_empty(&qp->timerwait))
-               list_add_tail(&qp->timerwait,
-                             &dev->pending[dev->pending_index]);
-       spin_unlock(&dev->pending_lock);
-}
-
-/**
- * ipath_make_rc_ack - construct a response packet (ACK, NAK, or RDMA read)
- * @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- *
- * Return 1 if constructed; otherwise, return 0.
- * Note that we are in the responder's side of the QP context.
- * Note the QP s_lock must be held.
- */
-static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
-                            struct ipath_other_headers *ohdr, u32 pmtu)
-{
-       struct ipath_ack_entry *e;
-       u32 hwords;
-       u32 len;
-       u32 bth0;
-       u32 bth2;
-
-       /* Don't send an ACK if we aren't supposed to. */
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
-               goto bail;
-
-       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
-       hwords = 5;
-
-       switch (qp->s_ack_state) {
-       case OP(RDMA_READ_RESPONSE_LAST):
-       case OP(RDMA_READ_RESPONSE_ONLY):
-       case OP(ATOMIC_ACKNOWLEDGE):
-               /*
-                * We can increment the tail pointer now that the last
-                * response has been sent instead of only being
-                * constructed.
-                */
-               if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
-                       qp->s_tail_ack_queue = 0;
-               /* FALLTHROUGH */
-       case OP(SEND_ONLY):
-       case OP(ACKNOWLEDGE):
-               /* Check for no next entry in the queue. */
-               if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
-                       if (qp->s_flags & IPATH_S_ACK_PENDING)
-                               goto normal;
-                       qp->s_ack_state = OP(ACKNOWLEDGE);
-                       goto bail;
-               }
-
-               e = &qp->s_ack_queue[qp->s_tail_ack_queue];
-               if (e->opcode == OP(RDMA_READ_REQUEST)) {
-                       /* Copy SGE state in case we need to resend */
-                       qp->s_ack_rdma_sge = e->rdma_sge;
-                       qp->s_cur_sge = &qp->s_ack_rdma_sge;
-                       len = e->rdma_sge.sge.sge_length;
-                       if (len > pmtu) {
-                               len = pmtu;
-                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
-                       } else {
-                               qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
-                               e->sent = 1;
-                       }
-                       ohdr->u.aeth = ipath_compute_aeth(qp);
-                       hwords++;
-                       qp->s_ack_rdma_psn = e->psn;
-                       bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
-               } else {
-                       /* COMPARE_SWAP or FETCH_ADD */
-                       qp->s_cur_sge = NULL;
-                       len = 0;
-                       qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
-                       ohdr->u.at.aeth = ipath_compute_aeth(qp);
-                       ohdr->u.at.atomic_ack_eth[0] =
-                               cpu_to_be32(e->atomic_data >> 32);
-                       ohdr->u.at.atomic_ack_eth[1] =
-                               cpu_to_be32(e->atomic_data);
-                       hwords += sizeof(ohdr->u.at) / sizeof(u32);
-                       bth2 = e->psn;
-                       e->sent = 1;
-               }
-               bth0 = qp->s_ack_state << 24;
-               break;
-
-       case OP(RDMA_READ_RESPONSE_FIRST):
-               qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
-               /* FALLTHROUGH */
-       case OP(RDMA_READ_RESPONSE_MIDDLE):
-               len = qp->s_ack_rdma_sge.sge.sge_length;
-               if (len > pmtu)
-                       len = pmtu;
-               else {
-                       ohdr->u.aeth = ipath_compute_aeth(qp);
-                       hwords++;
-                       qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
-                       qp->s_ack_queue[qp->s_tail_ack_queue].sent = 1;
-               }
-               bth0 = qp->s_ack_state << 24;
-               bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
-               break;
-
-       default:
-       normal:
-               /*
-                * Send a regular ACK.
-                * Set the s_ack_state so we wait until after sending
-                * the ACK before setting s_ack_state to ACKNOWLEDGE
-                * (see above).
-                */
-               qp->s_ack_state = OP(SEND_ONLY);
-               qp->s_flags &= ~IPATH_S_ACK_PENDING;
-               qp->s_cur_sge = NULL;
-               if (qp->s_nak_state)
-                       ohdr->u.aeth =
-                               cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
-                                           (qp->s_nak_state <<
-                                            IPATH_AETH_CREDIT_SHIFT));
-               else
-                       ohdr->u.aeth = ipath_compute_aeth(qp);
-               hwords++;
-               len = 0;
-               bth0 = OP(ACKNOWLEDGE) << 24;
-               bth2 = qp->s_ack_psn & IPATH_PSN_MASK;
-       }
-       qp->s_hdrwords = hwords;
-       qp->s_cur_size = len;
-       ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
-       return 1;
-
-bail:
-       return 0;
-}
-
-/**
- * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
- * @qp: a pointer to the QP
- *
- * Return 1 if constructed; otherwise, return 0.
- */
-int ipath_make_rc_req(struct ipath_qp *qp)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ipath_other_headers *ohdr;
-       struct ipath_sge_state *ss;
-       struct ipath_swqe *wqe;
-       u32 hwords;
-       u32 len;
-       u32 bth0;
-       u32 bth2;
-       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
-       char newreq;
-       unsigned long flags;
-       int ret = 0;
-
-       ohdr = &qp->s_hdr.u.oth;
-       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
-               ohdr = &qp->s_hdr.u.l.oth;
-
-       /*
-        * The lock is needed to synchronize between the sending tasklet,
-        * the receive interrupt handler, and timeout resends.
-        */
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       /* Sending responses has higher priority over sending requests. */
-       if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
-            (qp->s_flags & IPATH_S_ACK_PENDING) ||
-            qp->s_ack_state != OP(ACKNOWLEDGE)) &&
-           ipath_make_rc_ack(dev, qp, ohdr, pmtu))
-               goto done;
-
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
-               if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
-                       goto bail;
-               /* We are in the error state, flush the work request. */
-               if (qp->s_last == qp->s_head)
-                       goto bail;
-               /* If DMAs are in progress, we can't flush immediately. */
-               if (atomic_read(&qp->s_dma_busy)) {
-                       qp->s_flags |= IPATH_S_WAIT_DMA;
-                       goto bail;
-               }
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
-               goto done;
-       }
-
-       /* Leave BUSY set until RNR timeout. */
-       if (qp->s_rnr_timeout) {
-               qp->s_flags |= IPATH_S_WAITING;
-               goto bail;
-       }
-
-       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
-       hwords = 5;
-       bth0 = 1 << 22; /* Set M bit */
-
-       /* Send a request. */
-       wqe = get_swqe_ptr(qp, qp->s_cur);
-       switch (qp->s_state) {
-       default:
-               if (!(ib_ipath_state_ops[qp->state] &
-                   IPATH_PROCESS_NEXT_SEND_OK))
-                       goto bail;
-               /*
-                * Resend an old request or start a new one.
-                *
-                * We keep track of the current SWQE so that
-                * we don't reset the "furthest progress" state
-                * if we need to back up.
-                */
-               newreq = 0;
-               if (qp->s_cur == qp->s_tail) {
-                       /* Check if send work queue is empty. */
-                       if (qp->s_tail == qp->s_head)
-                               goto bail;
-                       /*
-                        * If a fence is requested, wait for previous
-                        * RDMA read and atomic operations to finish.
-                        */
-                       if ((wqe->wr.send_flags & IB_SEND_FENCE) &&
-                           qp->s_num_rd_atomic) {
-                               qp->s_flags |= IPATH_S_FENCE_PENDING;
-                               goto bail;
-                       }
-                       wqe->psn = qp->s_next_psn;
-                       newreq = 1;
-               }
-               /*
-                * Note that we have to be careful not to modify the
-                * original work request since we may need to resend
-                * it.
-                */
-               len = wqe->length;
-               ss = &qp->s_sge;
-               bth2 = 0;
-               switch (wqe->wr.opcode) {
-               case IB_WR_SEND:
-               case IB_WR_SEND_WITH_IMM:
-                       /* If no credit, return. */
-                       if (qp->s_lsn != (u32) -1 &&
-                           ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
-                               qp->s_flags |= IPATH_S_WAIT_SSN_CREDIT;
-                               goto bail;
-                       }
-                       wqe->lpsn = wqe->psn;
-                       if (len > pmtu) {
-                               wqe->lpsn += (len - 1) / pmtu;
-                               qp->s_state = OP(SEND_FIRST);
-                               len = pmtu;
-                               break;
-                       }
-                       if (wqe->wr.opcode == IB_WR_SEND)
-                               qp->s_state = OP(SEND_ONLY);
-                       else {
-                               qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE);
-                               /* Immediate data comes after the BTH */
-                               ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                               hwords += 1;
-                       }
-                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                               bth0 |= 1 << 23;
-                       bth2 = 1 << 31; /* Request ACK. */
-                       if (++qp->s_cur == qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               case IB_WR_RDMA_WRITE:
-                       if (newreq && qp->s_lsn != (u32) -1)
-                               qp->s_lsn++;
-                       /* FALLTHROUGH */
-               case IB_WR_RDMA_WRITE_WITH_IMM:
-                       /* If no credit, return. */
-                       if (qp->s_lsn != (u32) -1 &&
-                           ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) {
-                               qp->s_flags |= IPATH_S_WAIT_SSN_CREDIT;
-                               goto bail;
-                       }
-                       ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->rdma_wr.remote_addr);
-                       ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->rdma_wr.rkey);
-                       ohdr->u.rc.reth.length = cpu_to_be32(len);
-                       hwords += sizeof(struct ib_reth) / sizeof(u32);
-                       wqe->lpsn = wqe->psn;
-                       if (len > pmtu) {
-                               wqe->lpsn += (len - 1) / pmtu;
-                               qp->s_state = OP(RDMA_WRITE_FIRST);
-                               len = pmtu;
-                               break;
-                       }
-                       if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
-                               qp->s_state = OP(RDMA_WRITE_ONLY);
-                       else {
-                               qp->s_state =
-                                       OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
-                               /* Immediate data comes after RETH */
-                               ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
-                               hwords += 1;
-                               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                                       bth0 |= 1 << 23;
-                       }
-                       bth2 = 1 << 31; /* Request ACK. */
-                       if (++qp->s_cur == qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               case IB_WR_RDMA_READ:
-                       /*
-                        * Don't allow more operations to be started
-                        * than the QP limits allow.
-                        */
-                       if (newreq) {
-                               if (qp->s_num_rd_atomic >=
-                                   qp->s_max_rd_atomic) {
-                                       qp->s_flags |= IPATH_S_RDMAR_PENDING;
-                                       goto bail;
-                               }
-                               qp->s_num_rd_atomic++;
-                               if (qp->s_lsn != (u32) -1)
-                                       qp->s_lsn++;
-                               /*
-                                * Adjust s_next_psn to count the
-                                * expected number of responses.
-                                */
-                               if (len > pmtu)
-                                       qp->s_next_psn += (len - 1) / pmtu;
-                               wqe->lpsn = qp->s_next_psn++;
-                       }
-                       ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->rdma_wr.remote_addr);
-                       ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->rdma_wr.rkey);
-                       ohdr->u.rc.reth.length = cpu_to_be32(len);
-                       qp->s_state = OP(RDMA_READ_REQUEST);
-                       hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
-                       ss = NULL;
-                       len = 0;
-                       if (++qp->s_cur == qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               case IB_WR_ATOMIC_CMP_AND_SWP:
-               case IB_WR_ATOMIC_FETCH_AND_ADD:
-                       /*
-                        * Don't allow more operations to be started
-                        * than the QP limits allow.
-                        */
-                       if (newreq) {
-                               if (qp->s_num_rd_atomic >=
-                                   qp->s_max_rd_atomic) {
-                                       qp->s_flags |= IPATH_S_RDMAR_PENDING;
-                                       goto bail;
-                               }
-                               qp->s_num_rd_atomic++;
-                               if (qp->s_lsn != (u32) -1)
-                                       qp->s_lsn++;
-                               wqe->lpsn = wqe->psn;
-                       }
-                       if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-                               qp->s_state = OP(COMPARE_SWAP);
-                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->atomic_wr.swap);
-                               ohdr->u.atomic_eth.compare_data = cpu_to_be64(
-                                       wqe->atomic_wr.compare_add);
-                       } else {
-                               qp->s_state = OP(FETCH_ADD);
-                               ohdr->u.atomic_eth.swap_data = cpu_to_be64(
-                                       wqe->atomic_wr.compare_add);
-                               ohdr->u.atomic_eth.compare_data = 0;
-                       }
-                       ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32(
-                               wqe->atomic_wr.remote_addr >> 32);
-                       ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32(
-                               wqe->atomic_wr.remote_addr);
-                       ohdr->u.atomic_eth.rkey = cpu_to_be32(
-                               wqe->atomic_wr.rkey);
-                       hwords += sizeof(struct ib_atomic_eth) / sizeof(u32);
-                       ss = NULL;
-                       len = 0;
-                       if (++qp->s_cur == qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               default:
-                       goto bail;
-               }
-               qp->s_sge.sge = wqe->sg_list[0];
-               qp->s_sge.sg_list = wqe->sg_list + 1;
-               qp->s_sge.num_sge = wqe->wr.num_sge;
-               qp->s_len = wqe->length;
-               if (newreq) {
-                       qp->s_tail++;
-                       if (qp->s_tail >= qp->s_size)
-                               qp->s_tail = 0;
-               }
-               bth2 |= qp->s_psn & IPATH_PSN_MASK;
-               if (wqe->wr.opcode == IB_WR_RDMA_READ)
-                       qp->s_psn = wqe->lpsn + 1;
-               else {
-                       qp->s_psn++;
-                       if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
-                               qp->s_next_psn = qp->s_psn;
-               }
-               /*
-                * Put the QP on the pending list so lost ACKs will cause
-                * a retry.  More than one request can be pending so the
-                * QP may already be on the dev->pending list.
-                */
-               spin_lock(&dev->pending_lock);
-               if (list_empty(&qp->timerwait))
-                       list_add_tail(&qp->timerwait,
-                                     &dev->pending[dev->pending_index]);
-               spin_unlock(&dev->pending_lock);
-               break;
-
-       case OP(RDMA_READ_RESPONSE_FIRST):
-               /*
-                * This case can only happen if a send is restarted.
-                * See ipath_restart_rc().
-                */
-               ipath_init_restart(qp, wqe);
-               /* FALLTHROUGH */
-       case OP(SEND_FIRST):
-               qp->s_state = OP(SEND_MIDDLE);
-               /* FALLTHROUGH */
-       case OP(SEND_MIDDLE):
-               bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-               if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
-                       qp->s_next_psn = qp->s_psn;
-               ss = &qp->s_sge;
-               len = qp->s_len;
-               if (len > pmtu) {
-                       len = pmtu;
-                       break;
-               }
-               if (wqe->wr.opcode == IB_WR_SEND)
-                       qp->s_state = OP(SEND_LAST);
-               else {
-                       qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
-                       /* Immediate data comes after the BTH */
-                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                       hwords += 1;
-               }
-               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                       bth0 |= 1 << 23;
-               bth2 |= 1 << 31;        /* Request ACK. */
-               qp->s_cur++;
-               if (qp->s_cur >= qp->s_size)
-                       qp->s_cur = 0;
-               break;
-
-       case OP(RDMA_READ_RESPONSE_LAST):
-               /*
-                * This case can only happen if a RDMA write is restarted.
-                * See ipath_restart_rc().
-                */
-               ipath_init_restart(qp, wqe);
-               /* FALLTHROUGH */
-       case OP(RDMA_WRITE_FIRST):
-               qp->s_state = OP(RDMA_WRITE_MIDDLE);
-               /* FALLTHROUGH */
-       case OP(RDMA_WRITE_MIDDLE):
-               bth2 = qp->s_psn++ & IPATH_PSN_MASK;
-               if (ipath_cmp24(qp->s_psn, qp->s_next_psn) > 0)
-                       qp->s_next_psn = qp->s_psn;
-               ss = &qp->s_sge;
-               len = qp->s_len;
-               if (len > pmtu) {
-                       len = pmtu;
-                       break;
-               }
-               if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
-                       qp->s_state = OP(RDMA_WRITE_LAST);
-               else {
-                       qp->s_state = OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);
-                       /* Immediate data comes after the BTH */
-                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                       hwords += 1;
-                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                               bth0 |= 1 << 23;
-               }
-               bth2 |= 1 << 31;        /* Request ACK. */
-               qp->s_cur++;
-               if (qp->s_cur >= qp->s_size)
-                       qp->s_cur = 0;
-               break;
-
-       case OP(RDMA_READ_RESPONSE_MIDDLE):
-               /*
-                * This case can only happen if a RDMA read is restarted.
-                * See ipath_restart_rc().
-                */
-               ipath_init_restart(qp, wqe);
-               len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
-               ohdr->u.rc.reth.vaddr =
-                       cpu_to_be64(wqe->rdma_wr.remote_addr + len);
-               ohdr->u.rc.reth.rkey =
-                       cpu_to_be32(wqe->rdma_wr.rkey);
-               ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
-               qp->s_state = OP(RDMA_READ_REQUEST);
-               hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32);
-               bth2 = qp->s_psn & IPATH_PSN_MASK;
-               qp->s_psn = wqe->lpsn + 1;
-               ss = NULL;
-               len = 0;
-               qp->s_cur++;
-               if (qp->s_cur == qp->s_size)
-                       qp->s_cur = 0;
-               break;
-       }
-       if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
-               bth2 |= 1 << 31;        /* Request ACK. */
-       qp->s_len -= len;
-       qp->s_hdrwords = hwords;
-       qp->s_cur_sge = ss;
-       qp->s_cur_size = len;
-       ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
-done:
-       ret = 1;
-       goto unlock;
-
-bail:
-       qp->s_flags &= ~IPATH_S_BUSY;
-unlock:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-       return ret;
-}
-
-/**
- * send_rc_ack - Construct an ACK packet and send it
- * @qp: a pointer to the QP
- *
- * This is called from ipath_rc_rcv() and only uses the receive
- * side QP state.
- * Note that RDMA reads and atomics are handled in the
- * send side QP state and tasklet.
- */
-static void send_rc_ack(struct ipath_qp *qp)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ipath_devdata *dd;
-       u16 lrh0;
-       u32 bth0;
-       u32 hwords;
-       u32 __iomem *piobuf;
-       struct ipath_ib_header hdr;
-       struct ipath_other_headers *ohdr;
-       unsigned long flags;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       /* Don't send ACK or NAK if a RDMA read or atomic is pending. */
-       if (qp->r_head_ack_queue != qp->s_tail_ack_queue ||
-           (qp->s_flags & IPATH_S_ACK_PENDING) ||
-           qp->s_ack_state != OP(ACKNOWLEDGE))
-               goto queue_ack;
-
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-
-       /* Don't try to send ACKs if the link isn't ACTIVE */
-       dd = dev->dd;
-       if (!(dd->ipath_flags & IPATH_LINKACTIVE))
-               goto done;
-
-       piobuf = ipath_getpiobuf(dd, 0, NULL);
-       if (!piobuf) {
-               /*
-                * We are out of PIO buffers at the moment.
-                * Pass responsibility for sending the ACK to the
-                * send tasklet so that when a PIO buffer becomes
-                * available, the ACK is sent ahead of other outgoing
-                * packets.
-                */
-               spin_lock_irqsave(&qp->s_lock, flags);
-               goto queue_ack;
-       }
-
-       /* Construct the header. */
-       ohdr = &hdr.u.oth;
-       lrh0 = IPATH_LRH_BTH;
-       /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4. */
-       hwords = 6;
-       if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
-               hwords += ipath_make_grh(dev, &hdr.u.l.grh,
-                                        &qp->remote_ah_attr.grh,
-                                        hwords, 0);
-               ohdr = &hdr.u.l.oth;
-               lrh0 = IPATH_LRH_GRH;
-       }
-       /* read pkey_index w/o lock (its atomic) */
-       bth0 = ipath_get_pkey(dd, qp->s_pkey_index) |
-               (OP(ACKNOWLEDGE) << 24) | (1 << 22);
-       if (qp->r_nak_state)
-               ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
-                                           (qp->r_nak_state <<
-                                            IPATH_AETH_CREDIT_SHIFT));
-       else
-               ohdr->u.aeth = ipath_compute_aeth(qp);
-       lrh0 |= qp->remote_ah_attr.sl << 4;
-       hdr.lrh[0] = cpu_to_be16(lrh0);
-       hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
-       hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
-       hdr.lrh[3] = cpu_to_be16(dd->ipath_lid |
-                                qp->remote_ah_attr.src_path_bits);
-       ohdr->bth[0] = cpu_to_be32(bth0);
-       ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
-       ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
-
-       writeq(hwords + 1, piobuf);
-
-       if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
-               u32 *hdrp = (u32 *) &hdr;
-
-               ipath_flush_wc();
-               __iowrite32_copy(piobuf + 2, hdrp, hwords - 1);
-               ipath_flush_wc();
-               __raw_writel(hdrp[hwords - 1], piobuf + hwords + 1);
-       } else
-               __iowrite32_copy(piobuf + 2, (u32 *) &hdr, hwords);
-
-       ipath_flush_wc();
-
-       dev->n_unicast_xmit++;
-       goto done;
-
-queue_ack:
-       if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK) {
-               dev->n_rc_qacks++;
-               qp->s_flags |= IPATH_S_ACK_PENDING;
-               qp->s_nak_state = qp->r_nak_state;
-               qp->s_ack_psn = qp->r_ack_psn;
-
-               /* Schedule the send tasklet. */
-               ipath_schedule_send(qp);
-       }
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-done:
-       return;
-}
-
-/**
- * reset_psn - reset the QP state to send starting from PSN
- * @qp: the QP
- * @psn: the packet sequence number to restart at
- *
- * This is called from ipath_rc_rcv() to process an incoming RC ACK
- * for the given QP.
- * Called at interrupt level with the QP s_lock held.
- */
-static void reset_psn(struct ipath_qp *qp, u32 psn)
-{
-       u32 n = qp->s_last;
-       struct ipath_swqe *wqe = get_swqe_ptr(qp, n);
-       u32 opcode;
-
-       qp->s_cur = n;
-
-       /*
-        * If we are starting the request from the beginning,
-        * let the normal send code handle initialization.
-        */
-       if (ipath_cmp24(psn, wqe->psn) <= 0) {
-               qp->s_state = OP(SEND_LAST);
-               goto done;
-       }
-
-       /* Find the work request opcode corresponding to the given PSN. */
-       opcode = wqe->wr.opcode;
-       for (;;) {
-               int diff;
-
-               if (++n == qp->s_size)
-                       n = 0;
-               if (n == qp->s_tail)
-                       break;
-               wqe = get_swqe_ptr(qp, n);
-               diff = ipath_cmp24(psn, wqe->psn);
-               if (diff < 0)
-                       break;
-               qp->s_cur = n;
-               /*
-                * If we are starting the request from the beginning,
-                * let the normal send code handle initialization.
-                */
-               if (diff == 0) {
-                       qp->s_state = OP(SEND_LAST);
-                       goto done;
-               }
-               opcode = wqe->wr.opcode;
-       }
-
-       /*
-        * Set the state to restart in the middle of a request.
-        * Don't change the s_sge, s_cur_sge, or s_cur_size.
-        * See ipath_make_rc_req().
-        */
-       switch (opcode) {
-       case IB_WR_SEND:
-       case IB_WR_SEND_WITH_IMM:
-               qp->s_state = OP(RDMA_READ_RESPONSE_FIRST);
-               break;
-
-       case IB_WR_RDMA_WRITE:
-       case IB_WR_RDMA_WRITE_WITH_IMM:
-               qp->s_state = OP(RDMA_READ_RESPONSE_LAST);
-               break;
-
-       case IB_WR_RDMA_READ:
-               qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE);
-               break;
-
-       default:
-               /*
-                * This case shouldn't happen since its only
-                * one PSN per req.
-                */
-               qp->s_state = OP(SEND_LAST);
-       }
-done:
-       qp->s_psn = psn;
-}
-
-/**
- * ipath_restart_rc - back up requester to resend the last un-ACKed request
- * @qp: the QP to restart
- * @psn: packet sequence number for the request
- * @wc: the work completion request
- *
- * The QP s_lock should be held and interrupts disabled.
- */
-void ipath_restart_rc(struct ipath_qp *qp, u32 psn)
-{
-       struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
-       struct ipath_ibdev *dev;
-
-       if (qp->s_retry == 0) {
-               ipath_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR);
-               ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
-               goto bail;
-       }
-       qp->s_retry--;
-
-       /*
-        * Remove the QP from the timeout queue.
-        * Note: it may already have been removed by ipath_ib_timer().
-        */
-       dev = to_idev(qp->ibqp.device);
-       spin_lock(&dev->pending_lock);
-       if (!list_empty(&qp->timerwait))
-               list_del_init(&qp->timerwait);
-       if (!list_empty(&qp->piowait))
-               list_del_init(&qp->piowait);
-       spin_unlock(&dev->pending_lock);
-
-       if (wqe->wr.opcode == IB_WR_RDMA_READ)
-               dev->n_rc_resends++;
-       else
-               dev->n_rc_resends += (qp->s_psn - psn) & IPATH_PSN_MASK;
-
-       reset_psn(qp, psn);
-       ipath_schedule_send(qp);
-
-bail:
-       return;
-}
-
-static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
-{
-       qp->s_last_psn = psn;
-}
-
-/**
- * do_rc_ack - process an incoming RC ACK
- * @qp: the QP the ACK came in on
- * @psn: the packet sequence number of the ACK
- * @opcode: the opcode of the request that resulted in the ACK
- *
- * This is called from ipath_rc_rcv_resp() to process an incoming RC ACK
- * for the given QP.
- * Called at interrupt level with the QP s_lock held and interrupts disabled.
- * Returns 1 if OK, 0 if current operation should be aborted (NAK).
- */
-static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
-                    u64 val)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ib_wc wc;
-       enum ib_wc_status status;
-       struct ipath_swqe *wqe;
-       int ret = 0;
-       u32 ack_psn;
-       int diff;
-
-       /*
-        * Remove the QP from the timeout queue (or RNR timeout queue).
-        * If ipath_ib_timer() has already removed it,
-        * it's OK since we hold the QP s_lock and ipath_restart_rc()
-        * just won't find anything to restart if we ACK everything.
-        */
-       spin_lock(&dev->pending_lock);
-       if (!list_empty(&qp->timerwait))
-               list_del_init(&qp->timerwait);
-       spin_unlock(&dev->pending_lock);
-
-       /*
-        * Note that NAKs implicitly ACK outstanding SEND and RDMA write
-        * requests and implicitly NAK RDMA read and atomic requests issued
-        * before the NAK'ed request.  The MSN won't include the NAK'ed
-        * request but will include an ACK'ed request(s).
-        */
-       ack_psn = psn;
-       if (aeth >> 29)
-               ack_psn--;
-       wqe = get_swqe_ptr(qp, qp->s_last);
-
-       /*
-        * The MSN might be for a later WQE than the PSN indicates so
-        * only complete WQEs that the PSN finishes.
-        */
-       while ((diff = ipath_cmp24(ack_psn, wqe->lpsn)) >= 0) {
-               /*
-                * RDMA_READ_RESPONSE_ONLY is a special case since
-                * we want to generate completion events for everything
-                * before the RDMA read, copy the data, then generate
-                * the completion for the read.
-                */
-               if (wqe->wr.opcode == IB_WR_RDMA_READ &&
-                   opcode == OP(RDMA_READ_RESPONSE_ONLY) &&
-                   diff == 0) {
-                       ret = 1;
-                       goto bail;
-               }
-               /*
-                * If this request is a RDMA read or atomic, and the ACK is
-                * for a later operation, this ACK NAKs the RDMA read or
-                * atomic.  In other words, only a RDMA_READ_LAST or ONLY
-                * can ACK a RDMA read and likewise for atomic ops.  Note
-                * that the NAK case can only happen if relaxed ordering is
-                * used and requests are sent after an RDMA read or atomic
-                * is sent but before the response is received.
-                */
-               if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
-                    (opcode != OP(RDMA_READ_RESPONSE_LAST) || diff != 0)) ||
-                   ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                     wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
-                    (opcode != OP(ATOMIC_ACKNOWLEDGE) || diff != 0))) {
-                       /*
-                        * The last valid PSN seen is the previous
-                        * request's.
-                        */
-                       update_last_psn(qp, wqe->psn - 1);
-                       /* Retry this request. */
-                       ipath_restart_rc(qp, wqe->psn);
-                       /*
-                        * No need to process the ACK/NAK since we are
-                        * restarting an earlier request.
-                        */
-                       goto bail;
-               }
-               if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                   wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-                       *(u64 *) wqe->sg_list[0].vaddr = val;
-               if (qp->s_num_rd_atomic &&
-                   (wqe->wr.opcode == IB_WR_RDMA_READ ||
-                    wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                    wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) {
-                       qp->s_num_rd_atomic--;
-                       /* Restart sending task if fence is complete */
-                       if (((qp->s_flags & IPATH_S_FENCE_PENDING) &&
-                            !qp->s_num_rd_atomic) ||
-                           qp->s_flags & IPATH_S_RDMAR_PENDING)
-                               ipath_schedule_send(qp);
-               }
-               /* Post a send completion queue entry if requested. */
-               if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
-                   (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
-                       memset(&wc, 0, sizeof wc);
-                       wc.wr_id = wqe->wr.wr_id;
-                       wc.status = IB_WC_SUCCESS;
-                       wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
-                       wc.byte_len = wqe->length;
-                       wc.qp = &qp->ibqp;
-                       wc.src_qp = qp->remote_qpn;
-                       wc.slid = qp->remote_ah_attr.dlid;
-                       wc.sl = qp->remote_ah_attr.sl;
-                       ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
-               }
-               qp->s_retry = qp->s_retry_cnt;
-               /*
-                * If we are completing a request which is in the process of
-                * being resent, we can stop resending it since we know the
-                * responder has already seen it.
-                */
-               if (qp->s_last == qp->s_cur) {
-                       if (++qp->s_cur >= qp->s_size)
-                               qp->s_cur = 0;
-                       qp->s_last = qp->s_cur;
-                       if (qp->s_last == qp->s_tail)
-                               break;
-                       wqe = get_swqe_ptr(qp, qp->s_cur);
-                       qp->s_state = OP(SEND_LAST);
-                       qp->s_psn = wqe->psn;
-               } else {
-                       if (++qp->s_last >= qp->s_size)
-                               qp->s_last = 0;
-                       if (qp->state == IB_QPS_SQD && qp->s_last == qp->s_cur)
-                               qp->s_draining = 0;
-                       if (qp->s_last == qp->s_tail)
-                               break;
-                       wqe = get_swqe_ptr(qp, qp->s_last);
-               }
-       }
-
-       switch (aeth >> 29) {
-       case 0:         /* ACK */
-               dev->n_rc_acks++;
-               /* If this is a partial ACK, reset the retransmit timer. */
-               if (qp->s_last != qp->s_tail) {
-                       spin_lock(&dev->pending_lock);
-                       if (list_empty(&qp->timerwait))
-                               list_add_tail(&qp->timerwait,
-                                       &dev->pending[dev->pending_index]);
-                       spin_unlock(&dev->pending_lock);
-                       /*
-                        * If we get a partial ACK for a resent operation,
-                        * we can stop resending the earlier packets and
-                        * continue with the next packet the receiver wants.
-                        */
-                       if (ipath_cmp24(qp->s_psn, psn) <= 0) {
-                               reset_psn(qp, psn + 1);
-                               ipath_schedule_send(qp);
-                       }
-               } else if (ipath_cmp24(qp->s_psn, psn) <= 0) {
-                       qp->s_state = OP(SEND_LAST);
-                       qp->s_psn = psn + 1;
-               }
-               ipath_get_credit(qp, aeth);
-               qp->s_rnr_retry = qp->s_rnr_retry_cnt;
-               qp->s_retry = qp->s_retry_cnt;
-               update_last_psn(qp, psn);
-               ret = 1;
-               goto bail;
-
-       case 1:         /* RNR NAK */
-               dev->n_rnr_naks++;
-               if (qp->s_last == qp->s_tail)
-                       goto bail;
-               if (qp->s_rnr_retry == 0) {
-                       status = IB_WC_RNR_RETRY_EXC_ERR;
-                       goto class_b;
-               }
-               if (qp->s_rnr_retry_cnt < 7)
-                       qp->s_rnr_retry--;
-
-               /* The last valid PSN is the previous PSN. */
-               update_last_psn(qp, psn - 1);
-
-               if (wqe->wr.opcode == IB_WR_RDMA_READ)
-                       dev->n_rc_resends++;
-               else
-                       dev->n_rc_resends +=
-                               (qp->s_psn - psn) & IPATH_PSN_MASK;
-
-               reset_psn(qp, psn);
-
-               qp->s_rnr_timeout =
-                       ib_ipath_rnr_table[(aeth >> IPATH_AETH_CREDIT_SHIFT) &
-                                          IPATH_AETH_CREDIT_MASK];
-               ipath_insert_rnr_queue(qp);
-               ipath_schedule_send(qp);
-               goto bail;
-
-       case 3:         /* NAK */
-               if (qp->s_last == qp->s_tail)
-                       goto bail;
-               /* The last valid PSN is the previous PSN. */
-               update_last_psn(qp, psn - 1);
-               switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
-                       IPATH_AETH_CREDIT_MASK) {
-               case 0: /* PSN sequence error */
-                       dev->n_seq_naks++;
-                       /*
-                        * Back up to the responder's expected PSN.
-                        * Note that we might get a NAK in the middle of an
-                        * RDMA READ response which terminates the RDMA
-                        * READ.
-                        */
-                       ipath_restart_rc(qp, psn);
-                       break;
-
-               case 1: /* Invalid Request */
-                       status = IB_WC_REM_INV_REQ_ERR;
-                       dev->n_other_naks++;
-                       goto class_b;
-
-               case 2: /* Remote Access Error */
-                       status = IB_WC_REM_ACCESS_ERR;
-                       dev->n_other_naks++;
-                       goto class_b;
-
-               case 3: /* Remote Operation Error */
-                       status = IB_WC_REM_OP_ERR;
-                       dev->n_other_naks++;
-               class_b:
-                       ipath_send_complete(qp, wqe, status);
-                       ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
-                       break;
-
-               default:
-                       /* Ignore other reserved NAK error codes */
-                       goto reserved;
-               }
-               qp->s_rnr_retry = qp->s_rnr_retry_cnt;
-               goto bail;
-
-       default:                /* 2: reserved */
-       reserved:
-               /* Ignore reserved NAK codes. */
-               goto bail;
-       }
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_rc_rcv_resp - process an incoming RC response packet
- * @dev: the device this packet came in on
- * @ohdr: the other headers for this packet
- * @data: the packet data
- * @tlen: the packet length
- * @qp: the QP for this packet
- * @opcode: the opcode for this packet
- * @psn: the packet sequence number for this packet
- * @hdrsize: the header length
- * @pmtu: the path MTU
- * @header_in_data: true if part of the header data is in the data buffer
- *
- * This is called from ipath_rc_rcv() to process an incoming RC response
- * packet for the given QP.
- * Called at interrupt level.
- */
-static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
-                                    struct ipath_other_headers *ohdr,
-                                    void *data, u32 tlen,
-                                    struct ipath_qp *qp,
-                                    u32 opcode,
-                                    u32 psn, u32 hdrsize, u32 pmtu,
-                                    int header_in_data)
-{
-       struct ipath_swqe *wqe;
-       enum ib_wc_status status;
-       unsigned long flags;
-       int diff;
-       u32 pad;
-       u32 aeth;
-       u64 val;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       /* Double check we can process this now that we hold the s_lock. */
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
-               goto ack_done;
-
-       /* Ignore invalid responses. */
-       if (ipath_cmp24(psn, qp->s_next_psn) >= 0)
-               goto ack_done;
-
-       /* Ignore duplicate responses. */
-       diff = ipath_cmp24(psn, qp->s_last_psn);
-       if (unlikely(diff <= 0)) {
-               /* Update credits for "ghost" ACKs */
-               if (diff == 0 && opcode == OP(ACKNOWLEDGE)) {
-                       if (!header_in_data)
-                               aeth = be32_to_cpu(ohdr->u.aeth);
-                       else {
-                               aeth = be32_to_cpu(((__be32 *) data)[0]);
-                               data += sizeof(__be32);
-                       }
-                       if ((aeth >> 29) == 0)
-                               ipath_get_credit(qp, aeth);
-               }
-               goto ack_done;
-       }
-
-       if (unlikely(qp->s_last == qp->s_tail))
-               goto ack_done;
-       wqe = get_swqe_ptr(qp, qp->s_last);
-       status = IB_WC_SUCCESS;
-
-       switch (opcode) {
-       case OP(ACKNOWLEDGE):
-       case OP(ATOMIC_ACKNOWLEDGE):
-       case OP(RDMA_READ_RESPONSE_FIRST):
-               if (!header_in_data)
-                       aeth = be32_to_cpu(ohdr->u.aeth);
-               else {
-                       aeth = be32_to_cpu(((__be32 *) data)[0]);
-                       data += sizeof(__be32);
-               }
-               if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
-                       if (!header_in_data) {
-                               __be32 *p = ohdr->u.at.atomic_ack_eth;
-
-                               val = ((u64) be32_to_cpu(p[0]) << 32) |
-                                       be32_to_cpu(p[1]);
-                       } else
-                               val = be64_to_cpu(((__be64 *) data)[0]);
-               } else
-                       val = 0;
-               if (!do_rc_ack(qp, aeth, psn, opcode, val) ||
-                   opcode != OP(RDMA_READ_RESPONSE_FIRST))
-                       goto ack_done;
-               hdrsize += 4;
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
-                       goto ack_op_err;
-               qp->r_flags &= ~IPATH_R_RDMAR_SEQ;
-               /*
-                * If this is a response to a resent RDMA read, we
-                * have to be careful to copy the data to the right
-                * location.
-                */
-               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
-                                                 wqe, psn, pmtu);
-               goto read_middle;
-
-       case OP(RDMA_READ_RESPONSE_MIDDLE):
-               /* no AETH, no ACK */
-               if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
-                       dev->n_rdma_seq++;
-                       if (qp->r_flags & IPATH_R_RDMAR_SEQ)
-                               goto ack_done;
-                       qp->r_flags |= IPATH_R_RDMAR_SEQ;
-                       ipath_restart_rc(qp, qp->s_last_psn + 1);
-                       goto ack_done;
-               }
-               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
-                       goto ack_op_err;
-       read_middle:
-               if (unlikely(tlen != (hdrsize + pmtu + 4)))
-                       goto ack_len_err;
-               if (unlikely(pmtu >= qp->s_rdma_read_len))
-                       goto ack_len_err;
-
-               /* We got a response so update the timeout. */
-               spin_lock(&dev->pending_lock);
-               if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
-                       list_move_tail(&qp->timerwait,
-                                      &dev->pending[dev->pending_index]);
-               spin_unlock(&dev->pending_lock);
-
-               if (opcode == OP(RDMA_READ_RESPONSE_MIDDLE))
-                       qp->s_retry = qp->s_retry_cnt;
-
-               /*
-                * Update the RDMA receive state but do the copy w/o
-                * holding the locks and blocking interrupts.
-                */
-               qp->s_rdma_read_len -= pmtu;
-               update_last_psn(qp, psn);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-               ipath_copy_sge(&qp->s_rdma_read_sge, data, pmtu);
-               goto bail;
-
-       case OP(RDMA_READ_RESPONSE_ONLY):
-               if (!header_in_data)
-                       aeth = be32_to_cpu(ohdr->u.aeth);
-               else
-                       aeth = be32_to_cpu(((__be32 *) data)[0]);
-               if (!do_rc_ack(qp, aeth, psn, opcode, 0))
-                       goto ack_done;
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /*
-                * Check that the data size is >= 0 && <= pmtu.
-                * Remember to account for the AETH header (4) and
-                * ICRC (4).
-                */
-               if (unlikely(tlen < (hdrsize + pad + 8)))
-                       goto ack_len_err;
-               /*
-                * If this is a response to a resent RDMA read, we
-                * have to be careful to copy the data to the right
-                * location.
-                */
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
-                                                 wqe, psn, pmtu);
-               goto read_last;
-
-       case OP(RDMA_READ_RESPONSE_LAST):
-               /* ACKs READ req. */
-               if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
-                       dev->n_rdma_seq++;
-                       if (qp->r_flags & IPATH_R_RDMAR_SEQ)
-                               goto ack_done;
-                       qp->r_flags |= IPATH_R_RDMAR_SEQ;
-                       ipath_restart_rc(qp, qp->s_last_psn + 1);
-                       goto ack_done;
-               }
-               if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
-                       goto ack_op_err;
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /*
-                * Check that the data size is >= 1 && <= pmtu.
-                * Remember to account for the AETH header (4) and
-                * ICRC (4).
-                */
-               if (unlikely(tlen <= (hdrsize + pad + 8)))
-                       goto ack_len_err;
-       read_last:
-               tlen -= hdrsize + pad + 8;
-               if (unlikely(tlen != qp->s_rdma_read_len))
-                       goto ack_len_err;
-               if (!header_in_data)
-                       aeth = be32_to_cpu(ohdr->u.aeth);
-               else {
-                       aeth = be32_to_cpu(((__be32 *) data)[0]);
-                       data += sizeof(__be32);
-               }
-               ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen);
-               (void) do_rc_ack(qp, aeth, psn,
-                                OP(RDMA_READ_RESPONSE_LAST), 0);
-               goto ack_done;
-       }
-
-ack_op_err:
-       status = IB_WC_LOC_QP_OP_ERR;
-       goto ack_err;
-
-ack_len_err:
-       status = IB_WC_LOC_LEN_ERR;
-ack_err:
-       ipath_send_complete(qp, wqe, status);
-       ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
-ack_done:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-bail:
-       return;
-}
-
-/**
- * ipath_rc_rcv_error - process an incoming duplicate or error RC packet
- * @dev: the device this packet came in on
- * @ohdr: the other headers for this packet
- * @data: the packet data
- * @qp: the QP for this packet
- * @opcode: the opcode for this packet
- * @psn: the packet sequence number for this packet
- * @diff: the difference between the PSN and the expected PSN
- * @header_in_data: true if part of the header data is in the data buffer
- *
- * This is called from ipath_rc_rcv() to process an unexpected
- * incoming RC packet for the given QP.
- * Called at interrupt level.
- * Return 1 if no more processing is needed; otherwise return 0 to
- * schedule a response to be sent.
- */
-static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
-                                    struct ipath_other_headers *ohdr,
-                                    void *data,
-                                    struct ipath_qp *qp,
-                                    u32 opcode,
-                                    u32 psn,
-                                    int diff,
-                                    int header_in_data)
-{
-       struct ipath_ack_entry *e;
-       u8 i, prev;
-       int old_req;
-       unsigned long flags;
-
-       if (diff > 0) {
-               /*
-                * Packet sequence error.
-                * A NAK will ACK earlier sends and RDMA writes.
-                * Don't queue the NAK if we already sent one.
-                */
-               if (!qp->r_nak_state) {
-                       qp->r_nak_state = IB_NAK_PSN_ERROR;
-                       /* Use the expected PSN. */
-                       qp->r_ack_psn = qp->r_psn;
-                       goto send_ack;
-               }
-               goto done;
-       }
-
-       /*
-        * Handle a duplicate request.  Don't re-execute SEND, RDMA
-        * write or atomic op.  Don't NAK errors, just silently drop
-        * the duplicate request.  Note that r_sge, r_len, and
-        * r_rcv_len may be in use so don't modify them.
-        *
-        * We are supposed to ACK the earliest duplicate PSN but we
-        * can coalesce an outstanding duplicate ACK.  We have to
-        * send the earliest so that RDMA reads can be restarted at
-        * the requester's expected PSN.
-        *
-        * First, find where this duplicate PSN falls within the
-        * ACKs previously sent.
-        */
-       psn &= IPATH_PSN_MASK;
-       e = NULL;
-       old_req = 1;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-       /* Double check we can process this now that we hold the s_lock. */
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
-               goto unlock_done;
-
-       for (i = qp->r_head_ack_queue; ; i = prev) {
-               if (i == qp->s_tail_ack_queue)
-                       old_req = 0;
-               if (i)
-                       prev = i - 1;
-               else
-                       prev = IPATH_MAX_RDMA_ATOMIC;
-               if (prev == qp->r_head_ack_queue) {
-                       e = NULL;
-                       break;
-               }
-               e = &qp->s_ack_queue[prev];
-               if (!e->opcode) {
-                       e = NULL;
-                       break;
-               }
-               if (ipath_cmp24(psn, e->psn) >= 0) {
-                       if (prev == qp->s_tail_ack_queue)
-                               old_req = 0;
-                       break;
-               }
-       }
-       switch (opcode) {
-       case OP(RDMA_READ_REQUEST): {
-               struct ib_reth *reth;
-               u32 offset;
-               u32 len;
-
-               /*
-                * If we didn't find the RDMA read request in the ack queue,
-                * or the send tasklet is already backed up to send an
-                * earlier entry, we can ignore this request.
-                */
-               if (!e || e->opcode != OP(RDMA_READ_REQUEST) || old_req)
-                       goto unlock_done;
-               /* RETH comes after BTH */
-               if (!header_in_data)
-                       reth = &ohdr->u.rc.reth;
-               else {
-                       reth = (struct ib_reth *)data;
-                       data += sizeof(*reth);
-               }
-               /*
-                * Address range must be a subset of the original
-                * request and start on pmtu boundaries.
-                * We reuse the old ack_queue slot since the requester
-                * should not back up and request an earlier PSN for the
-                * same request.
-                */
-               offset = ((psn - e->psn) & IPATH_PSN_MASK) *
-                       ib_mtu_enum_to_int(qp->path_mtu);
-               len = be32_to_cpu(reth->length);
-               if (unlikely(offset + len > e->rdma_sge.sge.sge_length))
-                       goto unlock_done;
-               if (len != 0) {
-                       u32 rkey = be32_to_cpu(reth->rkey);
-                       u64 vaddr = be64_to_cpu(reth->vaddr);
-                       int ok;
-
-                       ok = ipath_rkey_ok(qp, &e->rdma_sge,
-                                          len, vaddr, rkey,
-                                          IB_ACCESS_REMOTE_READ);
-                       if (unlikely(!ok))
-                               goto unlock_done;
-               } else {
-                       e->rdma_sge.sg_list = NULL;
-                       e->rdma_sge.num_sge = 0;
-                       e->rdma_sge.sge.mr = NULL;
-                       e->rdma_sge.sge.vaddr = NULL;
-                       e->rdma_sge.sge.length = 0;
-                       e->rdma_sge.sge.sge_length = 0;
-               }
-               e->psn = psn;
-               qp->s_ack_state = OP(ACKNOWLEDGE);
-               qp->s_tail_ack_queue = prev;
-               break;
-       }
-
-       case OP(COMPARE_SWAP):
-       case OP(FETCH_ADD): {
-               /*
-                * If we didn't find the atomic request in the ack queue
-                * or the send tasklet is already backed up to send an
-                * earlier entry, we can ignore this request.
-                */
-               if (!e || e->opcode != (u8) opcode || old_req)
-                       goto unlock_done;
-               qp->s_ack_state = OP(ACKNOWLEDGE);
-               qp->s_tail_ack_queue = prev;
-               break;
-       }
-
-       default:
-               if (old_req)
-                       goto unlock_done;
-               /*
-                * Resend the most recent ACK if this request is
-                * after all the previous RDMA reads and atomics.
-                */
-               if (i == qp->r_head_ack_queue) {
-                       spin_unlock_irqrestore(&qp->s_lock, flags);
-                       qp->r_nak_state = 0;
-                       qp->r_ack_psn = qp->r_psn - 1;
-                       goto send_ack;
-               }
-               /*
-                * Try to send a simple ACK to work around a Mellanox bug
-                * which doesn't accept a RDMA read response or atomic
-                * response as an ACK for earlier SENDs or RDMA writes.
-                */
-               if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
-                   !(qp->s_flags & IPATH_S_ACK_PENDING) &&
-                   qp->s_ack_state == OP(ACKNOWLEDGE)) {
-                       spin_unlock_irqrestore(&qp->s_lock, flags);
-                       qp->r_nak_state = 0;
-                       qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
-                       goto send_ack;
-               }
-               /*
-                * Resend the RDMA read or atomic op which
-                * ACKs this duplicate request.
-                */
-               qp->s_ack_state = OP(ACKNOWLEDGE);
-               qp->s_tail_ack_queue = i;
-               break;
-       }
-       qp->r_nak_state = 0;
-       ipath_schedule_send(qp);
-
-unlock_done:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-done:
-       return 1;
-
-send_ack:
-       return 0;
-}
-
-void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
-{
-       unsigned long flags;
-       int lastwqe;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-       lastwqe = ipath_error_qp(qp, err);
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-
-       if (lastwqe) {
-               struct ib_event ev;
-
-               ev.device = qp->ibqp.device;
-               ev.element.qp = &qp->ibqp;
-               ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
-               qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
-       }
-}
-
-static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
-{
-       unsigned next;
-
-       next = n + 1;
-       if (next > IPATH_MAX_RDMA_ATOMIC)
-               next = 0;
-       if (n == qp->s_tail_ack_queue) {
-               qp->s_tail_ack_queue = next;
-               qp->s_ack_state = OP(ACKNOWLEDGE);
-       }
-}
-
-/**
- * ipath_rc_rcv - process an incoming RC packet
- * @dev: the device this packet came in on
- * @hdr: the header of this packet
- * @has_grh: true if the header has a GRH
- * @data: the packet data
- * @tlen: the packet length
- * @qp: the QP for this packet
- *
- * This is called from ipath_qp_rcv() to process an incoming RC packet
- * for the given QP.
- * Called at interrupt level.
- */
-void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp)
-{
-       struct ipath_other_headers *ohdr;
-       u32 opcode;
-       u32 hdrsize;
-       u32 psn;
-       u32 pad;
-       struct ib_wc wc;
-       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
-       int diff;
-       struct ib_reth *reth;
-       int header_in_data;
-       unsigned long flags;
-
-       /* Validate the SLID. See Ch. 9.6.1.5 */
-       if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
-               goto done;
-
-       /* Check for GRH */
-       if (!has_grh) {
-               ohdr = &hdr->u.oth;
-               hdrsize = 8 + 12;       /* LRH + BTH */
-               psn = be32_to_cpu(ohdr->bth[2]);
-               header_in_data = 0;
-       } else {
-               ohdr = &hdr->u.l.oth;
-               hdrsize = 8 + 40 + 12;  /* LRH + GRH + BTH */
-               /*
-                * The header with GRH is 60 bytes and the core driver sets
-                * the eager header buffer size to 56 bytes so the last 4
-                * bytes of the BTH header (PSN) is in the data buffer.
-                */
-               header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
-               if (header_in_data) {
-                       psn = be32_to_cpu(((__be32 *) data)[0]);
-                       data += sizeof(__be32);
-               } else
-                       psn = be32_to_cpu(ohdr->bth[2]);
-       }
-
-       /*
-        * Process responses (ACKs) before anything else.  Note that the
-        * packet sequence number will be for something in the send work
-        * queue rather than the expected receive packet sequence number.
-        * In other words, this QP is the requester.
-        */
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
-       if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
-           opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
-               ipath_rc_rcv_resp(dev, ohdr, data, tlen, qp, opcode, psn,
-                                 hdrsize, pmtu, header_in_data);
-               goto done;
-       }
-
-       /* Compute 24 bits worth of difference. */
-       diff = ipath_cmp24(psn, qp->r_psn);
-       if (unlikely(diff)) {
-               if (ipath_rc_rcv_error(dev, ohdr, data, qp, opcode,
-                                      psn, diff, header_in_data))
-                       goto done;
-               goto send_ack;
-       }
-
-       /* Check for opcode sequence errors. */
-       switch (qp->r_state) {
-       case OP(SEND_FIRST):
-       case OP(SEND_MIDDLE):
-               if (opcode == OP(SEND_MIDDLE) ||
-                   opcode == OP(SEND_LAST) ||
-                   opcode == OP(SEND_LAST_WITH_IMMEDIATE))
-                       break;
-               goto nack_inv;
-
-       case OP(RDMA_WRITE_FIRST):
-       case OP(RDMA_WRITE_MIDDLE):
-               if (opcode == OP(RDMA_WRITE_MIDDLE) ||
-                   opcode == OP(RDMA_WRITE_LAST) ||
-                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
-                       break;
-               goto nack_inv;
-
-       default:
-               if (opcode == OP(SEND_MIDDLE) ||
-                   opcode == OP(SEND_LAST) ||
-                   opcode == OP(SEND_LAST_WITH_IMMEDIATE) ||
-                   opcode == OP(RDMA_WRITE_MIDDLE) ||
-                   opcode == OP(RDMA_WRITE_LAST) ||
-                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
-                       goto nack_inv;
-               /*
-                * Note that it is up to the requester to not send a new
-                * RDMA read or atomic operation before receiving an ACK
-                * for the previous operation.
-                */
-               break;
-       }
-
-       memset(&wc, 0, sizeof wc);
-
-       /* OK, process the packet. */
-       switch (opcode) {
-       case OP(SEND_FIRST):
-               if (!ipath_get_rwqe(qp, 0))
-                       goto rnr_nak;
-               qp->r_rcv_len = 0;
-               /* FALLTHROUGH */
-       case OP(SEND_MIDDLE):
-       case OP(RDMA_WRITE_MIDDLE):
-       send_middle:
-               /* Check for invalid length PMTU or posted rwqe len. */
-               if (unlikely(tlen != (hdrsize + pmtu + 4)))
-                       goto nack_inv;
-               qp->r_rcv_len += pmtu;
-               if (unlikely(qp->r_rcv_len > qp->r_len))
-                       goto nack_inv;
-               ipath_copy_sge(&qp->r_sge, data, pmtu);
-               break;
-
-       case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
-               /* consume RWQE */
-               if (!ipath_get_rwqe(qp, 1))
-                       goto rnr_nak;
-               goto send_last_imm;
-
-       case OP(SEND_ONLY):
-       case OP(SEND_ONLY_WITH_IMMEDIATE):
-               if (!ipath_get_rwqe(qp, 0))
-                       goto rnr_nak;
-               qp->r_rcv_len = 0;
-               if (opcode == OP(SEND_ONLY))
-                       goto send_last;
-               /* FALLTHROUGH */
-       case OP(SEND_LAST_WITH_IMMEDIATE):
-       send_last_imm:
-               if (header_in_data) {
-                       wc.ex.imm_data = *(__be32 *) data;
-                       data += sizeof(__be32);
-               } else {
-                       /* Immediate data comes after BTH */
-                       wc.ex.imm_data = ohdr->u.imm_data;
-               }
-               hdrsize += 4;
-               wc.wc_flags = IB_WC_WITH_IMM;
-               /* FALLTHROUGH */
-       case OP(SEND_LAST):
-       case OP(RDMA_WRITE_LAST):
-       send_last:
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /* Check for invalid length. */
-               /* XXX LAST len should be >= 1 */
-               if (unlikely(tlen < (hdrsize + pad + 4)))
-                       goto nack_inv;
-               /* Don't count the CRC. */
-               tlen -= (hdrsize + pad + 4);
-               wc.byte_len = tlen + qp->r_rcv_len;
-               if (unlikely(wc.byte_len > qp->r_len))
-                       goto nack_inv;
-               ipath_copy_sge(&qp->r_sge, data, tlen);
-               qp->r_msn++;
-               if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
-                       break;
-               wc.wr_id = qp->r_wr_id;
-               wc.status = IB_WC_SUCCESS;
-               if (opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE) ||
-                   opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
-                       wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
-               else
-                       wc.opcode = IB_WC_RECV;
-               wc.qp = &qp->ibqp;
-               wc.src_qp = qp->remote_qpn;
-               wc.slid = qp->remote_ah_attr.dlid;
-               wc.sl = qp->remote_ah_attr.sl;
-               /* Signal completion event if the solicited bit is set. */
-               ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                              (ohdr->bth[0] &
-                               cpu_to_be32(1 << 23)) != 0);
-               break;
-
-       case OP(RDMA_WRITE_FIRST):
-       case OP(RDMA_WRITE_ONLY):
-       case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_WRITE)))
-                       goto nack_inv;
-               /* consume RWQE */
-               /* RETH comes after BTH */
-               if (!header_in_data)
-                       reth = &ohdr->u.rc.reth;
-               else {
-                       reth = (struct ib_reth *)data;
-                       data += sizeof(*reth);
-               }
-               hdrsize += sizeof(*reth);
-               qp->r_len = be32_to_cpu(reth->length);
-               qp->r_rcv_len = 0;
-               if (qp->r_len != 0) {
-                       u32 rkey = be32_to_cpu(reth->rkey);
-                       u64 vaddr = be64_to_cpu(reth->vaddr);
-                       int ok;
-
-                       /* Check rkey & NAK */
-                       ok = ipath_rkey_ok(qp, &qp->r_sge,
-                                          qp->r_len, vaddr, rkey,
-                                          IB_ACCESS_REMOTE_WRITE);
-                       if (unlikely(!ok))
-                               goto nack_acc;
-               } else {
-                       qp->r_sge.sg_list = NULL;
-                       qp->r_sge.sge.mr = NULL;
-                       qp->r_sge.sge.vaddr = NULL;
-                       qp->r_sge.sge.length = 0;
-                       qp->r_sge.sge.sge_length = 0;
-               }
-               if (opcode == OP(RDMA_WRITE_FIRST))
-                       goto send_middle;
-               else if (opcode == OP(RDMA_WRITE_ONLY))
-                       goto send_last;
-               if (!ipath_get_rwqe(qp, 1))
-                       goto rnr_nak;
-               goto send_last_imm;
-
-       case OP(RDMA_READ_REQUEST): {
-               struct ipath_ack_entry *e;
-               u32 len;
-               u8 next;
-
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_READ)))
-                       goto nack_inv;
-               next = qp->r_head_ack_queue + 1;
-               if (next > IPATH_MAX_RDMA_ATOMIC)
-                       next = 0;
-               spin_lock_irqsave(&qp->s_lock, flags);
-               /* Double check we can process this while holding the s_lock. */
-               if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
-                       goto unlock;
-               if (unlikely(next == qp->s_tail_ack_queue)) {
-                       if (!qp->s_ack_queue[next].sent)
-                               goto nack_inv_unlck;
-                       ipath_update_ack_queue(qp, next);
-               }
-               e = &qp->s_ack_queue[qp->r_head_ack_queue];
-               /* RETH comes after BTH */
-               if (!header_in_data)
-                       reth = &ohdr->u.rc.reth;
-               else {
-                       reth = (struct ib_reth *)data;
-                       data += sizeof(*reth);
-               }
-               len = be32_to_cpu(reth->length);
-               if (len) {
-                       u32 rkey = be32_to_cpu(reth->rkey);
-                       u64 vaddr = be64_to_cpu(reth->vaddr);
-                       int ok;
-
-                       /* Check rkey & NAK */
-                       ok = ipath_rkey_ok(qp, &e->rdma_sge, len, vaddr,
-                                          rkey, IB_ACCESS_REMOTE_READ);
-                       if (unlikely(!ok))
-                               goto nack_acc_unlck;
-                       /*
-                        * Update the next expected PSN.  We add 1 later
-                        * below, so only add the remainder here.
-                        */
-                       if (len > pmtu)
-                               qp->r_psn += (len - 1) / pmtu;
-               } else {
-                       e->rdma_sge.sg_list = NULL;
-                       e->rdma_sge.num_sge = 0;
-                       e->rdma_sge.sge.mr = NULL;
-                       e->rdma_sge.sge.vaddr = NULL;
-                       e->rdma_sge.sge.length = 0;
-                       e->rdma_sge.sge.sge_length = 0;
-               }
-               e->opcode = opcode;
-               e->sent = 0;
-               e->psn = psn;
-               /*
-                * We need to increment the MSN here instead of when we
-                * finish sending the result since a duplicate request would
-                * increment it more than once.
-                */
-               qp->r_msn++;
-               qp->r_psn++;
-               qp->r_state = opcode;
-               qp->r_nak_state = 0;
-               qp->r_head_ack_queue = next;
-
-               /* Schedule the send tasklet. */
-               ipath_schedule_send(qp);
-
-               goto unlock;
-       }
-
-       case OP(COMPARE_SWAP):
-       case OP(FETCH_ADD): {
-               struct ib_atomic_eth *ateth;
-               struct ipath_ack_entry *e;
-               u64 vaddr;
-               atomic64_t *maddr;
-               u64 sdata;
-               u32 rkey;
-               u8 next;
-
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_ATOMIC)))
-                       goto nack_inv;
-               next = qp->r_head_ack_queue + 1;
-               if (next > IPATH_MAX_RDMA_ATOMIC)
-                       next = 0;
-               spin_lock_irqsave(&qp->s_lock, flags);
-               /* Double check we can process this while holding the s_lock. */
-               if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK))
-                       goto unlock;
-               if (unlikely(next == qp->s_tail_ack_queue)) {
-                       if (!qp->s_ack_queue[next].sent)
-                               goto nack_inv_unlck;
-                       ipath_update_ack_queue(qp, next);
-               }
-               if (!header_in_data)
-                       ateth = &ohdr->u.atomic_eth;
-               else
-                       ateth = (struct ib_atomic_eth *)data;
-               vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) |
-                       be32_to_cpu(ateth->vaddr[1]);
-               if (unlikely(vaddr & (sizeof(u64) - 1)))
-                       goto nack_inv_unlck;
-               rkey = be32_to_cpu(ateth->rkey);
-               /* Check rkey & NAK */
-               if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge,
-                                           sizeof(u64), vaddr, rkey,
-                                           IB_ACCESS_REMOTE_ATOMIC)))
-                       goto nack_acc_unlck;
-               /* Perform atomic OP and save result. */
-               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
-               sdata = be64_to_cpu(ateth->swap_data);
-               e = &qp->s_ack_queue[qp->r_head_ack_queue];
-               e->atomic_data = (opcode == OP(FETCH_ADD)) ?
-                       (u64) atomic64_add_return(sdata, maddr) - sdata :
-                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
-                                     be64_to_cpu(ateth->compare_data),
-                                     sdata);
-               e->opcode = opcode;
-               e->sent = 0;
-               e->psn = psn & IPATH_PSN_MASK;
-               qp->r_msn++;
-               qp->r_psn++;
-               qp->r_state = opcode;
-               qp->r_nak_state = 0;
-               qp->r_head_ack_queue = next;
-
-               /* Schedule the send tasklet. */
-               ipath_schedule_send(qp);
-
-               goto unlock;
-       }
-
-       default:
-               /* NAK unknown opcodes. */
-               goto nack_inv;
-       }
-       qp->r_psn++;
-       qp->r_state = opcode;
-       qp->r_ack_psn = psn;
-       qp->r_nak_state = 0;
-       /* Send an ACK if requested or required. */
-       if (psn & (1 << 31))
-               goto send_ack;
-       goto done;
-
-rnr_nak:
-       qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
-       qp->r_ack_psn = qp->r_psn;
-       goto send_ack;
-
-nack_inv_unlck:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-nack_inv:
-       ipath_rc_error(qp, IB_WC_LOC_QP_OP_ERR);
-       qp->r_nak_state = IB_NAK_INVALID_REQUEST;
-       qp->r_ack_psn = qp->r_psn;
-       goto send_ack;
-
-nack_acc_unlck:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-nack_acc:
-       ipath_rc_error(qp, IB_WC_LOC_PROT_ERR);
-       qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
-       qp->r_ack_psn = qp->r_psn;
-send_ack:
-       send_rc_ack(qp);
-       goto done;
-
-unlock:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-done:
-       return;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_registers.h b/drivers/staging/rdma/ipath/ipath_registers.h
deleted file mode 100644 (file)
index 8f44d0c..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _IPATH_REGISTERS_H
-#define _IPATH_REGISTERS_H
-
-/*
- * This file should only be included by kernel source, and by the diags.  It
- * defines the registers, and their contents, for InfiniPath chips.
- */
-
-/*
- * These are the InfiniPath register and buffer bit definitions,
- * that are visible to software, and needed only by the kernel
- * and diag code.  A few, that are visible to protocol and user
- * code are in ipath_common.h.  Some bits are specific
- * to a given chip implementation, and have been moved to the
- * chip-specific source file
- */
-
-/* kr_revision bits */
-#define INFINIPATH_R_CHIPREVMINOR_MASK 0xFF
-#define INFINIPATH_R_CHIPREVMINOR_SHIFT 0
-#define INFINIPATH_R_CHIPREVMAJOR_MASK 0xFF
-#define INFINIPATH_R_CHIPREVMAJOR_SHIFT 8
-#define INFINIPATH_R_ARCH_MASK 0xFF
-#define INFINIPATH_R_ARCH_SHIFT 16
-#define INFINIPATH_R_SOFTWARE_MASK 0xFF
-#define INFINIPATH_R_SOFTWARE_SHIFT 24
-#define INFINIPATH_R_BOARDID_MASK 0xFF
-#define INFINIPATH_R_BOARDID_SHIFT 32
-
-/* kr_control bits */
-#define INFINIPATH_C_FREEZEMODE 0x00000002
-#define INFINIPATH_C_LINKENABLE 0x00000004
-
-/* kr_sendctrl bits */
-#define INFINIPATH_S_DISARMPIOBUF_SHIFT 16
-#define INFINIPATH_S_UPDTHRESH_SHIFT 24
-#define INFINIPATH_S_UPDTHRESH_MASK 0x1f
-
-#define IPATH_S_ABORT          0
-#define IPATH_S_PIOINTBUFAVAIL 1
-#define IPATH_S_PIOBUFAVAILUPD 2
-#define IPATH_S_PIOENABLE      3
-#define IPATH_S_SDMAINTENABLE  9
-#define IPATH_S_SDMASINGLEDESCRIPTOR   10
-#define IPATH_S_SDMAENABLE     11
-#define IPATH_S_SDMAHALT       12
-#define IPATH_S_DISARM         31
-
-#define INFINIPATH_S_ABORT             (1U << IPATH_S_ABORT)
-#define INFINIPATH_S_PIOINTBUFAVAIL    (1U << IPATH_S_PIOINTBUFAVAIL)
-#define INFINIPATH_S_PIOBUFAVAILUPD    (1U << IPATH_S_PIOBUFAVAILUPD)
-#define INFINIPATH_S_PIOENABLE         (1U << IPATH_S_PIOENABLE)
-#define INFINIPATH_S_SDMAINTENABLE     (1U << IPATH_S_SDMAINTENABLE)
-#define INFINIPATH_S_SDMASINGLEDESCRIPTOR \
-                                       (1U << IPATH_S_SDMASINGLEDESCRIPTOR)
-#define INFINIPATH_S_SDMAENABLE                (1U << IPATH_S_SDMAENABLE)
-#define INFINIPATH_S_SDMAHALT          (1U << IPATH_S_SDMAHALT)
-#define INFINIPATH_S_DISARM            (1U << IPATH_S_DISARM)
-
-/* kr_rcvctrl bits that are the same on multiple chips */
-#define INFINIPATH_R_PORTENABLE_SHIFT 0
-#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38)
-
-/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_SDMAINT           0x8000000000000000ULL
-#define INFINIPATH_I_SDMADISABLED      0x4000000000000000ULL
-#define INFINIPATH_I_ERROR             0x0000000080000000ULL
-#define INFINIPATH_I_SPIOSENT          0x0000000040000000ULL
-#define INFINIPATH_I_SPIOBUFAVAIL      0x0000000020000000ULL
-#define INFINIPATH_I_GPIO              0x0000000010000000ULL
-#define INFINIPATH_I_JINT              0x0000000004000000ULL
-
-/* kr_errorstatus, kr_errorclear, kr_errormask bits */
-#define INFINIPATH_E_RFORMATERR                        0x0000000000000001ULL
-#define INFINIPATH_E_RVCRC                     0x0000000000000002ULL
-#define INFINIPATH_E_RICRC                     0x0000000000000004ULL
-#define INFINIPATH_E_RMINPKTLEN                        0x0000000000000008ULL
-#define INFINIPATH_E_RMAXPKTLEN                        0x0000000000000010ULL
-#define INFINIPATH_E_RLONGPKTLEN               0x0000000000000020ULL
-#define INFINIPATH_E_RSHORTPKTLEN              0x0000000000000040ULL
-#define INFINIPATH_E_RUNEXPCHAR                        0x0000000000000080ULL
-#define INFINIPATH_E_RUNSUPVL                  0x0000000000000100ULL
-#define INFINIPATH_E_REBP                      0x0000000000000200ULL
-#define INFINIPATH_E_RIBFLOW                   0x0000000000000400ULL
-#define INFINIPATH_E_RBADVERSION               0x0000000000000800ULL
-#define INFINIPATH_E_RRCVEGRFULL               0x0000000000001000ULL
-#define INFINIPATH_E_RRCVHDRFULL               0x0000000000002000ULL
-#define INFINIPATH_E_RBADTID                   0x0000000000004000ULL
-#define INFINIPATH_E_RHDRLEN                   0x0000000000008000ULL
-#define INFINIPATH_E_RHDR                      0x0000000000010000ULL
-#define INFINIPATH_E_RIBLOSTLINK               0x0000000000020000ULL
-#define INFINIPATH_E_SENDSPECIALTRIGGER                0x0000000008000000ULL
-#define INFINIPATH_E_SDMADISABLED              0x0000000010000000ULL
-#define INFINIPATH_E_SMINPKTLEN                        0x0000000020000000ULL
-#define INFINIPATH_E_SMAXPKTLEN                        0x0000000040000000ULL
-#define INFINIPATH_E_SUNDERRUN                 0x0000000080000000ULL
-#define INFINIPATH_E_SPKTLEN                   0x0000000100000000ULL
-#define INFINIPATH_E_SDROPPEDSMPPKT            0x0000000200000000ULL
-#define INFINIPATH_E_SDROPPEDDATAPKT           0x0000000400000000ULL
-#define INFINIPATH_E_SPIOARMLAUNCH             0x0000000800000000ULL
-#define INFINIPATH_E_SUNEXPERRPKTNUM           0x0000001000000000ULL
-#define INFINIPATH_E_SUNSUPVL                  0x0000002000000000ULL
-#define INFINIPATH_E_SENDBUFMISUSE             0x0000004000000000ULL
-#define INFINIPATH_E_SDMAGENMISMATCH           0x0000008000000000ULL
-#define INFINIPATH_E_SDMAOUTOFBOUND            0x0000010000000000ULL
-#define INFINIPATH_E_SDMATAILOUTOFBOUND                0x0000020000000000ULL
-#define INFINIPATH_E_SDMABASE                  0x0000040000000000ULL
-#define INFINIPATH_E_SDMA1STDESC               0x0000080000000000ULL
-#define INFINIPATH_E_SDMARPYTAG                        0x0000100000000000ULL
-#define INFINIPATH_E_SDMADWEN                  0x0000200000000000ULL
-#define INFINIPATH_E_SDMAMISSINGDW             0x0000400000000000ULL
-#define INFINIPATH_E_SDMAUNEXPDATA             0x0000800000000000ULL
-#define INFINIPATH_E_IBSTATUSCHANGED           0x0001000000000000ULL
-#define INFINIPATH_E_INVALIDADDR               0x0002000000000000ULL
-#define INFINIPATH_E_RESET                     0x0004000000000000ULL
-#define INFINIPATH_E_HARDWARE                  0x0008000000000000ULL
-#define INFINIPATH_E_SDMADESCADDRMISALIGN      0x0010000000000000ULL
-#define INFINIPATH_E_INVALIDEEPCMD             0x0020000000000000ULL
-
-/*
- * this is used to print "common" packet errors only when the
- * __IPATH_ERRPKTDBG bit is set in ipath_debug.
- */
-#define INFINIPATH_E_PKTERRS ( INFINIPATH_E_SPKTLEN \
-               | INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_RVCRC \
-               | INFINIPATH_E_RICRC | INFINIPATH_E_RSHORTPKTLEN \
-               | INFINIPATH_E_REBP )
-
-/* Convenience for decoding Send DMA errors */
-#define INFINIPATH_E_SDMAERRS ( \
-       INFINIPATH_E_SDMAGENMISMATCH | INFINIPATH_E_SDMAOUTOFBOUND | \
-       INFINIPATH_E_SDMATAILOUTOFBOUND | INFINIPATH_E_SDMABASE | \
-       INFINIPATH_E_SDMA1STDESC | INFINIPATH_E_SDMARPYTAG | \
-       INFINIPATH_E_SDMADWEN | INFINIPATH_E_SDMAMISSINGDW | \
-       INFINIPATH_E_SDMAUNEXPDATA | \
-       INFINIPATH_E_SDMADESCADDRMISALIGN | \
-       INFINIPATH_E_SDMADISABLED | \
-       INFINIPATH_E_SENDBUFMISUSE)
-
-/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
-/* TXEMEMPARITYERR bit 0: PIObuf, 1: PIOpbc, 2: launchfifo
- * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2:  expTID, 3: eagerTID
- *             bit 4: flag buffer, 5: datainfo, 6: header info */
-#define INFINIPATH_HWE_TXEMEMPARITYERR_MASK 0xFULL
-#define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40
-#define INFINIPATH_HWE_RXEMEMPARITYERR_MASK 0x7FULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT 44
-#define INFINIPATH_HWE_IBCBUSTOSPCPARITYERR 0x4000000000000000ULL
-#define INFINIPATH_HWE_IBCBUSFRSPCPARITYERR 0x8000000000000000ULL
-/* txe mem parity errors (shift by INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) */
-#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF  0x1ULL
-#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC  0x2ULL
-#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOLAUNCHFIFO 0x4ULL
-/* rxe mem parity errors (shift by INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) */
-#define INFINIPATH_HWE_RXEMEMPARITYERR_RCVBUF   0x01ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_LOOKUPQ  0x02ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID   0x04ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x08ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF  0x10ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL
-#define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO  0x40ULL
-/* waldo specific -- find the rest in ipath_6110.c */
-#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR  0x0000000400000000ULL
-/* 6120/7220 specific -- find the rest in ipath_6120.c and ipath_7220.c */
-#define INFINIPATH_HWE_MEMBISTFAILED   0x0040000000000000ULL
-
-/* kr_hwdiagctrl bits */
-#define INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK 0xFULL
-#define INFINIPATH_DC_FORCETXEMEMPARITYERR_SHIFT 40
-#define INFINIPATH_DC_FORCERXEMEMPARITYERR_MASK 0x7FULL
-#define INFINIPATH_DC_FORCERXEMEMPARITYERR_SHIFT 44
-#define INFINIPATH_DC_FORCERXDSYNCMEMPARITYERR  0x0000000400000000ULL
-#define INFINIPATH_DC_COUNTERDISABLE            0x1000000000000000ULL
-#define INFINIPATH_DC_COUNTERWREN               0x2000000000000000ULL
-#define INFINIPATH_DC_FORCEIBCBUSTOSPCPARITYERR 0x4000000000000000ULL
-#define INFINIPATH_DC_FORCEIBCBUSFRSPCPARITYERR 0x8000000000000000ULL
-
-/* kr_ibcctrl bits */
-#define INFINIPATH_IBCC_FLOWCTRLPERIOD_MASK 0xFFULL
-#define INFINIPATH_IBCC_FLOWCTRLPERIOD_SHIFT 0
-#define INFINIPATH_IBCC_FLOWCTRLWATERMARK_MASK 0xFFULL
-#define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8
-#define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL
-#define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1
-/* cycle through TS1/TS2 till OK */
-#define INFINIPATH_IBCC_LINKINITCMD_POLL 2
-/* wait for TS1, then go on */
-#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3
-#define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16
-#define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL
-#define INFINIPATH_IBCC_LINKCMD_DOWN 1         /* move to 0x11 */
-#define INFINIPATH_IBCC_LINKCMD_ARMED 2                /* move to 0x21 */
-#define INFINIPATH_IBCC_LINKCMD_ACTIVE 3       /* move to 0x31 */
-#define INFINIPATH_IBCC_LINKCMD_SHIFT 18
-#define INFINIPATH_IBCC_MAXPKTLEN_MASK 0x7FFULL
-#define INFINIPATH_IBCC_MAXPKTLEN_SHIFT 20
-#define INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK 0xFULL
-#define INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT 32
-#define INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK 0xFULL
-#define INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT 36
-#define INFINIPATH_IBCC_CREDITSCALE_MASK 0x7ULL
-#define INFINIPATH_IBCC_CREDITSCALE_SHIFT 40
-#define INFINIPATH_IBCC_LOOPBACK             0x8000000000000000ULL
-#define INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE 0x4000000000000000ULL
-
-/* kr_ibcstatus bits */
-#define INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT 0
-#define INFINIPATH_IBCS_LINKSTATE_MASK 0x7
-
-#define INFINIPATH_IBCS_TXREADY       0x40000000
-#define INFINIPATH_IBCS_TXCREDITOK    0x80000000
-/* link training states (shift by
-   INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */
-#define INFINIPATH_IBCS_LT_STATE_DISABLED      0x00
-#define INFINIPATH_IBCS_LT_STATE_LINKUP                0x01
-#define INFINIPATH_IBCS_LT_STATE_POLLACTIVE    0x02
-#define INFINIPATH_IBCS_LT_STATE_POLLQUIET     0x03
-#define INFINIPATH_IBCS_LT_STATE_SLEEPDELAY    0x04
-#define INFINIPATH_IBCS_LT_STATE_SLEEPQUIET    0x05
-#define INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE   0x08
-#define INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG    0x09
-#define INFINIPATH_IBCS_LT_STATE_CFGWAITRMT    0x0a
-#define INFINIPATH_IBCS_LT_STATE_CFGIDLE       0x0b
-#define INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN        0x0c
-#define INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT        0x0e
-#define INFINIPATH_IBCS_LT_STATE_RECOVERIDLE   0x0f
-/* link state machine states (shift by ibcs_ls_shift) */
-#define INFINIPATH_IBCS_L_STATE_DOWN           0x0
-#define INFINIPATH_IBCS_L_STATE_INIT           0x1
-#define INFINIPATH_IBCS_L_STATE_ARM            0x2
-#define INFINIPATH_IBCS_L_STATE_ACTIVE         0x3
-#define INFINIPATH_IBCS_L_STATE_ACT_DEFER      0x4
-
-
-/* kr_extstatus bits */
-#define INFINIPATH_EXTS_SERDESPLLLOCK 0x1
-#define INFINIPATH_EXTS_GPIOIN_MASK 0xFFFFULL
-#define INFINIPATH_EXTS_GPIOIN_SHIFT 48
-
-/* kr_extctrl bits */
-#define INFINIPATH_EXTC_GPIOINVERT_MASK 0xFFFFULL
-#define INFINIPATH_EXTC_GPIOINVERT_SHIFT 32
-#define INFINIPATH_EXTC_GPIOOE_MASK 0xFFFFULL
-#define INFINIPATH_EXTC_GPIOOE_SHIFT 48
-#define INFINIPATH_EXTC_SERDESENABLE         0x80000000ULL
-#define INFINIPATH_EXTC_SERDESCONNECT        0x40000000ULL
-#define INFINIPATH_EXTC_SERDESENTRUNKING     0x20000000ULL
-#define INFINIPATH_EXTC_SERDESDISRXFIFO      0x10000000ULL
-#define INFINIPATH_EXTC_SERDESENPLPBK1       0x08000000ULL
-#define INFINIPATH_EXTC_SERDESENPLPBK2       0x04000000ULL
-#define INFINIPATH_EXTC_SERDESENENCDEC       0x02000000ULL
-#define INFINIPATH_EXTC_LED1SECPORT_ON       0x00000020ULL
-#define INFINIPATH_EXTC_LED2SECPORT_ON       0x00000010ULL
-#define INFINIPATH_EXTC_LED1PRIPORT_ON       0x00000008ULL
-#define INFINIPATH_EXTC_LED2PRIPORT_ON       0x00000004ULL
-#define INFINIPATH_EXTC_LEDGBLOK_ON          0x00000002ULL
-#define INFINIPATH_EXTC_LEDGBLERR_OFF        0x00000001ULL
-
-/* kr_partitionkey bits */
-#define INFINIPATH_PKEY_SIZE 16
-#define INFINIPATH_PKEY_MASK 0xFFFF
-#define INFINIPATH_PKEY_DEFAULT_PKEY 0xFFFF
-
-/* kr_serdesconfig0 bits */
-#define INFINIPATH_SERDC0_RESET_MASK  0xfULL   /* overal reset bits */
-#define INFINIPATH_SERDC0_RESET_PLL   0x10000000ULL    /* pll reset */
-/* tx idle enables (per lane) */
-#define INFINIPATH_SERDC0_TXIDLE      0xF000ULL
-/* rx detect enables (per lane) */
-#define INFINIPATH_SERDC0_RXDETECT_EN 0xF0000ULL
-/* L1 Power down; use with RXDETECT, Otherwise not used on IB side */
-#define INFINIPATH_SERDC0_L1PWR_DN      0xF0ULL
-
-/* common kr_xgxsconfig bits (or safe in all, even if not implemented) */
-#define INFINIPATH_XGXS_RX_POL_SHIFT 19
-#define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
-
-
-/*
- * IPATH_PIO_MAXIBHDR is the max IB header size allowed for in our
- * PIO send buffers.  This is well beyond anything currently
- * defined in the InfiniBand spec.
- */
-#define IPATH_PIO_MAXIBHDR 128
-
-typedef u64 ipath_err_t;
-
-/* The following change with the type of device, so
- * need to be part of the ipath_devdata struct, or
- * we could have problems plugging in devices of
- * different types (e.g. one HT, one PCIE)
- * in one system, to be managed by one driver.
- * On the other hand, this file is may also be included
- * by other code, so leave the declarations here
- * temporarily. Minor footprint issue if common-model
- * linker used, none if C89+ linker used.
- */
-
-/* mask of defined bits for various registers */
-extern u64 infinipath_i_bitsextant;
-extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
-
-/* masks that are different in various chips, or only exist in some chips */
-extern u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
-
-/*
- * These are the infinipath general register numbers (not offsets).
- * The kernel registers are used directly, those beyond the kernel
- * registers are calculated from one of the base registers.  The use of
- * an integer type doesn't allow type-checking as thorough as, say,
- * an enum but allows for better hiding of chip differences.
- */
-typedef const u16 ipath_kreg,  /* infinipath general registers */
- ipath_creg,                   /* infinipath counter registers */
- ipath_sreg;                   /* kernel-only, infinipath send registers */
-
-/*
- * These are the chip registers common to all infinipath chips, and
- * used both by the kernel and the diagnostics or other user code.
- * They are all implemented such that 64 bit accesses work.
- * Some implement no more than 32 bits.  Because 64 bit reads
- * require 2 HT cmds on opteron, we access those with 32 bit
- * reads for efficiency (they are written as 64 bits, since
- * the extra 32 bits are nearly free on writes, and it slightly reduces
- * complexity).  The rest are all accessed as 64 bits.
- */
-struct ipath_kregs {
-       /* These are the 32 bit group */
-       ipath_kreg kr_control;
-       ipath_kreg kr_counterregbase;
-       ipath_kreg kr_intmask;
-       ipath_kreg kr_intstatus;
-       ipath_kreg kr_pagealign;
-       ipath_kreg kr_portcnt;
-       ipath_kreg kr_rcvtidbase;
-       ipath_kreg kr_rcvtidcnt;
-       ipath_kreg kr_rcvegrbase;
-       ipath_kreg kr_rcvegrcnt;
-       ipath_kreg kr_scratch;
-       ipath_kreg kr_sendctrl;
-       ipath_kreg kr_sendpiobufbase;
-       ipath_kreg kr_sendpiobufcnt;
-       ipath_kreg kr_sendpiosize;
-       ipath_kreg kr_sendregbase;
-       ipath_kreg kr_userregbase;
-       /* These are the 64 bit group */
-       ipath_kreg kr_debugport;
-       ipath_kreg kr_debugportselect;
-       ipath_kreg kr_errorclear;
-       ipath_kreg kr_errormask;
-       ipath_kreg kr_errorstatus;
-       ipath_kreg kr_extctrl;
-       ipath_kreg kr_extstatus;
-       ipath_kreg kr_gpio_clear;
-       ipath_kreg kr_gpio_mask;
-       ipath_kreg kr_gpio_out;
-       ipath_kreg kr_gpio_status;
-       ipath_kreg kr_hwdiagctrl;
-       ipath_kreg kr_hwerrclear;
-       ipath_kreg kr_hwerrmask;
-       ipath_kreg kr_hwerrstatus;
-       ipath_kreg kr_ibcctrl;
-       ipath_kreg kr_ibcstatus;
-       ipath_kreg kr_intblocked;
-       ipath_kreg kr_intclear;
-       ipath_kreg kr_interruptconfig;
-       ipath_kreg kr_mdio;
-       ipath_kreg kr_partitionkey;
-       ipath_kreg kr_rcvbthqp;
-       ipath_kreg kr_rcvbufbase;
-       ipath_kreg kr_rcvbufsize;
-       ipath_kreg kr_rcvctrl;
-       ipath_kreg kr_rcvhdrcnt;
-       ipath_kreg kr_rcvhdrentsize;
-       ipath_kreg kr_rcvhdrsize;
-       ipath_kreg kr_rcvintmembase;
-       ipath_kreg kr_rcvintmemsize;
-       ipath_kreg kr_revision;
-       ipath_kreg kr_sendbuffererror;
-       ipath_kreg kr_sendpioavailaddr;
-       ipath_kreg kr_serdesconfig0;
-       ipath_kreg kr_serdesconfig1;
-       ipath_kreg kr_serdesstatus;
-       ipath_kreg kr_txintmembase;
-       ipath_kreg kr_txintmemsize;
-       ipath_kreg kr_xgxsconfig;
-       ipath_kreg kr_ibpllcfg;
-       /* use these two (and the following N ports) only with
-        * ipath_k*_kreg64_port(); not *kreg64() */
-       ipath_kreg kr_rcvhdraddr;
-       ipath_kreg kr_rcvhdrtailaddr;
-
-       /* remaining registers are not present on all types of infinipath
-          chips  */
-       ipath_kreg kr_rcvpktledcnt;
-       ipath_kreg kr_pcierbuftestreg0;
-       ipath_kreg kr_pcierbuftestreg1;
-       ipath_kreg kr_pcieq0serdesconfig0;
-       ipath_kreg kr_pcieq0serdesconfig1;
-       ipath_kreg kr_pcieq0serdesstatus;
-       ipath_kreg kr_pcieq1serdesconfig0;
-       ipath_kreg kr_pcieq1serdesconfig1;
-       ipath_kreg kr_pcieq1serdesstatus;
-       ipath_kreg kr_hrtbt_guid;
-       ipath_kreg kr_ibcddrctrl;
-       ipath_kreg kr_ibcddrstatus;
-       ipath_kreg kr_jintreload;
-
-       /* send dma related regs */
-       ipath_kreg kr_senddmabase;
-       ipath_kreg kr_senddmalengen;
-       ipath_kreg kr_senddmatail;
-       ipath_kreg kr_senddmahead;
-       ipath_kreg kr_senddmaheadaddr;
-       ipath_kreg kr_senddmabufmask0;
-       ipath_kreg kr_senddmabufmask1;
-       ipath_kreg kr_senddmabufmask2;
-       ipath_kreg kr_senddmastatus;
-
-       /* SerDes related regs (IBA7220-only) */
-       ipath_kreg kr_ibserdesctrl;
-       ipath_kreg kr_ib_epbacc;
-       ipath_kreg kr_ib_epbtrans;
-       ipath_kreg kr_pcie_epbacc;
-       ipath_kreg kr_pcie_epbtrans;
-       ipath_kreg kr_ib_ddsrxeq;
-};
-
-struct ipath_cregs {
-       ipath_creg cr_badformatcnt;
-       ipath_creg cr_erricrccnt;
-       ipath_creg cr_errlinkcnt;
-       ipath_creg cr_errlpcrccnt;
-       ipath_creg cr_errpkey;
-       ipath_creg cr_errrcvflowctrlcnt;
-       ipath_creg cr_err_rlencnt;
-       ipath_creg cr_errslencnt;
-       ipath_creg cr_errtidfull;
-       ipath_creg cr_errtidvalid;
-       ipath_creg cr_errvcrccnt;
-       ipath_creg cr_ibstatuschange;
-       ipath_creg cr_intcnt;
-       ipath_creg cr_invalidrlencnt;
-       ipath_creg cr_invalidslencnt;
-       ipath_creg cr_lbflowstallcnt;
-       ipath_creg cr_iblinkdowncnt;
-       ipath_creg cr_iblinkerrrecovcnt;
-       ipath_creg cr_ibsymbolerrcnt;
-       ipath_creg cr_pktrcvcnt;
-       ipath_creg cr_pktrcvflowctrlcnt;
-       ipath_creg cr_pktsendcnt;
-       ipath_creg cr_pktsendflowcnt;
-       ipath_creg cr_portovflcnt;
-       ipath_creg cr_rcvebpcnt;
-       ipath_creg cr_rcvovflcnt;
-       ipath_creg cr_rxdroppktcnt;
-       ipath_creg cr_senddropped;
-       ipath_creg cr_sendstallcnt;
-       ipath_creg cr_sendunderruncnt;
-       ipath_creg cr_unsupvlcnt;
-       ipath_creg cr_wordrcvcnt;
-       ipath_creg cr_wordsendcnt;
-       ipath_creg cr_vl15droppedpktcnt;
-       ipath_creg cr_rxotherlocalphyerrcnt;
-       ipath_creg cr_excessbufferovflcnt;
-       ipath_creg cr_locallinkintegrityerrcnt;
-       ipath_creg cr_rxvlerrcnt;
-       ipath_creg cr_rxdlidfltrcnt;
-       ipath_creg cr_psstat;
-       ipath_creg cr_psstart;
-       ipath_creg cr_psinterval;
-       ipath_creg cr_psrcvdatacount;
-       ipath_creg cr_psrcvpktscount;
-       ipath_creg cr_psxmitdatacount;
-       ipath_creg cr_psxmitpktscount;
-       ipath_creg cr_psxmitwaitcount;
-};
-
-#endif                         /* _IPATH_REGISTERS_H */
diff --git a/drivers/staging/rdma/ipath/ipath_ruc.c b/drivers/staging/rdma/ipath/ipath_ruc.c
deleted file mode 100644 (file)
index e541a01..0000000
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/spinlock.h>
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-/*
- * Convert the AETH RNR timeout code into the number of milliseconds.
- */
-const u32 ib_ipath_rnr_table[32] = {
-       656,                    /* 0 */
-       1,                      /* 1 */
-       1,                      /* 2 */
-       1,                      /* 3 */
-       1,                      /* 4 */
-       1,                      /* 5 */
-       1,                      /* 6 */
-       1,                      /* 7 */
-       1,                      /* 8 */
-       1,                      /* 9 */
-       1,                      /* A */
-       1,                      /* B */
-       1,                      /* C */
-       1,                      /* D */
-       2,                      /* E */
-       2,                      /* F */
-       3,                      /* 10 */
-       4,                      /* 11 */
-       6,                      /* 12 */
-       8,                      /* 13 */
-       11,                     /* 14 */
-       16,                     /* 15 */
-       21,                     /* 16 */
-       31,                     /* 17 */
-       41,                     /* 18 */
-       62,                     /* 19 */
-       82,                     /* 1A */
-       123,                    /* 1B */
-       164,                    /* 1C */
-       246,                    /* 1D */
-       328,                    /* 1E */
-       492                     /* 1F */
-};
-
-/**
- * ipath_insert_rnr_queue - put QP on the RNR timeout list for the device
- * @qp: the QP
- *
- * Called with the QP s_lock held and interrupts disabled.
- * XXX Use a simple list for now.  We might need a priority
- * queue if we have lots of QPs waiting for RNR timeouts
- * but that should be rare.
- */
-void ipath_insert_rnr_queue(struct ipath_qp *qp)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-
-       /* We already did a spin_lock_irqsave(), so just use spin_lock */
-       spin_lock(&dev->pending_lock);
-       if (list_empty(&dev->rnrwait))
-               list_add(&qp->timerwait, &dev->rnrwait);
-       else {
-               struct list_head *l = &dev->rnrwait;
-               struct ipath_qp *nqp = list_entry(l->next, struct ipath_qp,
-                                                 timerwait);
-
-               while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) {
-                       qp->s_rnr_timeout -= nqp->s_rnr_timeout;
-                       l = l->next;
-                       if (l->next == &dev->rnrwait) {
-                               nqp = NULL;
-                               break;
-                       }
-                       nqp = list_entry(l->next, struct ipath_qp,
-                                        timerwait);
-               }
-               if (nqp)
-                       nqp->s_rnr_timeout -= qp->s_rnr_timeout;
-               list_add(&qp->timerwait, l);
-       }
-       spin_unlock(&dev->pending_lock);
-}
-
-/**
- * ipath_init_sge - Validate a RWQE and fill in the SGE state
- * @qp: the QP
- *
- * Return 1 if OK.
- */
-int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
-                  u32 *lengthp, struct ipath_sge_state *ss)
-{
-       int i, j, ret;
-       struct ib_wc wc;
-
-       *lengthp = 0;
-       for (i = j = 0; i < wqe->num_sge; i++) {
-               if (wqe->sg_list[i].length == 0)
-                       continue;
-               /* Check LKEY */
-               if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
-                                  &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
-                       goto bad_lkey;
-               *lengthp += wqe->sg_list[i].length;
-               j++;
-       }
-       ss->num_sge = j;
-       ret = 1;
-       goto bail;
-
-bad_lkey:
-       memset(&wc, 0, sizeof(wc));
-       wc.wr_id = wqe->wr_id;
-       wc.status = IB_WC_LOC_PROT_ERR;
-       wc.opcode = IB_WC_RECV;
-       wc.qp = &qp->ibqp;
-       /* Signal solicited completion event. */
-       ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
-       ret = 0;
-bail:
-       return ret;
-}
-
-/**
- * ipath_get_rwqe - copy the next RWQE into the QP's RWQE
- * @qp: the QP
- * @wr_id_only: update qp->r_wr_id only, not qp->r_sge
- *
- * Return 0 if no RWQE is available, otherwise return 1.
- *
- * Can be called from interrupt level.
- */
-int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
-{
-       unsigned long flags;
-       struct ipath_rq *rq;
-       struct ipath_rwq *wq;
-       struct ipath_srq *srq;
-       struct ipath_rwqe *wqe;
-       void (*handler)(struct ib_event *, void *);
-       u32 tail;
-       int ret;
-
-       if (qp->ibqp.srq) {
-               srq = to_isrq(qp->ibqp.srq);
-               handler = srq->ibsrq.event_handler;
-               rq = &srq->rq;
-       } else {
-               srq = NULL;
-               handler = NULL;
-               rq = &qp->r_rq;
-       }
-
-       spin_lock_irqsave(&rq->lock, flags);
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
-               ret = 0;
-               goto unlock;
-       }
-
-       wq = rq->wq;
-       tail = wq->tail;
-       /* Validate tail before using it since it is user writable. */
-       if (tail >= rq->size)
-               tail = 0;
-       do {
-               if (unlikely(tail == wq->head)) {
-                       ret = 0;
-                       goto unlock;
-               }
-               /* Make sure entry is read after head index is read. */
-               smp_rmb();
-               wqe = get_rwqe_ptr(rq, tail);
-               if (++tail >= rq->size)
-                       tail = 0;
-               if (wr_id_only)
-                       break;
-               qp->r_sge.sg_list = qp->r_sg_list;
-       } while (!ipath_init_sge(qp, wqe, &qp->r_len, &qp->r_sge));
-       qp->r_wr_id = wqe->wr_id;
-       wq->tail = tail;
-
-       ret = 1;
-       set_bit(IPATH_R_WRID_VALID, &qp->r_aflags);
-       if (handler) {
-               u32 n;
-
-               /*
-                * validate head pointer value and compute
-                * the number of remaining WQEs.
-                */
-               n = wq->head;
-               if (n >= rq->size)
-                       n = 0;
-               if (n < tail)
-                       n += rq->size - tail;
-               else
-                       n -= tail;
-               if (n < srq->limit) {
-                       struct ib_event ev;
-
-                       srq->limit = 0;
-                       spin_unlock_irqrestore(&rq->lock, flags);
-                       ev.device = qp->ibqp.device;
-                       ev.element.srq = qp->ibqp.srq;
-                       ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
-                       handler(&ev, srq->ibsrq.srq_context);
-                       goto bail;
-               }
-       }
-unlock:
-       spin_unlock_irqrestore(&rq->lock, flags);
-bail:
-       return ret;
-}
-
-/**
- * ipath_ruc_loopback - handle UC and RC lookback requests
- * @sqp: the sending QP
- *
- * This is called from ipath_do_send() to
- * forward a WQE addressed to the same HCA.
- * Note that although we are single threaded due to the tasklet, we still
- * have to protect against post_send().  We don't have to worry about
- * receive interrupts since this is a connected protocol and all packets
- * will pass through here.
- */
-static void ipath_ruc_loopback(struct ipath_qp *sqp)
-{
-       struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
-       struct ipath_qp *qp;
-       struct ipath_swqe *wqe;
-       struct ipath_sge *sge;
-       unsigned long flags;
-       struct ib_wc wc;
-       u64 sdata;
-       atomic64_t *maddr;
-       enum ib_wc_status send_status;
-
-       /*
-        * Note that we check the responder QP state after
-        * checking the requester's state.
-        */
-       qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn);
-
-       spin_lock_irqsave(&sqp->s_lock, flags);
-
-       /* Return if we are already busy processing a work request. */
-       if ((sqp->s_flags & (IPATH_S_BUSY | IPATH_S_ANY_WAIT)) ||
-           !(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_OR_FLUSH_SEND))
-               goto unlock;
-
-       sqp->s_flags |= IPATH_S_BUSY;
-
-again:
-       if (sqp->s_last == sqp->s_head)
-               goto clr_busy;
-       wqe = get_swqe_ptr(sqp, sqp->s_last);
-
-       /* Return if it is not OK to start a new work reqeust. */
-       if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_NEXT_SEND_OK)) {
-               if (!(ib_ipath_state_ops[sqp->state] & IPATH_FLUSH_SEND))
-                       goto clr_busy;
-               /* We are in the error state, flush the work request. */
-               send_status = IB_WC_WR_FLUSH_ERR;
-               goto flush_send;
-       }
-
-       /*
-        * We can rely on the entry not changing without the s_lock
-        * being held until we update s_last.
-        * We increment s_cur to indicate s_last is in progress.
-        */
-       if (sqp->s_last == sqp->s_cur) {
-               if (++sqp->s_cur >= sqp->s_size)
-                       sqp->s_cur = 0;
-       }
-       spin_unlock_irqrestore(&sqp->s_lock, flags);
-
-       if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
-               dev->n_pkt_drops++;
-               /*
-                * For RC, the requester would timeout and retry so
-                * shortcut the timeouts and just signal too many retries.
-                */
-               if (sqp->ibqp.qp_type == IB_QPT_RC)
-                       send_status = IB_WC_RETRY_EXC_ERR;
-               else
-                       send_status = IB_WC_SUCCESS;
-               goto serr;
-       }
-
-       memset(&wc, 0, sizeof wc);
-       send_status = IB_WC_SUCCESS;
-
-       sqp->s_sge.sge = wqe->sg_list[0];
-       sqp->s_sge.sg_list = wqe->sg_list + 1;
-       sqp->s_sge.num_sge = wqe->wr.num_sge;
-       sqp->s_len = wqe->length;
-       switch (wqe->wr.opcode) {
-       case IB_WR_SEND_WITH_IMM:
-               wc.wc_flags = IB_WC_WITH_IMM;
-               wc.ex.imm_data = wqe->wr.ex.imm_data;
-               /* FALLTHROUGH */
-       case IB_WR_SEND:
-               if (!ipath_get_rwqe(qp, 0))
-                       goto rnr_nak;
-               break;
-
-       case IB_WR_RDMA_WRITE_WITH_IMM:
-               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
-                       goto inv_err;
-               wc.wc_flags = IB_WC_WITH_IMM;
-               wc.ex.imm_data = wqe->wr.ex.imm_data;
-               if (!ipath_get_rwqe(qp, 1))
-                       goto rnr_nak;
-               /* FALLTHROUGH */
-       case IB_WR_RDMA_WRITE:
-               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE)))
-                       goto inv_err;
-               if (wqe->length == 0)
-                       break;
-               if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
-                                           wqe->rdma_wr.remote_addr,
-                                           wqe->rdma_wr.rkey,
-                                           IB_ACCESS_REMOTE_WRITE)))
-                       goto acc_err;
-               break;
-
-       case IB_WR_RDMA_READ:
-               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
-                       goto inv_err;
-               if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
-                                           wqe->rdma_wr.remote_addr,
-                                           wqe->rdma_wr.rkey,
-                                           IB_ACCESS_REMOTE_READ)))
-                       goto acc_err;
-               qp->r_sge.sge = wqe->sg_list[0];
-               qp->r_sge.sg_list = wqe->sg_list + 1;
-               qp->r_sge.num_sge = wqe->wr.num_sge;
-               break;
-
-       case IB_WR_ATOMIC_CMP_AND_SWP:
-       case IB_WR_ATOMIC_FETCH_AND_ADD:
-               if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC)))
-                       goto inv_err;
-               if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
-                                           wqe->atomic_wr.remote_addr,
-                                           wqe->atomic_wr.rkey,
-                                           IB_ACCESS_REMOTE_ATOMIC)))
-                       goto acc_err;
-               /* Perform atomic OP and save result. */
-               maddr = (atomic64_t *) qp->r_sge.sge.vaddr;
-               sdata = wqe->atomic_wr.compare_add;
-               *(u64 *) sqp->s_sge.sge.vaddr =
-                       (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ?
-                       (u64) atomic64_add_return(sdata, maddr) - sdata :
-                       (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr,
-                                     sdata, wqe->atomic_wr.swap);
-               goto send_comp;
-
-       default:
-               send_status = IB_WC_LOC_QP_OP_ERR;
-               goto serr;
-       }
-
-       sge = &sqp->s_sge.sge;
-       while (sqp->s_len) {
-               u32 len = sqp->s_len;
-
-               if (len > sge->length)
-                       len = sge->length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               ipath_copy_sge(&qp->r_sge, sge->vaddr, len);
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--sqp->s_sge.num_sge)
-                               *sge = *sqp->s_sge.sg_list++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-               sqp->s_len -= len;
-       }
-
-       if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
-               goto send_comp;
-
-       if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
-               wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
-       else
-               wc.opcode = IB_WC_RECV;
-       wc.wr_id = qp->r_wr_id;
-       wc.status = IB_WC_SUCCESS;
-       wc.byte_len = wqe->length;
-       wc.qp = &qp->ibqp;
-       wc.src_qp = qp->remote_qpn;
-       wc.slid = qp->remote_ah_attr.dlid;
-       wc.sl = qp->remote_ah_attr.sl;
-       wc.port_num = 1;
-       /* Signal completion event if the solicited bit is set. */
-       ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                      wqe->wr.send_flags & IB_SEND_SOLICITED);
-
-send_comp:
-       spin_lock_irqsave(&sqp->s_lock, flags);
-flush_send:
-       sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
-       ipath_send_complete(sqp, wqe, send_status);
-       goto again;
-
-rnr_nak:
-       /* Handle RNR NAK */
-       if (qp->ibqp.qp_type == IB_QPT_UC)
-               goto send_comp;
-       /*
-        * Note: we don't need the s_lock held since the BUSY flag
-        * makes this single threaded.
-        */
-       if (sqp->s_rnr_retry == 0) {
-               send_status = IB_WC_RNR_RETRY_EXC_ERR;
-               goto serr;
-       }
-       if (sqp->s_rnr_retry_cnt < 7)
-               sqp->s_rnr_retry--;
-       spin_lock_irqsave(&sqp->s_lock, flags);
-       if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_RECV_OK))
-               goto clr_busy;
-       sqp->s_flags |= IPATH_S_WAITING;
-       dev->n_rnr_naks++;
-       sqp->s_rnr_timeout = ib_ipath_rnr_table[qp->r_min_rnr_timer];
-       ipath_insert_rnr_queue(sqp);
-       goto clr_busy;
-
-inv_err:
-       send_status = IB_WC_REM_INV_REQ_ERR;
-       wc.status = IB_WC_LOC_QP_OP_ERR;
-       goto err;
-
-acc_err:
-       send_status = IB_WC_REM_ACCESS_ERR;
-       wc.status = IB_WC_LOC_PROT_ERR;
-err:
-       /* responder goes to error state */
-       ipath_rc_error(qp, wc.status);
-
-serr:
-       spin_lock_irqsave(&sqp->s_lock, flags);
-       ipath_send_complete(sqp, wqe, send_status);
-       if (sqp->ibqp.qp_type == IB_QPT_RC) {
-               int lastwqe = ipath_error_qp(sqp, IB_WC_WR_FLUSH_ERR);
-
-               sqp->s_flags &= ~IPATH_S_BUSY;
-               spin_unlock_irqrestore(&sqp->s_lock, flags);
-               if (lastwqe) {
-                       struct ib_event ev;
-
-                       ev.device = sqp->ibqp.device;
-                       ev.element.qp = &sqp->ibqp;
-                       ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
-                       sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context);
-               }
-               goto done;
-       }
-clr_busy:
-       sqp->s_flags &= ~IPATH_S_BUSY;
-unlock:
-       spin_unlock_irqrestore(&sqp->s_lock, flags);
-done:
-       if (qp && atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-}
-
-static void want_buffer(struct ipath_devdata *dd, struct ipath_qp *qp)
-{
-       if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA) ||
-           qp->ibqp.qp_type == IB_QPT_SMI) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                dd->ipath_sendctrl);
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-       }
-}
-
-/**
- * ipath_no_bufs_available - tell the layer driver we need buffers
- * @qp: the QP that caused the problem
- * @dev: the device we ran out of buffers on
- *
- * Called when we run out of PIO buffers.
- * If we are now in the error state, return zero to flush the
- * send work request.
- */
-static int ipath_no_bufs_available(struct ipath_qp *qp,
-                                   struct ipath_ibdev *dev)
-{
-       unsigned long flags;
-       int ret = 1;
-
-       /*
-        * Note that as soon as want_buffer() is called and
-        * possibly before it returns, ipath_ib_piobufavail()
-        * could be called. Therefore, put QP on the piowait list before
-        * enabling the PIO avail interrupt.
-        */
-       spin_lock_irqsave(&qp->s_lock, flags);
-       if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) {
-               dev->n_piowait++;
-               qp->s_flags |= IPATH_S_WAITING;
-               qp->s_flags &= ~IPATH_S_BUSY;
-               spin_lock(&dev->pending_lock);
-               if (list_empty(&qp->piowait))
-                       list_add_tail(&qp->piowait, &dev->piowait);
-               spin_unlock(&dev->pending_lock);
-       } else
-               ret = 0;
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-       if (ret)
-               want_buffer(dev->dd, qp);
-       return ret;
-}
-
-/**
- * ipath_make_grh - construct a GRH header
- * @dev: a pointer to the ipath device
- * @hdr: a pointer to the GRH header being constructed
- * @grh: the global route address to send to
- * @hwords: the number of 32 bit words of header being sent
- * @nwords: the number of 32 bit words of data being sent
- *
- * Return the size of the header in 32 bit words.
- */
-u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
-                  struct ib_global_route *grh, u32 hwords, u32 nwords)
-{
-       hdr->version_tclass_flow =
-               cpu_to_be32((6 << 28) |
-                           (grh->traffic_class << 20) |
-                           grh->flow_label);
-       hdr->paylen = cpu_to_be16((hwords - 2 + nwords + SIZE_OF_CRC) << 2);
-       /* next_hdr is defined by C8-7 in ch. 8.4.1 */
-       hdr->next_hdr = 0x1B;
-       hdr->hop_limit = grh->hop_limit;
-       /* The SGID is 32-bit aligned. */
-       hdr->sgid.global.subnet_prefix = dev->gid_prefix;
-       hdr->sgid.global.interface_id = dev->dd->ipath_guid;
-       hdr->dgid = grh->dgid;
-
-       /* GRH header size in 32-bit words. */
-       return sizeof(struct ib_grh) / sizeof(u32);
-}
-
-void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
-                          struct ipath_other_headers *ohdr,
-                          u32 bth0, u32 bth2)
-{
-       u16 lrh0;
-       u32 nwords;
-       u32 extra_bytes;
-
-       /* Construct the header. */
-       extra_bytes = -qp->s_cur_size & 3;
-       nwords = (qp->s_cur_size + extra_bytes) >> 2;
-       lrh0 = IPATH_LRH_BTH;
-       if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
-               qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
-                                                &qp->remote_ah_attr.grh,
-                                                qp->s_hdrwords, nwords);
-               lrh0 = IPATH_LRH_GRH;
-       }
-       lrh0 |= qp->remote_ah_attr.sl << 4;
-       qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
-       qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
-       qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
-       qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid |
-                                      qp->remote_ah_attr.src_path_bits);
-       bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
-       bth0 |= extra_bytes << 20;
-       ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
-       ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
-       ohdr->bth[2] = cpu_to_be32(bth2);
-}
-
-/**
- * ipath_do_send - perform a send on a QP
- * @data: contains a pointer to the QP
- *
- * Process entries in the send work queue until credit or queue is
- * exhausted.  Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, two threads could send packets out of order.
- */
-void ipath_do_send(unsigned long data)
-{
-       struct ipath_qp *qp = (struct ipath_qp *)data;
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       int (*make_req)(struct ipath_qp *qp);
-       unsigned long flags;
-
-       if ((qp->ibqp.qp_type == IB_QPT_RC ||
-            qp->ibqp.qp_type == IB_QPT_UC) &&
-           qp->remote_ah_attr.dlid == dev->dd->ipath_lid) {
-               ipath_ruc_loopback(qp);
-               goto bail;
-       }
-
-       if (qp->ibqp.qp_type == IB_QPT_RC)
-              make_req = ipath_make_rc_req;
-       else if (qp->ibqp.qp_type == IB_QPT_UC)
-              make_req = ipath_make_uc_req;
-       else
-              make_req = ipath_make_ud_req;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       /* Return if we are already busy processing a work request. */
-       if ((qp->s_flags & (IPATH_S_BUSY | IPATH_S_ANY_WAIT)) ||
-           !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_OR_FLUSH_SEND)) {
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-               goto bail;
-       }
-
-       qp->s_flags |= IPATH_S_BUSY;
-
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-
-again:
-       /* Check for a constructed packet to be sent. */
-       if (qp->s_hdrwords != 0) {
-               /*
-                * If no PIO bufs are available, return.  An interrupt will
-                * call ipath_ib_piobufavail() when one is available.
-                */
-               if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
-                                    qp->s_cur_sge, qp->s_cur_size)) {
-                       if (ipath_no_bufs_available(qp, dev))
-                               goto bail;
-               }
-               dev->n_unicast_xmit++;
-               /* Record that we sent the packet and s_hdr is empty. */
-               qp->s_hdrwords = 0;
-       }
-
-       if (make_req(qp))
-               goto again;
-
-bail:;
-}
-
-/*
- * This should be called with s_lock held.
- */
-void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
-                        enum ib_wc_status status)
-{
-       u32 old_last, last;
-
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_OR_FLUSH_SEND))
-               return;
-
-       /* See ch. 11.2.4.1 and 10.7.3.1 */
-       if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
-           (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
-           status != IB_WC_SUCCESS) {
-               struct ib_wc wc;
-
-               memset(&wc, 0, sizeof wc);
-               wc.wr_id = wqe->wr.wr_id;
-               wc.status = status;
-               wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
-               wc.qp = &qp->ibqp;
-               if (status == IB_WC_SUCCESS)
-                       wc.byte_len = wqe->length;
-               ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc,
-                              status != IB_WC_SUCCESS);
-       }
-
-       old_last = last = qp->s_last;
-       if (++last >= qp->s_size)
-               last = 0;
-       qp->s_last = last;
-       if (qp->s_cur == old_last)
-               qp->s_cur = last;
-       if (qp->s_tail == old_last)
-               qp->s_tail = last;
-       if (qp->state == IB_QPS_SQD && last == qp->s_cur)
-               qp->s_draining = 0;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_sdma.c b/drivers/staging/rdma/ipath/ipath_sdma.c
deleted file mode 100644 (file)
index 1ffc06a..0000000
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/spinlock.h>
-#include <linux/gfp.h>
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-#define SDMA_DESCQ_SZ PAGE_SIZE /* 256 entries per 4KB page */
-
-static void vl15_watchdog_enq(struct ipath_devdata *dd)
-{
-       /* ipath_sdma_lock must already be held */
-       if (atomic_inc_return(&dd->ipath_sdma_vl15_count) == 1) {
-               unsigned long interval = (HZ + 19) / 20;
-               dd->ipath_sdma_vl15_timer.expires = jiffies + interval;
-               add_timer(&dd->ipath_sdma_vl15_timer);
-       }
-}
-
-static void vl15_watchdog_deq(struct ipath_devdata *dd)
-{
-       /* ipath_sdma_lock must already be held */
-       if (atomic_dec_return(&dd->ipath_sdma_vl15_count) != 0) {
-               unsigned long interval = (HZ + 19) / 20;
-               mod_timer(&dd->ipath_sdma_vl15_timer, jiffies + interval);
-       } else {
-               del_timer(&dd->ipath_sdma_vl15_timer);
-       }
-}
-
-static void vl15_watchdog_timeout(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
-
-       if (atomic_read(&dd->ipath_sdma_vl15_count) != 0) {
-               ipath_dbg("vl15 watchdog timeout - clearing\n");
-               ipath_cancel_sends(dd, 1);
-               ipath_hol_down(dd);
-       } else {
-               ipath_dbg("vl15 watchdog timeout - "
-                         "condition already cleared\n");
-       }
-}
-
-static void unmap_desc(struct ipath_devdata *dd, unsigned head)
-{
-       __le64 *descqp = &dd->ipath_sdma_descq[head].qw[0];
-       u64 desc[2];
-       dma_addr_t addr;
-       size_t len;
-
-       desc[0] = le64_to_cpu(descqp[0]);
-       desc[1] = le64_to_cpu(descqp[1]);
-
-       addr = (desc[1] << 32) | (desc[0] >> 32);
-       len = (desc[0] >> 14) & (0x7ffULL << 2);
-       dma_unmap_single(&dd->pcidev->dev, addr, len, DMA_TO_DEVICE);
-}
-
-/*
- * ipath_sdma_lock should be locked before calling this.
- */
-int ipath_sdma_make_progress(struct ipath_devdata *dd)
-{
-       struct list_head *lp = NULL;
-       struct ipath_sdma_txreq *txp = NULL;
-       u16 dmahead;
-       u16 start_idx = 0;
-       int progress = 0;
-
-       if (!list_empty(&dd->ipath_sdma_activelist)) {
-               lp = dd->ipath_sdma_activelist.next;
-               txp = list_entry(lp, struct ipath_sdma_txreq, list);
-               start_idx = txp->start_idx;
-       }
-
-       /*
-        * Read the SDMA head register in order to know that the
-        * interrupt clear has been written to the chip.
-        * Otherwise, we may not get an interrupt for the last
-        * descriptor in the queue.
-        */
-       dmahead = (u16)ipath_read_kreg32(dd, dd->ipath_kregs->kr_senddmahead);
-       /* sanity check return value for error handling (chip reset, etc.) */
-       if (dmahead >= dd->ipath_sdma_descq_cnt)
-               goto done;
-
-       while (dd->ipath_sdma_descq_head != dmahead) {
-               if (txp && txp->flags & IPATH_SDMA_TXREQ_F_FREEDESC &&
-                   dd->ipath_sdma_descq_head == start_idx) {
-                       unmap_desc(dd, dd->ipath_sdma_descq_head);
-                       start_idx++;
-                       if (start_idx == dd->ipath_sdma_descq_cnt)
-                               start_idx = 0;
-               }
-
-               /* increment free count and head */
-               dd->ipath_sdma_descq_removed++;
-               if (++dd->ipath_sdma_descq_head == dd->ipath_sdma_descq_cnt)
-                       dd->ipath_sdma_descq_head = 0;
-
-               if (txp && txp->next_descq_idx == dd->ipath_sdma_descq_head) {
-                       /* move to notify list */
-                       if (txp->flags & IPATH_SDMA_TXREQ_F_VL15)
-                               vl15_watchdog_deq(dd);
-                       list_move_tail(lp, &dd->ipath_sdma_notifylist);
-                       if (!list_empty(&dd->ipath_sdma_activelist)) {
-                               lp = dd->ipath_sdma_activelist.next;
-                               txp = list_entry(lp, struct ipath_sdma_txreq,
-                                                list);
-                               start_idx = txp->start_idx;
-                       } else {
-                               lp = NULL;
-                               txp = NULL;
-                       }
-               }
-               progress = 1;
-       }
-
-       if (progress)
-               tasklet_hi_schedule(&dd->ipath_sdma_notify_task);
-
-done:
-       return progress;
-}
-
-static void ipath_sdma_notify(struct ipath_devdata *dd, struct list_head *list)
-{
-       struct ipath_sdma_txreq *txp, *txp_next;
-
-       list_for_each_entry_safe(txp, txp_next, list, list) {
-               list_del_init(&txp->list);
-
-               if (txp->callback)
-                       (*txp->callback)(txp->callback_cookie,
-                                        txp->callback_status);
-       }
-}
-
-static void sdma_notify_taskbody(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-       struct list_head list;
-
-       INIT_LIST_HEAD(&list);
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-       list_splice_init(&dd->ipath_sdma_notifylist, &list);
-
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       ipath_sdma_notify(dd, &list);
-
-       /*
-        * The IB verbs layer needs to see the callback before getting
-        * the call to ipath_ib_piobufavail() because the callback
-        * handles releasing resources the next send will need.
-        * Otherwise, we could do these calls in
-        * ipath_sdma_make_progress().
-        */
-       ipath_ib_piobufavail(dd->verbs_dev);
-}
-
-static void sdma_notify_task(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
-
-       if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-               sdma_notify_taskbody(dd);
-}
-
-static void dump_sdma_state(struct ipath_devdata *dd)
-{
-       unsigned long reg;
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmastatus);
-       ipath_cdbg(VERBOSE, "kr_senddmastatus: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendctrl);
-       ipath_cdbg(VERBOSE, "kr_sendctrl: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmabufmask0);
-       ipath_cdbg(VERBOSE, "kr_senddmabufmask0: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmabufmask1);
-       ipath_cdbg(VERBOSE, "kr_senddmabufmask1: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmabufmask2);
-       ipath_cdbg(VERBOSE, "kr_senddmabufmask2: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmatail);
-       ipath_cdbg(VERBOSE, "kr_senddmatail: 0x%016lx\n", reg);
-
-       reg = ipath_read_kreg64(dd, dd->ipath_kregs->kr_senddmahead);
-       ipath_cdbg(VERBOSE, "kr_senddmahead: 0x%016lx\n", reg);
-}
-
-static void sdma_abort_task(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
-       u64 status;
-       unsigned long flags;
-
-       if (test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-               return;
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-       status = dd->ipath_sdma_status & IPATH_SDMA_ABORT_MASK;
-
-       /* nothing to do */
-       if (status == IPATH_SDMA_ABORT_NONE)
-               goto unlock;
-
-       /* ipath_sdma_abort() is done, waiting for interrupt */
-       if (status == IPATH_SDMA_ABORT_DISARMED) {
-               if (time_before(jiffies, dd->ipath_sdma_abort_intr_timeout))
-                       goto resched_noprint;
-               /* give up, intr got lost somewhere */
-               ipath_dbg("give up waiting for SDMADISABLED intr\n");
-               __set_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
-               status = IPATH_SDMA_ABORT_ABORTED;
-       }
-
-       /* everything is stopped, time to clean up and restart */
-       if (status == IPATH_SDMA_ABORT_ABORTED) {
-               struct ipath_sdma_txreq *txp, *txpnext;
-               u64 hwstatus;
-               int notify = 0;
-
-               hwstatus = ipath_read_kreg64(dd,
-                               dd->ipath_kregs->kr_senddmastatus);
-
-               if ((hwstatus & (IPATH_SDMA_STATUS_SCORE_BOARD_DRAIN_IN_PROG |
-                                IPATH_SDMA_STATUS_ABORT_IN_PROG             |
-                                IPATH_SDMA_STATUS_INTERNAL_SDMA_ENABLE)) ||
-                   !(hwstatus & IPATH_SDMA_STATUS_SCB_EMPTY)) {
-                       if (dd->ipath_sdma_reset_wait > 0) {
-                               /* not done shutting down sdma */
-                               --dd->ipath_sdma_reset_wait;
-                               goto resched;
-                       }
-                       ipath_cdbg(VERBOSE, "gave up waiting for quiescent "
-                               "status after SDMA reset, continuing\n");
-                       dump_sdma_state(dd);
-               }
-
-               /* dequeue all "sent" requests */
-               list_for_each_entry_safe(txp, txpnext,
-                                        &dd->ipath_sdma_activelist, list) {
-                       txp->callback_status = IPATH_SDMA_TXREQ_S_ABORTED;
-                       if (txp->flags & IPATH_SDMA_TXREQ_F_VL15)
-                               vl15_watchdog_deq(dd);
-                       list_move_tail(&txp->list, &dd->ipath_sdma_notifylist);
-                       notify = 1;
-               }
-               if (notify)
-                       tasklet_hi_schedule(&dd->ipath_sdma_notify_task);
-
-               /* reset our notion of head and tail */
-               dd->ipath_sdma_descq_tail = 0;
-               dd->ipath_sdma_descq_head = 0;
-               dd->ipath_sdma_head_dma[0] = 0;
-               dd->ipath_sdma_generation = 0;
-               dd->ipath_sdma_descq_removed = dd->ipath_sdma_descq_added;
-
-               /* Reset SendDmaLenGen */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmalengen,
-                       (u64) dd->ipath_sdma_descq_cnt | (1ULL << 18));
-
-               /* done with sdma state for a bit */
-               spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-               /*
-                * Don't restart sdma here (with the exception
-                * below). Wait until link is up to ACTIVE.  VL15 MADs
-                * used to bring the link up use PIO, and multiple link
-                * transitions otherwise cause the sdma engine to be
-                * stopped and started multiple times.
-                * The disable is done here, including the shadow,
-                * so the state is kept consistent.
-                * See ipath_restart_sdma() for the actual starting
-                * of sdma.
-                */
-               spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-               dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-                                dd->ipath_sendctrl);
-               ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-               spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-               /* make sure I see next message */
-               dd->ipath_sdma_abort_jiffies = 0;
-
-               /*
-                * Not everything that takes SDMA offline is a link
-                * status change.  If the link was up, restart SDMA.
-                */
-               if (dd->ipath_flags & IPATH_LINKACTIVE)
-                       ipath_restart_sdma(dd);
-
-               goto done;
-       }
-
-resched:
-       /*
-        * for now, keep spinning
-        * JAG - this is bad to just have default be a loop without
-        * state change
-        */
-       if (time_after(jiffies, dd->ipath_sdma_abort_jiffies)) {
-               ipath_dbg("looping with status 0x%08lx\n",
-                         dd->ipath_sdma_status);
-               dd->ipath_sdma_abort_jiffies = jiffies + 5 * HZ;
-       }
-resched_noprint:
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-       if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-               tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
-       return;
-
-unlock:
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-done:
-       return;
-}
-
-/*
- * This is called from interrupt context.
- */
-void ipath_sdma_intr(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-       (void) ipath_sdma_make_progress(dd);
-
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-}
-
-static int alloc_sdma(struct ipath_devdata *dd)
-{
-       int ret = 0;
-
-       /* Allocate memory for SendDMA descriptor FIFO */
-       dd->ipath_sdma_descq = dma_alloc_coherent(&dd->pcidev->dev,
-               SDMA_DESCQ_SZ, &dd->ipath_sdma_descq_phys, GFP_KERNEL);
-
-       if (!dd->ipath_sdma_descq) {
-               ipath_dev_err(dd, "failed to allocate SendDMA descriptor "
-                       "FIFO memory\n");
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       dd->ipath_sdma_descq_cnt =
-               SDMA_DESCQ_SZ / sizeof(struct ipath_sdma_desc);
-
-       /* Allocate memory for DMA of head register to memory */
-       dd->ipath_sdma_head_dma = dma_alloc_coherent(&dd->pcidev->dev,
-               PAGE_SIZE, &dd->ipath_sdma_head_phys, GFP_KERNEL);
-       if (!dd->ipath_sdma_head_dma) {
-               ipath_dev_err(dd, "failed to allocate SendDMA head memory\n");
-               ret = -ENOMEM;
-               goto cleanup_descq;
-       }
-       dd->ipath_sdma_head_dma[0] = 0;
-
-       setup_timer(&dd->ipath_sdma_vl15_timer, vl15_watchdog_timeout,
-                       (unsigned long)dd);
-
-       atomic_set(&dd->ipath_sdma_vl15_count, 0);
-
-       goto done;
-
-cleanup_descq:
-       dma_free_coherent(&dd->pcidev->dev, SDMA_DESCQ_SZ,
-               (void *)dd->ipath_sdma_descq, dd->ipath_sdma_descq_phys);
-       dd->ipath_sdma_descq = NULL;
-       dd->ipath_sdma_descq_phys = 0;
-done:
-       return ret;
-}
-
-int setup_sdma(struct ipath_devdata *dd)
-{
-       int ret = 0;
-       unsigned i, n;
-       u64 tmp64;
-       u64 senddmabufmask[3] = { 0 };
-       unsigned long flags;
-
-       ret = alloc_sdma(dd);
-       if (ret)
-               goto done;
-
-       if (!dd->ipath_sdma_descq) {
-               ipath_dev_err(dd, "SendDMA memory not allocated\n");
-               goto done;
-       }
-
-       /*
-        * Set initial status as if we had been up, then gone down.
-        * This lets initial start on transition to ACTIVE be the
-        * same as restart after link flap.
-        */
-       dd->ipath_sdma_status = IPATH_SDMA_ABORT_ABORTED;
-       dd->ipath_sdma_abort_jiffies = 0;
-       dd->ipath_sdma_generation = 0;
-       dd->ipath_sdma_descq_tail = 0;
-       dd->ipath_sdma_descq_head = 0;
-       dd->ipath_sdma_descq_removed = 0;
-       dd->ipath_sdma_descq_added = 0;
-
-       /* Set SendDmaBase */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabase,
-                        dd->ipath_sdma_descq_phys);
-       /* Set SendDmaLenGen */
-       tmp64 = dd->ipath_sdma_descq_cnt;
-       tmp64 |= 1<<18; /* enable generation checking */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmalengen, tmp64);
-       /* Set SendDmaTail */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmatail,
-                        dd->ipath_sdma_descq_tail);
-       /* Set SendDmaHeadAddr */
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmaheadaddr,
-                        dd->ipath_sdma_head_phys);
-
-       /*
-        * Reserve all the former "kernel" piobufs, using high number range
-        * so we get as many 4K buffers as possible
-        */
-       n = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
-       i = dd->ipath_lastport_piobuf + dd->ipath_pioreserved;
-       ipath_chg_pioavailkernel(dd, i, n - i , 0);
-       for (; i < n; ++i) {
-               unsigned word = i / 64;
-               unsigned bit = i & 63;
-               BUG_ON(word >= 3);
-               senddmabufmask[word] |= 1ULL << bit;
-       }
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask0,
-                        senddmabufmask[0]);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask1,
-                        senddmabufmask[1]);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask2,
-                        senddmabufmask[2]);
-
-       INIT_LIST_HEAD(&dd->ipath_sdma_activelist);
-       INIT_LIST_HEAD(&dd->ipath_sdma_notifylist);
-
-       tasklet_init(&dd->ipath_sdma_notify_task, sdma_notify_task,
-                    (unsigned long) dd);
-       tasklet_init(&dd->ipath_sdma_abort_task, sdma_abort_task,
-                    (unsigned long) dd);
-
-       /*
-        * No use to turn on SDMA here, as link is probably not ACTIVE
-        * Just mark it RUNNING and enable the interrupt, and let the
-        * ipath_restart_sdma() on link transition to ACTIVE actually
-        * enable it.
-        */
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl |= INFINIPATH_S_SDMAINTENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       __set_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-done:
-       return ret;
-}
-
-void teardown_sdma(struct ipath_devdata *dd)
-{
-       struct ipath_sdma_txreq *txp, *txpnext;
-       unsigned long flags;
-       dma_addr_t sdma_head_phys = 0;
-       dma_addr_t sdma_descq_phys = 0;
-       void *sdma_descq = NULL;
-       void *sdma_head_dma = NULL;
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-       __clear_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status);
-       __set_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
-       __set_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status);
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       tasklet_kill(&dd->ipath_sdma_abort_task);
-       tasklet_kill(&dd->ipath_sdma_notify_task);
-
-       /* turn off sdma */
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-               dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-       /* dequeue all "sent" requests */
-       list_for_each_entry_safe(txp, txpnext, &dd->ipath_sdma_activelist,
-                                list) {
-               txp->callback_status = IPATH_SDMA_TXREQ_S_SHUTDOWN;
-               if (txp->flags & IPATH_SDMA_TXREQ_F_VL15)
-                       vl15_watchdog_deq(dd);
-               list_move_tail(&txp->list, &dd->ipath_sdma_notifylist);
-       }
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       sdma_notify_taskbody(dd);
-
-       del_timer_sync(&dd->ipath_sdma_vl15_timer);
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-       dd->ipath_sdma_abort_jiffies = 0;
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabase, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmalengen, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmatail, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmaheadaddr, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask0, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask1, 0);
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask2, 0);
-
-       if (dd->ipath_sdma_head_dma) {
-               sdma_head_dma = (void *) dd->ipath_sdma_head_dma;
-               sdma_head_phys = dd->ipath_sdma_head_phys;
-               dd->ipath_sdma_head_dma = NULL;
-               dd->ipath_sdma_head_phys = 0;
-       }
-
-       if (dd->ipath_sdma_descq) {
-               sdma_descq = dd->ipath_sdma_descq;
-               sdma_descq_phys = dd->ipath_sdma_descq_phys;
-               dd->ipath_sdma_descq = NULL;
-               dd->ipath_sdma_descq_phys = 0;
-       }
-
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       if (sdma_head_dma)
-               dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
-                                 sdma_head_dma, sdma_head_phys);
-
-       if (sdma_descq)
-               dma_free_coherent(&dd->pcidev->dev, SDMA_DESCQ_SZ,
-                                 sdma_descq, sdma_descq_phys);
-}
-
-/*
- * [Re]start SDMA, if we use it, and it's not already OK.
- * This is called on transition to link ACTIVE, either the first or
- * subsequent times.
- */
-void ipath_restart_sdma(struct ipath_devdata *dd)
-{
-       unsigned long flags;
-       int needed = 1;
-
-       if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA))
-               goto bail;
-
-       /*
-        * First, make sure we should, which is to say,
-        * check that we are "RUNNING" (not in teardown)
-        * and not "SHUTDOWN"
-        */
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-       if (!test_bit(IPATH_SDMA_RUNNING, &dd->ipath_sdma_status)
-               || test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
-                       needed = 0;
-       else {
-               __clear_bit(IPATH_SDMA_DISABLED, &dd->ipath_sdma_status);
-               __clear_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
-               __clear_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status);
-       }
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-       if (!needed) {
-               ipath_dbg("invalid attempt to restart SDMA, status 0x%08lx\n",
-                       dd->ipath_sdma_status);
-               goto bail;
-       }
-       spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
-       /*
-        * First clear, just to be safe. Enable is only done
-        * in chip on 0->1 transition
-        */
-       dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       dd->ipath_sendctrl |= INFINIPATH_S_SDMAENABLE;
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
-       ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
-       spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
-       /* notify upper layers */
-       ipath_ib_piobufavail(dd->verbs_dev);
-
-bail:
-       return;
-}
-
-static inline void make_sdma_desc(struct ipath_devdata *dd,
-       u64 *sdmadesc, u64 addr, u64 dwlen, u64 dwoffset)
-{
-       WARN_ON(addr & 3);
-       /* SDmaPhyAddr[47:32] */
-       sdmadesc[1] = addr >> 32;
-       /* SDmaPhyAddr[31:0] */
-       sdmadesc[0] = (addr & 0xfffffffcULL) << 32;
-       /* SDmaGeneration[1:0] */
-       sdmadesc[0] |= (dd->ipath_sdma_generation & 3ULL) << 30;
-       /* SDmaDwordCount[10:0] */
-       sdmadesc[0] |= (dwlen & 0x7ffULL) << 16;
-       /* SDmaBufOffset[12:2] */
-       sdmadesc[0] |= dwoffset & 0x7ffULL;
-}
-
-/*
- * This function queues one IB packet onto the send DMA queue per call.
- * The caller is responsible for checking:
- * 1) The number of send DMA descriptor entries is less than the size of
- *    the descriptor queue.
- * 2) The IB SGE addresses and lengths are 32-bit aligned
- *    (except possibly the last SGE's length)
- * 3) The SGE addresses are suitable for passing to dma_map_single().
- */
-int ipath_sdma_verbs_send(struct ipath_devdata *dd,
-       struct ipath_sge_state *ss, u32 dwords,
-       struct ipath_verbs_txreq *tx)
-{
-
-       unsigned long flags;
-       struct ipath_sge *sge;
-       int ret = 0;
-       u16 tail;
-       __le64 *descqp;
-       u64 sdmadesc[2];
-       u32 dwoffset;
-       dma_addr_t addr;
-
-       if ((tx->map_len + (dwords<<2)) > dd->ipath_ibmaxlen) {
-               ipath_dbg("packet size %X > ibmax %X, fail\n",
-                       tx->map_len + (dwords<<2), dd->ipath_ibmaxlen);
-               ret = -EMSGSIZE;
-               goto fail;
-       }
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-retry:
-       if (unlikely(test_bit(IPATH_SDMA_ABORTING, &dd->ipath_sdma_status))) {
-               ret = -EBUSY;
-               goto unlock;
-       }
-
-       if (tx->txreq.sg_count > ipath_sdma_descq_freecnt(dd)) {
-               if (ipath_sdma_make_progress(dd))
-                       goto retry;
-               ret = -ENOBUFS;
-               goto unlock;
-       }
-
-       addr = dma_map_single(&dd->pcidev->dev, tx->txreq.map_addr,
-                             tx->map_len, DMA_TO_DEVICE);
-       if (dma_mapping_error(&dd->pcidev->dev, addr))
-               goto ioerr;
-
-       dwoffset = tx->map_len >> 2;
-       make_sdma_desc(dd, sdmadesc, (u64) addr, dwoffset, 0);
-
-       /* SDmaFirstDesc */
-       sdmadesc[0] |= 1ULL << 12;
-       if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_USELARGEBUF)
-               sdmadesc[0] |= 1ULL << 14;      /* SDmaUseLargeBuf */
-
-       /* write to the descq */
-       tail = dd->ipath_sdma_descq_tail;
-       descqp = &dd->ipath_sdma_descq[tail].qw[0];
-       *descqp++ = cpu_to_le64(sdmadesc[0]);
-       *descqp++ = cpu_to_le64(sdmadesc[1]);
-
-       if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEDESC)
-               tx->txreq.start_idx = tail;
-
-       /* increment the tail */
-       if (++tail == dd->ipath_sdma_descq_cnt) {
-               tail = 0;
-               descqp = &dd->ipath_sdma_descq[0].qw[0];
-               ++dd->ipath_sdma_generation;
-       }
-
-       sge = &ss->sge;
-       while (dwords) {
-               u32 dw;
-               u32 len;
-
-               len = dwords << 2;
-               if (len > sge->length)
-                       len = sge->length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               dw = (len + 3) >> 2;
-               addr = dma_map_single(&dd->pcidev->dev, sge->vaddr, dw << 2,
-                                     DMA_TO_DEVICE);
-               if (dma_mapping_error(&dd->pcidev->dev, addr))
-                       goto unmap;
-               make_sdma_desc(dd, sdmadesc, (u64) addr, dw, dwoffset);
-               /* SDmaUseLargeBuf has to be set in every descriptor */
-               if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_USELARGEBUF)
-                       sdmadesc[0] |= 1ULL << 14;
-               /* write to the descq */
-               *descqp++ = cpu_to_le64(sdmadesc[0]);
-               *descqp++ = cpu_to_le64(sdmadesc[1]);
-
-               /* increment the tail */
-               if (++tail == dd->ipath_sdma_descq_cnt) {
-                       tail = 0;
-                       descqp = &dd->ipath_sdma_descq[0].qw[0];
-                       ++dd->ipath_sdma_generation;
-               }
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--ss->num_sge)
-                               *sge = *ss->sg_list++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-
-               dwoffset += dw;
-               dwords -= dw;
-       }
-
-       if (!tail)
-               descqp = &dd->ipath_sdma_descq[dd->ipath_sdma_descq_cnt].qw[0];
-       descqp -= 2;
-       /* SDmaLastDesc */
-       descqp[0] |= cpu_to_le64(1ULL << 11);
-       if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_INTREQ) {
-               /* SDmaIntReq */
-               descqp[0] |= cpu_to_le64(1ULL << 15);
-       }
-
-       /* Commit writes to memory and advance the tail on the chip */
-       wmb();
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmatail, tail);
-
-       tx->txreq.next_descq_idx = tail;
-       tx->txreq.callback_status = IPATH_SDMA_TXREQ_S_OK;
-       dd->ipath_sdma_descq_tail = tail;
-       dd->ipath_sdma_descq_added += tx->txreq.sg_count;
-       list_add_tail(&tx->txreq.list, &dd->ipath_sdma_activelist);
-       if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_VL15)
-               vl15_watchdog_enq(dd);
-       goto unlock;
-
-unmap:
-       while (tail != dd->ipath_sdma_descq_tail) {
-               if (!tail)
-                       tail = dd->ipath_sdma_descq_cnt - 1;
-               else
-                       tail--;
-               unmap_desc(dd, tail);
-       }
-ioerr:
-       ret = -EIO;
-unlock:
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-fail:
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_srq.c b/drivers/staging/rdma/ipath/ipath_srq.c
deleted file mode 100644 (file)
index 2627198..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include "ipath_verbs.h"
-
-/**
- * ipath_post_srq_receive - post a receive on a shared receive queue
- * @ibsrq: the SRQ to post the receive on
- * @wr: the list of work requests to post
- * @bad_wr: the first WR to cause a problem is put here
- *
- * This may be called from interrupt context.
- */
-int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
-                          struct ib_recv_wr **bad_wr)
-{
-       struct ipath_srq *srq = to_isrq(ibsrq);
-       struct ipath_rwq *wq;
-       unsigned long flags;
-       int ret;
-
-       for (; wr; wr = wr->next) {
-               struct ipath_rwqe *wqe;
-               u32 next;
-               int i;
-
-               if ((unsigned) wr->num_sge > srq->rq.max_sge) {
-                       *bad_wr = wr;
-                       ret = -EINVAL;
-                       goto bail;
-               }
-
-               spin_lock_irqsave(&srq->rq.lock, flags);
-               wq = srq->rq.wq;
-               next = wq->head + 1;
-               if (next >= srq->rq.size)
-                       next = 0;
-               if (next == wq->tail) {
-                       spin_unlock_irqrestore(&srq->rq.lock, flags);
-                       *bad_wr = wr;
-                       ret = -ENOMEM;
-                       goto bail;
-               }
-
-               wqe = get_rwqe_ptr(&srq->rq, wq->head);
-               wqe->wr_id = wr->wr_id;
-               wqe->num_sge = wr->num_sge;
-               for (i = 0; i < wr->num_sge; i++)
-                       wqe->sg_list[i] = wr->sg_list[i];
-               /* Make sure queue entry is written before the head index. */
-               smp_wmb();
-               wq->head = next;
-               spin_unlock_irqrestore(&srq->rq.lock, flags);
-       }
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_create_srq - create a shared receive queue
- * @ibpd: the protection domain of the SRQ to create
- * @srq_init_attr: the attributes of the SRQ
- * @udata: data from libipathverbs when creating a user SRQ
- */
-struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
-                               struct ib_srq_init_attr *srq_init_attr,
-                               struct ib_udata *udata)
-{
-       struct ipath_ibdev *dev = to_idev(ibpd->device);
-       struct ipath_srq *srq;
-       u32 sz;
-       struct ib_srq *ret;
-
-       if (srq_init_attr->srq_type != IB_SRQT_BASIC) {
-               ret = ERR_PTR(-ENOSYS);
-               goto done;
-       }
-
-       if (srq_init_attr->attr.max_wr == 0) {
-               ret = ERR_PTR(-EINVAL);
-               goto done;
-       }
-
-       if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) ||
-           (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) {
-               ret = ERR_PTR(-EINVAL);
-               goto done;
-       }
-
-       srq = kmalloc(sizeof(*srq), GFP_KERNEL);
-       if (!srq) {
-               ret = ERR_PTR(-ENOMEM);
-               goto done;
-       }
-
-       /*
-        * Need to use vmalloc() if we want to support large #s of entries.
-        */
-       srq->rq.size = srq_init_attr->attr.max_wr + 1;
-       srq->rq.max_sge = srq_init_attr->attr.max_sge;
-       sz = sizeof(struct ib_sge) * srq->rq.max_sge +
-               sizeof(struct ipath_rwqe);
-       srq->rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + srq->rq.size * sz);
-       if (!srq->rq.wq) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail_srq;
-       }
-
-       /*
-        * Return the address of the RWQ as the offset to mmap.
-        * See ipath_mmap() for details.
-        */
-       if (udata && udata->outlen >= sizeof(__u64)) {
-               int err;
-               u32 s = sizeof(struct ipath_rwq) + srq->rq.size * sz;
-
-               srq->ip =
-                   ipath_create_mmap_info(dev, s,
-                                          ibpd->uobject->context,
-                                          srq->rq.wq);
-               if (!srq->ip) {
-                       ret = ERR_PTR(-ENOMEM);
-                       goto bail_wq;
-               }
-
-               err = ib_copy_to_udata(udata, &srq->ip->offset,
-                                      sizeof(srq->ip->offset));
-               if (err) {
-                       ret = ERR_PTR(err);
-                       goto bail_ip;
-               }
-       } else
-               srq->ip = NULL;
-
-       /*
-        * ib_create_srq() will initialize srq->ibsrq.
-        */
-       spin_lock_init(&srq->rq.lock);
-       srq->rq.wq->head = 0;
-       srq->rq.wq->tail = 0;
-       srq->limit = srq_init_attr->attr.srq_limit;
-
-       spin_lock(&dev->n_srqs_lock);
-       if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
-               spin_unlock(&dev->n_srqs_lock);
-               ret = ERR_PTR(-ENOMEM);
-               goto bail_ip;
-       }
-
-       dev->n_srqs_allocated++;
-       spin_unlock(&dev->n_srqs_lock);
-
-       if (srq->ip) {
-               spin_lock_irq(&dev->pending_lock);
-               list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps);
-               spin_unlock_irq(&dev->pending_lock);
-       }
-
-       ret = &srq->ibsrq;
-       goto done;
-
-bail_ip:
-       kfree(srq->ip);
-bail_wq:
-       vfree(srq->rq.wq);
-bail_srq:
-       kfree(srq);
-done:
-       return ret;
-}
-
-/**
- * ipath_modify_srq - modify a shared receive queue
- * @ibsrq: the SRQ to modify
- * @attr: the new attributes of the SRQ
- * @attr_mask: indicates which attributes to modify
- * @udata: user data for ipathverbs.so
- */
-int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
-                    enum ib_srq_attr_mask attr_mask,
-                    struct ib_udata *udata)
-{
-       struct ipath_srq *srq = to_isrq(ibsrq);
-       struct ipath_rwq *wq;
-       int ret = 0;
-
-       if (attr_mask & IB_SRQ_MAX_WR) {
-               struct ipath_rwq *owq;
-               struct ipath_rwqe *p;
-               u32 sz, size, n, head, tail;
-
-               /* Check that the requested sizes are below the limits. */
-               if ((attr->max_wr > ib_ipath_max_srq_wrs) ||
-                   ((attr_mask & IB_SRQ_LIMIT) ?
-                    attr->srq_limit : srq->limit) > attr->max_wr) {
-                       ret = -EINVAL;
-                       goto bail;
-               }
-
-               sz = sizeof(struct ipath_rwqe) +
-                       srq->rq.max_sge * sizeof(struct ib_sge);
-               size = attr->max_wr + 1;
-               wq = vmalloc_user(sizeof(struct ipath_rwq) + size * sz);
-               if (!wq) {
-                       ret = -ENOMEM;
-                       goto bail;
-               }
-
-               /* Check that we can write the offset to mmap. */
-               if (udata && udata->inlen >= sizeof(__u64)) {
-                       __u64 offset_addr;
-                       __u64 offset = 0;
-
-                       ret = ib_copy_from_udata(&offset_addr, udata,
-                                                sizeof(offset_addr));
-                       if (ret)
-                               goto bail_free;
-                       udata->outbuf =
-                               (void __user *) (unsigned long) offset_addr;
-                       ret = ib_copy_to_udata(udata, &offset,
-                                              sizeof(offset));
-                       if (ret)
-                               goto bail_free;
-               }
-
-               spin_lock_irq(&srq->rq.lock);
-               /*
-                * validate head pointer value and compute
-                * the number of remaining WQEs.
-                */
-               owq = srq->rq.wq;
-               head = owq->head;
-               if (head >= srq->rq.size)
-                       head = 0;
-               tail = owq->tail;
-               if (tail >= srq->rq.size)
-                       tail = 0;
-               n = head;
-               if (n < tail)
-                       n += srq->rq.size - tail;
-               else
-                       n -= tail;
-               if (size <= n) {
-                       ret = -EINVAL;
-                       goto bail_unlock;
-               }
-               n = 0;
-               p = wq->wq;
-               while (tail != head) {
-                       struct ipath_rwqe *wqe;
-                       int i;
-
-                       wqe = get_rwqe_ptr(&srq->rq, tail);
-                       p->wr_id = wqe->wr_id;
-                       p->num_sge = wqe->num_sge;
-                       for (i = 0; i < wqe->num_sge; i++)
-                               p->sg_list[i] = wqe->sg_list[i];
-                       n++;
-                       p = (struct ipath_rwqe *)((char *) p + sz);
-                       if (++tail >= srq->rq.size)
-                               tail = 0;
-               }
-               srq->rq.wq = wq;
-               srq->rq.size = size;
-               wq->head = n;
-               wq->tail = 0;
-               if (attr_mask & IB_SRQ_LIMIT)
-                       srq->limit = attr->srq_limit;
-               spin_unlock_irq(&srq->rq.lock);
-
-               vfree(owq);
-
-               if (srq->ip) {
-                       struct ipath_mmap_info *ip = srq->ip;
-                       struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
-                       u32 s = sizeof(struct ipath_rwq) + size * sz;
-
-                       ipath_update_mmap_info(dev, ip, s, wq);
-
-                       /*
-                        * Return the offset to mmap.
-                        * See ipath_mmap() for details.
-                        */
-                       if (udata && udata->inlen >= sizeof(__u64)) {
-                               ret = ib_copy_to_udata(udata, &ip->offset,
-                                                      sizeof(ip->offset));
-                               if (ret)
-                                       goto bail;
-                       }
-
-                       spin_lock_irq(&dev->pending_lock);
-                       if (list_empty(&ip->pending_mmaps))
-                               list_add(&ip->pending_mmaps,
-                                        &dev->pending_mmaps);
-                       spin_unlock_irq(&dev->pending_lock);
-               }
-       } else if (attr_mask & IB_SRQ_LIMIT) {
-               spin_lock_irq(&srq->rq.lock);
-               if (attr->srq_limit >= srq->rq.size)
-                       ret = -EINVAL;
-               else
-                       srq->limit = attr->srq_limit;
-               spin_unlock_irq(&srq->rq.lock);
-       }
-       goto bail;
-
-bail_unlock:
-       spin_unlock_irq(&srq->rq.lock);
-bail_free:
-       vfree(wq);
-bail:
-       return ret;
-}
-
-int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
-{
-       struct ipath_srq *srq = to_isrq(ibsrq);
-
-       attr->max_wr = srq->rq.size - 1;
-       attr->max_sge = srq->rq.max_sge;
-       attr->srq_limit = srq->limit;
-       return 0;
-}
-
-/**
- * ipath_destroy_srq - destroy a shared receive queue
- * @ibsrq: the SRQ to destroy
- */
-int ipath_destroy_srq(struct ib_srq *ibsrq)
-{
-       struct ipath_srq *srq = to_isrq(ibsrq);
-       struct ipath_ibdev *dev = to_idev(ibsrq->device);
-
-       spin_lock(&dev->n_srqs_lock);
-       dev->n_srqs_allocated--;
-       spin_unlock(&dev->n_srqs_lock);
-       if (srq->ip)
-               kref_put(&srq->ip->ref, ipath_release_mmap_info);
-       else
-               vfree(srq->rq.wq);
-       kfree(srq);
-
-       return 0;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_stats.c b/drivers/staging/rdma/ipath/ipath_stats.c
deleted file mode 100644 (file)
index f63e143..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "ipath_kernel.h"
-
-struct infinipath_stats ipath_stats;
-
-/**
- * ipath_snap_cntr - snapshot a chip counter
- * @dd: the infinipath device
- * @creg: the counter to snapshot
- *
- * called from add_timer and user counter read calls, to deal with
- * counters that wrap in "human time".  The words sent and received, and
- * the packets sent and received are all that we worry about.  For now,
- * at least, we don't worry about error counters, because if they wrap
- * that quickly, we probably don't care.  We may eventually just make this
- * handle all the counters.  word counters can wrap in about 20 seconds
- * of full bandwidth traffic, packet counters in a few hours.
- */
-
-u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
-{
-       u32 val, reg64 = 0;
-       u64 val64;
-       unsigned long t0, t1;
-       u64 ret;
-
-       t0 = jiffies;
-       /* If fast increment counters are only 32 bits, snapshot them,
-        * and maintain them as 64bit values in the driver */
-       if (!(dd->ipath_flags & IPATH_32BITCOUNTERS) &&
-           (creg == dd->ipath_cregs->cr_wordsendcnt ||
-            creg == dd->ipath_cregs->cr_wordrcvcnt ||
-            creg == dd->ipath_cregs->cr_pktsendcnt ||
-            creg == dd->ipath_cregs->cr_pktrcvcnt)) {
-               val64 = ipath_read_creg(dd, creg);
-               val = val64 == ~0ULL ? ~0U : 0;
-               reg64 = 1;
-       } else                  /* val64 just to keep gcc quiet... */
-               val64 = val = ipath_read_creg32(dd, creg);
-       /*
-        * See if a second has passed.  This is just a way to detect things
-        * that are quite broken.  Normally this should take just a few
-        * cycles (the check is for long enough that we don't care if we get
-        * pre-empted.)  An Opteron HT O read timeout is 4 seconds with
-        * normal NB values
-        */
-       t1 = jiffies;
-       if (time_before(t0 + HZ, t1) && val == -1) {
-               ipath_dev_err(dd, "Error!  Read counter 0x%x timed out\n",
-                             creg);
-               ret = 0ULL;
-               goto bail;
-       }
-       if (reg64) {
-               ret = val64;
-               goto bail;
-       }
-
-       if (creg == dd->ipath_cregs->cr_wordsendcnt) {
-               if (val != dd->ipath_lastsword) {
-                       dd->ipath_sword += val - dd->ipath_lastsword;
-                       dd->ipath_lastsword = val;
-               }
-               val64 = dd->ipath_sword;
-       } else if (creg == dd->ipath_cregs->cr_wordrcvcnt) {
-               if (val != dd->ipath_lastrword) {
-                       dd->ipath_rword += val - dd->ipath_lastrword;
-                       dd->ipath_lastrword = val;
-               }
-               val64 = dd->ipath_rword;
-       } else if (creg == dd->ipath_cregs->cr_pktsendcnt) {
-               if (val != dd->ipath_lastspkts) {
-                       dd->ipath_spkts += val - dd->ipath_lastspkts;
-                       dd->ipath_lastspkts = val;
-               }
-               val64 = dd->ipath_spkts;
-       } else if (creg == dd->ipath_cregs->cr_pktrcvcnt) {
-               if (val != dd->ipath_lastrpkts) {
-                       dd->ipath_rpkts += val - dd->ipath_lastrpkts;
-                       dd->ipath_lastrpkts = val;
-               }
-               val64 = dd->ipath_rpkts;
-       } else if (creg == dd->ipath_cregs->cr_ibsymbolerrcnt) {
-               if (dd->ibdeltainprog)
-                       val64 -= val64 - dd->ibsymsnap;
-               val64 -= dd->ibsymdelta;
-       } else if (creg == dd->ipath_cregs->cr_iblinkerrrecovcnt) {
-               if (dd->ibdeltainprog)
-                       val64 -= val64 - dd->iblnkerrsnap;
-               val64 -= dd->iblnkerrdelta;
-       } else
-               val64 = (u64) val;
-
-       ret = val64;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_qcheck - print delta of egrfull/hdrqfull errors for kernel ports
- * @dd: the infinipath device
- *
- * print the delta of egrfull/hdrqfull errors for kernel ports no more than
- * every 5 seconds.  User processes are printed at close, but kernel doesn't
- * close, so...  Separate routine so may call from other places someday, and
- * so function name when printed by _IPATH_INFO is meaningfull
- */
-static void ipath_qcheck(struct ipath_devdata *dd)
-{
-       static u64 last_tot_hdrqfull;
-       struct ipath_portdata *pd = dd->ipath_pd[0];
-       size_t blen = 0;
-       char buf[128];
-       u32 hdrqtail;
-
-       *buf = 0;
-       if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) {
-               blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u",
-                               pd->port_hdrqfull -
-                               dd->ipath_p0_hdrqfull);
-               dd->ipath_p0_hdrqfull = pd->port_hdrqfull;
-       }
-       if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) {
-               blen += snprintf(buf + blen, sizeof buf - blen,
-                                "%srcvegrfull %llu",
-                                blen ? ", " : "",
-                                (unsigned long long)
-                                (ipath_stats.sps_etidfull -
-                                 dd->ipath_last_tidfull));
-               dd->ipath_last_tidfull = ipath_stats.sps_etidfull;
-       }
-
-       /*
-        * this is actually the number of hdrq full interrupts, not actual
-        * events, but at the moment that's mostly what I'm interested in.
-        * Actual count, etc. is in the counters, if needed.  For production
-        * users this won't ordinarily be printed.
-        */
-
-       if ((ipath_debug & (__IPATH_PKTDBG | __IPATH_DBG)) &&
-           ipath_stats.sps_hdrqfull != last_tot_hdrqfull) {
-               blen += snprintf(buf + blen, sizeof buf - blen,
-                                "%shdrqfull %llu (all ports)",
-                                blen ? ", " : "",
-                                (unsigned long long)
-                                (ipath_stats.sps_hdrqfull -
-                                 last_tot_hdrqfull));
-               last_tot_hdrqfull = ipath_stats.sps_hdrqfull;
-       }
-       if (blen)
-               ipath_dbg("%s\n", buf);
-
-       hdrqtail = ipath_get_hdrqtail(pd);
-       if (pd->port_head != hdrqtail) {
-               if (dd->ipath_lastport0rcv_cnt ==
-                   ipath_stats.sps_port0pkts) {
-                       ipath_cdbg(PKT, "missing rcv interrupts? "
-                                  "port0 hd=%x tl=%x; port0pkts %llx; write"
-                                  " hd (w/intr)\n",
-                                  pd->port_head, hdrqtail,
-                                  (unsigned long long)
-                                  ipath_stats.sps_port0pkts);
-                       ipath_write_ureg(dd, ur_rcvhdrhead, hdrqtail |
-                               dd->ipath_rhdrhead_intr_off, pd->port_port);
-               }
-               dd->ipath_lastport0rcv_cnt = ipath_stats.sps_port0pkts;
-       }
-}
-
-static void ipath_chk_errormask(struct ipath_devdata *dd)
-{
-       static u32 fixed;
-       u32 ctrl;
-       unsigned long errormask;
-       unsigned long hwerrs;
-
-       if (!dd->ipath_errormask || !(dd->ipath_flags & IPATH_INITTED))
-               return;
-
-       errormask = ipath_read_kreg64(dd, dd->ipath_kregs->kr_errormask);
-
-       if (errormask == dd->ipath_errormask)
-               return;
-       fixed++;
-
-       hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
-       ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
-
-       ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-               dd->ipath_errormask);
-
-       if ((hwerrs & dd->ipath_hwerrmask) ||
-               (ctrl & INFINIPATH_C_FREEZEMODE)) {
-               /* force re-interrupt of pending events, just in case */
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, 0ULL);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
-               dev_info(&dd->pcidev->dev,
-                       "errormask fixed(%u) %lx -> %lx, ctrl %x hwerr %lx\n",
-                       fixed, errormask, (unsigned long)dd->ipath_errormask,
-                       ctrl, hwerrs);
-       } else
-               ipath_dbg("errormask fixed(%u) %lx -> %lx, no freeze\n",
-                       fixed, errormask,
-                       (unsigned long)dd->ipath_errormask);
-}
-
-
-/**
- * ipath_get_faststats - get word counters from chip before they overflow
- * @opaque - contains a pointer to the infinipath device ipath_devdata
- *
- * called from add_timer
- */
-void ipath_get_faststats(unsigned long opaque)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
-       int i;
-       static unsigned cnt;
-       unsigned long flags;
-       u64 traffic_wds;
-
-       /*
-        * don't access the chip while running diags, or memory diags can
-        * fail
-        */
-       if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_INITTED) ||
-           ipath_diag_inuse)
-               /* but re-arm the timer, for diags case; won't hurt other */
-               goto done;
-
-       /*
-        * We now try to maintain a "active timer", based on traffic
-        * exceeding a threshold, so we need to check the word-counts
-        * even if they are 64-bit.
-        */
-       traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) +
-               ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
-       spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-       traffic_wds -= dd->ipath_traffic_wds;
-       dd->ipath_traffic_wds += traffic_wds;
-       if (traffic_wds  >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
-               atomic_add(5, &dd->ipath_active_time); /* S/B #define */
-       spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
-
-       if (dd->ipath_flags & IPATH_32BITCOUNTERS) {
-               ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
-               ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
-       }
-
-       ipath_qcheck(dd);
-
-       /*
-        * deal with repeat error suppression.  Doesn't really matter if
-        * last error was almost a full interval ago, or just a few usecs
-        * ago; still won't get more than 2 per interval.  We may want
-        * longer intervals for this eventually, could do with mod, counter
-        * or separate timer.  Also see code in ipath_handle_errors() and
-        * ipath_handle_hwerrors().
-        */
-
-       if (dd->ipath_lasterror)
-               dd->ipath_lasterror = 0;
-       if (dd->ipath_lasthwerror)
-               dd->ipath_lasthwerror = 0;
-       if (dd->ipath_maskederrs
-           && time_after(jiffies, dd->ipath_unmasktime)) {
-               char ebuf[256];
-               int iserr;
-               iserr = ipath_decode_err(dd, ebuf, sizeof ebuf,
-                                        dd->ipath_maskederrs);
-               if (dd->ipath_maskederrs &
-                   ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
-                     INFINIPATH_E_PKTERRS))
-                       ipath_dev_err(dd, "Re-enabling masked errors "
-                                     "(%s)\n", ebuf);
-               else {
-                       /*
-                        * rcvegrfull and rcvhdrqfull are "normal", for some
-                        * types of processes (mostly benchmarks) that send
-                        * huge numbers of messages, while not processing
-                        * them.  So only complain about these at debug
-                        * level.
-                        */
-                       if (iserr)
-                               ipath_dbg(
-                                       "Re-enabling queue full errors (%s)\n",
-                                       ebuf);
-                       else
-                               ipath_cdbg(ERRPKT, "Re-enabling packet"
-                                       " problem interrupt (%s)\n", ebuf);
-               }
-
-               /* re-enable masked errors */
-               dd->ipath_errormask |= dd->ipath_maskederrs;
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-                                dd->ipath_errormask);
-               dd->ipath_maskederrs = 0;
-       }
-
-       /* limit qfull messages to ~one per minute per port */
-       if ((++cnt & 0x10)) {
-               for (i = (int) dd->ipath_cfgports; --i >= 0; ) {
-                       struct ipath_portdata *pd = dd->ipath_pd[i];
-
-                       if (pd && pd->port_lastrcvhdrqtail != -1)
-                               pd->port_lastrcvhdrqtail = -1;
-               }
-       }
-
-       ipath_chk_errormask(dd);
-done:
-       mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5);
-}
diff --git a/drivers/staging/rdma/ipath/ipath_sysfs.c b/drivers/staging/rdma/ipath/ipath_sysfs.c
deleted file mode 100644 (file)
index b12b1f6..0000000
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/ctype.h>
-#include <linux/stat.h>
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-/**
- * ipath_parse_ushort - parse an unsigned short value in an arbitrary base
- * @str: the string containing the number
- * @valp: where to put the result
- *
- * returns the number of bytes consumed, or negative value on error
- */
-int ipath_parse_ushort(const char *str, unsigned short *valp)
-{
-       unsigned long val;
-       char *end;
-       int ret;
-
-       if (!isdigit(str[0])) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       val = simple_strtoul(str, &end, 0);
-
-       if (val > 0xffff) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       *valp = val;
-
-       ret = end + 1 - str;
-       if (ret == 0)
-               ret = -EINVAL;
-
-bail:
-       return ret;
-}
-
-static ssize_t show_version(struct device_driver *dev, char *buf)
-{
-       /* The string printed here is already newline-terminated. */
-       return scnprintf(buf, PAGE_SIZE, "%s", ib_ipath_version);
-}
-
-static ssize_t show_num_units(struct device_driver *dev, char *buf)
-{
-       return scnprintf(buf, PAGE_SIZE, "%d\n",
-                        ipath_count_units(NULL, NULL, NULL));
-}
-
-static ssize_t show_status(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       ssize_t ret;
-
-       if (!dd->ipath_statusp) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n",
-                       (unsigned long long) *(dd->ipath_statusp));
-
-bail:
-       return ret;
-}
-
-static const char *ipath_status_str[] = {
-       "Initted",
-       "Disabled",
-       "Admin_Disabled",
-       "", /* This used to be the old "OIB_SMA" status. */
-       "", /* This used to be the old "SMA" status. */
-       "Present",
-       "IB_link_up",
-       "IB_configured",
-       "NoIBcable",
-       "Fatal_Hardware_Error",
-       NULL,
-};
-
-static ssize_t show_status_str(struct device *dev,
-                              struct device_attribute *attr,
-                              char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int i, any;
-       u64 s;
-       ssize_t ret;
-
-       if (!dd->ipath_statusp) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       s = *(dd->ipath_statusp);
-       *buf = '\0';
-       for (any = i = 0; s && ipath_status_str[i]; i++) {
-               if (s & 1) {
-                       if (any && strlcat(buf, " ", PAGE_SIZE) >=
-                           PAGE_SIZE)
-                               /* overflow */
-                               break;
-                       if (strlcat(buf, ipath_status_str[i],
-                                   PAGE_SIZE) >= PAGE_SIZE)
-                               break;
-                       any = 1;
-               }
-               s >>= 1;
-       }
-       if (any)
-               strlcat(buf, "\n", PAGE_SIZE);
-
-       ret = strlen(buf);
-
-bail:
-       return ret;
-}
-
-static ssize_t show_boardversion(struct device *dev,
-                              struct device_attribute *attr,
-                              char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       /* The string printed here is already newline-terminated. */
-       return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion);
-}
-
-static ssize_t show_localbus_info(struct device *dev,
-                              struct device_attribute *attr,
-                              char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       /* The string printed here is already newline-terminated. */
-       return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_lbus_info);
-}
-
-static ssize_t show_lmc(struct device *dev,
-                       struct device_attribute *attr,
-                       char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc);
-}
-
-static ssize_t store_lmc(struct device *dev,
-                        struct device_attribute *attr,
-                        const char *buf,
-                        size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u16 lmc = 0;
-       int ret;
-
-       ret = ipath_parse_ushort(buf, &lmc);
-       if (ret < 0)
-               goto invalid;
-
-       if (lmc > 7) {
-               ret = -EINVAL;
-               goto invalid;
-       }
-
-       ipath_set_lid(dd, dd->ipath_lid, lmc);
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc);
-bail:
-       return ret;
-}
-
-static ssize_t show_lid(struct device *dev,
-                       struct device_attribute *attr,
-                       char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_lid);
-}
-
-static ssize_t store_lid(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u16 lid = 0;
-       int ret;
-
-       ret = ipath_parse_ushort(buf, &lid);
-       if (ret < 0)
-               goto invalid;
-
-       if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) {
-               ret = -EINVAL;
-               goto invalid;
-       }
-
-       ipath_set_lid(dd, lid, dd->ipath_lmc);
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid LID 0x%x\n", lid);
-bail:
-       return ret;
-}
-
-static ssize_t show_mlid(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_mlid);
-}
-
-static ssize_t store_mlid(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u16 mlid;
-       int ret;
-
-       ret = ipath_parse_ushort(buf, &mlid);
-       if (ret < 0 || mlid < IPATH_MULTICAST_LID_BASE)
-               goto invalid;
-
-       dd->ipath_mlid = mlid;
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid MLID\n");
-bail:
-       return ret;
-}
-
-static ssize_t show_guid(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u8 *guid;
-
-       guid = (u8 *) & (dd->ipath_guid);
-
-       return scnprintf(buf, PAGE_SIZE,
-                        "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-                        guid[0], guid[1], guid[2], guid[3],
-                        guid[4], guid[5], guid[6], guid[7]);
-}
-
-static ssize_t store_guid(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       ssize_t ret;
-       unsigned short guid[8];
-       __be64 new_guid;
-       u8 *ng;
-       int i;
-
-       if (sscanf(buf, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
-                  &guid[0], &guid[1], &guid[2], &guid[3],
-                  &guid[4], &guid[5], &guid[6], &guid[7]) != 8)
-               goto invalid;
-
-       ng = (u8 *) &new_guid;
-
-       for (i = 0; i < 8; i++) {
-               if (guid[i] > 0xff)
-                       goto invalid;
-               ng[i] = guid[i];
-       }
-
-       if (new_guid == 0)
-               goto invalid;
-
-       dd->ipath_guid = new_guid;
-       dd->ipath_nguid = 1;
-       if (dd->verbs_dev)
-               dd->verbs_dev->ibdev.node_guid = new_guid;
-
-       ret = strlen(buf);
-       goto bail;
-
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid GUID\n");
-       ret = -EINVAL;
-
-bail:
-       return ret;
-}
-
-static ssize_t show_nguid(struct device *dev,
-                         struct device_attribute *attr,
-                         char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid);
-}
-
-static ssize_t show_nports(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       /* Return the number of user ports available. */
-       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_cfgports - 1);
-}
-
-static ssize_t show_serial(struct device *dev,
-                          struct device_attribute *attr,
-                          char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       buf[sizeof dd->ipath_serial] = '\0';
-       memcpy(buf, dd->ipath_serial, sizeof dd->ipath_serial);
-       strcat(buf, "\n");
-       return strlen(buf);
-}
-
-static ssize_t show_unit(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
-}
-
-static ssize_t show_jint_max_packets(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
-}
-
-static ssize_t store_jint_max_packets(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf,
-                                     size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u16 v = 0;
-       int ret;
-
-       ret = ipath_parse_ushort(buf, &v);
-       if (ret < 0)
-               ipath_dev_err(dd, "invalid jint_max_packets.\n");
-       else
-               dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
-
-       return ret;
-}
-
-static ssize_t show_jint_idle_ticks(struct device *dev,
-                                   struct device_attribute *attr,
-                                   char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
-}
-
-static ssize_t store_jint_idle_ticks(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf,
-                                    size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       u16 v = 0;
-       int ret;
-
-       ret = ipath_parse_ushort(buf, &v);
-       if (ret < 0)
-               ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
-       else
-               dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
-
-       return ret;
-}
-
-#define DEVICE_COUNTER(name, attr) \
-       static ssize_t show_counter_##name(struct device *dev, \
-                                          struct device_attribute *attr, \
-                                          char *buf) \
-       { \
-               struct ipath_devdata *dd = dev_get_drvdata(dev); \
-               return scnprintf(\
-                       buf, PAGE_SIZE, "%llu\n", (unsigned long long) \
-                       ipath_snap_cntr( \
-                               dd, offsetof(struct infinipath_counters, \
-                                            attr) / sizeof(u64)));     \
-       } \
-       static DEVICE_ATTR(name, S_IRUGO, show_counter_##name, NULL);
-
-DEVICE_COUNTER(ib_link_downeds, IBLinkDownedCnt);
-DEVICE_COUNTER(ib_link_err_recoveries, IBLinkErrRecoveryCnt);
-DEVICE_COUNTER(ib_status_changes, IBStatusChangeCnt);
-DEVICE_COUNTER(ib_symbol_errs, IBSymbolErrCnt);
-DEVICE_COUNTER(lb_flow_stalls, LBFlowStallCnt);
-DEVICE_COUNTER(lb_ints, LBIntCnt);
-DEVICE_COUNTER(rx_bad_formats, RxBadFormatCnt);
-DEVICE_COUNTER(rx_buf_ovfls, RxBufOvflCnt);
-DEVICE_COUNTER(rx_data_pkts, RxDataPktCnt);
-DEVICE_COUNTER(rx_dropped_pkts, RxDroppedPktCnt);
-DEVICE_COUNTER(rx_dwords, RxDwordCnt);
-DEVICE_COUNTER(rx_ebps, RxEBPCnt);
-DEVICE_COUNTER(rx_flow_ctrl_errs, RxFlowCtrlErrCnt);
-DEVICE_COUNTER(rx_flow_pkts, RxFlowPktCnt);
-DEVICE_COUNTER(rx_icrc_errs, RxICRCErrCnt);
-DEVICE_COUNTER(rx_len_errs, RxLenErrCnt);
-DEVICE_COUNTER(rx_link_problems, RxLinkProblemCnt);
-DEVICE_COUNTER(rx_lpcrc_errs, RxLPCRCErrCnt);
-DEVICE_COUNTER(rx_max_min_len_errs, RxMaxMinLenErrCnt);
-DEVICE_COUNTER(rx_p0_hdr_egr_ovfls, RxP0HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p1_hdr_egr_ovfls, RxP1HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p2_hdr_egr_ovfls, RxP2HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p3_hdr_egr_ovfls, RxP3HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p4_hdr_egr_ovfls, RxP4HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p5_hdr_egr_ovfls, RxP5HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p6_hdr_egr_ovfls, RxP6HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p7_hdr_egr_ovfls, RxP7HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_p8_hdr_egr_ovfls, RxP8HdrEgrOvflCnt);
-DEVICE_COUNTER(rx_pkey_mismatches, RxPKeyMismatchCnt);
-DEVICE_COUNTER(rx_tid_full_errs, RxTIDFullErrCnt);
-DEVICE_COUNTER(rx_tid_valid_errs, RxTIDValidErrCnt);
-DEVICE_COUNTER(rx_vcrc_errs, RxVCRCErrCnt);
-DEVICE_COUNTER(tx_data_pkts, TxDataPktCnt);
-DEVICE_COUNTER(tx_dropped_pkts, TxDroppedPktCnt);
-DEVICE_COUNTER(tx_dwords, TxDwordCnt);
-DEVICE_COUNTER(tx_flow_pkts, TxFlowPktCnt);
-DEVICE_COUNTER(tx_flow_stalls, TxFlowStallCnt);
-DEVICE_COUNTER(tx_len_errs, TxLenErrCnt);
-DEVICE_COUNTER(tx_max_min_len_errs, TxMaxMinLenErrCnt);
-DEVICE_COUNTER(tx_underruns, TxUnderrunCnt);
-DEVICE_COUNTER(tx_unsup_vl_errs, TxUnsupVLErrCnt);
-
-static struct attribute *dev_counter_attributes[] = {
-       &dev_attr_ib_link_downeds.attr,
-       &dev_attr_ib_link_err_recoveries.attr,
-       &dev_attr_ib_status_changes.attr,
-       &dev_attr_ib_symbol_errs.attr,
-       &dev_attr_lb_flow_stalls.attr,
-       &dev_attr_lb_ints.attr,
-       &dev_attr_rx_bad_formats.attr,
-       &dev_attr_rx_buf_ovfls.attr,
-       &dev_attr_rx_data_pkts.attr,
-       &dev_attr_rx_dropped_pkts.attr,
-       &dev_attr_rx_dwords.attr,
-       &dev_attr_rx_ebps.attr,
-       &dev_attr_rx_flow_ctrl_errs.attr,
-       &dev_attr_rx_flow_pkts.attr,
-       &dev_attr_rx_icrc_errs.attr,
-       &dev_attr_rx_len_errs.attr,
-       &dev_attr_rx_link_problems.attr,
-       &dev_attr_rx_lpcrc_errs.attr,
-       &dev_attr_rx_max_min_len_errs.attr,
-       &dev_attr_rx_p0_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p1_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p2_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p3_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p4_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p5_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p6_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p7_hdr_egr_ovfls.attr,
-       &dev_attr_rx_p8_hdr_egr_ovfls.attr,
-       &dev_attr_rx_pkey_mismatches.attr,
-       &dev_attr_rx_tid_full_errs.attr,
-       &dev_attr_rx_tid_valid_errs.attr,
-       &dev_attr_rx_vcrc_errs.attr,
-       &dev_attr_tx_data_pkts.attr,
-       &dev_attr_tx_dropped_pkts.attr,
-       &dev_attr_tx_dwords.attr,
-       &dev_attr_tx_flow_pkts.attr,
-       &dev_attr_tx_flow_stalls.attr,
-       &dev_attr_tx_len_errs.attr,
-       &dev_attr_tx_max_min_len_errs.attr,
-       &dev_attr_tx_underruns.attr,
-       &dev_attr_tx_unsup_vl_errs.attr,
-       NULL
-};
-
-static struct attribute_group dev_counter_attr_group = {
-       .name = "counters",
-       .attrs = dev_counter_attributes
-};
-
-static ssize_t store_reset(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       if (count < 5 || memcmp(buf, "reset", 5)) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       if (dd->ipath_flags & IPATH_DISABLED) {
-               /*
-                * post-reset init would re-enable interrupts, etc.
-                * so don't allow reset on disabled devices.  Not
-                * perfect error, but about the best choice.
-                */
-               dev_info(dev,"Unit %d is disabled, can't reset\n",
-                        dd->ipath_unit);
-               ret = -EINVAL;
-               goto bail;
-       }
-       ret = ipath_reset_device(dd->ipath_unit);
-bail:
-       return ret<0 ? ret : count;
-}
-
-static ssize_t store_link_state(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 state;
-
-       ret = ipath_parse_ushort(buf, &state);
-       if (ret < 0)
-               goto invalid;
-
-       r = ipath_set_linkstate(dd, state);
-       if (r < 0) {
-               ret = r;
-               goto bail;
-       }
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid link state\n");
-bail:
-       return ret;
-}
-
-static ssize_t show_mtu(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_ibmtu);
-}
-
-static ssize_t store_mtu(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       ssize_t ret;
-       u16 mtu = 0;
-       int r;
-
-       ret = ipath_parse_ushort(buf, &mtu);
-       if (ret < 0)
-               goto invalid;
-
-       r = ipath_set_mtu(dd, mtu);
-       if (r < 0)
-               ret = r;
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid MTU\n");
-bail:
-       return ret;
-}
-
-static ssize_t show_enabled(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       return scnprintf(buf, PAGE_SIZE, "%u\n",
-                        (dd->ipath_flags & IPATH_DISABLED) ? 0 : 1);
-}
-
-static ssize_t store_enabled(struct device *dev,
-                        struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       ssize_t ret;
-       u16 enable = 0;
-
-       ret = ipath_parse_ushort(buf, &enable);
-       if (ret < 0) {
-               ipath_dev_err(dd, "attempt to use non-numeric on enable\n");
-               goto bail;
-       }
-
-       if (enable) {
-               if (!(dd->ipath_flags & IPATH_DISABLED))
-                       goto bail;
-
-               dev_info(dev, "Enabling unit %d\n", dd->ipath_unit);
-               /* same as post-reset */
-               ret = ipath_init_chip(dd, 1);
-               if (ret)
-                       ipath_dev_err(dd, "Failed to enable unit %d\n",
-                                     dd->ipath_unit);
-               else {
-                       dd->ipath_flags &= ~IPATH_DISABLED;
-                       *dd->ipath_statusp &= ~IPATH_STATUS_ADMIN_DISABLED;
-               }
-       } else if (!(dd->ipath_flags & IPATH_DISABLED)) {
-               dev_info(dev, "Disabling unit %d\n", dd->ipath_unit);
-               ipath_shutdown_device(dd);
-               dd->ipath_flags |= IPATH_DISABLED;
-               *dd->ipath_statusp |= IPATH_STATUS_ADMIN_DISABLED;
-       }
-
-bail:
-       return ret;
-}
-
-static ssize_t store_rx_pol_inv(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret < 0)
-               goto invalid;
-
-       r = ipath_set_rx_pol_inv(dd, val);
-       if (r < 0) {
-               ret = r;
-               goto bail;
-       }
-
-       goto bail;
-invalid:
-       ipath_dev_err(dd, "attempt to set invalid Rx Polarity invert\n");
-bail:
-       return ret;
-}
-
-static ssize_t store_led_override(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret > 0)
-               ipath_set_led_override(dd, val);
-       else
-               ipath_dev_err(dd, "attempt to set invalid LED override\n");
-       return ret;
-}
-
-static ssize_t show_logged_errs(struct device *dev,
-                               struct device_attribute *attr,
-                               char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int idx, count;
-
-       /* force consistency with actual EEPROM */
-       if (ipath_update_eeprom_log(dd) != 0)
-               return -ENXIO;
-
-       count = 0;
-       for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
-               count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
-                       dd->ipath_eep_st_errs[idx],
-                       idx == (IPATH_EEP_LOG_CNT - 1) ? '\n' : ' ');
-       }
-
-       return count;
-}
-
-/*
- * New sysfs entries to control various IB config. These all turn into
- * accesses via ipath_f_get/set_ib_cfg.
- *
- * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
- */
-static ssize_t show_hrtbt_enb(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-static ssize_t store_hrtbt_enb(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret >= 0 && val > 3)
-               ret = -EINVAL;
-       if (ret < 0) {
-               ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
-               goto bail;
-       }
-
-       /*
-        * Set the "intentional" heartbeat enable per either of
-        * "Enable" and "Auto", as these are normally set together.
-        * This bit is consulted when leaving loopback mode,
-        * because entering loopback mode overrides it and automatically
-        * disables heartbeat.
-        */
-       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
-       if (r < 0)
-               ret = r;
-       else if (val == IPATH_IB_HRTBT_OFF)
-               dd->ipath_flags |= IPATH_NO_HRTBT;
-       else
-               dd->ipath_flags &= ~IPATH_NO_HRTBT;
-
-bail:
-       return ret;
-}
-
-/*
- * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
- * _not_ the particular encoding of any given chip)
- */
-static ssize_t show_lwid_enb(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-static ssize_t store_lwid_enb(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret >= 0 && (val == 0 || val > 3))
-               ret = -EINVAL;
-       if (ret < 0) {
-               ipath_dev_err(dd,
-                       "attempt to set invalid Link Width (enable)\n");
-               goto bail;
-       }
-
-       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
-       if (r < 0)
-               ret = r;
-
-bail:
-       return ret;
-}
-
-/* Get current link width */
-static ssize_t show_lwid(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-/*
- * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
- */
-static ssize_t show_spd_enb(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-static ssize_t store_spd_enb(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
-               ret = -EINVAL;
-       if (ret < 0) {
-               ipath_dev_err(dd,
-                       "attempt to set invalid Link Speed (enable)\n");
-               goto bail;
-       }
-
-       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
-       if (r < 0)
-               ret = r;
-
-bail:
-       return ret;
-}
-
-/* Get current link speed */
-static ssize_t show_spd(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-/*
- * Get/Set RX polarity-invert enable. 0=no, 1=yes.
- */
-static ssize_t show_rx_polinv_enb(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-static ssize_t store_rx_polinv_enb(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret >= 0 && val > 1) {
-               ipath_dev_err(dd,
-                       "attempt to set invalid Rx Polarity (enable)\n");
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
-       if (r < 0)
-               ret = r;
-
-bail:
-       return ret;
-}
-
-/*
- * Get/Set RX lane-reversal enable. 0=no, 1=yes.
- */
-static ssize_t show_lanerev_enb(struct device *dev,
-                        struct device_attribute *attr,
-                        char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-
-       ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
-       if (ret >= 0)
-               ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
-       return ret;
-}
-
-static ssize_t store_lanerev_enb(struct device *dev,
-                         struct device_attribute *attr,
-                         const char *buf,
-                         size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, r;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret >= 0 && val > 1) {
-               ret = -EINVAL;
-               ipath_dev_err(dd,
-                       "attempt to set invalid Lane reversal (enable)\n");
-               goto bail;
-       }
-
-       r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
-       if (r < 0)
-               ret = r;
-
-bail:
-       return ret;
-}
-
-static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
-static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
-
-static struct attribute *driver_attributes[] = {
-       &driver_attr_num_units.attr,
-       &driver_attr_version.attr,
-       NULL
-};
-
-static struct attribute_group driver_attr_group = {
-       .attrs = driver_attributes
-};
-
-static ssize_t store_tempsense(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf,
-                              size_t count)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret, stat;
-       u16 val;
-
-       ret = ipath_parse_ushort(buf, &val);
-       if (ret <= 0) {
-               ipath_dev_err(dd, "attempt to set invalid tempsense config\n");
-               goto bail;
-       }
-       /* If anything but the highest limit, enable T_CRIT_A "interrupt" */
-       stat = ipath_tempsense_write(dd, 9, (val == 0x7f7f) ? 0x80 : 0);
-       if (stat) {
-               ipath_dev_err(dd, "Unable to set tempsense config\n");
-               ret = -1;
-               goto bail;
-       }
-       stat = ipath_tempsense_write(dd, 0xB, (u8) (val & 0xFF));
-       if (stat) {
-               ipath_dev_err(dd, "Unable to set local Tcrit\n");
-               ret = -1;
-               goto bail;
-       }
-       stat = ipath_tempsense_write(dd, 0xD, (u8) (val >> 8));
-       if (stat) {
-               ipath_dev_err(dd, "Unable to set remote Tcrit\n");
-               ret = -1;
-               goto bail;
-       }
-
-bail:
-       return ret;
-}
-
-/*
- * dump tempsense regs. in decimal, to ease shell-scripts.
- */
-static ssize_t show_tempsense(struct device *dev,
-                             struct device_attribute *attr,
-                             char *buf)
-{
-       struct ipath_devdata *dd = dev_get_drvdata(dev);
-       int ret;
-       int idx;
-       u8 regvals[8];
-
-       ret = -ENXIO;
-       for (idx = 0; idx < 8; ++idx) {
-               if (idx == 6)
-                       continue;
-               ret = ipath_tempsense_read(dd, idx);
-               if (ret < 0)
-                       break;
-               regvals[idx] = ret;
-       }
-       if (idx == 8)
-               ret = scnprintf(buf, PAGE_SIZE, "%d %d %02X %02X %d %d\n",
-                       *(signed char *)(regvals),
-                       *(signed char *)(regvals + 1),
-                       regvals[2], regvals[3],
-                       *(signed char *)(regvals + 5),
-                       *(signed char *)(regvals + 7));
-       return ret;
-}
-
-const struct attribute_group *ipath_driver_attr_groups[] = {
-       &driver_attr_group,
-       NULL,
-};
-
-static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
-static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
-static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
-static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state);
-static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
-static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu);
-static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled);
-static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL);
-static DEVICE_ATTR(nports, S_IRUGO, show_nports, NULL);
-static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset);
-static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
-static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
-static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
-static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
-static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
-static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
-static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
-static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
-static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
-static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
-                  show_jint_max_packets, store_jint_max_packets);
-static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
-                  show_jint_idle_ticks, store_jint_idle_ticks);
-static DEVICE_ATTR(tempsense, S_IWUSR | S_IRUGO,
-                  show_tempsense, store_tempsense);
-
-static struct attribute *dev_attributes[] = {
-       &dev_attr_guid.attr,
-       &dev_attr_lmc.attr,
-       &dev_attr_lid.attr,
-       &dev_attr_link_state.attr,
-       &dev_attr_mlid.attr,
-       &dev_attr_mtu.attr,
-       &dev_attr_nguid.attr,
-       &dev_attr_nports.attr,
-       &dev_attr_serial.attr,
-       &dev_attr_status.attr,
-       &dev_attr_status_str.attr,
-       &dev_attr_boardversion.attr,
-       &dev_attr_unit.attr,
-       &dev_attr_enabled.attr,
-       &dev_attr_rx_pol_inv.attr,
-       &dev_attr_led_override.attr,
-       &dev_attr_logged_errors.attr,
-       &dev_attr_tempsense.attr,
-       &dev_attr_localbus_info.attr,
-       NULL
-};
-
-static struct attribute_group dev_attr_group = {
-       .attrs = dev_attributes
-};
-
-static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
-                  store_hrtbt_enb);
-static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
-                  store_lwid_enb);
-static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
-static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
-                  store_spd_enb);
-static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
-static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
-                  store_rx_polinv_enb);
-static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
-                  store_lanerev_enb);
-
-static struct attribute *dev_ibcfg_attributes[] = {
-       &dev_attr_hrtbt_enable.attr,
-       &dev_attr_link_width_enable.attr,
-       &dev_attr_link_width.attr,
-       &dev_attr_link_speed_enable.attr,
-       &dev_attr_link_speed.attr,
-       &dev_attr_rx_pol_inv_enable.attr,
-       &dev_attr_rx_lane_rev_enable.attr,
-       NULL
-};
-
-static struct attribute_group dev_ibcfg_attr_group = {
-       .attrs = dev_ibcfg_attributes
-};
-
-/**
- * ipath_expose_reset - create a device reset file
- * @dev: the device structure
- *
- * Only expose a file that lets us reset the device after someone
- * enters diag mode.  A device reset is quite likely to crash the
- * machine entirely, so we don't want to normally make it
- * available.
- *
- * Called with ipath_mutex held.
- */
-int ipath_expose_reset(struct device *dev)
-{
-       static int exposed;
-       int ret;
-
-       if (!exposed) {
-               ret = device_create_file(dev, &dev_attr_reset);
-               exposed = 1;
-       } else {
-               ret = 0;
-       }
-
-       return ret;
-}
-
-int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
-{
-       int ret;
-
-       ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
-       if (ret)
-               goto bail;
-
-       ret = sysfs_create_group(&dev->kobj, &dev_counter_attr_group);
-       if (ret)
-               goto bail_attrs;
-
-       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
-               ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
-               if (ret)
-                       goto bail_counter;
-               ret = device_create_file(dev, &dev_attr_jint_max_packets);
-               if (ret)
-                       goto bail_idle;
-
-               ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
-               if (ret)
-                       goto bail_max;
-       }
-
-       return 0;
-
-bail_max:
-       device_remove_file(dev, &dev_attr_jint_max_packets);
-bail_idle:
-       device_remove_file(dev, &dev_attr_jint_idle_ticks);
-bail_counter:
-       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
-bail_attrs:
-       sysfs_remove_group(&dev->kobj, &dev_attr_group);
-bail:
-       return ret;
-}
-
-void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
-{
-       sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
-
-       if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
-               sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
-               device_remove_file(dev, &dev_attr_jint_idle_ticks);
-               device_remove_file(dev, &dev_attr_jint_max_packets);
-       }
-
-       sysfs_remove_group(&dev->kobj, &dev_attr_group);
-
-       device_remove_file(dev, &dev_attr_reset);
-}
diff --git a/drivers/staging/rdma/ipath/ipath_uc.c b/drivers/staging/rdma/ipath/ipath_uc.c
deleted file mode 100644 (file)
index 0246b30..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-/* cut down ridiculously long IB macro names */
-#define OP(x) IB_OPCODE_UC_##x
-
-/**
- * ipath_make_uc_req - construct a request packet (SEND, RDMA write)
- * @qp: a pointer to the QP
- *
- * Return 1 if constructed; otherwise, return 0.
- */
-int ipath_make_uc_req(struct ipath_qp *qp)
-{
-       struct ipath_other_headers *ohdr;
-       struct ipath_swqe *wqe;
-       unsigned long flags;
-       u32 hwords;
-       u32 bth0;
-       u32 len;
-       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
-       int ret = 0;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
-               if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
-                       goto bail;
-               /* We are in the error state, flush the work request. */
-               if (qp->s_last == qp->s_head)
-                       goto bail;
-               /* If DMAs are in progress, we can't flush immediately. */
-               if (atomic_read(&qp->s_dma_busy)) {
-                       qp->s_flags |= IPATH_S_WAIT_DMA;
-                       goto bail;
-               }
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
-               goto done;
-       }
-
-       ohdr = &qp->s_hdr.u.oth;
-       if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
-               ohdr = &qp->s_hdr.u.l.oth;
-
-       /* header size in 32-bit words LRH+BTH = (8+12)/4. */
-       hwords = 5;
-       bth0 = 1 << 22; /* Set M bit */
-
-       /* Get the next send request. */
-       wqe = get_swqe_ptr(qp, qp->s_cur);
-       qp->s_wqe = NULL;
-       switch (qp->s_state) {
-       default:
-               if (!(ib_ipath_state_ops[qp->state] &
-                   IPATH_PROCESS_NEXT_SEND_OK))
-                       goto bail;
-               /* Check if send work queue is empty. */
-               if (qp->s_cur == qp->s_head)
-                       goto bail;
-               /*
-                * Start a new request.
-                */
-               qp->s_psn = wqe->psn = qp->s_next_psn;
-               qp->s_sge.sge = wqe->sg_list[0];
-               qp->s_sge.sg_list = wqe->sg_list + 1;
-               qp->s_sge.num_sge = wqe->wr.num_sge;
-               qp->s_len = len = wqe->length;
-               switch (wqe->wr.opcode) {
-               case IB_WR_SEND:
-               case IB_WR_SEND_WITH_IMM:
-                       if (len > pmtu) {
-                               qp->s_state = OP(SEND_FIRST);
-                               len = pmtu;
-                               break;
-                       }
-                       if (wqe->wr.opcode == IB_WR_SEND)
-                               qp->s_state = OP(SEND_ONLY);
-                       else {
-                               qp->s_state =
-                                       OP(SEND_ONLY_WITH_IMMEDIATE);
-                               /* Immediate data comes after the BTH */
-                               ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                               hwords += 1;
-                       }
-                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                               bth0 |= 1 << 23;
-                       qp->s_wqe = wqe;
-                       if (++qp->s_cur >= qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               case IB_WR_RDMA_WRITE:
-               case IB_WR_RDMA_WRITE_WITH_IMM:
-                       ohdr->u.rc.reth.vaddr =
-                               cpu_to_be64(wqe->rdma_wr.remote_addr);
-                       ohdr->u.rc.reth.rkey =
-                               cpu_to_be32(wqe->rdma_wr.rkey);
-                       ohdr->u.rc.reth.length = cpu_to_be32(len);
-                       hwords += sizeof(struct ib_reth) / 4;
-                       if (len > pmtu) {
-                               qp->s_state = OP(RDMA_WRITE_FIRST);
-                               len = pmtu;
-                               break;
-                       }
-                       if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
-                               qp->s_state = OP(RDMA_WRITE_ONLY);
-                       else {
-                               qp->s_state =
-                                       OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
-                               /* Immediate data comes after the RETH */
-                               ohdr->u.rc.imm_data = wqe->wr.ex.imm_data;
-                               hwords += 1;
-                               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                                       bth0 |= 1 << 23;
-                       }
-                       qp->s_wqe = wqe;
-                       if (++qp->s_cur >= qp->s_size)
-                               qp->s_cur = 0;
-                       break;
-
-               default:
-                       goto bail;
-               }
-               break;
-
-       case OP(SEND_FIRST):
-               qp->s_state = OP(SEND_MIDDLE);
-               /* FALLTHROUGH */
-       case OP(SEND_MIDDLE):
-               len = qp->s_len;
-               if (len > pmtu) {
-                       len = pmtu;
-                       break;
-               }
-               if (wqe->wr.opcode == IB_WR_SEND)
-                       qp->s_state = OP(SEND_LAST);
-               else {
-                       qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE);
-                       /* Immediate data comes after the BTH */
-                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                       hwords += 1;
-               }
-               if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                       bth0 |= 1 << 23;
-               qp->s_wqe = wqe;
-               if (++qp->s_cur >= qp->s_size)
-                       qp->s_cur = 0;
-               break;
-
-       case OP(RDMA_WRITE_FIRST):
-               qp->s_state = OP(RDMA_WRITE_MIDDLE);
-               /* FALLTHROUGH */
-       case OP(RDMA_WRITE_MIDDLE):
-               len = qp->s_len;
-               if (len > pmtu) {
-                       len = pmtu;
-                       break;
-               }
-               if (wqe->wr.opcode == IB_WR_RDMA_WRITE)
-                       qp->s_state = OP(RDMA_WRITE_LAST);
-               else {
-                       qp->s_state =
-                               OP(RDMA_WRITE_LAST_WITH_IMMEDIATE);
-                       /* Immediate data comes after the BTH */
-                       ohdr->u.imm_data = wqe->wr.ex.imm_data;
-                       hwords += 1;
-                       if (wqe->wr.send_flags & IB_SEND_SOLICITED)
-                               bth0 |= 1 << 23;
-               }
-               qp->s_wqe = wqe;
-               if (++qp->s_cur >= qp->s_size)
-                       qp->s_cur = 0;
-               break;
-       }
-       qp->s_len -= len;
-       qp->s_hdrwords = hwords;
-       qp->s_cur_sge = &qp->s_sge;
-       qp->s_cur_size = len;
-       ipath_make_ruc_header(to_idev(qp->ibqp.device),
-                             qp, ohdr, bth0 | (qp->s_state << 24),
-                             qp->s_next_psn++ & IPATH_PSN_MASK);
-done:
-       ret = 1;
-       goto unlock;
-
-bail:
-       qp->s_flags &= ~IPATH_S_BUSY;
-unlock:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-       return ret;
-}
-
-/**
- * ipath_uc_rcv - handle an incoming UC packet
- * @dev: the device the packet came in on
- * @hdr: the header of the packet
- * @has_grh: true if the packet has a GRH
- * @data: the packet data
- * @tlen: the length of the packet
- * @qp: the QP for this packet.
- *
- * This is called from ipath_qp_rcv() to process an incoming UC packet
- * for the given QP.
- * Called at interrupt level.
- */
-void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp)
-{
-       struct ipath_other_headers *ohdr;
-       int opcode;
-       u32 hdrsize;
-       u32 psn;
-       u32 pad;
-       struct ib_wc wc;
-       u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
-       struct ib_reth *reth;
-       int header_in_data;
-
-       /* Validate the SLID. See Ch. 9.6.1.5 */
-       if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
-               goto done;
-
-       /* Check for GRH */
-       if (!has_grh) {
-               ohdr = &hdr->u.oth;
-               hdrsize = 8 + 12;       /* LRH + BTH */
-               psn = be32_to_cpu(ohdr->bth[2]);
-               header_in_data = 0;
-       } else {
-               ohdr = &hdr->u.l.oth;
-               hdrsize = 8 + 40 + 12;  /* LRH + GRH + BTH */
-               /*
-                * The header with GRH is 60 bytes and the
-                * core driver sets the eager header buffer
-                * size to 56 bytes so the last 4 bytes of
-                * the BTH header (PSN) is in the data buffer.
-                */
-               header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
-               if (header_in_data) {
-                       psn = be32_to_cpu(((__be32 *) data)[0]);
-                       data += sizeof(__be32);
-               } else
-                       psn = be32_to_cpu(ohdr->bth[2]);
-       }
-       /*
-        * The opcode is in the low byte when its in network order
-        * (top byte when in host order).
-        */
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
-
-       memset(&wc, 0, sizeof wc);
-
-       /* Compare the PSN verses the expected PSN. */
-       if (unlikely(ipath_cmp24(psn, qp->r_psn) != 0)) {
-               /*
-                * Handle a sequence error.
-                * Silently drop any current message.
-                */
-               qp->r_psn = psn;
-       inv:
-               qp->r_state = OP(SEND_LAST);
-               switch (opcode) {
-               case OP(SEND_FIRST):
-               case OP(SEND_ONLY):
-               case OP(SEND_ONLY_WITH_IMMEDIATE):
-                       goto send_first;
-
-               case OP(RDMA_WRITE_FIRST):
-               case OP(RDMA_WRITE_ONLY):
-               case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
-                       goto rdma_first;
-
-               default:
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-       }
-
-       /* Check for opcode sequence errors. */
-       switch (qp->r_state) {
-       case OP(SEND_FIRST):
-       case OP(SEND_MIDDLE):
-               if (opcode == OP(SEND_MIDDLE) ||
-                   opcode == OP(SEND_LAST) ||
-                   opcode == OP(SEND_LAST_WITH_IMMEDIATE))
-                       break;
-               goto inv;
-
-       case OP(RDMA_WRITE_FIRST):
-       case OP(RDMA_WRITE_MIDDLE):
-               if (opcode == OP(RDMA_WRITE_MIDDLE) ||
-                   opcode == OP(RDMA_WRITE_LAST) ||
-                   opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
-                       break;
-               goto inv;
-
-       default:
-               if (opcode == OP(SEND_FIRST) ||
-                   opcode == OP(SEND_ONLY) ||
-                   opcode == OP(SEND_ONLY_WITH_IMMEDIATE) ||
-                   opcode == OP(RDMA_WRITE_FIRST) ||
-                   opcode == OP(RDMA_WRITE_ONLY) ||
-                   opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
-                       break;
-               goto inv;
-       }
-
-       /* OK, process the packet. */
-       switch (opcode) {
-       case OP(SEND_FIRST):
-       case OP(SEND_ONLY):
-       case OP(SEND_ONLY_WITH_IMMEDIATE):
-       send_first:
-               if (qp->r_flags & IPATH_R_REUSE_SGE) {
-                       qp->r_flags &= ~IPATH_R_REUSE_SGE;
-                       qp->r_sge = qp->s_rdma_read_sge;
-               } else if (!ipath_get_rwqe(qp, 0)) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               /* Save the WQE so we can reuse it in case of an error. */
-               qp->s_rdma_read_sge = qp->r_sge;
-               qp->r_rcv_len = 0;
-               if (opcode == OP(SEND_ONLY))
-                       goto send_last;
-               else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE))
-                       goto send_last_imm;
-               /* FALLTHROUGH */
-       case OP(SEND_MIDDLE):
-               /* Check for invalid length PMTU or posted rwqe len. */
-               if (unlikely(tlen != (hdrsize + pmtu + 4))) {
-                       qp->r_flags |= IPATH_R_REUSE_SGE;
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               qp->r_rcv_len += pmtu;
-               if (unlikely(qp->r_rcv_len > qp->r_len)) {
-                       qp->r_flags |= IPATH_R_REUSE_SGE;
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               ipath_copy_sge(&qp->r_sge, data, pmtu);
-               break;
-
-       case OP(SEND_LAST_WITH_IMMEDIATE):
-       send_last_imm:
-               if (header_in_data) {
-                       wc.ex.imm_data = *(__be32 *) data;
-                       data += sizeof(__be32);
-               } else {
-                       /* Immediate data comes after BTH */
-                       wc.ex.imm_data = ohdr->u.imm_data;
-               }
-               hdrsize += 4;
-               wc.wc_flags = IB_WC_WITH_IMM;
-               /* FALLTHROUGH */
-       case OP(SEND_LAST):
-       send_last:
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /* Check for invalid length. */
-               /* XXX LAST len should be >= 1 */
-               if (unlikely(tlen < (hdrsize + pad + 4))) {
-                       qp->r_flags |= IPATH_R_REUSE_SGE;
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               /* Don't count the CRC. */
-               tlen -= (hdrsize + pad + 4);
-               wc.byte_len = tlen + qp->r_rcv_len;
-               if (unlikely(wc.byte_len > qp->r_len)) {
-                       qp->r_flags |= IPATH_R_REUSE_SGE;
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               wc.opcode = IB_WC_RECV;
-       last_imm:
-               ipath_copy_sge(&qp->r_sge, data, tlen);
-               wc.wr_id = qp->r_wr_id;
-               wc.status = IB_WC_SUCCESS;
-               wc.qp = &qp->ibqp;
-               wc.src_qp = qp->remote_qpn;
-               wc.slid = qp->remote_ah_attr.dlid;
-               wc.sl = qp->remote_ah_attr.sl;
-               /* Signal completion event if the solicited bit is set. */
-               ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                              (ohdr->bth[0] &
-                               cpu_to_be32(1 << 23)) != 0);
-               break;
-
-       case OP(RDMA_WRITE_FIRST):
-       case OP(RDMA_WRITE_ONLY):
-       case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */
-       rdma_first:
-               /* RETH comes after BTH */
-               if (!header_in_data)
-                       reth = &ohdr->u.rc.reth;
-               else {
-                       reth = (struct ib_reth *)data;
-                       data += sizeof(*reth);
-               }
-               hdrsize += sizeof(*reth);
-               qp->r_len = be32_to_cpu(reth->length);
-               qp->r_rcv_len = 0;
-               if (qp->r_len != 0) {
-                       u32 rkey = be32_to_cpu(reth->rkey);
-                       u64 vaddr = be64_to_cpu(reth->vaddr);
-                       int ok;
-
-                       /* Check rkey */
-                       ok = ipath_rkey_ok(qp, &qp->r_sge, qp->r_len,
-                                          vaddr, rkey,
-                                          IB_ACCESS_REMOTE_WRITE);
-                       if (unlikely(!ok)) {
-                               dev->n_pkt_drops++;
-                               goto done;
-                       }
-               } else {
-                       qp->r_sge.sg_list = NULL;
-                       qp->r_sge.sge.mr = NULL;
-                       qp->r_sge.sge.vaddr = NULL;
-                       qp->r_sge.sge.length = 0;
-                       qp->r_sge.sge.sge_length = 0;
-               }
-               if (unlikely(!(qp->qp_access_flags &
-                              IB_ACCESS_REMOTE_WRITE))) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               if (opcode == OP(RDMA_WRITE_ONLY))
-                       goto rdma_last;
-               else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
-                       goto rdma_last_imm;
-               /* FALLTHROUGH */
-       case OP(RDMA_WRITE_MIDDLE):
-               /* Check for invalid length PMTU or posted rwqe len. */
-               if (unlikely(tlen != (hdrsize + pmtu + 4))) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               qp->r_rcv_len += pmtu;
-               if (unlikely(qp->r_rcv_len > qp->r_len)) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               ipath_copy_sge(&qp->r_sge, data, pmtu);
-               break;
-
-       case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
-       rdma_last_imm:
-               if (header_in_data) {
-                       wc.ex.imm_data = *(__be32 *) data;
-                       data += sizeof(__be32);
-               } else {
-                       /* Immediate data comes after BTH */
-                       wc.ex.imm_data = ohdr->u.imm_data;
-               }
-               hdrsize += 4;
-               wc.wc_flags = IB_WC_WITH_IMM;
-
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /* Check for invalid length. */
-               /* XXX LAST len should be >= 1 */
-               if (unlikely(tlen < (hdrsize + pad + 4))) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               /* Don't count the CRC. */
-               tlen -= (hdrsize + pad + 4);
-               if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               if (qp->r_flags & IPATH_R_REUSE_SGE)
-                       qp->r_flags &= ~IPATH_R_REUSE_SGE;
-               else if (!ipath_get_rwqe(qp, 1)) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               wc.byte_len = qp->r_len;
-               wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
-               goto last_imm;
-
-       case OP(RDMA_WRITE_LAST):
-       rdma_last:
-               /* Get the number of bytes the message was padded by. */
-               pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-               /* Check for invalid length. */
-               /* XXX LAST len should be >= 1 */
-               if (unlikely(tlen < (hdrsize + pad + 4))) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               /* Don't count the CRC. */
-               tlen -= (hdrsize + pad + 4);
-               if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) {
-                       dev->n_pkt_drops++;
-                       goto done;
-               }
-               ipath_copy_sge(&qp->r_sge, data, tlen);
-               break;
-
-       default:
-               /* Drop packet for unknown opcodes. */
-               dev->n_pkt_drops++;
-               goto done;
-       }
-       qp->r_psn++;
-       qp->r_state = opcode;
-done:
-       return;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_ud.c b/drivers/staging/rdma/ipath/ipath_ud.c
deleted file mode 100644 (file)
index 385d941..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <rdma/ib_smi.h>
-
-#include "ipath_verbs.h"
-#include "ipath_kernel.h"
-
-/**
- * ipath_ud_loopback - handle send on loopback QPs
- * @sqp: the sending QP
- * @swqe: the send work request
- *
- * This is called from ipath_make_ud_req() to forward a WQE addressed
- * to the same HCA.
- * Note that the receive interrupt handler may be calling ipath_ud_rcv()
- * while this is being called.
- */
-static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
-{
-       struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
-       struct ipath_qp *qp;
-       struct ib_ah_attr *ah_attr;
-       unsigned long flags;
-       struct ipath_rq *rq;
-       struct ipath_srq *srq;
-       struct ipath_sge_state rsge;
-       struct ipath_sge *sge;
-       struct ipath_rwq *wq;
-       struct ipath_rwqe *wqe;
-       void (*handler)(struct ib_event *, void *);
-       struct ib_wc wc;
-       u32 tail;
-       u32 rlen;
-       u32 length;
-
-       qp = ipath_lookup_qpn(&dev->qp_table, swqe->ud_wr.remote_qpn);
-       if (!qp || !(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
-               dev->n_pkt_drops++;
-               goto done;
-       }
-
-       /*
-        * Check that the qkey matches (except for QP0, see 9.6.1.4.1).
-        * Qkeys with the high order bit set mean use the
-        * qkey from the QP context instead of the WR (see 10.2.5).
-        */
-       if (unlikely(qp->ibqp.qp_num &&
-                    ((int) swqe->ud_wr.remote_qkey < 0 ?
-                     sqp->qkey : swqe->ud_wr.remote_qkey) != qp->qkey)) {
-               /* XXX OK to lose a count once in a while. */
-               dev->qkey_violations++;
-               dev->n_pkt_drops++;
-               goto drop;
-       }
-
-       /*
-        * A GRH is expected to precede the data even if not
-        * present on the wire.
-        */
-       length = swqe->length;
-       memset(&wc, 0, sizeof wc);
-       wc.byte_len = length + sizeof(struct ib_grh);
-
-       if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
-               wc.wc_flags = IB_WC_WITH_IMM;
-               wc.ex.imm_data = swqe->wr.ex.imm_data;
-       }
-
-       /*
-        * This would be a lot simpler if we could call ipath_get_rwqe()
-        * but that uses state that the receive interrupt handler uses
-        * so we would need to lock out receive interrupts while doing
-        * local loopback.
-        */
-       if (qp->ibqp.srq) {
-               srq = to_isrq(qp->ibqp.srq);
-               handler = srq->ibsrq.event_handler;
-               rq = &srq->rq;
-       } else {
-               srq = NULL;
-               handler = NULL;
-               rq = &qp->r_rq;
-       }
-
-       /*
-        * Get the next work request entry to find where to put the data.
-        * Note that it is safe to drop the lock after changing rq->tail
-        * since ipath_post_receive() won't fill the empty slot.
-        */
-       spin_lock_irqsave(&rq->lock, flags);
-       wq = rq->wq;
-       tail = wq->tail;
-       /* Validate tail before using it since it is user writable. */
-       if (tail >= rq->size)
-               tail = 0;
-       if (unlikely(tail == wq->head)) {
-               spin_unlock_irqrestore(&rq->lock, flags);
-               dev->n_pkt_drops++;
-               goto drop;
-       }
-       wqe = get_rwqe_ptr(rq, tail);
-       rsge.sg_list = qp->r_ud_sg_list;
-       if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
-               spin_unlock_irqrestore(&rq->lock, flags);
-               dev->n_pkt_drops++;
-               goto drop;
-       }
-       /* Silently drop packets which are too big. */
-       if (wc.byte_len > rlen) {
-               spin_unlock_irqrestore(&rq->lock, flags);
-               dev->n_pkt_drops++;
-               goto drop;
-       }
-       if (++tail >= rq->size)
-               tail = 0;
-       wq->tail = tail;
-       wc.wr_id = wqe->wr_id;
-       if (handler) {
-               u32 n;
-
-               /*
-                * validate head pointer value and compute
-                * the number of remaining WQEs.
-                */
-               n = wq->head;
-               if (n >= rq->size)
-                       n = 0;
-               if (n < tail)
-                       n += rq->size - tail;
-               else
-                       n -= tail;
-               if (n < srq->limit) {
-                       struct ib_event ev;
-
-                       srq->limit = 0;
-                       spin_unlock_irqrestore(&rq->lock, flags);
-                       ev.device = qp->ibqp.device;
-                       ev.element.srq = qp->ibqp.srq;
-                       ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
-                       handler(&ev, srq->ibsrq.srq_context);
-               } else
-                       spin_unlock_irqrestore(&rq->lock, flags);
-       } else
-               spin_unlock_irqrestore(&rq->lock, flags);
-
-       ah_attr = &to_iah(swqe->ud_wr.ah)->attr;
-       if (ah_attr->ah_flags & IB_AH_GRH) {
-               ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
-               wc.wc_flags |= IB_WC_GRH;
-       } else
-               ipath_skip_sge(&rsge, sizeof(struct ib_grh));
-       sge = swqe->sg_list;
-       while (length) {
-               u32 len = sge->length;
-
-               if (len > length)
-                       len = length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               ipath_copy_sge(&rsge, sge->vaddr, len);
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--swqe->wr.num_sge)
-                               sge++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-               length -= len;
-       }
-       wc.status = IB_WC_SUCCESS;
-       wc.opcode = IB_WC_RECV;
-       wc.qp = &qp->ibqp;
-       wc.src_qp = sqp->ibqp.qp_num;
-       /* XXX do we know which pkey matched? Only needed for GSI. */
-       wc.pkey_index = 0;
-       wc.slid = dev->dd->ipath_lid |
-               (ah_attr->src_path_bits &
-                ((1 << dev->dd->ipath_lmc) - 1));
-       wc.sl = ah_attr->sl;
-       wc.dlid_path_bits =
-               ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1);
-       wc.port_num = 1;
-       /* Signal completion event if the solicited bit is set. */
-       ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                      swqe->ud_wr.wr.send_flags & IB_SEND_SOLICITED);
-drop:
-       if (atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-done:;
-}
-
-/**
- * ipath_make_ud_req - construct a UD request packet
- * @qp: the QP
- *
- * Return 1 if constructed; otherwise, return 0.
- */
-int ipath_make_ud_req(struct ipath_qp *qp)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ipath_other_headers *ohdr;
-       struct ib_ah_attr *ah_attr;
-       struct ipath_swqe *wqe;
-       unsigned long flags;
-       u32 nwords;
-       u32 extra_bytes;
-       u32 bth0;
-       u16 lrh0;
-       u16 lid;
-       int ret = 0;
-       int next_cur;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_NEXT_SEND_OK)) {
-               if (!(ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND))
-                       goto bail;
-               /* We are in the error state, flush the work request. */
-               if (qp->s_last == qp->s_head)
-                       goto bail;
-               /* If DMAs are in progress, we can't flush immediately. */
-               if (atomic_read(&qp->s_dma_busy)) {
-                       qp->s_flags |= IPATH_S_WAIT_DMA;
-                       goto bail;
-               }
-               wqe = get_swqe_ptr(qp, qp->s_last);
-               ipath_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR);
-               goto done;
-       }
-
-       if (qp->s_cur == qp->s_head)
-               goto bail;
-
-       wqe = get_swqe_ptr(qp, qp->s_cur);
-       next_cur = qp->s_cur + 1;
-       if (next_cur >= qp->s_size)
-               next_cur = 0;
-
-       /* Construct the header. */
-       ah_attr = &to_iah(wqe->ud_wr.ah)->attr;
-       if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
-               if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
-                       dev->n_multicast_xmit++;
-               else
-                       dev->n_unicast_xmit++;
-       } else {
-               dev->n_unicast_xmit++;
-               lid = ah_attr->dlid & ~((1 << dev->dd->ipath_lmc) - 1);
-               if (unlikely(lid == dev->dd->ipath_lid)) {
-                       /*
-                        * If DMAs are in progress, we can't generate
-                        * a completion for the loopback packet since
-                        * it would be out of order.
-                        * XXX Instead of waiting, we could queue a
-                        * zero length descriptor so we get a callback.
-                        */
-                       if (atomic_read(&qp->s_dma_busy)) {
-                               qp->s_flags |= IPATH_S_WAIT_DMA;
-                               goto bail;
-                       }
-                       qp->s_cur = next_cur;
-                       spin_unlock_irqrestore(&qp->s_lock, flags);
-                       ipath_ud_loopback(qp, wqe);
-                       spin_lock_irqsave(&qp->s_lock, flags);
-                       ipath_send_complete(qp, wqe, IB_WC_SUCCESS);
-                       goto done;
-               }
-       }
-
-       qp->s_cur = next_cur;
-       extra_bytes = -wqe->length & 3;
-       nwords = (wqe->length + extra_bytes) >> 2;
-
-       /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
-       qp->s_hdrwords = 7;
-       qp->s_cur_size = wqe->length;
-       qp->s_cur_sge = &qp->s_sge;
-       qp->s_dmult = ah_attr->static_rate;
-       qp->s_wqe = wqe;
-       qp->s_sge.sge = wqe->sg_list[0];
-       qp->s_sge.sg_list = wqe->sg_list + 1;
-       qp->s_sge.num_sge = wqe->ud_wr.wr.num_sge;
-
-       if (ah_attr->ah_flags & IB_AH_GRH) {
-               /* Header size in 32-bit words. */
-               qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
-                                                &ah_attr->grh,
-                                                qp->s_hdrwords, nwords);
-               lrh0 = IPATH_LRH_GRH;
-               ohdr = &qp->s_hdr.u.l.oth;
-               /*
-                * Don't worry about sending to locally attached multicast
-                * QPs.  It is unspecified by the spec. what happens.
-                */
-       } else {
-               /* Header size in 32-bit words. */
-               lrh0 = IPATH_LRH_BTH;
-               ohdr = &qp->s_hdr.u.oth;
-       }
-       if (wqe->ud_wr.wr.opcode == IB_WR_SEND_WITH_IMM) {
-               qp->s_hdrwords++;
-               ohdr->u.ud.imm_data = wqe->ud_wr.wr.ex.imm_data;
-               bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
-       } else
-               bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
-       lrh0 |= ah_attr->sl << 4;
-       if (qp->ibqp.qp_type == IB_QPT_SMI)
-               lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
-       qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
-       qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid);  /* DEST LID */
-       qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
-                                          SIZE_OF_CRC);
-       lid = dev->dd->ipath_lid;
-       if (lid) {
-               lid |= ah_attr->src_path_bits &
-                       ((1 << dev->dd->ipath_lmc) - 1);
-               qp->s_hdr.lrh[3] = cpu_to_be16(lid);
-       } else
-               qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
-       if (wqe->ud_wr.wr.send_flags & IB_SEND_SOLICITED)
-               bth0 |= 1 << 23;
-       bth0 |= extra_bytes << 20;
-       bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
-               ipath_get_pkey(dev->dd, qp->s_pkey_index);
-       ohdr->bth[0] = cpu_to_be32(bth0);
-       /*
-        * Use the multicast QP if the destination LID is a multicast LID.
-        */
-       ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
-               ah_attr->dlid != IPATH_PERMISSIVE_LID ?
-               cpu_to_be32(IPATH_MULTICAST_QPN) :
-               cpu_to_be32(wqe->ud_wr.remote_qpn);
-       ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
-       /*
-        * Qkeys with the high order bit set mean use the
-        * qkey from the QP context instead of the WR (see 10.2.5).
-        */
-       ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->ud_wr.remote_qkey < 0 ?
-                                        qp->qkey : wqe->ud_wr.remote_qkey);
-       ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
-
-done:
-       ret = 1;
-       goto unlock;
-
-bail:
-       qp->s_flags &= ~IPATH_S_BUSY;
-unlock:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-       return ret;
-}
-
-/**
- * ipath_ud_rcv - receive an incoming UD packet
- * @dev: the device the packet came in on
- * @hdr: the packet header
- * @has_grh: true if the packet has a GRH
- * @data: the packet data
- * @tlen: the packet length
- * @qp: the QP the packet came on
- *
- * This is called from ipath_qp_rcv() to process an incoming UD packet
- * for the given QP.
- * Called at interrupt level.
- */
-void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp)
-{
-       struct ipath_other_headers *ohdr;
-       int opcode;
-       u32 hdrsize;
-       u32 pad;
-       struct ib_wc wc;
-       u32 qkey;
-       u32 src_qp;
-       u16 dlid;
-       int header_in_data;
-
-       /* Check for GRH */
-       if (!has_grh) {
-               ohdr = &hdr->u.oth;
-               hdrsize = 8 + 12 + 8;   /* LRH + BTH + DETH */
-               qkey = be32_to_cpu(ohdr->u.ud.deth[0]);
-               src_qp = be32_to_cpu(ohdr->u.ud.deth[1]);
-               header_in_data = 0;
-       } else {
-               ohdr = &hdr->u.l.oth;
-               hdrsize = 8 + 40 + 12 + 8; /* LRH + GRH + BTH + DETH */
-               /*
-                * The header with GRH is 68 bytes and the core driver sets
-                * the eager header buffer size to 56 bytes so the last 12
-                * bytes of the IB header is in the data buffer.
-                */
-               header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
-               if (header_in_data) {
-                       qkey = be32_to_cpu(((__be32 *) data)[1]);
-                       src_qp = be32_to_cpu(((__be32 *) data)[2]);
-                       data += 12;
-               } else {
-                       qkey = be32_to_cpu(ohdr->u.ud.deth[0]);
-                       src_qp = be32_to_cpu(ohdr->u.ud.deth[1]);
-               }
-       }
-       src_qp &= IPATH_QPN_MASK;
-
-       /*
-        * Check that the permissive LID is only used on QP0
-        * and the QKEY matches (see 9.6.1.4.1 and 9.6.1.5.1).
-        */
-       if (qp->ibqp.qp_num) {
-               if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE ||
-                            hdr->lrh[3] == IB_LID_PERMISSIVE)) {
-                       dev->n_pkt_drops++;
-                       goto bail;
-               }
-               if (unlikely(qkey != qp->qkey)) {
-                       /* XXX OK to lose a count once in a while. */
-                       dev->qkey_violations++;
-                       dev->n_pkt_drops++;
-                       goto bail;
-               }
-       } else if (hdr->lrh[1] == IB_LID_PERMISSIVE ||
-                  hdr->lrh[3] == IB_LID_PERMISSIVE) {
-               struct ib_smp *smp = (struct ib_smp *) data;
-
-               if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
-                       dev->n_pkt_drops++;
-                       goto bail;
-               }
-       }
-
-       /*
-        * The opcode is in the low byte when its in network order
-        * (top byte when in host order).
-        */
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
-       if (qp->ibqp.qp_num > 1 &&
-           opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) {
-               if (header_in_data) {
-                       wc.ex.imm_data = *(__be32 *) data;
-                       data += sizeof(__be32);
-               } else
-                       wc.ex.imm_data = ohdr->u.ud.imm_data;
-               wc.wc_flags = IB_WC_WITH_IMM;
-               hdrsize += sizeof(u32);
-       } else if (opcode == IB_OPCODE_UD_SEND_ONLY) {
-               wc.ex.imm_data = 0;
-               wc.wc_flags = 0;
-       } else {
-               dev->n_pkt_drops++;
-               goto bail;
-       }
-
-       /* Get the number of bytes the message was padded by. */
-       pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
-       if (unlikely(tlen < (hdrsize + pad + 4))) {
-               /* Drop incomplete packets. */
-               dev->n_pkt_drops++;
-               goto bail;
-       }
-       tlen -= hdrsize + pad + 4;
-
-       /* Drop invalid MAD packets (see 13.5.3.1). */
-       if (unlikely((qp->ibqp.qp_num == 0 &&
-                     (tlen != 256 ||
-                      (be16_to_cpu(hdr->lrh[0]) >> 12) != 15)) ||
-                    (qp->ibqp.qp_num == 1 &&
-                     (tlen != 256 ||
-                      (be16_to_cpu(hdr->lrh[0]) >> 12) == 15)))) {
-               dev->n_pkt_drops++;
-               goto bail;
-       }
-
-       /*
-        * A GRH is expected to precede the data even if not
-        * present on the wire.
-        */
-       wc.byte_len = tlen + sizeof(struct ib_grh);
-
-       /*
-        * Get the next work request entry to find where to put the data.
-        */
-       if (qp->r_flags & IPATH_R_REUSE_SGE)
-               qp->r_flags &= ~IPATH_R_REUSE_SGE;
-       else if (!ipath_get_rwqe(qp, 0)) {
-               /*
-                * Count VL15 packets dropped due to no receive buffer.
-                * Otherwise, count them as buffer overruns since usually,
-                * the HW will be able to receive packets even if there are
-                * no QPs with posted receive buffers.
-                */
-               if (qp->ibqp.qp_num == 0)
-                       dev->n_vl15_dropped++;
-               else
-                       dev->rcv_errors++;
-               goto bail;
-       }
-       /* Silently drop packets which are too big. */
-       if (wc.byte_len > qp->r_len) {
-               qp->r_flags |= IPATH_R_REUSE_SGE;
-               dev->n_pkt_drops++;
-               goto bail;
-       }
-       if (has_grh) {
-               ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh,
-                              sizeof(struct ib_grh));
-               wc.wc_flags |= IB_WC_GRH;
-       } else
-               ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh));
-       ipath_copy_sge(&qp->r_sge, data,
-                      wc.byte_len - sizeof(struct ib_grh));
-       if (!test_and_clear_bit(IPATH_R_WRID_VALID, &qp->r_aflags))
-               goto bail;
-       wc.wr_id = qp->r_wr_id;
-       wc.status = IB_WC_SUCCESS;
-       wc.opcode = IB_WC_RECV;
-       wc.vendor_err = 0;
-       wc.qp = &qp->ibqp;
-       wc.src_qp = src_qp;
-       /* XXX do we know which pkey matched? Only needed for GSI. */
-       wc.pkey_index = 0;
-       wc.slid = be16_to_cpu(hdr->lrh[3]);
-       wc.sl = (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF;
-       dlid = be16_to_cpu(hdr->lrh[1]);
-       /*
-        * Save the LMC lower bits if the destination LID is a unicast LID.
-        */
-       wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
-               dlid & ((1 << dev->dd->ipath_lmc) - 1);
-       wc.port_num = 1;
-       /* Signal completion event if the solicited bit is set. */
-       ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
-                      (ohdr->bth[0] &
-                       cpu_to_be32(1 << 23)) != 0);
-
-bail:;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_user_pages.c b/drivers/staging/rdma/ipath/ipath_user_pages.c
deleted file mode 100644 (file)
index d29b4da..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/mm.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-
-#include "ipath_kernel.h"
-
-static void __ipath_release_user_pages(struct page **p, size_t num_pages,
-                                  int dirty)
-{
-       size_t i;
-
-       for (i = 0; i < num_pages; i++) {
-               ipath_cdbg(MM, "%lu/%lu put_page %p\n", (unsigned long) i,
-                          (unsigned long) num_pages, p[i]);
-               if (dirty)
-                       set_page_dirty_lock(p[i]);
-               put_page(p[i]);
-       }
-}
-
-/* call with current->mm->mmap_sem held */
-static int __ipath_get_user_pages(unsigned long start_page, size_t num_pages,
-                                 struct page **p)
-{
-       unsigned long lock_limit;
-       size_t got;
-       int ret;
-
-       lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
-       if (num_pages > lock_limit) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       ipath_cdbg(VERBOSE, "pin %lx pages from vaddr %lx\n",
-                  (unsigned long) num_pages, start_page);
-
-       for (got = 0; got < num_pages; got += ret) {
-               ret = get_user_pages(current, current->mm,
-                                    start_page + got * PAGE_SIZE,
-                                    num_pages - got, 1, 1,
-                                    p + got, NULL);
-               if (ret < 0)
-                       goto bail_release;
-       }
-
-       current->mm->pinned_vm += num_pages;
-
-       ret = 0;
-       goto bail;
-
-bail_release:
-       __ipath_release_user_pages(p, got, 0);
-bail:
-       return ret;
-}
-
-/**
- * ipath_map_page - a safety wrapper around pci_map_page()
- *
- * A dma_addr of all 0's is interpreted by the chip as "disabled".
- * Unfortunately, it can also be a valid dma_addr returned on some
- * architectures.
- *
- * The powerpc iommu assigns dma_addrs in ascending order, so we don't
- * have to bother with retries or mapping a dummy page to insure we
- * don't just get the same mapping again.
- *
- * I'm sure we won't be so lucky with other iommu's, so FIXME.
- */
-dma_addr_t ipath_map_page(struct pci_dev *hwdev, struct page *page,
-       unsigned long offset, size_t size, int direction)
-{
-       dma_addr_t phys;
-
-       phys = pci_map_page(hwdev, page, offset, size, direction);
-
-       if (phys == 0) {
-               pci_unmap_page(hwdev, phys, size, direction);
-               phys = pci_map_page(hwdev, page, offset, size, direction);
-               /*
-                * FIXME: If we get 0 again, we should keep this page,
-                * map another, then free the 0 page.
-                */
-       }
-
-       return phys;
-}
-
-/**
- * ipath_map_single - a safety wrapper around pci_map_single()
- *
- * Same idea as ipath_map_page().
- */
-dma_addr_t ipath_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
-       int direction)
-{
-       dma_addr_t phys;
-
-       phys = pci_map_single(hwdev, ptr, size, direction);
-
-       if (phys == 0) {
-               pci_unmap_single(hwdev, phys, size, direction);
-               phys = pci_map_single(hwdev, ptr, size, direction);
-               /*
-                * FIXME: If we get 0 again, we should keep this page,
-                * map another, then free the 0 page.
-                */
-       }
-
-       return phys;
-}
-
-/**
- * ipath_get_user_pages - lock user pages into memory
- * @start_page: the start page
- * @num_pages: the number of pages
- * @p: the output page structures
- *
- * This function takes a given start page (page aligned user virtual
- * address) and pins it and the following specified number of pages.  For
- * now, num_pages is always 1, but that will probably change at some point
- * (because caller is doing expected sends on a single virtually contiguous
- * buffer, so we can do all pages at once).
- */
-int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
-                        struct page **p)
-{
-       int ret;
-
-       down_write(&current->mm->mmap_sem);
-
-       ret = __ipath_get_user_pages(start_page, num_pages, p);
-
-       up_write(&current->mm->mmap_sem);
-
-       return ret;
-}
-
-void ipath_release_user_pages(struct page **p, size_t num_pages)
-{
-       down_write(&current->mm->mmap_sem);
-
-       __ipath_release_user_pages(p, num_pages, 1);
-
-       current->mm->pinned_vm -= num_pages;
-
-       up_write(&current->mm->mmap_sem);
-}
-
-struct ipath_user_pages_work {
-       struct work_struct work;
-       struct mm_struct *mm;
-       unsigned long num_pages;
-};
-
-static void user_pages_account(struct work_struct *_work)
-{
-       struct ipath_user_pages_work *work =
-               container_of(_work, struct ipath_user_pages_work, work);
-
-       down_write(&work->mm->mmap_sem);
-       work->mm->pinned_vm -= work->num_pages;
-       up_write(&work->mm->mmap_sem);
-       mmput(work->mm);
-       kfree(work);
-}
-
-void ipath_release_user_pages_on_close(struct page **p, size_t num_pages)
-{
-       struct ipath_user_pages_work *work;
-       struct mm_struct *mm;
-
-       __ipath_release_user_pages(p, num_pages, 1);
-
-       mm = get_task_mm(current);
-       if (!mm)
-               return;
-
-       work = kmalloc(sizeof(*work), GFP_KERNEL);
-       if (!work)
-               goto bail_mm;
-
-       INIT_WORK(&work->work, user_pages_account);
-       work->mm = mm;
-       work->num_pages = num_pages;
-
-       queue_work(ib_wq, &work->work);
-       return;
-
-bail_mm:
-       mmput(mm);
-       return;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_user_sdma.c b/drivers/staging/rdma/ipath/ipath_user_sdma.c
deleted file mode 100644 (file)
index 8c12e3c..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-/*
- * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <linux/mm.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/highmem.h>
-#include <linux/io.h>
-#include <linux/uio.h>
-#include <linux/rbtree.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-
-#include "ipath_kernel.h"
-#include "ipath_user_sdma.h"
-
-/* minimum size of header */
-#define IPATH_USER_SDMA_MIN_HEADER_LENGTH      64
-/* expected size of headers (for dma_pool) */
-#define IPATH_USER_SDMA_EXP_HEADER_LENGTH      64
-/* length mask in PBC (lower 11 bits) */
-#define IPATH_PBC_LENGTH_MASK                  ((1 << 11) - 1)
-
-struct ipath_user_sdma_pkt {
-       u8 naddr;               /* dimension of addr (1..3) ... */
-       u32 counter;            /* sdma pkts queued counter for this entry */
-       u64 added;              /* global descq number of entries */
-
-       struct {
-               u32 offset;                     /* offset for kvaddr, addr */
-               u32 length;                     /* length in page */
-               u8  put_page;                   /* should we put_page? */
-               u8  dma_mapped;                 /* is page dma_mapped? */
-               struct page *page;              /* may be NULL (coherent mem) */
-               void *kvaddr;                   /* FIXME: only for pio hack */
-               dma_addr_t addr;
-       } addr[4];   /* max pages, any more and we coalesce */
-       struct list_head list;  /* list element */
-};
-
-struct ipath_user_sdma_queue {
-       /*
-        * pkts sent to dma engine are queued on this
-        * list head.  the type of the elements of this
-        * list are struct ipath_user_sdma_pkt...
-        */
-       struct list_head sent;
-
-       /* headers with expected length are allocated from here... */
-       char header_cache_name[64];
-       struct dma_pool *header_cache;
-
-       /* packets are allocated from the slab cache... */
-       char pkt_slab_name[64];
-       struct kmem_cache *pkt_slab;
-
-       /* as packets go on the queued queue, they are counted... */
-       u32 counter;
-       u32 sent_counter;
-
-       /* dma page table */
-       struct rb_root dma_pages_root;
-
-       /* protect everything above... */
-       struct mutex lock;
-};
-
-struct ipath_user_sdma_queue *
-ipath_user_sdma_queue_create(struct device *dev, int unit, int port, int sport)
-{
-       struct ipath_user_sdma_queue *pq =
-               kmalloc(sizeof(struct ipath_user_sdma_queue), GFP_KERNEL);
-
-       if (!pq)
-               goto done;
-
-       pq->counter = 0;
-       pq->sent_counter = 0;
-       INIT_LIST_HEAD(&pq->sent);
-
-       mutex_init(&pq->lock);
-
-       snprintf(pq->pkt_slab_name, sizeof(pq->pkt_slab_name),
-                "ipath-user-sdma-pkts-%u-%02u.%02u", unit, port, sport);
-       pq->pkt_slab = kmem_cache_create(pq->pkt_slab_name,
-                                        sizeof(struct ipath_user_sdma_pkt),
-                                        0, 0, NULL);
-
-       if (!pq->pkt_slab)
-               goto err_kfree;
-
-       snprintf(pq->header_cache_name, sizeof(pq->header_cache_name),
-                "ipath-user-sdma-headers-%u-%02u.%02u", unit, port, sport);
-       pq->header_cache = dma_pool_create(pq->header_cache_name,
-                                          dev,
-                                          IPATH_USER_SDMA_EXP_HEADER_LENGTH,
-                                          4, 0);
-       if (!pq->header_cache)
-               goto err_slab;
-
-       pq->dma_pages_root = RB_ROOT;
-
-       goto done;
-
-err_slab:
-       kmem_cache_destroy(pq->pkt_slab);
-err_kfree:
-       kfree(pq);
-       pq = NULL;
-
-done:
-       return pq;
-}
-
-static void ipath_user_sdma_init_frag(struct ipath_user_sdma_pkt *pkt,
-                                     int i, size_t offset, size_t len,
-                                     int put_page, int dma_mapped,
-                                     struct page *page,
-                                     void *kvaddr, dma_addr_t dma_addr)
-{
-       pkt->addr[i].offset = offset;
-       pkt->addr[i].length = len;
-       pkt->addr[i].put_page = put_page;
-       pkt->addr[i].dma_mapped = dma_mapped;
-       pkt->addr[i].page = page;
-       pkt->addr[i].kvaddr = kvaddr;
-       pkt->addr[i].addr = dma_addr;
-}
-
-static void ipath_user_sdma_init_header(struct ipath_user_sdma_pkt *pkt,
-                                       u32 counter, size_t offset,
-                                       size_t len, int dma_mapped,
-                                       struct page *page,
-                                       void *kvaddr, dma_addr_t dma_addr)
-{
-       pkt->naddr = 1;
-       pkt->counter = counter;
-       ipath_user_sdma_init_frag(pkt, 0, offset, len, 0, dma_mapped, page,
-                                 kvaddr, dma_addr);
-}
-
-/* we've too many pages in the iovec, coalesce to a single page */
-static int ipath_user_sdma_coalesce(const struct ipath_devdata *dd,
-                                   struct ipath_user_sdma_pkt *pkt,
-                                   const struct iovec *iov,
-                                   unsigned long niov) {
-       int ret = 0;
-       struct page *page = alloc_page(GFP_KERNEL);
-       void *mpage_save;
-       char *mpage;
-       int i;
-       int len = 0;
-       dma_addr_t dma_addr;
-
-       if (!page) {
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       mpage = kmap(page);
-       mpage_save = mpage;
-       for (i = 0; i < niov; i++) {
-               int cfur;
-
-               cfur = copy_from_user(mpage,
-                                     iov[i].iov_base, iov[i].iov_len);
-               if (cfur) {
-                       ret = -EFAULT;
-                       goto free_unmap;
-               }
-
-               mpage += iov[i].iov_len;
-               len += iov[i].iov_len;
-       }
-
-       dma_addr = dma_map_page(&dd->pcidev->dev, page, 0, len,
-                               DMA_TO_DEVICE);
-       if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
-               ret = -ENOMEM;
-               goto free_unmap;
-       }
-
-       ipath_user_sdma_init_frag(pkt, 1, 0, len, 0, 1, page, mpage_save,
-                                 dma_addr);
-       pkt->naddr = 2;
-
-       goto done;
-
-free_unmap:
-       kunmap(page);
-       __free_page(page);
-done:
-       return ret;
-}
-
-/* how many pages in this iovec element? */
-static int ipath_user_sdma_num_pages(const struct iovec *iov)
-{
-       const unsigned long addr  = (unsigned long) iov->iov_base;
-       const unsigned long  len  = iov->iov_len;
-       const unsigned long spage = addr & PAGE_MASK;
-       const unsigned long epage = (addr + len - 1) & PAGE_MASK;
-
-       return 1 + ((epage - spage) >> PAGE_SHIFT);
-}
-
-/* truncate length to page boundary */
-static int ipath_user_sdma_page_length(unsigned long addr, unsigned long len)
-{
-       const unsigned long offset = offset_in_page(addr);
-
-       return ((offset + len) > PAGE_SIZE) ? (PAGE_SIZE - offset) : len;
-}
-
-static void ipath_user_sdma_free_pkt_frag(struct device *dev,
-                                         struct ipath_user_sdma_queue *pq,
-                                         struct ipath_user_sdma_pkt *pkt,
-                                         int frag)
-{
-       const int i = frag;
-
-       if (pkt->addr[i].page) {
-               if (pkt->addr[i].dma_mapped)
-                       dma_unmap_page(dev,
-                                      pkt->addr[i].addr,
-                                      pkt->addr[i].length,
-                                      DMA_TO_DEVICE);
-
-               if (pkt->addr[i].kvaddr)
-                       kunmap(pkt->addr[i].page);
-
-               if (pkt->addr[i].put_page)
-                       put_page(pkt->addr[i].page);
-               else
-                       __free_page(pkt->addr[i].page);
-       } else if (pkt->addr[i].kvaddr)
-               /* free coherent mem from cache... */
-               dma_pool_free(pq->header_cache,
-                             pkt->addr[i].kvaddr, pkt->addr[i].addr);
-}
-
-/* return number of pages pinned... */
-static int ipath_user_sdma_pin_pages(const struct ipath_devdata *dd,
-                                    struct ipath_user_sdma_pkt *pkt,
-                                    unsigned long addr, int tlen, int npages)
-{
-       struct page *pages[2];
-       int j;
-       int ret;
-
-       ret = get_user_pages_fast(addr, npages, 0, pages);
-       if (ret != npages) {
-               int i;
-
-               for (i = 0; i < ret; i++)
-                       put_page(pages[i]);
-
-               ret = -ENOMEM;
-               goto done;
-       }
-
-       for (j = 0; j < npages; j++) {
-               /* map the pages... */
-               const int flen =
-                       ipath_user_sdma_page_length(addr, tlen);
-               dma_addr_t dma_addr =
-                       dma_map_page(&dd->pcidev->dev,
-                                    pages[j], 0, flen, DMA_TO_DEVICE);
-               unsigned long fofs = offset_in_page(addr);
-
-               if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
-                       ret = -ENOMEM;
-                       goto done;
-               }
-
-               ipath_user_sdma_init_frag(pkt, pkt->naddr, fofs, flen, 1, 1,
-                                         pages[j], kmap(pages[j]),
-                                         dma_addr);
-
-               pkt->naddr++;
-               addr += flen;
-               tlen -= flen;
-       }
-
-done:
-       return ret;
-}
-
-static int ipath_user_sdma_pin_pkt(const struct ipath_devdata *dd,
-                                  struct ipath_user_sdma_queue *pq,
-                                  struct ipath_user_sdma_pkt *pkt,
-                                  const struct iovec *iov,
-                                  unsigned long niov)
-{
-       int ret = 0;
-       unsigned long idx;
-
-       for (idx = 0; idx < niov; idx++) {
-               const int npages = ipath_user_sdma_num_pages(iov + idx);
-               const unsigned long addr = (unsigned long) iov[idx].iov_base;
-
-               ret = ipath_user_sdma_pin_pages(dd, pkt,
-                                               addr, iov[idx].iov_len,
-                                               npages);
-               if (ret < 0)
-                       goto free_pkt;
-       }
-
-       goto done;
-
-free_pkt:
-       for (idx = 0; idx < pkt->naddr; idx++)
-               ipath_user_sdma_free_pkt_frag(&dd->pcidev->dev, pq, pkt, idx);
-
-done:
-       return ret;
-}
-
-static int ipath_user_sdma_init_payload(const struct ipath_devdata *dd,
-                                       struct ipath_user_sdma_queue *pq,
-                                       struct ipath_user_sdma_pkt *pkt,
-                                       const struct iovec *iov,
-                                       unsigned long niov, int npages)
-{
-       int ret = 0;
-
-       if (npages >= ARRAY_SIZE(pkt->addr))
-               ret = ipath_user_sdma_coalesce(dd, pkt, iov, niov);
-       else
-               ret = ipath_user_sdma_pin_pkt(dd, pq, pkt, iov, niov);
-
-       return ret;
-}
-
-/* free a packet list -- return counter value of last packet */
-static void ipath_user_sdma_free_pkt_list(struct device *dev,
-                                         struct ipath_user_sdma_queue *pq,
-                                         struct list_head *list)
-{
-       struct ipath_user_sdma_pkt *pkt, *pkt_next;
-
-       list_for_each_entry_safe(pkt, pkt_next, list, list) {
-               int i;
-
-               for (i = 0; i < pkt->naddr; i++)
-                       ipath_user_sdma_free_pkt_frag(dev, pq, pkt, i);
-
-               kmem_cache_free(pq->pkt_slab, pkt);
-       }
-}
-
-/*
- * copy headers, coalesce etc -- pq->lock must be held
- *
- * we queue all the packets to list, returning the
- * number of bytes total.  list must be empty initially,
- * as, if there is an error we clean it...
- */
-static int ipath_user_sdma_queue_pkts(const struct ipath_devdata *dd,
-                                     struct ipath_user_sdma_queue *pq,
-                                     struct list_head *list,
-                                     const struct iovec *iov,
-                                     unsigned long niov,
-                                     int maxpkts)
-{
-       unsigned long idx = 0;
-       int ret = 0;
-       int npkts = 0;
-       struct page *page = NULL;
-       __le32 *pbc;
-       dma_addr_t dma_addr;
-       struct ipath_user_sdma_pkt *pkt = NULL;
-       size_t len;
-       size_t nw;
-       u32 counter = pq->counter;
-       int dma_mapped = 0;
-
-       while (idx < niov && npkts < maxpkts) {
-               const unsigned long addr = (unsigned long) iov[idx].iov_base;
-               const unsigned long idx_save = idx;
-               unsigned pktnw;
-               unsigned pktnwc;
-               int nfrags = 0;
-               int npages = 0;
-               int cfur;
-
-               dma_mapped = 0;
-               len = iov[idx].iov_len;
-               nw = len >> 2;
-               page = NULL;
-
-               pkt = kmem_cache_alloc(pq->pkt_slab, GFP_KERNEL);
-               if (!pkt) {
-                       ret = -ENOMEM;
-                       goto free_list;
-               }
-
-               if (len < IPATH_USER_SDMA_MIN_HEADER_LENGTH ||
-                   len > PAGE_SIZE || len & 3 || addr & 3) {
-                       ret = -EINVAL;
-                       goto free_pkt;
-               }
-
-               if (len == IPATH_USER_SDMA_EXP_HEADER_LENGTH)
-                       pbc = dma_pool_alloc(pq->header_cache, GFP_KERNEL,
-                                            &dma_addr);
-               else
-                       pbc = NULL;
-
-               if (!pbc) {
-                       page = alloc_page(GFP_KERNEL);
-                       if (!page) {
-                               ret = -ENOMEM;
-                               goto free_pkt;
-                       }
-                       pbc = kmap(page);
-               }
-
-               cfur = copy_from_user(pbc, iov[idx].iov_base, len);
-               if (cfur) {
-                       ret = -EFAULT;
-                       goto free_pbc;
-               }
-
-               /*
-                * this assignment is a bit strange.  it's because the
-                * the pbc counts the number of 32 bit words in the full
-                * packet _except_ the first word of the pbc itself...
-                */
-               pktnwc = nw - 1;
-
-               /*
-                * pktnw computation yields the number of 32 bit words
-                * that the caller has indicated in the PBC.  note that
-                * this is one less than the total number of words that
-                * goes to the send DMA engine as the first 32 bit word
-                * of the PBC itself is not counted.  Armed with this count,
-                * we can verify that the packet is consistent with the
-                * iovec lengths.
-                */
-               pktnw = le32_to_cpu(*pbc) & IPATH_PBC_LENGTH_MASK;
-               if (pktnw < pktnwc || pktnw > pktnwc + (PAGE_SIZE >> 2)) {
-                       ret = -EINVAL;
-                       goto free_pbc;
-               }
-
-
-               idx++;
-               while (pktnwc < pktnw && idx < niov) {
-                       const size_t slen = iov[idx].iov_len;
-                       const unsigned long faddr =
-                               (unsigned long) iov[idx].iov_base;
-
-                       if (slen & 3 || faddr & 3 || !slen ||
-                           slen > PAGE_SIZE) {
-                               ret = -EINVAL;
-                               goto free_pbc;
-                       }
-
-                       npages++;
-                       if ((faddr & PAGE_MASK) !=
-                           ((faddr + slen - 1) & PAGE_MASK))
-                               npages++;
-
-                       pktnwc += slen >> 2;
-                       idx++;
-                       nfrags++;
-               }
-
-               if (pktnwc != pktnw) {
-                       ret = -EINVAL;
-                       goto free_pbc;
-               }
-
-               if (page) {
-                       dma_addr = dma_map_page(&dd->pcidev->dev,
-                                               page, 0, len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(&dd->pcidev->dev, dma_addr)) {
-                               ret = -ENOMEM;
-                               goto free_pbc;
-                       }
-
-                       dma_mapped = 1;
-               }
-
-               ipath_user_sdma_init_header(pkt, counter, 0, len, dma_mapped,
-                                           page, pbc, dma_addr);
-
-               if (nfrags) {
-                       ret = ipath_user_sdma_init_payload(dd, pq, pkt,
-                                                          iov + idx_save + 1,
-                                                          nfrags, npages);
-                       if (ret < 0)
-                               goto free_pbc_dma;
-               }
-
-               counter++;
-               npkts++;
-
-               list_add_tail(&pkt->list, list);
-       }
-
-       ret = idx;
-       goto done;
-
-free_pbc_dma:
-       if (dma_mapped)
-               dma_unmap_page(&dd->pcidev->dev, dma_addr, len, DMA_TO_DEVICE);
-free_pbc:
-       if (page) {
-               kunmap(page);
-               __free_page(page);
-       } else
-               dma_pool_free(pq->header_cache, pbc, dma_addr);
-free_pkt:
-       kmem_cache_free(pq->pkt_slab, pkt);
-free_list:
-       ipath_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, list);
-done:
-       return ret;
-}
-
-static void ipath_user_sdma_set_complete_counter(struct ipath_user_sdma_queue *pq,
-                                                u32 c)
-{
-       pq->sent_counter = c;
-}
-
-/* try to clean out queue -- needs pq->lock */
-static int ipath_user_sdma_queue_clean(const struct ipath_devdata *dd,
-                                      struct ipath_user_sdma_queue *pq)
-{
-       struct list_head free_list;
-       struct ipath_user_sdma_pkt *pkt;
-       struct ipath_user_sdma_pkt *pkt_prev;
-       int ret = 0;
-
-       INIT_LIST_HEAD(&free_list);
-
-       list_for_each_entry_safe(pkt, pkt_prev, &pq->sent, list) {
-               s64 descd = dd->ipath_sdma_descq_removed - pkt->added;
-
-               if (descd < 0)
-                       break;
-
-               list_move_tail(&pkt->list, &free_list);
-
-               /* one more packet cleaned */
-               ret++;
-       }
-
-       if (!list_empty(&free_list)) {
-               u32 counter;
-
-               pkt = list_entry(free_list.prev,
-                                struct ipath_user_sdma_pkt, list);
-               counter = pkt->counter;
-
-               ipath_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
-               ipath_user_sdma_set_complete_counter(pq, counter);
-       }
-
-       return ret;
-}
-
-void ipath_user_sdma_queue_destroy(struct ipath_user_sdma_queue *pq)
-{
-       if (!pq)
-               return;
-
-       kmem_cache_destroy(pq->pkt_slab);
-       dma_pool_destroy(pq->header_cache);
-       kfree(pq);
-}
-
-/* clean descriptor queue, returns > 0 if some elements cleaned */
-static int ipath_user_sdma_hwqueue_clean(struct ipath_devdata *dd)
-{
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-       ret = ipath_sdma_make_progress(dd);
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       return ret;
-}
-
-/* we're in close, drain packets so that we can cleanup successfully... */
-void ipath_user_sdma_queue_drain(struct ipath_devdata *dd,
-                                struct ipath_user_sdma_queue *pq)
-{
-       int i;
-
-       if (!pq)
-               return;
-
-       for (i = 0; i < 100; i++) {
-               mutex_lock(&pq->lock);
-               if (list_empty(&pq->sent)) {
-                       mutex_unlock(&pq->lock);
-                       break;
-               }
-               ipath_user_sdma_hwqueue_clean(dd);
-               ipath_user_sdma_queue_clean(dd, pq);
-               mutex_unlock(&pq->lock);
-               msleep(10);
-       }
-
-       if (!list_empty(&pq->sent)) {
-               struct list_head free_list;
-
-               printk(KERN_INFO "drain: lists not empty: forcing!\n");
-               INIT_LIST_HEAD(&free_list);
-               mutex_lock(&pq->lock);
-               list_splice_init(&pq->sent, &free_list);
-               ipath_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &free_list);
-               mutex_unlock(&pq->lock);
-       }
-}
-
-static inline __le64 ipath_sdma_make_desc0(struct ipath_devdata *dd,
-                                          u64 addr, u64 dwlen, u64 dwoffset)
-{
-       return cpu_to_le64(/* SDmaPhyAddr[31:0] */
-                          ((addr & 0xfffffffcULL) << 32) |
-                          /* SDmaGeneration[1:0] */
-                          ((dd->ipath_sdma_generation & 3ULL) << 30) |
-                          /* SDmaDwordCount[10:0] */
-                          ((dwlen & 0x7ffULL) << 16) |
-                          /* SDmaBufOffset[12:2] */
-                          (dwoffset & 0x7ffULL));
-}
-
-static inline __le64 ipath_sdma_make_first_desc0(__le64 descq)
-{
-       return descq | cpu_to_le64(1ULL << 12);
-}
-
-static inline __le64 ipath_sdma_make_last_desc0(__le64 descq)
-{
-                                             /* last */  /* dma head */
-       return descq | cpu_to_le64(1ULL << 11 | 1ULL << 13);
-}
-
-static inline __le64 ipath_sdma_make_desc1(u64 addr)
-{
-       /* SDmaPhyAddr[47:32] */
-       return cpu_to_le64(addr >> 32);
-}
-
-static void ipath_user_sdma_send_frag(struct ipath_devdata *dd,
-                                     struct ipath_user_sdma_pkt *pkt, int idx,
-                                     unsigned ofs, u16 tail)
-{
-       const u64 addr = (u64) pkt->addr[idx].addr +
-               (u64) pkt->addr[idx].offset;
-       const u64 dwlen = (u64) pkt->addr[idx].length / 4;
-       __le64 *descqp;
-       __le64 descq0;
-
-       descqp = &dd->ipath_sdma_descq[tail].qw[0];
-
-       descq0 = ipath_sdma_make_desc0(dd, addr, dwlen, ofs);
-       if (idx == 0)
-               descq0 = ipath_sdma_make_first_desc0(descq0);
-       if (idx == pkt->naddr - 1)
-               descq0 = ipath_sdma_make_last_desc0(descq0);
-
-       descqp[0] = descq0;
-       descqp[1] = ipath_sdma_make_desc1(addr);
-}
-
-/* pq->lock must be held, get packets on the wire... */
-static int ipath_user_sdma_push_pkts(struct ipath_devdata *dd,
-                                    struct ipath_user_sdma_queue *pq,
-                                    struct list_head *pktlist)
-{
-       int ret = 0;
-       unsigned long flags;
-       u16 tail;
-
-       if (list_empty(pktlist))
-               return 0;
-
-       if (unlikely(!(dd->ipath_flags & IPATH_LINKACTIVE)))
-               return -ECOMM;
-
-       spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
-
-       if (unlikely(dd->ipath_sdma_status & IPATH_SDMA_ABORT_MASK)) {
-               ret = -ECOMM;
-               goto unlock;
-       }
-
-       tail = dd->ipath_sdma_descq_tail;
-       while (!list_empty(pktlist)) {
-               struct ipath_user_sdma_pkt *pkt =
-                       list_entry(pktlist->next, struct ipath_user_sdma_pkt,
-                                  list);
-               int i;
-               unsigned ofs = 0;
-               u16 dtail = tail;
-
-               if (pkt->naddr > ipath_sdma_descq_freecnt(dd))
-                       goto unlock_check_tail;
-
-               for (i = 0; i < pkt->naddr; i++) {
-                       ipath_user_sdma_send_frag(dd, pkt, i, ofs, tail);
-                       ofs += pkt->addr[i].length >> 2;
-
-                       if (++tail == dd->ipath_sdma_descq_cnt) {
-                               tail = 0;
-                               ++dd->ipath_sdma_generation;
-                       }
-               }
-
-               if ((ofs<<2) > dd->ipath_ibmaxlen) {
-                       ipath_dbg("packet size %X > ibmax %X, fail\n",
-                               ofs<<2, dd->ipath_ibmaxlen);
-                       ret = -EMSGSIZE;
-                       goto unlock;
-               }
-
-               /*
-                * if the packet is >= 2KB mtu equivalent, we have to use
-                * the large buffers, and have to mark each descriptor as
-                * part of a large buffer packet.
-                */
-               if (ofs >= IPATH_SMALLBUF_DWORDS) {
-                       for (i = 0; i < pkt->naddr; i++) {
-                               dd->ipath_sdma_descq[dtail].qw[0] |=
-                                       cpu_to_le64(1ULL << 14);
-                               if (++dtail == dd->ipath_sdma_descq_cnt)
-                                       dtail = 0;
-                       }
-               }
-
-               dd->ipath_sdma_descq_added += pkt->naddr;
-               pkt->added = dd->ipath_sdma_descq_added;
-               list_move_tail(&pkt->list, &pq->sent);
-               ret++;
-       }
-
-unlock_check_tail:
-       /* advance the tail on the chip if necessary */
-       if (dd->ipath_sdma_descq_tail != tail) {
-               wmb();
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmatail, tail);
-               dd->ipath_sdma_descq_tail = tail;
-       }
-
-unlock:
-       spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
-
-       return ret;
-}
-
-int ipath_user_sdma_writev(struct ipath_devdata *dd,
-                          struct ipath_user_sdma_queue *pq,
-                          const struct iovec *iov,
-                          unsigned long dim)
-{
-       int ret = 0;
-       struct list_head list;
-       int npkts = 0;
-
-       INIT_LIST_HEAD(&list);
-
-       mutex_lock(&pq->lock);
-
-       if (dd->ipath_sdma_descq_added != dd->ipath_sdma_descq_removed) {
-               ipath_user_sdma_hwqueue_clean(dd);
-               ipath_user_sdma_queue_clean(dd, pq);
-       }
-
-       while (dim) {
-               const int mxp = 8;
-
-               ret = ipath_user_sdma_queue_pkts(dd, pq, &list, iov, dim, mxp);
-               if (ret <= 0)
-                       goto done_unlock;
-               else {
-                       dim -= ret;
-                       iov += ret;
-               }
-
-               /* force packets onto the sdma hw queue... */
-               if (!list_empty(&list)) {
-                       /*
-                        * lazily clean hw queue.  the 4 is a guess of about
-                        * how many sdma descriptors a packet will take (it
-                        * doesn't have to be perfect).
-                        */
-                       if (ipath_sdma_descq_freecnt(dd) < ret * 4) {
-                               ipath_user_sdma_hwqueue_clean(dd);
-                               ipath_user_sdma_queue_clean(dd, pq);
-                       }
-
-                       ret = ipath_user_sdma_push_pkts(dd, pq, &list);
-                       if (ret < 0)
-                               goto done_unlock;
-                       else {
-                               npkts += ret;
-                               pq->counter += ret;
-
-                               if (!list_empty(&list))
-                                       goto done_unlock;
-                       }
-               }
-       }
-
-done_unlock:
-       if (!list_empty(&list))
-               ipath_user_sdma_free_pkt_list(&dd->pcidev->dev, pq, &list);
-       mutex_unlock(&pq->lock);
-
-       return (ret < 0) ? ret : npkts;
-}
-
-int ipath_user_sdma_make_progress(struct ipath_devdata *dd,
-                                 struct ipath_user_sdma_queue *pq)
-{
-       int ret = 0;
-
-       mutex_lock(&pq->lock);
-       ipath_user_sdma_hwqueue_clean(dd);
-       ret = ipath_user_sdma_queue_clean(dd, pq);
-       mutex_unlock(&pq->lock);
-
-       return ret;
-}
-
-u32 ipath_user_sdma_complete_counter(const struct ipath_user_sdma_queue *pq)
-{
-       return pq->sent_counter;
-}
-
-u32 ipath_user_sdma_inflight_counter(struct ipath_user_sdma_queue *pq)
-{
-       return pq->counter;
-}
-
diff --git a/drivers/staging/rdma/ipath/ipath_user_sdma.h b/drivers/staging/rdma/ipath/ipath_user_sdma.h
deleted file mode 100644 (file)
index fc76316..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2007, 2008 QLogic Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <linux/device.h>
-
-struct ipath_user_sdma_queue;
-
-struct ipath_user_sdma_queue *
-ipath_user_sdma_queue_create(struct device *dev, int unit, int port, int sport);
-void ipath_user_sdma_queue_destroy(struct ipath_user_sdma_queue *pq);
-
-int ipath_user_sdma_writev(struct ipath_devdata *dd,
-                          struct ipath_user_sdma_queue *pq,
-                          const struct iovec *iov,
-                          unsigned long dim);
-
-int ipath_user_sdma_make_progress(struct ipath_devdata *dd,
-                                 struct ipath_user_sdma_queue *pq);
-
-void ipath_user_sdma_queue_drain(struct ipath_devdata *dd,
-                                struct ipath_user_sdma_queue *pq);
-
-u32 ipath_user_sdma_complete_counter(const struct ipath_user_sdma_queue *pq);
-u32 ipath_user_sdma_inflight_counter(struct ipath_user_sdma_queue *pq);
diff --git a/drivers/staging/rdma/ipath/ipath_verbs.c b/drivers/staging/rdma/ipath/ipath_verbs.c
deleted file mode 100644 (file)
index 53f9dca..0000000
+++ /dev/null
@@ -1,2376 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <rdma/ib_mad.h>
-#include <rdma/ib_user_verbs.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/utsname.h>
-#include <linux/rculist.h>
-
-#include "ipath_kernel.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-static unsigned int ib_ipath_qp_table_size = 251;
-module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO);
-MODULE_PARM_DESC(qp_table_size, "QP table size");
-
-unsigned int ib_ipath_lkey_table_size = 12;
-module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint,
-                  S_IRUGO);
-MODULE_PARM_DESC(lkey_table_size,
-                "LKEY table size in bits (2^n, 1 <= n <= 23)");
-
-static unsigned int ib_ipath_max_pds = 0xFFFF;
-module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_pds,
-                "Maximum number of protection domains to support");
-
-static unsigned int ib_ipath_max_ahs = 0xFFFF;
-module_param_named(max_ahs, ib_ipath_max_ahs, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_ahs, "Maximum number of address handles to support");
-
-unsigned int ib_ipath_max_cqes = 0x2FFFF;
-module_param_named(max_cqes, ib_ipath_max_cqes, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_cqes,
-                "Maximum number of completion queue entries to support");
-
-unsigned int ib_ipath_max_cqs = 0x1FFFF;
-module_param_named(max_cqs, ib_ipath_max_cqs, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_cqs, "Maximum number of completion queues to support");
-
-unsigned int ib_ipath_max_qp_wrs = 0x3FFF;
-module_param_named(max_qp_wrs, ib_ipath_max_qp_wrs, uint,
-                  S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support");
-
-unsigned int ib_ipath_max_qps = 16384;
-module_param_named(max_qps, ib_ipath_max_qps, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support");
-
-unsigned int ib_ipath_max_sges = 0x60;
-module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support");
-
-unsigned int ib_ipath_max_mcast_grps = 16384;
-module_param_named(max_mcast_grps, ib_ipath_max_mcast_grps, uint,
-                  S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_mcast_grps,
-                "Maximum number of multicast groups to support");
-
-unsigned int ib_ipath_max_mcast_qp_attached = 16;
-module_param_named(max_mcast_qp_attached, ib_ipath_max_mcast_qp_attached,
-                  uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_mcast_qp_attached,
-                "Maximum number of attached QPs to support");
-
-unsigned int ib_ipath_max_srqs = 1024;
-module_param_named(max_srqs, ib_ipath_max_srqs, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_srqs, "Maximum number of SRQs to support");
-
-unsigned int ib_ipath_max_srq_sges = 128;
-module_param_named(max_srq_sges, ib_ipath_max_srq_sges,
-                  uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_srq_sges, "Maximum number of SRQ SGEs to support");
-
-unsigned int ib_ipath_max_srq_wrs = 0x1FFFF;
-module_param_named(max_srq_wrs, ib_ipath_max_srq_wrs,
-                  uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support");
-
-static unsigned int ib_ipath_disable_sma;
-module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(disable_sma, "Disable the SMA");
-
-/*
- * Note that it is OK to post send work requests in the SQE and ERR
- * states; ipath_do_send() will process them and generate error
- * completions as per IB 1.2 C10-96.
- */
-const int ib_ipath_state_ops[IB_QPS_ERR + 1] = {
-       [IB_QPS_RESET] = 0,
-       [IB_QPS_INIT] = IPATH_POST_RECV_OK,
-       [IB_QPS_RTR] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK,
-       [IB_QPS_RTS] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
-           IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK |
-           IPATH_PROCESS_NEXT_SEND_OK,
-       [IB_QPS_SQD] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
-           IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK,
-       [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK |
-           IPATH_POST_SEND_OK | IPATH_FLUSH_SEND,
-       [IB_QPS_ERR] = IPATH_POST_RECV_OK | IPATH_FLUSH_RECV |
-           IPATH_POST_SEND_OK | IPATH_FLUSH_SEND,
-};
-
-struct ipath_ucontext {
-       struct ib_ucontext ibucontext;
-};
-
-static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext
-                                                 *ibucontext)
-{
-       return container_of(ibucontext, struct ipath_ucontext, ibucontext);
-}
-
-/*
- * Translate ib_wr_opcode into ib_wc_opcode.
- */
-const enum ib_wc_opcode ib_ipath_wc_opcode[] = {
-       [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE,
-       [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE,
-       [IB_WR_SEND] = IB_WC_SEND,
-       [IB_WR_SEND_WITH_IMM] = IB_WC_SEND,
-       [IB_WR_RDMA_READ] = IB_WC_RDMA_READ,
-       [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP,
-       [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD
-};
-
-/*
- * System image GUID.
- */
-static __be64 sys_image_guid;
-
-/**
- * ipath_copy_sge - copy data to SGE memory
- * @ss: the SGE state
- * @data: the data to copy
- * @length: the length of the data
- */
-void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length)
-{
-       struct ipath_sge *sge = &ss->sge;
-
-       while (length) {
-               u32 len = sge->length;
-
-               if (len > length)
-                       len = length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               memcpy(sge->vaddr, data, len);
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--ss->num_sge)
-                               *sge = *ss->sg_list++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-               data += len;
-               length -= len;
-       }
-}
-
-/**
- * ipath_skip_sge - skip over SGE memory - XXX almost dup of prev func
- * @ss: the SGE state
- * @length: the number of bytes to skip
- */
-void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
-{
-       struct ipath_sge *sge = &ss->sge;
-
-       while (length) {
-               u32 len = sge->length;
-
-               if (len > length)
-                       len = length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--ss->num_sge)
-                               *sge = *ss->sg_list++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-               length -= len;
-       }
-}
-
-/*
- * Count the number of DMA descriptors needed to send length bytes of data.
- * Don't modify the ipath_sge_state to get the count.
- * Return zero if any of the segments is not aligned.
- */
-static u32 ipath_count_sge(struct ipath_sge_state *ss, u32 length)
-{
-       struct ipath_sge *sg_list = ss->sg_list;
-       struct ipath_sge sge = ss->sge;
-       u8 num_sge = ss->num_sge;
-       u32 ndesc = 1;  /* count the header */
-
-       while (length) {
-               u32 len = sge.length;
-
-               if (len > length)
-                       len = length;
-               if (len > sge.sge_length)
-                       len = sge.sge_length;
-               BUG_ON(len == 0);
-               if (((long) sge.vaddr & (sizeof(u32) - 1)) ||
-                   (len != length && (len & (sizeof(u32) - 1)))) {
-                       ndesc = 0;
-                       break;
-               }
-               ndesc++;
-               sge.vaddr += len;
-               sge.length -= len;
-               sge.sge_length -= len;
-               if (sge.sge_length == 0) {
-                       if (--num_sge)
-                               sge = *sg_list++;
-               } else if (sge.length == 0 && sge.mr != NULL) {
-                       if (++sge.n >= IPATH_SEGSZ) {
-                               if (++sge.m >= sge.mr->mapsz)
-                                       break;
-                               sge.n = 0;
-                       }
-                       sge.vaddr =
-                               sge.mr->map[sge.m]->segs[sge.n].vaddr;
-                       sge.length =
-                               sge.mr->map[sge.m]->segs[sge.n].length;
-               }
-               length -= len;
-       }
-       return ndesc;
-}
-
-/*
- * Copy from the SGEs to the data buffer.
- */
-static void ipath_copy_from_sge(void *data, struct ipath_sge_state *ss,
-                               u32 length)
-{
-       struct ipath_sge *sge = &ss->sge;
-
-       while (length) {
-               u32 len = sge->length;
-
-               if (len > length)
-                       len = length;
-               if (len > sge->sge_length)
-                       len = sge->sge_length;
-               BUG_ON(len == 0);
-               memcpy(data, sge->vaddr, len);
-               sge->vaddr += len;
-               sge->length -= len;
-               sge->sge_length -= len;
-               if (sge->sge_length == 0) {
-                       if (--ss->num_sge)
-                               *sge = *ss->sg_list++;
-               } else if (sge->length == 0 && sge->mr != NULL) {
-                       if (++sge->n >= IPATH_SEGSZ) {
-                               if (++sge->m >= sge->mr->mapsz)
-                                       break;
-                               sge->n = 0;
-                       }
-                       sge->vaddr =
-                               sge->mr->map[sge->m]->segs[sge->n].vaddr;
-                       sge->length =
-                               sge->mr->map[sge->m]->segs[sge->n].length;
-               }
-               data += len;
-               length -= len;
-       }
-}
-
-/**
- * ipath_post_one_send - post one RC, UC, or UD send work request
- * @qp: the QP to post on
- * @wr: the work request to send
- */
-static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
-{
-       struct ipath_swqe *wqe;
-       u32 next;
-       int i;
-       int j;
-       int acc;
-       int ret;
-       unsigned long flags;
-       struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
-
-       spin_lock_irqsave(&qp->s_lock, flags);
-
-       if (qp->ibqp.qp_type != IB_QPT_SMI &&
-           !(dd->ipath_flags & IPATH_LINKACTIVE)) {
-               ret = -ENETDOWN;
-               goto bail;
-       }
-
-       /* Check that state is OK to post send. */
-       if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)))
-               goto bail_inval;
-
-       /* IB spec says that num_sge == 0 is OK. */
-       if (wr->num_sge > qp->s_max_sge)
-               goto bail_inval;
-
-       /*
-        * Don't allow RDMA reads or atomic operations on UC or
-        * undefined operations.
-        * Make sure buffer is large enough to hold the result for atomics.
-        */
-       if (qp->ibqp.qp_type == IB_QPT_UC) {
-               if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
-                       goto bail_inval;
-       } else if (qp->ibqp.qp_type == IB_QPT_UD) {
-               /* Check UD opcode */
-               if (wr->opcode != IB_WR_SEND &&
-                   wr->opcode != IB_WR_SEND_WITH_IMM)
-                       goto bail_inval;
-               /* Check UD destination address PD */
-               if (qp->ibqp.pd != ud_wr(wr)->ah->pd)
-                       goto bail_inval;
-       } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
-               goto bail_inval;
-       else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
-                  (wr->num_sge == 0 ||
-                   wr->sg_list[0].length < sizeof(u64) ||
-                   wr->sg_list[0].addr & (sizeof(u64) - 1)))
-               goto bail_inval;
-       else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
-               goto bail_inval;
-
-       next = qp->s_head + 1;
-       if (next >= qp->s_size)
-               next = 0;
-       if (next == qp->s_last) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       wqe = get_swqe_ptr(qp, qp->s_head);
-
-       if (qp->ibqp.qp_type != IB_QPT_UC &&
-           qp->ibqp.qp_type != IB_QPT_RC)
-               memcpy(&wqe->ud_wr, ud_wr(wr), sizeof(wqe->ud_wr));
-       else if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM ||
-                wr->opcode == IB_WR_RDMA_WRITE ||
-                wr->opcode == IB_WR_RDMA_READ)
-               memcpy(&wqe->rdma_wr, rdma_wr(wr), sizeof(wqe->rdma_wr));
-       else if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
-                wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
-               memcpy(&wqe->atomic_wr, atomic_wr(wr), sizeof(wqe->atomic_wr));
-       else
-               memcpy(&wqe->wr, wr, sizeof(wqe->wr));
-
-       wqe->length = 0;
-       if (wr->num_sge) {
-               acc = wr->opcode >= IB_WR_RDMA_READ ?
-                       IB_ACCESS_LOCAL_WRITE : 0;
-               for (i = 0, j = 0; i < wr->num_sge; i++) {
-                       u32 length = wr->sg_list[i].length;
-                       int ok;
-
-                       if (length == 0)
-                               continue;
-                       ok = ipath_lkey_ok(qp, &wqe->sg_list[j],
-                                          &wr->sg_list[i], acc);
-                       if (!ok)
-                               goto bail_inval;
-                       wqe->length += length;
-                       j++;
-               }
-               wqe->wr.num_sge = j;
-       }
-       if (qp->ibqp.qp_type == IB_QPT_UC ||
-           qp->ibqp.qp_type == IB_QPT_RC) {
-               if (wqe->length > 0x80000000U)
-                       goto bail_inval;
-       } else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
-               goto bail_inval;
-       wqe->ssn = qp->s_ssn++;
-       qp->s_head = next;
-
-       ret = 0;
-       goto bail;
-
-bail_inval:
-       ret = -EINVAL;
-bail:
-       spin_unlock_irqrestore(&qp->s_lock, flags);
-       return ret;
-}
-
-/**
- * ipath_post_send - post a send on a QP
- * @ibqp: the QP to post the send on
- * @wr: the list of work requests to post
- * @bad_wr: the first bad WR is put here
- *
- * This may be called from interrupt context.
- */
-static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
-                          struct ib_send_wr **bad_wr)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-       int err = 0;
-
-       for (; wr; wr = wr->next) {
-               err = ipath_post_one_send(qp, wr);
-               if (err) {
-                       *bad_wr = wr;
-                       goto bail;
-               }
-       }
-
-       /* Try to do the send work in the caller's context. */
-       ipath_do_send((unsigned long) qp);
-
-bail:
-       return err;
-}
-
-/**
- * ipath_post_receive - post a receive on a QP
- * @ibqp: the QP to post the receive on
- * @wr: the WR to post
- * @bad_wr: the first bad WR is put here
- *
- * This may be called from interrupt context.
- */
-static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
-                             struct ib_recv_wr **bad_wr)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-       struct ipath_rwq *wq = qp->r_rq.wq;
-       unsigned long flags;
-       int ret;
-
-       /* Check that state is OK to post receive. */
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK) || !wq) {
-               *bad_wr = wr;
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       for (; wr; wr = wr->next) {
-               struct ipath_rwqe *wqe;
-               u32 next;
-               int i;
-
-               if ((unsigned) wr->num_sge > qp->r_rq.max_sge) {
-                       *bad_wr = wr;
-                       ret = -EINVAL;
-                       goto bail;
-               }
-
-               spin_lock_irqsave(&qp->r_rq.lock, flags);
-               next = wq->head + 1;
-               if (next >= qp->r_rq.size)
-                       next = 0;
-               if (next == wq->tail) {
-                       spin_unlock_irqrestore(&qp->r_rq.lock, flags);
-                       *bad_wr = wr;
-                       ret = -ENOMEM;
-                       goto bail;
-               }
-
-               wqe = get_rwqe_ptr(&qp->r_rq, wq->head);
-               wqe->wr_id = wr->wr_id;
-               wqe->num_sge = wr->num_sge;
-               for (i = 0; i < wr->num_sge; i++)
-                       wqe->sg_list[i] = wr->sg_list[i];
-               /* Make sure queue entry is written before the head index. */
-               smp_wmb();
-               wq->head = next;
-               spin_unlock_irqrestore(&qp->r_rq.lock, flags);
-       }
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_qp_rcv - processing an incoming packet on a QP
- * @dev: the device the packet came on
- * @hdr: the packet header
- * @has_grh: true if the packet has a GRH
- * @data: the packet data
- * @tlen: the packet length
- * @qp: the QP the packet came on
- *
- * This is called from ipath_ib_rcv() to process an incoming packet
- * for the given QP.
- * Called at interrupt level.
- */
-static void ipath_qp_rcv(struct ipath_ibdev *dev,
-                        struct ipath_ib_header *hdr, int has_grh,
-                        void *data, u32 tlen, struct ipath_qp *qp)
-{
-       /* Check for valid receive state. */
-       if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) {
-               dev->n_pkt_drops++;
-               return;
-       }
-
-       switch (qp->ibqp.qp_type) {
-       case IB_QPT_SMI:
-       case IB_QPT_GSI:
-               if (ib_ipath_disable_sma)
-                       break;
-               /* FALLTHROUGH */
-       case IB_QPT_UD:
-               ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp);
-               break;
-
-       case IB_QPT_RC:
-               ipath_rc_rcv(dev, hdr, has_grh, data, tlen, qp);
-               break;
-
-       case IB_QPT_UC:
-               ipath_uc_rcv(dev, hdr, has_grh, data, tlen, qp);
-               break;
-
-       default:
-               break;
-       }
-}
-
-/**
- * ipath_ib_rcv - process an incoming packet
- * @arg: the device pointer
- * @rhdr: the header of the packet
- * @data: the packet data
- * @tlen: the packet length
- *
- * This is called from ipath_kreceive() to process an incoming packet at
- * interrupt level. Tlen is the length of the header + data + CRC in bytes.
- */
-void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
-                 u32 tlen)
-{
-       struct ipath_ib_header *hdr = rhdr;
-       struct ipath_other_headers *ohdr;
-       struct ipath_qp *qp;
-       u32 qp_num;
-       int lnh;
-       u8 opcode;
-       u16 lid;
-
-       if (unlikely(dev == NULL))
-               goto bail;
-
-       if (unlikely(tlen < 24)) {      /* LRH+BTH+CRC */
-               dev->rcv_errors++;
-               goto bail;
-       }
-
-       /* Check for a valid destination LID (see ch. 7.11.1). */
-       lid = be16_to_cpu(hdr->lrh[1]);
-       if (lid < IPATH_MULTICAST_LID_BASE) {
-               lid &= ~((1 << dev->dd->ipath_lmc) - 1);
-               if (unlikely(lid != dev->dd->ipath_lid)) {
-                       dev->rcv_errors++;
-                       goto bail;
-               }
-       }
-
-       /* Check for GRH */
-       lnh = be16_to_cpu(hdr->lrh[0]) & 3;
-       if (lnh == IPATH_LRH_BTH)
-               ohdr = &hdr->u.oth;
-       else if (lnh == IPATH_LRH_GRH)
-               ohdr = &hdr->u.l.oth;
-       else {
-               dev->rcv_errors++;
-               goto bail;
-       }
-
-       opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f;
-       dev->opstats[opcode].n_bytes += tlen;
-       dev->opstats[opcode].n_packets++;
-
-       /* Get the destination QP number. */
-       qp_num = be32_to_cpu(ohdr->bth[1]) & IPATH_QPN_MASK;
-       if (qp_num == IPATH_MULTICAST_QPN) {
-               struct ipath_mcast *mcast;
-               struct ipath_mcast_qp *p;
-
-               if (lnh != IPATH_LRH_GRH) {
-                       dev->n_pkt_drops++;
-                       goto bail;
-               }
-               mcast = ipath_mcast_find(&hdr->u.l.grh.dgid);
-               if (mcast == NULL) {
-                       dev->n_pkt_drops++;
-                       goto bail;
-               }
-               dev->n_multicast_rcv++;
-               list_for_each_entry_rcu(p, &mcast->qp_list, list)
-                       ipath_qp_rcv(dev, hdr, 1, data, tlen, p->qp);
-               /*
-                * Notify ipath_multicast_detach() if it is waiting for us
-                * to finish.
-                */
-               if (atomic_dec_return(&mcast->refcount) <= 1)
-                       wake_up(&mcast->wait);
-       } else {
-               qp = ipath_lookup_qpn(&dev->qp_table, qp_num);
-               if (qp) {
-                       dev->n_unicast_rcv++;
-                       ipath_qp_rcv(dev, hdr, lnh == IPATH_LRH_GRH, data,
-                                    tlen, qp);
-                       /*
-                        * Notify ipath_destroy_qp() if it is waiting
-                        * for us to finish.
-                        */
-                       if (atomic_dec_and_test(&qp->refcount))
-                               wake_up(&qp->wait);
-               } else
-                       dev->n_pkt_drops++;
-       }
-
-bail:;
-}
-
-/**
- * ipath_ib_timer - verbs timer
- * @arg: the device pointer
- *
- * This is called from ipath_do_rcv_timer() at interrupt level to check for
- * QPs which need retransmits and to collect performance numbers.
- */
-static void ipath_ib_timer(struct ipath_ibdev *dev)
-{
-       struct ipath_qp *resend = NULL;
-       struct ipath_qp *rnr = NULL;
-       struct list_head *last;
-       struct ipath_qp *qp;
-       unsigned long flags;
-
-       if (dev == NULL)
-               return;
-
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       /* Start filling the next pending queue. */
-       if (++dev->pending_index >= ARRAY_SIZE(dev->pending))
-               dev->pending_index = 0;
-       /* Save any requests still in the new queue, they have timed out. */
-       last = &dev->pending[dev->pending_index];
-       while (!list_empty(last)) {
-               qp = list_entry(last->next, struct ipath_qp, timerwait);
-               list_del_init(&qp->timerwait);
-               qp->timer_next = resend;
-               resend = qp;
-               atomic_inc(&qp->refcount);
-       }
-       last = &dev->rnrwait;
-       if (!list_empty(last)) {
-               qp = list_entry(last->next, struct ipath_qp, timerwait);
-               if (--qp->s_rnr_timeout == 0) {
-                       do {
-                               list_del_init(&qp->timerwait);
-                               qp->timer_next = rnr;
-                               rnr = qp;
-                               atomic_inc(&qp->refcount);
-                               if (list_empty(last))
-                                       break;
-                               qp = list_entry(last->next, struct ipath_qp,
-                                               timerwait);
-                       } while (qp->s_rnr_timeout == 0);
-               }
-       }
-       /*
-        * We should only be in the started state if pma_sample_start != 0
-        */
-       if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED &&
-           --dev->pma_sample_start == 0) {
-               dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
-               ipath_snapshot_counters(dev->dd, &dev->ipath_sword,
-                                       &dev->ipath_rword,
-                                       &dev->ipath_spkts,
-                                       &dev->ipath_rpkts,
-                                       &dev->ipath_xmit_wait);
-       }
-       if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) {
-               if (dev->pma_sample_interval == 0) {
-                       u64 ta, tb, tc, td, te;
-
-                       dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
-                       ipath_snapshot_counters(dev->dd, &ta, &tb,
-                                               &tc, &td, &te);
-
-                       dev->ipath_sword = ta - dev->ipath_sword;
-                       dev->ipath_rword = tb - dev->ipath_rword;
-                       dev->ipath_spkts = tc - dev->ipath_spkts;
-                       dev->ipath_rpkts = td - dev->ipath_rpkts;
-                       dev->ipath_xmit_wait = te - dev->ipath_xmit_wait;
-               } else {
-                       dev->pma_sample_interval--;
-               }
-       }
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-
-       /* XXX What if timer fires again while this is running? */
-       while (resend != NULL) {
-               qp = resend;
-               resend = qp->timer_next;
-
-               spin_lock_irqsave(&qp->s_lock, flags);
-               if (qp->s_last != qp->s_tail &&
-                   ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) {
-                       dev->n_timeouts++;
-                       ipath_restart_rc(qp, qp->s_last_psn + 1);
-               }
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-
-               /* Notify ipath_destroy_qp() if it is waiting. */
-               if (atomic_dec_and_test(&qp->refcount))
-                       wake_up(&qp->wait);
-       }
-       while (rnr != NULL) {
-               qp = rnr;
-               rnr = qp->timer_next;
-
-               spin_lock_irqsave(&qp->s_lock, flags);
-               if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)
-                       ipath_schedule_send(qp);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-
-               /* Notify ipath_destroy_qp() if it is waiting. */
-               if (atomic_dec_and_test(&qp->refcount))
-                       wake_up(&qp->wait);
-       }
-}
-
-static void update_sge(struct ipath_sge_state *ss, u32 length)
-{
-       struct ipath_sge *sge = &ss->sge;
-
-       sge->vaddr += length;
-       sge->length -= length;
-       sge->sge_length -= length;
-       if (sge->sge_length == 0) {
-               if (--ss->num_sge)
-                       *sge = *ss->sg_list++;
-       } else if (sge->length == 0 && sge->mr != NULL) {
-               if (++sge->n >= IPATH_SEGSZ) {
-                       if (++sge->m >= sge->mr->mapsz)
-                               return;
-                       sge->n = 0;
-               }
-               sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
-               sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
-       }
-}
-
-#ifdef __LITTLE_ENDIAN
-static inline u32 get_upper_bits(u32 data, u32 shift)
-{
-       return data >> shift;
-}
-
-static inline u32 set_upper_bits(u32 data, u32 shift)
-{
-       return data << shift;
-}
-
-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
-{
-       data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
-       data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
-       return data;
-}
-#else
-static inline u32 get_upper_bits(u32 data, u32 shift)
-{
-       return data << shift;
-}
-
-static inline u32 set_upper_bits(u32 data, u32 shift)
-{
-       return data >> shift;
-}
-
-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
-{
-       data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
-       data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
-       return data;
-}
-#endif
-
-static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
-                   u32 length, unsigned flush_wc)
-{
-       u32 extra = 0;
-       u32 data = 0;
-       u32 last;
-
-       while (1) {
-               u32 len = ss->sge.length;
-               u32 off;
-
-               if (len > length)
-                       len = length;
-               if (len > ss->sge.sge_length)
-                       len = ss->sge.sge_length;
-               BUG_ON(len == 0);
-               /* If the source address is not aligned, try to align it. */
-               off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
-               if (off) {
-                       u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
-                                           ~(sizeof(u32) - 1));
-                       u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
-                       u32 y;
-
-                       y = sizeof(u32) - off;
-                       if (len > y)
-                               len = y;
-                       if (len + extra >= sizeof(u32)) {
-                               data |= set_upper_bits(v, extra *
-                                                      BITS_PER_BYTE);
-                               len = sizeof(u32) - extra;
-                               if (len == length) {
-                                       last = data;
-                                       break;
-                               }
-                               __raw_writel(data, piobuf);
-                               piobuf++;
-                               extra = 0;
-                               data = 0;
-                       } else {
-                               /* Clear unused upper bytes */
-                               data |= clear_upper_bytes(v, len, extra);
-                               if (len == length) {
-                                       last = data;
-                                       break;
-                               }
-                               extra += len;
-                       }
-               } else if (extra) {
-                       /* Source address is aligned. */
-                       u32 *addr = (u32 *) ss->sge.vaddr;
-                       int shift = extra * BITS_PER_BYTE;
-                       int ushift = 32 - shift;
-                       u32 l = len;
-
-                       while (l >= sizeof(u32)) {
-                               u32 v = *addr;
-
-                               data |= set_upper_bits(v, shift);
-                               __raw_writel(data, piobuf);
-                               data = get_upper_bits(v, ushift);
-                               piobuf++;
-                               addr++;
-                               l -= sizeof(u32);
-                       }
-                       /*
-                        * We still have 'extra' number of bytes leftover.
-                        */
-                       if (l) {
-                               u32 v = *addr;
-
-                               if (l + extra >= sizeof(u32)) {
-                                       data |= set_upper_bits(v, shift);
-                                       len -= l + extra - sizeof(u32);
-                                       if (len == length) {
-                                               last = data;
-                                               break;
-                                       }
-                                       __raw_writel(data, piobuf);
-                                       piobuf++;
-                                       extra = 0;
-                                       data = 0;
-                               } else {
-                                       /* Clear unused upper bytes */
-                                       data |= clear_upper_bytes(v, l,
-                                                                 extra);
-                                       if (len == length) {
-                                               last = data;
-                                               break;
-                                       }
-                                       extra += l;
-                               }
-                       } else if (len == length) {
-                               last = data;
-                               break;
-                       }
-               } else if (len == length) {
-                       u32 w;
-
-                       /*
-                        * Need to round up for the last dword in the
-                        * packet.
-                        */
-                       w = (len + 3) >> 2;
-                       __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
-                       piobuf += w - 1;
-                       last = ((u32 *) ss->sge.vaddr)[w - 1];
-                       break;
-               } else {
-                       u32 w = len >> 2;
-
-                       __iowrite32_copy(piobuf, ss->sge.vaddr, w);
-                       piobuf += w;
-
-                       extra = len & (sizeof(u32) - 1);
-                       if (extra) {
-                               u32 v = ((u32 *) ss->sge.vaddr)[w];
-
-                               /* Clear unused upper bytes */
-                               data = clear_upper_bytes(v, extra, 0);
-                       }
-               }
-               update_sge(ss, len);
-               length -= len;
-       }
-       /* Update address before sending packet. */
-       update_sge(ss, length);
-       if (flush_wc) {
-               /* must flush early everything before trigger word */
-               ipath_flush_wc();
-               __raw_writel(last, piobuf);
-               /* be sure trigger word is written */
-               ipath_flush_wc();
-       } else
-               __raw_writel(last, piobuf);
-}
-
-/*
- * Convert IB rate to delay multiplier.
- */
-unsigned ipath_ib_rate_to_mult(enum ib_rate rate)
-{
-       switch (rate) {
-       case IB_RATE_2_5_GBPS: return 8;
-       case IB_RATE_5_GBPS:   return 4;
-       case IB_RATE_10_GBPS:  return 2;
-       case IB_RATE_20_GBPS:  return 1;
-       default:               return 0;
-       }
-}
-
-/*
- * Convert delay multiplier to IB rate
- */
-static enum ib_rate ipath_mult_to_ib_rate(unsigned mult)
-{
-       switch (mult) {
-       case 8:  return IB_RATE_2_5_GBPS;
-       case 4:  return IB_RATE_5_GBPS;
-       case 2:  return IB_RATE_10_GBPS;
-       case 1:  return IB_RATE_20_GBPS;
-       default: return IB_RATE_PORT_CURRENT;
-       }
-}
-
-static inline struct ipath_verbs_txreq *get_txreq(struct ipath_ibdev *dev)
-{
-       struct ipath_verbs_txreq *tx = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       if (!list_empty(&dev->txreq_free)) {
-               struct list_head *l = dev->txreq_free.next;
-
-               list_del(l);
-               tx = list_entry(l, struct ipath_verbs_txreq, txreq.list);
-       }
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-       return tx;
-}
-
-static inline void put_txreq(struct ipath_ibdev *dev,
-                            struct ipath_verbs_txreq *tx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       list_add(&tx->txreq.list, &dev->txreq_free);
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-}
-
-static void sdma_complete(void *cookie, int status)
-{
-       struct ipath_verbs_txreq *tx = cookie;
-       struct ipath_qp *qp = tx->qp;
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       unsigned long flags;
-       enum ib_wc_status ibs = status == IPATH_SDMA_TXREQ_S_OK ?
-               IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR;
-
-       if (atomic_dec_and_test(&qp->s_dma_busy)) {
-               spin_lock_irqsave(&qp->s_lock, flags);
-               if (tx->wqe)
-                       ipath_send_complete(qp, tx->wqe, ibs);
-               if ((ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND &&
-                    qp->s_last != qp->s_head) ||
-                   (qp->s_flags & IPATH_S_WAIT_DMA))
-                       ipath_schedule_send(qp);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-               wake_up(&qp->wait_dma);
-       } else if (tx->wqe) {
-               spin_lock_irqsave(&qp->s_lock, flags);
-               ipath_send_complete(qp, tx->wqe, ibs);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-       }
-
-       if (tx->txreq.flags & IPATH_SDMA_TXREQ_F_FREEBUF)
-               kfree(tx->txreq.map_addr);
-       put_txreq(dev, tx);
-
-       if (atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-}
-
-static void decrement_dma_busy(struct ipath_qp *qp)
-{
-       unsigned long flags;
-
-       if (atomic_dec_and_test(&qp->s_dma_busy)) {
-               spin_lock_irqsave(&qp->s_lock, flags);
-               if ((ib_ipath_state_ops[qp->state] & IPATH_FLUSH_SEND &&
-                    qp->s_last != qp->s_head) ||
-                   (qp->s_flags & IPATH_S_WAIT_DMA))
-                       ipath_schedule_send(qp);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-               wake_up(&qp->wait_dma);
-       }
-}
-
-/*
- * Compute the number of clock cycles of delay before sending the next packet.
- * The multipliers reflect the number of clocks for the fastest rate so
- * one tick at 4xDDR is 8 ticks at 1xSDR.
- * If the destination port will take longer to receive a packet than
- * the outgoing link can send it, we need to delay sending the next packet
- * by the difference in time it takes the receiver to receive and the sender
- * to send this packet.
- * Note that this delay is always correct for UC and RC but not always
- * optimal for UD. For UD, the destination HCA can be different for each
- * packet, in which case, we could send packets to a different destination
- * while "waiting" for the delay. The overhead for doing this without
- * HW support is more than just paying the cost of delaying some packets
- * unnecessarily.
- */
-static inline unsigned ipath_pkt_delay(u32 plen, u8 snd_mult, u8 rcv_mult)
-{
-       return (rcv_mult > snd_mult) ?
-               (plen * (rcv_mult - snd_mult) + 1) >> 1 : 0;
-}
-
-static int ipath_verbs_send_dma(struct ipath_qp *qp,
-                               struct ipath_ib_header *hdr, u32 hdrwords,
-                               struct ipath_sge_state *ss, u32 len,
-                               u32 plen, u32 dwords)
-{
-       struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-       struct ipath_devdata *dd = dev->dd;
-       struct ipath_verbs_txreq *tx;
-       u32 *piobuf;
-       u32 control;
-       u32 ndesc;
-       int ret;
-
-       tx = qp->s_tx;
-       if (tx) {
-               qp->s_tx = NULL;
-               /* resend previously constructed packet */
-               atomic_inc(&qp->s_dma_busy);
-               ret = ipath_sdma_verbs_send(dd, tx->ss, tx->len, tx);
-               if (ret) {
-                       qp->s_tx = tx;
-                       decrement_dma_busy(qp);
-               }
-               goto bail;
-       }
-
-       tx = get_txreq(dev);
-       if (!tx) {
-               ret = -EBUSY;
-               goto bail;
-       }
-
-       /*
-        * Get the saved delay count we computed for the previous packet
-        * and save the delay count for this packet to be used next time
-        * we get here.
-        */
-       control = qp->s_pkt_delay;
-       qp->s_pkt_delay = ipath_pkt_delay(plen, dd->delay_mult, qp->s_dmult);
-
-       tx->qp = qp;
-       atomic_inc(&qp->refcount);
-       tx->wqe = qp->s_wqe;
-       tx->txreq.callback = sdma_complete;
-       tx->txreq.callback_cookie = tx;
-       tx->txreq.flags = IPATH_SDMA_TXREQ_F_HEADTOHOST |
-               IPATH_SDMA_TXREQ_F_INTREQ | IPATH_SDMA_TXREQ_F_FREEDESC;
-       if (plen + 1 >= IPATH_SMALLBUF_DWORDS)
-               tx->txreq.flags |= IPATH_SDMA_TXREQ_F_USELARGEBUF;
-
-       /* VL15 packets bypass credit check */
-       if ((be16_to_cpu(hdr->lrh[0]) >> 12) == 15) {
-               control |= 1ULL << 31;
-               tx->txreq.flags |= IPATH_SDMA_TXREQ_F_VL15;
-       }
-
-       if (len) {
-               /*
-                * Don't try to DMA if it takes more descriptors than
-                * the queue holds.
-                */
-               ndesc = ipath_count_sge(ss, len);
-               if (ndesc >= dd->ipath_sdma_descq_cnt)
-                       ndesc = 0;
-       } else
-               ndesc = 1;
-       if (ndesc) {
-               tx->hdr.pbc[0] = cpu_to_le32(plen);
-               tx->hdr.pbc[1] = cpu_to_le32(control);
-               memcpy(&tx->hdr.hdr, hdr, hdrwords << 2);
-               tx->txreq.sg_count = ndesc;
-               tx->map_len = (hdrwords + 2) << 2;
-               tx->txreq.map_addr = &tx->hdr;
-               atomic_inc(&qp->s_dma_busy);
-               ret = ipath_sdma_verbs_send(dd, ss, dwords, tx);
-               if (ret) {
-                       /* save ss and length in dwords */
-                       tx->ss = ss;
-                       tx->len = dwords;
-                       qp->s_tx = tx;
-                       decrement_dma_busy(qp);
-               }
-               goto bail;
-       }
-
-       /* Allocate a buffer and copy the header and payload to it. */
-       tx->map_len = (plen + 1) << 2;
-       piobuf = kmalloc(tx->map_len, GFP_ATOMIC);
-       if (unlikely(piobuf == NULL)) {
-               ret = -EBUSY;
-               goto err_tx;
-       }
-       tx->txreq.map_addr = piobuf;
-       tx->txreq.flags |= IPATH_SDMA_TXREQ_F_FREEBUF;
-       tx->txreq.sg_count = 1;
-
-       *piobuf++ = (__force u32) cpu_to_le32(plen);
-       *piobuf++ = (__force u32) cpu_to_le32(control);
-       memcpy(piobuf, hdr, hdrwords << 2);
-       ipath_copy_from_sge(piobuf + hdrwords, ss, len);
-
-       atomic_inc(&qp->s_dma_busy);
-       ret = ipath_sdma_verbs_send(dd, NULL, 0, tx);
-       /*
-        * If we couldn't queue the DMA request, save the info
-        * and try again later rather than destroying the
-        * buffer and undoing the side effects of the copy.
-        */
-       if (ret) {
-               tx->ss = NULL;
-               tx->len = 0;
-               qp->s_tx = tx;
-               decrement_dma_busy(qp);
-       }
-       dev->n_unaligned++;
-       goto bail;
-
-err_tx:
-       if (atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-       put_txreq(dev, tx);
-bail:
-       return ret;
-}
-
-static int ipath_verbs_send_pio(struct ipath_qp *qp,
-                               struct ipath_ib_header *ibhdr, u32 hdrwords,
-                               struct ipath_sge_state *ss, u32 len,
-                               u32 plen, u32 dwords)
-{
-       struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
-       u32 *hdr = (u32 *) ibhdr;
-       u32 __iomem *piobuf;
-       unsigned flush_wc;
-       u32 control;
-       int ret;
-       unsigned long flags;
-
-       piobuf = ipath_getpiobuf(dd, plen, NULL);
-       if (unlikely(piobuf == NULL)) {
-               ret = -EBUSY;
-               goto bail;
-       }
-
-       /*
-        * Get the saved delay count we computed for the previous packet
-        * and save the delay count for this packet to be used next time
-        * we get here.
-        */
-       control = qp->s_pkt_delay;
-       qp->s_pkt_delay = ipath_pkt_delay(plen, dd->delay_mult, qp->s_dmult);
-
-       /* VL15 packets bypass credit check */
-       if ((be16_to_cpu(ibhdr->lrh[0]) >> 12) == 15)
-               control |= 1ULL << 31;
-
-       /*
-        * Write the length to the control qword plus any needed flags.
-        * We have to flush after the PBC for correctness on some cpus
-        * or WC buffer can be written out of order.
-        */
-       writeq(((u64) control << 32) | plen, piobuf);
-       piobuf += 2;
-
-       flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC;
-       if (len == 0) {
-               /*
-                * If there is just the header portion, must flush before
-                * writing last word of header for correctness, and after
-                * the last header word (trigger word).
-                */
-               if (flush_wc) {
-                       ipath_flush_wc();
-                       __iowrite32_copy(piobuf, hdr, hdrwords - 1);
-                       ipath_flush_wc();
-                       __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
-                       ipath_flush_wc();
-               } else
-                       __iowrite32_copy(piobuf, hdr, hdrwords);
-               goto done;
-       }
-
-       if (flush_wc)
-               ipath_flush_wc();
-       __iowrite32_copy(piobuf, hdr, hdrwords);
-       piobuf += hdrwords;
-
-       /* The common case is aligned and contained in one segment. */
-       if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
-                  !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
-               u32 *addr = (u32 *) ss->sge.vaddr;
-
-               /* Update address before sending packet. */
-               update_sge(ss, len);
-               if (flush_wc) {
-                       __iowrite32_copy(piobuf, addr, dwords - 1);
-                       /* must flush early everything before trigger word */
-                       ipath_flush_wc();
-                       __raw_writel(addr[dwords - 1], piobuf + dwords - 1);
-                       /* be sure trigger word is written */
-                       ipath_flush_wc();
-               } else
-                       __iowrite32_copy(piobuf, addr, dwords);
-               goto done;
-       }
-       copy_io(piobuf, ss, len, flush_wc);
-done:
-       if (qp->s_wqe) {
-               spin_lock_irqsave(&qp->s_lock, flags);
-               ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-       }
-       ret = 0;
-bail:
-       return ret;
-}
-
-/**
- * ipath_verbs_send - send a packet
- * @qp: the QP to send on
- * @hdr: the packet header
- * @hdrwords: the number of 32-bit words in the header
- * @ss: the SGE to send
- * @len: the length of the packet in bytes
- */
-int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
-                    u32 hdrwords, struct ipath_sge_state *ss, u32 len)
-{
-       struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
-       u32 plen;
-       int ret;
-       u32 dwords = (len + 3) >> 2;
-
-       /*
-        * Calculate the send buffer trigger address.
-        * The +1 counts for the pbc control dword following the pbc length.
-        */
-       plen = hdrwords + dwords + 1;
-
-       /*
-        * VL15 packets (IB_QPT_SMI) will always use PIO, so we
-        * can defer SDMA restart until link goes ACTIVE without
-        * worrying about just how we got there.
-        */
-       if (qp->ibqp.qp_type == IB_QPT_SMI ||
-           !(dd->ipath_flags & IPATH_HAS_SEND_DMA))
-               ret = ipath_verbs_send_pio(qp, hdr, hdrwords, ss, len,
-                                          plen, dwords);
-       else
-               ret = ipath_verbs_send_dma(qp, hdr, hdrwords, ss, len,
-                                          plen, dwords);
-
-       return ret;
-}
-
-int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
-                           u64 *rwords, u64 *spkts, u64 *rpkts,
-                           u64 *xmit_wait)
-{
-       int ret;
-
-       if (!(dd->ipath_flags & IPATH_INITTED)) {
-               /* no hardware, freeze, etc. */
-               ret = -EINVAL;
-               goto bail;
-       }
-       *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
-       *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
-       *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
-       *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
-       *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt);
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_get_counters - get various chip counters
- * @dd: the infinipath device
- * @cntrs: counters are placed here
- *
- * Return the counters needed by recv_pma_get_portcounters().
- */
-int ipath_get_counters(struct ipath_devdata *dd,
-                      struct ipath_verbs_counters *cntrs)
-{
-       struct ipath_cregs const *crp = dd->ipath_cregs;
-       int ret;
-
-       if (!(dd->ipath_flags & IPATH_INITTED)) {
-               /* no hardware, freeze, etc. */
-               ret = -EINVAL;
-               goto bail;
-       }
-       cntrs->symbol_error_counter =
-               ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt);
-       cntrs->link_error_recovery_counter =
-               ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt);
-       /*
-        * The link downed counter counts when the other side downs the
-        * connection.  We add in the number of times we downed the link
-        * due to local link integrity errors to compensate.
-        */
-       cntrs->link_downed_counter =
-               ipath_snap_cntr(dd, crp->cr_iblinkdowncnt);
-       cntrs->port_rcv_errors =
-               ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) +
-               ipath_snap_cntr(dd, crp->cr_rcvovflcnt) +
-               ipath_snap_cntr(dd, crp->cr_portovflcnt) +
-               ipath_snap_cntr(dd, crp->cr_err_rlencnt) +
-               ipath_snap_cntr(dd, crp->cr_invalidrlencnt) +
-               ipath_snap_cntr(dd, crp->cr_errlinkcnt) +
-               ipath_snap_cntr(dd, crp->cr_erricrccnt) +
-               ipath_snap_cntr(dd, crp->cr_errvcrccnt) +
-               ipath_snap_cntr(dd, crp->cr_errlpcrccnt) +
-               ipath_snap_cntr(dd, crp->cr_badformatcnt) +
-               dd->ipath_rxfc_unsupvl_errs;
-       if (crp->cr_rxotherlocalphyerrcnt)
-               cntrs->port_rcv_errors +=
-                       ipath_snap_cntr(dd, crp->cr_rxotherlocalphyerrcnt);
-       if (crp->cr_rxvlerrcnt)
-               cntrs->port_rcv_errors +=
-                       ipath_snap_cntr(dd, crp->cr_rxvlerrcnt);
-       cntrs->port_rcv_remphys_errors =
-               ipath_snap_cntr(dd, crp->cr_rcvebpcnt);
-       cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt);
-       cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt);
-       cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt);
-       cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt);
-       cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt);
-       cntrs->local_link_integrity_errors =
-               crp->cr_locallinkintegrityerrcnt ?
-               ipath_snap_cntr(dd, crp->cr_locallinkintegrityerrcnt) :
-               ((dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
-                dd->ipath_lli_errs : dd->ipath_lli_errors);
-       cntrs->excessive_buffer_overrun_errors =
-               crp->cr_excessbufferovflcnt ?
-               ipath_snap_cntr(dd, crp->cr_excessbufferovflcnt) :
-               dd->ipath_overrun_thresh_errs;
-       cntrs->vl15_dropped = crp->cr_vl15droppedpktcnt ?
-               ipath_snap_cntr(dd, crp->cr_vl15droppedpktcnt) : 0;
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_ib_piobufavail - callback when a PIO buffer is available
- * @arg: the device pointer
- *
- * This is called from ipath_intr() at interrupt level when a PIO buffer is
- * available after ipath_verbs_send() returned an error that no buffers were
- * available.  Return 1 if we consumed all the PIO buffers and we still have
- * QPs waiting for buffers (for now, just restart the send tasklet and
- * return zero).
- */
-int ipath_ib_piobufavail(struct ipath_ibdev *dev)
-{
-       struct list_head *list;
-       struct ipath_qp *qplist;
-       struct ipath_qp *qp;
-       unsigned long flags;
-
-       if (dev == NULL)
-               goto bail;
-
-       list = &dev->piowait;
-       qplist = NULL;
-
-       spin_lock_irqsave(&dev->pending_lock, flags);
-       while (!list_empty(list)) {
-               qp = list_entry(list->next, struct ipath_qp, piowait);
-               list_del_init(&qp->piowait);
-               qp->pio_next = qplist;
-               qplist = qp;
-               atomic_inc(&qp->refcount);
-       }
-       spin_unlock_irqrestore(&dev->pending_lock, flags);
-
-       while (qplist != NULL) {
-               qp = qplist;
-               qplist = qp->pio_next;
-
-               spin_lock_irqsave(&qp->s_lock, flags);
-               if (ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)
-                       ipath_schedule_send(qp);
-               spin_unlock_irqrestore(&qp->s_lock, flags);
-
-               /* Notify ipath_destroy_qp() if it is waiting. */
-               if (atomic_dec_and_test(&qp->refcount))
-                       wake_up(&qp->wait);
-       }
-
-bail:
-       return 0;
-}
-
-static int ipath_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
-                             struct ib_udata *uhw)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-
-       if (uhw->inlen || uhw->outlen)
-               return -EINVAL;
-
-       memset(props, 0, sizeof(*props));
-
-       props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
-               IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
-               IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN |
-               IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE;
-       props->page_size_cap = PAGE_SIZE;
-       props->vendor_id =
-               IPATH_SRC_OUI_1 << 16 | IPATH_SRC_OUI_2 << 8 | IPATH_SRC_OUI_3;
-       props->vendor_part_id = dev->dd->ipath_deviceid;
-       props->hw_ver = dev->dd->ipath_pcirev;
-
-       props->sys_image_guid = dev->sys_image_guid;
-
-       props->max_mr_size = ~0ull;
-       props->max_qp = ib_ipath_max_qps;
-       props->max_qp_wr = ib_ipath_max_qp_wrs;
-       props->max_sge = ib_ipath_max_sges;
-       props->max_sge_rd = ib_ipath_max_sges;
-       props->max_cq = ib_ipath_max_cqs;
-       props->max_ah = ib_ipath_max_ahs;
-       props->max_cqe = ib_ipath_max_cqes;
-       props->max_mr = dev->lk_table.max;
-       props->max_fmr = dev->lk_table.max;
-       props->max_map_per_fmr = 32767;
-       props->max_pd = ib_ipath_max_pds;
-       props->max_qp_rd_atom = IPATH_MAX_RDMA_ATOMIC;
-       props->max_qp_init_rd_atom = 255;
-       /* props->max_res_rd_atom */
-       props->max_srq = ib_ipath_max_srqs;
-       props->max_srq_wr = ib_ipath_max_srq_wrs;
-       props->max_srq_sge = ib_ipath_max_srq_sges;
-       /* props->local_ca_ack_delay */
-       props->atomic_cap = IB_ATOMIC_GLOB;
-       props->max_pkeys = ipath_get_npkeys(dev->dd);
-       props->max_mcast_grp = ib_ipath_max_mcast_grps;
-       props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached;
-       props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
-               props->max_mcast_grp;
-
-       return 0;
-}
-
-const u8 ipath_cvt_physportstate[32] = {
-       [INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
-       [INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
-       [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
-       [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
-       [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
-       [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
-       [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] =
-               IB_PHYSPORTSTATE_CFG_TRAIN,
-       [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] =
-               IB_PHYSPORTSTATE_CFG_TRAIN,
-       [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] =
-               IB_PHYSPORTSTATE_CFG_TRAIN,
-       [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] =
-               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] =
-               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-       [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] =
-               IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
-       [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
-       [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
-};
-
-u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
-{
-       return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
-}
-
-static int ipath_query_port(struct ib_device *ibdev,
-                           u8 port, struct ib_port_attr *props)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_devdata *dd = dev->dd;
-       enum ib_mtu mtu;
-       u16 lid = dd->ipath_lid;
-       u64 ibcstat;
-
-       memset(props, 0, sizeof(*props));
-       props->lid = lid ? lid : be16_to_cpu(IB_LID_PERMISSIVE);
-       props->lmc = dd->ipath_lmc;
-       props->sm_lid = dev->sm_lid;
-       props->sm_sl = dev->sm_sl;
-       ibcstat = dd->ipath_lastibcstat;
-       /* map LinkState to IB portinfo values.  */
-       props->state = ipath_ib_linkstate(dd, ibcstat) + 1;
-
-       /* See phys_state_show() */
-       props->phys_state = /* MEA: assumes shift == 0 */
-               ipath_cvt_physportstate[dd->ipath_lastibcstat &
-               dd->ibcs_lts_mask];
-       props->port_cap_flags = dev->port_cap_flags;
-       props->gid_tbl_len = 1;
-       props->max_msg_sz = 0x80000000;
-       props->pkey_tbl_len = ipath_get_npkeys(dd);
-       props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) -
-               dev->z_pkey_violations;
-       props->qkey_viol_cntr = dev->qkey_violations;
-       props->active_width = dd->ipath_link_width_active;
-       /* See rate_show() */
-       props->active_speed = dd->ipath_link_speed_active;
-       props->max_vl_num = 1;          /* VLCap = VL0 */
-       props->init_type_reply = 0;
-
-       props->max_mtu = ipath_mtu4096 ? IB_MTU_4096 : IB_MTU_2048;
-       switch (dd->ipath_ibmtu) {
-       case 4096:
-               mtu = IB_MTU_4096;
-               break;
-       case 2048:
-               mtu = IB_MTU_2048;
-               break;
-       case 1024:
-               mtu = IB_MTU_1024;
-               break;
-       case 512:
-               mtu = IB_MTU_512;
-               break;
-       case 256:
-               mtu = IB_MTU_256;
-               break;
-       default:
-               mtu = IB_MTU_2048;
-       }
-       props->active_mtu = mtu;
-       props->subnet_timeout = dev->subnet_timeout;
-
-       return 0;
-}
-
-static int ipath_modify_device(struct ib_device *device,
-                              int device_modify_mask,
-                              struct ib_device_modify *device_modify)
-{
-       int ret;
-
-       if (device_modify_mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID |
-                                  IB_DEVICE_MODIFY_NODE_DESC)) {
-               ret = -EOPNOTSUPP;
-               goto bail;
-       }
-
-       if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC)
-               memcpy(device->node_desc, device_modify->node_desc, 64);
-
-       if (device_modify_mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID)
-               to_idev(device)->sys_image_guid =
-                       cpu_to_be64(device_modify->sys_image_guid);
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-static int ipath_modify_port(struct ib_device *ibdev,
-                            u8 port, int port_modify_mask,
-                            struct ib_port_modify *props)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-
-       dev->port_cap_flags |= props->set_port_cap_mask;
-       dev->port_cap_flags &= ~props->clr_port_cap_mask;
-       if (port_modify_mask & IB_PORT_SHUTDOWN)
-               ipath_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
-       if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
-               dev->qkey_violations = 0;
-       return 0;
-}
-
-static int ipath_query_gid(struct ib_device *ibdev, u8 port,
-                          int index, union ib_gid *gid)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       int ret;
-
-       if (index >= 1) {
-               ret = -EINVAL;
-               goto bail;
-       }
-       gid->global.subnet_prefix = dev->gid_prefix;
-       gid->global.interface_id = dev->dd->ipath_guid;
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-static struct ib_pd *ipath_alloc_pd(struct ib_device *ibdev,
-                                   struct ib_ucontext *context,
-                                   struct ib_udata *udata)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       struct ipath_pd *pd;
-       struct ib_pd *ret;
-
-       /*
-        * This is actually totally arbitrary.  Some correctness tests
-        * assume there's a maximum number of PDs that can be allocated.
-        * We don't actually have this limit, but we fail the test if
-        * we allow allocations of more than we report for this value.
-        */
-
-       pd = kmalloc(sizeof *pd, GFP_KERNEL);
-       if (!pd) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       spin_lock(&dev->n_pds_lock);
-       if (dev->n_pds_allocated == ib_ipath_max_pds) {
-               spin_unlock(&dev->n_pds_lock);
-               kfree(pd);
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       dev->n_pds_allocated++;
-       spin_unlock(&dev->n_pds_lock);
-
-       /* ib_alloc_pd() will initialize pd->ibpd. */
-       pd->user = udata != NULL;
-
-       ret = &pd->ibpd;
-
-bail:
-       return ret;
-}
-
-static int ipath_dealloc_pd(struct ib_pd *ibpd)
-{
-       struct ipath_pd *pd = to_ipd(ibpd);
-       struct ipath_ibdev *dev = to_idev(ibpd->device);
-
-       spin_lock(&dev->n_pds_lock);
-       dev->n_pds_allocated--;
-       spin_unlock(&dev->n_pds_lock);
-
-       kfree(pd);
-
-       return 0;
-}
-
-/**
- * ipath_create_ah - create an address handle
- * @pd: the protection domain
- * @ah_attr: the attributes of the AH
- *
- * This may be called from interrupt context.
- */
-static struct ib_ah *ipath_create_ah(struct ib_pd *pd,
-                                    struct ib_ah_attr *ah_attr)
-{
-       struct ipath_ah *ah;
-       struct ib_ah *ret;
-       struct ipath_ibdev *dev = to_idev(pd->device);
-       unsigned long flags;
-
-       /* A multicast address requires a GRH (see ch. 8.4.1). */
-       if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
-           ah_attr->dlid != IPATH_PERMISSIVE_LID &&
-           !(ah_attr->ah_flags & IB_AH_GRH)) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       if (ah_attr->dlid == 0) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       if (ah_attr->port_num < 1 ||
-           ah_attr->port_num > pd->device->phys_port_cnt) {
-               ret = ERR_PTR(-EINVAL);
-               goto bail;
-       }
-
-       ah = kmalloc(sizeof *ah, GFP_ATOMIC);
-       if (!ah) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       spin_lock_irqsave(&dev->n_ahs_lock, flags);
-       if (dev->n_ahs_allocated == ib_ipath_max_ahs) {
-               spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
-               kfree(ah);
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       dev->n_ahs_allocated++;
-       spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
-
-       /* ib_create_ah() will initialize ah->ibah. */
-       ah->attr = *ah_attr;
-       ah->attr.static_rate = ipath_ib_rate_to_mult(ah_attr->static_rate);
-
-       ret = &ah->ibah;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_destroy_ah - destroy an address handle
- * @ibah: the AH to destroy
- *
- * This may be called from interrupt context.
- */
-static int ipath_destroy_ah(struct ib_ah *ibah)
-{
-       struct ipath_ibdev *dev = to_idev(ibah->device);
-       struct ipath_ah *ah = to_iah(ibah);
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->n_ahs_lock, flags);
-       dev->n_ahs_allocated--;
-       spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
-
-       kfree(ah);
-
-       return 0;
-}
-
-static int ipath_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
-{
-       struct ipath_ah *ah = to_iah(ibah);
-
-       *ah_attr = ah->attr;
-       ah_attr->static_rate = ipath_mult_to_ib_rate(ah->attr.static_rate);
-
-       return 0;
-}
-
-/**
- * ipath_get_npkeys - return the size of the PKEY table for port 0
- * @dd: the infinipath device
- */
-unsigned ipath_get_npkeys(struct ipath_devdata *dd)
-{
-       return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys);
-}
-
-/**
- * ipath_get_pkey - return the indexed PKEY from the port PKEY table
- * @dd: the infinipath device
- * @index: the PKEY index
- */
-unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index)
-{
-       unsigned ret;
-
-       /* always a kernel port, no locking needed */
-       if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
-               ret = 0;
-       else
-               ret = dd->ipath_pd[0]->port_pkeys[index];
-
-       return ret;
-}
-
-static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
-                           u16 *pkey)
-{
-       struct ipath_ibdev *dev = to_idev(ibdev);
-       int ret;
-
-       if (index >= ipath_get_npkeys(dev->dd)) {
-               ret = -EINVAL;
-               goto bail;
-       }
-
-       *pkey = ipath_get_pkey(dev->dd, index);
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-/**
- * ipath_alloc_ucontext - allocate a ucontest
- * @ibdev: the infiniband device
- * @udata: not used by the InfiniPath driver
- */
-
-static struct ib_ucontext *ipath_alloc_ucontext(struct ib_device *ibdev,
-                                               struct ib_udata *udata)
-{
-       struct ipath_ucontext *context;
-       struct ib_ucontext *ret;
-
-       context = kmalloc(sizeof *context, GFP_KERNEL);
-       if (!context) {
-               ret = ERR_PTR(-ENOMEM);
-               goto bail;
-       }
-
-       ret = &context->ibucontext;
-
-bail:
-       return ret;
-}
-
-static int ipath_dealloc_ucontext(struct ib_ucontext *context)
-{
-       kfree(to_iucontext(context));
-       return 0;
-}
-
-static int ipath_verbs_register_sysfs(struct ib_device *dev);
-
-static void __verbs_timer(unsigned long arg)
-{
-       struct ipath_devdata *dd = (struct ipath_devdata *) arg;
-
-       /* Handle verbs layer timeouts. */
-       ipath_ib_timer(dd->verbs_dev);
-
-       mod_timer(&dd->verbs_timer, jiffies + 1);
-}
-
-static int enable_timer(struct ipath_devdata *dd)
-{
-       /*
-        * Early chips had a design flaw where the chip and kernel idea
-        * of the tail register don't always agree, and therefore we won't
-        * get an interrupt on the next packet received.
-        * If the board supports per packet receive interrupts, use it.
-        * Otherwise, the timer function periodically checks for packets
-        * to cover this case.
-        * Either way, the timer is needed for verbs layer related
-        * processing.
-        */
-       if (dd->ipath_flags & IPATH_GPIO_INTR) {
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
-                                0x2074076542310ULL);
-               /* Enable GPIO bit 2 interrupt */
-               dd->ipath_gpio_mask |= (u64) (1 << IPATH_GPIO_PORT0_BIT);
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
-                                dd->ipath_gpio_mask);
-       }
-
-       setup_timer(&dd->verbs_timer, __verbs_timer, (unsigned long)dd);
-
-       dd->verbs_timer.expires = jiffies + 1;
-       add_timer(&dd->verbs_timer);
-
-       return 0;
-}
-
-static int disable_timer(struct ipath_devdata *dd)
-{
-       /* Disable GPIO bit 2 interrupt */
-       if (dd->ipath_flags & IPATH_GPIO_INTR) {
-                /* Disable GPIO bit 2 interrupt */
-               dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
-               ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
-                                dd->ipath_gpio_mask);
-               /*
-                * We might want to undo changes to debugportselect,
-                * but how?
-                */
-       }
-
-       del_timer_sync(&dd->verbs_timer);
-
-       return 0;
-}
-
-static int ipath_port_immutable(struct ib_device *ibdev, u8 port_num,
-                               struct ib_port_immutable *immutable)
-{
-       struct ib_port_attr attr;
-       int err;
-
-       err = ipath_query_port(ibdev, port_num, &attr);
-       if (err)
-               return err;
-
-       immutable->pkey_tbl_len = attr.pkey_tbl_len;
-       immutable->gid_tbl_len = attr.gid_tbl_len;
-       immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
-       immutable->max_mad_size = IB_MGMT_MAD_SIZE;
-
-       return 0;
-}
-
-/**
- * ipath_register_ib_device - register our device with the infiniband core
- * @dd: the device data structure
- * Return the allocated ipath_ibdev pointer or NULL on error.
- */
-int ipath_register_ib_device(struct ipath_devdata *dd)
-{
-       struct ipath_verbs_counters cntrs;
-       struct ipath_ibdev *idev;
-       struct ib_device *dev;
-       struct ipath_verbs_txreq *tx;
-       unsigned i;
-       int ret;
-
-       idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev);
-       if (idev == NULL) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-
-       dev = &idev->ibdev;
-
-       if (dd->ipath_sdma_descq_cnt) {
-               tx = kmalloc_array(dd->ipath_sdma_descq_cnt, sizeof *tx,
-                                  GFP_KERNEL);
-               if (tx == NULL) {
-                       ret = -ENOMEM;
-                       goto err_tx;
-               }
-       } else
-               tx = NULL;
-       idev->txreq_bufs = tx;
-
-       /* Only need to initialize non-zero fields. */
-       spin_lock_init(&idev->n_pds_lock);
-       spin_lock_init(&idev->n_ahs_lock);
-       spin_lock_init(&idev->n_cqs_lock);
-       spin_lock_init(&idev->n_qps_lock);
-       spin_lock_init(&idev->n_srqs_lock);
-       spin_lock_init(&idev->n_mcast_grps_lock);
-
-       spin_lock_init(&idev->qp_table.lock);
-       spin_lock_init(&idev->lk_table.lock);
-       idev->sm_lid = be16_to_cpu(IB_LID_PERMISSIVE);
-       /* Set the prefix to the default value (see ch. 4.1.1) */
-       idev->gid_prefix = cpu_to_be64(0xfe80000000000000ULL);
-
-       ret = ipath_init_qp_table(idev, ib_ipath_qp_table_size);
-       if (ret)
-               goto err_qp;
-
-       /*
-        * The top ib_ipath_lkey_table_size bits are used to index the
-        * table.  The lower 8 bits can be owned by the user (copied from
-        * the LKEY).  The remaining bits act as a generation number or tag.
-        */
-       idev->lk_table.max = 1 << ib_ipath_lkey_table_size;
-       idev->lk_table.table = kcalloc(idev->lk_table.max,
-                                      sizeof(*idev->lk_table.table),
-                                      GFP_KERNEL);
-       if (idev->lk_table.table == NULL) {
-               ret = -ENOMEM;
-               goto err_lk;
-       }
-       INIT_LIST_HEAD(&idev->pending_mmaps);
-       spin_lock_init(&idev->pending_lock);
-       idev->mmap_offset = PAGE_SIZE;
-       spin_lock_init(&idev->mmap_offset_lock);
-       INIT_LIST_HEAD(&idev->pending[0]);
-       INIT_LIST_HEAD(&idev->pending[1]);
-       INIT_LIST_HEAD(&idev->pending[2]);
-       INIT_LIST_HEAD(&idev->piowait);
-       INIT_LIST_HEAD(&idev->rnrwait);
-       INIT_LIST_HEAD(&idev->txreq_free);
-       idev->pending_index = 0;
-       idev->port_cap_flags =
-               IB_PORT_SYS_IMAGE_GUID_SUP | IB_PORT_CLIENT_REG_SUP;
-       if (dd->ipath_flags & IPATH_HAS_LINK_LATENCY)
-               idev->port_cap_flags |= IB_PORT_LINK_LATENCY_SUP;
-       idev->pma_counter_select[0] = IB_PMA_PORT_XMIT_DATA;
-       idev->pma_counter_select[1] = IB_PMA_PORT_RCV_DATA;
-       idev->pma_counter_select[2] = IB_PMA_PORT_XMIT_PKTS;
-       idev->pma_counter_select[3] = IB_PMA_PORT_RCV_PKTS;
-       idev->pma_counter_select[4] = IB_PMA_PORT_XMIT_WAIT;
-
-       /* Snapshot current HW counters to "clear" them. */
-       ipath_get_counters(dd, &cntrs);
-       idev->z_symbol_error_counter = cntrs.symbol_error_counter;
-       idev->z_link_error_recovery_counter =
-               cntrs.link_error_recovery_counter;
-       idev->z_link_downed_counter = cntrs.link_downed_counter;
-       idev->z_port_rcv_errors = cntrs.port_rcv_errors;
-       idev->z_port_rcv_remphys_errors =
-               cntrs.port_rcv_remphys_errors;
-       idev->z_port_xmit_discards = cntrs.port_xmit_discards;
-       idev->z_port_xmit_data = cntrs.port_xmit_data;
-       idev->z_port_rcv_data = cntrs.port_rcv_data;
-       idev->z_port_xmit_packets = cntrs.port_xmit_packets;
-       idev->z_port_rcv_packets = cntrs.port_rcv_packets;
-       idev->z_local_link_integrity_errors =
-               cntrs.local_link_integrity_errors;
-       idev->z_excessive_buffer_overrun_errors =
-               cntrs.excessive_buffer_overrun_errors;
-       idev->z_vl15_dropped = cntrs.vl15_dropped;
-
-       for (i = 0; i < dd->ipath_sdma_descq_cnt; i++, tx++)
-               list_add(&tx->txreq.list, &idev->txreq_free);
-
-       /*
-        * The system image GUID is supposed to be the same for all
-        * IB HCAs in a single system but since there can be other
-        * device types in the system, we can't be sure this is unique.
-        */
-       if (!sys_image_guid)
-               sys_image_guid = dd->ipath_guid;
-       idev->sys_image_guid = sys_image_guid;
-       idev->ib_unit = dd->ipath_unit;
-       idev->dd = dd;
-
-       strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX);
-       dev->owner = THIS_MODULE;
-       dev->node_guid = dd->ipath_guid;
-       dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION;
-       dev->uverbs_cmd_mask =
-               (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
-               (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
-               (1ull << IB_USER_VERBS_CMD_QUERY_PORT)          |
-               (1ull << IB_USER_VERBS_CMD_ALLOC_PD)            |
-               (1ull << IB_USER_VERBS_CMD_DEALLOC_PD)          |
-               (1ull << IB_USER_VERBS_CMD_CREATE_AH)           |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_AH)          |
-               (1ull << IB_USER_VERBS_CMD_QUERY_AH)            |
-               (1ull << IB_USER_VERBS_CMD_REG_MR)              |
-               (1ull << IB_USER_VERBS_CMD_DEREG_MR)            |
-               (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
-               (1ull << IB_USER_VERBS_CMD_CREATE_CQ)           |
-               (1ull << IB_USER_VERBS_CMD_RESIZE_CQ)           |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_CQ)          |
-               (1ull << IB_USER_VERBS_CMD_POLL_CQ)             |
-               (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ)       |
-               (1ull << IB_USER_VERBS_CMD_CREATE_QP)           |
-               (1ull << IB_USER_VERBS_CMD_QUERY_QP)            |
-               (1ull << IB_USER_VERBS_CMD_MODIFY_QP)           |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_QP)          |
-               (1ull << IB_USER_VERBS_CMD_POST_SEND)           |
-               (1ull << IB_USER_VERBS_CMD_POST_RECV)           |
-               (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST)        |
-               (1ull << IB_USER_VERBS_CMD_DETACH_MCAST)        |
-               (1ull << IB_USER_VERBS_CMD_CREATE_SRQ)          |
-               (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ)          |
-               (1ull << IB_USER_VERBS_CMD_QUERY_SRQ)           |
-               (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ)         |
-               (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
-       dev->node_type = RDMA_NODE_IB_CA;
-       dev->phys_port_cnt = 1;
-       dev->num_comp_vectors = 1;
-       dev->dma_device = &dd->pcidev->dev;
-       dev->query_device = ipath_query_device;
-       dev->modify_device = ipath_modify_device;
-       dev->query_port = ipath_query_port;
-       dev->modify_port = ipath_modify_port;
-       dev->query_pkey = ipath_query_pkey;
-       dev->query_gid = ipath_query_gid;
-       dev->alloc_ucontext = ipath_alloc_ucontext;
-       dev->dealloc_ucontext = ipath_dealloc_ucontext;
-       dev->alloc_pd = ipath_alloc_pd;
-       dev->dealloc_pd = ipath_dealloc_pd;
-       dev->create_ah = ipath_create_ah;
-       dev->destroy_ah = ipath_destroy_ah;
-       dev->query_ah = ipath_query_ah;
-       dev->create_srq = ipath_create_srq;
-       dev->modify_srq = ipath_modify_srq;
-       dev->query_srq = ipath_query_srq;
-       dev->destroy_srq = ipath_destroy_srq;
-       dev->create_qp = ipath_create_qp;
-       dev->modify_qp = ipath_modify_qp;
-       dev->query_qp = ipath_query_qp;
-       dev->destroy_qp = ipath_destroy_qp;
-       dev->post_send = ipath_post_send;
-       dev->post_recv = ipath_post_receive;
-       dev->post_srq_recv = ipath_post_srq_receive;
-       dev->create_cq = ipath_create_cq;
-       dev->destroy_cq = ipath_destroy_cq;
-       dev->resize_cq = ipath_resize_cq;
-       dev->poll_cq = ipath_poll_cq;
-       dev->req_notify_cq = ipath_req_notify_cq;
-       dev->get_dma_mr = ipath_get_dma_mr;
-       dev->reg_user_mr = ipath_reg_user_mr;
-       dev->dereg_mr = ipath_dereg_mr;
-       dev->alloc_fmr = ipath_alloc_fmr;
-       dev->map_phys_fmr = ipath_map_phys_fmr;
-       dev->unmap_fmr = ipath_unmap_fmr;
-       dev->dealloc_fmr = ipath_dealloc_fmr;
-       dev->attach_mcast = ipath_multicast_attach;
-       dev->detach_mcast = ipath_multicast_detach;
-       dev->process_mad = ipath_process_mad;
-       dev->mmap = ipath_mmap;
-       dev->dma_ops = &ipath_dma_mapping_ops;
-       dev->get_port_immutable = ipath_port_immutable;
-
-       snprintf(dev->node_desc, sizeof(dev->node_desc),
-                IPATH_IDSTR " %s", init_utsname()->nodename);
-
-       ret = ib_register_device(dev, NULL);
-       if (ret)
-               goto err_reg;
-
-       ret = ipath_verbs_register_sysfs(dev);
-       if (ret)
-               goto err_class;
-
-       enable_timer(dd);
-
-       goto bail;
-
-err_class:
-       ib_unregister_device(dev);
-err_reg:
-       kfree(idev->lk_table.table);
-err_lk:
-       kfree(idev->qp_table.table);
-err_qp:
-       kfree(idev->txreq_bufs);
-err_tx:
-       ib_dealloc_device(dev);
-       ipath_dev_err(dd, "cannot register verbs: %d!\n", -ret);
-       idev = NULL;
-
-bail:
-       dd->verbs_dev = idev;
-       return ret;
-}
-
-void ipath_unregister_ib_device(struct ipath_ibdev *dev)
-{
-       struct ib_device *ibdev = &dev->ibdev;
-       u32 qps_inuse;
-
-       ib_unregister_device(ibdev);
-
-       disable_timer(dev->dd);
-
-       if (!list_empty(&dev->pending[0]) ||
-           !list_empty(&dev->pending[1]) ||
-           !list_empty(&dev->pending[2]))
-               ipath_dev_err(dev->dd, "pending list not empty!\n");
-       if (!list_empty(&dev->piowait))
-               ipath_dev_err(dev->dd, "piowait list not empty!\n");
-       if (!list_empty(&dev->rnrwait))
-               ipath_dev_err(dev->dd, "rnrwait list not empty!\n");
-       if (!ipath_mcast_tree_empty())
-               ipath_dev_err(dev->dd, "multicast table memory leak!\n");
-       /*
-        * Note that ipath_unregister_ib_device() can be called before all
-        * the QPs are destroyed!
-        */
-       qps_inuse = ipath_free_all_qps(&dev->qp_table);
-       if (qps_inuse)
-               ipath_dev_err(dev->dd, "QP memory leak! %u still in use\n",
-                       qps_inuse);
-       kfree(dev->qp_table.table);
-       kfree(dev->lk_table.table);
-       kfree(dev->txreq_bufs);
-       ib_dealloc_device(ibdev);
-}
-
-static ssize_t show_rev(struct device *device, struct device_attribute *attr,
-                       char *buf)
-{
-       struct ipath_ibdev *dev =
-               container_of(device, struct ipath_ibdev, ibdev.dev);
-
-       return sprintf(buf, "%x\n", dev->dd->ipath_pcirev);
-}
-
-static ssize_t show_hca(struct device *device, struct device_attribute *attr,
-                       char *buf)
-{
-       struct ipath_ibdev *dev =
-               container_of(device, struct ipath_ibdev, ibdev.dev);
-       int ret;
-
-       ret = dev->dd->ipath_f_get_boardname(dev->dd, buf, 128);
-       if (ret < 0)
-               goto bail;
-       strcat(buf, "\n");
-       ret = strlen(buf);
-
-bail:
-       return ret;
-}
-
-static ssize_t show_stats(struct device *device, struct device_attribute *attr,
-                         char *buf)
-{
-       struct ipath_ibdev *dev =
-               container_of(device, struct ipath_ibdev, ibdev.dev);
-       int i;
-       int len;
-
-       len = sprintf(buf,
-                     "RC resends  %d\n"
-                     "RC no QACK  %d\n"
-                     "RC ACKs     %d\n"
-                     "RC SEQ NAKs %d\n"
-                     "RC RDMA seq %d\n"
-                     "RC RNR NAKs %d\n"
-                     "RC OTH NAKs %d\n"
-                     "RC timeouts %d\n"
-                     "RC RDMA dup %d\n"
-                     "piobuf wait %d\n"
-                     "unaligned   %d\n"
-                     "PKT drops   %d\n"
-                     "WQE errs    %d\n",
-                     dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks,
-                     dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks,
-                     dev->n_other_naks, dev->n_timeouts,
-                     dev->n_rdma_dup_busy, dev->n_piowait, dev->n_unaligned,
-                     dev->n_pkt_drops, dev->n_wqe_errs);
-       for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) {
-               const struct ipath_opcode_stats *si = &dev->opstats[i];
-
-               if (!si->n_packets && !si->n_bytes)
-                       continue;
-               len += sprintf(buf + len, "%02x %llu/%llu\n", i,
-                              (unsigned long long) si->n_packets,
-                              (unsigned long long) si->n_bytes);
-       }
-       return len;
-}
-
-static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
-static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL);
-static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL);
-
-static struct device_attribute *ipath_class_attributes[] = {
-       &dev_attr_hw_rev,
-       &dev_attr_hca_type,
-       &dev_attr_board_id,
-       &dev_attr_stats
-};
-
-static int ipath_verbs_register_sysfs(struct ib_device *dev)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) {
-               ret = device_create_file(&dev->dev,
-                                      ipath_class_attributes[i]);
-               if (ret)
-                       goto bail;
-       }
-       return 0;
-bail:
-       for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i)
-               device_remove_file(&dev->dev, ipath_class_attributes[i]);
-       return ret;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_verbs.h b/drivers/staging/rdma/ipath/ipath_verbs.h
deleted file mode 100644 (file)
index 6c70a89..0000000
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef IPATH_VERBS_H
-#define IPATH_VERBS_H
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/kref.h>
-#include <rdma/ib_pack.h>
-#include <rdma/ib_user_verbs.h>
-
-#include "ipath_kernel.h"
-
-#define IPATH_MAX_RDMA_ATOMIC  4
-
-#define QPN_MAX                 (1 << 24)
-#define QPNMAP_ENTRIES          (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE)
-
-/*
- * Increment this value if any changes that break userspace ABI
- * compatibility are made.
- */
-#define IPATH_UVERBS_ABI_VERSION       2
-
-/*
- * Define an ib_cq_notify value that is not valid so we know when CQ
- * notifications are armed.
- */
-#define IB_CQ_NONE     (IB_CQ_NEXT_COMP + 1)
-
-/* AETH NAK opcode values */
-#define IB_RNR_NAK                     0x20
-#define IB_NAK_PSN_ERROR               0x60
-#define IB_NAK_INVALID_REQUEST         0x61
-#define IB_NAK_REMOTE_ACCESS_ERROR     0x62
-#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
-#define IB_NAK_INVALID_RD_REQUEST      0x64
-
-/* Flags for checking QP state (see ib_ipath_state_ops[]) */
-#define IPATH_POST_SEND_OK             0x01
-#define IPATH_POST_RECV_OK             0x02
-#define IPATH_PROCESS_RECV_OK          0x04
-#define IPATH_PROCESS_SEND_OK          0x08
-#define IPATH_PROCESS_NEXT_SEND_OK     0x10
-#define IPATH_FLUSH_SEND               0x20
-#define IPATH_FLUSH_RECV               0x40
-#define IPATH_PROCESS_OR_FLUSH_SEND \
-       (IPATH_PROCESS_SEND_OK | IPATH_FLUSH_SEND)
-
-/* IB Performance Manager status values */
-#define IB_PMA_SAMPLE_STATUS_DONE      0x00
-#define IB_PMA_SAMPLE_STATUS_STARTED   0x01
-#define IB_PMA_SAMPLE_STATUS_RUNNING   0x02
-
-/* Mandatory IB performance counter select values. */
-#define IB_PMA_PORT_XMIT_DATA  cpu_to_be16(0x0001)
-#define IB_PMA_PORT_RCV_DATA   cpu_to_be16(0x0002)
-#define IB_PMA_PORT_XMIT_PKTS  cpu_to_be16(0x0003)
-#define IB_PMA_PORT_RCV_PKTS   cpu_to_be16(0x0004)
-#define IB_PMA_PORT_XMIT_WAIT  cpu_to_be16(0x0005)
-
-struct ib_reth {
-       __be64 vaddr;
-       __be32 rkey;
-       __be32 length;
-} __attribute__ ((packed));
-
-struct ib_atomic_eth {
-       __be32 vaddr[2];        /* unaligned so access as 2 32-bit words */
-       __be32 rkey;
-       __be64 swap_data;
-       __be64 compare_data;
-} __attribute__ ((packed));
-
-struct ipath_other_headers {
-       __be32 bth[3];
-       union {
-               struct {
-                       __be32 deth[2];
-                       __be32 imm_data;
-               } ud;
-               struct {
-                       struct ib_reth reth;
-                       __be32 imm_data;
-               } rc;
-               struct {
-                       __be32 aeth;
-                       __be32 atomic_ack_eth[2];
-               } at;
-               __be32 imm_data;
-               __be32 aeth;
-               struct ib_atomic_eth atomic_eth;
-       } u;
-} __attribute__ ((packed));
-
-/*
- * Note that UD packets with a GRH header are 8+40+12+8 = 68 bytes
- * long (72 w/ imm_data).  Only the first 56 bytes of the IB header
- * will be in the eager header buffer.  The remaining 12 or 16 bytes
- * are in the data buffer.
- */
-struct ipath_ib_header {
-       __be16 lrh[4];
-       union {
-               struct {
-                       struct ib_grh grh;
-                       struct ipath_other_headers oth;
-               } l;
-               struct ipath_other_headers oth;
-       } u;
-} __attribute__ ((packed));
-
-struct ipath_pio_header {
-       __le32 pbc[2];
-       struct ipath_ib_header hdr;
-} __attribute__ ((packed));
-
-/*
- * There is one struct ipath_mcast for each multicast GID.
- * All attached QPs are then stored as a list of
- * struct ipath_mcast_qp.
- */
-struct ipath_mcast_qp {
-       struct list_head list;
-       struct ipath_qp *qp;
-};
-
-struct ipath_mcast {
-       struct rb_node rb_node;
-       union ib_gid mgid;
-       struct list_head qp_list;
-       wait_queue_head_t wait;
-       atomic_t refcount;
-       int n_attached;
-};
-
-/* Protection domain */
-struct ipath_pd {
-       struct ib_pd ibpd;
-       int user;               /* non-zero if created from user space */
-};
-
-/* Address Handle */
-struct ipath_ah {
-       struct ib_ah ibah;
-       struct ib_ah_attr attr;
-};
-
-/*
- * This structure is used by ipath_mmap() to validate an offset
- * when an mmap() request is made.  The vm_area_struct then uses
- * this as its vm_private_data.
- */
-struct ipath_mmap_info {
-       struct list_head pending_mmaps;
-       struct ib_ucontext *context;
-       void *obj;
-       __u64 offset;
-       struct kref ref;
-       unsigned size;
-};
-
-/*
- * This structure is used to contain the head pointer, tail pointer,
- * and completion queue entries as a single memory allocation so
- * it can be mmap'ed into user space.
- */
-struct ipath_cq_wc {
-       u32 head;               /* index of next entry to fill */
-       u32 tail;               /* index of next ib_poll_cq() entry */
-       union {
-               /* these are actually size ibcq.cqe + 1 */
-               struct ib_uverbs_wc uqueue[0];
-               struct ib_wc kqueue[0];
-       };
-};
-
-/*
- * The completion queue structure.
- */
-struct ipath_cq {
-       struct ib_cq ibcq;
-       struct tasklet_struct comptask;
-       spinlock_t lock;
-       u8 notify;
-       u8 triggered;
-       struct ipath_cq_wc *queue;
-       struct ipath_mmap_info *ip;
-};
-
-/*
- * A segment is a linear region of low physical memory.
- * XXX Maybe we should use phys addr here and kmap()/kunmap().
- * Used by the verbs layer.
- */
-struct ipath_seg {
-       void *vaddr;
-       size_t length;
-};
-
-/* The number of ipath_segs that fit in a page. */
-#define IPATH_SEGSZ     (PAGE_SIZE / sizeof (struct ipath_seg))
-
-struct ipath_segarray {
-       struct ipath_seg segs[IPATH_SEGSZ];
-};
-
-struct ipath_mregion {
-       struct ib_pd *pd;       /* shares refcnt of ibmr.pd */
-       u64 user_base;          /* User's address for this region */
-       u64 iova;               /* IB start address of this region */
-       size_t length;
-       u32 lkey;
-       u32 offset;             /* offset (bytes) to start of region */
-       int access_flags;
-       u32 max_segs;           /* number of ipath_segs in all the arrays */
-       u32 mapsz;              /* size of the map array */
-       struct ipath_segarray *map[0];  /* the segments */
-};
-
-/*
- * These keep track of the copy progress within a memory region.
- * Used by the verbs layer.
- */
-struct ipath_sge {
-       struct ipath_mregion *mr;
-       void *vaddr;            /* kernel virtual address of segment */
-       u32 sge_length;         /* length of the SGE */
-       u32 length;             /* remaining length of the segment */
-       u16 m;                  /* current index: mr->map[m] */
-       u16 n;                  /* current index: mr->map[m]->segs[n] */
-};
-
-/* Memory region */
-struct ipath_mr {
-       struct ib_mr ibmr;
-       struct ib_umem *umem;
-       struct ipath_mregion mr;        /* must be last */
-};
-
-/*
- * Send work request queue entry.
- * The size of the sg_list is determined when the QP is created and stored
- * in qp->s_max_sge.
- */
-struct ipath_swqe {
-       union {
-               struct ib_send_wr wr;   /* don't use wr.sg_list */
-               struct ib_ud_wr ud_wr;
-               struct ib_rdma_wr rdma_wr;
-               struct ib_atomic_wr atomic_wr;
-       };
-
-       u32 psn;                /* first packet sequence number */
-       u32 lpsn;               /* last packet sequence number */
-       u32 ssn;                /* send sequence number */
-       u32 length;             /* total length of data in sg_list */
-       struct ipath_sge sg_list[0];
-};
-
-/*
- * Receive work request queue entry.
- * The size of the sg_list is determined when the QP (or SRQ) is created
- * and stored in qp->r_rq.max_sge (or srq->rq.max_sge).
- */
-struct ipath_rwqe {
-       u64 wr_id;
-       u8 num_sge;
-       struct ib_sge sg_list[0];
-};
-
-/*
- * This structure is used to contain the head pointer, tail pointer,
- * and receive work queue entries as a single memory allocation so
- * it can be mmap'ed into user space.
- * Note that the wq array elements are variable size so you can't
- * just index into the array to get the N'th element;
- * use get_rwqe_ptr() instead.
- */
-struct ipath_rwq {
-       u32 head;               /* new work requests posted to the head */
-       u32 tail;               /* receives pull requests from here. */
-       struct ipath_rwqe wq[0];
-};
-
-struct ipath_rq {
-       struct ipath_rwq *wq;
-       spinlock_t lock;
-       u32 size;               /* size of RWQE array */
-       u8 max_sge;
-};
-
-struct ipath_srq {
-       struct ib_srq ibsrq;
-       struct ipath_rq rq;
-       struct ipath_mmap_info *ip;
-       /* send signal when number of RWQEs < limit */
-       u32 limit;
-};
-
-struct ipath_sge_state {
-       struct ipath_sge *sg_list;      /* next SGE to be used if any */
-       struct ipath_sge sge;   /* progress state for the current SGE */
-       u8 num_sge;
-       u8 static_rate;
-};
-
-/*
- * This structure holds the information that the send tasklet needs
- * to send a RDMA read response or atomic operation.
- */
-struct ipath_ack_entry {
-       u8 opcode;
-       u8 sent;
-       u32 psn;
-       union {
-               struct ipath_sge_state rdma_sge;
-               u64 atomic_data;
-       };
-};
-
-/*
- * Variables prefixed with s_ are for the requester (sender).
- * Variables prefixed with r_ are for the responder (receiver).
- * Variables prefixed with ack_ are for responder replies.
- *
- * Common variables are protected by both r_rq.lock and s_lock in that order
- * which only happens in modify_qp() or changing the QP 'state'.
- */
-struct ipath_qp {
-       struct ib_qp ibqp;
-       struct ipath_qp *next;          /* link list for QPN hash table */
-       struct ipath_qp *timer_next;    /* link list for ipath_ib_timer() */
-       struct ipath_qp *pio_next;      /* link for ipath_ib_piobufavail() */
-       struct list_head piowait;       /* link for wait PIO buf */
-       struct list_head timerwait;     /* link for waiting for timeouts */
-       struct ib_ah_attr remote_ah_attr;
-       struct ipath_ib_header s_hdr;   /* next packet header to send */
-       atomic_t refcount;
-       wait_queue_head_t wait;
-       wait_queue_head_t wait_dma;
-       struct tasklet_struct s_task;
-       struct ipath_mmap_info *ip;
-       struct ipath_sge_state *s_cur_sge;
-       struct ipath_verbs_txreq *s_tx;
-       struct ipath_sge_state s_sge;   /* current send request data */
-       struct ipath_ack_entry s_ack_queue[IPATH_MAX_RDMA_ATOMIC + 1];
-       struct ipath_sge_state s_ack_rdma_sge;
-       struct ipath_sge_state s_rdma_read_sge;
-       struct ipath_sge_state r_sge;   /* current receive data */
-       spinlock_t s_lock;
-       atomic_t s_dma_busy;
-       u16 s_pkt_delay;
-       u16 s_hdrwords;         /* size of s_hdr in 32 bit words */
-       u32 s_cur_size;         /* size of send packet in bytes */
-       u32 s_len;              /* total length of s_sge */
-       u32 s_rdma_read_len;    /* total length of s_rdma_read_sge */
-       u32 s_next_psn;         /* PSN for next request */
-       u32 s_last_psn;         /* last response PSN processed */
-       u32 s_psn;              /* current packet sequence number */
-       u32 s_ack_rdma_psn;     /* PSN for sending RDMA read responses */
-       u32 s_ack_psn;          /* PSN for acking sends and RDMA writes */
-       u32 s_rnr_timeout;      /* number of milliseconds for RNR timeout */
-       u32 r_ack_psn;          /* PSN for next ACK or atomic ACK */
-       u64 r_wr_id;            /* ID for current receive WQE */
-       unsigned long r_aflags;
-       u32 r_len;              /* total length of r_sge */
-       u32 r_rcv_len;          /* receive data len processed */
-       u32 r_psn;              /* expected rcv packet sequence number */
-       u32 r_msn;              /* message sequence number */
-       u8 state;               /* QP state */
-       u8 s_state;             /* opcode of last packet sent */
-       u8 s_ack_state;         /* opcode of packet to ACK */
-       u8 s_nak_state;         /* non-zero if NAK is pending */
-       u8 r_state;             /* opcode of last packet received */
-       u8 r_nak_state;         /* non-zero if NAK is pending */
-       u8 r_min_rnr_timer;     /* retry timeout value for RNR NAKs */
-       u8 r_flags;
-       u8 r_max_rd_atomic;     /* max number of RDMA read/atomic to receive */
-       u8 r_head_ack_queue;    /* index into s_ack_queue[] */
-       u8 qp_access_flags;
-       u8 s_max_sge;           /* size of s_wq->sg_list */
-       u8 s_retry_cnt;         /* number of times to retry */
-       u8 s_rnr_retry_cnt;
-       u8 s_retry;             /* requester retry counter */
-       u8 s_rnr_retry;         /* requester RNR retry counter */
-       u8 s_pkey_index;        /* PKEY index to use */
-       u8 s_max_rd_atomic;     /* max number of RDMA read/atomic to send */
-       u8 s_num_rd_atomic;     /* number of RDMA read/atomic pending */
-       u8 s_tail_ack_queue;    /* index into s_ack_queue[] */
-       u8 s_flags;
-       u8 s_dmult;
-       u8 s_draining;
-       u8 timeout;             /* Timeout for this QP */
-       enum ib_mtu path_mtu;
-       u32 remote_qpn;
-       u32 qkey;               /* QKEY for this QP (for UD or RD) */
-       u32 s_size;             /* send work queue size */
-       u32 s_head;             /* new entries added here */
-       u32 s_tail;             /* next entry to process */
-       u32 s_cur;              /* current work queue entry */
-       u32 s_last;             /* last un-ACK'ed entry */
-       u32 s_ssn;              /* SSN of tail entry */
-       u32 s_lsn;              /* limit sequence number (credit) */
-       struct ipath_swqe *s_wq;        /* send work queue */
-       struct ipath_swqe *s_wqe;
-       struct ipath_sge *r_ud_sg_list;
-       struct ipath_rq r_rq;           /* receive work queue */
-       struct ipath_sge r_sg_list[0];  /* verified SGEs */
-};
-
-/*
- * Atomic bit definitions for r_aflags.
- */
-#define IPATH_R_WRID_VALID     0
-
-/*
- * Bit definitions for r_flags.
- */
-#define IPATH_R_REUSE_SGE      0x01
-#define IPATH_R_RDMAR_SEQ      0x02
-
-/*
- * Bit definitions for s_flags.
- *
- * IPATH_S_FENCE_PENDING - waiting for all prior RDMA read or atomic SWQEs
- *                        before processing the next SWQE
- * IPATH_S_RDMAR_PENDING - waiting for any RDMA read or atomic SWQEs
- *                        before processing the next SWQE
- * IPATH_S_WAITING - waiting for RNR timeout or send buffer available.
- * IPATH_S_WAIT_SSN_CREDIT - waiting for RC credits to process next SWQE
- * IPATH_S_WAIT_DMA - waiting for send DMA queue to drain before generating
- *                   next send completion entry not via send DMA.
- */
-#define IPATH_S_SIGNAL_REQ_WR  0x01
-#define IPATH_S_FENCE_PENDING  0x02
-#define IPATH_S_RDMAR_PENDING  0x04
-#define IPATH_S_ACK_PENDING    0x08
-#define IPATH_S_BUSY           0x10
-#define IPATH_S_WAITING                0x20
-#define IPATH_S_WAIT_SSN_CREDIT        0x40
-#define IPATH_S_WAIT_DMA       0x80
-
-#define IPATH_S_ANY_WAIT (IPATH_S_FENCE_PENDING | IPATH_S_RDMAR_PENDING | \
-       IPATH_S_WAITING | IPATH_S_WAIT_SSN_CREDIT | IPATH_S_WAIT_DMA)
-
-#define IPATH_PSN_CREDIT       512
-
-/*
- * Since struct ipath_swqe is not a fixed size, we can't simply index into
- * struct ipath_qp.s_wq.  This function does the array index computation.
- */
-static inline struct ipath_swqe *get_swqe_ptr(struct ipath_qp *qp,
-                                             unsigned n)
-{
-       return (struct ipath_swqe *)((char *)qp->s_wq +
-                                    (sizeof(struct ipath_swqe) +
-                                     qp->s_max_sge *
-                                     sizeof(struct ipath_sge)) * n);
-}
-
-/*
- * Since struct ipath_rwqe is not a fixed size, we can't simply index into
- * struct ipath_rwq.wq.  This function does the array index computation.
- */
-static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq,
-                                             unsigned n)
-{
-       return (struct ipath_rwqe *)
-               ((char *) rq->wq->wq +
-                (sizeof(struct ipath_rwqe) +
-                 rq->max_sge * sizeof(struct ib_sge)) * n);
-}
-
-/*
- * QPN-map pages start out as NULL, they get allocated upon
- * first use and are never deallocated. This way,
- * large bitmaps are not allocated unless large numbers of QPs are used.
- */
-struct qpn_map {
-       atomic_t n_free;
-       void *page;
-};
-
-struct ipath_qp_table {
-       spinlock_t lock;
-       u32 last;               /* last QP number allocated */
-       u32 max;                /* size of the hash table */
-       u32 nmaps;              /* size of the map table */
-       struct ipath_qp **table;
-       /* bit map of free numbers */
-       struct qpn_map map[QPNMAP_ENTRIES];
-};
-
-struct ipath_lkey_table {
-       spinlock_t lock;
-       u32 next;               /* next unused index (speeds search) */
-       u32 gen;                /* generation count */
-       u32 max;                /* size of the table */
-       struct ipath_mregion **table;
-};
-
-struct ipath_opcode_stats {
-       u64 n_packets;          /* number of packets */
-       u64 n_bytes;            /* total number of bytes */
-};
-
-struct ipath_ibdev {
-       struct ib_device ibdev;
-       struct ipath_devdata *dd;
-       struct list_head pending_mmaps;
-       spinlock_t mmap_offset_lock;
-       u32 mmap_offset;
-       int ib_unit;            /* This is the device number */
-       u16 sm_lid;             /* in host order */
-       u8 sm_sl;
-       u8 mkeyprot;
-       /* non-zero when timer is set */
-       unsigned long mkey_lease_timeout;
-
-       /* The following fields are really per port. */
-       struct ipath_qp_table qp_table;
-       struct ipath_lkey_table lk_table;
-       struct list_head pending[3];    /* FIFO of QPs waiting for ACKs */
-       struct list_head piowait;       /* list for wait PIO buf */
-       struct list_head txreq_free;
-       void *txreq_bufs;
-       /* list of QPs waiting for RNR timer */
-       struct list_head rnrwait;
-       spinlock_t pending_lock;
-       __be64 sys_image_guid;  /* in network order */
-       __be64 gid_prefix;      /* in network order */
-       __be64 mkey;
-
-       u32 n_pds_allocated;    /* number of PDs allocated for device */
-       spinlock_t n_pds_lock;
-       u32 n_ahs_allocated;    /* number of AHs allocated for device */
-       spinlock_t n_ahs_lock;
-       u32 n_cqs_allocated;    /* number of CQs allocated for device */
-       spinlock_t n_cqs_lock;
-       u32 n_qps_allocated;    /* number of QPs allocated for device */
-       spinlock_t n_qps_lock;
-       u32 n_srqs_allocated;   /* number of SRQs allocated for device */
-       spinlock_t n_srqs_lock;
-       u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
-       spinlock_t n_mcast_grps_lock;
-
-       u64 ipath_sword;        /* total dwords sent (sample result) */
-       u64 ipath_rword;        /* total dwords received (sample result) */
-       u64 ipath_spkts;        /* total packets sent (sample result) */
-       u64 ipath_rpkts;        /* total packets received (sample result) */
-       /* # of ticks no data sent (sample result) */
-       u64 ipath_xmit_wait;
-       u64 rcv_errors;         /* # of packets with SW detected rcv errs */
-       u64 n_unicast_xmit;     /* total unicast packets sent */
-       u64 n_unicast_rcv;      /* total unicast packets received */
-       u64 n_multicast_xmit;   /* total multicast packets sent */
-       u64 n_multicast_rcv;    /* total multicast packets received */
-       u64 z_symbol_error_counter;             /* starting count for PMA */
-       u64 z_link_error_recovery_counter;      /* starting count for PMA */
-       u64 z_link_downed_counter;              /* starting count for PMA */
-       u64 z_port_rcv_errors;                  /* starting count for PMA */
-       u64 z_port_rcv_remphys_errors;          /* starting count for PMA */
-       u64 z_port_xmit_discards;               /* starting count for PMA */
-       u64 z_port_xmit_data;                   /* starting count for PMA */
-       u64 z_port_rcv_data;                    /* starting count for PMA */
-       u64 z_port_xmit_packets;                /* starting count for PMA */
-       u64 z_port_rcv_packets;                 /* starting count for PMA */
-       u32 z_pkey_violations;                  /* starting count for PMA */
-       u32 z_local_link_integrity_errors;      /* starting count for PMA */
-       u32 z_excessive_buffer_overrun_errors;  /* starting count for PMA */
-       u32 z_vl15_dropped;                     /* starting count for PMA */
-       u32 n_rc_resends;
-       u32 n_rc_acks;
-       u32 n_rc_qacks;
-       u32 n_seq_naks;
-       u32 n_rdma_seq;
-       u32 n_rnr_naks;
-       u32 n_other_naks;
-       u32 n_timeouts;
-       u32 n_pkt_drops;
-       u32 n_vl15_dropped;
-       u32 n_wqe_errs;
-       u32 n_rdma_dup_busy;
-       u32 n_piowait;
-       u32 n_unaligned;
-       u32 port_cap_flags;
-       u32 pma_sample_start;
-       u32 pma_sample_interval;
-       __be16 pma_counter_select[5];
-       u16 pma_tag;
-       u16 qkey_violations;
-       u16 mkey_violations;
-       u16 mkey_lease_period;
-       u16 pending_index;      /* which pending queue is active */
-       u8 pma_sample_status;
-       u8 subnet_timeout;
-       u8 vl_high_limit;
-       struct ipath_opcode_stats opstats[128];
-};
-
-struct ipath_verbs_counters {
-       u64 symbol_error_counter;
-       u64 link_error_recovery_counter;
-       u64 link_downed_counter;
-       u64 port_rcv_errors;
-       u64 port_rcv_remphys_errors;
-       u64 port_xmit_discards;
-       u64 port_xmit_data;
-       u64 port_rcv_data;
-       u64 port_xmit_packets;
-       u64 port_rcv_packets;
-       u32 local_link_integrity_errors;
-       u32 excessive_buffer_overrun_errors;
-       u32 vl15_dropped;
-};
-
-struct ipath_verbs_txreq {
-       struct ipath_qp         *qp;
-       struct ipath_swqe       *wqe;
-       u32                      map_len;
-       u32                      len;
-       struct ipath_sge_state  *ss;
-       struct ipath_pio_header  hdr;
-       struct ipath_sdma_txreq  txreq;
-};
-
-static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
-{
-       return container_of(ibmr, struct ipath_mr, ibmr);
-}
-
-static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd)
-{
-       return container_of(ibpd, struct ipath_pd, ibpd);
-}
-
-static inline struct ipath_ah *to_iah(struct ib_ah *ibah)
-{
-       return container_of(ibah, struct ipath_ah, ibah);
-}
-
-static inline struct ipath_cq *to_icq(struct ib_cq *ibcq)
-{
-       return container_of(ibcq, struct ipath_cq, ibcq);
-}
-
-static inline struct ipath_srq *to_isrq(struct ib_srq *ibsrq)
-{
-       return container_of(ibsrq, struct ipath_srq, ibsrq);
-}
-
-static inline struct ipath_qp *to_iqp(struct ib_qp *ibqp)
-{
-       return container_of(ibqp, struct ipath_qp, ibqp);
-}
-
-static inline struct ipath_ibdev *to_idev(struct ib_device *ibdev)
-{
-       return container_of(ibdev, struct ipath_ibdev, ibdev);
-}
-
-/*
- * This must be called with s_lock held.
- */
-static inline void ipath_schedule_send(struct ipath_qp *qp)
-{
-       if (qp->s_flags & IPATH_S_ANY_WAIT)
-               qp->s_flags &= ~IPATH_S_ANY_WAIT;
-       if (!(qp->s_flags & IPATH_S_BUSY))
-               tasklet_hi_schedule(&qp->s_task);
-}
-
-int ipath_process_mad(struct ib_device *ibdev,
-                     int mad_flags,
-                     u8 port_num,
-                     const struct ib_wc *in_wc,
-                     const struct ib_grh *in_grh,
-                     const struct ib_mad_hdr *in, size_t in_mad_size,
-                     struct ib_mad_hdr *out, size_t *out_mad_size,
-                     u16 *out_mad_pkey_index);
-
-/*
- * Compare the lower 24 bits of the two values.
- * Returns an integer <, ==, or > than zero.
- */
-static inline int ipath_cmp24(u32 a, u32 b)
-{
-       return (((int) a) - ((int) b)) << 8;
-}
-
-struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid);
-
-int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
-                           u64 *rwords, u64 *spkts, u64 *rpkts,
-                           u64 *xmit_wait);
-
-int ipath_get_counters(struct ipath_devdata *dd,
-                      struct ipath_verbs_counters *cntrs);
-
-int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
-
-int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
-
-int ipath_mcast_tree_empty(void);
-
-__be32 ipath_compute_aeth(struct ipath_qp *qp);
-
-struct ipath_qp *ipath_lookup_qpn(struct ipath_qp_table *qpt, u32 qpn);
-
-struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
-                             struct ib_qp_init_attr *init_attr,
-                             struct ib_udata *udata);
-
-int ipath_destroy_qp(struct ib_qp *ibqp);
-
-int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
-
-int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
-                   int attr_mask, struct ib_udata *udata);
-
-int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
-                  int attr_mask, struct ib_qp_init_attr *init_attr);
-
-unsigned ipath_free_all_qps(struct ipath_qp_table *qpt);
-
-int ipath_init_qp_table(struct ipath_ibdev *idev, int size);
-
-void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
-
-unsigned ipath_ib_rate_to_mult(enum ib_rate rate);
-
-int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
-                    u32 hdrwords, struct ipath_sge_state *ss, u32 len);
-
-void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
-
-void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
-
-void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
-
-void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
-
-void ipath_restart_rc(struct ipath_qp *qp, u32 psn);
-
-void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err);
-
-int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr);
-
-void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
-                 int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
-
-int ipath_alloc_lkey(struct ipath_lkey_table *rkt,
-                    struct ipath_mregion *mr);
-
-void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey);
-
-int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
-                 struct ib_sge *sge, int acc);
-
-int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
-                 u32 len, u64 vaddr, u32 rkey, int acc);
-
-int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
-                          struct ib_recv_wr **bad_wr);
-
-struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
-                               struct ib_srq_init_attr *srq_init_attr,
-                               struct ib_udata *udata);
-
-int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
-                    enum ib_srq_attr_mask attr_mask,
-                    struct ib_udata *udata);
-
-int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
-
-int ipath_destroy_srq(struct ib_srq *ibsrq);
-
-void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
-
-int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev,
-                             const struct ib_cq_init_attr *attr,
-                             struct ib_ucontext *context,
-                             struct ib_udata *udata);
-
-int ipath_destroy_cq(struct ib_cq *ibcq);
-
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
-
-int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
-
-struct ib_mr *ipath_get_dma_mr(struct ib_pd *pd, int acc);
-
-struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
-                               u64 virt_addr, int mr_access_flags,
-                               struct ib_udata *udata);
-
-int ipath_dereg_mr(struct ib_mr *ibmr);
-
-struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
-                              struct ib_fmr_attr *fmr_attr);
-
-int ipath_map_phys_fmr(struct ib_fmr *ibfmr, u64 * page_list,
-                      int list_len, u64 iova);
-
-int ipath_unmap_fmr(struct list_head *fmr_list);
-
-int ipath_dealloc_fmr(struct ib_fmr *ibfmr);
-
-void ipath_release_mmap_info(struct kref *ref);
-
-struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
-                                              u32 size,
-                                              struct ib_ucontext *context,
-                                              void *obj);
-
-void ipath_update_mmap_info(struct ipath_ibdev *dev,
-                           struct ipath_mmap_info *ip,
-                           u32 size, void *obj);
-
-int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
-
-void ipath_insert_rnr_queue(struct ipath_qp *qp);
-
-int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
-                  u32 *lengthp, struct ipath_sge_state *ss);
-
-int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
-
-u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
-                  struct ib_global_route *grh, u32 hwords, u32 nwords);
-
-void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
-                          struct ipath_other_headers *ohdr,
-                          u32 bth0, u32 bth2);
-
-void ipath_do_send(unsigned long data);
-
-void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
-                        enum ib_wc_status status);
-
-int ipath_make_rc_req(struct ipath_qp *qp);
-
-int ipath_make_uc_req(struct ipath_qp *qp);
-
-int ipath_make_ud_req(struct ipath_qp *qp);
-
-int ipath_register_ib_device(struct ipath_devdata *);
-
-void ipath_unregister_ib_device(struct ipath_ibdev *);
-
-void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
-
-int ipath_ib_piobufavail(struct ipath_ibdev *);
-
-unsigned ipath_get_npkeys(struct ipath_devdata *);
-
-u32 ipath_get_cr_errpkey(struct ipath_devdata *);
-
-unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
-
-extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
-
-/*
- * Below converts HCA-specific LinkTrainingState to IB PhysPortState
- * values.
- */
-extern const u8 ipath_cvt_physportstate[];
-#define IB_PHYSPORTSTATE_SLEEP 1
-#define IB_PHYSPORTSTATE_POLL 2
-#define IB_PHYSPORTSTATE_DISABLED 3
-#define IB_PHYSPORTSTATE_CFG_TRAIN 4
-#define IB_PHYSPORTSTATE_LINKUP 5
-#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
-
-extern const int ib_ipath_state_ops[];
-
-extern unsigned int ib_ipath_lkey_table_size;
-
-extern unsigned int ib_ipath_max_cqes;
-
-extern unsigned int ib_ipath_max_cqs;
-
-extern unsigned int ib_ipath_max_qp_wrs;
-
-extern unsigned int ib_ipath_max_qps;
-
-extern unsigned int ib_ipath_max_sges;
-
-extern unsigned int ib_ipath_max_mcast_grps;
-
-extern unsigned int ib_ipath_max_mcast_qp_attached;
-
-extern unsigned int ib_ipath_max_srqs;
-
-extern unsigned int ib_ipath_max_srq_sges;
-
-extern unsigned int ib_ipath_max_srq_wrs;
-
-extern const u32 ib_ipath_rnr_table[];
-
-extern struct ib_dma_mapping_ops ipath_dma_mapping_ops;
-
-#endif                         /* IPATH_VERBS_H */
diff --git a/drivers/staging/rdma/ipath/ipath_verbs_mcast.c b/drivers/staging/rdma/ipath/ipath_verbs_mcast.c
deleted file mode 100644 (file)
index 72d476f..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <linux/rculist.h>
-#include <linux/slab.h>
-
-#include "ipath_verbs.h"
-
-/*
- * Global table of GID to attached QPs.
- * The table is global to all ipath devices since a send from one QP/device
- * needs to be locally routed to any locally attached QPs on the same
- * or different device.
- */
-static struct rb_root mcast_tree;
-static DEFINE_SPINLOCK(mcast_lock);
-
-/**
- * ipath_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct
- * @qp: the QP to link
- */
-static struct ipath_mcast_qp *ipath_mcast_qp_alloc(struct ipath_qp *qp)
-{
-       struct ipath_mcast_qp *mqp;
-
-       mqp = kmalloc(sizeof *mqp, GFP_KERNEL);
-       if (!mqp)
-               goto bail;
-
-       mqp->qp = qp;
-       atomic_inc(&qp->refcount);
-
-bail:
-       return mqp;
-}
-
-static void ipath_mcast_qp_free(struct ipath_mcast_qp *mqp)
-{
-       struct ipath_qp *qp = mqp->qp;
-
-       /* Notify ipath_destroy_qp() if it is waiting. */
-       if (atomic_dec_and_test(&qp->refcount))
-               wake_up(&qp->wait);
-
-       kfree(mqp);
-}
-
-/**
- * ipath_mcast_alloc - allocate the multicast GID structure
- * @mgid: the multicast GID
- *
- * A list of QPs will be attached to this structure.
- */
-static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid)
-{
-       struct ipath_mcast *mcast;
-
-       mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
-       if (!mcast)
-               goto bail;
-
-       mcast->mgid = *mgid;
-       INIT_LIST_HEAD(&mcast->qp_list);
-       init_waitqueue_head(&mcast->wait);
-       atomic_set(&mcast->refcount, 0);
-       mcast->n_attached = 0;
-
-bail:
-       return mcast;
-}
-
-static void ipath_mcast_free(struct ipath_mcast *mcast)
-{
-       struct ipath_mcast_qp *p, *tmp;
-
-       list_for_each_entry_safe(p, tmp, &mcast->qp_list, list)
-               ipath_mcast_qp_free(p);
-
-       kfree(mcast);
-}
-
-/**
- * ipath_mcast_find - search the global table for the given multicast GID
- * @mgid: the multicast GID to search for
- *
- * Returns NULL if not found.
- *
- * The caller is responsible for decrementing the reference count if found.
- */
-struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid)
-{
-       struct rb_node *n;
-       unsigned long flags;
-       struct ipath_mcast *mcast;
-
-       spin_lock_irqsave(&mcast_lock, flags);
-       n = mcast_tree.rb_node;
-       while (n) {
-               int ret;
-
-               mcast = rb_entry(n, struct ipath_mcast, rb_node);
-
-               ret = memcmp(mgid->raw, mcast->mgid.raw,
-                            sizeof(union ib_gid));
-               if (ret < 0)
-                       n = n->rb_left;
-               else if (ret > 0)
-                       n = n->rb_right;
-               else {
-                       atomic_inc(&mcast->refcount);
-                       spin_unlock_irqrestore(&mcast_lock, flags);
-                       goto bail;
-               }
-       }
-       spin_unlock_irqrestore(&mcast_lock, flags);
-
-       mcast = NULL;
-
-bail:
-       return mcast;
-}
-
-/**
- * ipath_mcast_add - insert mcast GID into table and attach QP struct
- * @mcast: the mcast GID table
- * @mqp: the QP to attach
- *
- * Return zero if both were added.  Return EEXIST if the GID was already in
- * the table but the QP was added.  Return ESRCH if the QP was already
- * attached and neither structure was added.
- */
-static int ipath_mcast_add(struct ipath_ibdev *dev,
-                          struct ipath_mcast *mcast,
-                          struct ipath_mcast_qp *mqp)
-{
-       struct rb_node **n = &mcast_tree.rb_node;
-       struct rb_node *pn = NULL;
-       int ret;
-
-       spin_lock_irq(&mcast_lock);
-
-       while (*n) {
-               struct ipath_mcast *tmcast;
-               struct ipath_mcast_qp *p;
-
-               pn = *n;
-               tmcast = rb_entry(pn, struct ipath_mcast, rb_node);
-
-               ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw,
-                            sizeof(union ib_gid));
-               if (ret < 0) {
-                       n = &pn->rb_left;
-                       continue;
-               }
-               if (ret > 0) {
-                       n = &pn->rb_right;
-                       continue;
-               }
-
-               /* Search the QP list to see if this is already there. */
-               list_for_each_entry_rcu(p, &tmcast->qp_list, list) {
-                       if (p->qp == mqp->qp) {
-                               ret = ESRCH;
-                               goto bail;
-                       }
-               }
-               if (tmcast->n_attached == ib_ipath_max_mcast_qp_attached) {
-                       ret = ENOMEM;
-                       goto bail;
-               }
-
-               tmcast->n_attached++;
-
-               list_add_tail_rcu(&mqp->list, &tmcast->qp_list);
-               ret = EEXIST;
-               goto bail;
-       }
-
-       spin_lock(&dev->n_mcast_grps_lock);
-       if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) {
-               spin_unlock(&dev->n_mcast_grps_lock);
-               ret = ENOMEM;
-               goto bail;
-       }
-
-       dev->n_mcast_grps_allocated++;
-       spin_unlock(&dev->n_mcast_grps_lock);
-
-       mcast->n_attached++;
-
-       list_add_tail_rcu(&mqp->list, &mcast->qp_list);
-
-       atomic_inc(&mcast->refcount);
-       rb_link_node(&mcast->rb_node, pn, n);
-       rb_insert_color(&mcast->rb_node, &mcast_tree);
-
-       ret = 0;
-
-bail:
-       spin_unlock_irq(&mcast_lock);
-
-       return ret;
-}
-
-int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-       struct ipath_ibdev *dev = to_idev(ibqp->device);
-       struct ipath_mcast *mcast;
-       struct ipath_mcast_qp *mqp;
-       int ret;
-
-       /*
-        * Allocate data structures since its better to do this outside of
-        * spin locks and it will most likely be needed.
-        */
-       mcast = ipath_mcast_alloc(gid);
-       if (mcast == NULL) {
-               ret = -ENOMEM;
-               goto bail;
-       }
-       mqp = ipath_mcast_qp_alloc(qp);
-       if (mqp == NULL) {
-               ipath_mcast_free(mcast);
-               ret = -ENOMEM;
-               goto bail;
-       }
-       switch (ipath_mcast_add(dev, mcast, mqp)) {
-       case ESRCH:
-               /* Neither was used: can't attach the same QP twice. */
-               ipath_mcast_qp_free(mqp);
-               ipath_mcast_free(mcast);
-               ret = -EINVAL;
-               goto bail;
-       case EEXIST:            /* The mcast wasn't used */
-               ipath_mcast_free(mcast);
-               break;
-       case ENOMEM:
-               /* Exceeded the maximum number of mcast groups. */
-               ipath_mcast_qp_free(mqp);
-               ipath_mcast_free(mcast);
-               ret = -ENOMEM;
-               goto bail;
-       default:
-               break;
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
-{
-       struct ipath_qp *qp = to_iqp(ibqp);
-       struct ipath_ibdev *dev = to_idev(ibqp->device);
-       struct ipath_mcast *mcast = NULL;
-       struct ipath_mcast_qp *p, *tmp;
-       struct rb_node *n;
-       int last = 0;
-       int ret;
-
-       spin_lock_irq(&mcast_lock);
-
-       /* Find the GID in the mcast table. */
-       n = mcast_tree.rb_node;
-       while (1) {
-               if (n == NULL) {
-                       spin_unlock_irq(&mcast_lock);
-                       ret = -EINVAL;
-                       goto bail;
-               }
-
-               mcast = rb_entry(n, struct ipath_mcast, rb_node);
-               ret = memcmp(gid->raw, mcast->mgid.raw,
-                            sizeof(union ib_gid));
-               if (ret < 0)
-                       n = n->rb_left;
-               else if (ret > 0)
-                       n = n->rb_right;
-               else
-                       break;
-       }
-
-       /* Search the QP list. */
-       list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) {
-               if (p->qp != qp)
-                       continue;
-               /*
-                * We found it, so remove it, but don't poison the forward
-                * link until we are sure there are no list walkers.
-                */
-               list_del_rcu(&p->list);
-               mcast->n_attached--;
-
-               /* If this was the last attached QP, remove the GID too. */
-               if (list_empty(&mcast->qp_list)) {
-                       rb_erase(&mcast->rb_node, &mcast_tree);
-                       last = 1;
-               }
-               break;
-       }
-
-       spin_unlock_irq(&mcast_lock);
-
-       if (p) {
-               /*
-                * Wait for any list walkers to finish before freeing the
-                * list element.
-                */
-               wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1);
-               ipath_mcast_qp_free(p);
-       }
-       if (last) {
-               atomic_dec(&mcast->refcount);
-               wait_event(mcast->wait, !atomic_read(&mcast->refcount));
-               ipath_mcast_free(mcast);
-               spin_lock_irq(&dev->n_mcast_grps_lock);
-               dev->n_mcast_grps_allocated--;
-               spin_unlock_irq(&dev->n_mcast_grps_lock);
-       }
-
-       ret = 0;
-
-bail:
-       return ret;
-}
-
-int ipath_mcast_tree_empty(void)
-{
-       return mcast_tree.rb_node == NULL;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_wc_ppc64.c b/drivers/staging/rdma/ipath/ipath_wc_ppc64.c
deleted file mode 100644 (file)
index 1a7e20a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This file is conditionally built on PowerPC only.  Otherwise weak symbol
- * versions of the functions exported from here are used.
- */
-
-#include "ipath_kernel.h"
-
-/**
- * ipath_enable_wc - enable write combining for MMIO writes to the device
- * @dd: infinipath device
- *
- * Nothing to do on PowerPC, so just return without error.
- */
-int ipath_enable_wc(struct ipath_devdata *dd)
-{
-       return 0;
-}
diff --git a/drivers/staging/rdma/ipath/ipath_wc_x86_64.c b/drivers/staging/rdma/ipath/ipath_wc_x86_64.c
deleted file mode 100644 (file)
index 7b6e4c8..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This file is conditionally built on x86_64 only.  Otherwise weak symbol
- * versions of the functions exported from here are used.
- */
-
-#include <linux/pci.h>
-#include <asm/processor.h>
-
-#include "ipath_kernel.h"
-
-/**
- * ipath_enable_wc - enable write combining for MMIO writes to the device
- * @dd: infinipath device
- *
- * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable
- * write combining.
- */
-int ipath_enable_wc(struct ipath_devdata *dd)
-{
-       int ret = 0;
-       u64 pioaddr, piolen;
-       unsigned bits;
-       const unsigned long addr = pci_resource_start(dd->pcidev, 0);
-       const size_t len = pci_resource_len(dd->pcidev, 0);
-
-       /*
-        * Set the PIO buffers to be WCCOMB, so we get HT bursts to the
-        * chip.  Linux (possibly the hardware) requires it to be on a power
-        * of 2 address matching the length (which has to be a power of 2).
-        * For rev1, that means the base address, for rev2, it will be just
-        * the PIO buffers themselves.
-        * For chips with two sets of buffers, the calculations are
-        * somewhat more complicated; we need to sum, and the piobufbase
-        * register has both offsets, 2K in low 32 bits, 4K in high 32 bits.
-        * The buffers are still packed, so a single range covers both.
-        */
-       if (dd->ipath_piobcnt2k && dd->ipath_piobcnt4k) { /* 2 sizes */
-               unsigned long pio2kbase, pio4kbase;
-               pio2kbase = dd->ipath_piobufbase & 0xffffffffUL;
-               pio4kbase = (dd->ipath_piobufbase >> 32) & 0xffffffffUL;
-               if (pio2kbase < pio4kbase) { /* all, for now */
-                       pioaddr = addr + pio2kbase;
-                       piolen = pio4kbase - pio2kbase +
-                               dd->ipath_piobcnt4k * dd->ipath_4kalign;
-               } else {
-                       pioaddr = addr + pio4kbase;
-                       piolen = pio2kbase - pio4kbase +
-                               dd->ipath_piobcnt2k * dd->ipath_palign;
-               }
-       } else {  /* single buffer size (2K, currently) */
-               pioaddr = addr + dd->ipath_piobufbase;
-               piolen = dd->ipath_piobcnt2k * dd->ipath_palign +
-                       dd->ipath_piobcnt4k * dd->ipath_4kalign;
-       }
-
-       for (bits = 0; !(piolen & (1ULL << bits)); bits++)
-               /* do nothing */ ;
-
-       if (piolen != (1ULL << bits)) {
-               piolen >>= bits;
-               while (piolen >>= 1)
-                       bits++;
-               piolen = 1ULL << (bits + 1);
-       }
-       if (pioaddr & (piolen - 1)) {
-               u64 atmp;
-               ipath_dbg("pioaddr %llx not on right boundary for size "
-                         "%llx, fixing\n",
-                         (unsigned long long) pioaddr,
-                         (unsigned long long) piolen);
-               atmp = pioaddr & ~(piolen - 1);
-               if (atmp < addr || (atmp + piolen) > (addr + len)) {
-                       ipath_dev_err(dd, "No way to align address/size "
-                                     "(%llx/%llx), no WC mtrr\n",
-                                     (unsigned long long) atmp,
-                                     (unsigned long long) piolen << 1);
-                       ret = -ENODEV;
-               } else {
-                       ipath_dbg("changing WC base from %llx to %llx, "
-                                 "len from %llx to %llx\n",
-                                 (unsigned long long) pioaddr,
-                                 (unsigned long long) atmp,
-                                 (unsigned long long) piolen,
-                                 (unsigned long long) piolen << 1);
-                       pioaddr = atmp;
-                       piolen <<= 1;
-               }
-       }
-
-       if (!ret) {
-               dd->wc_cookie = arch_phys_wc_add(pioaddr, piolen);
-               if (dd->wc_cookie < 0) {
-                       ipath_dev_err(dd, "Seting mtrr failed on PIO buffers\n");
-                       ret = -ENODEV;
-               } else if (dd->wc_cookie == 0)
-                       ipath_cdbg(VERBOSE, "Set mtrr for chip to WC not needed\n");
-               else
-                       ipath_cdbg(VERBOSE, "Set mtrr for chip to WC\n");
-       }
-
-       return ret;
-}
-
-/**
- * ipath_disable_wc - disable write combining for MMIO writes to the device
- * @dd: infinipath device
- */
-void ipath_disable_wc(struct ipath_devdata *dd)
-{
-       arch_phys_wc_del(dd->wc_cookie);
-}
index efd6f4560d3e55ceeab571fdc1d0ebc242a38df2..7e8037e230b8e024ae2bb9d8797bba1d9eab7141 100644 (file)
@@ -1,7 +1,7 @@
 menu "Speakup console speech"
 
 config SPEAKUP
-       depends on VT
+       depends on VT && !MN10300
        tristate "Speakup core"
        ---help---
                This is the Speakup screen reader.  Think of it as a
index b668db6a45fbd98efd1aa8d6dba85d096086e61d..1a2dda09b69d70f706fc2420b633e34492935a5c 100644 (file)
@@ -1210,7 +1210,7 @@ static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer,
                           struct sk_buff *skb, u16 payload_len,
                           struct vnt_mic_hdr *mic_hdr)
 {
-       struct ieee80211_key_seq seq;
+       u64 pn64;
        u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
 
        /* strip header and icv len from payload */
@@ -1243,9 +1243,13 @@ static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer,
                mic_hdr->payload_len = cpu_to_be16(payload_len);
                ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
 
-               ieee80211_get_key_tx_seq(tx_key, &seq);
-
-               memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
+               pn64 = atomic64_read(&tx_key->tx_pn);
+               mic_hdr->ccmp_pn[5] = pn64;
+               mic_hdr->ccmp_pn[4] = pn64 >> 8;
+               mic_hdr->ccmp_pn[3] = pn64 >> 16;
+               mic_hdr->ccmp_pn[2] = pn64 >> 24;
+               mic_hdr->ccmp_pn[1] = pn64 >> 32;
+               mic_hdr->ccmp_pn[0] = pn64 >> 40;
 
                if (ieee80211_has_a4(hdr->frame_control))
                        mic_hdr->hlen = cpu_to_be16(28);
index a0c69b697901de76e18e1bc8272fbded8921eb23..b74e3200131843a762515ce66bc88ced94f3636b 100644 (file)
@@ -716,7 +716,7 @@ static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context,
        u16 payload_len, struct vnt_mic_hdr *mic_hdr)
 {
        struct ieee80211_hdr *hdr = tx_context->hdr;
-       struct ieee80211_key_seq seq;
+       u64 pn64;
        u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
 
        /* strip header and icv len from payload */
@@ -749,9 +749,13 @@ static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context,
                mic_hdr->payload_len = cpu_to_be16(payload_len);
                ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
 
-               ieee80211_get_key_tx_seq(tx_key, &seq);
-
-               memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
+               pn64 = atomic64_read(&tx_key->tx_pn);
+               mic_hdr->ccmp_pn[5] = pn64;
+               mic_hdr->ccmp_pn[4] = pn64 >> 8;
+               mic_hdr->ccmp_pn[3] = pn64 >> 16;
+               mic_hdr->ccmp_pn[2] = pn64 >> 24;
+               mic_hdr->ccmp_pn[1] = pn64 >> 32;
+               mic_hdr->ccmp_pn[0] = pn64 >> 40;
 
                if (ieee80211_has_a4(hdr->frame_control))
                        mic_hdr->hlen = cpu_to_be16(28);
index 3327c49674d37d1a362f706eb30d55d7128d60a5..713c63d9681b3cf4e413cb50f93cd466adb8520c 100644 (file)
@@ -898,7 +898,7 @@ static ssize_t unmap_zeroes_data_store(struct config_item *item,
        da->unmap_zeroes_data = flag;
        pr_debug("dev[%p]: SE Device Thin Provisioning LBPRZ bit: %d\n",
                 da->da_dev, flag);
-       return 0;
+       return count;
 }
 
 /*
index cacd97a8cbd02d32509b0a590ff2c40b59be36b1..da457e25717a6099842e883f4291515dcacf344a 100644 (file)
@@ -828,6 +828,50 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        return dev;
 }
 
+/*
+ * Check if the underlying struct block_device request_queue supports
+ * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
+ * in ATA and we need to set TPE=1
+ */
+bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
+                                      struct request_queue *q, int block_size)
+{
+       if (!blk_queue_discard(q))
+               return false;
+
+       attrib->max_unmap_lba_count = (q->limits.max_discard_sectors << 9) /
+                                                               block_size;
+       /*
+        * Currently hardcoded to 1 in Linux/SCSI code..
+        */
+       attrib->max_unmap_block_desc_count = 1;
+       attrib->unmap_granularity = q->limits.discard_granularity / block_size;
+       attrib->unmap_granularity_alignment = q->limits.discard_alignment /
+                                                               block_size;
+       attrib->unmap_zeroes_data = q->limits.discard_zeroes_data;
+       return true;
+}
+EXPORT_SYMBOL(target_configure_unmap_from_queue);
+
+/*
+ * Convert from blocksize advertised to the initiator to the 512 byte
+ * units unconditionally used by the Linux block layer.
+ */
+sector_t target_to_linux_sector(struct se_device *dev, sector_t lb)
+{
+       switch (dev->dev_attrib.block_size) {
+       case 4096:
+               return lb << 3;
+       case 2048:
+               return lb << 2;
+       case 1024:
+               return lb << 1;
+       default:
+               return lb;
+       }
+}
+EXPORT_SYMBOL(target_to_linux_sector);
+
 int target_configure_device(struct se_device *dev)
 {
        struct se_hba *hba = dev->se_hba;
index e3195700211a3ebc38192391bf6488ed6ae86099..75f0f08b2a34f32d0b2bfdd35fa40f027e74ae75 100644 (file)
@@ -160,25 +160,11 @@ static int fd_configure_device(struct se_device *dev)
                        " block_device blocks: %llu logical_block_size: %d\n",
                        dev_size, div_u64(dev_size, fd_dev->fd_block_size),
                        fd_dev->fd_block_size);
-               /*
-                * Check if the underlying struct block_device request_queue supports
-                * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
-                * in ATA and we need to set TPE=1
-                */
-               if (blk_queue_discard(q)) {
-                       dev->dev_attrib.max_unmap_lba_count =
-                               q->limits.max_discard_sectors;
-                       /*
-                        * Currently hardcoded to 1 in Linux/SCSI code..
-                        */
-                       dev->dev_attrib.max_unmap_block_desc_count = 1;
-                       dev->dev_attrib.unmap_granularity =
-                               q->limits.discard_granularity >> 9;
-                       dev->dev_attrib.unmap_granularity_alignment =
-                               q->limits.discard_alignment;
+
+               if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
+                                                     fd_dev->fd_block_size))
                        pr_debug("IFILE: BLOCK Discard support available,"
-                                       " disabled by default\n");
-               }
+                                " disabled by default\n");
                /*
                 * Enable write same emulation for IBLOCK and use 0xFFFF as
                 * the smaller WRITE_SAME(10) only has a two-byte block count.
@@ -490,9 +476,12 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
        if (S_ISBLK(inode->i_mode)) {
                /* The backend is block device, use discard */
                struct block_device *bdev = inode->i_bdev;
+               struct se_device *dev = cmd->se_dev;
 
-               ret = blkdev_issue_discard(bdev, lba,
-                               nolb, GFP_KERNEL, 0);
+               ret = blkdev_issue_discard(bdev,
+                                          target_to_linux_sector(dev, lba),
+                                          target_to_linux_sector(dev,  nolb),
+                                          GFP_KERNEL, 0);
                if (ret < 0) {
                        pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n",
                                ret);
index 5a2899f9f50b6e4b88730f9db76bf085f97b2b88..abe4eb997a842240f8b76875cc7cfbb7f55dbe0f 100644 (file)
@@ -121,29 +121,11 @@ static int iblock_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
        dev->dev_attrib.hw_queue_depth = q->nr_requests;
 
-       /*
-        * Check if the underlying struct block_device request_queue supports
-        * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
-        * in ATA and we need to set TPE=1
-        */
-       if (blk_queue_discard(q)) {
-               dev->dev_attrib.max_unmap_lba_count =
-                               q->limits.max_discard_sectors;
-
-               /*
-                * Currently hardcoded to 1 in Linux/SCSI code..
-                */
-               dev->dev_attrib.max_unmap_block_desc_count = 1;
-               dev->dev_attrib.unmap_granularity =
-                               q->limits.discard_granularity >> 9;
-               dev->dev_attrib.unmap_granularity_alignment =
-                               q->limits.discard_alignment;
-               dev->dev_attrib.unmap_zeroes_data =
-                               q->limits.discard_zeroes_data;
-
+       if (target_configure_unmap_from_queue(&dev->dev_attrib, q,
+                                             dev->dev_attrib.hw_block_size))
                pr_debug("IBLOCK: BLOCK Discard support available,"
-                               " disabled by default\n");
-       }
+                        " disabled by default\n");
+
        /*
         * Enable write same emulation for IBLOCK and use 0xFFFF as
         * the smaller WRITE_SAME(10) only has a two-byte block count.
@@ -415,9 +397,13 @@ static sense_reason_t
 iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
 {
        struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
+       struct se_device *dev = cmd->se_dev;
        int ret;
 
-       ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0);
+       ret = blkdev_issue_discard(bdev,
+                                  target_to_linux_sector(dev, lba),
+                                  target_to_linux_sector(dev,  nolb),
+                                  GFP_KERNEL, 0);
        if (ret < 0) {
                pr_err("blkdev_issue_discard() failed: %d\n", ret);
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -433,8 +419,10 @@ iblock_execute_write_same(struct se_cmd *cmd)
        struct scatterlist *sg;
        struct bio *bio;
        struct bio_list list;
-       sector_t block_lba = cmd->t_task_lba;
-       sector_t sectors = sbc_get_write_same_sectors(cmd);
+       struct se_device *dev = cmd->se_dev;
+       sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba);
+       sector_t sectors = target_to_linux_sector(dev,
+                                       sbc_get_write_same_sectors(cmd));
 
        if (cmd->prot_op) {
                pr_err("WRITE_SAME: Protection information with IBLOCK"
@@ -648,12 +636,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                  enum dma_data_direction data_direction)
 {
        struct se_device *dev = cmd->se_dev;
+       sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba);
        struct iblock_req *ibr;
        struct bio *bio, *bio_start;
        struct bio_list list;
        struct scatterlist *sg;
        u32 sg_num = sgl_nents;
-       sector_t block_lba;
        unsigned bio_cnt;
        int rw = 0;
        int i;
@@ -679,24 +667,6 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                rw = READ;
        }
 
-       /*
-        * Convert the blocksize advertised to the initiator to the 512 byte
-        * units unconditionally used by the Linux block layer.
-        */
-       if (dev->dev_attrib.block_size == 4096)
-               block_lba = (cmd->t_task_lba << 3);
-       else if (dev->dev_attrib.block_size == 2048)
-               block_lba = (cmd->t_task_lba << 2);
-       else if (dev->dev_attrib.block_size == 1024)
-               block_lba = (cmd->t_task_lba << 1);
-       else if (dev->dev_attrib.block_size == 512)
-               block_lba = cmd->t_task_lba;
-       else {
-               pr_err("Unsupported SCSI -> BLOCK LBA conversion:"
-                               " %u\n", dev->dev_attrib.block_size);
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-       }
-
        ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL);
        if (!ibr)
                goto fail;
index dae0750c2032bd87430ab99609d475a615e691db..db4412fe6b8a3f9ba73d46fadb11dcf1bf40980b 100644 (file)
@@ -141,7 +141,6 @@ void        transport_dump_vpd_proto_id(struct t10_vpd *, unsigned char *, int);
 int    transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int);
 int    transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int);
 int    transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int);
-bool   target_stop_cmd(struct se_cmd *cmd, unsigned long *flags);
 void   transport_clear_lun_ref(struct se_lun *);
 void   transport_send_task_abort(struct se_cmd *);
 sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size);
index fcdcb117c60da36e546370ecfd7e973f17b5d4ec..82a663ba98009fb5f286a88651c9b3a54cf68bbb 100644 (file)
@@ -68,23 +68,25 @@ void core_tmr_release_req(struct se_tmr_req *tmr)
 
        if (dev) {
                spin_lock_irqsave(&dev->se_tmr_lock, flags);
-               list_del(&tmr->tmr_list);
+               list_del_init(&tmr->tmr_list);
                spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
        }
 
        kfree(tmr);
 }
 
-static void core_tmr_handle_tas_abort(
-       struct se_node_acl *tmr_nacl,
-       struct se_cmd *cmd,
-       int tas)
+static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas)
 {
-       bool remove = true;
+       unsigned long flags;
+       bool remove = true, send_tas;
        /*
         * TASK ABORTED status (TAS) bit support
         */
-       if ((tmr_nacl && (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) {
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       send_tas = (cmd->transport_state & CMD_T_TAS);
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
+       if (send_tas) {
                remove = false;
                transport_send_task_abort(cmd);
        }
@@ -107,6 +109,46 @@ static int target_check_cdb_and_preempt(struct list_head *list,
        return 1;
 }
 
+static bool __target_check_io_state(struct se_cmd *se_cmd,
+                                   struct se_session *tmr_sess, int tas)
+{
+       struct se_session *sess = se_cmd->se_sess;
+
+       assert_spin_locked(&sess->sess_cmd_lock);
+       WARN_ON_ONCE(!irqs_disabled());
+       /*
+        * If command already reached CMD_T_COMPLETE state within
+        * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
+        * this se_cmd has been passed to fabric driver and will
+        * not be aborted.
+        *
+        * Otherwise, obtain a local se_cmd->cmd_kref now for TMR
+        * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
+        * long as se_cmd->cmd_kref is still active unless zero.
+        */
+       spin_lock(&se_cmd->t_state_lock);
+       if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) {
+               pr_debug("Attempted to abort io tag: %llu already complete or"
+                       " fabric stop, skipping\n", se_cmd->tag);
+               spin_unlock(&se_cmd->t_state_lock);
+               return false;
+       }
+       if (sess->sess_tearing_down || se_cmd->cmd_wait_set) {
+               pr_debug("Attempted to abort io tag: %llu already shutdown,"
+                       " skipping\n", se_cmd->tag);
+               spin_unlock(&se_cmd->t_state_lock);
+               return false;
+       }
+       se_cmd->transport_state |= CMD_T_ABORTED;
+
+       if ((tmr_sess != se_cmd->se_sess) && tas)
+               se_cmd->transport_state |= CMD_T_TAS;
+
+       spin_unlock(&se_cmd->t_state_lock);
+
+       return kref_get_unless_zero(&se_cmd->cmd_kref);
+}
+
 void core_tmr_abort_task(
        struct se_device *dev,
        struct se_tmr_req *tmr,
@@ -130,34 +172,22 @@ void core_tmr_abort_task(
                if (tmr->ref_task_tag != ref_tag)
                        continue;
 
-               if (!kref_get_unless_zero(&se_cmd->cmd_kref))
-                       continue;
-
                printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
                        se_cmd->se_tfo->get_fabric_name(), ref_tag);
 
-               spin_lock(&se_cmd->t_state_lock);
-               if (se_cmd->transport_state & CMD_T_COMPLETE) {
-                       printk("ABORT_TASK: ref_tag: %llu already complete,"
-                              " skipping\n", ref_tag);
-                       spin_unlock(&se_cmd->t_state_lock);
+               if (!__target_check_io_state(se_cmd, se_sess, 0)) {
                        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-
                        target_put_sess_cmd(se_cmd);
-
                        goto out;
                }
-               se_cmd->transport_state |= CMD_T_ABORTED;
-               spin_unlock(&se_cmd->t_state_lock);
-
                list_del_init(&se_cmd->se_cmd_list);
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
                cancel_work_sync(&se_cmd->work);
                transport_wait_for_tasks(se_cmd);
 
-               target_put_sess_cmd(se_cmd);
                transport_cmd_finish_abort(se_cmd, true);
+               target_put_sess_cmd(se_cmd);
 
                printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for"
                                " ref_tag: %llu\n", ref_tag);
@@ -178,9 +208,11 @@ static void core_tmr_drain_tmr_list(
        struct list_head *preempt_and_abort_list)
 {
        LIST_HEAD(drain_tmr_list);
+       struct se_session *sess;
        struct se_tmr_req *tmr_p, *tmr_pp;
        struct se_cmd *cmd;
        unsigned long flags;
+       bool rc;
        /*
         * Release all pending and outgoing TMRs aside from the received
         * LUN_RESET tmr..
@@ -206,17 +238,39 @@ static void core_tmr_drain_tmr_list(
                if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd))
                        continue;
 
+               sess = cmd->se_sess;
+               if (WARN_ON_ONCE(!sess))
+                       continue;
+
+               spin_lock(&sess->sess_cmd_lock);
                spin_lock(&cmd->t_state_lock);
-               if (!(cmd->transport_state & CMD_T_ACTIVE)) {
+               if (!(cmd->transport_state & CMD_T_ACTIVE) ||
+                    (cmd->transport_state & CMD_T_FABRIC_STOP)) {
                        spin_unlock(&cmd->t_state_lock);
+                       spin_unlock(&sess->sess_cmd_lock);
                        continue;
                }
                if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) {
                        spin_unlock(&cmd->t_state_lock);
+                       spin_unlock(&sess->sess_cmd_lock);
                        continue;
                }
+               if (sess->sess_tearing_down || cmd->cmd_wait_set) {
+                       spin_unlock(&cmd->t_state_lock);
+                       spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
+               cmd->transport_state |= CMD_T_ABORTED;
                spin_unlock(&cmd->t_state_lock);
 
+               rc = kref_get_unless_zero(&cmd->cmd_kref);
+               if (!rc) {
+                       printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n");
+                       spin_unlock(&sess->sess_cmd_lock);
+                       continue;
+               }
+               spin_unlock(&sess->sess_cmd_lock);
+
                list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
        }
        spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
@@ -230,20 +284,26 @@ static void core_tmr_drain_tmr_list(
                        (preempt_and_abort_list) ? "Preempt" : "", tmr_p,
                        tmr_p->function, tmr_p->response, cmd->t_state);
 
+               cancel_work_sync(&cmd->work);
+               transport_wait_for_tasks(cmd);
+
                transport_cmd_finish_abort(cmd, 1);
+               target_put_sess_cmd(cmd);
        }
 }
 
 static void core_tmr_drain_state_list(
        struct se_device *dev,
        struct se_cmd *prout_cmd,
-       struct se_node_acl *tmr_nacl,
+       struct se_session *tmr_sess,
        int tas,
        struct list_head *preempt_and_abort_list)
 {
        LIST_HEAD(drain_task_list);
+       struct se_session *sess;
        struct se_cmd *cmd, *next;
        unsigned long flags;
+       int rc;
 
        /*
         * Complete outstanding commands with TASK_ABORTED SAM status.
@@ -282,6 +342,16 @@ static void core_tmr_drain_state_list(
                if (prout_cmd == cmd)
                        continue;
 
+               sess = cmd->se_sess;
+               if (WARN_ON_ONCE(!sess))
+                       continue;
+
+               spin_lock(&sess->sess_cmd_lock);
+               rc = __target_check_io_state(cmd, tmr_sess, tas);
+               spin_unlock(&sess->sess_cmd_lock);
+               if (!rc)
+                       continue;
+
                list_move_tail(&cmd->state_list, &drain_task_list);
                cmd->state_active = false;
        }
@@ -289,7 +359,7 @@ static void core_tmr_drain_state_list(
 
        while (!list_empty(&drain_task_list)) {
                cmd = list_entry(drain_task_list.next, struct se_cmd, state_list);
-               list_del(&cmd->state_list);
+               list_del_init(&cmd->state_list);
 
                pr_debug("LUN_RESET: %s cmd: %p"
                        " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d"
@@ -313,16 +383,11 @@ static void core_tmr_drain_state_list(
                 * loop above, but we do it down here given that
                 * cancel_work_sync may block.
                 */
-               if (cmd->t_state == TRANSPORT_COMPLETE)
-                       cancel_work_sync(&cmd->work);
-
-               spin_lock_irqsave(&cmd->t_state_lock, flags);
-               target_stop_cmd(cmd, &flags);
-
-               cmd->transport_state |= CMD_T_ABORTED;
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               cancel_work_sync(&cmd->work);
+               transport_wait_for_tasks(cmd);
 
-               core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);
+               core_tmr_handle_tas_abort(cmd, tas);
+               target_put_sess_cmd(cmd);
        }
 }
 
@@ -334,6 +399,7 @@ int core_tmr_lun_reset(
 {
        struct se_node_acl *tmr_nacl = NULL;
        struct se_portal_group *tmr_tpg = NULL;
+       struct se_session *tmr_sess = NULL;
        int tas;
         /*
         * TASK_ABORTED status bit, this is configurable via ConfigFS
@@ -352,8 +418,9 @@ int core_tmr_lun_reset(
         * or struct se_device passthrough..
         */
        if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) {
-               tmr_nacl = tmr->task_cmd->se_sess->se_node_acl;
-               tmr_tpg = tmr->task_cmd->se_sess->se_tpg;
+               tmr_sess = tmr->task_cmd->se_sess;
+               tmr_nacl = tmr_sess->se_node_acl;
+               tmr_tpg = tmr_sess->se_tpg;
                if (tmr_nacl && tmr_tpg) {
                        pr_debug("LUN_RESET: TMR caller fabric: %s"
                                " initiator port %s\n",
@@ -366,7 +433,7 @@ int core_tmr_lun_reset(
                dev->transport->name, tas);
 
        core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list);
-       core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas,
+       core_tmr_drain_state_list(dev, prout_cmd, tmr_sess, tas,
                                preempt_and_abort_list);
 
        /*
index 9f3608e10f25a0ea2c1cf71b419596d558e7f31b..867bc6d0a68a3ecfbd1aab610f01ff73614b3305 100644 (file)
@@ -534,9 +534,6 @@ void transport_deregister_session(struct se_session *se_sess)
 }
 EXPORT_SYMBOL(transport_deregister_session);
 
-/*
- * Called with cmd->t_state_lock held.
- */
 static void target_remove_from_state_list(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
@@ -561,10 +558,6 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists,
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
-       if (write_pending)
-               cmd->t_state = TRANSPORT_WRITE_PENDING;
-
        if (remove_from_lists) {
                target_remove_from_state_list(cmd);
 
@@ -574,6 +567,10 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists,
                cmd->se_lun = NULL;
        }
 
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       if (write_pending)
+               cmd->t_state = TRANSPORT_WRITE_PENDING;
+
        /*
         * Determine if frontend context caller is requesting the stopping of
         * this command for frontend exceptions.
@@ -627,6 +624,8 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
 
 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
+       bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF);
+
        if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
                transport_lun_remove_cmd(cmd);
        /*
@@ -638,7 +637,7 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 
        if (transport_cmd_check_stop_to_fabric(cmd))
                return;
-       if (remove)
+       if (remove && ack_kref)
                transport_put_cmd(cmd);
 }
 
@@ -693,20 +692,11 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
                        success = 1;
        }
 
-       /*
-        * See if we are waiting to complete for an exception condition.
-        */
-       if (cmd->transport_state & CMD_T_REQUEST_STOP) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               complete(&cmd->task_stop_comp);
-               return;
-       }
-
        /*
         * Check for case where an explicit ABORT_TASK has been received
         * and transport_wait_for_tasks() will be waiting for completion..
         */
-       if (cmd->transport_state & CMD_T_ABORTED &&
+       if (cmd->transport_state & CMD_T_ABORTED ||
            cmd->transport_state & CMD_T_STOP) {
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                complete_all(&cmd->t_transport_stop_comp);
@@ -721,10 +711,10 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
        cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-       if (cmd->cpuid == -1)
-               queue_work(target_completion_wq, &cmd->work);
-       else
+       if (cmd->se_cmd_flags & SCF_USE_CPUID)
                queue_work_on(cmd->cpuid, target_completion_wq, &cmd->work);
+       else
+               queue_work(target_completion_wq, &cmd->work);
 }
 EXPORT_SYMBOL(target_complete_cmd);
 
@@ -1203,7 +1193,6 @@ void transport_init_se_cmd(
        INIT_LIST_HEAD(&cmd->state_list);
        init_completion(&cmd->t_transport_stop_comp);
        init_completion(&cmd->cmd_wait_comp);
-       init_completion(&cmd->task_stop_comp);
        spin_lock_init(&cmd->t_state_lock);
        kref_init(&cmd->cmd_kref);
        cmd->transport_state = CMD_T_DEV_ACTIVE;
@@ -1437,6 +1426,12 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
         */
        transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
                                data_length, data_dir, task_attr, sense);
+
+       if (flags & TARGET_SCF_USE_CPUID)
+               se_cmd->se_cmd_flags |= SCF_USE_CPUID;
+       else
+               se_cmd->cpuid = WORK_CPU_UNBOUND;
+
        if (flags & TARGET_SCF_UNKNOWN_SIZE)
                se_cmd->unknown_data_length = 1;
        /*
@@ -1634,33 +1629,6 @@ int target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
 }
 EXPORT_SYMBOL(target_submit_tmr);
 
-/*
- * If the cmd is active, request it to be stopped and sleep until it
- * has completed.
- */
-bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
-       __releases(&cmd->t_state_lock)
-       __acquires(&cmd->t_state_lock)
-{
-       bool was_active = false;
-
-       if (cmd->transport_state & CMD_T_BUSY) {
-               cmd->transport_state |= CMD_T_REQUEST_STOP;
-               spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
-
-               pr_debug("cmd %p waiting to complete\n", cmd);
-               wait_for_completion(&cmd->task_stop_comp);
-               pr_debug("cmd %p stopped successfully\n", cmd);
-
-               spin_lock_irqsave(&cmd->t_state_lock, *flags);
-               cmd->transport_state &= ~CMD_T_REQUEST_STOP;
-               cmd->transport_state &= ~CMD_T_BUSY;
-               was_active = true;
-       }
-
-       return was_active;
-}
-
 /*
  * Handle SAM-esque emulation for generic transport request failures.
  */
@@ -1859,19 +1827,21 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
        return true;
 }
 
+static int __transport_check_aborted_status(struct se_cmd *, int);
+
 void target_execute_cmd(struct se_cmd *cmd)
 {
-       /*
-        * If the received CDB has aleady been aborted stop processing it here.
-        */
-       if (transport_check_aborted_status(cmd, 1))
-               return;
-
        /*
         * Determine if frontend context caller is requesting the stopping of
         * this command for frontend exceptions.
+        *
+        * If the received CDB has aleady been aborted stop processing it here.
         */
        spin_lock_irq(&cmd->t_state_lock);
+       if (__transport_check_aborted_status(cmd, 1)) {
+               spin_unlock_irq(&cmd->t_state_lock);
+               return;
+       }
        if (cmd->transport_state & CMD_T_STOP) {
                pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n",
                        __func__, __LINE__, cmd->tag);
@@ -2222,20 +2192,14 @@ static inline void transport_free_pages(struct se_cmd *cmd)
 }
 
 /**
- * transport_release_cmd - free a command
- * @cmd:       command to free
+ * transport_put_cmd - release a reference to a command
+ * @cmd:       command to release
  *
- * This routine unconditionally frees a command, and reference counting
- * or list removal must be done in the caller.
+ * This routine releases our reference to the command and frees it if possible.
  */
-static int transport_release_cmd(struct se_cmd *cmd)
+static int transport_put_cmd(struct se_cmd *cmd)
 {
        BUG_ON(!cmd->se_tfo);
-
-       if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
-               core_tmr_release_req(cmd->se_tmr_req);
-       if (cmd->t_task_cdb != cmd->__t_task_cdb)
-               kfree(cmd->t_task_cdb);
        /*
         * If this cmd has been setup with target_get_sess_cmd(), drop
         * the kref and call ->release_cmd() in kref callback.
@@ -2243,18 +2207,6 @@ static int transport_release_cmd(struct se_cmd *cmd)
        return target_put_sess_cmd(cmd);
 }
 
-/**
- * transport_put_cmd - release a reference to a command
- * @cmd:       command to release
- *
- * This routine releases our reference to the command and frees it if possible.
- */
-static int transport_put_cmd(struct se_cmd *cmd)
-{
-       transport_free_pages(cmd);
-       return transport_release_cmd(cmd);
-}
-
 void *transport_kmap_data_sg(struct se_cmd *cmd)
 {
        struct scatterlist *sg = cmd->t_data_sg;
@@ -2450,34 +2402,58 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
        }
 }
 
-int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+static bool
+__transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *,
+                          unsigned long *flags);
+
+static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
 {
        unsigned long flags;
+
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       __transport_wait_for_tasks(cmd, true, aborted, tas, &flags);
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+}
+
+int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+{
        int ret = 0;
+       bool aborted = false, tas = false;
 
        if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
                if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
-                        transport_wait_for_tasks(cmd);
+                       target_wait_free_cmd(cmd, &aborted, &tas);
 
-               ret = transport_release_cmd(cmd);
+               if (!aborted || tas)
+                       ret = transport_put_cmd(cmd);
        } else {
                if (wait_for_tasks)
-                       transport_wait_for_tasks(cmd);
+                       target_wait_free_cmd(cmd, &aborted, &tas);
                /*
                 * Handle WRITE failure case where transport_generic_new_cmd()
                 * has already added se_cmd to state_list, but fabric has
                 * failed command before I/O submission.
                 */
-               if (cmd->state_active) {
-                       spin_lock_irqsave(&cmd->t_state_lock, flags);
+               if (cmd->state_active)
                        target_remove_from_state_list(cmd);
-                       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
-               }
 
                if (cmd->se_lun)
                        transport_lun_remove_cmd(cmd);
 
-               ret = transport_put_cmd(cmd);
+               if (!aborted || tas)
+                       ret = transport_put_cmd(cmd);
+       }
+       /*
+        * If the task has been internally aborted due to TMR ABORT_TASK
+        * or LUN_RESET, target_core_tmr.c is responsible for performing
+        * the remaining calls to target_put_sess_cmd(), and not the
+        * callers of this function.
+        */
+       if (aborted) {
+               pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag);
+               wait_for_completion(&cmd->cmd_wait_comp);
+               cmd->se_tfo->release_cmd(cmd);
+               ret = 1;
        }
        return ret;
 }
@@ -2517,26 +2493,46 @@ out:
 }
 EXPORT_SYMBOL(target_get_sess_cmd);
 
+static void target_free_cmd_mem(struct se_cmd *cmd)
+{
+       transport_free_pages(cmd);
+
+       if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
+               core_tmr_release_req(cmd->se_tmr_req);
+       if (cmd->t_task_cdb != cmd->__t_task_cdb)
+               kfree(cmd->t_task_cdb);
+}
+
 static void target_release_cmd_kref(struct kref *kref)
 {
        struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
        struct se_session *se_sess = se_cmd->se_sess;
        unsigned long flags;
+       bool fabric_stop;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (list_empty(&se_cmd->se_cmd_list)) {
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+               target_free_cmd_mem(se_cmd);
                se_cmd->se_tfo->release_cmd(se_cmd);
                return;
        }
-       if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
+
+       spin_lock(&se_cmd->t_state_lock);
+       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
+       spin_unlock(&se_cmd->t_state_lock);
+
+       if (se_cmd->cmd_wait_set || fabric_stop) {
+               list_del_init(&se_cmd->se_cmd_list);
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+               target_free_cmd_mem(se_cmd);
                complete(&se_cmd->cmd_wait_comp);
                return;
        }
-       list_del(&se_cmd->se_cmd_list);
+       list_del_init(&se_cmd->se_cmd_list);
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
+       target_free_cmd_mem(se_cmd);
        se_cmd->se_tfo->release_cmd(se_cmd);
 }
 
@@ -2548,6 +2544,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd)
        struct se_session *se_sess = se_cmd->se_sess;
 
        if (!se_sess) {
+               target_free_cmd_mem(se_cmd);
                se_cmd->se_tfo->release_cmd(se_cmd);
                return 1;
        }
@@ -2564,6 +2561,7 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 {
        struct se_cmd *se_cmd;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (se_sess->sess_tearing_down) {
@@ -2573,8 +2571,15 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
        se_sess->sess_tearing_down = 1;
        list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
 
-       list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
-               se_cmd->cmd_wait_set = 1;
+       list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
+               rc = kref_get_unless_zero(&se_cmd->cmd_kref);
+               if (rc) {
+                       se_cmd->cmd_wait_set = 1;
+                       spin_lock(&se_cmd->t_state_lock);
+                       se_cmd->transport_state |= CMD_T_FABRIC_STOP;
+                       spin_unlock(&se_cmd->t_state_lock);
+               }
+       }
 
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 }
@@ -2587,15 +2592,25 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
 {
        struct se_cmd *se_cmd, *tmp_cmd;
        unsigned long flags;
+       bool tas;
 
        list_for_each_entry_safe(se_cmd, tmp_cmd,
                                &se_sess->sess_wait_list, se_cmd_list) {
-               list_del(&se_cmd->se_cmd_list);
+               list_del_init(&se_cmd->se_cmd_list);
 
                pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
                        " %d\n", se_cmd, se_cmd->t_state,
                        se_cmd->se_tfo->get_cmd_state(se_cmd));
 
+               spin_lock_irqsave(&se_cmd->t_state_lock, flags);
+               tas = (se_cmd->transport_state & CMD_T_TAS);
+               spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);
+
+               if (!target_put_sess_cmd(se_cmd)) {
+                       if (tas)
+                               target_put_sess_cmd(se_cmd);
+               }
+
                wait_for_completion(&se_cmd->cmd_wait_comp);
                pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
                        " fabric state: %d\n", se_cmd, se_cmd->t_state,
@@ -2617,53 +2632,75 @@ void transport_clear_lun_ref(struct se_lun *lun)
        wait_for_completion(&lun->lun_ref_comp);
 }
 
-/**
- * transport_wait_for_tasks - wait for completion to occur
- * @cmd:       command to wait
- *
- * Called from frontend fabric context to wait for storage engine
- * to pause and/or release frontend generated struct se_cmd.
- */
-bool transport_wait_for_tasks(struct se_cmd *cmd)
+static bool
+__transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop,
+                          bool *aborted, bool *tas, unsigned long *flags)
+       __releases(&cmd->t_state_lock)
+       __acquires(&cmd->t_state_lock)
 {
-       unsigned long flags;
 
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       assert_spin_locked(&cmd->t_state_lock);
+       WARN_ON_ONCE(!irqs_disabled());
+
+       if (fabric_stop)
+               cmd->transport_state |= CMD_T_FABRIC_STOP;
+
+       if (cmd->transport_state & CMD_T_ABORTED)
+               *aborted = true;
+
+       if (cmd->transport_state & CMD_T_TAS)
+               *tas = true;
+
        if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) &&
-           !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+           !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
                return false;
-       }
 
        if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) &&
-           !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+           !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
                return false;
-       }
 
-       if (!(cmd->transport_state & CMD_T_ACTIVE)) {
-               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       if (!(cmd->transport_state & CMD_T_ACTIVE))
+               return false;
+
+       if (fabric_stop && *aborted)
                return false;
-       }
 
        cmd->transport_state |= CMD_T_STOP;
 
-       pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n",
-               cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
+       pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d,"
+                " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag,
+                cmd->se_tfo->get_cmd_state(cmd), cmd->t_state);
 
-       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+       spin_unlock_irqrestore(&cmd->t_state_lock, *flags);
 
        wait_for_completion(&cmd->t_transport_stop_comp);
 
-       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       spin_lock_irqsave(&cmd->t_state_lock, *flags);
        cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP);
 
-       pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n",
-               cmd->tag);
+       pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->"
+                "t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag);
 
+       return true;
+}
+
+/**
+ * transport_wait_for_tasks - wait for completion to occur
+ * @cmd:       command to wait
+ *
+ * Called from frontend fabric context to wait for storage engine
+ * to pause and/or release frontend generated struct se_cmd.
+ */
+bool transport_wait_for_tasks(struct se_cmd *cmd)
+{
+       unsigned long flags;
+       bool ret, aborted = false, tas = false;
+
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags);
        spin_unlock_irqrestore(&cmd->t_state_lock, flags);
 
-       return true;
+       return ret;
 }
 EXPORT_SYMBOL(transport_wait_for_tasks);
 
@@ -2845,28 +2882,49 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
 }
 EXPORT_SYMBOL(transport_send_check_condition_and_sense);
 
-int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+       __releases(&cmd->t_state_lock)
+       __acquires(&cmd->t_state_lock)
 {
+       assert_spin_locked(&cmd->t_state_lock);
+       WARN_ON_ONCE(!irqs_disabled());
+
        if (!(cmd->transport_state & CMD_T_ABORTED))
                return 0;
-
        /*
         * If cmd has been aborted but either no status is to be sent or it has
         * already been sent, just return
         */
-       if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS))
+       if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) {
+               if (send_status)
+                       cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
                return 1;
+       }
 
-       pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n",
-                cmd->t_task_cdb[0], cmd->tag);
+       pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB:"
+               " 0x%02x ITT: 0x%08llx\n", cmd->t_task_cdb[0], cmd->tag);
 
        cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
        cmd->scsi_status = SAM_STAT_TASK_ABORTED;
        trace_target_cmd_complete(cmd);
+
+       spin_unlock_irq(&cmd->t_state_lock);
        cmd->se_tfo->queue_status(cmd);
+       spin_lock_irq(&cmd->t_state_lock);
 
        return 1;
 }
+
+int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
+{
+       int ret;
+
+       spin_lock_irq(&cmd->t_state_lock);
+       ret = __transport_check_aborted_status(cmd, send_status);
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       return ret;
+}
 EXPORT_SYMBOL(transport_check_aborted_status);
 
 void transport_send_task_abort(struct se_cmd *cmd)
@@ -2888,11 +2946,17 @@ void transport_send_task_abort(struct se_cmd *cmd)
         */
        if (cmd->data_direction == DMA_TO_DEVICE) {
                if (cmd->se_tfo->write_pending_status(cmd) != 0) {
-                       cmd->transport_state |= CMD_T_ABORTED;
+                       spin_lock_irqsave(&cmd->t_state_lock, flags);
+                       if (cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS) {
+                               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+                               goto send_abort;
+                       }
                        cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS;
+                       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                        return;
                }
        }
+send_abort:
        cmd->scsi_status = SAM_STAT_TASK_ABORTED;
 
        transport_lun_remove_cmd(cmd);
@@ -2909,8 +2973,17 @@ static void target_tmr_work(struct work_struct *work)
        struct se_cmd *cmd = container_of(work, struct se_cmd, work);
        struct se_device *dev = cmd->se_dev;
        struct se_tmr_req *tmr = cmd->se_tmr_req;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       if (cmd->transport_state & CMD_T_ABORTED) {
+               tmr->response = TMR_FUNCTION_REJECTED;
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               goto check_stop;
+       }
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
        switch (tmr->function) {
        case TMR_ABORT_TASK:
                core_tmr_abort_task(dev, tmr, cmd->se_sess);
@@ -2943,9 +3016,17 @@ static void target_tmr_work(struct work_struct *work)
                break;
        }
 
+       spin_lock_irqsave(&cmd->t_state_lock, flags);
+       if (cmd->transport_state & CMD_T_ABORTED) {
+               spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+               goto check_stop;
+       }
        cmd->t_state = TRANSPORT_ISTATE_PROCESSING;
+       spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+
        cmd->se_tfo->queue_tm_rsp(cmd);
 
+check_stop:
        transport_cmd_check_stop_to_fabric(cmd);
 }
 
index dd600e5ead719ba95d41ae0b3b4eeed8a9161eab..94f5154ac788594e4a223147f02c20642ec842df 100644 (file)
@@ -903,7 +903,7 @@ static int tcmu_configure_device(struct se_device *dev)
        info->version = __stringify(TCMU_MAILBOX_VERSION);
 
        info->mem[0].name = "tcm-user command & data buffer";
-       info->mem[0].addr = (phys_addr_t) udev->mb_addr;
+       info->mem[0].addr = (phys_addr_t)(uintptr_t)udev->mb_addr;
        info->mem[0].size = TCMU_RING_SIZE;
        info->mem[0].memtype = UIO_MEM_VIRTUAL;
 
index 8cc4ac64a91c36347b9307addb88ae99d545d2b7..7c92c09be21386c3d60ff41b76a6694234c93432 100644 (file)
@@ -195,7 +195,7 @@ config IMX_THERMAL
          passive trip is crossed.
 
 config SPEAR_THERMAL
-       bool "SPEAr thermal sensor driver"
+       tristate "SPEAr thermal sensor driver"
        depends on PLAT_SPEAR || COMPILE_TEST
        depends on OF
        help
@@ -237,8 +237,8 @@ config DOVE_THERMAL
          framework.
 
 config DB8500_THERMAL
-       bool "DB8500 thermal management"
-       depends on ARCH_U8500
+       tristate "DB8500 thermal management"
+       depends on MFD_DB8500_PRCMU
        default y
        help
          Adds DB8500 thermal management implementation according to the thermal
index e3fbc5a5d88f166930e8633e671348614d00dd4d..6ceac4f2d4b227d52045632992568d08ea158c5b 100644 (file)
@@ -377,26 +377,28 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device,
  * get_load() - get load for a cpu since last updated
  * @cpufreq_device:    &struct cpufreq_cooling_device for this cpu
  * @cpu:       cpu number
+ * @cpu_idx:   index of the cpu in cpufreq_device->allowed_cpus
  *
  * Return: The average load of cpu @cpu in percentage since this
  * function was last called.
  */
-static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu)
+static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu,
+                   int cpu_idx)
 {
        u32 load;
        u64 now, now_idle, delta_time, delta_idle;
 
        now_idle = get_cpu_idle_time(cpu, &now, 0);
-       delta_idle = now_idle - cpufreq_device->time_in_idle[cpu];
-       delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu];
+       delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx];
+       delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx];
 
        if (delta_time <= delta_idle)
                load = 0;
        else
                load = div64_u64(100 * (delta_time - delta_idle), delta_time);
 
-       cpufreq_device->time_in_idle[cpu] = now_idle;
-       cpufreq_device->time_in_idle_timestamp[cpu] = now;
+       cpufreq_device->time_in_idle[cpu_idx] = now_idle;
+       cpufreq_device->time_in_idle_timestamp[cpu_idx] = now;
 
        return load;
 }
@@ -598,7 +600,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
                u32 load;
 
                if (cpu_online(cpu))
-                       load = get_load(cpufreq_device, cpu);
+                       load = get_load(cpufreq_device, cpu, i);
                else
                        load = 0;
 
index be4eedcb839ac22158fe180c2abc37df712d9511..9043f8f918529bd600eda1bbffe3bdf91f036ef4 100644 (file)
@@ -475,14 +475,10 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 
        sensor_np = of_node_get(dev->of_node);
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                struct of_phandle_args sensor_specs;
                int ret, id;
 
-               /* Check whether child is enabled or not */
-               if (!of_device_is_available(child))
-                       continue;
-
                /* For now, thermal framework supports only 1 sensor per zone */
                ret = of_parse_phandle_with_args(child, "thermal-sensors",
                                                 "#thermal-sensor-cells",
@@ -881,16 +877,12 @@ int __init of_parse_thermal_zones(void)
                return 0; /* Run successfully on systems without thermal DT */
        }
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                struct thermal_zone_device *zone;
                struct thermal_zone_params *tzp;
                int i, mask = 0;
                u32 prop;
 
-               /* Check whether child is enabled or not */
-               if (!of_device_is_available(child))
-                       continue;
-
                tz = thermal_of_build_thermal_zone(child);
                if (IS_ERR(tz)) {
                        pr_err("failed to build thermal zone %s: %ld\n",
@@ -968,13 +960,9 @@ void of_thermal_destroy_zones(void)
                return;
        }
 
-       for_each_child_of_node(np, child) {
+       for_each_available_child_of_node(np, child) {
                struct thermal_zone_device *zone;
 
-               /* Check whether child is enabled or not */
-               if (!of_device_is_available(child))
-                       continue;
-
                zone = thermal_zone_get_zone_by_name(child->name);
                if (IS_ERR(zone))
                        continue;
index 44b9c485157d8c6e624548ee7c7cfccacea241d9..0e735acea33afc7b8e747857b57046647d50e7d9 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reboot.h>
@@ -75,8 +76,10 @@ struct rcar_thermal_priv {
 #define rcar_has_irq_support(priv)     ((priv)->common->base)
 #define rcar_id_to_shift(priv)         ((priv)->id * 8)
 
+#define USE_OF_THERMAL 1
 static const struct of_device_id rcar_thermal_dt_ids[] = {
        { .compatible = "renesas,rcar-thermal", },
+       { .compatible = "renesas,rcar-gen2-thermal", .data = (void *)USE_OF_THERMAL },
        {},
 };
 MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
@@ -200,9 +203,9 @@ err_out_unlock:
        return ret;
 }
 
-static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
+static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
+                                        int *temp)
 {
-       struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
        int tmp;
        int ret;
 
@@ -226,6 +229,20 @@ static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
        return 0;
 }
 
+static int rcar_thermal_of_get_temp(void *data, int *temp)
+{
+       struct rcar_thermal_priv *priv = data;
+
+       return rcar_thermal_get_current_temp(priv, temp);
+}
+
+static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
+{
+       struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
+
+       return rcar_thermal_get_current_temp(priv, temp);
+}
+
 static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
                                      int trip, enum thermal_trip_type *type)
 {
@@ -282,6 +299,10 @@ static int rcar_thermal_notify(struct thermal_zone_device *zone,
        return 0;
 }
 
+static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = {
+       .get_temp       = rcar_thermal_of_get_temp,
+};
+
 static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
        .get_temp       = rcar_thermal_get_temp,
        .get_trip_type  = rcar_thermal_get_trip_type,
@@ -318,14 +339,20 @@ static void rcar_thermal_work(struct work_struct *work)
 
        priv = container_of(work, struct rcar_thermal_priv, work.work);
 
-       rcar_thermal_get_temp(priv->zone, &cctemp);
+       ret = rcar_thermal_get_current_temp(priv, &cctemp);
+       if (ret < 0)
+               return;
+
        ret = rcar_thermal_update_temp(priv);
        if (ret < 0)
                return;
 
        rcar_thermal_irq_enable(priv);
 
-       rcar_thermal_get_temp(priv->zone, &nctemp);
+       ret = rcar_thermal_get_current_temp(priv, &nctemp);
+       if (ret < 0)
+               return;
+
        if (nctemp != cctemp)
                thermal_zone_device_update(priv->zone);
 }
@@ -403,6 +430,8 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        struct rcar_thermal_priv *priv;
        struct device *dev = &pdev->dev;
        struct resource *res, *irq;
+       const struct of_device_id *of_id = of_match_device(rcar_thermal_dt_ids, dev);
+       unsigned long of_data = (unsigned long)of_id->data;
        int mres = 0;
        int i;
        int ret = -ENODEV;
@@ -463,7 +492,13 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                if (ret < 0)
                        goto error_unregister;
 
-               priv->zone = thermal_zone_device_register("rcar_thermal",
+               if (of_data == USE_OF_THERMAL)
+                       priv->zone = thermal_zone_of_sensor_register(
+                                               dev, i, priv,
+                                               &rcar_thermal_zone_of_ops);
+               else
+                       priv->zone = thermal_zone_device_register(
+                                               "rcar_thermal",
                                                1, 0, priv,
                                                &rcar_thermal_zone_ops, NULL, 0,
                                                idle);
index 534dd913666283fa13eecfaeb8823ea3d55ac0c8..81b35aace9de0439c4dd76c4c4c0d91597d3b3f3 100644 (file)
@@ -54,8 +54,7 @@ static struct thermal_zone_device_ops ops = {
        .get_temp = thermal_get_temp,
 };
 
-#ifdef CONFIG_PM
-static int spear_thermal_suspend(struct device *dev)
+static int __maybe_unused spear_thermal_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -72,7 +71,7 @@ static int spear_thermal_suspend(struct device *dev)
        return 0;
 }
 
-static int spear_thermal_resume(struct device *dev)
+static int __maybe_unused spear_thermal_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
@@ -94,7 +93,6 @@ static int spear_thermal_resume(struct device *dev)
 
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops, spear_thermal_suspend,
                spear_thermal_resume);
index b3110040164ae64fa29e66fae2d7f5bd4d7d139f..2348fa6137070e19c19d97a5dc436b1a0b762441 100644 (file)
@@ -681,7 +681,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 /* this is called once with whichever end is closed last */
 static void pty_unix98_shutdown(struct tty_struct *tty)
 {
-       devpts_kill_index(tty->driver_data, tty->index);
+       struct inode *ptmx_inode;
+
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               ptmx_inode = tty->driver_data;
+       else
+               ptmx_inode = tty->link->driver_data;
+       devpts_kill_index(ptmx_inode, tty->index);
+       devpts_del_ref(ptmx_inode);
 }
 
 static const struct tty_operations ptm_unix98_ops = {
@@ -773,6 +780,18 @@ static int ptmx_open(struct inode *inode, struct file *filp)
        set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
        tty->driver_data = inode;
 
+       /*
+        * In the case where all references to ptmx inode are dropped and we
+        * still have /dev/tty opened pointing to the master/slave pair (ptmx
+        * is closed/released before /dev/tty), we must make sure that the inode
+        * is still valid when we call the final pty_unix98_shutdown, thus we
+        * hold an additional reference to the ptmx inode. For the same /dev/tty
+        * last close case, we also need to make sure the super_block isn't
+        * destroyed (devpts instance unmounted), before /dev/tty is closed and
+        * on its release devpts_kill_index is called.
+        */
+       devpts_add_ref(inode);
+
        tty_add_file(tty, filp);
 
        slave_inode = devpts_pty_new(inode,
index e71ec78fc11ea1ab074486c8876fa855337564fb..7cd6f9a9054212d905e808bcfba2d76d676aaae2 100644 (file)
@@ -1941,6 +1941,7 @@ pci_wch_ch38x_setup(struct serial_private *priv,
 #define PCIE_VENDOR_ID_WCH             0x1c00
 #define PCIE_DEVICE_ID_WCH_CH382_2S1P  0x3250
 #define PCIE_DEVICE_ID_WCH_CH384_4S    0x3470
+#define PCIE_DEVICE_ID_WCH_CH382_2S    0x3253
 
 #define PCI_VENDOR_ID_PERICOM                  0x12D8
 #define PCI_DEVICE_ID_PERICOM_PI7C9X7951       0x7951
@@ -2637,6 +2638,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_wch_ch353_setup,
        },
+       /* WCH CH382 2S card (16850 clone) */
+       {
+               .vendor         = PCIE_VENDOR_ID_WCH,
+               .device         = PCIE_DEVICE_ID_WCH_CH382_2S,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_wch_ch38x_setup,
+       },
        /* WCH CH382 2S1P card (16850 clone) */
        {
                .vendor         = PCIE_VENDOR_ID_WCH,
@@ -2955,6 +2964,7 @@ enum pci_board_num_t {
        pbn_fintek_4,
        pbn_fintek_8,
        pbn_fintek_12,
+       pbn_wch382_2,
        pbn_wch384_4,
        pbn_pericom_PI7C9X7951,
        pbn_pericom_PI7C9X7952,
@@ -3775,6 +3785,13 @@ static struct pciserial_board pci_boards[] = {
                .base_baud      = 115200,
                .first_offset   = 0x40,
        },
+       [pbn_wch382_2] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+               .first_offset   = 0xC0,
+       },
        [pbn_wch384_4] = {
                .flags          = FL_BASE0,
                .num_ports      = 4,
@@ -5574,6 +5591,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
+       {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_wch382_2 },
+
        {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_wch384_4 },
index b645f9228ed77b90ac6d4791e1b0ab27056a066b..fa49eb1e2fa2429f1c162d1464d06fb727a91d1c 100644 (file)
@@ -1165,7 +1165,7 @@ serial_omap_type(struct uart_port *port)
 
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
-static void wait_for_xmitr(struct uart_omap_port *up)
+static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
 {
        unsigned int status, tmout = 10000;
 
@@ -1343,7 +1343,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
 
 /* Enable or disable the rs485 support */
 static int
-serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
 {
        struct uart_omap_port *up = to_uart_omap_port(port);
        unsigned int mode;
@@ -1356,8 +1356,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
        up->ier = 0;
        serial_out(up, UART_IER, 0);
 
+       /* Clamp the delays to [0, 100ms] */
+       rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
+       rs485->delay_rts_after_send  = min(rs485->delay_rts_after_send, 100U);
+
        /* store new config */
-       port->rs485 = *rs485conf;
+       port->rs485 = *rs485;
 
        /*
         * Just as a precaution, only allow rs485
index 5cec01c75691a6b7ee58ea65346c05572db1bab1..a7eacef1bd2216ef697c12d046cb8975f9fefb20 100644 (file)
@@ -2066,13 +2066,12 @@ retry_open:
                if (tty) {
                        mutex_unlock(&tty_mutex);
                        retval = tty_lock_interruptible(tty);
+                       tty_kref_put(tty);  /* drop kref from tty_driver_lookup_tty() */
                        if (retval) {
                                if (retval == -EINTR)
                                        retval = -ERESTARTSYS;
                                goto err_unref;
                        }
-                       /* safe to drop the kref from tty_driver_lookup_tty() */
-                       tty_kref_put(tty);
                        retval = tty_reopen(tty);
                        if (retval < 0) {
                                tty_unlock(tty);
index d2f3c4cd697f5cd2bae639fd4d88009af5e2733b..dfa9ec03fa8e06dfe03a6e0ae04c62a2ac774103 100644 (file)
@@ -21,10 +21,15 @@ EXPORT_SYMBOL(tty_lock);
 
 int tty_lock_interruptible(struct tty_struct *tty)
 {
+       int ret;
+
        if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty))
                return -EIO;
        tty_kref_get(tty);
-       return mutex_lock_interruptible(&tty->legacy_mutex);
+       ret = mutex_lock_interruptible(&tty->legacy_mutex);
+       if (ret)
+               tty_kref_put(tty);
+       return ret;
 }
 
 void __lockfunc tty_unlock(struct tty_struct *tty)
index b59195edf63634a3be94bcd3dc9ede6d87699185..b635ab67490de3a93a9c0df0f17848376ae1d947 100644 (file)
@@ -85,8 +85,8 @@ static int ci_hdrc_pci_probe(struct pci_dev *pdev,
 
        /* register a nop PHY */
        ci->phy = usb_phy_generic_register();
-       if (!ci->phy)
-               return -ENOMEM;
+       if (IS_ERR(ci->phy))
+               return PTR_ERR(ci->phy);
 
        memset(res, 0, sizeof(res));
        res[0].start    = pci_resource_start(pdev, 0);
index a4f7db2e18ddc295fc4ff1a0cad99bc1ff8b04bd..df47110bad2d6f277b3893bf48657ecfde165fcf 100644 (file)
@@ -100,6 +100,9 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
        if (sscanf(buf, "%u", &mode) != 1)
                return -EINVAL;
 
+       if (mode > 255)
+               return -EBADRQC;
+
        pm_runtime_get_sync(ci->dev);
        spin_lock_irqsave(&ci->lock, flags);
        ret = hw_port_test_set(ci, mode);
index 45f86da1d6d37b4650ddfaf216879195ca9c6542..03b6743461d15de129a2d7908e851db450111d3c 100644 (file)
@@ -158,7 +158,7 @@ static void ci_otg_work(struct work_struct *work)
 int ci_hdrc_otg_init(struct ci_hdrc *ci)
 {
        INIT_WORK(&ci->work, ci_otg_work);
-       ci->wq = create_singlethread_workqueue("ci_otg");
+       ci->wq = create_freezable_workqueue("ci_otg");
        if (!ci->wq) {
                dev_err(ci->dev, "can't create workqueue\n");
                return -ENODEV;
index 350dcd9af5d86eb2181e6cc8f77f25a33f712cce..51b436918f7892b1249c7ec1b19dad515a9a5755 100644 (file)
@@ -5401,6 +5401,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
        }
 
        bos = udev->bos;
+       udev->bos = NULL;
 
        for (i = 0; i < SET_CONFIG_TRIES; ++i) {
 
@@ -5493,11 +5494,8 @@ done:
        usb_set_usb2_hardware_lpm(udev, 1);
        usb_unlocked_enable_lpm(udev);
        usb_enable_ltm(udev);
-       /* release the new BOS descriptor allocated  by hub_port_init() */
-       if (udev->bos != bos) {
-               usb_release_bos_descriptor(udev);
-               udev->bos = bos;
-       }
+       usb_release_bos_descriptor(udev);
+       udev->bos = bos;
        return 0;
 
 re_enumerate:
index fd95ba6ec317fdacb13478d84c4157656893740c..f0decc0d69b5197d183c29ec16882a8fcc18208e 100644 (file)
@@ -1,5 +1,6 @@
 config USB_DWC2
        tristate "DesignWare USB2 DRD Core Support"
+       depends on HAS_DMA
        depends on USB || USB_GADGET
        help
          Say Y here if your system has a Dual Role Hi-Speed USB
index 39a0fa8a4c0aea17b9ecf330c127b110b4b54ba4..46c4ba75dc2afdb744bd32fbf047949ff50ec1fd 100644 (file)
@@ -572,12 +572,6 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
        set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
        clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
 
-       /*
-        * If the force mode bit is already set, don't set it.
-        */
-       if ((gusbcfg & set) && !(gusbcfg & clear))
-               return false;
-
        gusbcfg &= ~clear;
        gusbcfg |= set;
        dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
@@ -625,6 +619,12 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
                         __func__, hsotg->dr_mode);
                break;
        }
+
+       /*
+        * NOTE: This is required for some rockchip soc based
+        * platforms.
+        */
+       msleep(50);
 }
 
 /*
@@ -3278,9 +3278,6 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
 /**
  * During device initialization, read various hardware configuration
  * registers and interpret the contents.
- *
- * This should be called during driver probe. It will perform a core
- * soft reset in order to get the reset values of the parameters.
  */
 int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
 {
@@ -3288,7 +3285,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
        unsigned width;
        u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
        u32 grxfsiz;
-       int retval;
 
        /*
         * Attempt to ensure this device is really a DWC_otg Controller.
@@ -3308,10 +3304,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
                hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
                hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
 
-       retval = dwc2_core_reset(hsotg);
-       if (retval)
-               return retval;
-
        hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);
        hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
        hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3);
index 36606fc33c0d31f0ed52d85bc626f3fe29e36099..a41274aa52adc5f8e1119544a90e8f79c421c2b5 100644 (file)
@@ -1174,14 +1174,11 @@ static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
        failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
                                                     halt_status, n_bytes,
                                                     xfer_done);
-       if (*xfer_done && urb->status != -EINPROGRESS)
-               failed = 1;
-
-       if (failed) {
+       if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
                dwc2_host_complete(hsotg, qtd, urb->status);
                dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
-               dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
-                        failed, *xfer_done, urb->status);
+               dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x\n",
+                        failed, *xfer_done);
                return failed;
        }
 
@@ -1236,21 +1233,23 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
 
        list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
                int i;
+               int qtd_desc_count;
 
                qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
                xfer_done = 0;
+               qtd_desc_count = qtd->n_desc;
 
-               for (i = 0; i < qtd->n_desc; i++) {
+               for (i = 0; i < qtd_desc_count; i++) {
                        if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
                                                       desc_num, halt_status,
-                                                      &xfer_done)) {
-                               qtd = NULL;
-                               break;
-                       }
+                                                      &xfer_done))
+                               goto stop_scan;
+
                        desc_num++;
                }
        }
 
+stop_scan:
        if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
                /*
                 * Resetting the data toggle for bulk and interrupt endpoints
@@ -1258,7 +1257,7 @@ static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
                 */
                if (halt_status == DWC2_HC_XFER_STALL)
                        qh->data_toggle = DWC2_HC_PID_DATA0;
-               else if (qtd)
+               else
                        dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
        }
 
index f8253803a0507543f617af6e2aacc266b43762de..cadba8b13c4837d3e7a3432a3909d69239a70c5d 100644 (file)
@@ -525,11 +525,19 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
        u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
 
        if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+               if (WARN(!chan || !chan->qh,
+                        "chan->qh must be specified for non-control eps\n"))
+                       return;
+
                if (pid == TSIZ_SC_MC_PID_DATA0)
                        chan->qh->data_toggle = DWC2_HC_PID_DATA0;
                else
                        chan->qh->data_toggle = DWC2_HC_PID_DATA1;
        } else {
+               if (WARN(!qtd,
+                        "qtd must be specified for control eps\n"))
+                       return;
+
                if (pid == TSIZ_SC_MC_PID_DATA0)
                        qtd->data_toggle = DWC2_HC_PID_DATA0;
                else
index 510f787434b3d574e40cfe4a5a41511c92f1ad50..690b9fd98b55165a8b1d6a7b8bce30f730ac6805 100644 (file)
@@ -530,7 +530,13 @@ static int dwc2_driver_probe(struct platform_device *dev)
        if (retval)
                return retval;
 
-       /* Reset the controller and detect hardware config values */
+       /*
+        * Reset before dwc2_get_hwparams() then it could get power-on real
+        * reset value form registers.
+        */
+       dwc2_core_reset_and_force_dr_mode(hsotg);
+
+       /* Detect config values from hardware */
        retval = dwc2_get_hwparams(hsotg);
        if (retval)
                goto error;
index 29130682e547e568fb92e32734dbf0141a5e1bef..e4f8b90d9627f9baed5fe4f7fd6dcac7963f49f5 100644 (file)
@@ -856,7 +856,6 @@ struct dwc3 {
        unsigned                pullups_connected:1;
        unsigned                resize_fifos:1;
        unsigned                setup_packet_pending:1;
-       unsigned                start_config_issued:1;
        unsigned                three_stage_setup:1;
        unsigned                usb3_lpm_capable:1;
 
index 3a9354abcb68bfc6e9d27cc64c7155d54dec04e0..8d6b75c2f53b2e0d0991ca3dddc784f6dccecadb 100644 (file)
@@ -555,7 +555,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        int ret;
        u32 reg;
 
-       dwc->start_config_issued = false;
        cfg = le16_to_cpu(ctrl->wValue);
 
        switch (state) {
@@ -737,10 +736,6 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY");
                ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
                break;
-       case USB_REQ_SET_INTERFACE:
-               dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE");
-               dwc->start_config_issued = false;
-               /* Fall through */
        default:
                dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver");
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
index af023a81a0b02160f85e4800594b49aa318190c2..2363bad45af865dd2e7ee0c28e009fff1ae7a7d5 100644 (file)
@@ -385,24 +385,66 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep)
        dep->trb_pool_dma = 0;
 }
 
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep);
+
+/**
+ * dwc3_gadget_start_config - Configure EP resources
+ * @dwc: pointer to our controller context structure
+ * @dep: endpoint that is being enabled
+ *
+ * The assignment of transfer resources cannot perfectly follow the
+ * data book due to the fact that the controller driver does not have
+ * all knowledge of the configuration in advance. It is given this
+ * information piecemeal by the composite gadget framework after every
+ * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook
+ * programming model in this scenario can cause errors. For two
+ * reasons:
+ *
+ * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION
+ * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of
+ * multiple interfaces.
+ *
+ * 2) The databook does not mention doing more DEPXFERCFG for new
+ * endpoint on alt setting (8.1.6).
+ *
+ * The following simplified method is used instead:
+ *
+ * All hardware endpoints can be assigned a transfer resource and this
+ * setting will stay persistent until either a core reset or
+ * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and
+ * do DEPXFERCFG for every hardware endpoint as well. We are
+ * guaranteed that there are as many transfer resources as endpoints.
+ *
+ * This function is called for each endpoint when it is being enabled
+ * but is triggered only when called for EP0-out, which always happens
+ * first, and which should only happen in one of the above conditions.
+ */
 static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 {
        struct dwc3_gadget_ep_cmd_params params;
        u32                     cmd;
+       int                     i;
+       int                     ret;
+
+       if (dep->number)
+               return 0;
 
        memset(&params, 0x00, sizeof(params));
+       cmd = DWC3_DEPCMD_DEPSTARTCFG;
 
-       if (dep->number != 1) {
-               cmd = DWC3_DEPCMD_DEPSTARTCFG;
-               /* XferRscIdx == 0 for ep0 and 2 for the remaining */
-               if (dep->number > 1) {
-                       if (dwc->start_config_issued)
-                               return 0;
-                       dwc->start_config_issued = true;
-                       cmd |= DWC3_DEPCMD_PARAM(2);
-               }
+       ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+       if (ret)
+               return ret;
 
-               return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+       for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+               struct dwc3_ep *dep = dwc->eps[i];
+
+               if (!dep)
+                       continue;
+
+               ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -516,10 +558,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                struct dwc3_trb *trb_st_hw;
                struct dwc3_trb *trb_link;
 
-               ret = dwc3_gadget_set_xfer_resource(dwc, dep);
-               if (ret)
-                       return ret;
-
                dep->endpoint.desc = desc;
                dep->comp_desc = comp_desc;
                dep->type = usb_endpoint_type(desc);
@@ -1636,8 +1674,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        }
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
-       dwc->start_config_issued = false;
-
        /* Start with SuperSpeed Default */
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
@@ -2237,7 +2273,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc3_writel(dwc->regs, DWC3_DCTL, reg);
 
        dwc3_disconnect_gadget(dwc);
-       dwc->start_config_issued = false;
 
        dwc->gadget.speed = USB_SPEED_UNKNOWN;
        dwc->setup_packet_pending = false;
@@ -2288,7 +2323,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
        dwc3_stop_active_transfers(dwc);
        dwc3_clear_stall_all_ep(dwc);
-       dwc->start_config_issued = false;
 
        /* Reset device address to zero */
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2789,6 +2823,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
        dwc->gadget.speed               = USB_SPEED_UNKNOWN;
        dwc->gadget.sg_supported        = true;
        dwc->gadget.name                = "dwc3-gadget";
+       dwc->gadget.is_otg              = dwc->dr_mode == USB_DR_MODE_OTG;
 
        /*
         * FIXME We might be setting max_speed to <SUPER, however versions
index 7e179f81d05cae3e91fd8b976a1f2665e3958cc3..87fb0fd6aaabea260758ba338769d6be70472740 100644 (file)
@@ -130,7 +130,8 @@ struct dev_data {
                                        setup_can_stall : 1,
                                        setup_out_ready : 1,
                                        setup_out_error : 1,
-                                       setup_abort : 1;
+                                       setup_abort : 1,
+                                       gadget_registered : 1;
        unsigned                        setup_wLength;
 
        /* the rest is basically write-once */
@@ -1179,7 +1180,8 @@ dev_release (struct inode *inode, struct file *fd)
 
        /* closing ep0 === shutdown all */
 
-       usb_gadget_unregister_driver (&gadgetfs_driver);
+       if (dev->gadget_registered)
+               usb_gadget_unregister_driver (&gadgetfs_driver);
 
        /* at this point "good" hardware has disconnected the
         * device from USB; the host won't see it any more.
@@ -1847,6 +1849,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                 * kick in after the ep0 descriptor is closed.
                 */
                value = len;
+               dev->gadget_registered = true;
        }
        return value;
 
index 53c0692f1b096eef837624bda521a11ad3181fc4..93d28cb00b76f15de7f281f465a1c791aa7edbbe 100644 (file)
@@ -2340,7 +2340,7 @@ static struct qe_udc *qe_udc_config(struct platform_device *ofdev)
 {
        struct qe_udc *udc;
        struct device_node *np = ofdev->dev.of_node;
-       unsigned int tmp_addr = 0;
+       unsigned long tmp_addr = 0;
        struct usb_device_para __iomem *usbpram;
        unsigned int i;
        u64 size;
index 4dff60d34f732097752e59360e0edcf7e5eb90b4..0d32052bf16f90d5e1ace964cedd484c14a6f65d 100644 (file)
@@ -369,9 +369,20 @@ static inline void set_max_speed(struct net2280_ep *ep, u32 max)
        static const u32 ep_enhanced[9] = { 0x10, 0x60, 0x30, 0x80,
                                          0x50, 0x20, 0x70, 0x40, 0x90 };
 
-       if (ep->dev->enhanced_mode)
+       if (ep->dev->enhanced_mode) {
                reg = ep_enhanced[ep->num];
-       else{
+               switch (ep->dev->gadget.speed) {
+               case USB_SPEED_SUPER:
+                       reg += 2;
+                       break;
+               case USB_SPEED_FULL:
+                       reg += 1;
+                       break;
+               case USB_SPEED_HIGH:
+               default:
+                       break;
+               }
+       } else {
                reg = (ep->num + 1) * 0x10;
                if (ep->dev->gadget.speed != USB_SPEED_HIGH)
                        reg += 1;
index fd73a3ea07c20e4cac1100be1883dce5ea81c033..b86a6f03592ec9e1d42f5bdc813b83c1297b6e52 100644 (file)
@@ -413,9 +413,10 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
                if (!driver->udc_name || strcmp(driver->udc_name,
                                                dev_name(&udc->dev)) == 0) {
                        ret = udc_bind_to_driver(udc, driver);
+                       if (ret != -EPROBE_DEFER)
+                               list_del(&driver->pending);
                        if (ret)
                                goto err4;
-                       list_del(&driver->pending);
                        break;
                }
        }
index 04ce6b156b350e5dd0f9f9a321c79eb4d173b656..e0244fb3903dc85287f509bbac97600734c9b5af 100644 (file)
@@ -112,12 +112,16 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id)
        offset = start;
        if (!start || start == XHCI_HCC_PARAMS_OFFSET) {
                val = readl(base + XHCI_HCC_PARAMS_OFFSET);
+               if (val == ~0)
+                       return 0;
                offset = XHCI_HCC_EXT_CAPS(val) << 2;
                if (!offset)
                        return 0;
        };
        do {
                val = readl(base + offset);
+               if (val == ~0)
+                       return 0;
                if (XHCI_EXT_CAPS_ID(val) == id && offset != start)
                        return offset;
 
index c30de7c39f44088e302b257a480a6c7b159ff167..73f763c4f5f591a2c19053083dedf7b6aa252f31 100644 (file)
@@ -275,8 +275,9 @@ static bool need_bw_sch(struct usb_host_endpoint *ep,
                return false;
 
        /*
-        * for LS & FS periodic endpoints which its device don't attach
-        * to TT are also ignored, root-hub will schedule them directly
+        * for LS & FS periodic endpoints which its device is not behind
+        * a TT are also ignored, root-hub will schedule them directly,
+        * but need set @bpkts field of endpoint context to 1.
         */
        if (is_fs_or_ls(speed) && !has_tt)
                return false;
@@ -339,8 +340,17 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
                GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)),
                usb_endpoint_dir_in(&ep->desc), ep);
 
-       if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT))
+       if (!need_bw_sch(ep, udev->speed, slot_ctx->tt_info & TT_SLOT)) {
+               /*
+                * set @bpkts to 1 if it is LS or FS periodic endpoint, and its
+                * device does not connected through an external HS hub
+                */
+               if (usb_endpoint_xfer_int(&ep->desc)
+                       || usb_endpoint_xfer_isoc(&ep->desc))
+                       ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(1));
+
                return 0;
+       }
 
        bw_index = get_bw_index(xhci, udev, ep);
        sch_bw = &sch_array[bw_index];
index c9ab6a44c34aef05968c0b7e053e63cafd392d8f..9532f5aef71bfe310b499db66a266e9a2c7b32f4 100644 (file)
@@ -696,9 +696,24 @@ static int xhci_mtk_remove(struct platform_device *dev)
 }
 
 #ifdef CONFIG_PM_SLEEP
+/*
+ * if ip sleep fails, and all clocks are disabled, access register will hang
+ * AHB bus, so stop polling roothubs to avoid regs access on bus suspend.
+ * and no need to check whether ip sleep failed or not; this will cause SPM
+ * to wake up system immediately after system suspend complete if ip sleep
+ * fails, it is what we wanted.
+ */
 static int xhci_mtk_suspend(struct device *dev)
 {
        struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+       struct usb_hcd *hcd = mtk->hcd;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       xhci_dbg(xhci, "%s: stop port polling\n", __func__);
+       clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       del_timer_sync(&hcd->rh_timer);
+       clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+       del_timer_sync(&xhci->shared_hcd->rh_timer);
 
        xhci_mtk_host_disable(mtk);
        xhci_mtk_phy_power_off(mtk);
@@ -710,11 +725,19 @@ static int xhci_mtk_suspend(struct device *dev)
 static int xhci_mtk_resume(struct device *dev)
 {
        struct xhci_hcd_mtk *mtk = dev_get_drvdata(dev);
+       struct usb_hcd *hcd = mtk->hcd;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
        usb_wakeup_disable(mtk);
        xhci_mtk_clks_enable(mtk);
        xhci_mtk_phy_power_on(mtk);
        xhci_mtk_host_enable(mtk);
+
+       xhci_dbg(xhci, "%s: restart port polling\n", __func__);
+       set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       usb_hcd_poll_rh_status(hcd);
+       set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
+       usb_hcd_poll_rh_status(xhci->shared_hcd);
        return 0;
 }
 
index 58c43ed7ff3b6c5291bab17bb646c2bbefcf67b6..f0640b7a1c42e2b82c4b8c6071fa0c43561ab7e7 100644 (file)
@@ -28,7 +28,9 @@
 #include "xhci.h"
 #include "xhci-trace.h"
 
-#define PORT2_SSIC_CONFIG_REG2 0x883c
+#define SSIC_PORT_NUM          2
+#define SSIC_PORT_CFG2         0x880c
+#define SSIC_PORT_CFG2_OFFSET  0x30
 #define PROG_DONE              (1 << 30)
 #define SSIC_PORT_UNUSED       (1 << 31)
 
@@ -45,6 +47,7 @@
 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI            0x22b5
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI                0xa12f
 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI       0x9d2f
+#define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI             0x0aa8
 
 static const char hcd_name[] = "xhci_hcd";
 
@@ -151,9 +154,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
                (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
                 pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI ||
-                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) {
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+                pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) {
                xhci->quirks |= XHCI_PME_STUCK_QUIRK;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
+                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
+               xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
+       }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_EJ168) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
@@ -312,22 +320,20 @@ static void xhci_pci_remove(struct pci_dev *dev)
  * SSIC PORT need to be marked as "unused" before putting xHCI
  * into D3. After D3 exit, the SSIC port need to be marked as "used".
  * Without this change, xHCI might not enter D3 state.
- * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
- * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
  */
-static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
+static void xhci_ssic_port_unused_quirk(struct usb_hcd *hcd, bool suspend)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
        u32 val;
        void __iomem *reg;
+       int i;
 
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
-                pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
-
-               reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
+       for (i = 0; i < SSIC_PORT_NUM; i++) {
+               reg = (void __iomem *) xhci->cap_regs +
+                               SSIC_PORT_CFG2 +
+                               i * SSIC_PORT_CFG2_OFFSET;
 
-               /* Notify SSIC that SSIC profile programming is not done */
+               /* Notify SSIC that SSIC profile programming is not done. */
                val = readl(reg) & ~PROG_DONE;
                writel(val, reg);
 
@@ -344,6 +350,17 @@ static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
                writel(val, reg);
                readl(reg);
        }
+}
+
+/*
+ * Make sure PME works on some Intel xHCI controllers by writing 1 to clear
+ * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
+ */
+static void xhci_pme_quirk(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       void __iomem *reg;
+       u32 val;
 
        reg = (void __iomem *) xhci->cap_regs + 0x80a4;
        val = readl(reg);
@@ -355,6 +372,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
+       int                     ret;
 
        /*
         * Systems with the TI redriver that loses port status change events
@@ -364,9 +382,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
                pdev->no_d3cold = true;
 
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(hcd, true);
+               xhci_pme_quirk(hcd);
+
+       if (xhci->quirks & XHCI_SSIC_PORT_UNUSED)
+               xhci_ssic_port_unused_quirk(hcd, true);
 
-       return xhci_suspend(xhci, do_wakeup);
+       ret = xhci_suspend(xhci, do_wakeup);
+       if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED))
+               xhci_ssic_port_unused_quirk(hcd, false);
+
+       return ret;
 }
 
 static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
@@ -396,8 +421,11 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
        if (pdev->vendor == PCI_VENDOR_ID_INTEL)
                usb_enable_intel_xhci_ports(pdev);
 
+       if (xhci->quirks & XHCI_SSIC_PORT_UNUSED)
+               xhci_ssic_port_unused_quirk(hcd, false);
+
        if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
-               xhci_pme_quirk(hcd, false);
+               xhci_pme_quirk(hcd);
 
        retval = xhci_resume(xhci, hibernated);
        return retval;
index 770b6b08879790ec2754e26fbb424fcd03c1205c..d39d6bf1d090dad06687892ed723ea3a5e993083 100644 (file)
@@ -184,7 +184,8 @@ static int xhci_plat_probe(struct platform_device *pdev)
                struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
 
                /* Just copy data for now */
-               *priv = *priv_match;
+               if (priv_match)
+                       *priv = *priv_match;
        }
 
        if (xhci_plat_type_is(hcd, XHCI_PLAT_TYPE_MARVELL_ARMADA)) {
index f1c21c40b4a674e6a8fad98ac34c0b9385df76be..3915657e6078b66211fd699eab9bf227752f1ffc 100644 (file)
@@ -2193,10 +2193,6 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                }
        /* Fast path - was this the last TRB in the TD for this URB? */
        } else if (event_trb == td->last_trb) {
-               if (td->urb_length_set && trb_comp_code == COMP_SHORT_TX)
-                       return finish_td(xhci, td, event_trb, event, ep,
-                                        status, false);
-
                if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
@@ -2248,12 +2244,6 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                        td->urb->actual_length +=
                                TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
                                EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
-
-               if (trb_comp_code == COMP_SHORT_TX) {
-                       xhci_dbg(xhci, "mid bulk/intr SP, wait for last TRB event\n");
-                       td->urb_length_set = true;
-                       return 0;
-               }
        }
 
        return finish_td(xhci, td, event_trb, event, ep, status, false);
index 26a44c0e969e621be5d2a6e2d947cf9292505716..0c8087d3c3138f72e6eeaedc928c09453ab32285 100644 (file)
@@ -1554,7 +1554,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
                                "HW died, freeing TD.");
                urb_priv = urb->hcpriv;
-               for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+               for (i = urb_priv->td_cnt;
+                    i < urb_priv->length && xhci->devs[urb->dev->slot_id];
+                    i++) {
                        td = urb_priv->td[i];
                        if (!list_empty(&td->td_list))
                                list_del_init(&td->td_list);
index 9be7348872baab804691c7fd10f31115a0c7e3fe..cc651383ce5a85d713c66b032a0aa30bd4331dc8 100644 (file)
@@ -1631,6 +1631,7 @@ struct xhci_hcd {
 #define XHCI_BROKEN_STREAMS    (1 << 19)
 #define XHCI_PME_STUCK_QUIRK   (1 << 20)
 #define XHCI_MTK_HOST          (1 << 21)
+#define XHCI_SSIC_PORT_UNUSED  (1 << 22)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
index 795a45b1b25bacb016552b4d0635166965ebfce6..58487a4735218518ce50326750ca8718aaa2a516 100644 (file)
@@ -662,7 +662,7 @@ static int musb_tx_dma_set_mode_mentor(struct dma_controller *dma,
                csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
                csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */
        }
-       channel->desired_mode = mode;
+       channel->desired_mode = *mode;
        musb_writew(epio, MUSB_TXCSR, csr);
 
        return 0;
@@ -2003,10 +2003,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                                qh->offset,
                                urb->transfer_buffer_length);
 
-                       done = musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh,
-                                                             urb, xfer_len,
-                                                             iso_err);
-                       if (done)
+                       if (musb_rx_dma_in_inventra_cppi41(c, hw_ep, qh, urb,
+                                                          xfer_len, iso_err))
                                goto finish;
                        else
                                dev_err(musb->controller, "error: rx_dma failed\n");
index b2685e75a6835fe2b4615b3f86f7aef378fedcae..3eaa4ba6867d408a516abec7bb4180d5c9f05d40 100644 (file)
@@ -348,7 +348,9 @@ static int ux500_suspend(struct device *dev)
        struct ux500_glue       *glue = dev_get_drvdata(dev);
        struct musb             *musb = glue_to_musb(glue);
 
-       usb_phy_set_suspend(musb->xceiv, 1);
+       if (musb)
+               usb_phy_set_suspend(musb->xceiv, 1);
+
        clk_disable_unprepare(glue->clk);
 
        return 0;
@@ -366,7 +368,8 @@ static int ux500_resume(struct device *dev)
                return ret;
        }
 
-       usb_phy_set_suspend(musb->xceiv, 0);
+       if (musb)
+               usb_phy_set_suspend(musb->xceiv, 0);
 
        return 0;
 }
index 0d19a6d61a71f7ccb7a55e1b90a7d5d5f27db535..72b387d592c278eafb5a73e519482b405d921e39 100644 (file)
@@ -757,14 +757,8 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
        otg->host = host;
        dev_dbg(otg->usb_phy->dev, "host driver registered w/ tranceiver\n");
 
-       /*
-        * Kick the state machine work, if peripheral is not supported
-        * or peripheral is already registered with us.
-        */
-       if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {
-               pm_runtime_get_sync(otg->usb_phy->dev);
-               schedule_work(&motg->sm_work);
-       }
+       pm_runtime_get_sync(otg->usb_phy->dev);
+       schedule_work(&motg->sm_work);
 
        return 0;
 }
@@ -827,14 +821,8 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,
        dev_dbg(otg->usb_phy->dev,
                "peripheral driver registered w/ tranceiver\n");
 
-       /*
-        * Kick the state machine work, if host is not supported
-        * or host is already registered with us.
-        */
-       if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {
-               pm_runtime_get_sync(otg->usb_phy->dev);
-               schedule_work(&motg->sm_work);
-       }
+       pm_runtime_get_sync(otg->usb_phy->dev);
+       schedule_work(&motg->sm_work);
 
        return 0;
 }
@@ -1599,6 +1587,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
                                                &motg->id.nb);
                if (ret < 0) {
                        dev_err(&pdev->dev, "register ID notifier failed\n");
+                       extcon_unregister_notifier(motg->vbus.extcon,
+                                                  EXTCON_USB, &motg->vbus.nb);
                        return ret;
                }
 
@@ -1660,15 +1650,6 @@ static int msm_otg_probe(struct platform_device *pdev)
        if (!motg)
                return -ENOMEM;
 
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata) {
-               if (!np)
-                       return -ENXIO;
-               ret = msm_otg_read_dt(pdev, motg);
-               if (ret)
-                       return ret;
-       }
-
        motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
                                     GFP_KERNEL);
        if (!motg->phy.otg)
@@ -1710,6 +1691,15 @@ static int msm_otg_probe(struct platform_device *pdev)
        if (!motg->regs)
                return -ENOMEM;
 
+       pdata = dev_get_platdata(&pdev->dev);
+       if (!pdata) {
+               if (!np)
+                       return -ENXIO;
+               ret = msm_otg_read_dt(pdev, motg);
+               if (ret)
+                       return ret;
+       }
+
        /*
         * NOTE: The PHYs can be multiplexed between the chipidea controller
         * and the dwc3 controller, using a single bit. It is important that
@@ -1717,8 +1707,10 @@ static int msm_otg_probe(struct platform_device *pdev)
         */
        if (motg->phy_number) {
                phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
-               if (!phy_select)
-                       return -ENOMEM;
+               if (!phy_select) {
+                       ret = -ENOMEM;
+                       goto unregister_extcon;
+               }
                /* Enable second PHY with the OTG port */
                writel(0x1, phy_select);
        }
@@ -1728,7 +1720,8 @@ static int msm_otg_probe(struct platform_device *pdev)
        motg->irq = platform_get_irq(pdev, 0);
        if (motg->irq < 0) {
                dev_err(&pdev->dev, "platform_get_irq failed\n");
-               return motg->irq;
+               ret = motg->irq;
+               goto unregister_extcon;
        }
 
        regs[0].supply = "vddcx";
@@ -1737,7 +1730,7 @@ static int msm_otg_probe(struct platform_device *pdev)
 
        ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs);
        if (ret)
-               return ret;
+               goto unregister_extcon;
 
        motg->vddcx = regs[0].consumer;
        motg->v3p3  = regs[1].consumer;
@@ -1834,6 +1827,12 @@ disable_clks:
        clk_disable_unprepare(motg->clk);
        if (!IS_ERR(motg->core_clk))
                clk_disable_unprepare(motg->core_clk);
+unregister_extcon:
+       extcon_unregister_notifier(motg->id.extcon,
+                                  EXTCON_USB_HOST, &motg->id.nb);
+       extcon_unregister_notifier(motg->vbus.extcon,
+                                  EXTCON_USB, &motg->vbus.nb);
+
        return ret;
 }
 
index c2936dc48ca7b45b0e5c186859d2879569719323..00bfea01be6501d9b53ccc7975b069c24bc57d7b 100644 (file)
@@ -220,7 +220,7 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
 /* Return true if the vbus is there */
 static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
 {
-       unsigned int vbus_value;
+       unsigned int vbus_value = 0;
 
        if (!mxs_phy->regmap_anatop)
                return false;
index f612dda9c9778aaf78da02d7422f2d73a14818c2..56ecb8b5115dd66b8d0db52849e9738e127a2afa 100644 (file)
@@ -475,22 +475,6 @@ config USB_SERIAL_MOS7840
          To compile this driver as a module, choose M here: the
          module will be called mos7840.  If unsure, choose N.
 
-config USB_SERIAL_MXUPORT11
-       tristate "USB Moxa UPORT 11x0 Serial Driver"
-       ---help---
-         Say Y here if you want to use a MOXA UPort 11x0 Serial hub.
-
-         This driver supports:
-
-         - UPort 1110  : 1 port RS-232 USB to Serial Hub.
-         - UPort 1130  : 1 port RS-422/485 USB to Serial Hub.
-         - UPort 1130I : 1 port RS-422/485 USB to Serial Hub with Isolation.
-         - UPort 1150  : 1 port RS-232/422/485 USB to Serial Hub.
-         - UPort 1150I : 1 port RS-232/422/485 USB to Serial Hub with Isolation.
-
-         To compile this driver as a module, choose M here: the
-         module will be called mxu11x0.
-
 config USB_SERIAL_MXUPORT
        tristate "USB Moxa UPORT Serial Driver"
        ---help---
index f3fa5e53702d869faa08cb7c2b05e03beae85390..349d9df0895f5afc4139b046383362bc46348739 100644 (file)
@@ -38,7 +38,6 @@ obj-$(CONFIG_USB_SERIAL_METRO)                        += metro-usb.o
 obj-$(CONFIG_USB_SERIAL_MOS7720)               += mos7720.o
 obj-$(CONFIG_USB_SERIAL_MOS7840)               += mos7840.o
 obj-$(CONFIG_USB_SERIAL_MXUPORT)               += mxuport.o
-obj-$(CONFIG_USB_SERIAL_MXUPORT11)             += mxu11x0.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)                        += navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)               += omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTICON)               += opticon.o
index 987813b8a7f91e27b6a582a44ca88254dbd49c13..73a366de5102ada85dbf9539c75a9bb70ddaf4fd 100644 (file)
@@ -163,6 +163,9 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
        { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
        { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */
+       { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
+       { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
+       { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
        { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
        { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
        { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */
diff --git a/drivers/usb/serial/mxu11x0.c b/drivers/usb/serial/mxu11x0.c
deleted file mode 100644 (file)
index 6196073..0000000
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*
- * USB Moxa UPORT 11x0 Serial Driver
- *
- * Copyright (C) 2007 MOXA Technologies Co., Ltd.
- * Copyright (C) 2015 Mathieu Othacehe <m.othacehe@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- *
- * Supports the following Moxa USB to serial converters:
- *  UPort 1110,  1 port RS-232 USB to Serial Hub.
- *  UPort 1130,  1 port RS-422/485 USB to Serial Hub.
- *  UPort 1130I, 1 port RS-422/485 USB to Serial Hub with isolation
- *    protection.
- *  UPort 1150,  1 port RS-232/422/485 USB to Serial Hub.
- *  UPort 1150I, 1 port RS-232/422/485 USB to Serial Hub with isolation
- *  protection.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/jiffies.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-
-/* Vendor and product ids */
-#define MXU1_VENDOR_ID                         0x110a
-#define MXU1_1110_PRODUCT_ID                   0x1110
-#define MXU1_1130_PRODUCT_ID                   0x1130
-#define MXU1_1150_PRODUCT_ID                   0x1150
-#define MXU1_1151_PRODUCT_ID                   0x1151
-#define MXU1_1131_PRODUCT_ID                   0x1131
-
-/* Commands */
-#define MXU1_GET_VERSION                       0x01
-#define MXU1_GET_PORT_STATUS                   0x02
-#define MXU1_GET_PORT_DEV_INFO                 0x03
-#define MXU1_GET_CONFIG                                0x04
-#define MXU1_SET_CONFIG                                0x05
-#define MXU1_OPEN_PORT                         0x06
-#define MXU1_CLOSE_PORT                                0x07
-#define MXU1_START_PORT                                0x08
-#define MXU1_STOP_PORT                         0x09
-#define MXU1_TEST_PORT                         0x0A
-#define MXU1_PURGE_PORT                                0x0B
-#define MXU1_RESET_EXT_DEVICE                  0x0C
-#define MXU1_GET_OUTQUEUE                      0x0D
-#define MXU1_WRITE_DATA                                0x80
-#define MXU1_READ_DATA                         0x81
-#define MXU1_REQ_TYPE_CLASS                    0x82
-
-/* Module identifiers */
-#define MXU1_I2C_PORT                          0x01
-#define MXU1_IEEE1284_PORT                     0x02
-#define MXU1_UART1_PORT                                0x03
-#define MXU1_UART2_PORT                                0x04
-#define MXU1_RAM_PORT                          0x05
-
-/* Modem status */
-#define MXU1_MSR_DELTA_CTS                     0x01
-#define MXU1_MSR_DELTA_DSR                     0x02
-#define MXU1_MSR_DELTA_RI                      0x04
-#define MXU1_MSR_DELTA_CD                      0x08
-#define MXU1_MSR_CTS                           0x10
-#define MXU1_MSR_DSR                           0x20
-#define MXU1_MSR_RI                            0x40
-#define MXU1_MSR_CD                            0x80
-#define MXU1_MSR_DELTA_MASK                    0x0F
-#define MXU1_MSR_MASK                          0xF0
-
-/* Line status */
-#define MXU1_LSR_OVERRUN_ERROR                 0x01
-#define MXU1_LSR_PARITY_ERROR                  0x02
-#define MXU1_LSR_FRAMING_ERROR                 0x04
-#define MXU1_LSR_BREAK                         0x08
-#define MXU1_LSR_ERROR                         0x0F
-#define MXU1_LSR_RX_FULL                       0x10
-#define MXU1_LSR_TX_EMPTY                      0x20
-
-/* Modem control */
-#define MXU1_MCR_LOOP                          0x04
-#define MXU1_MCR_DTR                           0x10
-#define MXU1_MCR_RTS                           0x20
-
-/* Mask settings */
-#define MXU1_UART_ENABLE_RTS_IN                        0x0001
-#define MXU1_UART_DISABLE_RTS                  0x0002
-#define MXU1_UART_ENABLE_PARITY_CHECKING       0x0008
-#define MXU1_UART_ENABLE_DSR_OUT               0x0010
-#define MXU1_UART_ENABLE_CTS_OUT               0x0020
-#define MXU1_UART_ENABLE_X_OUT                 0x0040
-#define MXU1_UART_ENABLE_XA_OUT                        0x0080
-#define MXU1_UART_ENABLE_X_IN                  0x0100
-#define MXU1_UART_ENABLE_DTR_IN                        0x0800
-#define MXU1_UART_DISABLE_DTR                  0x1000
-#define MXU1_UART_ENABLE_MS_INTS               0x2000
-#define MXU1_UART_ENABLE_AUTO_START_DMA                0x4000
-#define MXU1_UART_SEND_BREAK_SIGNAL            0x8000
-
-/* Parity */
-#define MXU1_UART_NO_PARITY                    0x00
-#define MXU1_UART_ODD_PARITY                   0x01
-#define MXU1_UART_EVEN_PARITY                  0x02
-#define MXU1_UART_MARK_PARITY                  0x03
-#define MXU1_UART_SPACE_PARITY                 0x04
-
-/* Stop bits */
-#define MXU1_UART_1_STOP_BITS                  0x00
-#define MXU1_UART_1_5_STOP_BITS                        0x01
-#define MXU1_UART_2_STOP_BITS                  0x02
-
-/* Bits per character */
-#define MXU1_UART_5_DATA_BITS                  0x00
-#define MXU1_UART_6_DATA_BITS                  0x01
-#define MXU1_UART_7_DATA_BITS                  0x02
-#define MXU1_UART_8_DATA_BITS                  0x03
-
-/* Operation modes */
-#define MXU1_UART_232                          0x00
-#define MXU1_UART_485_RECEIVER_DISABLED                0x01
-#define MXU1_UART_485_RECEIVER_ENABLED         0x02
-
-/* Pipe transfer mode and timeout */
-#define MXU1_PIPE_MODE_CONTINUOUS              0x01
-#define MXU1_PIPE_MODE_MASK                    0x03
-#define MXU1_PIPE_TIMEOUT_MASK                 0x7C
-#define MXU1_PIPE_TIMEOUT_ENABLE               0x80
-
-/* Config struct */
-struct mxu1_uart_config {
-       __be16  wBaudRate;
-       __be16  wFlags;
-       u8      bDataBits;
-       u8      bParity;
-       u8      bStopBits;
-       char    cXon;
-       char    cXoff;
-       u8      bUartMode;
-} __packed;
-
-/* Purge modes */
-#define MXU1_PURGE_OUTPUT                      0x00
-#define MXU1_PURGE_INPUT                       0x80
-
-/* Read/Write data */
-#define MXU1_RW_DATA_ADDR_SFR                  0x10
-#define MXU1_RW_DATA_ADDR_IDATA                        0x20
-#define MXU1_RW_DATA_ADDR_XDATA                        0x30
-#define MXU1_RW_DATA_ADDR_CODE                 0x40
-#define MXU1_RW_DATA_ADDR_GPIO                 0x50
-#define MXU1_RW_DATA_ADDR_I2C                  0x60
-#define MXU1_RW_DATA_ADDR_FLASH                        0x70
-#define MXU1_RW_DATA_ADDR_DSP                  0x80
-
-#define MXU1_RW_DATA_UNSPECIFIED               0x00
-#define MXU1_RW_DATA_BYTE                      0x01
-#define MXU1_RW_DATA_WORD                      0x02
-#define MXU1_RW_DATA_DOUBLE_WORD               0x04
-
-struct mxu1_write_data_bytes {
-       u8      bAddrType;
-       u8      bDataType;
-       u8      bDataCounter;
-       __be16  wBaseAddrHi;
-       __be16  wBaseAddrLo;
-       u8      bData[0];
-} __packed;
-
-/* Interrupt codes */
-#define MXU1_CODE_HARDWARE_ERROR               0xFF
-#define MXU1_CODE_DATA_ERROR                   0x03
-#define MXU1_CODE_MODEM_STATUS                 0x04
-
-static inline int mxu1_get_func_from_code(unsigned char code)
-{
-       return code & 0x0f;
-}
-
-/* Download firmware max packet size */
-#define MXU1_DOWNLOAD_MAX_PACKET_SIZE          64
-
-/* Firmware image header */
-struct mxu1_firmware_header {
-       __le16 wLength;
-       u8 bCheckSum;
-} __packed;
-
-#define MXU1_UART_BASE_ADDR        0xFFA0
-#define MXU1_UART_OFFSET_MCR       0x0004
-
-#define MXU1_BAUD_BASE              923077
-
-#define MXU1_TRANSFER_TIMEOUT      2
-#define MXU1_DOWNLOAD_TIMEOUT       1000
-#define MXU1_DEFAULT_CLOSING_WAIT   4000 /* in .01 secs */
-
-struct mxu1_port {
-       u8 msr;
-       u8 mcr;
-       u8 uart_mode;
-       spinlock_t spinlock; /* Protects msr */
-       struct mutex mutex; /* Protects mcr */
-       bool send_break;
-};
-
-struct mxu1_device {
-       u16 mxd_model;
-};
-
-static const struct usb_device_id mxu1_idtable[] = {
-       { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1110_PRODUCT_ID) },
-       { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1130_PRODUCT_ID) },
-       { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1150_PRODUCT_ID) },
-       { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1151_PRODUCT_ID) },
-       { USB_DEVICE(MXU1_VENDOR_ID, MXU1_1131_PRODUCT_ID) },
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, mxu1_idtable);
-
-/* Write the given buffer out to the control pipe.  */
-static int mxu1_send_ctrl_data_urb(struct usb_serial *serial,
-                                  u8 request,
-                                  u16 value, u16 index,
-                                  void *data, size_t size)
-{
-       int status;
-
-       status = usb_control_msg(serial->dev,
-                                usb_sndctrlpipe(serial->dev, 0),
-                                request,
-                                (USB_DIR_OUT | USB_TYPE_VENDOR |
-                                 USB_RECIP_DEVICE), value, index,
-                                data, size,
-                                USB_CTRL_SET_TIMEOUT);
-       if (status < 0) {
-               dev_err(&serial->interface->dev,
-                       "%s - usb_control_msg failed: %d\n",
-                       __func__, status);
-               return status;
-       }
-
-       if (status != size) {
-               dev_err(&serial->interface->dev,
-                       "%s - short write (%d / %zd)\n",
-                       __func__, status, size);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/* Send a vendor request without any data */
-static int mxu1_send_ctrl_urb(struct usb_serial *serial,
-                             u8 request, u16 value, u16 index)
-{
-       return mxu1_send_ctrl_data_urb(serial, request, value, index,
-                                      NULL, 0);
-}
-
-static int mxu1_download_firmware(struct usb_serial *serial,
-                                 const struct firmware *fw_p)
-{
-       int status = 0;
-       int buffer_size;
-       int pos;
-       int len;
-       int done;
-       u8 cs = 0;
-       u8 *buffer;
-       struct usb_device *dev = serial->dev;
-       struct mxu1_firmware_header *header;
-       unsigned int pipe;
-
-       pipe = usb_sndbulkpipe(dev, serial->port[0]->bulk_out_endpointAddress);
-
-       buffer_size = fw_p->size + sizeof(*header);
-       buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (!buffer)
-               return -ENOMEM;
-
-       memcpy(buffer, fw_p->data, fw_p->size);
-       memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
-
-       for (pos = sizeof(*header); pos < buffer_size; pos++)
-               cs = (u8)(cs + buffer[pos]);
-
-       header = (struct mxu1_firmware_header *)buffer;
-       header->wLength = cpu_to_le16(buffer_size - sizeof(*header));
-       header->bCheckSum = cs;
-
-       dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__);
-
-       for (pos = 0; pos < buffer_size; pos += done) {
-               len = min(buffer_size - pos, MXU1_DOWNLOAD_MAX_PACKET_SIZE);
-
-               status = usb_bulk_msg(dev, pipe, buffer + pos, len, &done,
-                               MXU1_DOWNLOAD_TIMEOUT);
-               if (status)
-                       break;
-       }
-
-       kfree(buffer);
-
-       if (status) {
-               dev_err(&dev->dev, "failed to download firmware: %d\n", status);
-               return status;
-       }
-
-       msleep_interruptible(100);
-       usb_reset_device(dev);
-
-       dev_dbg(&dev->dev, "%s - download successful\n", __func__);
-
-       return 0;
-}
-
-static int mxu1_port_probe(struct usb_serial_port *port)
-{
-       struct mxu1_port *mxport;
-       struct mxu1_device *mxdev;
-
-       if (!port->interrupt_in_urb) {
-               dev_err(&port->dev, "no interrupt urb\n");
-               return -ENODEV;
-       }
-
-       mxport = kzalloc(sizeof(struct mxu1_port), GFP_KERNEL);
-       if (!mxport)
-               return -ENOMEM;
-
-       spin_lock_init(&mxport->spinlock);
-       mutex_init(&mxport->mutex);
-
-       mxdev = usb_get_serial_data(port->serial);
-
-       switch (mxdev->mxd_model) {
-       case MXU1_1110_PRODUCT_ID:
-       case MXU1_1150_PRODUCT_ID:
-       case MXU1_1151_PRODUCT_ID:
-               mxport->uart_mode = MXU1_UART_232;
-               break;
-       case MXU1_1130_PRODUCT_ID:
-       case MXU1_1131_PRODUCT_ID:
-               mxport->uart_mode = MXU1_UART_485_RECEIVER_DISABLED;
-               break;
-       }
-
-       usb_set_serial_port_data(port, mxport);
-
-       port->port.closing_wait =
-                       msecs_to_jiffies(MXU1_DEFAULT_CLOSING_WAIT * 10);
-       port->port.drain_delay = 1;
-
-       return 0;
-}
-
-static int mxu1_port_remove(struct usb_serial_port *port)
-{
-       struct mxu1_port *mxport;
-
-       mxport = usb_get_serial_port_data(port);
-       kfree(mxport);
-
-       return 0;
-}
-
-static int mxu1_startup(struct usb_serial *serial)
-{
-       struct mxu1_device *mxdev;
-       struct usb_device *dev = serial->dev;
-       struct usb_host_interface *cur_altsetting;
-       char fw_name[32];
-       const struct firmware *fw_p = NULL;
-       int err;
-
-       dev_dbg(&serial->interface->dev, "%s - product 0x%04X, num configurations %d, configuration value %d\n",
-               __func__, le16_to_cpu(dev->descriptor.idProduct),
-               dev->descriptor.bNumConfigurations,
-               dev->actconfig->desc.bConfigurationValue);
-
-       /* create device structure */
-       mxdev = kzalloc(sizeof(struct mxu1_device), GFP_KERNEL);
-       if (!mxdev)
-               return -ENOMEM;
-
-       usb_set_serial_data(serial, mxdev);
-
-       mxdev->mxd_model = le16_to_cpu(dev->descriptor.idProduct);
-
-       cur_altsetting = serial->interface->cur_altsetting;
-
-       /* if we have only 1 configuration, download firmware */
-       if (cur_altsetting->desc.bNumEndpoints == 1) {
-
-               snprintf(fw_name,
-                        sizeof(fw_name),
-                        "moxa/moxa-%04x.fw",
-                        mxdev->mxd_model);
-
-               err = request_firmware(&fw_p, fw_name, &serial->interface->dev);
-               if (err) {
-                       dev_err(&serial->interface->dev, "failed to request firmware: %d\n",
-                               err);
-                       goto err_free_mxdev;
-               }
-
-               err = mxu1_download_firmware(serial, fw_p);
-               if (err)
-                       goto err_release_firmware;
-
-               /* device is being reset */
-               err = -ENODEV;
-               goto err_release_firmware;
-       }
-
-       return 0;
-
-err_release_firmware:
-       release_firmware(fw_p);
-err_free_mxdev:
-       kfree(mxdev);
-
-       return err;
-}
-
-static void mxu1_release(struct usb_serial *serial)
-{
-       struct mxu1_device *mxdev;
-
-       mxdev = usb_get_serial_data(serial);
-       kfree(mxdev);
-}
-
-static int mxu1_write_byte(struct usb_serial_port *port, u32 addr,
-                          u8 mask, u8 byte)
-{
-       int status;
-       size_t size;
-       struct mxu1_write_data_bytes *data;
-
-       dev_dbg(&port->dev, "%s - addr 0x%08X, mask 0x%02X, byte 0x%02X\n",
-               __func__, addr, mask, byte);
-
-       size = sizeof(struct mxu1_write_data_bytes) + 2;
-       data = kzalloc(size, GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->bAddrType = MXU1_RW_DATA_ADDR_XDATA;
-       data->bDataType = MXU1_RW_DATA_BYTE;
-       data->bDataCounter = 1;
-       data->wBaseAddrHi = cpu_to_be16(addr >> 16);
-       data->wBaseAddrLo = cpu_to_be16(addr);
-       data->bData[0] = mask;
-       data->bData[1] = byte;
-
-       status = mxu1_send_ctrl_data_urb(port->serial, MXU1_WRITE_DATA, 0,
-                                        MXU1_RAM_PORT, data, size);
-       if (status < 0)
-               dev_err(&port->dev, "%s - failed: %d\n", __func__, status);
-
-       kfree(data);
-
-       return status;
-}
-
-static int mxu1_set_mcr(struct usb_serial_port *port, unsigned int mcr)
-{
-       int status;
-
-       status = mxu1_write_byte(port,
-                                MXU1_UART_BASE_ADDR + MXU1_UART_OFFSET_MCR,
-                                MXU1_MCR_RTS | MXU1_MCR_DTR | MXU1_MCR_LOOP,
-                                mcr);
-       return status;
-}
-
-static void mxu1_set_termios(struct tty_struct *tty,
-                            struct usb_serial_port *port,
-                            struct ktermios *old_termios)
-{
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-       struct mxu1_uart_config *config;
-       tcflag_t cflag, iflag;
-       speed_t baud;
-       int status;
-       unsigned int mcr;
-
-       cflag = tty->termios.c_cflag;
-       iflag = tty->termios.c_iflag;
-
-       if (old_termios &&
-           !tty_termios_hw_change(&tty->termios, old_termios) &&
-           tty->termios.c_iflag == old_termios->c_iflag) {
-               dev_dbg(&port->dev, "%s - nothing to change\n", __func__);
-               return;
-       }
-
-       dev_dbg(&port->dev,
-               "%s - cflag 0x%08x, iflag 0x%08x\n", __func__, cflag, iflag);
-
-       if (old_termios) {
-               dev_dbg(&port->dev, "%s - old cflag 0x%08x, old iflag 0x%08x\n",
-                       __func__,
-                       old_termios->c_cflag,
-                       old_termios->c_iflag);
-       }
-
-       config = kzalloc(sizeof(*config), GFP_KERNEL);
-       if (!config)
-               return;
-
-       /* these flags must be set */
-       config->wFlags |= MXU1_UART_ENABLE_MS_INTS;
-       config->wFlags |= MXU1_UART_ENABLE_AUTO_START_DMA;
-       if (mxport->send_break)
-               config->wFlags |= MXU1_UART_SEND_BREAK_SIGNAL;
-       config->bUartMode = mxport->uart_mode;
-
-       switch (C_CSIZE(tty)) {
-       case CS5:
-               config->bDataBits = MXU1_UART_5_DATA_BITS;
-               break;
-       case CS6:
-               config->bDataBits = MXU1_UART_6_DATA_BITS;
-               break;
-       case CS7:
-               config->bDataBits = MXU1_UART_7_DATA_BITS;
-               break;
-       default:
-       case CS8:
-               config->bDataBits = MXU1_UART_8_DATA_BITS;
-               break;
-       }
-
-       if (C_PARENB(tty)) {
-               config->wFlags |= MXU1_UART_ENABLE_PARITY_CHECKING;
-               if (C_CMSPAR(tty)) {
-                       if (C_PARODD(tty))
-                               config->bParity = MXU1_UART_MARK_PARITY;
-                       else
-                               config->bParity = MXU1_UART_SPACE_PARITY;
-               } else {
-                       if (C_PARODD(tty))
-                               config->bParity = MXU1_UART_ODD_PARITY;
-                       else
-                               config->bParity = MXU1_UART_EVEN_PARITY;
-               }
-       } else {
-               config->bParity = MXU1_UART_NO_PARITY;
-       }
-
-       if (C_CSTOPB(tty))
-               config->bStopBits = MXU1_UART_2_STOP_BITS;
-       else
-               config->bStopBits = MXU1_UART_1_STOP_BITS;
-
-       if (C_CRTSCTS(tty)) {
-               /* RTS flow control must be off to drop RTS for baud rate B0 */
-               if (C_BAUD(tty) != B0)
-                       config->wFlags |= MXU1_UART_ENABLE_RTS_IN;
-               config->wFlags |= MXU1_UART_ENABLE_CTS_OUT;
-       }
-
-       if (I_IXOFF(tty) || I_IXON(tty)) {
-               config->cXon  = START_CHAR(tty);
-               config->cXoff = STOP_CHAR(tty);
-
-               if (I_IXOFF(tty))
-                       config->wFlags |= MXU1_UART_ENABLE_X_IN;
-
-               if (I_IXON(tty))
-                       config->wFlags |= MXU1_UART_ENABLE_X_OUT;
-       }
-
-       baud = tty_get_baud_rate(tty);
-       if (!baud)
-               baud = 9600;
-       config->wBaudRate = MXU1_BAUD_BASE / baud;
-
-       dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",
-               __func__, baud, config->wBaudRate, config->wFlags,
-               config->bDataBits, config->bParity, config->bStopBits,
-               config->cXon, config->cXoff, config->bUartMode);
-
-       cpu_to_be16s(&config->wBaudRate);
-       cpu_to_be16s(&config->wFlags);
-
-       status = mxu1_send_ctrl_data_urb(port->serial, MXU1_SET_CONFIG, 0,
-                                        MXU1_UART1_PORT, config,
-                                        sizeof(*config));
-       if (status)
-               dev_err(&port->dev, "cannot set config: %d\n", status);
-
-       mutex_lock(&mxport->mutex);
-       mcr = mxport->mcr;
-
-       if (C_BAUD(tty) == B0)
-               mcr &= ~(MXU1_MCR_DTR | MXU1_MCR_RTS);
-       else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
-               mcr |= MXU1_MCR_DTR | MXU1_MCR_RTS;
-
-       status = mxu1_set_mcr(port, mcr);
-       if (status)
-               dev_err(&port->dev, "cannot set modem control: %d\n", status);
-       else
-               mxport->mcr = mcr;
-
-       mutex_unlock(&mxport->mutex);
-
-       kfree(config);
-}
-
-static int mxu1_get_serial_info(struct usb_serial_port *port,
-                               struct serial_struct __user *ret_arg)
-{
-       struct serial_struct ret_serial;
-       unsigned cwait;
-
-       if (!ret_arg)
-               return -EFAULT;
-
-       cwait = port->port.closing_wait;
-       if (cwait != ASYNC_CLOSING_WAIT_NONE)
-               cwait = jiffies_to_msecs(cwait) / 10;
-
-       memset(&ret_serial, 0, sizeof(ret_serial));
-
-       ret_serial.type = PORT_16550A;
-       ret_serial.line = port->minor;
-       ret_serial.port = 0;
-       ret_serial.xmit_fifo_size = port->bulk_out_size;
-       ret_serial.baud_base = MXU1_BAUD_BASE;
-       ret_serial.close_delay = 5*HZ;
-       ret_serial.closing_wait = cwait;
-
-       if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int mxu1_set_serial_info(struct usb_serial_port *port,
-                               struct serial_struct __user *new_arg)
-{
-       struct serial_struct new_serial;
-       unsigned cwait;
-
-       if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
-               return -EFAULT;
-
-       cwait = new_serial.closing_wait;
-       if (cwait != ASYNC_CLOSING_WAIT_NONE)
-               cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
-
-       port->port.closing_wait = cwait;
-
-       return 0;
-}
-
-static int mxu1_ioctl(struct tty_struct *tty,
-                     unsigned int cmd, unsigned long arg)
-{
-       struct usb_serial_port *port = tty->driver_data;
-
-       switch (cmd) {
-       case TIOCGSERIAL:
-               return mxu1_get_serial_info(port,
-                                           (struct serial_struct __user *)arg);
-       case TIOCSSERIAL:
-               return mxu1_set_serial_info(port,
-                                           (struct serial_struct __user *)arg);
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-static int mxu1_tiocmget(struct tty_struct *tty)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-       unsigned int result;
-       unsigned int msr;
-       unsigned int mcr;
-       unsigned long flags;
-
-       mutex_lock(&mxport->mutex);
-       spin_lock_irqsave(&mxport->spinlock, flags);
-
-       msr = mxport->msr;
-       mcr = mxport->mcr;
-
-       spin_unlock_irqrestore(&mxport->spinlock, flags);
-       mutex_unlock(&mxport->mutex);
-
-       result = ((mcr & MXU1_MCR_DTR)  ? TIOCM_DTR     : 0) |
-                ((mcr & MXU1_MCR_RTS)  ? TIOCM_RTS     : 0) |
-                ((mcr & MXU1_MCR_LOOP) ? TIOCM_LOOP    : 0) |
-                ((msr & MXU1_MSR_CTS)  ? TIOCM_CTS     : 0) |
-                ((msr & MXU1_MSR_CD)   ? TIOCM_CAR     : 0) |
-                ((msr & MXU1_MSR_RI)   ? TIOCM_RI      : 0) |
-                ((msr & MXU1_MSR_DSR)  ? TIOCM_DSR     : 0);
-
-       dev_dbg(&port->dev, "%s - 0x%04X\n", __func__, result);
-
-       return result;
-}
-
-static int mxu1_tiocmset(struct tty_struct *tty,
-                        unsigned int set, unsigned int clear)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-       int err;
-       unsigned int mcr;
-
-       mutex_lock(&mxport->mutex);
-       mcr = mxport->mcr;
-
-       if (set & TIOCM_RTS)
-               mcr |= MXU1_MCR_RTS;
-       if (set & TIOCM_DTR)
-               mcr |= MXU1_MCR_DTR;
-       if (set & TIOCM_LOOP)
-               mcr |= MXU1_MCR_LOOP;
-
-       if (clear & TIOCM_RTS)
-               mcr &= ~MXU1_MCR_RTS;
-       if (clear & TIOCM_DTR)
-               mcr &= ~MXU1_MCR_DTR;
-       if (clear & TIOCM_LOOP)
-               mcr &= ~MXU1_MCR_LOOP;
-
-       err = mxu1_set_mcr(port, mcr);
-       if (!err)
-               mxport->mcr = mcr;
-
-       mutex_unlock(&mxport->mutex);
-
-       return err;
-}
-
-static void mxu1_break(struct tty_struct *tty, int break_state)
-{
-       struct usb_serial_port *port = tty->driver_data;
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-
-       if (break_state == -1)
-               mxport->send_break = true;
-       else
-               mxport->send_break = false;
-
-       mxu1_set_termios(tty, port, NULL);
-}
-
-static int mxu1_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-       struct usb_serial *serial = port->serial;
-       int status;
-       u16 open_settings;
-
-       open_settings = (MXU1_PIPE_MODE_CONTINUOUS |
-                        MXU1_PIPE_TIMEOUT_ENABLE |
-                        (MXU1_TRANSFER_TIMEOUT << 2));
-
-       mxport->msr = 0;
-
-       status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-       if (status) {
-               dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
-                       status);
-               return status;
-       }
-
-       if (tty)
-               mxu1_set_termios(tty, port, NULL);
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
-                                   open_settings, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot send open command: %d\n", status);
-               goto unlink_int_urb;
-       }
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
-                                   0, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot send start command: %d\n", status);
-               goto unlink_int_urb;
-       }
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
-                                   MXU1_PURGE_INPUT, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot clear input buffers: %d\n",
-                       status);
-
-               goto unlink_int_urb;
-       }
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_PURGE_PORT,
-                                   MXU1_PURGE_OUTPUT, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot clear output buffers: %d\n",
-                       status);
-
-               goto unlink_int_urb;
-       }
-
-       /*
-        * reset the data toggle on the bulk endpoints to work around bug in
-        * host controllers where things get out of sync some times
-        */
-       usb_clear_halt(serial->dev, port->write_urb->pipe);
-       usb_clear_halt(serial->dev, port->read_urb->pipe);
-
-       if (tty)
-               mxu1_set_termios(tty, port, NULL);
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_OPEN_PORT,
-                                   open_settings, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot send open command: %d\n", status);
-               goto unlink_int_urb;
-       }
-
-       status = mxu1_send_ctrl_urb(serial, MXU1_START_PORT,
-                                   0, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "cannot send start command: %d\n", status);
-               goto unlink_int_urb;
-       }
-
-       status = usb_serial_generic_open(tty, port);
-       if (status)
-               goto unlink_int_urb;
-
-       return 0;
-
-unlink_int_urb:
-       usb_kill_urb(port->interrupt_in_urb);
-
-       return status;
-}
-
-static void mxu1_close(struct usb_serial_port *port)
-{
-       int status;
-
-       usb_serial_generic_close(port);
-       usb_kill_urb(port->interrupt_in_urb);
-
-       status = mxu1_send_ctrl_urb(port->serial, MXU1_CLOSE_PORT,
-                                   0, MXU1_UART1_PORT);
-       if (status) {
-               dev_err(&port->dev, "failed to send close port command: %d\n",
-                       status);
-       }
-}
-
-static void mxu1_handle_new_msr(struct usb_serial_port *port, u8 msr)
-{
-       struct mxu1_port *mxport = usb_get_serial_port_data(port);
-       struct async_icount *icount;
-       unsigned long flags;
-
-       dev_dbg(&port->dev, "%s - msr 0x%02X\n", __func__, msr);
-
-       spin_lock_irqsave(&mxport->spinlock, flags);
-       mxport->msr = msr & MXU1_MSR_MASK;
-       spin_unlock_irqrestore(&mxport->spinlock, flags);
-
-       if (msr & MXU1_MSR_DELTA_MASK) {
-               icount = &port->icount;
-               if (msr & MXU1_MSR_DELTA_CTS)
-                       icount->cts++;
-               if (msr & MXU1_MSR_DELTA_DSR)
-                       icount->dsr++;
-               if (msr & MXU1_MSR_DELTA_CD)
-                       icount->dcd++;
-               if (msr & MXU1_MSR_DELTA_RI)
-                       icount->rng++;
-
-               wake_up_interruptible(&port->port.delta_msr_wait);
-       }
-}
-
-static void mxu1_interrupt_callback(struct urb *urb)
-{
-       struct usb_serial_port *port = urb->context;
-       unsigned char *data = urb->transfer_buffer;
-       int length = urb->actual_length;
-       int function;
-       int status;
-       u8 msr;
-
-       switch (urb->status) {
-       case 0:
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               dev_dbg(&port->dev, "%s - urb shutting down: %d\n",
-                       __func__, urb->status);
-               return;
-       default:
-               dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
-                       __func__, urb->status);
-               goto exit;
-       }
-
-       if (length != 2) {
-               dev_dbg(&port->dev, "%s - bad packet size: %d\n",
-                       __func__, length);
-               goto exit;
-       }
-
-       if (data[0] == MXU1_CODE_HARDWARE_ERROR) {
-               dev_err(&port->dev, "hardware error: %d\n", data[1]);
-               goto exit;
-       }
-
-       function = mxu1_get_func_from_code(data[0]);
-
-       dev_dbg(&port->dev, "%s - function %d, data 0x%02X\n",
-                __func__, function, data[1]);
-
-       switch (function) {
-       case MXU1_CODE_DATA_ERROR:
-               dev_dbg(&port->dev, "%s - DATA ERROR, data 0x%02X\n",
-                        __func__, data[1]);
-               break;
-
-       case MXU1_CODE_MODEM_STATUS:
-               msr = data[1];
-               mxu1_handle_new_msr(port, msr);
-               break;
-
-       default:
-               dev_err(&port->dev, "unknown interrupt code: 0x%02X\n",
-                       data[1]);
-               break;
-       }
-
-exit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
-               dev_err(&port->dev, "resubmit interrupt urb failed: %d\n",
-                       status);
-       }
-}
-
-static struct usb_serial_driver mxu11x0_device = {
-       .driver = {
-               .owner          = THIS_MODULE,
-               .name           = "mxu11x0",
-       },
-       .description            = "MOXA UPort 11x0",
-       .id_table               = mxu1_idtable,
-       .num_ports              = 1,
-       .port_probe             = mxu1_port_probe,
-       .port_remove            = mxu1_port_remove,
-       .attach                 = mxu1_startup,
-       .release                = mxu1_release,
-       .open                   = mxu1_open,
-       .close                  = mxu1_close,
-       .ioctl                  = mxu1_ioctl,
-       .set_termios            = mxu1_set_termios,
-       .tiocmget               = mxu1_tiocmget,
-       .tiocmset               = mxu1_tiocmset,
-       .tiocmiwait             = usb_serial_generic_tiocmiwait,
-       .get_icount             = usb_serial_generic_get_icount,
-       .break_ctl              = mxu1_break,
-       .read_int_callback      = mxu1_interrupt_callback,
-};
-
-static struct usb_serial_driver *const serial_drivers[] = {
-       &mxu11x0_device, NULL
-};
-
-module_usb_serial_driver(serial_drivers, mxu1_idtable);
-
-MODULE_AUTHOR("Mathieu Othacehe <m.othacehe@gmail.com>");
-MODULE_DESCRIPTION("MOXA UPort 11x0 USB to Serial Hub Driver");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("moxa/moxa-1110.fw");
-MODULE_FIRMWARE("moxa/moxa-1130.fw");
-MODULE_FIRMWARE("moxa/moxa-1131.fw");
-MODULE_FIRMWARE("moxa/moxa-1150.fw");
-MODULE_FIRMWARE("moxa/moxa-1151.fw");
index db86e512e0fcb3af0548eb9907b04ce68db3a8dc..348e19834b83e12e7aafafa9d46374822fe43f7f 100644 (file)
@@ -270,6 +270,7 @@ static void option_instat_callback(struct urb *urb);
 #define TELIT_PRODUCT_UE910_V2                 0x1012
 #define TELIT_PRODUCT_LE922_USBCFG0            0x1042
 #define TELIT_PRODUCT_LE922_USBCFG3            0x1043
+#define TELIT_PRODUCT_LE922_USBCFG5            0x1045
 #define TELIT_PRODUCT_LE920                    0x1200
 #define TELIT_PRODUCT_LE910                    0x1201
 
@@ -315,6 +316,7 @@ static void option_instat_callback(struct urb *urb);
 #define TOSHIBA_PRODUCT_G450                   0x0d45
 
 #define ALINK_VENDOR_ID                                0x1e0e
+#define SIMCOM_PRODUCT_SIM7100E                        0x9001 /* Yes, ALINK_VENDOR_ID */
 #define ALINK_PRODUCT_PH300                    0x9100
 #define ALINK_PRODUCT_3GU                      0x9200
 
@@ -607,6 +609,10 @@ static const struct option_blacklist_info zte_1255_blacklist = {
        .reserved = BIT(3) | BIT(4),
 };
 
+static const struct option_blacklist_info simcom_sim7100e_blacklist = {
+       .reserved = BIT(5) | BIT(6),
+};
+
 static const struct option_blacklist_info telit_le910_blacklist = {
        .sendsetup = BIT(0),
        .reserved = BIT(1) | BIT(2),
@@ -1122,9 +1128,13 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
+       { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */
+         .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
+       { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
@@ -1176,6 +1186,8 @@ static const struct usb_device_id option_ids[] = {
                .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
                .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
+               .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
                .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
@@ -1645,6 +1657,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
        { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) },
        { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
+       { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E),
+         .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
          .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
        },
index 9919d2a9faf278177aacf32c149fda22b00a1d83..1bc6089b90083a05e0ef3e4ff71c0ef752e3831a 100644 (file)
@@ -157,14 +157,17 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x1199, 0x9056)},   /* Sierra Wireless Modem */
        {DEVICE_SWI(0x1199, 0x9060)},   /* Sierra Wireless Modem */
        {DEVICE_SWI(0x1199, 0x9061)},   /* Sierra Wireless Modem */
-       {DEVICE_SWI(0x1199, 0x9070)},   /* Sierra Wireless MC74xx/EM74xx */
-       {DEVICE_SWI(0x1199, 0x9071)},   /* Sierra Wireless MC74xx/EM74xx */
+       {DEVICE_SWI(0x1199, 0x9070)},   /* Sierra Wireless MC74xx */
+       {DEVICE_SWI(0x1199, 0x9071)},   /* Sierra Wireless MC74xx */
+       {DEVICE_SWI(0x1199, 0x9078)},   /* Sierra Wireless EM74xx */
+       {DEVICE_SWI(0x1199, 0x9079)},   /* Sierra Wireless EM74xx */
        {DEVICE_SWI(0x413c, 0x81a2)},   /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a3)},   /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a4)},   /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a8)},   /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81a9)},   /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
        {DEVICE_SWI(0x413c, 0x81b1)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {DEVICE_SWI(0x413c, 0x81b3)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
 
        /* Huawei devices */
        {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
index 2760a7ba3f309d1a344781c2f9a4eb6c3b3ff4aa..8c80a48e32335346e426547fa5007e179ff7cec7 100644 (file)
@@ -446,7 +446,8 @@ static long vfio_pci_ioctl(void *device_data,
                info.num_regions = VFIO_PCI_NUM_REGIONS;
                info.num_irqs = VFIO_PCI_NUM_IRQS;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
                struct pci_dev *pdev = vdev->pdev;
@@ -520,7 +521,8 @@ static long vfio_pci_ioctl(void *device_data,
                        return -EINVAL;
                }
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
                struct vfio_irq_info info;
@@ -555,7 +557,8 @@ static long vfio_pci_ioctl(void *device_data,
                else
                        info.flags |= VFIO_IRQ_INFO_NORESIZE;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_SET_IRQS) {
                struct vfio_irq_set hdr;
index 418cdd9ba3f4841353c5cbdddb345e9363578736..e65b142d34222dd4ba548e46c44017d2b762cf06 100644 (file)
@@ -219,7 +219,8 @@ static long vfio_platform_ioctl(void *device_data,
                info.num_regions = vdev->num_regions;
                info.num_irqs = vdev->num_irqs;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
                struct vfio_region_info info;
@@ -240,7 +241,8 @@ static long vfio_platform_ioctl(void *device_data,
                info.size = vdev->regions[info.index].size;
                info.flags = vdev->regions[info.index].flags;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
                struct vfio_irq_info info;
@@ -259,7 +261,8 @@ static long vfio_platform_ioctl(void *device_data,
                info.flags = vdev->irqs[info.index].flags;
                info.count = vdev->irqs[info.index].count;
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_DEVICE_SET_IRQS) {
                struct vfio_irq_set hdr;
index 6f1ea3dddbad9a75dd094d8613fb426742f844e4..75b24e93cedb3da273a589bb129b6ce502b247fd 100644 (file)
@@ -999,7 +999,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
 
                info.iova_pgsizes = vfio_pgsize_bitmap(iommu);
 
-               return copy_to_user((void __user *)arg, &info, minsz);
+               return copy_to_user((void __user *)arg, &info, minsz) ?
+                       -EFAULT : 0;
 
        } else if (cmd == VFIO_IOMMU_MAP_DMA) {
                struct vfio_iommu_type1_dma_map map;
@@ -1032,7 +1033,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
                if (ret)
                        return ret;
 
-               return copy_to_user((void __user *)arg, &unmap, minsz);
+               return copy_to_user((void __user *)arg, &unmap, minsz) ?
+                       -EFAULT : 0;
        }
 
        return -ENOTTY;
index ad2146a9ab2d4b19cca5469402c203ade61e8545..236553e81027c15b089cdf2a0d4378f60e3f8d6a 100644 (file)
@@ -1156,6 +1156,8 @@ int vhost_init_used(struct vhost_virtqueue *vq)
 {
        __virtio16 last_used_idx;
        int r;
+       bool is_le = vq->is_le;
+
        if (!vq->private_data) {
                vq->is_le = virtio_legacy_is_little_endian();
                return 0;
@@ -1165,15 +1167,20 @@ int vhost_init_used(struct vhost_virtqueue *vq)
 
        r = vhost_update_used_flags(vq);
        if (r)
-               return r;
+               goto err;
        vq->signalled_used_valid = false;
-       if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx))
-               return -EFAULT;
+       if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) {
+               r = -EFAULT;
+               goto err;
+       }
        r = __get_user(last_used_idx, &vq->used->idx);
        if (r)
-               return r;
+               goto err;
        vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx);
        return 0;
+err:
+       vq->is_le = is_le;
+       return r;
 }
 EXPORT_SYMBOL_GPL(vhost_init_used);
 
index 92f394927f241bef338a293170e4a09b9f45c647..6e92917ba77a97477f32a0426ee914c351867a6b 100644 (file)
@@ -709,6 +709,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
        }
 
        if (!err) {
+               ops->cur_blink_jiffies = HZ / 5;
                info->fbcon_par = ops;
 
                if (vc)
@@ -956,6 +957,7 @@ static const char *fbcon_startup(void)
        ops->currcon = -1;
        ops->graphics = 1;
        ops->cur_rotate = -1;
+       ops->cur_blink_jiffies = HZ / 5;
        info->fbcon_par = ops;
        p->con_rotate = initial_rotation;
        set_blitting_type(vc, info);
index 0081725c6b5be62f6c7939d5bc2b4022881f363e..6b2a06d09f2b612ae6fac5252977df0853fc8cf1 100644 (file)
@@ -152,7 +152,7 @@ static void lcdc_write(unsigned int val, unsigned int addr)
 
 struct da8xx_fb_par {
        struct device           *dev;
-       resource_size_t p_palette_base;
+       dma_addr_t              p_palette_base;
        unsigned char *v_palette_base;
        dma_addr_t              vram_phys;
        unsigned long           vram_size;
@@ -1428,7 +1428,7 @@ static int fb_probe(struct platform_device *device)
 
        par->vram_virt = dma_alloc_coherent(NULL,
                                            par->vram_size,
-                                           (resource_size_t *) &par->vram_phys,
+                                           &par->vram_phys,
                                            GFP_KERNEL | GFP_DMA);
        if (!par->vram_virt) {
                dev_err(&device->dev,
@@ -1448,7 +1448,7 @@ static int fb_probe(struct platform_device *device)
 
        /* allocate palette buffer */
        par->v_palette_base = dma_zalloc_coherent(NULL, PALETTE_SIZE,
-                                                 (resource_size_t *)&par->p_palette_base,
+                                                 &par->p_palette_base,
                                                  GFP_KERNEL | GFP_DMA);
        if (!par->v_palette_base) {
                dev_err(&device->dev,
index 95873f26e39cf6d58fe78b0dce1fdbabcf9c1390..de2f3e793786c77c73923616fb30b0170d1100b1 100644 (file)
@@ -829,8 +829,7 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
 {
        struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -843,7 +842,7 @@ static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
        return 0;
 }
 
-static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+static int __maybe_unused s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
 {
        struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
 
@@ -855,10 +854,6 @@ static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
 
        return 0;
 }
-#else
-#define s6e8ax0_suspend                NULL
-#define s6e8ax0_resume         NULL
-#endif
 
 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
        .name = "s6e8ax0",
@@ -867,8 +862,8 @@ static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
        .power_on = s6e8ax0_power_on,
        .set_sequence = s6e8ax0_set_sequence,
        .probe = s6e8ax0_probe,
-       .suspend = s6e8ax0_suspend,
-       .resume = s6e8ax0_resume,
+       .suspend = IS_ENABLED(CONFIG_PM) ? s6e8ax0_suspend : NULL,
+       .resume = IS_ENABLED(CONFIG_PM) ? s6e8ax0_resume : NULL,
 };
 
 static int s6e8ax0_init(void)
index cee88603efc9e40195430fe1a745eebefb97ef0b..bb2f1e866020199d31b8ba0b1940cb9e6b87923f 100644 (file)
@@ -902,6 +902,21 @@ static int imxfb_probe(struct platform_device *pdev)
                goto failed_getclock;
        }
 
+       /*
+        * The LCDC controller does not have an enable bit. The
+        * controller starts directly when the clocks are enabled.
+        * If the clocks are enabled when the controller is not yet
+        * programmed with proper register values (enabled at the
+        * bootloader, for example) then it just goes into some undefined
+        * state.
+        * To avoid this issue, let's enable and disable LCDC IPG clock
+        * so that we force some kind of 'reset' to the LCDC block.
+        */
+       ret = clk_prepare_enable(fbi->clk_ipg);
+       if (ret)
+               goto failed_getclock;
+       clk_disable_unprepare(fbi->clk_ipg);
+
        fbi->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
        if (IS_ERR(fbi->clk_ahb)) {
                ret = PTR_ERR(fbi->clk_ahb);
index de54a474806504ba9844839267fcc7604422ce3f..b6f83d5df9fdeab329478d5ccfeb78610da9e532 100644 (file)
@@ -503,8 +503,7 @@ static int mmphw_probe(struct platform_device *pdev)
        ctrl->reg_base = devm_ioremap_nocache(ctrl->dev,
                        res->start, resource_size(res));
        if (ctrl->reg_base == NULL) {
-               dev_err(ctrl->dev, "%s: res %x - %x map failed\n", __func__,
-                       res->start, res->end);
+               dev_err(ctrl->dev, "%s: res %pR map failed\n", __func__, res);
                ret = -ENOMEM;
                goto failed;
        }
index c9293aea8ec3502e27ddf6125f07201c16996a7b..a970edc2a6f8c781696ac7b0b6664fd7c4513ffa 100644 (file)
@@ -123,11 +123,11 @@ static int ocfb_setupfb(struct ocfb_dev *fbdev)
 
        /* Horizontal timings */
        ocfb_writereg(fbdev, OCFB_HTIM, (var->hsync_len - 1) << 24 |
-                     (var->right_margin - 1) << 16 | (var->xres - 1));
+                     (var->left_margin - 1) << 16 | (var->xres - 1));
 
        /* Vertical timings */
        ocfb_writereg(fbdev, OCFB_VTIM, (var->vsync_len - 1) << 24 |
-                     (var->lower_margin - 1) << 16 | (var->yres - 1));
+                     (var->upper_margin - 1) << 16 | (var->yres - 1));
 
        /* Total length of frame */
        hlen = var->left_margin + var->right_margin + var->hsync_len +
index c0c11fad4611a72a3712c3ef7471193cb5d8fa5d..7760fc1a2218e9ea9e053caf8db2be27dc8d2952 100644 (file)
@@ -679,7 +679,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
 
        pci_read_config_dword(pci_dev,
                              notify + offsetof(struct virtio_pci_notify_cap,
-                                               cap.length),
+                                               cap.offset),
                              &notify_offset);
 
        /* We don't know how many VQs we'll map, ahead of the time.
index 4f0e7be0da346c90d8559d9653bd41927f722b22..80825a7e8e48e1ebd06af14a1bcf208acb733daf 100644 (file)
@@ -145,7 +145,8 @@ config MENF21BMC_WATCHDOG
 config TANGOX_WATCHDOG
        tristate "Sigma Designs SMP86xx/SMP87xx watchdog"
        select WATCHDOG_CORE
-       depends on ARCH_TANGOX || COMPILE_TEST
+       depends on ARCH_TANGO || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Support for the watchdog in Sigma Designs SMP86xx (tango3)
          and SMP87xx (tango4) family chips.
@@ -618,6 +619,7 @@ config DIGICOLOR_WATCHDOG
 config LPC18XX_WATCHDOG
        tristate "LPC18xx/43xx Watchdog"
        depends on ARCH_LPC18XX || COMPILE_TEST
+       depends on HAS_IOMEM
        select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
@@ -1374,6 +1376,7 @@ config BCM_KONA_WDT_DEBUG
 config BCM7038_WDT
        tristate "BCM7038 Watchdog"
        select WATCHDOG_CORE
+       depends on HAS_IOMEM
        help
         Watchdog driver for the built-in hardware in Broadcom 7038 SoCs.
 
@@ -1383,6 +1386,7 @@ config IMGPDC_WDT
        tristate "Imagination Technologies PDC Watchdog Timer"
        depends on HAS_IOMEM
        depends on METAG || MIPS || COMPILE_TEST
+       select WATCHDOG_CORE
        help
          Driver for Imagination Technologies PowerDown Controller
          Watchdog Timer.
@@ -1565,6 +1569,17 @@ config WATCHDOG_RIO
          machines.  The watchdog timeout period is normally one minute but
          can be changed with a boot-time parameter.
 
+config WATCHDOG_SUN4V
+       tristate "Sun4v Watchdog support"
+       select WATCHDOG_CORE
+       depends on SPARC64
+       help
+         Say Y here to support the hypervisor watchdog capability embedded
+         in the SPARC sun4v architecture.
+
+         To compile this driver as a module, choose M here. The module will
+         be called sun4v_wdt.
+
 # XTENSA Architecture
 
 # Xen Architecture
index f566753256abbbb74535337d3f9a9cc0442fd78e..f6a6a387c6c71f7a5e9e2cda4cc91ae3f39edf2c 100644 (file)
@@ -179,6 +179,7 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
 
 obj-$(CONFIG_WATCHDOG_RIO)             += riowd.o
 obj-$(CONFIG_WATCHDOG_CP1XXX)          += cpwd.o
+obj-$(CONFIG_WATCHDOG_SUN4V)           += sun4v_wdt.o
 
 # XTENSA Architecture
 
index f36ca4be07207a9fd200d92577e9242a10e774df..ac5840d9689aed0f79fafa82e6a56e4515bb1b27 100644 (file)
@@ -292,4 +292,4 @@ MODULE_PARM_DESC(nodelay,
                 "Force selection of a timeout setting without initial delay "
                 "(max6373/74 only, default=0)");
 
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index 1a11aedc4fe850738bfe17d469232da64959b84d..68952d9ccf8394412654d76fc2c14edef3f74124 100644 (file)
@@ -608,7 +608,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
        struct usb_pcwd_private *usb_pcwd = NULL;
-       int pipe, maxp;
+       int pipe;
        int retval = -ENOMEM;
        int got_fw_rev;
        unsigned char fw_rev_major, fw_rev_minor;
@@ -641,7 +641,6 @@ static int usb_pcwd_probe(struct usb_interface *interface,
 
        /* get a handle to the interrupt data pipe */
        pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
-       maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 
        /* allocate memory for our device and initialize it */
        usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
index 01d816251302c2491c24a70e8f7c542b61c2f15a..e7a715e820217eb82a90cc8e5eed54d6d826e22c 100644 (file)
@@ -139,12 +139,11 @@ static int wdt_config(struct watchdog_device *wdd, bool ping)
 
        writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
        writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
+       writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
 
-       if (!ping) {
-               writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
+       if (!ping)
                writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base +
                                WDTCONTROL);
-       }
 
        writel_relaxed(LOCK, wdt->base + WDTLOCK);
 
diff --git a/drivers/watchdog/sun4v_wdt.c b/drivers/watchdog/sun4v_wdt.c
new file mode 100644 (file)
index 0000000..1467fe5
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ *     sun4v watchdog timer
+ *     (c) Copyright 2016 Oracle Corporation
+ *
+ *     Implement a simple watchdog driver using the built-in sun4v hypervisor
+ *     watchdog support. If time expires, the hypervisor stops or bounces
+ *     the guest domain.
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/watchdog.h>
+#include <asm/hypervisor.h>
+#include <asm/mdesc.h>
+
+#define WDT_TIMEOUT                    60
+#define WDT_MAX_TIMEOUT                        31536000
+#define WDT_MIN_TIMEOUT                        1
+#define WDT_DEFAULT_RESOLUTION_MS      1000    /* 1 second */
+
+static unsigned int timeout;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+       __MODULE_STRING(WDT_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int sun4v_wdt_stop(struct watchdog_device *wdd)
+{
+       sun4v_mach_set_watchdog(0, NULL);
+
+       return 0;
+}
+
+static int sun4v_wdt_ping(struct watchdog_device *wdd)
+{
+       int hverr;
+
+       /*
+        * HV watchdog timer will round up the timeout
+        * passed in to the nearest multiple of the
+        * watchdog resolution in milliseconds.
+        */
+       hverr = sun4v_mach_set_watchdog(wdd->timeout * 1000, NULL);
+       if (hverr == HV_EINVAL)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sun4v_wdt_set_timeout(struct watchdog_device *wdd,
+                                unsigned int timeout)
+{
+       wdd->timeout = timeout;
+
+       return 0;
+}
+
+static const struct watchdog_info sun4v_wdt_ident = {
+       .options =      WDIOF_SETTIMEOUT |
+                       WDIOF_MAGICCLOSE |
+                       WDIOF_KEEPALIVEPING,
+       .identity =     "sun4v hypervisor watchdog",
+       .firmware_version = 0,
+};
+
+static struct watchdog_ops sun4v_wdt_ops = {
+       .owner =        THIS_MODULE,
+       .start =        sun4v_wdt_ping,
+       .stop =         sun4v_wdt_stop,
+       .ping =         sun4v_wdt_ping,
+       .set_timeout =  sun4v_wdt_set_timeout,
+};
+
+static struct watchdog_device wdd = {
+       .info = &sun4v_wdt_ident,
+       .ops = &sun4v_wdt_ops,
+       .min_timeout = WDT_MIN_TIMEOUT,
+       .max_timeout = WDT_MAX_TIMEOUT,
+       .timeout = WDT_TIMEOUT,
+};
+
+static int __init sun4v_wdt_init(void)
+{
+       struct mdesc_handle *handle;
+       u64 node;
+       const u64 *value;
+       int err = 0;
+       unsigned long major = 1, minor = 1;
+
+       /*
+        * There are 2 properties that can be set from the control
+        * domain for the watchdog.
+        * watchdog-resolution
+        * watchdog-max-timeout
+        *
+        * We can expect a handle to be returned otherwise something
+        * serious is wrong. Correct to return -ENODEV here.
+        */
+
+       handle = mdesc_grab();
+       if (!handle)
+               return -ENODEV;
+
+       node = mdesc_node_by_name(handle, MDESC_NODE_NULL, "platform");
+       err = -ENODEV;
+       if (node == MDESC_NODE_NULL)
+               goto out_release;
+
+       /*
+        * This is a safe way to validate if we are on the right
+        * platform.
+        */
+       if (sun4v_hvapi_register(HV_GRP_CORE, major, &minor))
+               goto out_hv_unreg;
+
+       /* Allow value of watchdog-resolution up to 1s (default) */
+       value = mdesc_get_property(handle, node, "watchdog-resolution", NULL);
+       err = -EINVAL;
+       if (value) {
+               if (*value == 0 ||
+                   *value > WDT_DEFAULT_RESOLUTION_MS)
+                       goto out_hv_unreg;
+       }
+
+       value = mdesc_get_property(handle, node, "watchdog-max-timeout", NULL);
+       if (value) {
+               /*
+                * If the property value (in ms) is smaller than
+                * min_timeout, return -EINVAL.
+                */
+               if (*value < wdd.min_timeout * 1000)
+                       goto out_hv_unreg;
+
+               /*
+                * If the property value is smaller than
+                * default max_timeout  then set watchdog max_timeout to
+                * the value of the property in seconds.
+                */
+               if (*value < wdd.max_timeout * 1000)
+                       wdd.max_timeout = *value  / 1000;
+       }
+
+       watchdog_init_timeout(&wdd, timeout, NULL);
+
+       watchdog_set_nowayout(&wdd, nowayout);
+
+       err = watchdog_register_device(&wdd);
+       if (err)
+               goto out_hv_unreg;
+
+       pr_info("initialized (timeout=%ds, nowayout=%d)\n",
+                wdd.timeout, nowayout);
+
+       mdesc_release(handle);
+
+       return 0;
+
+out_hv_unreg:
+       sun4v_hvapi_unregister(HV_GRP_CORE);
+
+out_release:
+       mdesc_release(handle);
+       return err;
+}
+
+static void __exit sun4v_wdt_exit(void)
+{
+       sun4v_hvapi_unregister(HV_GRP_CORE);
+       watchdog_unregister_device(&wdd);
+}
+
+module_init(sun4v_wdt_init);
+module_exit(sun4v_wdt_exit);
+
+MODULE_AUTHOR("Wim Coekaerts <wim.coekaerts@oracle.com>");
+MODULE_DESCRIPTION("sun4v watchdog driver");
+MODULE_LICENSE("GPL");
index 73dafdc494aa8322e037f1d4a9ad4ec5530c5743..fb0221434f814aa49eef41f6aea7a60c86a4c817 100644 (file)
@@ -227,8 +227,9 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
        /*
         * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able
         * to access the BARs where the MSI-X entries reside.
+        * But VF devices are unique in which the PF needs to be checked.
         */
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_read_config_word(pci_physfn(dev), PCI_COMMAND, &cmd);
        if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY))
                return -ENXIO;
 
@@ -332,6 +333,9 @@ void xen_pcibk_do_op(struct work_struct *data)
        struct xen_pcibk_dev_data *dev_data = NULL;
        struct xen_pci_op *op = &pdev->op;
        int test_intx = 0;
+#ifdef CONFIG_PCI_MSI
+       unsigned int nr = 0;
+#endif
 
        *op = pdev->sh_info->op;
        barrier();
@@ -360,6 +364,7 @@ void xen_pcibk_do_op(struct work_struct *data)
                        op->err = xen_pcibk_disable_msi(pdev, dev, op);
                        break;
                case XEN_PCI_OP_enable_msix:
+                       nr = op->value;
                        op->err = xen_pcibk_enable_msix(pdev, dev, op);
                        break;
                case XEN_PCI_OP_disable_msix:
@@ -382,7 +387,7 @@ void xen_pcibk_do_op(struct work_struct *data)
        if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) {
                unsigned int i;
 
-               for (i = 0; i < op->value; i++)
+               for (i = 0; i < nr; i++)
                        pdev->sh_info->op.msix_entries[i].vector =
                                op->msix_entries[i].vector;
        }
index ad4eb1024d1ffb7663db4e770fdd4c5c2663e821..c46ee189466f81ab584282651494fad765a38417 100644 (file)
@@ -848,6 +848,24 @@ static int scsiback_map(struct vscsibk_info *info)
        return scsiback_init_sring(info, ring_ref, evtchn);
 }
 
+/*
+  Check for a translation entry being present
+*/
+static struct v2p_entry *scsiback_chk_translation_entry(
+       struct vscsibk_info *info, struct ids_tuple *v)
+{
+       struct list_head *head = &(info->v2p_entry_lists);
+       struct v2p_entry *entry;
+
+       list_for_each_entry(entry, head, l)
+               if ((entry->v.chn == v->chn) &&
+                   (entry->v.tgt == v->tgt) &&
+                   (entry->v.lun == v->lun))
+                       return entry;
+
+       return NULL;
+}
+
 /*
   Add a new translation entry
 */
@@ -855,9 +873,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info,
                                          char *phy, struct ids_tuple *v)
 {
        int err = 0;
-       struct v2p_entry *entry;
        struct v2p_entry *new;
-       struct list_head *head = &(info->v2p_entry_lists);
        unsigned long flags;
        char *lunp;
        unsigned long long unpacked_lun;
@@ -917,15 +933,10 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info,
        spin_lock_irqsave(&info->v2p_lock, flags);
 
        /* Check double assignment to identical virtual ID */
-       list_for_each_entry(entry, head, l) {
-               if ((entry->v.chn == v->chn) &&
-                   (entry->v.tgt == v->tgt) &&
-                   (entry->v.lun == v->lun)) {
-                       pr_warn("Virtual ID is already used. Assignment was not performed.\n");
-                       err = -EEXIST;
-                       goto out;
-               }
-
+       if (scsiback_chk_translation_entry(info, v)) {
+               pr_warn("Virtual ID is already used. Assignment was not performed.\n");
+               err = -EEXIST;
+               goto out;
        }
 
        /* Create a new translation entry and add to the list */
@@ -933,18 +944,18 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info,
        new->v = *v;
        new->tpg = tpg;
        new->lun = unpacked_lun;
-       list_add_tail(&new->l, head);
+       list_add_tail(&new->l, &info->v2p_entry_lists);
 
 out:
        spin_unlock_irqrestore(&info->v2p_lock, flags);
 
 out_free:
-       mutex_lock(&tpg->tv_tpg_mutex);
-       tpg->tv_tpg_fe_count--;
-       mutex_unlock(&tpg->tv_tpg_mutex);
-
-       if (err)
+       if (err) {
+               mutex_lock(&tpg->tv_tpg_mutex);
+               tpg->tv_tpg_fe_count--;
+               mutex_unlock(&tpg->tv_tpg_mutex);
                kfree(new);
+       }
 
        return err;
 }
@@ -956,39 +967,40 @@ static void __scsiback_del_translation_entry(struct v2p_entry *entry)
 }
 
 /*
-  Delete the translation entry specfied
+  Delete the translation entry specified
 */
 static int scsiback_del_translation_entry(struct vscsibk_info *info,
                                          struct ids_tuple *v)
 {
        struct v2p_entry *entry;
-       struct list_head *head = &(info->v2p_entry_lists);
        unsigned long flags;
+       int ret = 0;
 
        spin_lock_irqsave(&info->v2p_lock, flags);
        /* Find out the translation entry specified */
-       list_for_each_entry(entry, head, l) {
-               if ((entry->v.chn == v->chn) &&
-                   (entry->v.tgt == v->tgt) &&
-                   (entry->v.lun == v->lun)) {
-                       goto found;
-               }
-       }
-
-       spin_unlock_irqrestore(&info->v2p_lock, flags);
-       return 1;
-
-found:
-       /* Delete the translation entry specfied */
-       __scsiback_del_translation_entry(entry);
+       entry = scsiback_chk_translation_entry(info, v);
+       if (entry)
+               __scsiback_del_translation_entry(entry);
+       else
+               ret = -ENOENT;
 
        spin_unlock_irqrestore(&info->v2p_lock, flags);
-       return 0;
+       return ret;
 }
 
 static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state,
                                char *phy, struct ids_tuple *vir, int try)
 {
+       struct v2p_entry *entry;
+       unsigned long flags;
+
+       if (try) {
+               spin_lock_irqsave(&info->v2p_lock, flags);
+               entry = scsiback_chk_translation_entry(info, vir);
+               spin_unlock_irqrestore(&info->v2p_lock, flags);
+               if (entry)
+                       return;
+       }
        if (!scsiback_add_translation_entry(info, phy, vir)) {
                if (xenbus_printf(XBT_NIL, info->dev->nodename, state,
                                  "%d", XenbusStateInitialised)) {
index 9433e46518c8dc8680fd1e5a44d823aa7f65fdb0..912b64edb42b4a016201b4e7d1a695ca25056610 100644 (file)
@@ -188,6 +188,8 @@ static int queue_reply(struct list_head *queue, const void *data, size_t len)
 
        if (len == 0)
                return 0;
+       if (len > XENSTORE_PAYLOAD_MAX)
+               return -EINVAL;
 
        rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
        if (rb == NULL)
index 0548c53f41d51902a4e0ce7b983f7cd365f656f9..22fc7c802d698766fb5b274e686e89df4e0d76d1 100644 (file)
@@ -511,8 +511,6 @@ affs_do_readpage_ofs(struct page *page, unsigned to)
        pr_debug("%s(%lu, %ld, 0, %d)\n", __func__, inode->i_ino,
                 page->index, to);
        BUG_ON(to > PAGE_CACHE_SIZE);
-       kmap(page);
-       data = page_address(page);
        bsize = AFFS_SB(sb)->s_data_blksize;
        tmp = page->index << PAGE_CACHE_SHIFT;
        bidx = tmp / bsize;
@@ -524,14 +522,15 @@ affs_do_readpage_ofs(struct page *page, unsigned to)
                        return PTR_ERR(bh);
                tmp = min(bsize - boff, to - pos);
                BUG_ON(pos + tmp > to || tmp > bsize);
+               data = kmap_atomic(page);
                memcpy(data + pos, AFFS_DATA(bh) + boff, tmp);
+               kunmap_atomic(data);
                affs_brelse(bh);
                bidx++;
                pos += tmp;
                boff = 0;
        }
        flush_dcache_page(page);
-       kunmap(page);
        return 0;
 }
 
index 051ea4809c14037fd0b1efffccb12c3909b3e46b..7d914c67a9d07f7ebb8a3f8f0bea8200d739ee9f 100644 (file)
@@ -653,7 +653,7 @@ static unsigned long randomize_stack_top(unsigned long stack_top)
 
        if ((current->flags & PF_RANDOMIZE) &&
                !(current->personality & ADDR_NO_RANDOMIZE)) {
-               random_variable = (unsigned long) get_random_int();
+               random_variable = get_random_long();
                random_variable &= STACK_RND_MASK;
                random_variable <<= PAGE_SHIFT;
        }
index afb43748436201e29343a923077976d01a2344fd..826b164a4b5b1faa9719aefc9cceccec20eda479 100644 (file)
@@ -1201,7 +1201,11 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                bdev->bd_disk = disk;
                bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
-               bdev->bd_inode->i_flags = disk->fops->direct_access ? S_DAX : 0;
+               if (IS_ENABLED(CONFIG_BLK_DEV_DAX) && disk->fops->direct_access)
+                       bdev->bd_inode->i_flags = S_DAX;
+               else
+                       bdev->bd_inode->i_flags = 0;
+
                if (!partno) {
                        ret = -ENXIO;
                        bdev->bd_part = disk_get_part(disk, partno);
@@ -1693,13 +1697,24 @@ static int blkdev_releasepage(struct page *page, gfp_t wait)
        return try_to_free_buffers(page);
 }
 
+static int blkdev_writepages(struct address_space *mapping,
+                            struct writeback_control *wbc)
+{
+       if (dax_mapping(mapping)) {
+               struct block_device *bdev = I_BDEV(mapping->host);
+
+               return dax_writeback_mapping_range(mapping, bdev, wbc);
+       }
+       return generic_writepages(mapping, wbc);
+}
+
 static const struct address_space_operations def_blk_aops = {
        .readpage       = blkdev_readpage,
        .readpages      = blkdev_readpages,
        .writepage      = blkdev_writepage,
        .write_begin    = blkdev_write_begin,
        .write_end      = blkdev_write_end,
-       .writepages     = generic_writepages,
+       .writepages     = blkdev_writepages,
        .releasepage    = blkdev_releasepage,
        .direct_IO      = blkdev_direct_IO,
        .is_dirty_writeback = buffer_check_dirty_writeback,
@@ -1730,6 +1745,12 @@ static int blkdev_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        return __dax_fault(vma, vmf, blkdev_get_block, NULL);
 }
 
+static int blkdev_dax_pfn_mkwrite(struct vm_area_struct *vma,
+               struct vm_fault *vmf)
+{
+       return dax_pfn_mkwrite(vma, vmf);
+}
+
 static int blkdev_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
                pmd_t *pmd, unsigned int flags)
 {
@@ -1739,7 +1760,7 @@ static int blkdev_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
 static const struct vm_operations_struct blkdev_dax_vm_ops = {
        .fault          = blkdev_dax_fault,
        .pmd_fault      = blkdev_dax_pmd_fault,
-       .pfn_mkwrite    = blkdev_dax_fault,
+       .pfn_mkwrite    = blkdev_dax_pfn_mkwrite,
 };
 
 static const struct vm_operations_struct blkdev_default_vm_ops = {
index b90cd3776f8e0a41635ce7cf5447e7b9652e6cca..f6dac40f87ff5d4022559e6701b506589aad0353 100644 (file)
@@ -1406,7 +1406,8 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
                        read_extent_buffer(eb, dest + bytes_left,
                                           name_off, name_len);
                if (eb != eb_in) {
-                       btrfs_tree_read_unlock_blocking(eb);
+                       if (!path->skip_locking)
+                               btrfs_tree_read_unlock_blocking(eb);
                        free_extent_buffer(eb);
                }
                ret = btrfs_find_item(fs_root, path, parent, 0,
@@ -1426,9 +1427,10 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
                eb = path->nodes[0];
                /* make sure we can use eb after releasing the path */
                if (eb != eb_in) {
-                       atomic_inc(&eb->refs);
-                       btrfs_tree_read_lock(eb);
-                       btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+                       if (!path->skip_locking)
+                               btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+                       path->nodes[0] = NULL;
+                       path->locks[0] = 0;
                }
                btrfs_release_path(path);
                iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
index c473c42d7d6c4d559dbe1587491cd2fb93804145..3346cd8f991032f2457b4c48a8e3440780d53a9a 100644 (file)
@@ -637,11 +637,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        faili = nr_pages - 1;
        cb->nr_pages = nr_pages;
 
-       /* In the parent-locked case, we only locked the range we are
-        * interested in.  In all other cases, we can opportunistically
-        * cache decompressed data that goes beyond the requested range. */
-       if (!(bio_flags & EXTENT_BIO_PARENT_LOCKED))
-               add_ra_bio_pages(inode, em_start + em_len, cb);
+       add_ra_bio_pages(inode, em_start + em_len, cb);
 
        /* include any pages we added in add_ra-bio_pages */
        uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE;
index 0be47e4b813672996b490515ef88af357c40a276..b57daa895cea8340fd7b3ed491bb730196b6b5e6 100644 (file)
@@ -1689,7 +1689,7 @@ int btrfs_should_delete_dir_index(struct list_head *del_list,
  *
  */
 int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
-                                   struct list_head *ins_list)
+                                   struct list_head *ins_list, bool *emitted)
 {
        struct btrfs_dir_item *di;
        struct btrfs_delayed_item *curr, *next;
@@ -1733,6 +1733,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
 
                if (over)
                        return 1;
+               *emitted = true;
        }
        return 0;
 }
index f70119f254216583f3c7317085ec209eceb03d0f..0167853c84aea2d93a8fdd0314342e0a1ef42d1b 100644 (file)
@@ -144,7 +144,7 @@ void btrfs_put_delayed_items(struct list_head *ins_list,
 int btrfs_should_delete_dir_index(struct list_head *del_list,
                                  u64 index);
 int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
-                                   struct list_head *ins_list);
+                                   struct list_head *ins_list, bool *emitted);
 
 /* for init */
 int __init btrfs_delayed_inode_init(void);
index 2e7c97a3f3444aec33a688a4d1f705b0486026cf..392592dc70106e72f61a76b9e2924b5aa99363af 100644 (file)
@@ -2897,12 +2897,11 @@ static int __do_readpage(struct extent_io_tree *tree,
        struct block_device *bdev;
        int ret;
        int nr = 0;
-       int parent_locked = *bio_flags & EXTENT_BIO_PARENT_LOCKED;
        size_t pg_offset = 0;
        size_t iosize;
        size_t disk_io_size;
        size_t blocksize = inode->i_sb->s_blocksize;
-       unsigned long this_bio_flag = *bio_flags & EXTENT_BIO_PARENT_LOCKED;
+       unsigned long this_bio_flag = 0;
 
        set_page_extent_mapped(page);
 
@@ -2942,18 +2941,16 @@ static int __do_readpage(struct extent_io_tree *tree,
                        kunmap_atomic(userpage);
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
                                            &cached, GFP_NOFS);
-                       if (!parent_locked)
-                               unlock_extent_cached(tree, cur,
-                                                    cur + iosize - 1,
-                                                    &cached, GFP_NOFS);
+                       unlock_extent_cached(tree, cur,
+                                            cur + iosize - 1,
+                                            &cached, GFP_NOFS);
                        break;
                }
                em = __get_extent_map(inode, page, pg_offset, cur,
                                      end - cur + 1, get_extent, em_cached);
                if (IS_ERR_OR_NULL(em)) {
                        SetPageError(page);
-                       if (!parent_locked)
-                               unlock_extent(tree, cur, end);
+                       unlock_extent(tree, cur, end);
                        break;
                }
                extent_offset = cur - em->start;
@@ -3038,12 +3035,9 @@ static int __do_readpage(struct extent_io_tree *tree,
 
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
                                            &cached, GFP_NOFS);
-                       if (parent_locked)
-                               free_extent_state(cached);
-                       else
-                               unlock_extent_cached(tree, cur,
-                                                    cur + iosize - 1,
-                                                    &cached, GFP_NOFS);
+                       unlock_extent_cached(tree, cur,
+                                            cur + iosize - 1,
+                                            &cached, GFP_NOFS);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -3052,8 +3046,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                if (test_range_bit(tree, cur, cur_end,
                                   EXTENT_UPTODATE, 1, NULL)) {
                        check_page_uptodate(tree, page);
-                       if (!parent_locked)
-                               unlock_extent(tree, cur, cur + iosize - 1);
+                       unlock_extent(tree, cur, cur + iosize - 1);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -3063,8 +3056,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                 */
                if (block_start == EXTENT_MAP_INLINE) {
                        SetPageError(page);
-                       if (!parent_locked)
-                               unlock_extent(tree, cur, cur + iosize - 1);
+                       unlock_extent(tree, cur, cur + iosize - 1);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -3083,8 +3075,7 @@ static int __do_readpage(struct extent_io_tree *tree,
                        *bio_flags = this_bio_flag;
                } else {
                        SetPageError(page);
-                       if (!parent_locked)
-                               unlock_extent(tree, cur, cur + iosize - 1);
+                       unlock_extent(tree, cur, cur + iosize - 1);
                }
                cur = cur + iosize;
                pg_offset += iosize;
@@ -3213,20 +3204,6 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
        return ret;
 }
 
-int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
-                                get_extent_t *get_extent, int mirror_num)
-{
-       struct bio *bio = NULL;
-       unsigned long bio_flags = EXTENT_BIO_PARENT_LOCKED;
-       int ret;
-
-       ret = __do_readpage(tree, page, get_extent, NULL, &bio, mirror_num,
-                           &bio_flags, READ, NULL);
-       if (bio)
-               ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
-       return ret;
-}
-
 static noinline void update_nr_written(struct page *page,
                                      struct writeback_control *wbc,
                                      unsigned long nr_written)
index 0377413bd4b98257eae07d12041d4dce45ac2c4f..880d5292e9721f6f2c59dfd0f85d3f6fd2cde3bb 100644 (file)
@@ -29,7 +29,6 @@
  */
 #define EXTENT_BIO_COMPRESSED 1
 #define EXTENT_BIO_TREE_LOG 2
-#define EXTENT_BIO_PARENT_LOCKED 4
 #define EXTENT_BIO_FLAG_SHIFT 16
 
 /* these are bit numbers for test/set bit */
@@ -210,8 +209,6 @@ static inline int lock_extent(struct extent_io_tree *tree, u64 start, u64 end)
 int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
 int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
                          get_extent_t *get_extent, int mirror_num);
-int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
-                                get_extent_t *get_extent, int mirror_num);
 int __init extent_io_init(void);
 void extent_io_exit(void);
 
index 5f06eb1f43843055c0373daeb9ad98648865150f..d96f5cf38a2dd2a8e227ad93ff22f7a678611034 100644 (file)
@@ -5717,6 +5717,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
        char *name_ptr;
        int name_len;
        int is_curr = 0;        /* ctx->pos points to the current index? */
+       bool emitted;
 
        /* FIXME, use a real flag for deciding about the key type */
        if (root->fs_info->tree_root == root)
@@ -5745,6 +5746,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
        if (ret < 0)
                goto err;
 
+       emitted = false;
        while (1) {
                leaf = path->nodes[0];
                slot = path->slots[0];
@@ -5824,6 +5826,7 @@ skip:
 
                        if (over)
                                goto nopos;
+                       emitted = true;
                        di_len = btrfs_dir_name_len(leaf, di) +
                                 btrfs_dir_data_len(leaf, di) + sizeof(*di);
                        di_cur += di_len;
@@ -5836,11 +5839,20 @@ next:
        if (key_type == BTRFS_DIR_INDEX_KEY) {
                if (is_curr)
                        ctx->pos++;
-               ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
+               ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted);
                if (ret)
                        goto nopos;
        }
 
+       /*
+        * If we haven't emitted any dir entry, we must not touch ctx->pos as
+        * it was was set to the termination value in previous call. We assume
+        * that "." and ".." were emitted if we reach this point and set the
+        * termination value as well for an empty directory.
+        */
+       if (ctx->pos > 2 && !emitted)
+               goto nopos;
+
        /* Reached end of directory/root. Bump pos past the last item. */
        ctx->pos++;
 
@@ -7974,6 +7986,7 @@ static void btrfs_endio_direct_read(struct bio *bio)
 
        kfree(dip);
 
+       dio_bio->bi_error = bio->bi_error;
        dio_end_io(dio_bio, bio->bi_error);
 
        if (io_bio->end_io)
@@ -8028,6 +8041,7 @@ static void btrfs_endio_direct_write(struct bio *bio)
 
        kfree(dip);
 
+       dio_bio->bi_error = bio->bi_error;
        dio_end_io(dio_bio, bio->bi_error);
        bio_put(bio);
 }
index 952172ca7e455633c28a79292d18ebbfd68c4d18..48aee9846329c526260aa09f5751335c351ea1e3 100644 (file)
@@ -2794,24 +2794,29 @@ out:
 static struct page *extent_same_get_page(struct inode *inode, pgoff_t index)
 {
        struct page *page;
-       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
 
        page = grab_cache_page(inode->i_mapping, index);
        if (!page)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        if (!PageUptodate(page)) {
-               if (extent_read_full_page_nolock(tree, page, btrfs_get_extent,
-                                                0))
-                       return NULL;
+               int ret;
+
+               ret = btrfs_readpage(NULL, page);
+               if (ret)
+                       return ERR_PTR(ret);
                lock_page(page);
                if (!PageUptodate(page)) {
                        unlock_page(page);
                        page_cache_release(page);
-                       return NULL;
+                       return ERR_PTR(-EIO);
+               }
+               if (page->mapping != inode->i_mapping) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       return ERR_PTR(-EAGAIN);
                }
        }
-       unlock_page(page);
 
        return page;
 }
@@ -2823,17 +2828,31 @@ static int gather_extent_pages(struct inode *inode, struct page **pages,
        pgoff_t index = off >> PAGE_CACHE_SHIFT;
 
        for (i = 0; i < num_pages; i++) {
+again:
                pages[i] = extent_same_get_page(inode, index + i);
-               if (!pages[i])
-                       return -ENOMEM;
+               if (IS_ERR(pages[i])) {
+                       int err = PTR_ERR(pages[i]);
+
+                       if (err == -EAGAIN)
+                               goto again;
+                       pages[i] = NULL;
+                       return err;
+               }
        }
        return 0;
 }
 
-static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
+static int lock_extent_range(struct inode *inode, u64 off, u64 len,
+                            bool retry_range_locking)
 {
-       /* do any pending delalloc/csum calc on src, one way or
-          another, and lock file content */
+       /*
+        * Do any pending delalloc/csum calculations on inode, one way or
+        * another, and lock file content.
+        * The locking order is:
+        *
+        *   1) pages
+        *   2) range in the inode's io tree
+        */
        while (1) {
                struct btrfs_ordered_extent *ordered;
                lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
@@ -2851,8 +2870,11 @@ static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
                unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
                if (ordered)
                        btrfs_put_ordered_extent(ordered);
+               if (!retry_range_locking)
+                       return -EAGAIN;
                btrfs_wait_ordered_range(inode, off, len);
        }
+       return 0;
 }
 
 static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2)
@@ -2877,15 +2899,24 @@ static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1,
        unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1);
 }
 
-static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
-                                    struct inode *inode2, u64 loff2, u64 len)
+static int btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
+                                   struct inode *inode2, u64 loff2, u64 len,
+                                   bool retry_range_locking)
 {
+       int ret;
+
        if (inode1 < inode2) {
                swap(inode1, inode2);
                swap(loff1, loff2);
        }
-       lock_extent_range(inode1, loff1, len);
-       lock_extent_range(inode2, loff2, len);
+       ret = lock_extent_range(inode1, loff1, len, retry_range_locking);
+       if (ret)
+               return ret;
+       ret = lock_extent_range(inode2, loff2, len, retry_range_locking);
+       if (ret)
+               unlock_extent(&BTRFS_I(inode1)->io_tree, loff1,
+                             loff1 + len - 1);
+       return ret;
 }
 
 struct cmp_pages {
@@ -2901,11 +2932,15 @@ static void btrfs_cmp_data_free(struct cmp_pages *cmp)
 
        for (i = 0; i < cmp->num_pages; i++) {
                pg = cmp->src_pages[i];
-               if (pg)
+               if (pg) {
+                       unlock_page(pg);
                        page_cache_release(pg);
+               }
                pg = cmp->dst_pages[i];
-               if (pg)
+               if (pg) {
+                       unlock_page(pg);
                        page_cache_release(pg);
+               }
        }
        kfree(cmp->src_pages);
        kfree(cmp->dst_pages);
@@ -2966,6 +3001,8 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
 
                src_page = cmp->src_pages[i];
                dst_page = cmp->dst_pages[i];
+               ASSERT(PageLocked(src_page));
+               ASSERT(PageLocked(dst_page));
 
                addr = kmap_atomic(src_page);
                dst_addr = kmap_atomic(dst_page);
@@ -3078,14 +3115,46 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
                goto out_unlock;
        }
 
+again:
        ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp);
        if (ret)
                goto out_unlock;
 
        if (same_inode)
-               lock_extent_range(src, same_lock_start, same_lock_len);
+               ret = lock_extent_range(src, same_lock_start, same_lock_len,
+                                       false);
        else
-               btrfs_double_extent_lock(src, loff, dst, dst_loff, len);
+               ret = btrfs_double_extent_lock(src, loff, dst, dst_loff, len,
+                                              false);
+       /*
+        * If one of the inodes has dirty pages in the respective range or
+        * ordered extents, we need to flush dellaloc and wait for all ordered
+        * extents in the range. We must unlock the pages and the ranges in the
+        * io trees to avoid deadlocks when flushing delalloc (requires locking
+        * pages) and when waiting for ordered extents to complete (they require
+        * range locking).
+        */
+       if (ret == -EAGAIN) {
+               /*
+                * Ranges in the io trees already unlocked. Now unlock all
+                * pages before waiting for all IO to complete.
+                */
+               btrfs_cmp_data_free(&cmp);
+               if (same_inode) {
+                       btrfs_wait_ordered_range(src, same_lock_start,
+                                                same_lock_len);
+               } else {
+                       btrfs_wait_ordered_range(src, loff, len);
+                       btrfs_wait_ordered_range(dst, dst_loff, len);
+               }
+               goto again;
+       }
+       ASSERT(ret == 0);
+       if (WARN_ON(ret)) {
+               /* ranges in the io trees already unlocked */
+               btrfs_cmp_data_free(&cmp);
+               return ret;
+       }
 
        /* pass original length for comparison so we stay within i_size */
        ret = btrfs_cmp_data(src, loff, dst, dst_loff, olen, &cmp);
@@ -3795,9 +3864,15 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
                u64 lock_start = min_t(u64, off, destoff);
                u64 lock_len = max_t(u64, off, destoff) + len - lock_start;
 
-               lock_extent_range(src, lock_start, lock_len);
+               ret = lock_extent_range(src, lock_start, lock_len, true);
        } else {
-               btrfs_double_extent_lock(src, off, inode, destoff, len);
+               ret = btrfs_double_extent_lock(src, off, inode, destoff, len,
+                                              true);
+       }
+       ASSERT(ret == 0);
+       if (WARN_ON(ret)) {
+               /* ranges in the io trees already unlocked */
+               goto out_unlock;
        }
 
        ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
index 7cf8509deda7c0ea6e98af02a8ab0acafbe016b2..2c849b08a91b53e0a7f1c475301a77d623cb5293 100644 (file)
@@ -310,8 +310,16 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
                set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state);
 
                err = btrfs_insert_fs_root(root->fs_info, root);
+               /*
+                * The root might have been inserted already, as before we look
+                * for orphan roots, log replay might have happened, which
+                * triggers a transaction commit and qgroup accounting, which
+                * in turn reads and inserts fs roots while doing backref
+                * walking.
+                */
+               if (err == -EEXIST)
+                       err = 0;
                if (err) {
-                       BUG_ON(err == -EEXIST);
                        btrfs_free_fs_root(root);
                        break;
                }
index c22213789090f975b3680b10e022a1e5f2f9fdb4..19adeb0ef82a397f122682db3a9ba31f56df5f5d 100644 (file)
@@ -1756,6 +1756,10 @@ int ceph_pool_perm_check(struct ceph_inode_info *ci, int need)
        u32 pool;
        int ret, flags;
 
+       /* does not support pool namespace yet */
+       if (ci->i_pool_ns_len)
+               return -EIO;
+
        if (ceph_test_mount_opt(ceph_inode_to_client(&ci->vfs_inode),
                                NOPOOLPERM))
                return 0;
index cdbf8cf3d52c3354569b7c86a709f4ce3fc09e2c..6fe0ad26a7dfc0430da9e9e0fca8c312a4b2bdc0 100644 (file)
@@ -2753,7 +2753,8 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
                             void *inline_data, int inline_len,
                             struct ceph_buffer *xattr_buf,
                             struct ceph_mds_session *session,
-                            struct ceph_cap *cap, int issued)
+                            struct ceph_cap *cap, int issued,
+                            u32 pool_ns_len)
        __releases(ci->i_ceph_lock)
        __releases(mdsc->snap_rwsem)
 {
@@ -2873,6 +2874,8 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
        if (newcaps & (CEPH_CAP_ANY_FILE_RD | CEPH_CAP_ANY_FILE_WR)) {
                /* file layout may have changed */
                ci->i_layout = grant->layout;
+               ci->i_pool_ns_len = pool_ns_len;
+
                /* size/truncate_seq? */
                queue_trunc = ceph_fill_file_size(inode, issued,
                                        le32_to_cpu(grant->truncate_seq),
@@ -3411,6 +3414,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        u32  inline_len = 0;
        void *snaptrace;
        size_t snaptrace_len;
+       u32 pool_ns_len = 0;
        void *p, *end;
 
        dout("handle_caps from mds%d\n", mds);
@@ -3463,6 +3467,21 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                p += inline_len;
        }
 
+       if (le16_to_cpu(msg->hdr.version) >= 8) {
+               u64 flush_tid;
+               u32 caller_uid, caller_gid;
+               u32 osd_epoch_barrier;
+               /* version >= 5 */
+               ceph_decode_32_safe(&p, end, osd_epoch_barrier, bad);
+               /* version >= 6 */
+               ceph_decode_64_safe(&p, end, flush_tid, bad);
+               /* version >= 7 */
+               ceph_decode_32_safe(&p, end, caller_uid, bad);
+               ceph_decode_32_safe(&p, end, caller_gid, bad);
+               /* version >= 8 */
+               ceph_decode_32_safe(&p, end, pool_ns_len, bad);
+       }
+
        /* lookup ino */
        inode = ceph_find_inode(sb, vino);
        ci = ceph_inode(inode);
@@ -3518,7 +3537,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                                  &cap, &issued);
                handle_cap_grant(mdsc, inode, h,
                                 inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued);
+                                msg->middle, session, cap, issued,
+                                pool_ns_len);
                if (realm)
                        ceph_put_snap_realm(mdsc, realm);
                goto done_unlocked;
@@ -3542,7 +3562,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                issued |= __ceph_caps_dirty(ci);
                handle_cap_grant(mdsc, inode, h,
                                 inline_version, inline_data, inline_len,
-                                msg->middle, session, cap, issued);
+                                msg->middle, session, cap, issued,
+                                pool_ns_len);
                goto done_unlocked;
 
        case CEPH_CAP_OP_FLUSH_ACK:
index 86a9c383955e56037eb38419b1e4617317d32237..eb9028e8cfc5197ef1ea99524fcbc67d67b4df91 100644 (file)
@@ -698,8 +698,8 @@ static void ceph_aio_retry_work(struct work_struct *work)
 
        req = ceph_osdc_alloc_request(orig_req->r_osdc, snapc, 2,
                        false, GFP_NOFS);
-       if (IS_ERR(req)) {
-               ret = PTR_ERR(req);
+       if (!req) {
+               ret = -ENOMEM;
                req = orig_req;
                goto out;
        }
@@ -716,7 +716,6 @@ static void ceph_aio_retry_work(struct work_struct *work)
        ceph_osdc_build_request(req, req->r_ops[0].extent.offset,
                                snapc, CEPH_NOSNAP, &aio_req->mtime);
 
-       ceph_put_snap_context(snapc);
        ceph_osdc_put_request(orig_req);
 
        req->r_callback = ceph_aio_complete_req;
@@ -731,6 +730,7 @@ out:
                ceph_aio_complete_req(req, NULL);
        }
 
+       ceph_put_snap_context(snapc);
        kfree(aio_work);
 }
 
index fb4ba2e4e2a5fa5c5d62afa3b94f758c7906687b..5849b88bbed3cfc333318574db80ded6305e0d9c 100644 (file)
@@ -396,6 +396,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_symlink = NULL;
 
        memset(&ci->i_dir_layout, 0, sizeof(ci->i_dir_layout));
+       ci->i_pool_ns_len = 0;
 
        ci->i_fragtree = RB_ROOT;
        mutex_init(&ci->i_fragtree_mutex);
@@ -756,6 +757,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
                if (ci->i_layout.fl_pg_pool != info->layout.fl_pg_pool)
                        ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
                ci->i_layout = info->layout;
+               ci->i_pool_ns_len = iinfo->pool_ns_len;
 
                queue_trunc = ceph_fill_file_size(inode, issued,
                                        le32_to_cpu(info->truncate_seq),
index e7b130a637f9f31a34efd67d6cf5789a8fcdef00..911d64d865f176aa4ce28832207abb8651a4fec8 100644 (file)
@@ -100,6 +100,14 @@ static int parse_reply_info_in(void **p, void *end,
        } else
                info->inline_version = CEPH_INLINE_NONE;
 
+       if (features & CEPH_FEATURE_FS_FILE_LAYOUT_V2) {
+               ceph_decode_32_safe(p, end, info->pool_ns_len, bad);
+               ceph_decode_need(p, end, info->pool_ns_len, bad);
+               *p += info->pool_ns_len;
+       } else {
+               info->pool_ns_len = 0;
+       }
+
        return 0;
 bad:
        return err;
@@ -2298,6 +2306,14 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
 
+       /* deny access to directories with pool_ns layouts */
+       if (req->r_inode && S_ISDIR(req->r_inode->i_mode) &&
+           ceph_inode(req->r_inode)->i_pool_ns_len)
+               return -EIO;
+       if (req->r_locked_dir &&
+           ceph_inode(req->r_locked_dir)->i_pool_ns_len)
+               return -EIO;
+
        /* issue */
        mutex_lock(&mdsc->mutex);
        __register_request(mdsc, req, dir);
index ccf11ef0ca8717f79e6bfc9d6cf806ec359b5e8c..37712ccffcc6b67c2f98a866c9c2be40324bc6ae 100644 (file)
@@ -44,6 +44,7 @@ struct ceph_mds_reply_info_in {
        u64 inline_version;
        u32 inline_len;
        char *inline_data;
+       u32 pool_ns_len;
 };
 
 /*
index 75b7d125ce668a9b3f4f851d2be1c688d6d5f964..9c458eb522458da2364238cef2e92530ace87df9 100644 (file)
@@ -287,6 +287,7 @@ struct ceph_inode_info {
 
        struct ceph_dir_layout i_dir_layout;
        struct ceph_file_layout i_layout;
+       size_t i_pool_ns_len;
        char *i_symlink;
 
        /* for dirs */
index 7dc886c9a78fc428b368a1c911b8c1ad745f48a5..e956cba94338184416c96925690f21493fc61ab6 100644 (file)
@@ -175,7 +175,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
         * string to the length of the original string to allow for worst case.
         */
        md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
-       mountdata = kzalloc(md_len + 1, GFP_KERNEL);
+       mountdata = kzalloc(md_len + sizeof("ip=") + 1, GFP_KERNEL);
        if (mountdata == NULL) {
                rc = -ENOMEM;
                goto compose_mount_options_err;
index afa09fce81515e4caf7500b04c16dfb96a71cfd1..e682b36a210f236561817bd11a799d3a8f57caf2 100644 (file)
@@ -714,7 +714,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
 
        ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
        if (!ses->auth_key.response) {
-               rc = ENOMEM;
+               rc = -ENOMEM;
                ses->auth_key.len = 0;
                goto setup_ntlmv2_rsp_ret;
        }
index c48ca13673e37f2eba7c4045f140e6e8b740e499..2eea40353e6086fc808da8c74deeaaf158a43da9 100644 (file)
@@ -1013,7 +1013,6 @@ const struct file_operations cifs_file_strict_ops = {
        .llseek = cifs_llseek,
        .unlocked_ioctl = cifs_ioctl,
        .clone_file_range = cifs_clone_file_range,
-       .clone_file_range = cifs_clone_file_range,
        .setlease = cifs_setlease,
        .fallocate = cifs_fallocate,
 };
index 68c4547528c486f2477a8177692374dd6033e2bf..83aac8ba50b0e168ec5b2a252c8b77daf9c2428b 100644 (file)
  * so that it will fit. We use hash_64 to convert the value to 31 bits, and
  * then add 1, to ensure that we don't end up with a 0 as the value.
  */
-#if BITS_PER_LONG == 64
 static inline ino_t
 cifs_uniqueid_to_ino_t(u64 fileid)
 {
+       if ((sizeof(ino_t)) < (sizeof(u64)))
+               return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
+
        return (ino_t)fileid;
+
 }
-#else
-static inline ino_t
-cifs_uniqueid_to_ino_t(u64 fileid)
-{
-       return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1;
-}
-#endif
 
 extern struct file_system_type cifs_fs_type;
 extern const struct address_space_operations cifs_addr_ops;
index 90b4f9f7de660a261b5f93322af59282294953fd..76fcb50295a38b63a58a0d3f656d023e02b988a8 100644 (file)
@@ -1396,11 +1396,10 @@ openRetry:
  * current bigbuf.
  */
 static int
-cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+discard_remaining_data(struct TCP_Server_Info *server)
 {
        unsigned int rfclen = get_rfc1002_length(server->smallbuf);
        int remaining = rfclen + 4 - server->total_read;
-       struct cifs_readdata *rdata = mid->callback_data;
 
        while (remaining > 0) {
                int length;
@@ -1414,10 +1413,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                remaining -= length;
        }
 
-       dequeue_mid(mid, rdata->result);
        return 0;
 }
 
+static int
+cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
+{
+       int length;
+       struct cifs_readdata *rdata = mid->callback_data;
+
+       length = discard_remaining_data(server);
+       dequeue_mid(mid, rdata->result);
+       return length;
+}
+
 int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
@@ -1446,6 +1455,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                return length;
        server->total_read += length;
 
+       if (server->ops->is_status_pending &&
+           server->ops->is_status_pending(buf, server, 0)) {
+               discard_remaining_data(server);
+               return -1;
+       }
+
        /* Was the SMB read successful? */
        rdata->result = server->ops->map_error(buf, false);
        if (rdata->result != 0) {
index 4fbd92d2e113e69d5e3105235a215a52b2e756e7..a763cd3d9e7c80589df30ddaa9515906c6fa6138 100644 (file)
@@ -2999,8 +2999,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
        if (ses_init_buf) {
                ses_init_buf->trailer.session_req.called_len = 32;
 
-               if (server->server_RFC1001_name &&
-                   server->server_RFC1001_name[0] != 0)
+               if (server->server_RFC1001_name[0] != 0)
                        rfc1002mangle(ses_init_buf->trailer.
                                      session_req.called_name,
                                      server->server_RFC1001_name,
index 10f8d5cf5681e26b843c0ac15821eab69e6eeb22..42e1f440eb1e9ae1ca497c7f8127ff58b7988b77 100644 (file)
@@ -1106,21 +1106,25 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
 {
        char *data_offset;
        struct create_context *cc;
-       unsigned int next = 0;
+       unsigned int next;
+       unsigned int remaining;
        char *name;
 
        data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
+       remaining = le32_to_cpu(rsp->CreateContextsLength);
        cc = (struct create_context *)data_offset;
-       do {
-               cc = (struct create_context *)((char *)cc + next);
+       while (remaining >= sizeof(struct create_context)) {
                name = le16_to_cpu(cc->NameOffset) + (char *)cc;
-               if (le16_to_cpu(cc->NameLength) != 4 ||
-                   strncmp(name, "RqLs", 4)) {
-                       next = le32_to_cpu(cc->Next);
-                       continue;
-               }
-               return server->ops->parse_lease_buf(cc, epoch);
-       } while (next != 0);
+               if (le16_to_cpu(cc->NameLength) == 4 &&
+                   strncmp(name, "RqLs", 4) == 0)
+                       return server->ops->parse_lease_buf(cc, epoch);
+
+               next = le32_to_cpu(cc->Next);
+               if (!next)
+                       break;
+               remaining -= next;
+               cc = (struct create_context *)((char *)cc + next);
+       }
 
        return 0;
 }
index e0e9358baf3524ba1b3e3cebb23787e43df0d1c6..711172450da642ccdcf4ac7dcceb7546faf66fad 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -79,15 +79,14 @@ struct page *read_dax_sector(struct block_device *bdev, sector_t n)
 }
 
 /*
- * dax_clear_blocks() is called from within transaction context from XFS,
+ * dax_clear_sectors() is called from within transaction context from XFS,
  * and hence this means the stack from this point must follow GFP_NOFS
  * semantics for all operations.
  */
-int dax_clear_blocks(struct inode *inode, sector_t block, long _size)
+int dax_clear_sectors(struct block_device *bdev, sector_t _sector, long _size)
 {
-       struct block_device *bdev = inode->i_sb->s_bdev;
        struct blk_dax_ctl dax = {
-               .sector = block << (inode->i_blkbits - 9),
+               .sector = _sector,
                .size = _size,
        };
 
@@ -109,7 +108,7 @@ int dax_clear_blocks(struct inode *inode, sector_t block, long _size)
        wmb_pmem();
        return 0;
 }
-EXPORT_SYMBOL_GPL(dax_clear_blocks);
+EXPORT_SYMBOL_GPL(dax_clear_sectors);
 
 /* the clear_pmem() calls are ordered by a wmb_pmem() in the caller */
 static void dax_new_buf(void __pmem *addr, unsigned size, unsigned first,
@@ -358,7 +357,8 @@ static int dax_radix_entry(struct address_space *mapping, pgoff_t index,
        void *entry;
 
        WARN_ON_ONCE(pmd_entry && !dirty);
-       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+       if (dirty)
+               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
 
        spin_lock_irq(&mapping->tree_lock);
 
@@ -484,11 +484,10 @@ static int dax_writeback_one(struct block_device *bdev,
  * end]. This is required by data integrity operations to ensure file data is
  * on persistent storage prior to completion of the operation.
  */
-int dax_writeback_mapping_range(struct address_space *mapping, loff_t start,
-               loff_t end)
+int dax_writeback_mapping_range(struct address_space *mapping,
+               struct block_device *bdev, struct writeback_control *wbc)
 {
        struct inode *inode = mapping->host;
-       struct block_device *bdev = inode->i_sb->s_bdev;
        pgoff_t start_index, end_index, pmd_index;
        pgoff_t indices[PAGEVEC_SIZE];
        struct pagevec pvec;
@@ -499,8 +498,11 @@ int dax_writeback_mapping_range(struct address_space *mapping, loff_t start,
        if (WARN_ON_ONCE(inode->i_blkbits != PAGE_SHIFT))
                return -EIO;
 
-       start_index = start >> PAGE_CACHE_SHIFT;
-       end_index = end >> PAGE_CACHE_SHIFT;
+       if (!mapping->nrexceptional || wbc->sync_mode != WB_SYNC_ALL)
+               return 0;
+
+       start_index = wbc->range_start >> PAGE_CACHE_SHIFT;
+       end_index = wbc->range_end >> PAGE_CACHE_SHIFT;
        pmd_index = DAX_PMD_INDEX(start_index);
 
        rcu_read_lock();
index 92d5140de8516c642b6ea5af81f0ffe89399a416..2398f9f9433752aa53dbd3af4cfe0f82aba22d99 100644 (file)
@@ -269,9 +269,6 @@ static inline int dname_external(const struct dentry *dentry)
        return dentry->d_name.name != dentry->d_iname;
 }
 
-/*
- * Make sure other CPUs see the inode attached before the type is set.
- */
 static inline void __d_set_inode_and_type(struct dentry *dentry,
                                          struct inode *inode,
                                          unsigned type_flags)
@@ -279,28 +276,18 @@ static inline void __d_set_inode_and_type(struct dentry *dentry,
        unsigned flags;
 
        dentry->d_inode = inode;
-       smp_wmb();
        flags = READ_ONCE(dentry->d_flags);
        flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
        flags |= type_flags;
        WRITE_ONCE(dentry->d_flags, flags);
 }
 
-/*
- * Ideally, we want to make sure that other CPUs see the flags cleared before
- * the inode is detached, but this is really a violation of RCU principles
- * since the ordering suggests we should always set inode before flags.
- *
- * We should instead replace or discard the entire dentry - but that sucks
- * performancewise on mass deletion/rename.
- */
 static inline void __d_clear_type_and_inode(struct dentry *dentry)
 {
        unsigned flags = READ_ONCE(dentry->d_flags);
 
        flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
        WRITE_ONCE(dentry->d_flags, flags);
-       smp_wmb();
        dentry->d_inode = NULL;
 }
 
@@ -370,9 +357,11 @@ static void dentry_unlink_inode(struct dentry * dentry)
        __releases(dentry->d_inode->i_lock)
 {
        struct inode *inode = dentry->d_inode;
+
+       raw_write_seqcount_begin(&dentry->d_seq);
        __d_clear_type_and_inode(dentry);
        hlist_del_init(&dentry->d_u.d_alias);
-       dentry_rcuwalk_invalidate(dentry);
+       raw_write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
        spin_unlock(&inode->i_lock);
        if (!inode->i_nlink)
@@ -1758,8 +1747,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
        spin_lock(&dentry->d_lock);
        if (inode)
                hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
+       raw_write_seqcount_begin(&dentry->d_seq);
        __d_set_inode_and_type(dentry, inode, add_flags);
-       dentry_rcuwalk_invalidate(dentry);
+       raw_write_seqcount_end(&dentry->d_seq);
        spin_unlock(&dentry->d_lock);
        fsnotify_d_instantiate(dentry, inode);
 }
index 1f107fd513286f0f3e8be601cd715ea0ee5443e8..655f21f991606b5bf2bef600a54b814994dbed98 100644 (file)
@@ -575,6 +575,26 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
        mutex_unlock(&allocated_ptys_lock);
 }
 
+/*
+ * pty code needs to hold extra references in case of last /dev/tty close
+ */
+
+void devpts_add_ref(struct inode *ptmx_inode)
+{
+       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+
+       atomic_inc(&sb->s_active);
+       ihold(ptmx_inode);
+}
+
+void devpts_del_ref(struct inode *ptmx_inode)
+{
+       struct super_block *sb = pts_sb_from_inode(ptmx_inode);
+
+       iput(ptmx_inode);
+       deactivate_super(sb);
+}
+
 /**
  * devpts_pty_new -- create a new inode in /dev/pts/
  * @ptmx_inode: inode of the master
index 1b2f7ffc8b841fd16cf312874fe8c7d4c0fa0e8e..d6a9012d42ad570f231a1f48c6706c6af8d5a598 100644 (file)
@@ -472,8 +472,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
                dio->io_error = -EIO;
 
        if (dio->is_async && dio->rw == READ && dio->should_dirty) {
-               bio_check_pages_dirty(bio);     /* transfers ownership */
                err = bio->bi_error;
+               bio_check_pages_dirty(bio);     /* transfers ownership */
        } else {
                bio_for_each_segment_all(bvec, bio, i) {
                        struct page *page = bvec->bv_page;
index c424e4813ec8019b5f8a62feb8eb51c6d13f7f97..d48e0d261d78da6e1ce2830e65000e37ed4bd292 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/mount.h>
 
 #include "internal.h"
 
@@ -103,9 +104,78 @@ out_free:
        return size;
 }
 
+static int
+efivarfs_ioc_getxflags(struct file *file, void __user *arg)
+{
+       struct inode *inode = file->f_mapping->host;
+       unsigned int i_flags;
+       unsigned int flags = 0;
+
+       i_flags = inode->i_flags;
+       if (i_flags & S_IMMUTABLE)
+               flags |= FS_IMMUTABLE_FL;
+
+       if (copy_to_user(arg, &flags, sizeof(flags)))
+               return -EFAULT;
+       return 0;
+}
+
+static int
+efivarfs_ioc_setxflags(struct file *file, void __user *arg)
+{
+       struct inode *inode = file->f_mapping->host;
+       unsigned int flags;
+       unsigned int i_flags = 0;
+       int error;
+
+       if (!inode_owner_or_capable(inode))
+               return -EACCES;
+
+       if (copy_from_user(&flags, arg, sizeof(flags)))
+               return -EFAULT;
+
+       if (flags & ~FS_IMMUTABLE_FL)
+               return -EOPNOTSUPP;
+
+       if (!capable(CAP_LINUX_IMMUTABLE))
+               return -EPERM;
+
+       if (flags & FS_IMMUTABLE_FL)
+               i_flags |= S_IMMUTABLE;
+
+
+       error = mnt_want_write_file(file);
+       if (error)
+               return error;
+
+       inode_lock(inode);
+       inode_set_flags(inode, i_flags, S_IMMUTABLE);
+       inode_unlock(inode);
+
+       mnt_drop_write_file(file);
+
+       return 0;
+}
+
+long
+efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
+{
+       void __user *arg = (void __user *)p;
+
+       switch (cmd) {
+       case FS_IOC_GETFLAGS:
+               return efivarfs_ioc_getxflags(file, arg);
+       case FS_IOC_SETFLAGS:
+               return efivarfs_ioc_setxflags(file, arg);
+       }
+
+       return -ENOTTY;
+}
+
 const struct file_operations efivarfs_file_operations = {
        .open   = simple_open,
        .read   = efivarfs_file_read,
        .write  = efivarfs_file_write,
        .llseek = no_llseek,
+       .unlocked_ioctl = efivarfs_file_ioctl,
 };
index 3381b9da9ee6080881720f0500b71c74ecdf6058..e2ab6d0497f2bb86dee165421487d27e4b64ba0d 100644 (file)
@@ -15,7 +15,8 @@
 #include "internal.h"
 
 struct inode *efivarfs_get_inode(struct super_block *sb,
-                               const struct inode *dir, int mode, dev_t dev)
+                               const struct inode *dir, int mode,
+                               dev_t dev, bool is_removable)
 {
        struct inode *inode = new_inode(sb);
 
@@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb,
                inode->i_ino = get_next_ino();
                inode->i_mode = mode;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               inode->i_flags = is_removable ? 0 : S_IMMUTABLE;
                switch (mode & S_IFMT) {
                case S_IFREG:
                        inode->i_fop = &efivarfs_file_operations;
@@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
 static int efivarfs_create(struct inode *dir, struct dentry *dentry,
                          umode_t mode, bool excl)
 {
-       struct inode *inode;
+       struct inode *inode = NULL;
        struct efivar_entry *var;
        int namelen, i = 0, err = 0;
+       bool is_removable = false;
 
        if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
                return -EINVAL;
 
-       inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
-       if (!inode)
-               return -ENOMEM;
-
        var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
-       if (!var) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!var)
+               return -ENOMEM;
 
        /* length of the variable name itself: remove GUID and separator */
        namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
@@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
        efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
                        &var->var.VendorGuid);
 
+       if (efivar_variable_is_removable(var->var.VendorGuid,
+                                        dentry->d_name.name, namelen))
+               is_removable = true;
+
+       inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable);
+       if (!inode) {
+               err = -ENOMEM;
+               goto out;
+       }
+
        for (i = 0; i < namelen; i++)
                var->var.VariableName[i] = dentry->d_name.name[i];
 
@@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
 out:
        if (err) {
                kfree(var);
-               iput(inode);
+               if (inode)
+                       iput(inode);
        }
        return err;
 }
index b5ff16addb7ce0984d14d2efe0324be884d20911..b4505188e799b9f5f50b2f792090775fd4244127 100644 (file)
@@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations;
 extern const struct inode_operations efivarfs_dir_inode_operations;
 extern bool efivarfs_valid_name(const char *str, int len);
 extern struct inode *efivarfs_get_inode(struct super_block *sb,
-                       const struct inode *dir, int mode, dev_t dev);
+                       const struct inode *dir, int mode, dev_t dev,
+                       bool is_removable);
 
 extern struct list_head efivarfs_list;
 
index b8a564f29107b6d38e90b54d99c86f4aa4b96532..dd029d13ea6140f7df1ed99fb2634a9c858f801f 100644 (file)
@@ -118,8 +118,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
        struct dentry *dentry, *root = sb->s_root;
        unsigned long size = 0;
        char *name;
-       int len, i;
+       int len;
        int err = -ENOMEM;
+       bool is_removable = false;
 
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (!entry)
@@ -128,15 +129,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
        memcpy(entry->var.VariableName, name16, name_size);
        memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
 
-       len = ucs2_strlen(entry->var.VariableName);
+       len = ucs2_utf8size(entry->var.VariableName);
 
        /* name, plus '-', plus GUID, plus NUL*/
        name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
        if (!name)
                goto fail;
 
-       for (i = 0; i < len; i++)
-               name[i] = entry->var.VariableName[i] & 0xFF;
+       ucs2_as_utf8(name, entry->var.VariableName, len);
+
+       if (efivar_variable_is_removable(entry->var.VendorGuid, name, len))
+               is_removable = true;
 
        name[len] = '-';
 
@@ -144,7 +147,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
 
        name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
 
-       inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0);
+       inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0,
+                                  is_removable);
        if (!inode)
                goto fail_name;
 
@@ -200,7 +204,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_d_op              = &efivarfs_d_ops;
        sb->s_time_gran         = 1;
 
-       inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
+       inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
        if (!inode)
                return -ENOMEM;
        inode->i_op = &efivarfs_dir_inode_operations;
index ae1dbcf47e979d48b67ee83e1ec413e4d119a48b..cde60741cad2c4cc429f04e80f29e788b0e0d673 100644 (file)
 /* Epoll private bits inside the event mask */
 #define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE)
 
+#define EPOLLINOUT_BITS (POLLIN | POLLOUT)
+
+#define EPOLLEXCLUSIVE_OK_BITS (EPOLLINOUT_BITS | POLLERR | POLLHUP | \
+                               EPOLLWAKEUP | EPOLLET | EPOLLEXCLUSIVE)
+
 /* Maximum number of nesting allowed inside epoll sets */
 #define EP_MAX_NESTS 4
 
@@ -1068,7 +1073,22 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
         * wait list.
         */
        if (waitqueue_active(&ep->wq)) {
-               ewake = 1;
+               if ((epi->event.events & EPOLLEXCLUSIVE) &&
+                                       !((unsigned long)key & POLLFREE)) {
+                       switch ((unsigned long)key & EPOLLINOUT_BITS) {
+                       case POLLIN:
+                               if (epi->event.events & POLLIN)
+                                       ewake = 1;
+                               break;
+                       case POLLOUT:
+                               if (epi->event.events & POLLOUT)
+                                       ewake = 1;
+                               break;
+                       case 0:
+                               ewake = 1;
+                               break;
+                       }
+               }
                wake_up_locked(&ep->wq);
        }
        if (waitqueue_active(&ep->poll_wait))
@@ -1875,9 +1895,13 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
         * so EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation.
         * Also, we do not currently supported nested exclusive wakeups.
         */
-       if ((epds.events & EPOLLEXCLUSIVE) && (op == EPOLL_CTL_MOD ||
-               (op == EPOLL_CTL_ADD && is_file_epoll(tf.file))))
-               goto error_tgt_fput;
+       if (epds.events & EPOLLEXCLUSIVE) {
+               if (op == EPOLL_CTL_MOD)
+                       goto error_tgt_fput;
+               if (op == EPOLL_CTL_ADD && (is_file_epoll(tf.file) ||
+                               (epds.events & ~EPOLLEXCLUSIVE_OK_BITS)))
+                       goto error_tgt_fput;
+       }
 
        /*
         * At this point it is safe to assume that the "private_data" contains
@@ -1950,8 +1974,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                break;
        case EPOLL_CTL_MOD:
                if (epi) {
-                       epds.events |= POLLERR | POLLHUP;
-                       error = ep_modify(ep, epi, &epds);
+                       if (!(epi->event.events & EPOLLEXCLUSIVE)) {
+                               epds.events |= POLLERR | POLLHUP;
+                               error = ep_modify(ep, epi, &epds);
+                       }
                } else
                        error = -ENOENT;
                break;
index 2c88d683cd918d673c83390aea187e763b5aa78e..c1400b109805b8778d8ee947ecad3060539f5ebe 100644 (file)
@@ -80,23 +80,6 @@ static int ext2_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
        return ret;
 }
 
-static int ext2_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       struct inode *inode = file_inode(vma->vm_file);
-       struct ext2_inode_info *ei = EXT2_I(inode);
-       int ret;
-
-       sb_start_pagefault(inode->i_sb);
-       file_update_time(vma->vm_file);
-       down_read(&ei->dax_sem);
-
-       ret = __dax_mkwrite(vma, vmf, ext2_get_block, NULL);
-
-       up_read(&ei->dax_sem);
-       sb_end_pagefault(inode->i_sb);
-       return ret;
-}
-
 static int ext2_dax_pfn_mkwrite(struct vm_area_struct *vma,
                struct vm_fault *vmf)
 {
@@ -124,7 +107,7 @@ static int ext2_dax_pfn_mkwrite(struct vm_area_struct *vma,
 static const struct vm_operations_struct ext2_dax_vm_ops = {
        .fault          = ext2_dax_fault,
        .pmd_fault      = ext2_dax_pmd_fault,
-       .page_mkwrite   = ext2_dax_mkwrite,
+       .page_mkwrite   = ext2_dax_fault,
        .pfn_mkwrite    = ext2_dax_pfn_mkwrite,
 };
 
index 338eefda70c6fc4e2055c0165b590febf1295acb..6bd58e6ff038657f75b93857bad455ebdfedfa0f 100644 (file)
@@ -737,8 +737,10 @@ static int ext2_get_blocks(struct inode *inode,
                 * so that it's not found by another thread before it's
                 * initialised
                 */
-               err = dax_clear_blocks(inode, le32_to_cpu(chain[depth-1].key),
-                                               1 << inode->i_blkbits);
+               err = dax_clear_sectors(inode->i_sb->s_bdev,
+                               le32_to_cpu(chain[depth-1].key) <<
+                               (inode->i_blkbits - 9),
+                               1 << inode->i_blkbits);
                if (err) {
                        mutex_unlock(&ei->truncate_mutex);
                        goto cleanup;
@@ -874,6 +876,14 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, loff_t offset)
 static int
 ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
+#ifdef CONFIG_FS_DAX
+       if (dax_mapping(mapping)) {
+               return dax_writeback_mapping_range(mapping,
+                                                  mapping->host->i_sb->s_bdev,
+                                                  wbc);
+       }
+#endif
+
        return mpage_writepages(mapping, wbc, ext2_get_block);
 }
 
@@ -1296,7 +1306,7 @@ void ext2_set_inode_flags(struct inode *inode)
                inode->i_flags |= S_NOATIME;
        if (flags & EXT2_DIRSYNC_FL)
                inode->i_flags |= S_DIRSYNC;
-       if (test_opt(inode->i_sb, DAX))
+       if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode))
                inode->i_flags |= S_DAX;
 }
 
index ec0668a60678d215dadc9baa97623ddbd3dbc160..fe1f50fe764ff9238354e2e30491c6e1e6d149b9 100644 (file)
@@ -191,7 +191,6 @@ static int ext4_init_block_bitmap(struct super_block *sb,
        /* If checksum is bad mark all blocks used to prevent allocation
         * essentially implementing a per-group read-only flag. */
        if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
-               ext4_error(sb, "Checksum bad for group %u", block_group);
                grp = ext4_get_group_info(sb, block_group);
                if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
                        percpu_counter_sub(&sbi->s_freeclusters_counter,
@@ -442,14 +441,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
        }
        ext4_lock_group(sb, block_group);
        if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-
                err = ext4_init_block_bitmap(sb, bh, block_group, desc);
                set_bitmap_uptodate(bh);
                set_buffer_uptodate(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
-               if (err)
+               if (err) {
+                       ext4_error(sb, "Failed to init block bitmap for group "
+                                  "%u: %d", block_group, err);
                        goto out;
+               }
                goto verify;
        }
        ext4_unlock_group(sb, block_group);
index c8021208a7eb1a98ba32e16a8536146f570d5c4a..38f7562489bbb0ccdea3085bbfcbcf4098210203 100644 (file)
@@ -467,3 +467,59 @@ uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size)
                return size;
        return 0;
 }
+
+/*
+ * Validate dentries for encrypted directories to make sure we aren't
+ * potentially caching stale data after a key has been added or
+ * removed.
+ */
+static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       struct inode *dir = d_inode(dentry->d_parent);
+       struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info;
+       int dir_has_key, cached_with_key;
+
+       if (!ext4_encrypted_inode(dir))
+               return 0;
+
+       if (ci && ci->ci_keyring_key &&
+           (ci->ci_keyring_key->flags & ((1 << KEY_FLAG_INVALIDATED) |
+                                         (1 << KEY_FLAG_REVOKED) |
+                                         (1 << KEY_FLAG_DEAD))))
+               ci = NULL;
+
+       /* this should eventually be an flag in d_flags */
+       cached_with_key = dentry->d_fsdata != NULL;
+       dir_has_key = (ci != NULL);
+
+       /*
+        * If the dentry was cached without the key, and it is a
+        * negative dentry, it might be a valid name.  We can't check
+        * if the key has since been made available due to locking
+        * reasons, so we fail the validation so ext4_lookup() can do
+        * this check.
+        *
+        * We also fail the validation if the dentry was created with
+        * the key present, but we no longer have the key, or vice versa.
+        */
+       if ((!cached_with_key && d_is_negative(dentry)) ||
+           (!cached_with_key && dir_has_key) ||
+           (cached_with_key && !dir_has_key)) {
+#if 0                          /* Revalidation debug */
+               char buf[80];
+               char *cp = simple_dname(dentry, buf, sizeof(buf));
+
+               if (IS_ERR(cp))
+                       cp = (char *) "???";
+               pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata,
+                      cached_with_key, d_is_negative(dentry),
+                      dir_has_key);
+#endif
+               return 0;
+       }
+       return 1;
+}
+
+const struct dentry_operations ext4_encrypted_d_ops = {
+       .d_revalidate = ext4_d_revalidate,
+};
index 1d1bca74f84437172d96c26e648e6ed45e129725..33f5e2a50cf883c43842e1c89a868fcf70c4c2a9 100644 (file)
@@ -111,6 +111,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
        int dir_has_error = 0;
        struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
 
+       if (ext4_encrypted_inode(inode)) {
+               err = ext4_get_encryption_info(inode);
+               if (err && err != -ENOKEY)
+                       return err;
+       }
+
        if (is_dx_dir(inode)) {
                err = ext4_dx_readdir(file, ctx);
                if (err != ERR_BAD_DX_DIR) {
@@ -157,8 +163,11 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
                                        index, 1);
                        file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
                        bh = ext4_bread(NULL, inode, map.m_lblk, 0);
-                       if (IS_ERR(bh))
-                               return PTR_ERR(bh);
+                       if (IS_ERR(bh)) {
+                               err = PTR_ERR(bh);
+                               bh = NULL;
+                               goto errout;
+                       }
                }
 
                if (!bh) {
index 0662b285dc8a71982a54e5895d58d797c7bcf6a4..157b458a69d4b7c334f28b80c37fd5d11c9f0c25 100644 (file)
@@ -2302,6 +2302,7 @@ struct page *ext4_encrypt(struct inode *inode,
 int ext4_decrypt(struct page *page);
 int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk,
                           ext4_fsblk_t pblk, ext4_lblk_t len);
+extern const struct dentry_operations ext4_encrypted_d_ops;
 
 #ifdef CONFIG_EXT4_FS_ENCRYPTION
 int ext4_init_crypto(void);
index 0ffabaf90aa5d19914aaf9e3cbeca44922f15f86..3753ceb0b0dd7b610c8e3ddefe4b992c07416fff 100644 (file)
@@ -3928,7 +3928,7 @@ static int
 convert_initialized_extent(handle_t *handle, struct inode *inode,
                           struct ext4_map_blocks *map,
                           struct ext4_ext_path **ppath, int flags,
-                          unsigned int allocated, ext4_fsblk_t newblock)
+                          unsigned int allocated)
 {
        struct ext4_ext_path *path = *ppath;
        struct ext4_extent *ex;
@@ -4347,7 +4347,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
                            (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) {
                                allocated = convert_initialized_extent(
                                                handle, inode, map, &path,
-                                               flags, allocated, newblock);
+                                               flags, allocated);
                                goto out2;
                        } else if (!ext4_ext_is_unwritten(ex))
                                goto out;
index 1126436dada19519b97240bcdb42995acae46724..4cd318f31cbeff21979d552cab7390c6df76a5c9 100644 (file)
@@ -262,23 +262,8 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
        return result;
 }
 
-static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
-       int err;
-       struct inode *inode = file_inode(vma->vm_file);
-
-       sb_start_pagefault(inode->i_sb);
-       file_update_time(vma->vm_file);
-       down_read(&EXT4_I(inode)->i_mmap_sem);
-       err = __dax_mkwrite(vma, vmf, ext4_dax_mmap_get_block, NULL);
-       up_read(&EXT4_I(inode)->i_mmap_sem);
-       sb_end_pagefault(inode->i_sb);
-
-       return err;
-}
-
 /*
- * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_mkwrite()
+ * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_fault()
  * handler we check for races agaist truncate. Note that since we cycle through
  * i_mmap_sem, we are sure that also any hole punching that began before we
  * were called is finished by now and so if it included part of the file we
@@ -311,7 +296,7 @@ static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma,
 static const struct vm_operations_struct ext4_dax_vm_ops = {
        .fault          = ext4_dax_fault,
        .pmd_fault      = ext4_dax_pmd_fault,
-       .page_mkwrite   = ext4_dax_mkwrite,
+       .page_mkwrite   = ext4_dax_fault,
        .pfn_mkwrite    = ext4_dax_pfn_mkwrite,
 };
 #else
@@ -350,6 +335,7 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
        struct super_block *sb = inode->i_sb;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
        struct vfsmount *mnt = filp->f_path.mnt;
+       struct inode *dir = filp->f_path.dentry->d_parent->d_inode;
        struct path path;
        char buf[64], *cp;
        int ret;
@@ -393,6 +379,14 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
                if (ext4_encryption_info(inode) == NULL)
                        return -ENOKEY;
        }
+       if (ext4_encrypted_inode(dir) &&
+           !ext4_is_child_context_consistent_with_parent(dir, inode)) {
+               ext4_warning(inode->i_sb,
+                            "Inconsistent encryption contexts: %lu/%lu\n",
+                            (unsigned long) dir->i_ino,
+                            (unsigned long) inode->i_ino);
+               return -EPERM;
+       }
        /*
         * Set up the jbd2_inode if we are opening the inode for
         * writing and the journal is present
index 3fcfd50a2e8a0c05315d823fa1219bea2c87f6c8..acc0ad56bf2f43c5c3a95502342e83a28f8b4148 100644 (file)
@@ -76,7 +76,6 @@ static int ext4_init_inode_bitmap(struct super_block *sb,
        /* If checksum is bad mark all blocks and inodes use to prevent
         * allocation, essentially implementing a per-group read-only flag. */
        if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
-               ext4_error(sb, "Checksum bad for group %u", block_group);
                grp = ext4_get_group_info(sb, block_group);
                if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
                        percpu_counter_sub(&sbi->s_freeclusters_counter,
@@ -191,8 +190,11 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
                set_buffer_verified(bh);
                ext4_unlock_group(sb, block_group);
                unlock_buffer(bh);
-               if (err)
+               if (err) {
+                       ext4_error(sb, "Failed to init inode bitmap for group "
+                                  "%u: %d", block_group, err);
                        goto out;
+               }
                return bh;
        }
        ext4_unlock_group(sb, block_group);
index 83bc8bfb3bea8eeefed38ca46ae8260779222405..aee960b1af347e3407dd05f5a7095a7af4d8a96e 100644 (file)
@@ -686,6 +686,34 @@ out_sem:
        return retval;
 }
 
+/*
+ * Update EXT4_MAP_FLAGS in bh->b_state. For buffer heads attached to pages
+ * we have to be careful as someone else may be manipulating b_state as well.
+ */
+static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags)
+{
+       unsigned long old_state;
+       unsigned long new_state;
+
+       flags &= EXT4_MAP_FLAGS;
+
+       /* Dummy buffer_head? Set non-atomically. */
+       if (!bh->b_page) {
+               bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | flags;
+               return;
+       }
+       /*
+        * Someone else may be modifying b_state. Be careful! This is ugly but
+        * once we get rid of using bh as a container for mapping information
+        * to pass to / from get_block functions, this can go away.
+        */
+       do {
+               old_state = READ_ONCE(bh->b_state);
+               new_state = (old_state & ~EXT4_MAP_FLAGS) | flags;
+       } while (unlikely(
+                cmpxchg(&bh->b_state, old_state, new_state) != old_state));
+}
+
 /* Maximum number of blocks we map for direct IO at once. */
 #define DIO_MAX_BLOCKS 4096
 
@@ -722,7 +750,7 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock,
                ext4_io_end_t *io_end = ext4_inode_aio(inode);
 
                map_bh(bh, inode->i_sb, map.m_pblk);
-               bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+               ext4_update_bh_state(bh, map.m_flags);
                if (io_end && io_end->flag & EXT4_IO_END_UNWRITTEN)
                        set_buffer_defer_completion(bh);
                bh->b_size = inode->i_sb->s_blocksize * map.m_len;
@@ -1685,7 +1713,7 @@ int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
                return ret;
 
        map_bh(bh, inode->i_sb, map.m_pblk);
-       bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
+       ext4_update_bh_state(bh, map.m_flags);
 
        if (buffer_unwritten(bh)) {
                /* A delayed write to unwritten bh should be marked
@@ -2450,6 +2478,10 @@ static int ext4_writepages(struct address_space *mapping,
 
        trace_ext4_writepages(inode, wbc);
 
+       if (dax_mapping(mapping))
+               return dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev,
+                                                  wbc);
+
        /*
         * No pages to write? This is mainly a kludge to avoid starting
         * a transaction for special inodes like journal inode on last iput()
@@ -3253,29 +3285,29 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
         * case, we allocate an io_end structure to hook to the iocb.
         */
        iocb->private = NULL;
-       ext4_inode_aio_set(inode, NULL);
-       if (!is_sync_kiocb(iocb)) {
-               io_end = ext4_init_io_end(inode, GFP_NOFS);
-               if (!io_end) {
-                       ret = -ENOMEM;
-                       goto retake_lock;
-               }
-               /*
-                * Grab reference for DIO. Will be dropped in ext4_end_io_dio()
-                */
-               iocb->private = ext4_get_io_end(io_end);
-               /*
-                * we save the io structure for current async direct
-                * IO, so that later ext4_map_blocks() could flag the
-                * io structure whether there is a unwritten extents
-                * needs to be converted when IO is completed.
-                */
-               ext4_inode_aio_set(inode, io_end);
-       }
-
        if (overwrite) {
                get_block_func = ext4_get_block_overwrite;
        } else {
+               ext4_inode_aio_set(inode, NULL);
+               if (!is_sync_kiocb(iocb)) {
+                       io_end = ext4_init_io_end(inode, GFP_NOFS);
+                       if (!io_end) {
+                               ret = -ENOMEM;
+                               goto retake_lock;
+                       }
+                       /*
+                        * Grab reference for DIO. Will be dropped in
+                        * ext4_end_io_dio()
+                        */
+                       iocb->private = ext4_get_io_end(io_end);
+                       /*
+                        * we save the io structure for current async direct
+                        * IO, so that later ext4_map_blocks() could flag the
+                        * io structure whether there is a unwritten extents
+                        * needs to be converted when IO is completed.
+                        */
+                       ext4_inode_aio_set(inode, io_end);
+               }
                get_block_func = ext4_get_block_write;
                dio_flags = DIO_LOCKING;
        }
@@ -4127,7 +4159,7 @@ void ext4_set_inode_flags(struct inode *inode)
                new_fl |= S_NOATIME;
        if (flags & EXT4_DIRSYNC_FL)
                new_fl |= S_DIRSYNC;
-       if (test_opt(inode->i_sb, DAX))
+       if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode))
                new_fl |= S_DAX;
        inode_set_flags(inode, new_fl,
                        S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX);
index 0f6c36922c2466116d610e8092bd17b64285c29c..eae5917c534e51b2fddf7bcebfa1293ed76a2841 100644 (file)
@@ -208,7 +208,7 @@ static int ext4_ioctl_setflags(struct inode *inode,
 {
        struct ext4_inode_info *ei = EXT4_I(inode);
        handle_t *handle = NULL;
-       int err = EPERM, migrate = 0;
+       int err = -EPERM, migrate = 0;
        struct ext4_iloc iloc;
        unsigned int oldflags, mask, i;
        unsigned int jflag;
@@ -583,6 +583,11 @@ group_extend_out:
                                 "Online defrag not supported with bigalloc");
                        err = -EOPNOTSUPP;
                        goto mext_out;
+               } else if (IS_DAX(inode)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Online defrag not supported with DAX");
+                       err = -EOPNOTSUPP;
+                       goto mext_out;
                }
 
                err = mnt_want_write_file(filp);
index 61eaf74dca3794b122a9e782e87c568ac99a8a65..4424b7bf8ac64e431a11570e247a1d828634d29e 100644 (file)
@@ -2285,7 +2285,7 @@ static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
        if (group == 0)
                seq_puts(seq, "#group: free  frags first ["
                              " 2^0   2^1   2^2   2^3   2^4   2^5   2^6  "
-                             " 2^7   2^8   2^9   2^10  2^11  2^12  2^13  ]");
+                             " 2^7   2^8   2^9   2^10  2^11  2^12  2^13  ]\n");
 
        i = (sb->s_blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) +
                sizeof(struct ext4_group_info);
index fb6f11709ae62b4d0452352422bb6f3f50660ba3..e032a0423e351cabfd6fe6156cdfc9c53ebff216 100644 (file)
@@ -265,11 +265,12 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
        ext4_lblk_t orig_blk_offset, donor_blk_offset;
        unsigned long blocksize = orig_inode->i_sb->s_blocksize;
        unsigned int tmp_data_size, data_size, replaced_size;
-       int err2, jblocks, retries = 0;
+       int i, err2, jblocks, retries = 0;
        int replaced_count = 0;
        int from = data_offset_in_page << orig_inode->i_blkbits;
        int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits;
        struct super_block *sb = orig_inode->i_sb;
+       struct buffer_head *bh = NULL;
 
        /*
         * It needs twice the amount of ordinary journal buffers because
@@ -380,8 +381,16 @@ data_copy:
        }
        /* Perform all necessary steps similar write_begin()/write_end()
         * but keeping in mind that i_size will not change */
-       *err = __block_write_begin(pagep[0], from, replaced_size,
-                                  ext4_get_block);
+       if (!page_has_buffers(pagep[0]))
+               create_empty_buffers(pagep[0], 1 << orig_inode->i_blkbits, 0);
+       bh = page_buffers(pagep[0]);
+       for (i = 0; i < data_offset_in_page; i++)
+               bh = bh->b_this_page;
+       for (i = 0; i < block_len_in_page; i++) {
+               *err = ext4_get_block(orig_inode, orig_blk_offset + i, bh, 0);
+               if (*err < 0)
+                       break;
+       }
        if (!*err)
                *err = block_commit_write(pagep[0], from, from + replaced_size);
 
index 06574dd77614a3b1c4396d5bb3c017c681209d00..48e4b8907826eca52a1e94e14bdfdb0fd2240c56 100644 (file)
@@ -1558,6 +1558,24 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
        struct ext4_dir_entry_2 *de;
        struct buffer_head *bh;
 
+       if (ext4_encrypted_inode(dir)) {
+               int res = ext4_get_encryption_info(dir);
+
+               /*
+                * This should be a properly defined flag for
+                * dentry->d_flags when we uplift this to the VFS.
+                * d_fsdata is set to (void *) 1 if if the dentry is
+                * created while the directory was encrypted and we
+                * don't have access to the key.
+                */
+              dentry->d_fsdata = NULL;
+              if (ext4_encryption_info(dir))
+                      dentry->d_fsdata = (void *) 1;
+              d_set_d_op(dentry, &ext4_encrypted_d_ops);
+              if (res && res != -ENOKEY)
+                      return ERR_PTR(res);
+       }
+
        if (dentry->d_name.len > EXT4_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
@@ -1585,11 +1603,15 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                        return ERR_PTR(-EFSCORRUPTED);
                }
                if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
-                   (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
-                    S_ISLNK(inode->i_mode)) &&
+                   (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
                    !ext4_is_child_context_consistent_with_parent(dir,
                                                                  inode)) {
+                       int nokey = ext4_encrypted_inode(inode) &&
+                               !ext4_encryption_info(inode);
+
                        iput(inode);
+                       if (nokey)
+                               return ERR_PTR(-ENOKEY);
                        ext4_warning(inode->i_sb,
                                     "Inconsistent encryption contexts: %lu/%lu\n",
                                     (unsigned long) dir->i_ino,
index ad62d7acc31578df85c3b97ac7839295a4454008..34038e3598d59fa2b4bcaf2304d31602e803d5e0 100644 (file)
@@ -198,7 +198,7 @@ static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size)
        if (flex_gd == NULL)
                goto out3;
 
-       if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data))
+       if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_group_data))
                goto out2;
        flex_gd->count = flexbg_size;
 
index 6915c950e6e8aeefb7c6162e7e7410de98f4e309..5c46ed9f3e14087d4fa7bad553eb360b30fb4fd8 100644 (file)
@@ -223,6 +223,9 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi,
 #define WB_FRN_HIST_MAX_SLOTS  (WB_FRN_HIST_THR_SLOTS / 2 + 1)
                                        /* one round can affect upto 5 slots */
 
+static atomic_t isw_nr_in_flight = ATOMIC_INIT(0);
+static struct workqueue_struct *isw_wq;
+
 void __inode_attach_wb(struct inode *inode, struct page *page)
 {
        struct backing_dev_info *bdi = inode_to_bdi(inode);
@@ -424,6 +427,8 @@ skip_switch:
 
        iput(inode);
        kfree(isw);
+
+       atomic_dec(&isw_nr_in_flight);
 }
 
 static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head)
@@ -433,7 +438,7 @@ static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head)
 
        /* needs to grab bh-unsafe locks, bounce to work item */
        INIT_WORK(&isw->work, inode_switch_wbs_work_fn);
-       schedule_work(&isw->work);
+       queue_work(isw_wq, &isw->work);
 }
 
 /**
@@ -469,7 +474,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
 
        /* while holding I_WB_SWITCH, no one else can update the association */
        spin_lock(&inode->i_lock);
-       if (inode->i_state & (I_WB_SWITCH | I_FREEING) ||
+       if (!(inode->i_sb->s_flags & MS_ACTIVE) ||
+           inode->i_state & (I_WB_SWITCH | I_FREEING) ||
            inode_to_wb(inode) == isw->new_wb) {
                spin_unlock(&inode->i_lock);
                goto out_free;
@@ -480,6 +486,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id)
        ihold(inode);
        isw->inode = inode;
 
+       atomic_inc(&isw_nr_in_flight);
+
        /*
         * In addition to synchronizing among switchers, I_WB_SWITCH tells
         * the RCU protected stat update paths to grab the mapping's
@@ -840,6 +848,33 @@ restart:
                wb_put(last_wb);
 }
 
+/**
+ * cgroup_writeback_umount - flush inode wb switches for umount
+ *
+ * This function is called when a super_block is about to be destroyed and
+ * flushes in-flight inode wb switches.  An inode wb switch goes through
+ * RCU and then workqueue, so the two need to be flushed in order to ensure
+ * that all previously scheduled switches are finished.  As wb switches are
+ * rare occurrences and synchronize_rcu() can take a while, perform
+ * flushing iff wb switches are in flight.
+ */
+void cgroup_writeback_umount(void)
+{
+       if (atomic_read(&isw_nr_in_flight)) {
+               synchronize_rcu();
+               flush_workqueue(isw_wq);
+       }
+}
+
+static int __init cgroup_writeback_init(void)
+{
+       isw_wq = alloc_workqueue("inode_switch_wbs", 0, 0);
+       if (!isw_wq)
+               return -ENOMEM;
+       return 0;
+}
+fs_initcall(cgroup_writeback_init);
+
 #else  /* CONFIG_CGROUP_WRITEBACK */
 
 static struct bdi_writeback *
index 506765afa1a3135d1ff9bccc48f06634439fa69e..bb8d67e2740ac70d7c9c87c078429475f9e0b79d 100644 (file)
@@ -376,12 +376,11 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
        struct inode *inode = d_inode(dentry);
        dnode_secno dno;
        int r;
-       int rep = 0;
        int err;
 
        hpfs_lock(dir->i_sb);
        hpfs_adjust_length(name, &len);
-again:
+
        err = -ENOENT;
        de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
        if (!de)
@@ -401,33 +400,9 @@ again:
                hpfs_error(dir->i_sb, "there was error when removing dirent");
                err = -EFSERROR;
                break;
-       case 2:         /* no space for deleting, try to truncate file */
-
+       case 2:         /* no space for deleting */
                err = -ENOSPC;
-               if (rep++)
-                       break;
-
-               dentry_unhash(dentry);
-               if (!d_unhashed(dentry)) {
-                       hpfs_unlock(dir->i_sb);
-                       return -ENOSPC;
-               }
-               if (generic_permission(inode, MAY_WRITE) ||
-                   !S_ISREG(inode->i_mode) ||
-                   get_write_access(inode)) {
-                       d_rehash(dentry);
-               } else {
-                       struct iattr newattrs;
-                       /*pr_info("truncating file before delete.\n");*/
-                       newattrs.ia_size = 0;
-                       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-                       err = notify_change(dentry, &newattrs, NULL);
-                       put_write_access(inode);
-                       if (!err)
-                               goto again;
-               }
-               hpfs_unlock(dir->i_sb);
-               return -ENOSPC;
+               break;
        default:
                drop_nlink(inode);
                err = 0;
index 9f62db3bcc3efcc9cc678ed0d9bc88152f692ff8..69b8b526c1946c455c8b5ad0c8939542d9c2e82d 100644 (file)
@@ -154,6 +154,12 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_rdev = 0;
        inode->dirtied_when = 0;
 
+#ifdef CONFIG_CGROUP_WRITEBACK
+       inode->i_wb_frn_winner = 0;
+       inode->i_wb_frn_avg_time = 0;
+       inode->i_wb_frn_history = 0;
+#endif
+
        if (security_inode_alloc(inode))
                goto out;
        spin_lock_init(&inode->i_lock);
index 3ea36554107fc7740558ac81daa0328c308b2903..8918ac905a3b1face373e3a0ad456c2d3bf6d95b 100644 (file)
@@ -2,10 +2,6 @@
        JFFS2 LOCKING DOCUMENTATION
        ---------------------------
 
-At least theoretically, JFFS2 does not require the Big Kernel Lock
-(BKL), which was always helpfully obtained for it by Linux 2.4 VFS
-code. It has its own locking, as described below.
-
 This document attempts to describe the existing locking rules for
 JFFS2. It is not expected to remain perfectly up to date, but ought to
 be fairly close.
@@ -69,6 +65,7 @@ Ordering constraints:
           any f->sem held.
        2. Never attempt to lock two file mutexes in one thread.
           No ordering rules have been made for doing so.
+       3. Never lock a page cache page with f->sem held.
 
 
        erase_completion_lock spinlock
index 0ae91ad6df2dc916f077495876ec7fe1e47902ed..b288c8ae1236b0f81f271e0fcfcaf5ee246b2933 100644 (file)
@@ -50,7 +50,8 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
 
 
 static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
-                                   struct jffs2_inode_cache *ic)
+                                   struct jffs2_inode_cache *ic,
+                                   int *dir_hardlinks)
 {
        struct jffs2_full_dirent *fd;
 
@@ -69,19 +70,21 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
                        dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
                                  fd->name, fd->ino, ic->ino);
                        jffs2_mark_node_obsolete(c, fd->raw);
+                       /* Clear the ic/raw union so it doesn't cause problems later. */
+                       fd->ic = NULL;
                        continue;
                }
 
+               /* From this point, fd->raw is no longer used so we can set fd->ic */
+               fd->ic = child_ic;
+               child_ic->pino_nlink++;
+               /* If we appear (at this stage) to have hard-linked directories,
+                * set a flag to trigger a scan later */
                if (fd->type == DT_DIR) {
-                       if (child_ic->pino_nlink) {
-                               JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
-                                           fd->name, fd->ino, ic->ino);
-                               /* TODO: What do we do about it? */
-                       } else {
-                               child_ic->pino_nlink = ic->ino;
-                       }
-               } else
-                       child_ic->pino_nlink++;
+                       child_ic->flags |= INO_FLAGS_IS_DIR;
+                       if (child_ic->pino_nlink > 1)
+                               *dir_hardlinks = 1;
+               }
 
                dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
                /* Can't free scan_dents so far. We might need them in pass 2 */
@@ -95,8 +98,7 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
 */
 static int jffs2_build_filesystem(struct jffs2_sb_info *c)
 {
-       int ret;
-       int i;
+       int ret, i, dir_hardlinks = 0;
        struct jffs2_inode_cache *ic;
        struct jffs2_full_dirent *fd;
        struct jffs2_full_dirent *dead_fds = NULL;
@@ -120,7 +122,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        /* Now scan the directory tree, increasing nlink according to every dirent found. */
        for_each_inode(i, c, ic) {
                if (ic->scan_dents) {
-                       jffs2_build_inode_pass1(c, ic);
+                       jffs2_build_inode_pass1(c, ic, &dir_hardlinks);
                        cond_resched();
                }
        }
@@ -156,6 +158,20 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        }
 
        dbg_fsbuild("pass 2a complete\n");
+
+       if (dir_hardlinks) {
+               /* If we detected directory hardlinks earlier, *hopefully*
+                * they are gone now because some of the links were from
+                * dead directories which still had some old dirents lying
+                * around and not yet garbage-collected, but which have
+                * been discarded above. So clear the pino_nlink field
+                * in each directory, so that the final scan below can
+                * print appropriate warnings. */
+               for_each_inode(i, c, ic) {
+                       if (ic->flags & INO_FLAGS_IS_DIR)
+                               ic->pino_nlink = 0;
+               }
+       }
        dbg_fsbuild("freeing temporary data structures\n");
 
        /* Finally, we can scan again and free the dirent structs */
@@ -163,6 +179,33 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
                while(ic->scan_dents) {
                        fd = ic->scan_dents;
                        ic->scan_dents = fd->next;
+                       /* We do use the pino_nlink field to count nlink of
+                        * directories during fs build, so set it to the
+                        * parent ino# now. Now that there's hopefully only
+                        * one. */
+                       if (fd->type == DT_DIR) {
+                               if (!fd->ic) {
+                                       /* We'll have complained about it and marked the coresponding
+                                          raw node obsolete already. Just skip it. */
+                                       continue;
+                               }
+
+                               /* We *have* to have set this in jffs2_build_inode_pass1() */
+                               BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR));
+
+                               /* We clear ic->pino_nlink âˆ€ directories' ic *only* if dir_hardlinks
+                                * is set. Otherwise, we know this should never trigger anyway, so
+                                * we don't do the check. And ic->pino_nlink still contains the nlink
+                                * value (which is 1). */
+                               if (dir_hardlinks && fd->ic->pino_nlink) {
+                                       JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n",
+                                                   fd->name, fd->ino, ic->ino, fd->ic->pino_nlink);
+                                       /* Should we unlink it from its previous parent? */
+                               }
+
+                               /* For directories, ic->pino_nlink holds that parent inode # */
+                               fd->ic->pino_nlink = ic->ino;
+                       }
                        jffs2_free_full_dirent(fd);
                }
                ic->scan_dents = NULL;
@@ -241,11 +284,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
 
                        /* Reduce nlink of the child. If it's now zero, stick it on the
                           dead_fds list to be cleaned up later. Else just free the fd */
-
-                       if (fd->type == DT_DIR)
-                               child_ic->pino_nlink = 0;
-                       else
-                               child_ic->pino_nlink--;
+                       child_ic->pino_nlink--;
 
                        if (!child_ic->pino_nlink) {
                                dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
index c5ac5944bc1bd8ef1362e5911656f3bfb68ea70b..cad86bac345305e5c3231589c63051cba0a2da6c 100644 (file)
@@ -137,39 +137,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
        struct page *pg;
        struct inode *inode = mapping->host;
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
-       struct jffs2_raw_inode ri;
-       uint32_t alloc_len = 0;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
        uint32_t pageofs = index << PAGE_CACHE_SHIFT;
        int ret = 0;
 
-       jffs2_dbg(1, "%s()\n", __func__);
-
-       if (pageofs > inode->i_size) {
-               ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
-                                         ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
-               if (ret)
-                       return ret;
-       }
-
-       mutex_lock(&f->sem);
        pg = grab_cache_page_write_begin(mapping, index, flags);
-       if (!pg) {
-               if (alloc_len)
-                       jffs2_complete_reservation(c);
-               mutex_unlock(&f->sem);
+       if (!pg)
                return -ENOMEM;
-       }
        *pagep = pg;
 
-       if (alloc_len) {
+       jffs2_dbg(1, "%s()\n", __func__);
+
+       if (pageofs > inode->i_size) {
                /* Make new hole frag from old EOF to new page */
+               struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+               struct jffs2_raw_inode ri;
                struct jffs2_full_dnode *fn;
+               uint32_t alloc_len;
 
                jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
                          (unsigned int)inode->i_size, pageofs);
 
+               ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
+                                         ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+               if (ret)
+                       goto out_page;
+
+               mutex_lock(&f->sem);
                memset(&ri, 0, sizeof(ri));
 
                ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -196,6 +190,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
                if (IS_ERR(fn)) {
                        ret = PTR_ERR(fn);
                        jffs2_complete_reservation(c);
+                       mutex_unlock(&f->sem);
                        goto out_page;
                }
                ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -210,10 +205,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
                        jffs2_mark_node_obsolete(c, fn->raw);
                        jffs2_free_full_dnode(fn);
                        jffs2_complete_reservation(c);
+                       mutex_unlock(&f->sem);
                        goto out_page;
                }
                jffs2_complete_reservation(c);
                inode->i_size = pageofs;
+               mutex_unlock(&f->sem);
        }
 
        /*
@@ -222,18 +219,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
         * case of a short-copy.
         */
        if (!PageUptodate(pg)) {
+               mutex_lock(&f->sem);
                ret = jffs2_do_readpage_nolock(inode, pg);
+               mutex_unlock(&f->sem);
                if (ret)
                        goto out_page;
        }
-       mutex_unlock(&f->sem);
        jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
        return ret;
 
 out_page:
        unlock_page(pg);
        page_cache_release(pg);
-       mutex_unlock(&f->sem);
        return ret;
 }
 
index 5a2dec2b064c945aba23acac93dcee2820019d68..95d5880a63ee10fe98ad3520b20890f247e36d0c 100644 (file)
@@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                BUG_ON(start > orig_start);
        }
 
-       /* First, use readpage() to read the appropriate page into the page cache */
-       /* Q: What happens if we actually try to GC the _same_ page for which commit_write()
-        *    triggered garbage collection in the first place?
-        * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the
-        *    page OK. We'll actually write it out again in commit_write, which is a little
-        *    suboptimal, but at least we're correct.
-        */
+       /* The rules state that we must obtain the page lock *before* f->sem, so
+        * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's
+        * actually going to *change* so we're safe; we only allow reading.
+        *
+        * It is important to note that jffs2_write_begin() will ensure that its
+        * page is marked Uptodate before allocating space. That means that if we
+        * end up here trying to GC the *same* page that jffs2_write_begin() is
+        * trying to write out, read_cache_page() will not deadlock. */
+       mutex_unlock(&f->sem);
        pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
+       mutex_lock(&f->sem);
 
        if (IS_ERR(pg_ptr)) {
                pr_warn("read_cache_page() returned error: %ld\n",
index fa35ff79ab358fe79c734f54ff51ebcb21ab9f7f..0637271f377012b51f6684622f3a0c604385d474 100644 (file)
@@ -194,6 +194,7 @@ struct jffs2_inode_cache {
 #define INO_STATE_CLEARING     6       /* In clear_inode() */
 
 #define INO_FLAGS_XATTR_CHECKED        0x01    /* has no duplicate xattr_ref */
+#define INO_FLAGS_IS_DIR       0x02    /* is a directory */
 
 #define RAWNODE_CLASS_INODE_CACHE      0
 #define RAWNODE_CLASS_XATTR_DATUM      1
@@ -249,7 +250,10 @@ struct jffs2_readinode_info
 
 struct jffs2_full_dirent
 {
-       struct jffs2_raw_node_ref *raw;
+       union {
+               struct jffs2_raw_node_ref *raw;
+               struct jffs2_inode_cache *ic; /* Just during part of build */
+       };
        struct jffs2_full_dirent *next;
        uint32_t version;
        uint32_t ino; /* == zero for unlink */
index f624d132e01e6f5488fd0d9af13007b015e1e178..9c590e0f66e9c2189f360bf1b742f54f969713aa 100644 (file)
@@ -1712,6 +1712,11 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link,
                return 0;
        if (!follow)
                return 0;
+       /* make sure that d_is_symlink above matches inode */
+       if (nd->flags & LOOKUP_RCU) {
+               if (read_seqcount_retry(&link->dentry->d_seq, seq))
+                       return -ECHILD;
+       }
        return pick_link(nd, link, inode, seq);
 }
 
@@ -1743,11 +1748,11 @@ static int walk_component(struct nameidata *nd, int flags)
                if (err < 0)
                        return err;
 
-               inode = d_backing_inode(path.dentry);
                seq = 0;        /* we are already out of RCU mode */
                err = -ENOENT;
                if (d_is_negative(path.dentry))
                        goto out_path_put;
+               inode = d_backing_inode(path.dentry);
        }
 
        if (flags & WALK_PUT)
@@ -3192,12 +3197,12 @@ retry_lookup:
                return error;
 
        BUG_ON(nd->flags & LOOKUP_RCU);
-       inode = d_backing_inode(path.dentry);
        seq = 0;        /* out of RCU mode, so the value doesn't matter */
        if (unlikely(d_is_negative(path.dentry))) {
                path_to_nameidata(&path, nd);
                return -ENOENT;
        }
+       inode = d_backing_inode(path.dentry);
 finish_lookup:
        if (nd->depth)
                put_link(nd);
@@ -3206,11 +3211,6 @@ finish_lookup:
        if (unlikely(error))
                return error;
 
-       if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) {
-               path_to_nameidata(&path, nd);
-               return -ELOOP;
-       }
-
        if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) {
                path_to_nameidata(&path, nd);
        } else {
@@ -3229,6 +3229,10 @@ finish_open:
                return error;
        }
        audit_inode(nd->name, nd->path.dentry, 0);
+       if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) {
+               error = -ELOOP;
+               goto out;
+       }
        error = -EISDIR;
        if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
                goto out;
@@ -3273,6 +3277,10 @@ opened:
                        goto exit_fput;
        }
 out:
+       if (unlikely(error > 0)) {
+               WARN_ON(1);
+               error = -EINVAL;
+       }
        if (got_write)
                mnt_drop_write(nd->path.mnt);
        path_put(&save_parent);
index c59a59c37f3dabae1211db9efcb963442c013b36..35ab51c04814d67baecf83d3b3627d66fdd79359 100644 (file)
@@ -476,6 +476,7 @@ static void ext_tree_free_commitdata(struct nfs4_layoutcommit_args *arg,
 
                for (i = 0; i < nr_pages; i++)
                        put_page(arg->layoutupdate_pages[i]);
+               vfree(arg->start_p);
                kfree(arg->layoutupdate_pages);
        } else {
                put_page(arg->layoutupdate_page);
@@ -559,10 +560,15 @@ retry:
 
        if (unlikely(arg->layoutupdate_pages != &arg->layoutupdate_page)) {
                void *p = start_p, *end = p + arg->layoutupdate_len;
+               struct page *page = NULL;
                int i = 0;
 
-               for ( ; p < end; p += PAGE_SIZE)
-                       arg->layoutupdate_pages[i++] = vmalloc_to_page(p);
+               arg->start_p = start_p;
+               for ( ; p < end; p += PAGE_SIZE) {
+                       page = vmalloc_to_page(p);
+                       arg->layoutupdate_pages[i++] = page;
+                       get_page(page);
+               }
        }
 
        dprintk("%s found %zu ranges\n", __func__, count);
index 5bcd92d50e820ab6ccfa5e7789ee01152176b857..0cb1abd535e38469201478ee597e74045e593bc5 100644 (file)
@@ -1215,7 +1215,7 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
                                        hdr->pgio_mirror_idx + 1,
                                        &hdr->pgio_mirror_idx))
                        goto out_eagain;
-               set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+               set_bit(NFS_LAYOUT_RETURN_REQUESTED,
                        &hdr->lseg->pls_layout->plh_flags);
                pnfs_read_resend_pnfs(hdr);
                return task->tk_status;
index 29898a9550fa6f72541cbedc7ac1f0270c5a7c5c..eb370460ce203c11c8461e88115cc0fab9c417fa 100644 (file)
@@ -412,7 +412,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx,
                                         OP_ILLEGAL, GFP_NOIO);
                if (!fail_return) {
                        if (ff_layout_has_available_ds(lseg))
-                               set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+                               set_bit(NFS_LAYOUT_RETURN_REQUESTED,
                                        &lseg->pls_layout->plh_flags);
                        else
                                pnfs_error_mark_layout_for_return(ino, lseg);
index bd25dc7077f72f5a79dfbf81e27f15a75a85dd92..dff83460e5a63ff0b6578f419a793d70720c3997 100644 (file)
 
 #define NFSDBG_FACILITY NFSDBG_PROC
 
-static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
-                               fmode_t fmode)
-{
-       struct nfs_open_context *open;
-       struct nfs_lock_context *lock;
-       int ret;
-
-       open = get_nfs_open_context(nfs_file_open_context(file));
-       lock = nfs_get_lock_context(open);
-       if (IS_ERR(lock)) {
-               put_nfs_open_context(open);
-               return PTR_ERR(lock);
-       }
-
-       ret = nfs4_set_rw_stateid(dst, open, lock, fmode);
-
-       nfs_put_lock_context(lock);
-       put_nfs_open_context(open);
-       return ret;
-}
-
 static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
-                                loff_t offset, loff_t len)
+               struct nfs_lock_context *lock, loff_t offset, loff_t len)
 {
        struct inode *inode = file_inode(filep);
        struct nfs_server *server = NFS_SERVER(inode);
@@ -56,7 +35,8 @@ static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
        msg->rpc_argp = &args;
        msg->rpc_resp = &res;
 
-       status = nfs42_set_rw_stateid(&args.falloc_stateid, filep, FMODE_WRITE);
+       status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
+                       lock, FMODE_WRITE);
        if (status)
                return status;
 
@@ -78,15 +58,26 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
 {
        struct nfs_server *server = NFS_SERVER(file_inode(filep));
        struct nfs4_exception exception = { };
+       struct nfs_lock_context *lock;
        int err;
 
+       lock = nfs_get_lock_context(nfs_file_open_context(filep));
+       if (IS_ERR(lock))
+               return PTR_ERR(lock);
+
+       exception.inode = file_inode(filep);
+       exception.state = lock->open_context->state;
+
        do {
-               err = _nfs42_proc_fallocate(msg, filep, offset, len);
-               if (err == -ENOTSUPP)
-                       return -EOPNOTSUPP;
+               err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
+               if (err == -ENOTSUPP) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
                err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
 
+       nfs_put_lock_context(lock);
        return err;
 }
 
@@ -135,7 +126,8 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
        return err;
 }
 
-static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
+static loff_t _nfs42_proc_llseek(struct file *filep,
+               struct nfs_lock_context *lock, loff_t offset, int whence)
 {
        struct inode *inode = file_inode(filep);
        struct nfs42_seek_args args = {
@@ -156,7 +148,8 @@ static loff_t _nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
        if (!nfs_server_capable(inode, NFS_CAP_SEEK))
                return -ENOTSUPP;
 
-       status = nfs42_set_rw_stateid(&args.sa_stateid, filep, FMODE_READ);
+       status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
+                       lock, FMODE_READ);
        if (status)
                return status;
 
@@ -175,17 +168,28 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
 {
        struct nfs_server *server = NFS_SERVER(file_inode(filep));
        struct nfs4_exception exception = { };
+       struct nfs_lock_context *lock;
        loff_t err;
 
+       lock = nfs_get_lock_context(nfs_file_open_context(filep));
+       if (IS_ERR(lock))
+               return PTR_ERR(lock);
+
+       exception.inode = file_inode(filep);
+       exception.state = lock->open_context->state;
+
        do {
-               err = _nfs42_proc_llseek(filep, offset, whence);
+               err = _nfs42_proc_llseek(filep, lock, offset, whence);
                if (err >= 0)
                        break;
-               if (err == -ENOTSUPP)
-                       return -EOPNOTSUPP;
+               if (err == -ENOTSUPP) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
                err = nfs4_handle_exception(server, err, &exception);
        } while (exception.retry);
 
+       nfs_put_lock_context(lock);
        return err;
 }
 
@@ -298,8 +302,9 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server,
 }
 
 static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
-                            struct file *dst_f, loff_t src_offset,
-                            loff_t dst_offset, loff_t count)
+               struct file *dst_f, struct nfs_lock_context *src_lock,
+               struct nfs_lock_context *dst_lock, loff_t src_offset,
+               loff_t dst_offset, loff_t count)
 {
        struct inode *src_inode = file_inode(src_f);
        struct inode *dst_inode = file_inode(dst_f);
@@ -320,11 +325,13 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
        msg->rpc_argp = &args;
        msg->rpc_resp = &res;
 
-       status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ);
+       status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
+                       src_lock, FMODE_READ);
        if (status)
                return status;
 
-       status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE);
+       status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
+                       dst_lock, FMODE_WRITE);
        if (status)
                return status;
 
@@ -349,22 +356,48 @@ int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
        };
        struct inode *inode = file_inode(src_f);
        struct nfs_server *server = NFS_SERVER(file_inode(src_f));
-       struct nfs4_exception exception = { };
-       int err;
+       struct nfs_lock_context *src_lock;
+       struct nfs_lock_context *dst_lock;
+       struct nfs4_exception src_exception = { };
+       struct nfs4_exception dst_exception = { };
+       int err, err2;
 
        if (!nfs_server_capable(inode, NFS_CAP_CLONE))
                return -EOPNOTSUPP;
 
+       src_lock = nfs_get_lock_context(nfs_file_open_context(src_f));
+       if (IS_ERR(src_lock))
+               return PTR_ERR(src_lock);
+
+       src_exception.inode = file_inode(src_f);
+       src_exception.state = src_lock->open_context->state;
+
+       dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f));
+       if (IS_ERR(dst_lock)) {
+               err = PTR_ERR(dst_lock);
+               goto out_put_src_lock;
+       }
+
+       dst_exception.inode = file_inode(dst_f);
+       dst_exception.state = dst_lock->open_context->state;
+
        do {
-               err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset,
-                                       dst_offset, count);
+               err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
+                                       src_offset, dst_offset, count);
                if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
                        NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
-                       return -EOPNOTSUPP;
+                       err = -EOPNOTSUPP;
+                       break;
                }
-               err = nfs4_handle_exception(server, err, &exception);
-       } while (exception.retry);
 
-       return err;
+               err2 = nfs4_handle_exception(server, err, &src_exception);
+               err = nfs4_handle_exception(server, err, &dst_exception);
+               if (!err)
+                       err = err2;
+       } while (src_exception.retry || dst_exception.retry);
 
+       nfs_put_lock_context(dst_lock);
+out_put_src_lock:
+       nfs_put_lock_context(src_lock);
+       return err;
 }
index 4bfc33ad05637f58f9f0b675f058fd90085d4271..14881594dd07b9944a494d388722f4acf4b5457a 100644 (file)
@@ -2466,9 +2466,9 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                dentry = d_add_unique(dentry, igrab(state->inode));
                if (dentry == NULL) {
                        dentry = opendata->dentry;
-               } else if (dentry != ctx->dentry) {
+               } else {
                        dput(ctx->dentry);
-                       ctx->dentry = dget(dentry);
+                       ctx->dentry = dentry;
                }
                nfs_set_verifier(dentry,
                                nfs_save_change_attribute(d_inode(opendata->dir)));
index a3592cc34a20b76341c9c9b9af3378bdddebd477..2fa483e6dbe2e4a0e4333bf2d76cfd861073232b 100644 (file)
@@ -52,9 +52,7 @@ static DEFINE_SPINLOCK(pnfs_spinlock);
  */
 static LIST_HEAD(pnfs_modules_tbl);
 
-static int
-pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
-                      enum pnfs_iomode iomode, bool sync);
+static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo);
 
 /* Return the registered pnfs layout driver module matching given id */
 static struct pnfs_layoutdriver_type *
@@ -243,6 +241,8 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
 {
        struct inode *inode = lo->plh_inode;
 
+       pnfs_layoutreturn_before_put_layout_hdr(lo);
+
        if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
                if (!list_empty(&lo->plh_segs))
                        WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
@@ -252,6 +252,27 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
        }
 }
 
+/*
+ * Mark a pnfs_layout_hdr and all associated layout segments as invalid
+ *
+ * In order to continue using the pnfs_layout_hdr, a full recovery
+ * is required.
+ * Note that caller must hold inode->i_lock.
+ */
+static int
+pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo,
+               struct list_head *lseg_list)
+{
+       struct pnfs_layout_range range = {
+               .iomode = IOMODE_ANY,
+               .offset = 0,
+               .length = NFS4_MAX_UINT64,
+       };
+
+       set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags);
+       return pnfs_mark_matching_lsegs_invalid(lo, lseg_list, &range);
+}
+
 static int
 pnfs_iomode_to_fail_bit(u32 iomode)
 {
@@ -345,58 +366,6 @@ pnfs_layout_remove_lseg(struct pnfs_layout_hdr *lo,
        rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
 }
 
-/* Return true if layoutreturn is needed */
-static bool
-pnfs_layout_need_return(struct pnfs_layout_hdr *lo,
-                       struct pnfs_layout_segment *lseg)
-{
-       struct pnfs_layout_segment *s;
-
-       if (!test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
-               return false;
-
-       list_for_each_entry(s, &lo->plh_segs, pls_list)
-               if (s != lseg && test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
-                       return false;
-
-       return true;
-}
-
-static bool
-pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
-{
-       if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
-               return false;
-       lo->plh_return_iomode = 0;
-       pnfs_get_layout_hdr(lo);
-       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
-       return true;
-}
-
-static void pnfs_layoutreturn_before_put_lseg(struct pnfs_layout_segment *lseg,
-               struct pnfs_layout_hdr *lo, struct inode *inode)
-{
-       lo = lseg->pls_layout;
-       inode = lo->plh_inode;
-
-       spin_lock(&inode->i_lock);
-       if (pnfs_layout_need_return(lo, lseg)) {
-               nfs4_stateid stateid;
-               enum pnfs_iomode iomode;
-               bool send;
-
-               nfs4_stateid_copy(&stateid, &lo->plh_stateid);
-               iomode = lo->plh_return_iomode;
-               send = pnfs_prepare_layoutreturn(lo);
-               spin_unlock(&inode->i_lock);
-               if (send) {
-                       /* Send an async layoutreturn so we dont deadlock */
-                       pnfs_send_layoutreturn(lo, &stateid, iomode, false);
-               }
-       } else
-               spin_unlock(&inode->i_lock);
-}
-
 void
 pnfs_put_lseg(struct pnfs_layout_segment *lseg)
 {
@@ -410,15 +379,8 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg)
                atomic_read(&lseg->pls_refcount),
                test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
 
-       /* Handle the case where refcount != 1 */
-       if (atomic_add_unless(&lseg->pls_refcount, -1, 1))
-               return;
-
        lo = lseg->pls_layout;
        inode = lo->plh_inode;
-       /* Do we need a layoutreturn? */
-       if (test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags))
-               pnfs_layoutreturn_before_put_lseg(lseg, lo, inode);
 
        if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) {
                if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
@@ -613,9 +575,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
        spin_lock(&nfsi->vfs_inode.i_lock);
        lo = nfsi->layout;
        if (lo) {
-               lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
-               pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
                pnfs_get_layout_hdr(lo);
+               pnfs_mark_layout_stateid_invalid(lo, &tmp_list);
                pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RO_FAILED);
                pnfs_layout_clear_fail_bit(lo, NFS_LAYOUT_RW_FAILED);
                spin_unlock(&nfsi->vfs_inode.i_lock);
@@ -676,11 +637,6 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list,
 {
        struct pnfs_layout_hdr *lo;
        struct inode *inode;
-       struct pnfs_layout_range range = {
-               .iomode = IOMODE_ANY,
-               .offset = 0,
-               .length = NFS4_MAX_UINT64,
-       };
        LIST_HEAD(lseg_list);
        int ret = 0;
 
@@ -695,11 +651,11 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list,
 
                spin_lock(&inode->i_lock);
                list_del_init(&lo->plh_bulk_destroy);
-               lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */
-               if (is_bulk_recall)
-                       set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
-               if (pnfs_mark_matching_lsegs_invalid(lo, &lseg_list, &range))
+               if (pnfs_mark_layout_stateid_invalid(lo, &lseg_list)) {
+                       if (is_bulk_recall)
+                               set_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags);
                        ret = -EAGAIN;
+               }
                spin_unlock(&inode->i_lock);
                pnfs_free_lseg_list(&lseg_list);
                /* Free all lsegs that are attached to commit buckets */
@@ -937,6 +893,17 @@ void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo)
        rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
 }
 
+static bool
+pnfs_prepare_layoutreturn(struct pnfs_layout_hdr *lo)
+{
+       if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
+               return false;
+       lo->plh_return_iomode = 0;
+       pnfs_get_layout_hdr(lo);
+       clear_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
+       return true;
+}
+
 static int
 pnfs_send_layoutreturn(struct pnfs_layout_hdr *lo, const nfs4_stateid *stateid,
                       enum pnfs_iomode iomode, bool sync)
@@ -971,6 +938,48 @@ out:
        return status;
 }
 
+/* Return true if layoutreturn is needed */
+static bool
+pnfs_layout_need_return(struct pnfs_layout_hdr *lo)
+{
+       struct pnfs_layout_segment *s;
+
+       if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
+               return false;
+
+       /* Defer layoutreturn until all lsegs are done */
+       list_for_each_entry(s, &lo->plh_segs, pls_list) {
+               if (test_bit(NFS_LSEG_LAYOUTRETURN, &s->pls_flags))
+                       return false;
+       }
+
+       return true;
+}
+
+static void pnfs_layoutreturn_before_put_layout_hdr(struct pnfs_layout_hdr *lo)
+{
+       struct inode *inode= lo->plh_inode;
+
+       if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags))
+               return;
+       spin_lock(&inode->i_lock);
+       if (pnfs_layout_need_return(lo)) {
+               nfs4_stateid stateid;
+               enum pnfs_iomode iomode;
+               bool send;
+
+               nfs4_stateid_copy(&stateid, &lo->plh_stateid);
+               iomode = lo->plh_return_iomode;
+               send = pnfs_prepare_layoutreturn(lo);
+               spin_unlock(&inode->i_lock);
+               if (send) {
+                       /* Send an async layoutreturn so we dont deadlock */
+                       pnfs_send_layoutreturn(lo, &stateid, iomode, false);
+               }
+       } else
+               spin_unlock(&inode->i_lock);
+}
+
 /*
  * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
  * when the layout segment list is empty.
@@ -1091,7 +1100,7 @@ bool pnfs_roc(struct inode *ino)
 
        nfs4_stateid_copy(&stateid, &lo->plh_stateid);
        /* always send layoutreturn if being marked so */
-       if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
+       if (test_and_clear_bit(NFS_LAYOUT_RETURN_REQUESTED,
                                   &lo->plh_flags))
                layoutreturn = pnfs_prepare_layoutreturn(lo);
 
@@ -1744,8 +1753,19 @@ pnfs_set_plh_return_iomode(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode)
        if (lo->plh_return_iomode != 0)
                iomode = IOMODE_ANY;
        lo->plh_return_iomode = iomode;
+       set_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags);
 }
 
+/**
+ * pnfs_mark_matching_lsegs_return - Free or return matching layout segments
+ * @lo: pointer to layout header
+ * @tmp_list: list header to be used with pnfs_free_lseg_list()
+ * @return_range: describe layout segment ranges to be returned
+ *
+ * This function is mainly intended for use by layoutrecall. It attempts
+ * to free the layout segment immediately, or else to mark it for return
+ * as soon as its reference count drops to zero.
+ */
 int
 pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
                                struct list_head *tmp_list,
@@ -1768,12 +1788,11 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo,
                                lseg, lseg->pls_range.iomode,
                                lseg->pls_range.offset,
                                lseg->pls_range.length);
+                       if (mark_lseg_invalid(lseg, tmp_list))
+                               continue;
+                       remaining++;
                        set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags);
                        pnfs_set_plh_return_iomode(lo, return_range->iomode);
-                       if (!mark_lseg_invalid(lseg, tmp_list))
-                               remaining++;
-                       set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE,
-                                       &lo->plh_flags);
                }
        return remaining;
 }
index 9f4e2a47f4aa4ff41a590178dde2ddf160ae244f..1ac1db5f6dadb6508cf8658a53385add279eb9fa 100644 (file)
@@ -94,8 +94,8 @@ enum {
        NFS_LAYOUT_RO_FAILED = 0,       /* get ro layout failed stop trying */
        NFS_LAYOUT_RW_FAILED,           /* get rw layout failed stop trying */
        NFS_LAYOUT_BULK_RECALL,         /* bulk recall affecting layout */
-       NFS_LAYOUT_RETURN,              /* Return this layout ASAP */
-       NFS_LAYOUT_RETURN_BEFORE_CLOSE, /* Return this layout before close */
+       NFS_LAYOUT_RETURN,              /* layoutreturn in progress */
+       NFS_LAYOUT_RETURN_REQUESTED,    /* Return this layout ASAP */
        NFS_LAYOUT_INVALID_STID,        /* layout stateid id is invalid */
        NFS_LAYOUT_FIRST_LAYOUTGET,     /* Serialize first layoutget */
 };
index cfcbf114676ed9e5ee439563acc0a407e3541522..7115c5d7d373c63df1512eba5ea90351ea5c7c45 100644 (file)
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
 
+#define FSNOTIFY_REAPER_DELAY  (1)     /* 1 jiffy */
+
 struct srcu_struct fsnotify_mark_srcu;
+static DEFINE_SPINLOCK(destroy_lock);
+static LIST_HEAD(destroy_list);
+
+static void fsnotify_mark_destroy(struct work_struct *work);
+static DECLARE_DELAYED_WORK(reaper_work, fsnotify_mark_destroy);
 
 void fsnotify_get_mark(struct fsnotify_mark *mark)
 {
@@ -165,19 +172,10 @@ void fsnotify_detach_mark(struct fsnotify_mark *mark)
        atomic_dec(&group->num_marks);
 }
 
-static void
-fsnotify_mark_free_rcu(struct rcu_head *rcu)
-{
-       struct fsnotify_mark    *mark;
-
-       mark = container_of(rcu, struct fsnotify_mark, g_rcu);
-       fsnotify_put_mark(mark);
-}
-
 /*
- * Free fsnotify mark. The freeing is actually happening from a call_srcu
- * callback. Caller must have a reference to the mark or be protected by
- * fsnotify_mark_srcu.
+ * Free fsnotify mark. The freeing is actually happening from a kthread which
+ * first waits for srcu period end. Caller must have a reference to the mark
+ * or be protected by fsnotify_mark_srcu.
  */
 void fsnotify_free_mark(struct fsnotify_mark *mark)
 {
@@ -192,7 +190,11 @@ void fsnotify_free_mark(struct fsnotify_mark *mark)
        mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
        spin_unlock(&mark->lock);
 
-       call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
+       spin_lock(&destroy_lock);
+       list_add(&mark->g_list, &destroy_list);
+       spin_unlock(&destroy_lock);
+       queue_delayed_work(system_unbound_wq, &reaper_work,
+                               FSNOTIFY_REAPER_DELAY);
 
        /*
         * Some groups like to know that marks are being freed.  This is a
@@ -388,7 +390,12 @@ err:
 
        spin_unlock(&mark->lock);
 
-       call_srcu(&fsnotify_mark_srcu, &mark->g_rcu, fsnotify_mark_free_rcu);
+       spin_lock(&destroy_lock);
+       list_add(&mark->g_list, &destroy_list);
+       spin_unlock(&destroy_lock);
+       queue_delayed_work(system_unbound_wq, &reaper_work,
+                               FSNOTIFY_REAPER_DELAY);
+
        return ret;
 }
 
@@ -491,3 +498,21 @@ void fsnotify_init_mark(struct fsnotify_mark *mark,
        atomic_set(&mark->refcnt, 1);
        mark->free_mark = free_mark;
 }
+
+static void fsnotify_mark_destroy(struct work_struct *work)
+{
+       struct fsnotify_mark *mark, *next;
+       struct list_head private_destroy_list;
+
+       spin_lock(&destroy_lock);
+       /* exchange the list head */
+       list_replace_init(&destroy_list, &private_destroy_list);
+       spin_unlock(&destroy_lock);
+
+       synchronize_srcu(&fsnotify_mark_srcu);
+
+       list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) {
+               list_del_init(&mark->g_list);
+               fsnotify_put_mark(mark);
+       }
+}
index 794fd1587f34a3bc210d60770525a02f3cd59aba..cda0361e95a403e887d912174ec296aa4cbb6e4d 100644 (file)
@@ -956,6 +956,7 @@ clean_orphan:
                tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh,
                                update_isize, end);
                if (tmp_ret < 0) {
+                       ocfs2_inode_unlock(inode, 1);
                        ret = tmp_ret;
                        mlog_errno(ret);
                        brelse(di_bh);
index a3cc6d2fc896cea05a8605dcc84e09b7840a5e1a..a76b9ea7722e6d7d00d8c0c58217a4a0387f0ff0 100644 (file)
@@ -1254,15 +1254,15 @@ static const struct file_operations o2hb_debug_fops = {
 
 void o2hb_exit(void)
 {
-       kfree(o2hb_db_livenodes);
-       kfree(o2hb_db_liveregions);
-       kfree(o2hb_db_quorumregions);
-       kfree(o2hb_db_failedregions);
        debugfs_remove(o2hb_debug_failedregions);
        debugfs_remove(o2hb_debug_quorumregions);
        debugfs_remove(o2hb_debug_liveregions);
        debugfs_remove(o2hb_debug_livenodes);
        debugfs_remove(o2hb_debug_dir);
+       kfree(o2hb_db_livenodes);
+       kfree(o2hb_db_liveregions);
+       kfree(o2hb_db_quorumregions);
+       kfree(o2hb_db_failedregions);
 }
 
 static struct dentry *o2hb_debug_create(const char *name, struct dentry *dir,
@@ -1438,13 +1438,15 @@ static void o2hb_region_release(struct config_item *item)
 
        kfree(reg->hr_slots);
 
-       kfree(reg->hr_db_regnum);
-       kfree(reg->hr_db_livenodes);
        debugfs_remove(reg->hr_debug_livenodes);
        debugfs_remove(reg->hr_debug_regnum);
        debugfs_remove(reg->hr_debug_elapsed_time);
        debugfs_remove(reg->hr_debug_pinned);
        debugfs_remove(reg->hr_debug_dir);
+       kfree(reg->hr_db_livenodes);
+       kfree(reg->hr_db_regnum);
+       kfree(reg->hr_debug_elapsed_time);
+       kfree(reg->hr_debug_pinned);
 
        spin_lock(&o2hb_live_lock);
        list_del(&reg->hr_all_item);
index c5bdf02c213bd7ad5c086331a1ea8194bde40578..b94a425f0175fa84818d78742659c42293d96dba 100644 (file)
@@ -2367,6 +2367,8 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
                                                break;
                                        }
                                }
+                               dlm_lockres_clear_refmap_bit(dlm, res,
+                                               dead_node);
                                spin_unlock(&res->spinlock);
                                continue;
                        }
index ed95272d57a61af3f26a58c71cf789d3c94e28ce..52f6de5d40a9211baa29a39fc2a178598a86a92f 100644 (file)
@@ -618,7 +618,8 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
         * sole user of this dentry.  Too tricky...  Just unhash for
         * now.
         */
-       d_drop(dentry);
+       if (!err)
+               d_drop(dentry);
        inode_unlock(dir);
 
        return err;
@@ -903,6 +904,13 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
        if (!overwrite && new_is_dir && !old_opaque && new_opaque)
                ovl_remove_opaque(newdentry);
 
+       /*
+        * Old dentry now lives in different location. Dentries in
+        * lowerstack are stale. We cannot drop them here because
+        * access to them is lockless. This could be only pure upper
+        * or opaque directory - numlower is zero. Or upper non-dir
+        * entry - its pureness is tracked by flag opaque.
+        */
        if (old_opaque != new_opaque) {
                ovl_dentry_set_opaque(old, new_opaque);
                if (!overwrite)
index 49e204560655a8f1737a2a03a38b7a88604a5a4c..a4ff5d0d7db91605880b4eb350ea37aa397c9c9d 100644 (file)
@@ -65,6 +65,8 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
 
                inode_lock(upperdentry->d_inode);
                err = notify_change(upperdentry, attr, NULL);
+               if (!err)
+                       ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
                inode_unlock(upperdentry->d_inode);
        }
        ovl_drop_write(dentry);
index 8d826bd56b26b10d641d7ce1f7a47b747851fac9..619ad4b016d209adcb2b6649d6f654049c860b07 100644 (file)
@@ -76,12 +76,14 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry)
        if (oe->__upperdentry) {
                type = __OVL_PATH_UPPER;
 
-               if (oe->numlower) {
-                       if (S_ISDIR(dentry->d_inode->i_mode))
-                               type |= __OVL_PATH_MERGE;
-               } else if (!oe->opaque) {
+               /*
+                * Non-dir dentry can hold lower dentry from previous
+                * location. Its purity depends only on opaque flag.
+                */
+               if (oe->numlower && S_ISDIR(dentry->d_inode->i_mode))
+                       type |= __OVL_PATH_MERGE;
+               else if (!oe->opaque)
                        type |= __OVL_PATH_PURE;
-               }
        } else {
                if (oe->numlower > 1)
                        type |= __OVL_PATH_MERGE;
@@ -341,6 +343,7 @@ static const struct dentry_operations ovl_dentry_operations = {
 
 static const struct dentry_operations ovl_reval_dentry_operations = {
        .d_release = ovl_dentry_release,
+       .d_select_inode = ovl_d_select_inode,
        .d_revalidate = ovl_dentry_revalidate,
        .d_weak_revalidate = ovl_dentry_weak_revalidate,
 };
index 6367e1e435c64144a1d9adb94e9c1cfd1f157dfe..c524fdddc7fb1f601d6d06ddb46d0affcca89c08 100644 (file)
@@ -202,6 +202,11 @@ static struct mount *last_dest, *last_source, *dest_master;
 static struct mountpoint *mp;
 static struct hlist_head *list;
 
+static inline bool peers(struct mount *m1, struct mount *m2)
+{
+       return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id;
+}
+
 static int propagate_one(struct mount *m)
 {
        struct mount *child;
@@ -212,7 +217,7 @@ static int propagate_one(struct mount *m)
        /* skip if mountpoint isn't covered by it */
        if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
                return 0;
-       if (m->mnt_group_id == last_dest->mnt_group_id) {
+       if (peers(m, last_dest)) {
                type = CL_MAKE_SHARED;
        } else {
                struct mount *n, *p;
@@ -223,7 +228,7 @@ static int propagate_one(struct mount *m)
                                        last_source = last_source->mnt_master;
                                        last_dest = last_source->mnt_parent;
                                }
-                               if (n->mnt_group_id != last_dest->mnt_group_id) {
+                               if (!peers(n, last_dest)) {
                                        last_source = last_source->mnt_master;
                                        last_dest = last_source->mnt_parent;
                                }
index 85d16c67c33eaa8b7a5ac65e38ec465814916619..fa95ab2d36740803e06da898a4851db317b86a9e 100644 (file)
@@ -259,23 +259,29 @@ static int do_maps_open(struct inode *inode, struct file *file,
                                sizeof(struct proc_maps_private));
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-                               struct vm_area_struct *vma, bool is_pid)
+/*
+ * Indicate if the VMA is a stack for the given task; for
+ * /proc/PID/maps that is the stack of the main task.
+ */
+static int is_stack(struct proc_maps_private *priv,
+                   struct vm_area_struct *vma, int is_pid)
 {
-       struct inode *inode = priv->inode;
-       struct task_struct *task;
-       pid_t ret = 0;
+       int stack = 0;
+
+       if (is_pid) {
+               stack = vma->vm_start <= vma->vm_mm->start_stack &&
+                       vma->vm_end >= vma->vm_mm->start_stack;
+       } else {
+               struct inode *inode = priv->inode;
+               struct task_struct *task;
 
-       rcu_read_lock();
-       task = pid_task(proc_pid(inode), PIDTYPE_PID);
-       if (task) {
-               task = task_of_stack(task, vma, is_pid);
+               rcu_read_lock();
+               task = pid_task(proc_pid(inode), PIDTYPE_PID);
                if (task)
-                       ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
+                       stack = vma_is_stack_for_task(vma, task);
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
-
-       return ret;
+       return stack;
 }
 
 static void
@@ -335,8 +341,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
 
        name = arch_vma_name(vma);
        if (!name) {
-               pid_t tid;
-
                if (!mm) {
                        name = "[vdso]";
                        goto done;
@@ -348,21 +352,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
                        goto done;
                }
 
-               tid = pid_of_stack(priv, vma, is_pid);
-               if (tid != 0) {
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack)) {
-                               name = "[stack]";
-                       } else {
-                               /* Thread stack in /proc/PID/maps */
-                               seq_pad(m, ' ');
-                               seq_printf(m, "[stack:%d]", tid);
-                       }
-               }
+               if (is_stack(priv, vma, is_pid))
+                       name = "[stack]";
        }
 
 done:
@@ -1552,18 +1543,19 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
 static int gather_hugetlb_stats(pte_t *pte, unsigned long hmask,
                unsigned long addr, unsigned long end, struct mm_walk *walk)
 {
+       pte_t huge_pte = huge_ptep_get(pte);
        struct numa_maps *md;
        struct page *page;
 
-       if (!pte_present(*pte))
+       if (!pte_present(huge_pte))
                return 0;
 
-       page = pte_page(*pte);
+       page = pte_page(huge_pte);
        if (!page)
                return 0;
 
        md = walk->private;
-       gather_stats(page, md, pte_dirty(*pte), 1);
+       gather_stats(page, md, pte_dirty(huge_pte), 1);
        return 0;
 }
 
@@ -1617,19 +1609,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
                seq_file_path(m, file, "\n\t= ");
        } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
                seq_puts(m, " heap");
-       } else {
-               pid_t tid = pid_of_stack(proc_priv, vma, is_pid);
-               if (tid != 0) {
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack))
-                               seq_puts(m, " stack");
-                       else
-                               seq_printf(m, " stack:%d", tid);
-               }
+       } else if (is_stack(proc_priv, vma, is_pid)) {
+               seq_puts(m, " stack");
        }
 
        if (is_vm_hugetlb_page(vma))
index e0d64c92e4f6576c38a8a4a7cc9b8d13a2b3362e..faacb0c0d857602111bfc04f2e374c451059c358 100644 (file)
@@ -123,23 +123,26 @@ unsigned long task_statm(struct mm_struct *mm,
        return size;
 }
 
-static pid_t pid_of_stack(struct proc_maps_private *priv,
-                               struct vm_area_struct *vma, bool is_pid)
+static int is_stack(struct proc_maps_private *priv,
+                   struct vm_area_struct *vma, int is_pid)
 {
-       struct inode *inode = priv->inode;
-       struct task_struct *task;
-       pid_t ret = 0;
-
-       rcu_read_lock();
-       task = pid_task(proc_pid(inode), PIDTYPE_PID);
-       if (task) {
-               task = task_of_stack(task, vma, is_pid);
+       struct mm_struct *mm = vma->vm_mm;
+       int stack = 0;
+
+       if (is_pid) {
+               stack = vma->vm_start <= mm->start_stack &&
+                       vma->vm_end >= mm->start_stack;
+       } else {
+               struct inode *inode = priv->inode;
+               struct task_struct *task;
+
+               rcu_read_lock();
+               task = pid_task(proc_pid(inode), PIDTYPE_PID);
                if (task)
-                       ret = task_pid_nr_ns(task, inode->i_sb->s_fs_info);
+                       stack = vma_is_stack_for_task(vma, task);
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
-
-       return ret;
+       return stack;
 }
 
 /*
@@ -181,21 +184,9 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma,
        if (file) {
                seq_pad(m, ' ');
                seq_file_path(m, file, "");
-       } else if (mm) {
-               pid_t tid = pid_of_stack(priv, vma, is_pid);
-
-               if (tid != 0) {
-                       seq_pad(m, ' ');
-                       /*
-                        * Thread stack in /proc/PID/task/TID/maps or
-                        * the main process stack.
-                        */
-                       if (!is_pid || (vma->vm_start <= mm->start_stack &&
-                           vma->vm_end >= mm->start_stack))
-                               seq_printf(m, "[stack]");
-                       else
-                               seq_printf(m, "[stack:%d]", tid);
-               }
+       } else if (mm && is_stack(priv, vma, is_pid)) {
+               seq_pad(m, ' ');
+               seq_printf(m, "[stack]");
        }
 
        seq_putc(m, '\n');
index 324ec271cc4e64868c34e3ff2f28ac2c0542475e..dadf24e5c95bb7004d105f0773430576bfc57cf5 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/splice.h>
 #include <linux/compat.h>
 #include <linux/mount.h>
+#include <linux/fs.h>
 #include "internal.h"
 
 #include <asm/uaccess.h>
@@ -183,7 +184,7 @@ loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
        switch (whence) {
        case SEEK_SET: case SEEK_CUR:
                return generic_file_llseek_size(file, offset, whence,
-                                               ~0ULL, 0);
+                                               OFFSET_MAX, 0);
        default:
                return -EINVAL;
        }
@@ -1532,10 +1533,12 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
 
        if (!(file_in->f_mode & FMODE_READ) ||
            !(file_out->f_mode & FMODE_WRITE) ||
-           (file_out->f_flags & O_APPEND) ||
-           !file_in->f_op->clone_file_range)
+           (file_out->f_flags & O_APPEND))
                return -EBADF;
 
+       if (!file_in->f_op->clone_file_range)
+               return -EOPNOTSUPP;
+
        ret = clone_verify_area(file_in, pos_in, len, false);
        if (ret)
                return ret;
index 1182af8fd5ff3ede7459305440d50178821c061b..74914b1bae70ff09d451450cb596fb3b5639d969 100644 (file)
@@ -415,6 +415,7 @@ void generic_shutdown_super(struct super_block *sb)
                sb->s_flags &= ~MS_ACTIVE;
 
                fsnotify_unmount_inodes(sb);
+               cgroup_writeback_umount();
 
                evict_inodes(sb);
 
index 50311703135bc8c699bcc3d26d0b9aa24b5277f3..66cdb44616d5a0ba79a04f60de5fd835805b6e56 100644 (file)
@@ -286,6 +286,12 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address,
        if (unlikely(ACCESS_ONCE(ctx->released)))
                goto out;
 
+       /*
+        * We don't do userfault handling for the final child pid update.
+        */
+       if (current->flags & PF_EXITING)
+               goto out;
+
        /*
         * Check that we can return VM_FAULT_RETRY.
         *
index 07d0e47f6a7f1968782b2b31be478a6dd3851656..4861322e28e8da2154f46b7b92cbeda576ee1438 100644 (file)
@@ -940,7 +940,7 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
        bool trusted = capable(CAP_SYS_ADMIN);
        struct simple_xattr *xattr;
        ssize_t remaining_size = size;
-       int err;
+       int err = 0;
 
 #ifdef CONFIG_FS_POSIX_ACL
        if (inode->i_acl) {
@@ -965,11 +965,11 @@ ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
 
                err = xattr_list_one(&buffer, &remaining_size, xattr->name);
                if (err)
-                       return err;
+                       break;
        }
        spin_unlock(&xattrs->lock);
 
-       return size - remaining_size;
+       return err ? err : size - remaining_size;
 }
 
 /*
index 379c089fb0514a5a34934b51b790181567a3384f..a9ebabfe7587bf5abbc427e1603fcf012e5ac63c 100644 (file)
@@ -55,7 +55,7 @@ xfs_count_page_state(
        } while ((bh = bh->b_this_page) != head);
 }
 
-STATIC struct block_device *
+struct block_device *
 xfs_find_bdev_for_inode(
        struct inode            *inode)
 {
@@ -1208,6 +1208,10 @@ xfs_vm_writepages(
        struct writeback_control *wbc)
 {
        xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED);
+       if (dax_mapping(mapping))
+               return dax_writeback_mapping_range(mapping,
+                               xfs_find_bdev_for_inode(mapping->host), wbc);
+
        return generic_writepages(mapping, wbc);
 }
 
index f6ffc9ae5cebeae7ebf8c2cc7c3598c07c4c68f5..a4343c63fb38c60336abbaf8741a75c2a9298a4d 100644 (file)
@@ -62,5 +62,6 @@ int   xfs_get_blocks_dax_fault(struct inode *inode, sector_t offset,
                                 struct buffer_head *map_bh, int create);
 
 extern void xfs_count_page_state(struct page *, int *, int *);
+extern struct block_device *xfs_find_bdev_for_inode(struct inode *);
 
 #endif /* __XFS_AOPS_H__ */
index 45ec9e40150c3dc44bc2268c274472f108ad188b..6c876012b2e53246bf38ca3af8dd2d23861151fe 100644 (file)
@@ -75,7 +75,8 @@ xfs_zero_extent(
        ssize_t         size = XFS_FSB_TO_B(mp, count_fsb);
 
        if (IS_DAX(VFS_I(ip)))
-               return dax_clear_blocks(VFS_I(ip), block, size);
+               return dax_clear_sectors(xfs_find_bdev_for_inode(VFS_I(ip)),
+                               sector, size);
 
        /*
         * let the block layer decide on the fastest method of
index da37beb76f6e67faf90a658d55f49a06c6fc4152..594f7e63b432427fd5b6448afa0a75eb0b71d558 100644 (file)
@@ -4491,7 +4491,7 @@ xlog_recover_process(
         * know precisely what failed.
         */
        if (pass == XLOG_RECOVER_CRCPASS) {
-               if (rhead->h_crc && crc != le32_to_cpu(rhead->h_crc))
+               if (rhead->h_crc && crc != rhead->h_crc)
                        return -EFSBADCRC;
                return 0;
        }
@@ -4502,7 +4502,7 @@ xlog_recover_process(
         * zero CRC check prevents warnings from being emitted when upgrading
         * the kernel from one that does not add CRCs by default.
         */
-       if (crc != le32_to_cpu(rhead->h_crc)) {
+       if (crc != rhead->h_crc) {
                if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
                        xfs_alert(log->l_mp,
                "log record CRC mismatch: found 0x%x, expected 0x%x.",
index 717a29810473894aaf2f22e6e487f84087628df5..dad8af3ebeb5405c144db72cea488d7f5ea5fd39 100644 (file)
@@ -133,6 +133,5 @@ extern int acpi_get_psd_map(struct cpudata **);
 /* Methods to interact with the PCC mailbox controller. */
 extern struct mbox_chan *
        pcc_mbox_request_channel(struct mbox_client *, unsigned int);
-extern int mbox_send_message(struct mbox_chan *chan, void *mssg);
 
 #endif /* _CPPC_ACPI_H*/
index 0419485891f2a8eb6125f154f52d7b16c5fb05b4..0f1c6f315cdc5294ca63bac49efbf69a5dfee805 100644 (file)
@@ -75,7 +75,7 @@ typedef u64 __nocast cputime64_t;
  */
 static inline cputime_t timespec_to_cputime(const struct timespec *val)
 {
-       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
+       u64 ret = (u64)val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
        return (__force cputime_t) ret;
 }
 static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
@@ -91,7 +91,8 @@ static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
  */
 static inline cputime_t timeval_to_cputime(const struct timeval *val)
 {
-       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC;
+       u64 ret = (u64)val->tv_sec * NSEC_PER_SEC +
+                       val->tv_usec * NSEC_PER_USEC;
        return (__force cputime_t) ret;
 }
 static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)
index 0b3c0d39ef753053bb26c1b9fb4979e706240a58..c370b261c72004dcafa3dd036920b7b5fe3d01a2 100644 (file)
@@ -239,6 +239,14 @@ extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                            pmd_t *pmdp);
 #endif
 
+#ifndef __HAVE_ARCH_PMDP_HUGE_SPLIT_PREPARE
+static inline void pmdp_huge_split_prepare(struct vm_area_struct *vma,
+                                          unsigned long address, pmd_t *pmdp)
+{
+
+}
+#endif
+
 #ifndef __HAVE_ARCH_PTE_SAME
 static inline int pte_same(pte_t pte_a, pte_t pte_b)
 {
index 7bfb063029d83fe1374e78a174f4a638bc39bc49..461a0558bca4d8d16e81b88e0286e3fa6251ab79 100644 (file)
 
 void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
 
+static inline bool drm_arch_can_wc_memory(void)
+{
+#if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+       return false;
+#else
+       return true;
+#endif
+}
+
 #endif
index c65a212db77e7a99b26735c262cb31a9b2504195..c5b4b81a831ba733bee1dc8aba8c9a3bb7341739 100644 (file)
@@ -1166,6 +1166,7 @@ struct drm_connector {
        struct drm_mode_object base;
 
        char *name;
+       int connector_id;
        int connector_type;
        int connector_type_id;
        bool interlace_allowed;
@@ -2047,6 +2048,7 @@ struct drm_mode_config {
        struct list_head fb_list;
 
        int num_connector;
+       struct ida connector_ida;
        struct list_head connector_list;
        int num_encoder;
        struct list_head encoder_list;
@@ -2200,7 +2202,11 @@ int drm_connector_register(struct drm_connector *connector);
 void drm_connector_unregister(struct drm_connector *connector);
 
 extern void drm_connector_cleanup(struct drm_connector *connector);
-extern unsigned int drm_connector_index(struct drm_connector *connector);
+static inline unsigned drm_connector_index(struct drm_connector *connector)
+{
+       return connector->connector_id;
+}
+
 /* helper to unplug all connectors from sysfs for device */
 extern void drm_connector_unplug_all(struct drm_device *dev);
 
index 24ab1787b771936fdf1894aabd6271f65a771993..fdb47051d5492a4db126cc525667bd181343d2cd 100644 (file)
@@ -44,8 +44,6 @@ struct drm_dp_vcpi {
 /**
  * struct drm_dp_mst_port - MST port
  * @kref: reference count for this port.
- * @guid_valid: for DP 1.2 devices if we have validated the GUID.
- * @guid: guid for DP 1.2 device on this port.
  * @port_num: port number
  * @input: if this port is an input port.
  * @mcs: message capability status - DP 1.2 spec.
@@ -70,10 +68,6 @@ struct drm_dp_vcpi {
 struct drm_dp_mst_port {
        struct kref kref;
 
-       /* if dpcd 1.2 device is on this port - its GUID info */
-       bool guid_valid;
-       u8 guid[16];
-
        u8 port_num;
        bool input;
        bool mcs;
@@ -110,10 +104,12 @@ struct drm_dp_mst_port {
  * @tx_slots: transmission slots for this device.
  * @last_seqno: last sequence number used to talk to this.
  * @link_address_sent: if a link address message has been sent to this device yet.
+ * @guid: guid for DP 1.2 branch device. port under this branch can be
+ * identified by port #.
  *
  * This structure represents an MST branch device, there is one
- * primary branch device at the root, along with any others connected
- * to downstream ports
+ * primary branch device at the root, along with any other branches connected
+ * to downstream port of parent branches.
  */
 struct drm_dp_mst_branch {
        struct kref kref;
@@ -132,6 +128,9 @@ struct drm_dp_mst_branch {
        struct drm_dp_sideband_msg_tx *tx_slots[2];
        int last_seqno;
        bool link_address_sent;
+
+       /* global unique identifier to identify branch devices */
+       u8 guid[16];
 };
 
 
@@ -406,11 +405,9 @@ struct drm_dp_payload {
  * @conn_base_id: DRM connector ID this mgr is connected to.
  * @down_rep_recv: msg receiver state for down replies.
  * @up_req_recv: msg receiver state for up requests.
- * @lock: protects mst state, primary, guid, dpcd.
+ * @lock: protects mst state, primary, dpcd.
  * @mst_state: if this manager is enabled for an MST capable port.
  * @mst_primary: pointer to the primary branch device.
- * @guid_valid: GUID valid for the primary branch device.
- * @guid: GUID for primary port.
  * @dpcd: cache of DPCD for primary port.
  * @pbn_div: PBN to slots divisor.
  *
@@ -432,13 +429,11 @@ struct drm_dp_mst_topology_mgr {
        struct drm_dp_sideband_msg_rx up_req_recv;
 
        /* pointer to info about the initial MST device */
-       struct mutex lock; /* protects mst_state + primary + guid + dpcd */
+       struct mutex lock; /* protects mst_state + primary + dpcd */
 
        bool mst_state;
        struct drm_dp_mst_branch *mst_primary;
-       /* primary MST device GUID */
-       bool guid_valid;
-       u8 guid[16];
+
        u8 dpcd[DP_RECEIVER_CAP_SIZE];
        u8 sink_count;
        int pbn_div;
index d639049a613dfdb264650f8ee938836e6ed28e10..553210c02ee0f655fd28b8ae64d370e7cee2fc70 100644 (file)
@@ -73,18 +73,28 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B)
 #define DRM_FIXED_ONE          (1ULL << DRM_FIXED_POINT)
 #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1)
 #define DRM_FIXED_DIGITS_MASK  (~DRM_FIXED_DECIMAL_MASK)
+#define DRM_FIXED_EPSILON      1LL
+#define DRM_FIXED_ALMOST_ONE   (DRM_FIXED_ONE - DRM_FIXED_EPSILON)
 
 static inline s64 drm_int2fixp(int a)
 {
        return ((s64)a) << DRM_FIXED_POINT;
 }
 
-static inline int drm_fixp2int(int64_t a)
+static inline int drm_fixp2int(s64 a)
 {
        return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline unsigned drm_fixp_msbset(int64_t a)
+static inline int drm_fixp2int_ceil(s64 a)
+{
+       if (a > 0)
+               return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE);
+       else
+               return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE);
+}
+
+static inline unsigned drm_fixp_msbset(s64 a)
 {
        unsigned shift, sign = (a >> 63) & 1;
 
@@ -136,6 +146,45 @@ static inline s64 drm_fixp_div(s64 a, s64 b)
        return result;
 }
 
+static inline s64 drm_fixp_from_fraction(s64 a, s64 b)
+{
+       s64 res;
+       bool a_neg = a < 0;
+       bool b_neg = b < 0;
+       u64 a_abs = a_neg ? -a : a;
+       u64 b_abs = b_neg ? -b : b;
+       u64 rem;
+
+       /* determine integer part */
+       u64 res_abs  = div64_u64_rem(a_abs, b_abs, &rem);
+
+       /* determine fractional part */
+       {
+               u32 i = DRM_FIXED_POINT;
+
+               do {
+                       rem <<= 1;
+                       res_abs <<= 1;
+                       if (rem >= b_abs) {
+                               res_abs |= 1;
+                               rem -= b_abs;
+                       }
+               } while (--i != 0);
+       }
+
+       /* round up LSB */
+       {
+               u64 summand = (rem << 1) >= b_abs;
+
+               res_abs += summand;
+       }
+
+       res = (s64) res_abs;
+       if (a_neg ^ b_neg)
+               res = -res;
+       return res;
+}
+
 static inline s64 drm_fixp_exp(s64 x)
 {
        s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000);
index 6f45aea49e4ff049a51394f6782a803e32c389eb..0a05b0d36ae74d6c4e4a7e810e442ab2ff2b09bf 100644 (file)
 /* 104 */
 /* 105 */
 #define TEGRA210_CLK_D_AUDIO 106
-/* 107 ( affects abp -> ape) */
+#define TEGRA210_CLK_APB2APE 107
 /* 108 */
 /* 109 */
 /* 110 */
index d2992bfa17063a052a08a106b9105284ce4bfa4a..c1a2f345cbe6146352fff77080019eba5d0fe76e 100644 (file)
@@ -487,8 +487,8 @@ enum ata_tf_protocols {
 };
 
 enum ata_ioctls {
-       ATA_IOC_GET_IO32        = 0x309,
-       ATA_IOC_SET_IO32        = 0x324,
+       ATA_IOC_GET_IO32        = 0x309, /* HDIO_GET_32BIT */
+       ATA_IOC_SET_IO32        = 0x324, /* HDIO_SET_32BIT */
 };
 
 /* core structures */
index 3feb1b2d75d87b83febb605a86720b06a8132d3f..0367c63f596019b5b94d66f315d426e6ab8a4cc4 100644 (file)
@@ -151,6 +151,8 @@ struct bcma_host_ops {
 #define BCMA_CORE_PCIE2                        0x83C   /* PCI Express Gen2 */
 #define BCMA_CORE_USB30_DEV            0x83D
 #define BCMA_CORE_ARM_CR4              0x83E
+#define BCMA_CORE_GCI                  0x840
+#define BCMA_CORE_CMEM                 0x846   /* CNDS DDR2/3 memory controller */
 #define BCMA_CORE_ARM_CA7              0x847
 #define BCMA_CORE_SYS_MEM              0x849
 #define BCMA_CORE_DEFAULT              0xFFF
@@ -199,6 +201,7 @@ struct bcma_host_ops {
 #define  BCMA_PKG_ID_BCM4707   1
 #define  BCMA_PKG_ID_BCM4708   2
 #define  BCMA_PKG_ID_BCM4709   0
+#define BCMA_CHIP_ID_BCM47094  53030
 #define BCMA_CHIP_ID_BCM53018  53018
 
 /* Board types (on PCI usually equals to the subsystem dev id) */
index db51a6ffb7d6839ba1ffd08ffd072faed79031dc..846513c73606bd96997015eb115f55fc59e3e39d 100644 (file)
 #define         BCMA_CC_CLKDIV_JTAG_SHIFT      8
 #define         BCMA_CC_CLKDIV_UART            0x000000FF
 #define BCMA_CC_CAP_EXT                        0x00AC          /* Capabilities */
+#define  BCMA_CC_CAP_EXT_SECI_PRESENT  0x00000001
+#define  BCMA_CC_CAP_EXT_GSIO_PRESENT  0x00000002
+#define  BCMA_CC_CAP_EXT_GCI_PRESENT   0x00000004
+#define  BCMA_CC_CAP_EXT_SECI_PUART_PRESENT            0x00000008    /* UART present */
+#define  BCMA_CC_CAP_EXT_AOB_PRESENT   0x00000040
 #define BCMA_CC_PLLONDELAY             0x00B0          /* Rev >= 4 only */
 #define BCMA_CC_FREFSELDELAY           0x00B4          /* Rev >= 4 only */
 #define BCMA_CC_SLOWCLKCTL             0x00B8          /* 6 <= Rev <= 9 only */
 #define BCMA_CC_PMU_RES_REQTS          0x0640 /* PMU res req timer sel */
 #define BCMA_CC_PMU_RES_REQT           0x0644 /* PMU res req timer */
 #define BCMA_CC_PMU_RES_REQM           0x0648 /* PMU res req mask */
-#define BCMA_CC_CHIPCTL_ADDR           0x0650
-#define BCMA_CC_CHIPCTL_DATA           0x0654
-#define BCMA_CC_REGCTL_ADDR            0x0658
-#define BCMA_CC_REGCTL_DATA            0x065C
-#define BCMA_CC_PLLCTL_ADDR            0x0660
-#define BCMA_CC_PLLCTL_DATA            0x0664
+#define BCMA_CC_PMU_CHIPCTL_ADDR       0x0650
+#define BCMA_CC_PMU_CHIPCTL_DATA       0x0654
+#define BCMA_CC_PMU_REGCTL_ADDR                0x0658
+#define BCMA_CC_PMU_REGCTL_DATA                0x065C
+#define BCMA_CC_PMU_PLLCTL_ADDR                0x0660
+#define BCMA_CC_PMU_PLLCTL_DATA                0x0664
 #define BCMA_CC_PMU_STRAPOPT           0x0668 /* (corerev >= 28) */
 #define BCMA_CC_PMU_XTAL_FREQ          0x066C /* (pmurev >= 10) */
 #define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK     0x00001FFF
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
 struct bcma_chipcommon_pmu {
+       struct bcma_device *core;       /* Can be separated core or just ChipCommon one */
        u8 rev;                 /* PMU revision */
        u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 };
 
-#ifdef CONFIG_BCMA_DRIVER_MIPS
+#ifdef CONFIG_BCMA_PFLASH
 struct bcma_pflash {
        bool present;
-       u8 buswidth;
-       u32 window;
-       u32 window_size;
 };
+#endif
 
 #ifdef CONFIG_BCMA_SFLASH
 struct mtd_info;
@@ -600,6 +604,7 @@ struct bcma_nflash {
 };
 #endif
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
 struct bcma_serial_port {
        void *regs;
        unsigned long clockspeed;
@@ -619,8 +624,9 @@ struct bcma_drv_cc {
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct bcma_chipcommon_pmu pmu;
-#ifdef CONFIG_BCMA_DRIVER_MIPS
+#ifdef CONFIG_BCMA_PFLASH
        struct bcma_pflash pflash;
+#endif
 #ifdef CONFIG_BCMA_SFLASH
        struct bcma_sflash sflash;
 #endif
@@ -628,6 +634,7 @@ struct bcma_drv_cc {
        struct bcma_nflash nflash;
 #endif
 
+#ifdef CONFIG_BCMA_DRIVER_MIPS
        int nr_serial_ports;
        struct bcma_serial_port serial_ports[4];
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
@@ -660,6 +667,19 @@ struct bcma_drv_cc_b {
 #define bcma_cc_maskset32(cc, offset, mask, set) \
        bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
 
+/* PMU registers access */
+#define bcma_pmu_read32(cc, offset) \
+       bcma_read32((cc)->pmu.core, offset)
+#define bcma_pmu_write32(cc, offset, val) \
+       bcma_write32((cc)->pmu.core, offset, val)
+
+#define bcma_pmu_mask32(cc, offset, mask) \
+       bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
+#define bcma_pmu_set32(cc, offset, set) \
+       bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
+#define bcma_pmu_maskset32(cc, offset, mask, set) \
+       bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
+
 extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
 
 extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
index 5349e6816cbb075e2b5d6ac57cac1e8fee373438..cb68888241084e33af2d7e11753e048431cf7837 100644 (file)
@@ -310,6 +310,43 @@ static inline void bio_clear_flag(struct bio *bio, unsigned int bit)
        bio->bi_flags &= ~(1U << bit);
 }
 
+static inline void bio_get_first_bvec(struct bio *bio, struct bio_vec *bv)
+{
+       *bv = bio_iovec(bio);
+}
+
+static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv)
+{
+       struct bvec_iter iter = bio->bi_iter;
+       int idx;
+
+       if (!bio_flagged(bio, BIO_CLONED)) {
+               *bv = bio->bi_io_vec[bio->bi_vcnt - 1];
+               return;
+       }
+
+       if (unlikely(!bio_multiple_segments(bio))) {
+               *bv = bio_iovec(bio);
+               return;
+       }
+
+       bio_advance_iter(bio, &iter, iter.bi_size);
+
+       if (!iter.bi_bvec_done)
+               idx = iter.bi_idx - 1;
+       else    /* in the middle of bvec */
+               idx = iter.bi_idx;
+
+       *bv = bio->bi_io_vec[idx];
+
+       /*
+        * iter.bi_bvec_done records actual length of the last bvec
+        * if this bio ends in the middle of one io vector
+        */
+       if (iter.bi_bvec_done)
+               bv->bv_len = iter.bi_bvec_done;
+}
+
 enum bip_flags {
        BIP_BLOCK_INTEGRITY     = 1 << 0, /* block layer owns integrity data */
        BIP_MAPPED_INTEGRITY    = 1 << 1, /* ref tag has been remapped */
index 9653fdb76a4273dc21cecc1ddf87ea3b7576668d..e9b0b9ab07e5a58a14b5ed0648fb879962e2c6c7 100644 (file)
@@ -59,6 +59,8 @@
  * bitmap_find_free_region(bitmap, bits, order)        Find and allocate bit region
  * bitmap_release_region(bitmap, pos, order)   Free specified bit region
  * bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
+ * bitmap_from_u32array(dst, nbits, buf, nwords) *dst = *buf (nwords 32b words)
+ * bitmap_to_u32array(buf, nwords, src, nbits) *buf = *dst (nwords 32b words)
  */
 
 /*
@@ -163,6 +165,14 @@ extern void bitmap_fold(unsigned long *dst, const unsigned long *orig,
 extern int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order);
+extern unsigned int bitmap_from_u32array(unsigned long *bitmap,
+                                        unsigned int nbits,
+                                        const u32 *buf,
+                                        unsigned int nwords);
+extern unsigned int bitmap_to_u32array(u32 *buf,
+                                      unsigned int nwords,
+                                      const unsigned long *bitmap,
+                                      unsigned int nbits);
 #ifdef __BIG_ENDIAN
 extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
 #else
index 29189aeace19df0650c15e374e60724ce77ac917..413c84fbc4edafc582c765630ccb3f3117dbc1fc 100644 (file)
@@ -682,9 +682,12 @@ static inline bool blk_write_same_mergeable(struct bio *a, struct bio *b)
 /*
  * q->prep_rq_fn return values
  */
-#define BLKPREP_OK             0       /* serve it */
-#define BLKPREP_KILL           1       /* fatal error, kill */
-#define BLKPREP_DEFER          2       /* leave on queue */
+enum {
+       BLKPREP_OK,             /* serve it */
+       BLKPREP_KILL,           /* fatal error, kill, return -EIO */
+       BLKPREP_DEFER,          /* leave on queue */
+       BLKPREP_INVALID,        /* invalid command, kill, return -EREMOTEIO */
+};
 
 extern unsigned long blk_max_low_pfn, blk_max_pfn;
 
@@ -892,7 +895,7 @@ static inline unsigned int blk_rq_get_max_sectors(struct request *rq)
 {
        struct request_queue *q = rq->q;
 
-       if (unlikely(rq->cmd_type == REQ_TYPE_BLOCK_PC))
+       if (unlikely(rq->cmd_type != REQ_TYPE_FS))
                return q->limits.max_hw_sectors;
 
        if (!q->limits.chunk_sectors || (rq->cmd_flags & REQ_DISCARD))
@@ -1369,6 +1372,13 @@ static inline void put_dev_sector(Sector p)
        page_cache_release(p.v);
 }
 
+static inline bool __bvec_gap_to_prev(struct request_queue *q,
+                               struct bio_vec *bprv, unsigned int offset)
+{
+       return offset ||
+               ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+}
+
 /*
  * Check if adding a bio_vec after bprv with offset would create a gap in
  * the SG list. Most drivers don't care about this, but some do.
@@ -1378,18 +1388,22 @@ static inline bool bvec_gap_to_prev(struct request_queue *q,
 {
        if (!queue_virt_boundary(q))
                return false;
-       return offset ||
-               ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q));
+       return __bvec_gap_to_prev(q, bprv, offset);
 }
 
 static inline bool bio_will_gap(struct request_queue *q, struct bio *prev,
                         struct bio *next)
 {
-       if (!bio_has_data(prev))
-               return false;
+       if (bio_has_data(prev) && queue_virt_boundary(q)) {
+               struct bio_vec pb, nb;
+
+               bio_get_last_bvec(prev, &pb);
+               bio_get_first_bvec(next, &nb);
 
-       return bvec_gap_to_prev(q, &prev->bi_io_vec[prev->bi_vcnt - 1],
-                               next->bi_io_vec[0].bv_offset);
+               return __bvec_gap_to_prev(q, &pb, nb.bv_offset);
+       }
+
+       return false;
 }
 
 static inline bool req_gap_back_merge(struct request *req, struct bio *bio)
index 90ee6ab24bc53badebf5ab0f6362de1d4ad2062d..21ee41b92e8aaad2030f0d86c614dc4bfc4b5c5a 100644 (file)
@@ -10,6 +10,7 @@
 #include <uapi/linux/bpf.h>
 #include <linux/workqueue.h>
 #include <linux/file.h>
+#include <linux/percpu.h>
 
 struct bpf_map;
 
@@ -36,6 +37,7 @@ struct bpf_map {
        u32 key_size;
        u32 value_size;
        u32 max_entries;
+       u32 map_flags;
        u32 pages;
        struct user_struct *user;
        const struct bpf_map_ops *ops;
@@ -65,6 +67,7 @@ enum bpf_arg_type {
         */
        ARG_PTR_TO_STACK,       /* any pointer to eBPF program stack */
        ARG_CONST_STACK_SIZE,   /* number of bytes accessed from stack */
+       ARG_CONST_STACK_SIZE_OR_ZERO, /* number of bytes accessed from stack or 0 */
 
        ARG_PTR_TO_CTX,         /* pointer to context */
        ARG_ANYTHING,           /* any (initialized) argument is ok */
@@ -162,6 +165,8 @@ bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *f
 const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
 
 #ifdef CONFIG_BPF_SYSCALL
+DECLARE_PER_CPU(int, bpf_prog_active);
+
 void bpf_register_prog_type(struct bpf_prog_type_list *tl);
 void bpf_register_map_type(struct bpf_map_type_list *tl);
 
@@ -174,6 +179,7 @@ struct bpf_map *__bpf_map_get(struct fd f);
 void bpf_map_inc(struct bpf_map *map, bool uref);
 void bpf_map_put_with_uref(struct bpf_map *map);
 void bpf_map_put(struct bpf_map *map);
+int bpf_map_precharge_memlock(u32 pages);
 
 extern int sysctl_unprivileged_bpf_disabled;
 
@@ -189,6 +195,7 @@ int bpf_percpu_hash_update(struct bpf_map *map, void *key, void *value,
                           u64 flags);
 int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,
                            u64 flags);
+int bpf_stackmap_copy(struct bpf_map *map, void *key, void *value);
 
 /* memcpy that is used with 8-byte aligned pointers, power-of-8 size and
  * forced to use 'long' read/writes to try to atomically copy long counters.
@@ -237,6 +244,7 @@ extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
 extern const struct bpf_func_proto bpf_get_current_comm_proto;
 extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
 extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
+extern const struct bpf_func_proto bpf_get_stackid_proto;
 
 /* Shared helpers among cBPF and eBPF. */
 void bpf_user_rnd_init_once(void);
index f89b31d45cc894814d409a19e161a29c2c41e832..15151f3c41202c6b6229475affb654ae0bab272d 100644 (file)
 #define CEPH_FEATURE_OSD_MIN_SIZE_RECOVERY (1ULL<<49)
 // duplicated since it was introduced at the same time as MIN_SIZE_RECOVERY
 #define CEPH_FEATURE_OSD_PROXY_FEATURES (1ULL<<49)  /* overlap w/ above */
+#define CEPH_FEATURE_MON_METADATA (1ULL<<50)
+#define CEPH_FEATURE_OSD_BITWISE_HOBJ_SORT (1ULL<<51) /* can sort objs bitwise */
+#define CEPH_FEATURE_OSD_PROXY_WRITE_FEATURES (1ULL<<52)
+#define CEPH_FEATURE_ERASURE_CODE_PLUGINS_V3 (1ULL<<53)
+#define CEPH_FEATURE_OSD_HITSET_GMT (1ULL<<54)
+#define CEPH_FEATURE_HAMMER_0_94_4 (1ULL<<55)
+#define CEPH_FEATURE_NEW_OSDOP_ENCODING   (1ULL<<56) /* New, v7 encoding */
+#define CEPH_FEATURE_MON_STATEFUL_SUB (1ULL<<57) /* stateful mon subscription */
+#define CEPH_FEATURE_MON_ROUTE_OSDMAP (1ULL<<57) /* peon sends osdmaps */
+#define CEPH_FEATURE_CRUSH_TUNABLES5   (1ULL<<58) /* chooseleaf stable mode */
+// duplicated since it was introduced at the same time as CEPH_FEATURE_CRUSH_TUNABLES5
+#define CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING   (1ULL<<58) /* New, v7 encoding */
+#define CEPH_FEATURE_FS_FILE_LAYOUT_V2       (1ULL<<58) /* file_layout_t */
 
 /*
  * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature
@@ -108,7 +121,9 @@ static inline u64 ceph_sanitize_features(u64 features)
         CEPH_FEATURE_CRUSH_TUNABLES3 |         \
         CEPH_FEATURE_OSD_PRIMARY_AFFINITY |    \
         CEPH_FEATURE_MSGR_KEEPALIVE2 |         \
-        CEPH_FEATURE_CRUSH_V4)
+        CEPH_FEATURE_CRUSH_V4 |                \
+        CEPH_FEATURE_CRUSH_TUNABLES5 |         \
+        CEPH_FEATURE_NEW_OSDOPREPLY_ENCODING)
 
 #define CEPH_FEATURES_REQUIRED_DEFAULT   \
        (CEPH_FEATURE_NOSRCADDR |        \
index 7f540f7f588d8c8461af975a5ebd21a08e6cf14b..789471dba6fb30f15c752fbca46ddbefe5bfe850 100644 (file)
@@ -127,6 +127,12 @@ struct cgroup_subsys_state {
         */
        u64 serial_nr;
 
+       /*
+        * Incremented by online self and children.  Used to guarantee that
+        * parents are not offlined before their children.
+        */
+       atomic_t online_cnt;
+
        /* percpu_ref killing and RCU release */
        struct rcu_head rcu_head;
        struct work_struct destroy_work;
index 00b042c49ccdac7af3262a399d33dacc88c83e25..48f5aab117ae12625d041cd18555031e87c178fc 100644 (file)
@@ -144,7 +144,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
  */
 #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
 #define __trace_if(cond) \
-       if (__builtin_constant_p((cond)) ? !!(cond) :                   \
+       if (__builtin_constant_p(!!(cond)) ? !!(cond) :                 \
        ({                                                              \
                int ______r;                                            \
                static struct ftrace_branch_data                        \
index 85a868ccb4931d374a1ee9fb4e4036bb84399561..fea160ee5803fd121d0493f622e240b4c35da480 100644 (file)
@@ -137,6 +137,8 @@ static inline void set_mems_allowed(nodemask_t nodemask)
        task_unlock(current);
 }
 
+extern void cpuset_post_attach_flush(void);
+
 #else /* !CONFIG_CPUSETS */
 
 static inline bool cpusets_enabled(void) { return false; }
@@ -243,6 +245,10 @@ static inline bool read_mems_allowed_retry(unsigned int seq)
        return false;
 }
 
+static inline void cpuset_post_attach_flush(void)
+{
+}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
index 48b49305716bd728e69477db6b430c34e7781746..be8f12b8f1950499380c10de27ab6928df25fd8e 100644 (file)
@@ -59,7 +59,8 @@ enum {
        CRUSH_RULE_SET_CHOOSELEAF_TRIES = 9, /* override chooseleaf_descend_once */
        CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES = 10,
        CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11,
-       CRUSH_RULE_SET_CHOOSELEAF_VARY_R = 12
+       CRUSH_RULE_SET_CHOOSELEAF_VARY_R = 12,
+       CRUSH_RULE_SET_CHOOSELEAF_STABLE = 13
 };
 
 /*
@@ -205,6 +206,11 @@ struct crush_map {
         * mappings line up a bit better with previous mappings. */
        __u8 chooseleaf_vary_r;
 
+       /* if true, it makes chooseleaf firstn to return stable results (if
+        * no local retry) so that data migrations would be optimal when some
+        * device fails. */
+       __u8 chooseleaf_stable;
+
 #ifndef __KERNEL__
        /*
         * version 0 (original) of straw_calc has various flaws.  version 1
index 818e45078929b94af5780a8c91f0e84d82da8e0c..636dd59ab505c6633ae3184b9c283cad06ab893f 100644 (file)
@@ -7,7 +7,7 @@
 
 ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *, loff_t,
                  get_block_t, dio_iodone_t, int flags);
-int dax_clear_blocks(struct inode *, sector_t block, long size);
+int dax_clear_sectors(struct block_device *bdev, sector_t _sector, long _size);
 int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t);
 int dax_truncate_page(struct inode *, loff_t from, get_block_t);
 int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t,
@@ -52,6 +52,8 @@ static inline bool dax_mapping(struct address_space *mapping)
 {
        return mapping->host && IS_DAX(mapping->host);
 }
-int dax_writeback_mapping_range(struct address_space *mapping, loff_t start,
-               loff_t end);
+
+struct writeback_control;
+int dax_writeback_mapping_range(struct address_space *mapping,
+               struct block_device *bdev, struct writeback_control *wbc);
 #endif
index 7781ce11050353a44cd7a3982c97949651956103..c4b5f4b3f8f8bba5af054b2b22e5c2c6fcf72b89 100644 (file)
@@ -409,9 +409,7 @@ static inline bool d_mountpoint(const struct dentry *dentry)
  */
 static inline unsigned __d_entry_type(const struct dentry *dentry)
 {
-       unsigned type = READ_ONCE(dentry->d_flags);
-       smp_rmb();
-       return type & DCACHE_ENTRY_TYPE;
+       return dentry->d_flags & DCACHE_ENTRY_TYPE;
 }
 
 static inline bool d_is_miss(const struct dentry *dentry)
index 251a2090a55444cec55ce4f04510b6ef83a69cfb..e0ee0b3000b2da107c975137165fc989777d8a58 100644 (file)
@@ -19,6 +19,8 @@
 
 int devpts_new_index(struct inode *ptmx_inode);
 void devpts_kill_index(struct inode *ptmx_inode, int idx);
+void devpts_add_ref(struct inode *ptmx_inode);
+void devpts_del_ref(struct inode *ptmx_inode);
 /* mknod in devpts */
 struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
                void *priv);
@@ -32,6 +34,8 @@ void devpts_pty_kill(struct inode *inode);
 /* Dummy stubs in the no-pty case */
 static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
 static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
+static inline void devpts_add_ref(struct inode *ptmx_inode) { }
+static inline void devpts_del_ref(struct inode *ptmx_inode) { }
 static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
                dev_t device, int index, void *priv)
 {
index 569b5a866bb1e6308bbc4c0a28a2da92d106d6b5..47be3ad7d3e5bad63b48a8fa344dbea65c0a97dd 100644 (file)
@@ -1199,7 +1199,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
 struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
                                       struct list_head *head, bool remove);
 
-bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len);
+bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
+                    unsigned long data_size);
+bool efivar_variable_is_removable(efi_guid_t vendor, const char *name,
+                                 size_t len);
 
 extern struct work_struct efivar_work;
 void efivar_run_worker(void);
index 653dc9c4ebac7a176183af8e2a8ae26076a03eca..e2b7bf27c03ef3ea8ec089a02fc735b78b5c0072 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _LINUX_ETHTOOL_H
 #define _LINUX_ETHTOOL_H
 
+#include <linux/bitmap.h>
 #include <linux/compat.h>
 #include <uapi/linux/ethtool.h>
 
@@ -40,9 +41,6 @@ struct compat_ethtool_rxnfc {
 
 #include <linux/rculist.h>
 
-extern int __ethtool_get_settings(struct net_device *dev,
-                                 struct ethtool_cmd *cmd);
-
 /**
  * enum ethtool_phys_id_state - indicator state for physical identification
  * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
@@ -97,13 +95,70 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
        return index % n_rx_rings;
 }
 
+/* number of link mode bits/ulongs handled internally by kernel */
+#define __ETHTOOL_LINK_MODE_MASK_NBITS                 \
+       (__ETHTOOL_LINK_MODE_LAST + 1)
+
+/* declare a link mode bitmap */
+#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name)         \
+       DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/* drivers must ignore base.cmd and base.link_mode_masks_nwords
+ * fields, but they are allowed to overwrite them (will be ignored).
+ */
+struct ethtool_link_ksettings {
+       struct ethtool_link_settings base;
+       struct {
+               __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+               __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
+               __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
+       } link_modes;
+};
+
+/**
+ * ethtool_link_ksettings_zero_link_mode - clear link_ksettings link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ */
+#define ethtool_link_ksettings_zero_link_mode(ptr, name)               \
+       bitmap_zero((ptr)->link_modes.name, __ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/**
+ * ethtool_link_ksettings_add_link_mode - set bit in link_ksettings
+ * link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ *   @mode : one of the ETHTOOL_LINK_MODE_*_BIT
+ * (not atomic, no bound checking)
+ */
+#define ethtool_link_ksettings_add_link_mode(ptr, name, mode)          \
+       __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
+
+/**
+ * ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask
+ *   @ptr : pointer to struct ethtool_link_ksettings
+ *   @name : one of supported/advertising/lp_advertising
+ *   @mode : one of the ETHTOOL_LINK_MODE_*_BIT
+ * (not atomic, no bound checking)
+ *
+ * Returns true/false.
+ */
+#define ethtool_link_ksettings_test_link_mode(ptr, name, mode)         \
+       test_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
+
+extern int
+__ethtool_get_link_ksettings(struct net_device *dev,
+                            struct ethtool_link_ksettings *link_ksettings);
+
 /**
  * struct ethtool_ops - optional netdev operations
- * @get_settings: Get various device settings including Ethernet link
+ * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
+ *     API. Get various device settings including Ethernet link
  *     settings. The @cmd parameter is expected to have been cleared
- *     before get_settings is called. Returns a negative error code or
- *     zero.
- * @set_settings: Set various device settings including Ethernet link
+ *     before get_settings is called. Returns a negative error code
+ *     or zero.
+ * @set_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings
+ *     API. Set various device settings including Ethernet link
  *     settings.  Returns a negative error code or zero.
  * @get_drvinfo: Report driver/device information.  Should only set the
  *     @driver, @version, @fw_version and @bus_info fields.  If not
@@ -201,6 +256,29 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
  * @get_module_eeprom: Get the eeprom information from the plug-in module
  * @get_eee: Get Energy-Efficient (EEE) supported and status.
  * @set_eee: Set EEE status (enable/disable) as well as LPI timers.
+ * @get_per_queue_coalesce: Get interrupt coalescing parameters per queue.
+ *     It must check that the given queue number is valid. If neither a RX nor
+ *     a TX queue has this number, return -EINVAL. If only a RX queue or a TX
+ *     queue has this number, set the inapplicable fields to ~0 and return 0.
+ *     Returns a negative error code or zero.
+ * @set_per_queue_coalesce: Set interrupt coalescing parameters per queue.
+ *     It must check that the given queue number is valid. If neither a RX nor
+ *     a TX queue has this number, return -EINVAL. If only a RX queue or a TX
+ *     queue has this number, ignore the inapplicable fields.
+ *     Returns a negative error code or zero.
+ * @get_link_ksettings: When defined, takes precedence over the
+ *     %get_settings method. Get various device settings
+ *     including Ethernet link settings. The %cmd and
+ *     %link_mode_masks_nwords fields should be ignored (use
+ *     %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any
+ *     change to them will be overwritten by kernel. Returns a
+ *     negative error code or zero.
+ * @set_link_ksettings: When defined, takes precedence over the
+ *     %set_settings method. Set various device settings including
+ *     Ethernet link settings. The %cmd and %link_mode_masks_nwords
+ *     fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS
+ *     instead of the latter), any change to them will be overwritten
+ *     by kernel. Returns a negative error code or zero.
  *
  * All operations are optional (i.e. the function pointer may be set
  * to %NULL) and callers must take this into account.  Callers must
@@ -279,7 +357,13 @@ struct ethtool_ops {
                               const struct ethtool_tunable *, void *);
        int     (*set_tunable)(struct net_device *,
                               const struct ethtool_tunable *, const void *);
-
-
+       int     (*get_per_queue_coalesce)(struct net_device *, u32,
+                                         struct ethtool_coalesce *);
+       int     (*set_per_queue_coalesce)(struct net_device *, u32,
+                                         struct ethtool_coalesce *);
+       int     (*get_link_ksettings)(struct net_device *,
+                                     struct ethtool_link_ksettings *);
+       int     (*set_link_ksettings)(struct net_device *,
+                                     const struct ethtool_link_ksettings *);
 };
 #endif /* _LINUX_ETHTOOL_H */
index 6b7e89f45aa49e3eb1531c51f6edae4cc18d576a..533c4408529a19819570c5dc40d917aa10ac2d26 100644 (file)
@@ -220,10 +220,7 @@ struct fsnotify_mark {
        /* List of marks by group->i_fsnotify_marks. Also reused for queueing
         * mark into destroy_list when it's waiting for the end of SRCU period
         * before it can be freed. [group->mark_mutex] */
-       union {
-               struct list_head g_list;
-               struct rcu_head g_rcu;
-       };
+       struct list_head g_list;
        /* Protects inode / mnt pointers, flags, masks */
        spinlock_t lock;
        /* List of marks for inode / vfsmount [obj_lock] */
index 81de7123959d96d97dd57d41d76289b3a8185920..c2b340e23f62d3240abc6360ab0412a82a12f21a 100644 (file)
@@ -603,6 +603,7 @@ extern int ftrace_arch_read_dyn_info(char *buf, int size);
 
 extern int skip_trace(unsigned long ip);
 extern void ftrace_module_init(struct module *mod);
+extern void ftrace_module_enable(struct module *mod);
 extern void ftrace_release_mod(struct module *mod);
 
 extern void ftrace_disable_daemon(void);
@@ -612,8 +613,9 @@ static inline int skip_trace(unsigned long ip) { return 0; }
 static inline int ftrace_force_update(void) { return 0; }
 static inline void ftrace_disable_daemon(void) { }
 static inline void ftrace_enable_daemon(void) { }
-static inline void ftrace_release_mod(struct module *mod) {}
-static inline void ftrace_module_init(struct module *mod) {}
+static inline void ftrace_module_init(struct module *mod) { }
+static inline void ftrace_module_enable(struct module *mod) { }
+static inline void ftrace_release_mod(struct module *mod) { }
 static inline __init int register_ftrace_command(struct ftrace_func_command *cmd)
 {
        return -EINVAL;
index 28ad5f6494b018a2c49493920059de62fcacdb8e..af1f2b24bbe4172f6055407229f0670ee90dc534 100644 (file)
@@ -547,16 +547,16 @@ static inline bool pm_suspended_storage(void)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-#ifdef CONFIG_CMA
-
+#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
 /* The below functions must be run on a range from a single zone. */
 extern int alloc_contig_range(unsigned long start, unsigned long end,
                              unsigned migratetype);
 extern void free_contig_range(unsigned long pfn, unsigned nr_pages);
+#endif
 
+#ifdef CONFIG_CMA
 /* CMA stuff */
 extern void init_cma_reserved_pageblock(struct page *page);
-
 #endif
 
 #endif /* __LINUX_GFP_H */
index 452c0b0d2f3219dc0f11bec80878e5ea0b8e8803..3b1f6cef95136fa381d06eb5ccb409dde3e030a0 100644 (file)
@@ -163,6 +163,14 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
 /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
 #define IEEE80211_MAX_FRAME_LEN                2352
 
+/* Maximal size of an A-MSDU */
+#define IEEE80211_MAX_MPDU_LEN_HT_3839         3839
+#define IEEE80211_MAX_MPDU_LEN_HT_7935         7935
+
+#define IEEE80211_MAX_MPDU_LEN_VHT_3895                3895
+#define IEEE80211_MAX_MPDU_LEN_VHT_7991                7991
+#define IEEE80211_MAX_MPDU_LEN_VHT_11454       11454
+
 #define IEEE80211_MAX_SSID_LEN         32
 
 #define IEEE80211_MAX_MESH_ID_LEN      32
@@ -843,6 +851,8 @@ enum ieee80211_vht_opmode_bits {
 };
 
 #define WLAN_SA_QUERY_TR_ID_LEN 2
+#define WLAN_MEMBERSHIP_LEN 8
+#define WLAN_USER_POSITION_LEN 16
 
 /**
  * struct ieee80211_tpc_report_ie
@@ -989,6 +999,11 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 operating_mode;
                                } __packed vht_opmode_notif;
+                               struct {
+                                       u8 action_code;
+                                       u8 membership[WLAN_MEMBERSHIP_LEN];
+                                       u8 position[WLAN_USER_POSITION_LEN];
+                               } __packed vht_group_notif;
                                struct {
                                        u8 action_code;
                                        u8 dialog_token;
@@ -1498,6 +1513,7 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895                 0x00000000
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991                 0x00000001
 #define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454                        0x00000002
+#define IEEE80211_VHT_CAP_MAX_MPDU_MASK                                0x00000003
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ               0x00000004
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ      0x00000008
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK                 0x0000000C
@@ -2079,6 +2095,16 @@ enum ieee80211_tdls_actioncode {
 #define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED    BIT(5)
 #define WLAN_EXT_CAPA8_OPMODE_NOTIF    BIT(6)
 
+/* Defines the maximal number of MSDUs in an A-MSDU. */
+#define WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB   BIT(7)
+#define WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB   BIT(0)
+
+/*
+ * Fine Timing Measurement Initiator - bit 71 of @WLAN_EID_EXT_CAPABILITY
+ * information element
+ */
+#define WLAN_EXT_CAPA9_FTM_INITIATOR   BIT(7)
+
 /* TDLS specific payload type in the LLC/SNAP header */
 #define WLAN_TDLS_SNAP_RFTYPE  0x2
 
index a338a688ee4a4237eb938ff71627bbd5aafa442a..dcb89e3515db93d0359b726d60eccca918a0a707 100644 (file)
@@ -46,10 +46,6 @@ struct br_ip_list {
 #define BR_LEARNING_SYNC       BIT(9)
 #define BR_PROXYARP_WIFI       BIT(10)
 
-/* values as per ieee8021QBridgeFdbAgingTime */
-#define BR_MIN_AGEING_TIME     (10 * HZ)
-#define BR_MAX_AGEING_TIME     (1000000 * HZ)
-
 #define BR_DEFAULT_AGEING_TIME (300 * HZ)
 
 extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h
deleted file mode 100644 (file)
index 9a715cf..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- *  linux/include/linux/inet_lro.h
- *
- *  Large Receive Offload (ipv4 / tcp)
- *
- *  (C) Copyright IBM Corp. 2007
- *
- *  Authors:
- *       Jan-Bernd Themann <themann@de.ibm.com>
- *       Christoph Raisch <raisch@de.ibm.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __INET_LRO_H_
-#define __INET_LRO_H_
-
-#include <net/ip.h>
-#include <net/tcp.h>
-
-/*
- * LRO statistics
- */
-
-struct net_lro_stats {
-       unsigned long aggregated;
-       unsigned long flushed;
-       unsigned long no_desc;
-};
-
-/*
- * LRO descriptor for a tcp session
- */
-struct net_lro_desc {
-       struct sk_buff *parent;
-       struct sk_buff *last_skb;
-       struct skb_frag_struct *next_frag;
-       struct iphdr *iph;
-       struct tcphdr *tcph;
-       __wsum  data_csum;
-       __be32 tcp_rcv_tsecr;
-       __be32 tcp_rcv_tsval;
-       __be32 tcp_ack;
-       u32 tcp_next_seq;
-       u32 skb_tot_frags_len;
-       u16 ip_tot_len;
-       u16 tcp_saw_tstamp;             /* timestamps enabled */
-       __be16 tcp_window;
-       int pkt_aggr_cnt;               /* counts aggregated packets */
-       int vlan_packet;
-       int mss;
-       int active;
-};
-
-/*
- * Large Receive Offload (LRO) Manager
- *
- * Fields must be set by driver
- */
-
-struct net_lro_mgr {
-       struct net_device *dev;
-       struct net_lro_stats stats;
-
-       /* LRO features */
-       unsigned long features;
-#define LRO_F_NAPI            1  /* Pass packets to stack via NAPI */
-#define LRO_F_EXTRACT_VLAN_ID 2  /* Set flag if VLAN IDs are extracted
-                                   from received packets and eth protocol
-                                   is still ETH_P_8021Q */
-
-       /*
-        * Set for generated SKBs that are not added to
-        * the frag list in fragmented mode
-        */
-       u32 ip_summed;
-       u32 ip_summed_aggr; /* Set in aggregated SKBs: CHECKSUM_UNNECESSARY
-                            * or CHECKSUM_NONE */
-
-       int max_desc; /* Max number of LRO descriptors  */
-       int max_aggr; /* Max number of LRO packets to be aggregated */
-
-       int frag_align_pad; /* Padding required to properly align layer 3
-                            * headers in generated skb when using frags */
-
-       struct net_lro_desc *lro_arr; /* Array of LRO descriptors */
-
-       /*
-        * Optimized driver functions
-        *
-        * get_skb_header: returns tcp and ip header for packet in SKB
-        */
-       int (*get_skb_header)(struct sk_buff *skb, void **ip_hdr,
-                             void **tcpudp_hdr, u64 *hdr_flags, void *priv);
-
-       /* hdr_flags: */
-#define LRO_IPV4 1 /* ip_hdr is IPv4 header */
-#define LRO_TCP  2 /* tcpudp_hdr is TCP header */
-
-       /*
-        * get_frag_header: returns mac, tcp and ip header for packet in SKB
-        *
-        * @hdr_flags: Indicate what kind of LRO has to be done
-        *             (IPv4/IPv6/TCP/UDP)
-        */
-       int (*get_frag_header)(struct skb_frag_struct *frag, void **mac_hdr,
-                              void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
-                              void *priv);
-};
-
-/*
- * Processes a SKB
- *
- * @lro_mgr: LRO manager to use
- * @skb: SKB to aggregate
- * @priv: Private data that may be used by driver functions
- *        (for example get_tcp_ip_hdr)
- */
-
-void lro_receive_skb(struct net_lro_mgr *lro_mgr,
-                    struct sk_buff *skb,
-                    void *priv);
-/*
- * Forward all aggregated SKBs held by lro_mgr to network stack
- */
-
-void lro_flush_all(struct net_lro_mgr *lro_mgr);
-
-#endif
index 821273ca4873b147136f46f235d83b344b192373..2d9b650047a5b96582f66dff2b2581cce97c2b65 100644 (file)
@@ -235,6 +235,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 /* low 64 bit */
 #define dma_frcd_page_addr(d) (d & (((u64)-1) << PAGE_SHIFT))
 
+/* PRS_REG */
+#define DMA_PRS_PPR    ((u32)1)
+
 #define IOMMU_WAIT_OP(iommu, offset, op, cond, sts)                    \
 do {                                                                   \
        cycles_t start_time = get_cycles();                             \
index 4b2267e1b7c3300487b0dffab84326d259fb3822..7edc14fb66b6870298b7927e0727931d72342c1b 100644 (file)
@@ -62,6 +62,7 @@ struct ipv6_devconf {
                struct in6_addr secret;
        } stable_secret;
        __s32           use_oif_addrs_only;
+       __s32           keep_addr_on_down;
        void            *sysctl;
 };
 
index f31638c6e8738230edebe2606ff27d8782fc1a19..ac19239572366e05fb6fb194f9bde779c9c43186 100644 (file)
@@ -64,7 +64,7 @@
 #define round_down(x, y) ((x) & ~__round_mask(x, y))
 
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP
 #define DIV_ROUND_UP_ULL(ll,d) \
        ({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; })
 
index 851821bfd55321dce527f4b32e03d1534994678a..2c4ebef79d0c61b596efed901eb834d8a436492d 100644 (file)
@@ -526,6 +526,7 @@ enum ata_lpm_policy {
 enum ata_lpm_hints {
        ATA_LPM_EMPTY           = (1 << 0), /* port empty/probing */
        ATA_LPM_HIPM            = (1 << 1), /* may use HIPM */
+       ATA_LPM_WAKE_ONLY       = (1 << 2), /* only wake up link */
 };
 
 /* forward declarations */
@@ -719,7 +720,7 @@ struct ata_device {
        union {
                u16             id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
                u32             gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
-       };
+       } ____cacheline_aligned;
 
        /* DEVSLP Timing Variables from Identify Device Data Log */
        u8                      devslp_timing[ATA_LOG_DEVSLP_SIZE];
index bed40dff0e86999b5c39c82ebadc29f25e0060ec..141ffdd59960d7b31583f629140b0f7dd9916b37 100644 (file)
@@ -26,9 +26,8 @@ enum {
 
        /* need to set a limit somewhere, but yes, this is likely overkill */
        ND_IOCTL_MAX_BUFLEN = SZ_4M,
-       ND_CMD_MAX_ELEM = 4,
+       ND_CMD_MAX_ELEM = 5,
        ND_CMD_MAX_ENVELOPE = 16,
-       ND_CMD_ARS_STATUS_MAX = SZ_4K,
        ND_MAX_MAPPINGS = 32,
 
        /* region flag indicating to direct-map persistent memory by default */
index d6750111e48ecc4603dbc5f28eb01f2810ed6303..2190419bdf0a04e549b64946037d8d61fd025781 100644 (file)
@@ -135,6 +135,10 @@ enum {
        /* Memory types */
        NVM_ID_FMTYPE_SLC       = 0,
        NVM_ID_FMTYPE_MLC       = 1,
+
+       /* Device capabilities */
+       NVM_ID_DCAP_BBLKMGMT    = 0x1,
+       NVM_UD_DCAP_ECC         = 0x2,
 };
 
 struct nvm_id_lp_mlc {
index c57e424d914b70fc5032f9b6d1ec918e8e195c64..4dca42fd32f52d17326e436c4d9fcbd86a0e8d24 100644 (file)
@@ -66,7 +66,7 @@ struct lock_class {
        /*
         * class-hash:
         */
-       struct list_head                hash_entry;
+       struct hlist_node               hash_entry;
 
        /*
         * global list of all lock-classes:
@@ -199,7 +199,7 @@ struct lock_chain {
        u8                              irq_context;
        u8                              depth;
        u16                             base;
-       struct list_head                entry;
+       struct hlist_node               entry;
        u64                             chain_key;
 };
 
index 9ae48d4aeb5ec7d6fafa9528c79f65f62a091ed3..792c8981e63365b06a03e7feda7e647eafb533c0 100644 (file)
@@ -51,7 +51,7 @@ enum mem_cgroup_stat_index {
        MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
        MEM_CGROUP_STAT_NSTATS,
        /* default hierarchy stats */
-       MEMCG_SOCK,
+       MEMCG_SOCK = MEM_CGROUP_STAT_NSTATS,
        MEMCG_NR_STAT,
 };
 
index 430a929f048b3d2f27d1e842f45e80f9e9e6347a..a0e8cc8dcc67dcc88e7d32ab47a8ef22af52c946 100644 (file)
@@ -44,6 +44,8 @@
 
 #include <linux/timecounter.h>
 
+#define DEFAULT_UAR_PAGE_SHIFT  12
+
 #define MAX_MSIX_P_PORT                17
 #define MAX_MSIX               64
 #define MIN_MSIX_P_PORT                5
@@ -856,6 +858,7 @@ struct mlx4_dev {
        u64                     regid_promisc_array[MLX4_MAX_PORTS + 1];
        u64                     regid_allmulti_array[MLX4_MAX_PORTS + 1];
        struct mlx4_vf_dev     *dev_vfs;
+       u8  uar_page_shift;
 };
 
 struct mlx4_clock_params {
@@ -1528,4 +1531,14 @@ int mlx4_ACCESS_PTYS_REG(struct mlx4_dev *dev,
 int mlx4_get_internal_clock_params(struct mlx4_dev *dev,
                                   struct mlx4_clock_params *params);
 
+static inline int mlx4_to_hw_uar_index(struct mlx4_dev *dev, int index)
+{
+       return (index << (PAGE_SHIFT - dev->uar_page_shift));
+}
+
+static inline int mlx4_get_num_reserved_uar(struct mlx4_dev *dev)
+{
+       /* The first 128 UARs are used for EQ doorbells */
+       return (128 >> (PAGE_SHIFT - dev->uar_page_shift));
+}
 #endif /* MLX4_DEVICE_H */
index 2e8af001c5dadb9ac4888d11840f4a27e1b22a5d..bd0e7075ea6dfb78fd606fbaf0a9a41dc8839946 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef MLX4_DRIVER_H
 #define MLX4_DRIVER_H
 
+#include <net/devlink.h>
 #include <linux/mlx4/device.h>
 
 struct mlx4_dev;
@@ -89,6 +90,8 @@ int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p);
 
 void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port);
 
+struct devlink_port *mlx4_get_devlink_port(struct mlx4_dev *dev, int port);
+
 static inline u64 mlx4_mac_to_u64(u8 *addr)
 {
        u64 mac = 0;
index 987764afa65c2344d5a85328f9f35a419e21db64..68a56bc37df28783bdda30996c1b3f16ece01c49 100644 (file)
@@ -350,6 +350,12 @@ enum {
        MLX5_SET_PORT_PKEY_TABLE        = 20,
 };
 
+enum {
+       MLX5_BW_NO_LIMIT   = 0,
+       MLX5_100_MBPS_UNIT = 3,
+       MLX5_GBPS_UNIT     = 4,
+};
+
 enum {
        MLX5_MAX_PAGE_SHIFT             = 31
 };
@@ -1177,6 +1183,17 @@ enum {
        MLX5_RQC_RQ_TYPE_MEMORY_RQ_RPM    = 0x1,
 };
 
+enum mlx5_wol_mode {
+       MLX5_WOL_DISABLE        = 0,
+       MLX5_WOL_SECURED_MAGIC  = 1 << 1,
+       MLX5_WOL_MAGIC          = 1 << 2,
+       MLX5_WOL_ARP            = 1 << 3,
+       MLX5_WOL_BROADCAST      = 1 << 4,
+       MLX5_WOL_MULTICAST      = 1 << 5,
+       MLX5_WOL_UNICAST        = 1 << 6,
+       MLX5_WOL_PHY_ACTIVITY   = 1 << 7,
+};
+
 /* MLX5 DEV CAPs */
 
 /* TODO: EAT.ME */
index 1e3006dcf35d735175ebe054d8867f89b994231c..bb1a880a5bc537c517ed082bf6386b65009e976c 100644 (file)
@@ -54,7 +54,7 @@ enum {
        /* one minute for the sake of bringup. Generally, commands must always
         * complete and we may need to increase this timeout value
         */
-       MLX5_CMD_TIMEOUT_MSEC   = 7200 * 1000,
+       MLX5_CMD_TIMEOUT_MSEC   = 60 * 1000,
        MLX5_CMD_WQ_MAX_NAME    = 32,
 };
 
@@ -99,6 +99,8 @@ enum {
 };
 
 enum {
+       MLX5_REG_QETCR           = 0x4005,
+       MLX5_REG_QTCT            = 0x400a,
        MLX5_REG_PCAP            = 0x5001,
        MLX5_REG_PMTU            = 0x5003,
        MLX5_REG_PTYS            = 0x5004,
@@ -458,8 +460,6 @@ struct mlx5_priv {
        struct mlx5_uuar_info   uuari;
        MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock);
 
-       struct io_mapping       *bf_mapping;
-
        /* pages stuff */
        struct workqueue_struct *pg_wq;
        struct rb_root          page_root;
@@ -717,7 +717,8 @@ int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn);
 int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn);
 int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
 int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari);
-int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar);
+int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar,
+                      bool map_wc);
 void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar);
 void mlx5_health_cleanup(struct mlx5_core_dev *dev);
 int mlx5_health_init(struct mlx5_core_dev *dev);
@@ -794,37 +795,6 @@ int mlx5_core_access_reg(struct mlx5_core_dev *dev, void *data_in,
                         int size_in, void *data_out, int size_out,
                         u16 reg_num, int arg, int write);
 
-int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
-int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
-                        int ptys_size, int proto_mask, u8 local_port);
-int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
-                             u32 *proto_cap, int proto_mask);
-int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
-                               u32 *proto_admin, int proto_mask);
-int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
-                                   u8 *link_width_oper, u8 local_port);
-int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
-                              u8 *proto_oper, int proto_mask,
-                              u8 local_port);
-int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
-                       int proto_mask);
-int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
-                              enum mlx5_port_status status);
-int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
-                                enum mlx5_port_status *status);
-
-int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port);
-void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 port);
-void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
-                             u8 port);
-
-int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
-                             u8 *vl_hw_cap, u8 local_port);
-
-int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause);
-int mlx5_query_port_pause(struct mlx5_core_dev *dev,
-                         u32 *rx_pause, u32 *tx_pause);
-
 int mlx5_debug_eq_add(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 void mlx5_debug_eq_remove(struct mlx5_core_dev *dev, struct mlx5_eq *eq);
 int mlx5_core_eq_query(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
index 231ab6bcea76356ecf6539513fc210fe1e208451..9d91ce39eb0f0e9b43f5927c77a3cd5908a35bc7 100644 (file)
@@ -166,6 +166,8 @@ enum {
        MLX5_CMD_OP_SET_L2_TABLE_ENTRY            = 0x829,
        MLX5_CMD_OP_QUERY_L2_TABLE_ENTRY          = 0x82a,
        MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY         = 0x82b,
+       MLX5_CMD_OP_SET_WOL_ROL                   = 0x830,
+       MLX5_CMD_OP_QUERY_WOL_ROL                 = 0x831,
        MLX5_CMD_OP_CREATE_TIR                    = 0x900,
        MLX5_CMD_OP_MODIFY_TIR                    = 0x901,
        MLX5_CMD_OP_DESTROY_TIR                   = 0x902,
@@ -207,15 +209,15 @@ struct mlx5_ifc_flow_table_fields_supported_bits {
        u8         outer_dmac[0x1];
        u8         outer_smac[0x1];
        u8         outer_ether_type[0x1];
-       u8         reserved_0[0x1];
+       u8         reserved_at_3[0x1];
        u8         outer_first_prio[0x1];
        u8         outer_first_cfi[0x1];
        u8         outer_first_vid[0x1];
-       u8         reserved_1[0x1];
+       u8         reserved_at_7[0x1];
        u8         outer_second_prio[0x1];
        u8         outer_second_cfi[0x1];
        u8         outer_second_vid[0x1];
-       u8         reserved_2[0x1];
+       u8         reserved_at_b[0x1];
        u8         outer_sip[0x1];
        u8         outer_dip[0x1];
        u8         outer_frag[0x1];
@@ -230,21 +232,21 @@ struct mlx5_ifc_flow_table_fields_supported_bits {
        u8         outer_gre_protocol[0x1];
        u8         outer_gre_key[0x1];
        u8         outer_vxlan_vni[0x1];
-       u8         reserved_3[0x5];
+       u8         reserved_at_1a[0x5];
        u8         source_eswitch_port[0x1];
 
        u8         inner_dmac[0x1];
        u8         inner_smac[0x1];
        u8         inner_ether_type[0x1];
-       u8         reserved_4[0x1];
+       u8         reserved_at_23[0x1];
        u8         inner_first_prio[0x1];
        u8         inner_first_cfi[0x1];
        u8         inner_first_vid[0x1];
-       u8         reserved_5[0x1];
+       u8         reserved_at_27[0x1];
        u8         inner_second_prio[0x1];
        u8         inner_second_cfi[0x1];
        u8         inner_second_vid[0x1];
-       u8         reserved_6[0x1];
+       u8         reserved_at_2b[0x1];
        u8         inner_sip[0x1];
        u8         inner_dip[0x1];
        u8         inner_frag[0x1];
@@ -256,37 +258,37 @@ struct mlx5_ifc_flow_table_fields_supported_bits {
        u8         inner_tcp_sport[0x1];
        u8         inner_tcp_dport[0x1];
        u8         inner_tcp_flags[0x1];
-       u8         reserved_7[0x9];
+       u8         reserved_at_37[0x9];
 
-       u8         reserved_8[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_flow_table_prop_layout_bits {
        u8         ft_support[0x1];
-       u8         reserved_0[0x2];
+       u8         reserved_at_1[0x2];
        u8         flow_modify_en[0x1];
        u8         modify_root[0x1];
        u8         identified_miss_table_mode[0x1];
        u8         flow_table_modify[0x1];
-       u8         reserved_1[0x19];
+       u8         reserved_at_7[0x19];
 
-       u8         reserved_2[0x2];
+       u8         reserved_at_20[0x2];
        u8         log_max_ft_size[0x6];
-       u8         reserved_3[0x10];
+       u8         reserved_at_28[0x10];
        u8         max_ft_level[0x8];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_5[0x18];
+       u8         reserved_at_60[0x18];
        u8         log_max_ft_num[0x8];
 
-       u8         reserved_6[0x18];
+       u8         reserved_at_80[0x18];
        u8         log_max_destination[0x8];
 
-       u8         reserved_7[0x18];
+       u8         reserved_at_a0[0x18];
        u8         log_max_flow[0x8];
 
-       u8         reserved_8[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_flow_table_fields_supported_bits ft_field_support;
 
@@ -298,13 +300,13 @@ struct mlx5_ifc_odp_per_transport_service_cap_bits {
        u8         receive[0x1];
        u8         write[0x1];
        u8         read[0x1];
-       u8         reserved_0[0x1];
+       u8         reserved_at_4[0x1];
        u8         srq_receive[0x1];
-       u8         reserved_1[0x1a];
+       u8         reserved_at_6[0x1a];
 };
 
 struct mlx5_ifc_ipv4_layout_bits {
-       u8         reserved_0[0x60];
+       u8         reserved_at_0[0x60];
 
        u8         ipv4[0x20];
 };
@@ -316,7 +318,7 @@ struct mlx5_ifc_ipv6_layout_bits {
 union mlx5_ifc_ipv6_layout_ipv4_layout_auto_bits {
        struct mlx5_ifc_ipv6_layout_bits ipv6_layout;
        struct mlx5_ifc_ipv4_layout_bits ipv4_layout;
-       u8         reserved_0[0x80];
+       u8         reserved_at_0[0x80];
 };
 
 struct mlx5_ifc_fte_match_set_lyr_2_4_bits {
@@ -336,15 +338,15 @@ struct mlx5_ifc_fte_match_set_lyr_2_4_bits {
        u8         ip_dscp[0x6];
        u8         ip_ecn[0x2];
        u8         vlan_tag[0x1];
-       u8         reserved_0[0x1];
+       u8         reserved_at_91[0x1];
        u8         frag[0x1];
-       u8         reserved_1[0x4];
+       u8         reserved_at_93[0x4];
        u8         tcp_flags[0x9];
 
        u8         tcp_sport[0x10];
        u8         tcp_dport[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_c0[0x20];
 
        u8         udp_sport[0x10];
        u8         udp_dport[0x10];
@@ -355,9 +357,9 @@ struct mlx5_ifc_fte_match_set_lyr_2_4_bits {
 };
 
 struct mlx5_ifc_fte_match_set_misc_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         source_port[0x10];
 
        u8         outer_second_prio[0x3];
@@ -369,31 +371,31 @@ struct mlx5_ifc_fte_match_set_misc_bits {
 
        u8         outer_second_vlan_tag[0x1];
        u8         inner_second_vlan_tag[0x1];
-       u8         reserved_2[0xe];
+       u8         reserved_at_62[0xe];
        u8         gre_protocol[0x10];
 
        u8         gre_key_h[0x18];
        u8         gre_key_l[0x8];
 
        u8         vxlan_vni[0x18];
-       u8         reserved_3[0x8];
+       u8         reserved_at_b8[0x8];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_c0[0x20];
 
-       u8         reserved_5[0xc];
+       u8         reserved_at_e0[0xc];
        u8         outer_ipv6_flow_label[0x14];
 
-       u8         reserved_6[0xc];
+       u8         reserved_at_100[0xc];
        u8         inner_ipv6_flow_label[0x14];
 
-       u8         reserved_7[0xe0];
+       u8         reserved_at_120[0xe0];
 };
 
 struct mlx5_ifc_cmd_pas_bits {
        u8         pa_h[0x20];
 
        u8         pa_l[0x14];
-       u8         reserved_0[0xc];
+       u8         reserved_at_34[0xc];
 };
 
 struct mlx5_ifc_uint64_bits {
@@ -418,31 +420,31 @@ enum {
 struct mlx5_ifc_ads_bits {
        u8         fl[0x1];
        u8         free_ar[0x1];
-       u8         reserved_0[0xe];
+       u8         reserved_at_2[0xe];
        u8         pkey_index[0x10];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_20[0x8];
        u8         grh[0x1];
        u8         mlid[0x7];
        u8         rlid[0x10];
 
        u8         ack_timeout[0x5];
-       u8         reserved_2[0x3];
+       u8         reserved_at_45[0x3];
        u8         src_addr_index[0x8];
-       u8         reserved_3[0x4];
+       u8         reserved_at_50[0x4];
        u8         stat_rate[0x4];
        u8         hop_limit[0x8];
 
-       u8         reserved_4[0x4];
+       u8         reserved_at_60[0x4];
        u8         tclass[0x8];
        u8         flow_label[0x14];
 
        u8         rgid_rip[16][0x8];
 
-       u8         reserved_5[0x4];
+       u8         reserved_at_100[0x4];
        u8         f_dscp[0x1];
        u8         f_ecn[0x1];
-       u8         reserved_6[0x1];
+       u8         reserved_at_106[0x1];
        u8         f_eth_prio[0x1];
        u8         ecn[0x2];
        u8         dscp[0x6];
@@ -458,25 +460,25 @@ struct mlx5_ifc_ads_bits {
 };
 
 struct mlx5_ifc_flow_table_nic_cap_bits {
-       u8         reserved_0[0x200];
+       u8         reserved_at_0[0x200];
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive;
 
-       u8         reserved_1[0x200];
+       u8         reserved_at_400[0x200];
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_receive_sniffer;
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit;
 
-       u8         reserved_2[0x200];
+       u8         reserved_at_a00[0x200];
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_transmit_sniffer;
 
-       u8         reserved_3[0x7200];
+       u8         reserved_at_e00[0x7200];
 };
 
 struct mlx5_ifc_flow_table_eswitch_cap_bits {
-       u8     reserved_0[0x200];
+       u8     reserved_at_0[0x200];
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_nic_esw_fdb;
 
@@ -484,7 +486,7 @@ struct mlx5_ifc_flow_table_eswitch_cap_bits {
 
        struct mlx5_ifc_flow_table_prop_layout_bits flow_table_properties_esw_acl_egress;
 
-       u8      reserved_1[0x7800];
+       u8      reserved_at_800[0x7800];
 };
 
 struct mlx5_ifc_e_switch_cap_bits {
@@ -493,9 +495,9 @@ struct mlx5_ifc_e_switch_cap_bits {
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_insert_if_not_exist[0x1];
        u8         vport_cvlan_insert_overwrite[0x1];
-       u8         reserved_0[0x1b];
+       u8         reserved_at_5[0x1b];
 
-       u8         reserved_1[0x7e0];
+       u8         reserved_at_20[0x7e0];
 };
 
 struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
@@ -504,51 +506,51 @@ struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
        u8         lro_cap[0x1];
        u8         lro_psh_flag[0x1];
        u8         lro_time_stamp[0x1];
-       u8         reserved_0[0x3];
+       u8         reserved_at_5[0x3];
        u8         self_lb_en_modifiable[0x1];
-       u8         reserved_1[0x2];
+       u8         reserved_at_9[0x2];
        u8         max_lso_cap[0x5];
-       u8         reserved_2[0x4];
+       u8         reserved_at_10[0x4];
        u8         rss_ind_tbl_cap[0x4];
-       u8         reserved_3[0x3];
+       u8         reserved_at_18[0x3];
        u8         tunnel_lso_const_out_ip_id[0x1];
-       u8         reserved_4[0x2];
+       u8         reserved_at_1c[0x2];
        u8         tunnel_statless_gre[0x1];
        u8         tunnel_stateless_vxlan[0x1];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_6[0x10];
+       u8         reserved_at_40[0x10];
        u8         lro_min_mss_size[0x10];
 
-       u8         reserved_7[0x120];
+       u8         reserved_at_60[0x120];
 
        u8         lro_timer_supported_periods[4][0x20];
 
-       u8         reserved_8[0x600];
+       u8         reserved_at_200[0x600];
 };
 
 struct mlx5_ifc_roce_cap_bits {
        u8         roce_apm[0x1];
-       u8         reserved_0[0x1f];
+       u8         reserved_at_1[0x1f];
 
-       u8         reserved_1[0x60];
+       u8         reserved_at_20[0x60];
 
-       u8         reserved_2[0xc];
+       u8         reserved_at_80[0xc];
        u8         l3_type[0x4];
-       u8         reserved_3[0x8];
+       u8         reserved_at_90[0x8];
        u8         roce_version[0x8];
 
-       u8         reserved_4[0x10];
+       u8         reserved_at_a0[0x10];
        u8         r_roce_dest_udp_port[0x10];
 
        u8         r_roce_max_src_udp_port[0x10];
        u8         r_roce_min_src_udp_port[0x10];
 
-       u8         reserved_5[0x10];
+       u8         reserved_at_e0[0x10];
        u8         roce_address_table_size[0x10];
 
-       u8         reserved_6[0x700];
+       u8         reserved_at_100[0x700];
 };
 
 enum {
@@ -576,35 +578,35 @@ enum {
 };
 
 struct mlx5_ifc_atomic_caps_bits {
-       u8         reserved_0[0x40];
+       u8         reserved_at_0[0x40];
 
        u8         atomic_req_8B_endianess_mode[0x2];
-       u8         reserved_1[0x4];
+       u8         reserved_at_42[0x4];
        u8         supported_atomic_req_8B_endianess_mode_1[0x1];
 
-       u8         reserved_2[0x19];
+       u8         reserved_at_47[0x19];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
-       u8         reserved_4[0x10];
+       u8         reserved_at_80[0x10];
        u8         atomic_operations[0x10];
 
-       u8         reserved_5[0x10];
+       u8         reserved_at_a0[0x10];
        u8         atomic_size_qp[0x10];
 
-       u8         reserved_6[0x10];
+       u8         reserved_at_c0[0x10];
        u8         atomic_size_dc[0x10];
 
-       u8         reserved_7[0x720];
+       u8         reserved_at_e0[0x720];
 };
 
 struct mlx5_ifc_odp_cap_bits {
-       u8         reserved_0[0x40];
+       u8         reserved_at_0[0x40];
 
        u8         sig[0x1];
-       u8         reserved_1[0x1f];
+       u8         reserved_at_41[0x1f];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_odp_per_transport_service_cap_bits rc_odp_caps;
 
@@ -612,7 +614,7 @@ struct mlx5_ifc_odp_cap_bits {
 
        struct mlx5_ifc_odp_per_transport_service_cap_bits ud_odp_caps;
 
-       u8         reserved_3[0x720];
+       u8         reserved_at_e0[0x720];
 };
 
 enum {
@@ -660,55 +662,55 @@ enum {
 };
 
 struct mlx5_ifc_cmd_hca_cap_bits {
-       u8         reserved_0[0x80];
+       u8         reserved_at_0[0x80];
 
        u8         log_max_srq_sz[0x8];
        u8         log_max_qp_sz[0x8];
-       u8         reserved_1[0xb];
+       u8         reserved_at_90[0xb];
        u8         log_max_qp[0x5];
 
-       u8         reserved_2[0xb];
+       u8         reserved_at_a0[0xb];
        u8         log_max_srq[0x5];
-       u8         reserved_3[0x10];
+       u8         reserved_at_b0[0x10];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_c0[0x8];
        u8         log_max_cq_sz[0x8];
-       u8         reserved_5[0xb];
+       u8         reserved_at_d0[0xb];
        u8         log_max_cq[0x5];
 
        u8         log_max_eq_sz[0x8];
-       u8         reserved_6[0x2];
+       u8         reserved_at_e8[0x2];
        u8         log_max_mkey[0x6];
-       u8         reserved_7[0xc];
+       u8         reserved_at_f0[0xc];
        u8         log_max_eq[0x4];
 
        u8         max_indirection[0x8];
-       u8         reserved_8[0x1];
+       u8         reserved_at_108[0x1];
        u8         log_max_mrw_sz[0x7];
-       u8         reserved_9[0x2];
+       u8         reserved_at_110[0x2];
        u8         log_max_bsf_list_size[0x6];
-       u8         reserved_10[0x2];
+       u8         reserved_at_118[0x2];
        u8         log_max_klm_list_size[0x6];
 
-       u8         reserved_11[0xa];
+       u8         reserved_at_120[0xa];
        u8         log_max_ra_req_dc[0x6];
-       u8         reserved_12[0xa];
+       u8         reserved_at_130[0xa];
        u8         log_max_ra_res_dc[0x6];
 
-       u8         reserved_13[0xa];
+       u8         reserved_at_140[0xa];
        u8         log_max_ra_req_qp[0x6];
-       u8         reserved_14[0xa];
+       u8         reserved_at_150[0xa];
        u8         log_max_ra_res_qp[0x6];
 
        u8         pad_cap[0x1];
        u8         cc_query_allowed[0x1];
        u8         cc_modify_allowed[0x1];
-       u8         reserved_15[0xd];
+       u8         reserved_at_163[0xd];
        u8         gid_table_size[0x10];
 
        u8         out_of_seq_cnt[0x1];
        u8         vport_counters[0x1];
-       u8         reserved_16[0x4];
+       u8         reserved_at_182[0x4];
        u8         max_qp_cnt[0xa];
        u8         pkey_table_size[0x10];
 
@@ -716,158 +718,170 @@ struct mlx5_ifc_cmd_hca_cap_bits {
        u8         vhca_group_manager[0x1];
        u8         ib_virt[0x1];
        u8         eth_virt[0x1];
-       u8         reserved_17[0x1];
+       u8         reserved_at_1a4[0x1];
        u8         ets[0x1];
        u8         nic_flow_table[0x1];
        u8         eswitch_flow_table[0x1];
        u8         early_vf_enable;
-       u8         reserved_18[0x2];
+       u8         reserved_at_1a8[0x2];
        u8         local_ca_ack_delay[0x5];
-       u8         reserved_19[0x6];
+       u8         reserved_at_1af[0x6];
        u8         port_type[0x2];
        u8         num_ports[0x8];
 
-       u8         reserved_20[0x3];
+       u8         reserved_at_1bf[0x3];
        u8         log_max_msg[0x5];
-       u8         reserved_21[0x18];
+       u8         reserved_at_1c7[0x4];
+       u8         max_tc[0x4];
+       u8         reserved_at_1cf[0x6];
+       u8         rol_s[0x1];
+       u8         rol_g[0x1];
+       u8         reserved_at_1d7[0x1];
+       u8         wol_s[0x1];
+       u8         wol_g[0x1];
+       u8         wol_a[0x1];
+       u8         wol_b[0x1];
+       u8         wol_m[0x1];
+       u8         wol_u[0x1];
+       u8         wol_p[0x1];
 
        u8         stat_rate_support[0x10];
-       u8         reserved_22[0xc];
+       u8         reserved_at_1ef[0xc];
        u8         cqe_version[0x4];
 
        u8         compact_address_vector[0x1];
-       u8         reserved_23[0xe];
+       u8         reserved_at_200[0xe];
        u8         drain_sigerr[0x1];
        u8         cmdif_checksum[0x2];
        u8         sigerr_cqe[0x1];
-       u8         reserved_24[0x1];
+       u8         reserved_at_212[0x1];
        u8         wq_signature[0x1];
        u8         sctr_data_cqe[0x1];
-       u8         reserved_25[0x1];
+       u8         reserved_at_215[0x1];
        u8         sho[0x1];
        u8         tph[0x1];
        u8         rf[0x1];
        u8         dct[0x1];
-       u8         reserved_26[0x1];
+       u8         reserved_at_21a[0x1];
        u8         eth_net_offloads[0x1];
        u8         roce[0x1];
        u8         atomic[0x1];
-       u8         reserved_27[0x1];
+       u8         reserved_at_21e[0x1];
 
        u8         cq_oi[0x1];
        u8         cq_resize[0x1];
        u8         cq_moderation[0x1];
-       u8         reserved_28[0x3];
+       u8         reserved_at_222[0x3];
        u8         cq_eq_remap[0x1];
        u8         pg[0x1];
        u8         block_lb_mc[0x1];
-       u8         reserved_29[0x1];
+       u8         reserved_at_228[0x1];
        u8         scqe_break_moderation[0x1];
-       u8         reserved_30[0x1];
+       u8         reserved_at_22a[0x1];
        u8         cd[0x1];
-       u8         reserved_31[0x1];
+       u8         reserved_at_22c[0x1];
        u8         apm[0x1];
-       u8         reserved_32[0x7];
+       u8         reserved_at_22e[0x7];
        u8         qkv[0x1];
        u8         pkv[0x1];
-       u8         reserved_33[0x4];
+       u8         reserved_at_237[0x4];
        u8         xrc[0x1];
        u8         ud[0x1];
        u8         uc[0x1];
        u8         rc[0x1];
 
-       u8         reserved_34[0xa];
+       u8         reserved_at_23f[0xa];
        u8         uar_sz[0x6];
-       u8         reserved_35[0x8];
+       u8         reserved_at_24f[0x8];
        u8         log_pg_sz[0x8];
 
        u8         bf[0x1];
-       u8         reserved_36[0x1];
+       u8         reserved_at_260[0x1];
        u8         pad_tx_eth_packet[0x1];
-       u8         reserved_37[0x8];
+       u8         reserved_at_262[0x8];
        u8         log_bf_reg_size[0x5];
-       u8         reserved_38[0x10];
+       u8         reserved_at_26f[0x10];
 
-       u8         reserved_39[0x10];
+       u8         reserved_at_27f[0x10];
        u8         max_wqe_sz_sq[0x10];
 
-       u8         reserved_40[0x10];
+       u8         reserved_at_29f[0x10];
        u8         max_wqe_sz_rq[0x10];
 
-       u8         reserved_41[0x10];
+       u8         reserved_at_2bf[0x10];
        u8         max_wqe_sz_sq_dc[0x10];
 
-       u8         reserved_42[0x7];
+       u8         reserved_at_2df[0x7];
        u8         max_qp_mcg[0x19];
 
-       u8         reserved_43[0x18];
+       u8         reserved_at_2ff[0x18];
        u8         log_max_mcg[0x8];
 
-       u8         reserved_44[0x3];
+       u8         reserved_at_31f[0x3];
        u8         log_max_transport_domain[0x5];
-       u8         reserved_45[0x3];
+       u8         reserved_at_327[0x3];
        u8         log_max_pd[0x5];
-       u8         reserved_46[0xb];
+       u8         reserved_at_32f[0xb];
        u8         log_max_xrcd[0x5];
 
-       u8         reserved_47[0x20];
+       u8         reserved_at_33f[0x20];
 
-       u8         reserved_48[0x3];
+       u8         reserved_at_35f[0x3];
        u8         log_max_rq[0x5];
-       u8         reserved_49[0x3];
+       u8         reserved_at_367[0x3];
        u8         log_max_sq[0x5];
-       u8         reserved_50[0x3];
+       u8         reserved_at_36f[0x3];
        u8         log_max_tir[0x5];
-       u8         reserved_51[0x3];
+       u8         reserved_at_377[0x3];
        u8         log_max_tis[0x5];
 
        u8         basic_cyclic_rcv_wqe[0x1];
-       u8         reserved_52[0x2];
+       u8         reserved_at_380[0x2];
        u8         log_max_rmp[0x5];
-       u8         reserved_53[0x3];
+       u8         reserved_at_387[0x3];
        u8         log_max_rqt[0x5];
-       u8         reserved_54[0x3];
+       u8         reserved_at_38f[0x3];
        u8         log_max_rqt_size[0x5];
-       u8         reserved_55[0x3];
+       u8         reserved_at_397[0x3];
        u8         log_max_tis_per_sq[0x5];
 
-       u8         reserved_56[0x3];
+       u8         reserved_at_39f[0x3];
        u8         log_max_stride_sz_rq[0x5];
-       u8         reserved_57[0x3];
+       u8         reserved_at_3a7[0x3];
        u8         log_min_stride_sz_rq[0x5];
-       u8         reserved_58[0x3];
+       u8         reserved_at_3af[0x3];
        u8         log_max_stride_sz_sq[0x5];
-       u8         reserved_59[0x3];
+       u8         reserved_at_3b7[0x3];
        u8         log_min_stride_sz_sq[0x5];
 
-       u8         reserved_60[0x1b];
+       u8         reserved_at_3bf[0x1b];
        u8         log_max_wq_sz[0x5];
 
        u8         nic_vport_change_event[0x1];
-       u8         reserved_61[0xa];
+       u8         reserved_at_3e0[0xa];
        u8         log_max_vlan_list[0x5];
-       u8         reserved_62[0x3];
+       u8         reserved_at_3ef[0x3];
        u8         log_max_current_mc_list[0x5];
-       u8         reserved_63[0x3];
+       u8         reserved_at_3f7[0x3];
        u8         log_max_current_uc_list[0x5];
 
-       u8         reserved_64[0x80];
+       u8         reserved_at_3ff[0x80];
 
-       u8         reserved_65[0x3];
+       u8         reserved_at_47f[0x3];
        u8         log_max_l2_table[0x5];
-       u8         reserved_66[0x8];
+       u8         reserved_at_487[0x8];
        u8         log_uar_page_sz[0x10];
 
-       u8         reserved_67[0x20];
+       u8         reserved_at_49f[0x20];
        u8         device_frequency_mhz[0x20];
        u8         device_frequency_khz[0x20];
-       u8         reserved_68[0x5f];
+       u8         reserved_at_4ff[0x5f];
        u8         cqe_zip[0x1];
 
        u8         cqe_zip_timeout[0x10];
        u8         cqe_zip_max_num[0x10];
 
-       u8         reserved_69[0x220];
+       u8         reserved_at_57f[0x220];
 };
 
 enum mlx5_flow_destination_type {
@@ -880,7 +894,7 @@ struct mlx5_ifc_dest_format_struct_bits {
        u8         destination_type[0x8];
        u8         destination_id[0x18];
 
-       u8         reserved_0[0x20];
+       u8         reserved_at_20[0x20];
 };
 
 struct mlx5_ifc_fte_match_param_bits {
@@ -890,7 +904,7 @@ struct mlx5_ifc_fte_match_param_bits {
 
        struct mlx5_ifc_fte_match_set_lyr_2_4_bits inner_headers;
 
-       u8         reserved_0[0xa00];
+       u8         reserved_at_600[0xa00];
 };
 
 enum {
@@ -922,18 +936,18 @@ struct mlx5_ifc_wq_bits {
        u8         wq_signature[0x1];
        u8         end_padding_mode[0x2];
        u8         cd_slave[0x1];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         hds_skip_first_sge[0x1];
        u8         log2_hds_buf_size[0x3];
-       u8         reserved_1[0x7];
+       u8         reserved_at_24[0x7];
        u8         page_offset[0x5];
        u8         lwm[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         pd[0x18];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_60[0x8];
        u8         uar_page[0x18];
 
        u8         dbr_addr[0x40];
@@ -942,60 +956,60 @@ struct mlx5_ifc_wq_bits {
 
        u8         sw_counter[0x20];
 
-       u8         reserved_4[0xc];
+       u8         reserved_at_100[0xc];
        u8         log_wq_stride[0x4];
-       u8         reserved_5[0x3];
+       u8         reserved_at_110[0x3];
        u8         log_wq_pg_sz[0x5];
-       u8         reserved_6[0x3];
+       u8         reserved_at_118[0x3];
        u8         log_wq_sz[0x5];
 
-       u8         reserved_7[0x4e0];
+       u8         reserved_at_120[0x4e0];
 
        struct mlx5_ifc_cmd_pas_bits pas[0];
 };
 
 struct mlx5_ifc_rq_num_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         rq_num[0x18];
 };
 
 struct mlx5_ifc_mac_address_layout_bits {
-       u8         reserved_0[0x10];
+       u8         reserved_at_0[0x10];
        u8         mac_addr_47_32[0x10];
 
        u8         mac_addr_31_0[0x20];
 };
 
 struct mlx5_ifc_vlan_layout_bits {
-       u8         reserved_0[0x14];
+       u8         reserved_at_0[0x14];
        u8         vlan[0x0c];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_20[0x20];
 };
 
 struct mlx5_ifc_cong_control_r_roce_ecn_np_bits {
-       u8         reserved_0[0xa0];
+       u8         reserved_at_0[0xa0];
 
        u8         min_time_between_cnps[0x20];
 
-       u8         reserved_1[0x12];
+       u8         reserved_at_c0[0x12];
        u8         cnp_dscp[0x6];
-       u8         reserved_2[0x5];
+       u8         reserved_at_d8[0x5];
        u8         cnp_802p_prio[0x3];
 
-       u8         reserved_3[0x720];
+       u8         reserved_at_e0[0x720];
 };
 
 struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits {
-       u8         reserved_0[0x60];
+       u8         reserved_at_0[0x60];
 
-       u8         reserved_1[0x4];
+       u8         reserved_at_60[0x4];
        u8         clamp_tgt_rate[0x1];
-       u8         reserved_2[0x3];
+       u8         reserved_at_65[0x3];
        u8         clamp_tgt_rate_after_time_inc[0x1];
-       u8         reserved_3[0x17];
+       u8         reserved_at_69[0x17];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_80[0x20];
 
        u8         rpg_time_reset[0x20];
 
@@ -1015,7 +1029,7 @@ struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits {
 
        u8         rpg_min_rate[0x20];
 
-       u8         reserved_5[0xe0];
+       u8         reserved_at_1c0[0xe0];
 
        u8         rate_to_set_on_first_cnp[0x20];
 
@@ -1025,15 +1039,15 @@ struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits {
 
        u8         rate_reduce_monitor_period[0x20];
 
-       u8         reserved_6[0x20];
+       u8         reserved_at_320[0x20];
 
        u8         initial_alpha_value[0x20];
 
-       u8         reserved_7[0x4a0];
+       u8         reserved_at_360[0x4a0];
 };
 
 struct mlx5_ifc_cong_control_802_1qau_rp_bits {
-       u8         reserved_0[0x80];
+       u8         reserved_at_0[0x80];
 
        u8         rppp_max_rps[0x20];
 
@@ -1055,7 +1069,7 @@ struct mlx5_ifc_cong_control_802_1qau_rp_bits {
 
        u8         rpg_min_rate[0x20];
 
-       u8         reserved_1[0x640];
+       u8         reserved_at_1c0[0x640];
 };
 
 enum {
@@ -1205,7 +1219,7 @@ struct mlx5_ifc_phys_layer_cntrs_bits {
 
        u8         successful_recovery_events[0x20];
 
-       u8         reserved_0[0x180];
+       u8         reserved_at_640[0x180];
 };
 
 struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits {
@@ -1213,7 +1227,7 @@ struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits {
 
        u8         transmit_queue_low[0x20];
 
-       u8         reserved_0[0x780];
+       u8         reserved_at_40[0x780];
 };
 
 struct mlx5_ifc_eth_per_prio_grp_data_layout_bits {
@@ -1221,7 +1235,7 @@ struct mlx5_ifc_eth_per_prio_grp_data_layout_bits {
 
        u8         rx_octets_low[0x20];
 
-       u8         reserved_0[0xc0];
+       u8         reserved_at_40[0xc0];
 
        u8         rx_frames_high[0x20];
 
@@ -1231,7 +1245,7 @@ struct mlx5_ifc_eth_per_prio_grp_data_layout_bits {
 
        u8         tx_octets_low[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_180[0xc0];
 
        u8         tx_frames_high[0x20];
 
@@ -1257,7 +1271,7 @@ struct mlx5_ifc_eth_per_prio_grp_data_layout_bits {
 
        u8         rx_pause_transition_low[0x20];
 
-       u8         reserved_2[0x400];
+       u8         reserved_at_3c0[0x400];
 };
 
 struct mlx5_ifc_eth_extended_cntrs_grp_data_layout_bits {
@@ -1265,7 +1279,7 @@ struct mlx5_ifc_eth_extended_cntrs_grp_data_layout_bits {
 
        u8         port_transmit_wait_low[0x20];
 
-       u8         reserved_0[0x780];
+       u8         reserved_at_40[0x780];
 };
 
 struct mlx5_ifc_eth_3635_cntrs_grp_data_layout_bits {
@@ -1333,7 +1347,7 @@ struct mlx5_ifc_eth_3635_cntrs_grp_data_layout_bits {
 
        u8         dot3out_pause_frames_low[0x20];
 
-       u8         reserved_0[0x3c0];
+       u8         reserved_at_400[0x3c0];
 };
 
 struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits {
@@ -1421,7 +1435,7 @@ struct mlx5_ifc_eth_2819_cntrs_grp_data_layout_bits {
 
        u8         ether_stats_pkts8192to10239octets_low[0x20];
 
-       u8         reserved_0[0x280];
+       u8         reserved_at_540[0x280];
 };
 
 struct mlx5_ifc_eth_2863_cntrs_grp_data_layout_bits {
@@ -1477,7 +1491,7 @@ struct mlx5_ifc_eth_2863_cntrs_grp_data_layout_bits {
 
        u8         if_out_broadcast_pkts_low[0x20];
 
-       u8         reserved_0[0x480];
+       u8         reserved_at_340[0x480];
 };
 
 struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits {
@@ -1557,54 +1571,54 @@ struct mlx5_ifc_eth_802_3_cntrs_grp_data_layout_bits {
 
        u8         a_pause_mac_ctrl_frames_transmitted_low[0x20];
 
-       u8         reserved_0[0x300];
+       u8         reserved_at_4c0[0x300];
 };
 
 struct mlx5_ifc_cmd_inter_comp_event_bits {
        u8         command_completion_vector[0x20];
 
-       u8         reserved_0[0xc0];
+       u8         reserved_at_20[0xc0];
 };
 
 struct mlx5_ifc_stall_vl_event_bits {
-       u8         reserved_0[0x18];
+       u8         reserved_at_0[0x18];
        u8         port_num[0x1];
-       u8         reserved_1[0x3];
+       u8         reserved_at_19[0x3];
        u8         vl[0x4];
 
-       u8         reserved_2[0xa0];
+       u8         reserved_at_20[0xa0];
 };
 
 struct mlx5_ifc_db_bf_congestion_event_bits {
        u8         event_subtype[0x8];
-       u8         reserved_0[0x8];
+       u8         reserved_at_8[0x8];
        u8         congestion_level[0x8];
-       u8         reserved_1[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_2[0xa0];
+       u8         reserved_at_20[0xa0];
 };
 
 struct mlx5_ifc_gpio_event_bits {
-       u8         reserved_0[0x60];
+       u8         reserved_at_0[0x60];
 
        u8         gpio_event_hi[0x20];
 
        u8         gpio_event_lo[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_a0[0x40];
 };
 
 struct mlx5_ifc_port_state_change_event_bits {
-       u8         reserved_0[0x40];
+       u8         reserved_at_0[0x40];
 
        u8         port_num[0x4];
-       u8         reserved_1[0x1c];
+       u8         reserved_at_44[0x1c];
 
-       u8         reserved_2[0x80];
+       u8         reserved_at_60[0x80];
 };
 
 struct mlx5_ifc_dropped_packet_logged_bits {
-       u8         reserved_0[0xe0];
+       u8         reserved_at_0[0xe0];
 };
 
 enum {
@@ -1613,15 +1627,15 @@ enum {
 };
 
 struct mlx5_ifc_cq_error_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         cqn[0x18];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         syndrome[0x8];
 
-       u8         reserved_3[0x80];
+       u8         reserved_at_60[0x80];
 };
 
 struct mlx5_ifc_rdma_page_fault_event_bits {
@@ -1629,14 +1643,14 @@ struct mlx5_ifc_rdma_page_fault_event_bits {
 
        u8         r_key[0x20];
 
-       u8         reserved_0[0x10];
+       u8         reserved_at_40[0x10];
        u8         packet_len[0x10];
 
        u8         rdma_op_len[0x20];
 
        u8         rdma_va[0x40];
 
-       u8         reserved_1[0x5];
+       u8         reserved_at_c0[0x5];
        u8         rdma[0x1];
        u8         write[0x1];
        u8         requestor[0x1];
@@ -1646,15 +1660,15 @@ struct mlx5_ifc_rdma_page_fault_event_bits {
 struct mlx5_ifc_wqe_associated_page_fault_event_bits {
        u8         bytes_committed[0x20];
 
-       u8         reserved_0[0x10];
+       u8         reserved_at_20[0x10];
        u8         wqe_index[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_40[0x10];
        u8         len[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_60[0x60];
 
-       u8         reserved_3[0x5];
+       u8         reserved_at_c0[0x5];
        u8         rdma[0x1];
        u8         write_read[0x1];
        u8         requestor[0x1];
@@ -1662,26 +1676,26 @@ struct mlx5_ifc_wqe_associated_page_fault_event_bits {
 };
 
 struct mlx5_ifc_qp_events_bits {
-       u8         reserved_0[0xa0];
+       u8         reserved_at_0[0xa0];
 
        u8         type[0x8];
-       u8         reserved_1[0x18];
+       u8         reserved_at_a8[0x18];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_c0[0x8];
        u8         qpn_rqn_sqn[0x18];
 };
 
 struct mlx5_ifc_dct_events_bits {
-       u8         reserved_0[0xc0];
+       u8         reserved_at_0[0xc0];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_c0[0x8];
        u8         dct_number[0x18];
 };
 
 struct mlx5_ifc_comp_event_bits {
-       u8         reserved_0[0xc0];
+       u8         reserved_at_0[0xc0];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_c0[0x8];
        u8         cq_number[0x18];
 };
 
@@ -1754,41 +1768,41 @@ enum {
 
 struct mlx5_ifc_qpc_bits {
        u8         state[0x4];
-       u8         reserved_0[0x4];
+       u8         reserved_at_4[0x4];
        u8         st[0x8];
-       u8         reserved_1[0x3];
+       u8         reserved_at_10[0x3];
        u8         pm_state[0x2];
-       u8         reserved_2[0x7];
+       u8         reserved_at_15[0x7];
        u8         end_padding_mode[0x2];
-       u8         reserved_3[0x2];
+       u8         reserved_at_1e[0x2];
 
        u8         wq_signature[0x1];
        u8         block_lb_mc[0x1];
        u8         atomic_like_write_en[0x1];
        u8         latency_sensitive[0x1];
-       u8         reserved_4[0x1];
+       u8         reserved_at_24[0x1];
        u8         drain_sigerr[0x1];
-       u8         reserved_5[0x2];
+       u8         reserved_at_26[0x2];
        u8         pd[0x18];
 
        u8         mtu[0x3];
        u8         log_msg_max[0x5];
-       u8         reserved_6[0x1];
+       u8         reserved_at_48[0x1];
        u8         log_rq_size[0x4];
        u8         log_rq_stride[0x3];
        u8         no_sq[0x1];
        u8         log_sq_size[0x4];
-       u8         reserved_7[0x6];
+       u8         reserved_at_55[0x6];
        u8         rlky[0x1];
-       u8         reserved_8[0x4];
+       u8         reserved_at_5c[0x4];
 
        u8         counter_set_id[0x8];
        u8         uar_page[0x18];
 
-       u8         reserved_9[0x8];
+       u8         reserved_at_80[0x8];
        u8         user_index[0x18];
 
-       u8         reserved_10[0x3];
+       u8         reserved_at_a0[0x3];
        u8         log_page_size[0x5];
        u8         remote_qpn[0x18];
 
@@ -1797,66 +1811,66 @@ struct mlx5_ifc_qpc_bits {
        struct mlx5_ifc_ads_bits secondary_address_path;
 
        u8         log_ack_req_freq[0x4];
-       u8         reserved_11[0x4];
+       u8         reserved_at_384[0x4];
        u8         log_sra_max[0x3];
-       u8         reserved_12[0x2];
+       u8         reserved_at_38b[0x2];
        u8         retry_count[0x3];
        u8         rnr_retry[0x3];
-       u8         reserved_13[0x1];
+       u8         reserved_at_393[0x1];
        u8         fre[0x1];
        u8         cur_rnr_retry[0x3];
        u8         cur_retry_count[0x3];
-       u8         reserved_14[0x5];
+       u8         reserved_at_39b[0x5];
 
-       u8         reserved_15[0x20];
+       u8         reserved_at_3a0[0x20];
 
-       u8         reserved_16[0x8];
+       u8         reserved_at_3c0[0x8];
        u8         next_send_psn[0x18];
 
-       u8         reserved_17[0x8];
+       u8         reserved_at_3e0[0x8];
        u8         cqn_snd[0x18];
 
-       u8         reserved_18[0x40];
+       u8         reserved_at_400[0x40];
 
-       u8         reserved_19[0x8];
+       u8         reserved_at_440[0x8];
        u8         last_acked_psn[0x18];
 
-       u8         reserved_20[0x8];
+       u8         reserved_at_460[0x8];
        u8         ssn[0x18];
 
-       u8         reserved_21[0x8];
+       u8         reserved_at_480[0x8];
        u8         log_rra_max[0x3];
-       u8         reserved_22[0x1];
+       u8         reserved_at_48b[0x1];
        u8         atomic_mode[0x4];
        u8         rre[0x1];
        u8         rwe[0x1];
        u8         rae[0x1];
-       u8         reserved_23[0x1];
+       u8         reserved_at_493[0x1];
        u8         page_offset[0x6];
-       u8         reserved_24[0x3];
+       u8         reserved_at_49a[0x3];
        u8         cd_slave_receive[0x1];
        u8         cd_slave_send[0x1];
        u8         cd_master[0x1];
 
-       u8         reserved_25[0x3];
+       u8         reserved_at_4a0[0x3];
        u8         min_rnr_nak[0x5];
        u8         next_rcv_psn[0x18];
 
-       u8         reserved_26[0x8];
+       u8         reserved_at_4c0[0x8];
        u8         xrcd[0x18];
 
-       u8         reserved_27[0x8];
+       u8         reserved_at_4e0[0x8];
        u8         cqn_rcv[0x18];
 
        u8         dbr_addr[0x40];
 
        u8         q_key[0x20];
 
-       u8         reserved_28[0x5];
+       u8         reserved_at_560[0x5];
        u8         rq_type[0x3];
        u8         srqn_rmpn[0x18];
 
-       u8         reserved_29[0x8];
+       u8         reserved_at_580[0x8];
        u8         rmsn[0x18];
 
        u8         hw_sq_wqebb_counter[0x10];
@@ -1866,33 +1880,33 @@ struct mlx5_ifc_qpc_bits {
 
        u8         sw_rq_counter[0x20];
 
-       u8         reserved_30[0x20];
+       u8         reserved_at_600[0x20];
 
-       u8         reserved_31[0xf];
+       u8         reserved_at_620[0xf];
        u8         cgs[0x1];
        u8         cs_req[0x8];
        u8         cs_res[0x8];
 
        u8         dc_access_key[0x40];
 
-       u8         reserved_32[0xc0];
+       u8         reserved_at_680[0xc0];
 };
 
 struct mlx5_ifc_roce_addr_layout_bits {
        u8         source_l3_address[16][0x8];
 
-       u8         reserved_0[0x3];
+       u8         reserved_at_80[0x3];
        u8         vlan_valid[0x1];
        u8         vlan_id[0xc];
        u8         source_mac_47_32[0x10];
 
        u8         source_mac_31_0[0x20];
 
-       u8         reserved_1[0x14];
+       u8         reserved_at_c0[0x14];
        u8         roce_l3_type[0x4];
        u8         roce_version[0x8];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_e0[0x20];
 };
 
 union mlx5_ifc_hca_cap_union_bits {
@@ -1904,7 +1918,7 @@ union mlx5_ifc_hca_cap_union_bits {
        struct mlx5_ifc_flow_table_nic_cap_bits flow_table_nic_cap;
        struct mlx5_ifc_flow_table_eswitch_cap_bits flow_table_eswitch_cap;
        struct mlx5_ifc_e_switch_cap_bits e_switch_cap;
-       u8         reserved_0[0x8000];
+       u8         reserved_at_0[0x8000];
 };
 
 enum {
@@ -1914,24 +1928,24 @@ enum {
 };
 
 struct mlx5_ifc_flow_context_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
        u8         group_id[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         flow_tag[0x18];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_60[0x10];
        u8         action[0x10];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_80[0x8];
        u8         destination_list_size[0x18];
 
-       u8         reserved_4[0x160];
+       u8         reserved_at_a0[0x160];
 
        struct mlx5_ifc_fte_match_param_bits match_value;
 
-       u8         reserved_5[0x600];
+       u8         reserved_at_1200[0x600];
 
        struct mlx5_ifc_dest_format_struct_bits destination[0];
 };
@@ -1944,43 +1958,43 @@ enum {
 struct mlx5_ifc_xrc_srqc_bits {
        u8         state[0x4];
        u8         log_xrc_srq_size[0x4];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         wq_signature[0x1];
        u8         cont_srq[0x1];
-       u8         reserved_1[0x1];
+       u8         reserved_at_22[0x1];
        u8         rlky[0x1];
        u8         basic_cyclic_rcv_wqe[0x1];
        u8         log_rq_stride[0x3];
        u8         xrcd[0x18];
 
        u8         page_offset[0x6];
-       u8         reserved_2[0x2];
+       u8         reserved_at_46[0x2];
        u8         cqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         user_index_equal_xrc_srqn[0x1];
-       u8         reserved_4[0x1];
+       u8         reserved_at_81[0x1];
        u8         log_page_size[0x6];
        u8         user_index[0x18];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_a0[0x20];
 
-       u8         reserved_6[0x8];
+       u8         reserved_at_c0[0x8];
        u8         pd[0x18];
 
        u8         lwm[0x10];
        u8         wqe_cnt[0x10];
 
-       u8         reserved_7[0x40];
+       u8         reserved_at_100[0x40];
 
        u8         db_record_addr_h[0x20];
 
        u8         db_record_addr_l[0x1e];
-       u8         reserved_8[0x2];
+       u8         reserved_at_17e[0x2];
 
-       u8         reserved_9[0x80];
+       u8         reserved_at_180[0x80];
 };
 
 struct mlx5_ifc_traffic_counter_bits {
@@ -1990,16 +2004,16 @@ struct mlx5_ifc_traffic_counter_bits {
 };
 
 struct mlx5_ifc_tisc_bits {
-       u8         reserved_0[0xc];
+       u8         reserved_at_0[0xc];
        u8         prio[0x4];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x100];
+       u8         reserved_at_20[0x100];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_120[0x8];
        u8         transport_domain[0x18];
 
-       u8         reserved_4[0x3c0];
+       u8         reserved_at_140[0x3c0];
 };
 
 enum {
@@ -2024,31 +2038,31 @@ enum {
 };
 
 struct mlx5_ifc_tirc_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
        u8         disp_type[0x4];
-       u8         reserved_1[0x1c];
+       u8         reserved_at_24[0x1c];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
-       u8         reserved_3[0x4];
+       u8         reserved_at_80[0x4];
        u8         lro_timeout_period_usecs[0x10];
        u8         lro_enable_mask[0x4];
        u8         lro_max_ip_payload_size[0x8];
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_a0[0x40];
 
-       u8         reserved_5[0x8];
+       u8         reserved_at_e0[0x8];
        u8         inline_rqn[0x18];
 
        u8         rx_hash_symmetric[0x1];
-       u8         reserved_6[0x1];
+       u8         reserved_at_101[0x1];
        u8         tunneled_offload_en[0x1];
-       u8         reserved_7[0x5];
+       u8         reserved_at_103[0x5];
        u8         indirect_table[0x18];
 
        u8         rx_hash_fn[0x4];
-       u8         reserved_8[0x2];
+       u8         reserved_at_124[0x2];
        u8         self_lb_block[0x2];
        u8         transport_domain[0x18];
 
@@ -2058,7 +2072,7 @@ struct mlx5_ifc_tirc_bits {
 
        struct mlx5_ifc_rx_hash_field_select_bits rx_hash_field_selector_inner;
 
-       u8         reserved_9[0x4c0];
+       u8         reserved_at_2c0[0x4c0];
 };
 
 enum {
@@ -2069,39 +2083,39 @@ enum {
 struct mlx5_ifc_srqc_bits {
        u8         state[0x4];
        u8         log_srq_size[0x4];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         wq_signature[0x1];
        u8         cont_srq[0x1];
-       u8         reserved_1[0x1];
+       u8         reserved_at_22[0x1];
        u8         rlky[0x1];
-       u8         reserved_2[0x1];
+       u8         reserved_at_24[0x1];
        u8         log_rq_stride[0x3];
        u8         xrcd[0x18];
 
        u8         page_offset[0x6];
-       u8         reserved_3[0x2];
+       u8         reserved_at_46[0x2];
        u8         cqn[0x18];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_60[0x20];
 
-       u8         reserved_5[0x2];
+       u8         reserved_at_80[0x2];
        u8         log_page_size[0x6];
-       u8         reserved_6[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_7[0x20];
+       u8         reserved_at_a0[0x20];
 
-       u8         reserved_8[0x8];
+       u8         reserved_at_c0[0x8];
        u8         pd[0x18];
 
        u8         lwm[0x10];
        u8         wqe_cnt[0x10];
 
-       u8         reserved_9[0x40];
+       u8         reserved_at_100[0x40];
 
        u8         dbr_addr[0x40];
 
-       u8         reserved_10[0x80];
+       u8         reserved_at_180[0x80];
 };
 
 enum {
@@ -2115,39 +2129,39 @@ struct mlx5_ifc_sqc_bits {
        u8         cd_master[0x1];
        u8         fre[0x1];
        u8         flush_in_error_en[0x1];
-       u8         reserved_0[0x4];
+       u8         reserved_at_4[0x4];
        u8         state[0x4];
-       u8         reserved_1[0x14];
+       u8         reserved_at_c[0x14];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_20[0x8];
        u8         user_index[0x18];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
-       u8         reserved_4[0xa0];
+       u8         reserved_at_60[0xa0];
 
        u8         tis_lst_sz[0x10];
-       u8         reserved_5[0x10];
+       u8         reserved_at_110[0x10];
 
-       u8         reserved_6[0x40];
+       u8         reserved_at_120[0x40];
 
-       u8         reserved_7[0x8];
+       u8         reserved_at_160[0x8];
        u8         tis_num_0[0x18];
 
        struct mlx5_ifc_wq_bits wq;
 };
 
 struct mlx5_ifc_rqtc_bits {
-       u8         reserved_0[0xa0];
+       u8         reserved_at_0[0xa0];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_a0[0x10];
        u8         rqt_max_size[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_c0[0x10];
        u8         rqt_actual_size[0x10];
 
-       u8         reserved_3[0x6a0];
+       u8         reserved_at_e0[0x6a0];
 
        struct mlx5_ifc_rq_num_bits rq_num[0];
 };
@@ -2165,27 +2179,27 @@ enum {
 
 struct mlx5_ifc_rqc_bits {
        u8         rlky[0x1];
-       u8         reserved_0[0x2];
+       u8         reserved_at_1[0x2];
        u8         vsd[0x1];
        u8         mem_rq_type[0x4];
        u8         state[0x4];
-       u8         reserved_1[0x1];
+       u8         reserved_at_c[0x1];
        u8         flush_in_error_en[0x1];
-       u8         reserved_2[0x12];
+       u8         reserved_at_e[0x12];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_20[0x8];
        u8         user_index[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
        u8         counter_set_id[0x8];
-       u8         reserved_5[0x18];
+       u8         reserved_at_68[0x18];
 
-       u8         reserved_6[0x8];
+       u8         reserved_at_80[0x8];
        u8         rmpn[0x18];
 
-       u8         reserved_7[0xe0];
+       u8         reserved_at_a0[0xe0];
 
        struct mlx5_ifc_wq_bits wq;
 };
@@ -2196,31 +2210,31 @@ enum {
 };
 
 struct mlx5_ifc_rmpc_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         state[0x4];
-       u8         reserved_1[0x14];
+       u8         reserved_at_c[0x14];
 
        u8         basic_cyclic_rcv_wqe[0x1];
-       u8         reserved_2[0x1f];
+       u8         reserved_at_21[0x1f];
 
-       u8         reserved_3[0x140];
+       u8         reserved_at_40[0x140];
 
        struct mlx5_ifc_wq_bits wq;
 };
 
 struct mlx5_ifc_nic_vport_context_bits {
-       u8         reserved_0[0x1f];
+       u8         reserved_at_0[0x1f];
        u8         roce_en[0x1];
 
        u8         arm_change_event[0x1];
-       u8         reserved_1[0x1a];
+       u8         reserved_at_21[0x1a];
        u8         event_on_mtu[0x1];
        u8         event_on_promisc_change[0x1];
        u8         event_on_vlan_change[0x1];
        u8         event_on_mc_address_change[0x1];
        u8         event_on_uc_address_change[0x1];
 
-       u8         reserved_2[0xf0];
+       u8         reserved_at_40[0xf0];
 
        u8         mtu[0x10];
 
@@ -2228,21 +2242,21 @@ struct mlx5_ifc_nic_vport_context_bits {
        u8         port_guid[0x40];
        u8         node_guid[0x40];
 
-       u8         reserved_3[0x140];
+       u8         reserved_at_200[0x140];
        u8         qkey_violation_counter[0x10];
-       u8         reserved_4[0x430];
+       u8         reserved_at_350[0x430];
 
        u8         promisc_uc[0x1];
        u8         promisc_mc[0x1];
        u8         promisc_all[0x1];
-       u8         reserved_5[0x2];
+       u8         reserved_at_783[0x2];
        u8         allowed_list_type[0x3];
-       u8         reserved_6[0xc];
+       u8         reserved_at_788[0xc];
        u8         allowed_list_size[0xc];
 
        struct mlx5_ifc_mac_address_layout_bits permanent_address;
 
-       u8         reserved_7[0x20];
+       u8         reserved_at_7e0[0x20];
 
        u8         current_uc_mac_address[0][0x40];
 };
@@ -2254,9 +2268,9 @@ enum {
 };
 
 struct mlx5_ifc_mkc_bits {
-       u8         reserved_0[0x1];
+       u8         reserved_at_0[0x1];
        u8         free[0x1];
-       u8         reserved_1[0xd];
+       u8         reserved_at_2[0xd];
        u8         small_fence_on_rdma_read_response[0x1];
        u8         umr_en[0x1];
        u8         a[0x1];
@@ -2265,19 +2279,19 @@ struct mlx5_ifc_mkc_bits {
        u8         lw[0x1];
        u8         lr[0x1];
        u8         access_mode[0x2];
-       u8         reserved_2[0x8];
+       u8         reserved_at_18[0x8];
 
        u8         qpn[0x18];
        u8         mkey_7_0[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_40[0x20];
 
        u8         length64[0x1];
        u8         bsf_en[0x1];
        u8         sync_umr[0x1];
-       u8         reserved_4[0x2];
+       u8         reserved_at_63[0x2];
        u8         expected_sigerr_count[0x1];
-       u8         reserved_5[0x1];
+       u8         reserved_at_66[0x1];
        u8         en_rinval[0x1];
        u8         pd[0x18];
 
@@ -2287,18 +2301,18 @@ struct mlx5_ifc_mkc_bits {
 
        u8         bsf_octword_size[0x20];
 
-       u8         reserved_6[0x80];
+       u8         reserved_at_120[0x80];
 
        u8         translations_octword_size[0x20];
 
-       u8         reserved_7[0x1b];
+       u8         reserved_at_1c0[0x1b];
        u8         log_page_size[0x5];
 
-       u8         reserved_8[0x20];
+       u8         reserved_at_1e0[0x20];
 };
 
 struct mlx5_ifc_pkey_bits {
-       u8         reserved_0[0x10];
+       u8         reserved_at_0[0x10];
        u8         pkey[0x10];
 };
 
@@ -2309,19 +2323,19 @@ struct mlx5_ifc_array128_auto_bits {
 struct mlx5_ifc_hca_vport_context_bits {
        u8         field_select[0x20];
 
-       u8         reserved_0[0xe0];
+       u8         reserved_at_20[0xe0];
 
        u8         sm_virt_aware[0x1];
        u8         has_smi[0x1];
        u8         has_raw[0x1];
        u8         grh_required[0x1];
-       u8         reserved_1[0xc];
+       u8         reserved_at_104[0xc];
        u8         port_physical_state[0x4];
        u8         vport_state_policy[0x4];
        u8         port_state[0x4];
        u8         vport_state[0x4];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_120[0x20];
 
        u8         system_image_guid[0x40];
 
@@ -2337,33 +2351,33 @@ struct mlx5_ifc_hca_vport_context_bits {
 
        u8         cap_mask2_field_select[0x20];
 
-       u8         reserved_3[0x80];
+       u8         reserved_at_280[0x80];
 
        u8         lid[0x10];
-       u8         reserved_4[0x4];
+       u8         reserved_at_310[0x4];
        u8         init_type_reply[0x4];
        u8         lmc[0x3];
        u8         subnet_timeout[0x5];
 
        u8         sm_lid[0x10];
        u8         sm_sl[0x4];
-       u8         reserved_5[0xc];
+       u8         reserved_at_334[0xc];
 
        u8         qkey_violation_counter[0x10];
        u8         pkey_violation_counter[0x10];
 
-       u8         reserved_6[0xca0];
+       u8         reserved_at_360[0xca0];
 };
 
 struct mlx5_ifc_esw_vport_context_bits {
-       u8         reserved_0[0x3];
+       u8         reserved_at_0[0x3];
        u8         vport_svlan_strip[0x1];
        u8         vport_cvlan_strip[0x1];
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_insert[0x2];
-       u8         reserved_1[0x18];
+       u8         reserved_at_8[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_20[0x20];
 
        u8         svlan_cfi[0x1];
        u8         svlan_pcp[0x3];
@@ -2372,7 +2386,7 @@ struct mlx5_ifc_esw_vport_context_bits {
        u8         cvlan_pcp[0x3];
        u8         cvlan_id[0xc];
 
-       u8         reserved_3[0x7a0];
+       u8         reserved_at_60[0x7a0];
 };
 
 enum {
@@ -2387,41 +2401,41 @@ enum {
 
 struct mlx5_ifc_eqc_bits {
        u8         status[0x4];
-       u8         reserved_0[0x9];
+       u8         reserved_at_4[0x9];
        u8         ec[0x1];
        u8         oi[0x1];
-       u8         reserved_1[0x5];
+       u8         reserved_at_f[0x5];
        u8         st[0x4];
-       u8         reserved_2[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_4[0x14];
+       u8         reserved_at_40[0x14];
        u8         page_offset[0x6];
-       u8         reserved_5[0x6];
+       u8         reserved_at_5a[0x6];
 
-       u8         reserved_6[0x3];
+       u8         reserved_at_60[0x3];
        u8         log_eq_size[0x5];
        u8         uar_page[0x18];
 
-       u8         reserved_7[0x20];
+       u8         reserved_at_80[0x20];
 
-       u8         reserved_8[0x18];
+       u8         reserved_at_a0[0x18];
        u8         intr[0x8];
 
-       u8         reserved_9[0x3];
+       u8         reserved_at_c0[0x3];
        u8         log_page_size[0x5];
-       u8         reserved_10[0x18];
+       u8         reserved_at_c8[0x18];
 
-       u8         reserved_11[0x60];
+       u8         reserved_at_e0[0x60];
 
-       u8         reserved_12[0x8];
+       u8         reserved_at_140[0x8];
        u8         consumer_counter[0x18];
 
-       u8         reserved_13[0x8];
+       u8         reserved_at_160[0x8];
        u8         producer_counter[0x18];
 
-       u8         reserved_14[0x80];
+       u8         reserved_at_180[0x80];
 };
 
 enum {
@@ -2445,14 +2459,14 @@ enum {
 };
 
 struct mlx5_ifc_dctc_bits {
-       u8         reserved_0[0x4];
+       u8         reserved_at_0[0x4];
        u8         state[0x4];
-       u8         reserved_1[0x18];
+       u8         reserved_at_8[0x18];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_20[0x8];
        u8         user_index[0x18];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
        u8         counter_set_id[0x8];
@@ -2464,45 +2478,45 @@ struct mlx5_ifc_dctc_bits {
        u8         latency_sensitive[0x1];
        u8         rlky[0x1];
        u8         free_ar[0x1];
-       u8         reserved_4[0xd];
+       u8         reserved_at_73[0xd];
 
-       u8         reserved_5[0x8];
+       u8         reserved_at_80[0x8];
        u8         cs_res[0x8];
-       u8         reserved_6[0x3];
+       u8         reserved_at_90[0x3];
        u8         min_rnr_nak[0x5];
-       u8         reserved_7[0x8];
+       u8         reserved_at_98[0x8];
 
-       u8         reserved_8[0x8];
+       u8         reserved_at_a0[0x8];
        u8         srqn[0x18];
 
-       u8         reserved_9[0x8];
+       u8         reserved_at_c0[0x8];
        u8         pd[0x18];
 
        u8         tclass[0x8];
-       u8         reserved_10[0x4];
+       u8         reserved_at_e8[0x4];
        u8         flow_label[0x14];
 
        u8         dc_access_key[0x40];
 
-       u8         reserved_11[0x5];
+       u8         reserved_at_140[0x5];
        u8         mtu[0x3];
        u8         port[0x8];
        u8         pkey_index[0x10];
 
-       u8         reserved_12[0x8];
+       u8         reserved_at_160[0x8];
        u8         my_addr_index[0x8];
-       u8         reserved_13[0x8];
+       u8         reserved_at_170[0x8];
        u8         hop_limit[0x8];
 
        u8         dc_access_key_violation_count[0x20];
 
-       u8         reserved_14[0x14];
+       u8         reserved_at_1a0[0x14];
        u8         dei_cfi[0x1];
        u8         eth_prio[0x3];
        u8         ecn[0x2];
        u8         dscp[0x6];
 
-       u8         reserved_15[0x40];
+       u8         reserved_at_1c0[0x40];
 };
 
 enum {
@@ -2524,54 +2538,54 @@ enum {
 
 struct mlx5_ifc_cqc_bits {
        u8         status[0x4];
-       u8         reserved_0[0x4];
+       u8         reserved_at_4[0x4];
        u8         cqe_sz[0x3];
        u8         cc[0x1];
-       u8         reserved_1[0x1];
+       u8         reserved_at_c[0x1];
        u8         scqe_break_moderation_en[0x1];
        u8         oi[0x1];
-       u8         reserved_2[0x2];
+       u8         reserved_at_f[0x2];
        u8         cqe_zip_en[0x1];
        u8         mini_cqe_res_format[0x2];
        u8         st[0x4];
-       u8         reserved_3[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_5[0x14];
+       u8         reserved_at_40[0x14];
        u8         page_offset[0x6];
-       u8         reserved_6[0x6];
+       u8         reserved_at_5a[0x6];
 
-       u8         reserved_7[0x3];
+       u8         reserved_at_60[0x3];
        u8         log_cq_size[0x5];
        u8         uar_page[0x18];
 
-       u8         reserved_8[0x4];
+       u8         reserved_at_80[0x4];
        u8         cq_period[0xc];
        u8         cq_max_count[0x10];
 
-       u8         reserved_9[0x18];
+       u8         reserved_at_a0[0x18];
        u8         c_eqn[0x8];
 
-       u8         reserved_10[0x3];
+       u8         reserved_at_c0[0x3];
        u8         log_page_size[0x5];
-       u8         reserved_11[0x18];
+       u8         reserved_at_c8[0x18];
 
-       u8         reserved_12[0x20];
+       u8         reserved_at_e0[0x20];
 
-       u8         reserved_13[0x8];
+       u8         reserved_at_100[0x8];
        u8         last_notified_index[0x18];
 
-       u8         reserved_14[0x8];
+       u8         reserved_at_120[0x8];
        u8         last_solicit_index[0x18];
 
-       u8         reserved_15[0x8];
+       u8         reserved_at_140[0x8];
        u8         consumer_counter[0x18];
 
-       u8         reserved_16[0x8];
+       u8         reserved_at_160[0x8];
        u8         producer_counter[0x18];
 
-       u8         reserved_17[0x40];
+       u8         reserved_at_180[0x40];
 
        u8         dbr_addr[0x40];
 };
@@ -2580,16 +2594,16 @@ union mlx5_ifc_cong_control_roce_ecn_auto_bits {
        struct mlx5_ifc_cong_control_802_1qau_rp_bits cong_control_802_1qau_rp;
        struct mlx5_ifc_cong_control_r_roce_ecn_rp_bits cong_control_r_roce_ecn_rp;
        struct mlx5_ifc_cong_control_r_roce_ecn_np_bits cong_control_r_roce_ecn_np;
-       u8         reserved_0[0x800];
+       u8         reserved_at_0[0x800];
 };
 
 struct mlx5_ifc_query_adapter_param_block_bits {
-       u8         reserved_0[0xc0];
+       u8         reserved_at_0[0xc0];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_c0[0x8];
        u8         ieee_vendor_id[0x18];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_e0[0x10];
        u8         vsd_vendor_id[0x10];
 
        u8         vsd[208][0x8];
@@ -2600,14 +2614,14 @@ struct mlx5_ifc_query_adapter_param_block_bits {
 union mlx5_ifc_modify_field_select_resize_field_select_auto_bits {
        struct mlx5_ifc_modify_field_select_bits modify_field_select;
        struct mlx5_ifc_resize_field_select_bits resize_field_select;
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 };
 
 union mlx5_ifc_field_select_802_1_r_roce_auto_bits {
        struct mlx5_ifc_field_select_802_1qau_rp_bits field_select_802_1qau_rp;
        struct mlx5_ifc_field_select_r_roce_rp_bits field_select_r_roce_rp;
        struct mlx5_ifc_field_select_r_roce_np_bits field_select_r_roce_np;
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 };
 
 union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits {
@@ -2619,7 +2633,7 @@ union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits {
        struct mlx5_ifc_eth_per_prio_grp_data_layout_bits eth_per_prio_grp_data_layout;
        struct mlx5_ifc_eth_per_traffic_grp_data_layout_bits eth_per_traffic_grp_data_layout;
        struct mlx5_ifc_phys_layer_cntrs_bits phys_layer_cntrs;
-       u8         reserved_0[0x7c0];
+       u8         reserved_at_0[0x7c0];
 };
 
 union mlx5_ifc_event_auto_bits {
@@ -2635,23 +2649,23 @@ union mlx5_ifc_event_auto_bits {
        struct mlx5_ifc_db_bf_congestion_event_bits db_bf_congestion_event;
        struct mlx5_ifc_stall_vl_event_bits stall_vl_event;
        struct mlx5_ifc_cmd_inter_comp_event_bits cmd_inter_comp_event;
-       u8         reserved_0[0xe0];
+       u8         reserved_at_0[0xe0];
 };
 
 struct mlx5_ifc_health_buffer_bits {
-       u8         reserved_0[0x100];
+       u8         reserved_at_0[0x100];
 
        u8         assert_existptr[0x20];
 
        u8         assert_callra[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_140[0x40];
 
        u8         fw_version[0x20];
 
        u8         hw_id[0x20];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_1c0[0x20];
 
        u8         irisc_index[0x8];
        u8         synd[0x8];
@@ -2660,20 +2674,20 @@ struct mlx5_ifc_health_buffer_bits {
 
 struct mlx5_ifc_register_loopback_control_bits {
        u8         no_lb[0x1];
-       u8         reserved_0[0x7];
+       u8         reserved_at_1[0x7];
        u8         port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_teardown_hca_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 enum {
@@ -2683,108 +2697,108 @@ enum {
 
 struct mlx5_ifc_teardown_hca_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         profile[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_sqerr2rts_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_sqerr2rts_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_sqd2rts_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_sqd2rts_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_set_roce_address_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_roce_address_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         roce_address_index[0x10];
-       u8         reserved_2[0x10];
+       u8         reserved_at_50[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_roce_addr_layout_bits roce_address;
 };
 
 struct mlx5_ifc_set_mad_demux_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 enum {
@@ -2794,89 +2808,89 @@ enum {
 
 struct mlx5_ifc_set_mad_demux_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_3[0x6];
+       u8         reserved_at_60[0x6];
        u8         demux_mode[0x2];
-       u8         reserved_4[0x18];
+       u8         reserved_at_68[0x18];
 };
 
 struct mlx5_ifc_set_l2_table_entry_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_l2_table_entry_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_40[0x60];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_index[0x18];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_c0[0x20];
 
-       u8         reserved_5[0x13];
+       u8         reserved_at_e0[0x13];
        u8         vlan_valid[0x1];
        u8         vlan[0xc];
 
        struct mlx5_ifc_mac_address_layout_bits mac_address;
 
-       u8         reserved_6[0xc0];
+       u8         reserved_at_140[0xc0];
 };
 
 struct mlx5_ifc_set_issi_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_issi_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         current_issi[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_set_hca_cap_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_hca_cap_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        union mlx5_ifc_hca_cap_union_bits capability;
 };
@@ -2890,156 +2904,156 @@ enum {
 
 struct mlx5_ifc_set_fte_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_fte_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x18];
+       u8         reserved_at_c0[0x18];
        u8         modify_enable_mask[0x8];
 
-       u8         reserved_6[0x20];
+       u8         reserved_at_e0[0x20];
 
        u8         flow_index[0x20];
 
-       u8         reserved_7[0xe0];
+       u8         reserved_at_120[0xe0];
 
        struct mlx5_ifc_flow_context_bits flow_context;
 };
 
 struct mlx5_ifc_rts2rts_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_rts2rts_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_rtr2rts_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_rtr2rts_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_rst2init_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_rst2init_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_query_xrc_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_xrc_srqc_bits xrc_srq_context_entry;
 
-       u8         reserved_2[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_query_xrc_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrc_srqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 enum {
@@ -3049,13 +3063,13 @@ enum {
 
 struct mlx5_ifc_query_vport_state_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_60[0x18];
        u8         admin_state[0x4];
        u8         state[0x4];
 };
@@ -3067,25 +3081,25 @@ enum {
 
 struct mlx5_ifc_query_vport_state_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_vport_counter_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_traffic_counter_bits received_errors;
 
@@ -3111,7 +3125,7 @@ struct mlx5_ifc_query_vport_counter_out_bits {
 
        struct mlx5_ifc_traffic_counter_bits transmitted_eth_multicast;
 
-       u8         reserved_2[0xa00];
+       u8         reserved_at_680[0xa00];
 };
 
 enum {
@@ -3120,328 +3134,328 @@ enum {
 
 struct mlx5_ifc_query_vport_counter_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x60];
+       u8         reserved_at_60[0x60];
 
        u8         clear[0x1];
-       u8         reserved_4[0x1f];
+       u8         reserved_at_c1[0x1f];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_e0[0x20];
 };
 
 struct mlx5_ifc_query_tis_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_tisc_bits tis_context;
 };
 
 struct mlx5_ifc_query_tis_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tisn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_tir_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_tirc_bits tir_context;
 };
 
 struct mlx5_ifc_query_tir_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tirn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_srqc_bits srq_context_entry;
 
-       u8         reserved_2[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_query_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         srqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_sq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_sqc_bits sq_context;
 };
 
 struct mlx5_ifc_query_sq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         sqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_special_contexts_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 
        u8         resd_lkey[0x20];
 };
 
 struct mlx5_ifc_query_special_contexts_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_query_rqt_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rqtc_bits rqt_context;
 };
 
 struct mlx5_ifc_query_rqt_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqtn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_rq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rqc_bits rq_context;
 };
 
 struct mlx5_ifc_query_rq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_roce_address_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_roce_addr_layout_bits roce_address;
 };
 
 struct mlx5_ifc_query_roce_address_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         roce_address_index[0x10];
-       u8         reserved_2[0x10];
+       u8         reserved_at_50[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_rmp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rmpc_bits rmp_context;
 };
 
 struct mlx5_ifc_query_rmp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rmpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_3[0x80];
+       u8         reserved_at_800[0x80];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_query_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_q_counter_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         rx_write_requests[0x20];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_a0[0x20];
 
        u8         rx_read_requests[0x20];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_e0[0x20];
 
        u8         rx_atomic_requests[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_120[0x20];
 
        u8         rx_dct_connect[0x20];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_160[0x20];
 
        u8         out_of_buffer[0x20];
 
-       u8         reserved_6[0x20];
+       u8         reserved_at_1a0[0x20];
 
        u8         out_of_sequence[0x20];
 
-       u8         reserved_7[0x620];
+       u8         reserved_at_1e0[0x620];
 };
 
 struct mlx5_ifc_query_q_counter_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x80];
+       u8         reserved_at_40[0x80];
 
        u8         clear[0x1];
-       u8         reserved_3[0x1f];
+       u8         reserved_at_c1[0x1f];
 
-       u8         reserved_4[0x18];
+       u8         reserved_at_e0[0x18];
        u8         counter_set_id[0x8];
 };
 
 struct mlx5_ifc_query_pages_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_40[0x10];
        u8         function_id[0x10];
 
        u8         num_pages[0x20];
@@ -3455,55 +3469,55 @@ enum {
 
 struct mlx5_ifc_query_pages_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         function_id[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_nic_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_nic_vport_context_bits nic_vport_context;
 };
 
 struct mlx5_ifc_query_nic_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x5];
+       u8         reserved_at_60[0x5];
        u8         allowed_list_type[0x3];
-       u8         reserved_4[0x18];
+       u8         reserved_at_68[0x18];
 };
 
 struct mlx5_ifc_query_mkey_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_mkc_bits memory_key_mkey_entry;
 
-       u8         reserved_2[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         bsf0_klm0_pas_mtt0_1[16][0x8];
 
@@ -3512,265 +3526,265 @@ struct mlx5_ifc_query_mkey_out_bits {
 
 struct mlx5_ifc_query_mkey_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         mkey_index[0x18];
 
        u8         pg_access[0x1];
-       u8         reserved_3[0x1f];
+       u8         reserved_at_61[0x1f];
 };
 
 struct mlx5_ifc_query_mad_demux_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         mad_dumux_parameters_block[0x20];
 };
 
 struct mlx5_ifc_query_mad_demux_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_query_l2_table_entry_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xa0];
+       u8         reserved_at_40[0xa0];
 
-       u8         reserved_2[0x13];
+       u8         reserved_at_e0[0x13];
        u8         vlan_valid[0x1];
        u8         vlan[0xc];
 
        struct mlx5_ifc_mac_address_layout_bits mac_address;
 
-       u8         reserved_3[0xc0];
+       u8         reserved_at_140[0xc0];
 };
 
 struct mlx5_ifc_query_l2_table_entry_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_40[0x60];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_index[0x18];
 
-       u8         reserved_4[0x140];
+       u8         reserved_at_c0[0x140];
 };
 
 struct mlx5_ifc_query_issi_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_40[0x10];
        u8         current_issi[0x10];
 
-       u8         reserved_2[0xa0];
+       u8         reserved_at_60[0xa0];
 
-       u8         supported_issi_reserved[76][0x8];
+       u8         reserved_at_100[76][0x8];
        u8         supported_issi_dw0[0x20];
 };
 
 struct mlx5_ifc_query_issi_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_query_hca_vport_pkey_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_pkey_bits pkey[0];
 };
 
 struct mlx5_ifc_query_hca_vport_pkey_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xb];
+       u8         reserved_at_41[0xb];
        u8         port_num[0x4];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         pkey_index[0x10];
 };
 
 struct mlx5_ifc_query_hca_vport_gid_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 
        u8         gids_num[0x10];
-       u8         reserved_2[0x10];
+       u8         reserved_at_70[0x10];
 
        struct mlx5_ifc_array128_auto_bits gid[0];
 };
 
 struct mlx5_ifc_query_hca_vport_gid_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xb];
+       u8         reserved_at_41[0xb];
        u8         port_num[0x4];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         gid_index[0x10];
 };
 
 struct mlx5_ifc_query_hca_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_hca_vport_context_bits hca_vport_context;
 };
 
 struct mlx5_ifc_query_hca_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xb];
+       u8         reserved_at_41[0xb];
        u8         port_num[0x4];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_hca_cap_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        union mlx5_ifc_hca_cap_union_bits capability;
 };
 
 struct mlx5_ifc_query_hca_cap_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_query_flow_table_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x80];
+       u8         reserved_at_40[0x80];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_c0[0x8];
        u8         level[0x8];
-       u8         reserved_3[0x8];
+       u8         reserved_at_d0[0x8];
        u8         log_size[0x8];
 
-       u8         reserved_4[0x120];
+       u8         reserved_at_e0[0x120];
 };
 
 struct mlx5_ifc_query_flow_table_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x140];
+       u8         reserved_at_c0[0x140];
 };
 
 struct mlx5_ifc_query_fte_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x1c0];
+       u8         reserved_at_40[0x1c0];
 
        struct mlx5_ifc_flow_context_bits flow_context;
 };
 
 struct mlx5_ifc_query_fte_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x40];
+       u8         reserved_at_c0[0x40];
 
        u8         flow_index[0x20];
 
-       u8         reserved_6[0xe0];
+       u8         reserved_at_120[0xe0];
 };
 
 enum {
@@ -3781,84 +3795,84 @@ enum {
 
 struct mlx5_ifc_query_flow_group_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0xa0];
+       u8         reserved_at_40[0xa0];
 
        u8         start_flow_index[0x20];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_100[0x20];
 
        u8         end_flow_index[0x20];
 
-       u8         reserved_3[0xa0];
+       u8         reserved_at_140[0xa0];
 
-       u8         reserved_4[0x18];
+       u8         reserved_at_1e0[0x18];
        u8         match_criteria_enable[0x8];
 
        struct mlx5_ifc_fte_match_param_bits match_criteria;
 
-       u8         reserved_5[0xe00];
+       u8         reserved_at_1200[0xe00];
 };
 
 struct mlx5_ifc_query_flow_group_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
        u8         group_id[0x20];
 
-       u8         reserved_5[0x120];
+       u8         reserved_at_e0[0x120];
 };
 
 struct mlx5_ifc_query_esw_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_esw_vport_context_bits esw_vport_context;
 };
 
 struct mlx5_ifc_query_esw_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_modify_esw_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_esw_vport_context_fields_select_bits {
-       u8         reserved[0x1c];
+       u8         reserved_at_0[0x1c];
        u8         vport_cvlan_insert[0x1];
        u8         vport_svlan_insert[0x1];
        u8         vport_cvlan_strip[0x1];
@@ -3867,13 +3881,13 @@ struct mlx5_ifc_esw_vport_context_fields_select_bits {
 
 struct mlx5_ifc_modify_esw_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
        struct mlx5_ifc_esw_vport_context_fields_select_bits field_select;
@@ -3883,124 +3897,124 @@ struct mlx5_ifc_modify_esw_vport_context_in_bits {
 
 struct mlx5_ifc_query_eq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_eqc_bits eq_context_entry;
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_280[0x40];
 
        u8         event_bitmask[0x40];
 
-       u8         reserved_3[0x580];
+       u8         reserved_at_300[0x580];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_query_eq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         eq_number[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_dct_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_dctc_bits dct_context_entry;
 
-       u8         reserved_2[0x180];
+       u8         reserved_at_280[0x180];
 };
 
 struct mlx5_ifc_query_dct_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         dctn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_cq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_cqc_bits cq_context;
 
-       u8         reserved_2[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_query_cq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_cong_status_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 
        u8         enable[0x1];
        u8         tag_enable[0x1];
-       u8         reserved_2[0x1e];
+       u8         reserved_at_62[0x1e];
 };
 
 struct mlx5_ifc_query_cong_status_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         priority[0x4];
        u8         cong_protocol[0x4];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_cong_statistics_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         cur_flows[0x20];
 
@@ -4014,7 +4028,7 @@ struct mlx5_ifc_query_cong_statistics_out_bits {
 
        u8         cnp_handled_low[0x20];
 
-       u8         reserved_2[0x100];
+       u8         reserved_at_140[0x100];
 
        u8         time_stamp_high[0x20];
 
@@ -4030,453 +4044,455 @@ struct mlx5_ifc_query_cong_statistics_out_bits {
 
        u8         cnps_sent_low[0x20];
 
-       u8         reserved_3[0x560];
+       u8         reserved_at_320[0x560];
 };
 
 struct mlx5_ifc_query_cong_statistics_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         clear[0x1];
-       u8         reserved_2[0x1f];
+       u8         reserved_at_41[0x1f];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_cong_params_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        union mlx5_ifc_cong_control_roce_ecn_auto_bits congestion_parameters;
 };
 
 struct mlx5_ifc_query_cong_params_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x1c];
+       u8         reserved_at_40[0x1c];
        u8         cong_protocol[0x4];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_query_adapter_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_query_adapter_param_block_bits query_adapter_struct;
 };
 
 struct mlx5_ifc_query_adapter_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_qp_2rst_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_qp_2rst_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_qp_2err_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_qp_2err_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_page_fault_resume_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_page_fault_resume_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         error[0x1];
-       u8         reserved_2[0x4];
+       u8         reserved_at_41[0x4];
        u8         rdma[0x1];
        u8         read_write[0x1];
        u8         req_res[0x1];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_nop_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_nop_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_vport_state_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_vport_state_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x18];
+       u8         reserved_at_60[0x18];
        u8         admin_state[0x4];
-       u8         reserved_4[0x4];
+       u8         reserved_at_7c[0x4];
 };
 
 struct mlx5_ifc_modify_tis_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_tis_bitmask_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
-       u8         reserved_1[0x1f];
+       u8         reserved_at_20[0x1f];
        u8         prio[0x1];
 };
 
 struct mlx5_ifc_modify_tis_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tisn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_modify_tis_bitmask_bits bitmask;
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_tisc_bits ctx;
 };
 
 struct mlx5_ifc_modify_tir_bitmask_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
-       u8         reserved_1[0x1b];
+       u8         reserved_at_20[0x1b];
        u8         self_lb_en[0x1];
-       u8         reserved_2[0x3];
+       u8         reserved_at_3c[0x1];
+       u8         hash[0x1];
+       u8         reserved_at_3e[0x1];
        u8         lro[0x1];
 };
 
 struct mlx5_ifc_modify_tir_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_tir_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tirn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_modify_tir_bitmask_bits bitmask;
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_tirc_bits ctx;
 };
 
 struct mlx5_ifc_modify_sq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_sq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         sq_state[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_44[0x4];
        u8         sqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         modify_bitmask[0x40];
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_sqc_bits ctx;
 };
 
 struct mlx5_ifc_modify_rqt_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_rqt_bitmask_bits {
-       u8         reserved[0x20];
+       u8         reserved_at_0[0x20];
 
-       u8         reserved1[0x1f];
+       u8         reserved_at_20[0x1f];
        u8         rqn_list[0x1];
 };
 
 struct mlx5_ifc_modify_rqt_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqtn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_rqt_bitmask_bits bitmask;
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_rqtc_bits ctx;
 };
 
 struct mlx5_ifc_modify_rq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_rq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         rq_state[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_44[0x4];
        u8         rqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         modify_bitmask[0x40];
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_rqc_bits ctx;
 };
 
 struct mlx5_ifc_modify_rmp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_rmp_bitmask_bits {
-       u8         reserved[0x20];
+       u8         reserved_at_0[0x20];
 
-       u8         reserved1[0x1f];
+       u8         reserved_at_20[0x1f];
        u8         lwm[0x1];
 };
 
 struct mlx5_ifc_modify_rmp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         rmp_state[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_44[0x4];
        u8         rmpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_rmp_bitmask_bits bitmask;
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_c0[0x40];
 
        struct mlx5_ifc_rmpc_bits ctx;
 };
 
 struct mlx5_ifc_modify_nic_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_nic_vport_field_select_bits {
-       u8         reserved_0[0x19];
+       u8         reserved_at_0[0x19];
        u8         mtu[0x1];
        u8         change_event[0x1];
        u8         promisc[0x1];
        u8         permanent_address[0x1];
        u8         addresses_list[0x1];
        u8         roce_en[0x1];
-       u8         reserved_1[0x1];
+       u8         reserved_at_1f[0x1];
 };
 
 struct mlx5_ifc_modify_nic_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xf];
+       u8         reserved_at_41[0xf];
        u8         vport_number[0x10];
 
        struct mlx5_ifc_modify_nic_vport_field_select_bits field_select;
 
-       u8         reserved_3[0x780];
+       u8         reserved_at_80[0x780];
 
        struct mlx5_ifc_nic_vport_context_bits nic_vport_context;
 };
 
 struct mlx5_ifc_modify_hca_vport_context_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_hca_vport_context_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         other_vport[0x1];
-       u8         reserved_2[0xb];
+       u8         reserved_at_41[0xb];
        u8         port_num[0x4];
        u8         vport_number[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        struct mlx5_ifc_hca_vport_context_bits hca_vport_context;
 };
 
 struct mlx5_ifc_modify_cq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 enum {
@@ -4486,83 +4502,83 @@ enum {
 
 struct mlx5_ifc_modify_cq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
        union mlx5_ifc_modify_field_select_resize_field_select_auto_bits modify_field_select_resize_field_select;
 
        struct mlx5_ifc_cqc_bits cq_context;
 
-       u8         reserved_3[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_modify_cong_status_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_cong_status_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         priority[0x4];
        u8         cong_protocol[0x4];
 
        u8         enable[0x1];
        u8         tag_enable[0x1];
-       u8         reserved_3[0x1e];
+       u8         reserved_at_62[0x1e];
 };
 
 struct mlx5_ifc_modify_cong_params_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_cong_params_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x1c];
+       u8         reserved_at_40[0x1c];
        u8         cong_protocol[0x4];
 
        union mlx5_ifc_field_select_802_1_r_roce_auto_bits field_select;
 
-       u8         reserved_3[0x80];
+       u8         reserved_at_80[0x80];
 
        union mlx5_ifc_cong_control_roce_ecn_auto_bits congestion_parameters;
 };
 
 struct mlx5_ifc_manage_pages_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
        u8         output_num_entries[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         pas[0][0x40];
 };
@@ -4575,12 +4591,12 @@ enum {
 
 struct mlx5_ifc_manage_pages_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         function_id[0x10];
 
        u8         input_num_entries[0x20];
@@ -4590,117 +4606,117 @@ struct mlx5_ifc_manage_pages_in_bits {
 
 struct mlx5_ifc_mad_ifc_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         response_mad_packet[256][0x8];
 };
 
 struct mlx5_ifc_mad_ifc_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         remote_lid[0x10];
-       u8         reserved_2[0x8];
+       u8         reserved_at_50[0x8];
        u8         port[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         mad[256][0x8];
 };
 
 struct mlx5_ifc_init_hca_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_init_hca_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_init2rtr_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_init2rtr_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_init2init_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_init2init_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_800[0x80];
 };
 
 struct mlx5_ifc_get_dropped_packet_log_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         packet_headers_log[128][0x8];
 
@@ -4709,1029 +4725,1029 @@ struct mlx5_ifc_get_dropped_packet_log_out_bits {
 
 struct mlx5_ifc_get_dropped_packet_log_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_gen_eqe_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         eq_number[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         eqe[64][0x8];
 };
 
 struct mlx5_ifc_gen_eq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_enable_hca_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 };
 
 struct mlx5_ifc_enable_hca_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         function_id[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_drain_dct_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_drain_dct_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         dctn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_disable_hca_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_40[0x20];
 };
 
 struct mlx5_ifc_disable_hca_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         function_id[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_detach_from_mcg_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_detach_from_mcg_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         multicast_gid[16][0x8];
 };
 
 struct mlx5_ifc_destroy_xrc_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_xrc_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrc_srqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_tis_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_tis_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tisn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_tir_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_tir_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         tirn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         srqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_sq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_sq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         sqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_rqt_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_rqt_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqtn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_rq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_rq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_rmp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_rmp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         rmpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_psv_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_psv_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         psvn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_mkey_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_mkey_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         mkey_index[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_flow_table_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_flow_table_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x140];
+       u8         reserved_at_c0[0x140];
 };
 
 struct mlx5_ifc_destroy_flow_group_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_flow_group_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
        u8         group_id[0x20];
 
-       u8         reserved_5[0x120];
+       u8         reserved_at_e0[0x120];
 };
 
 struct mlx5_ifc_destroy_eq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_eq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         eq_number[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_dct_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_dct_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         dctn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_destroy_cq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_destroy_cq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_delete_vxlan_udp_dport_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_delete_vxlan_udp_dport_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         vxlan_udp_port[0x10];
 };
 
 struct mlx5_ifc_delete_l2_table_entry_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_delete_l2_table_entry_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_40[0x60];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_index[0x18];
 
-       u8         reserved_4[0x140];
+       u8         reserved_at_c0[0x140];
 };
 
 struct mlx5_ifc_delete_fte_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_delete_fte_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x40];
+       u8         reserved_at_c0[0x40];
 
        u8         flow_index[0x20];
 
-       u8         reserved_6[0xe0];
+       u8         reserved_at_120[0xe0];
 };
 
 struct mlx5_ifc_dealloc_xrcd_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_dealloc_xrcd_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrcd[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_dealloc_uar_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_dealloc_uar_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         uar[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_dealloc_transport_domain_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_dealloc_transport_domain_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         transport_domain[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_dealloc_q_counter_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_dealloc_q_counter_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_40[0x18];
        u8         counter_set_id[0x8];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_dealloc_pd_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_dealloc_pd_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         pd[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_xrc_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrc_srqn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_xrc_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_xrc_srqc_bits xrc_srq_context_entry;
 
-       u8         reserved_3[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_create_tis_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         tisn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_tis_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_tisc_bits ctx;
 };
 
 struct mlx5_ifc_create_tir_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         tirn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_tir_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_tirc_bits ctx;
 };
 
 struct mlx5_ifc_create_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         srqn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_srqc_bits srq_context_entry;
 
-       u8         reserved_3[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_create_sq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         sqn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_sq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_sqc_bits ctx;
 };
 
 struct mlx5_ifc_create_rqt_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqtn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_rqt_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rqtc_bits rqt_context;
 };
 
 struct mlx5_ifc_create_rq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         rqn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_rq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rqc_bits ctx;
 };
 
 struct mlx5_ifc_create_rmp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         rmpn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_rmp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0xc0];
+       u8         reserved_at_40[0xc0];
 
        struct mlx5_ifc_rmpc_bits ctx;
 };
 
 struct mlx5_ifc_create_qp_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_qp_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         opt_param_mask[0x20];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_a0[0x20];
 
        struct mlx5_ifc_qpc_bits qpc;
 
-       u8         reserved_4[0x80];
+       u8         reserved_at_800[0x80];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_create_psv_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_80[0x8];
        u8         psv0_index[0x18];
 
-       u8         reserved_3[0x8];
+       u8         reserved_at_a0[0x8];
        u8         psv1_index[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_c0[0x8];
        u8         psv2_index[0x18];
 
-       u8         reserved_5[0x8];
+       u8         reserved_at_e0[0x8];
        u8         psv3_index[0x18];
 };
 
 struct mlx5_ifc_create_psv_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         num_psv[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_44[0x4];
        u8         pd[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_mkey_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         mkey_index[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_mkey_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_40[0x20];
 
        u8         pg_access[0x1];
-       u8         reserved_3[0x1f];
+       u8         reserved_at_61[0x1f];
 
        struct mlx5_ifc_mkc_bits memory_key_mkey_entry;
 
-       u8         reserved_4[0x80];
+       u8         reserved_at_280[0x80];
 
        u8         translations_octword_actual_size[0x20];
 
-       u8         reserved_5[0x560];
+       u8         reserved_at_320[0x560];
 
        u8         klm_pas_mtt[0][0x20];
 };
 
 struct mlx5_ifc_create_flow_table_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_flow_table_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_a0[0x20];
 
-       u8         reserved_5[0x4];
+       u8         reserved_at_c0[0x4];
        u8         table_miss_mode[0x4];
        u8         level[0x8];
-       u8         reserved_6[0x8];
+       u8         reserved_at_d0[0x8];
        u8         log_size[0x8];
 
-       u8         reserved_7[0x8];
+       u8         reserved_at_e0[0x8];
        u8         table_miss_id[0x18];
 
-       u8         reserved_8[0x100];
+       u8         reserved_at_100[0x100];
 };
 
 struct mlx5_ifc_create_flow_group_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         group_id[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 enum {
@@ -5742,134 +5758,134 @@ enum {
 
 struct mlx5_ifc_create_flow_group_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_c0[0x20];
 
        u8         start_flow_index[0x20];
 
-       u8         reserved_6[0x20];
+       u8         reserved_at_100[0x20];
 
        u8         end_flow_index[0x20];
 
-       u8         reserved_7[0xa0];
+       u8         reserved_at_140[0xa0];
 
-       u8         reserved_8[0x18];
+       u8         reserved_at_1e0[0x18];
        u8         match_criteria_enable[0x8];
 
        struct mlx5_ifc_fte_match_param_bits match_criteria;
 
-       u8         reserved_9[0xe00];
+       u8         reserved_at_1200[0xe00];
 };
 
 struct mlx5_ifc_create_eq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x18];
+       u8         reserved_at_40[0x18];
        u8         eq_number[0x8];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_eq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_eqc_bits eq_context_entry;
 
-       u8         reserved_3[0x40];
+       u8         reserved_at_280[0x40];
 
        u8         event_bitmask[0x40];
 
-       u8         reserved_4[0x580];
+       u8         reserved_at_300[0x580];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_create_dct_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         dctn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_dct_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_dctc_bits dct_context_entry;
 
-       u8         reserved_3[0x180];
+       u8         reserved_at_280[0x180];
 };
 
 struct mlx5_ifc_create_cq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         cqn[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_create_cq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        struct mlx5_ifc_cqc_bits cq_context;
 
-       u8         reserved_3[0x600];
+       u8         reserved_at_280[0x600];
 
        u8         pas[0][0x40];
 };
 
 struct mlx5_ifc_config_int_moderation_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x4];
+       u8         reserved_at_40[0x4];
        u8         min_delay[0xc];
        u8         int_vector[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 enum {
@@ -5879,49 +5895,49 @@ enum {
 
 struct mlx5_ifc_config_int_moderation_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x4];
+       u8         reserved_at_40[0x4];
        u8         min_delay[0xc];
        u8         int_vector[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_attach_to_mcg_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_attach_to_mcg_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         qpn[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 
        u8         multicast_gid[16][0x8];
 };
 
 struct mlx5_ifc_arm_xrc_srq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 enum {
@@ -5930,25 +5946,25 @@ enum {
 
 struct mlx5_ifc_arm_xrc_srq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrc_srqn[0x18];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         lwm[0x10];
 };
 
 struct mlx5_ifc_arm_rq_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 enum {
@@ -5957,179 +5973,179 @@ enum {
 
 struct mlx5_ifc_arm_rq_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         srq_number[0x18];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         lwm[0x10];
 };
 
 struct mlx5_ifc_arm_dct_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_arm_dct_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_40[0x8];
        u8         dct_number[0x18];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_xrcd_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         xrcd[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_xrcd_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_alloc_uar_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         uar[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_uar_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_alloc_transport_domain_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         transport_domain[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_transport_domain_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_alloc_q_counter_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x18];
+       u8         reserved_at_40[0x18];
        u8         counter_set_id[0x8];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_q_counter_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_alloc_pd_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x8];
+       u8         reserved_at_40[0x8];
        u8         pd[0x18];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_60[0x20];
 };
 
 struct mlx5_ifc_alloc_pd_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_add_vxlan_udp_dport_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_add_vxlan_udp_dport_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         vxlan_udp_port[0x10];
 };
 
 struct mlx5_ifc_access_register_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         register_data[0][0x20];
 };
@@ -6141,12 +6157,12 @@ enum {
 
 struct mlx5_ifc_access_register_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x10];
+       u8         reserved_at_40[0x10];
        u8         register_id[0x10];
 
        u8         argument[0x20];
@@ -6159,24 +6175,24 @@ struct mlx5_ifc_sltp_reg_bits {
        u8         version[0x4];
        u8         local_port[0x8];
        u8         pnat[0x2];
-       u8         reserved_0[0x2];
+       u8         reserved_at_12[0x2];
        u8         lane[0x4];
-       u8         reserved_1[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_3[0x7];
+       u8         reserved_at_40[0x7];
        u8         polarity[0x1];
        u8         ob_tap0[0x8];
        u8         ob_tap1[0x8];
        u8         ob_tap2[0x8];
 
-       u8         reserved_4[0xc];
+       u8         reserved_at_60[0xc];
        u8         ob_preemp_mode[0x4];
        u8         ob_reg[0x8];
        u8         ob_bias[0x8];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_80[0x20];
 };
 
 struct mlx5_ifc_slrg_reg_bits {
@@ -6184,36 +6200,36 @@ struct mlx5_ifc_slrg_reg_bits {
        u8         version[0x4];
        u8         local_port[0x8];
        u8         pnat[0x2];
-       u8         reserved_0[0x2];
+       u8         reserved_at_12[0x2];
        u8         lane[0x4];
-       u8         reserved_1[0x8];
+       u8         reserved_at_18[0x8];
 
        u8         time_to_link_up[0x10];
-       u8         reserved_2[0xc];
+       u8         reserved_at_30[0xc];
        u8         grade_lane_speed[0x4];
 
        u8         grade_version[0x8];
        u8         grade[0x18];
 
-       u8         reserved_3[0x4];
+       u8         reserved_at_60[0x4];
        u8         height_grade_type[0x4];
        u8         height_grade[0x18];
 
        u8         height_dz[0x10];
        u8         height_dv[0x10];
 
-       u8         reserved_4[0x10];
+       u8         reserved_at_a0[0x10];
        u8         height_sigma[0x10];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_c0[0x20];
 
-       u8         reserved_6[0x4];
+       u8         reserved_at_e0[0x4];
        u8         phase_grade_type[0x4];
        u8         phase_grade[0x18];
 
-       u8         reserved_7[0x8];
+       u8         reserved_at_100[0x8];
        u8         phase_eo_pos[0x8];
-       u8         reserved_8[0x8];
+       u8         reserved_at_110[0x8];
        u8         phase_eo_neg[0x8];
 
        u8         ffe_set_tested[0x10];
@@ -6221,70 +6237,70 @@ struct mlx5_ifc_slrg_reg_bits {
 };
 
 struct mlx5_ifc_pvlc_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x1c];
+       u8         reserved_at_20[0x1c];
        u8         vl_hw_cap[0x4];
 
-       u8         reserved_3[0x1c];
+       u8         reserved_at_40[0x1c];
        u8         vl_admin[0x4];
 
-       u8         reserved_4[0x1c];
+       u8         reserved_at_60[0x1c];
        u8         vl_operational[0x4];
 };
 
 struct mlx5_ifc_pude_reg_bits {
        u8         swid[0x8];
        u8         local_port[0x8];
-       u8         reserved_0[0x4];
+       u8         reserved_at_10[0x4];
        u8         admin_status[0x4];
-       u8         reserved_1[0x4];
+       u8         reserved_at_18[0x4];
        u8         oper_status[0x4];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_ptys_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0xd];
+       u8         reserved_at_10[0xd];
        u8         proto_mask[0x3];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_20[0x40];
 
        u8         eth_proto_capability[0x20];
 
        u8         ib_link_width_capability[0x10];
        u8         ib_proto_capability[0x10];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_a0[0x20];
 
        u8         eth_proto_admin[0x20];
 
        u8         ib_link_width_admin[0x10];
        u8         ib_proto_admin[0x10];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_100[0x20];
 
        u8         eth_proto_oper[0x20];
 
        u8         ib_link_width_oper[0x10];
        u8         ib_proto_oper[0x10];
 
-       u8         reserved_5[0x20];
+       u8         reserved_at_160[0x20];
 
        u8         eth_proto_lp_advertise[0x20];
 
-       u8         reserved_6[0x60];
+       u8         reserved_at_1a0[0x60];
 };
 
 struct mlx5_ifc_ptas_reg_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
        u8         algorithm_options[0x10];
-       u8         reserved_1[0x4];
+       u8         reserved_at_30[0x4];
        u8         repetitions_mode[0x4];
        u8         num_of_repetitions[0x8];
 
@@ -6310,13 +6326,13 @@ struct mlx5_ifc_ptas_reg_bits {
        u8         ndeo_error_threshold[0x10];
 
        u8         mixer_offset_step_size[0x10];
-       u8         reserved_2[0x8];
+       u8         reserved_at_110[0x8];
        u8         mix90_phase_for_voltage_bath[0x8];
 
        u8         mixer_offset_start[0x10];
        u8         mixer_offset_end[0x10];
 
-       u8         reserved_3[0x15];
+       u8         reserved_at_140[0x15];
        u8         ber_test_time[0xb];
 };
 
@@ -6324,154 +6340,154 @@ struct mlx5_ifc_pspa_reg_bits {
        u8         swid[0x8];
        u8         local_port[0x8];
        u8         sub_port[0x8];
-       u8         reserved_0[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_20[0x20];
 };
 
 struct mlx5_ifc_pqdr_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x5];
+       u8         reserved_at_10[0x5];
        u8         prio[0x3];
-       u8         reserved_2[0x6];
+       u8         reserved_at_18[0x6];
        u8         mode[0x2];
 
-       u8         reserved_3[0x20];
+       u8         reserved_at_20[0x20];
 
-       u8         reserved_4[0x10];
+       u8         reserved_at_40[0x10];
        u8         min_threshold[0x10];
 
-       u8         reserved_5[0x10];
+       u8         reserved_at_60[0x10];
        u8         max_threshold[0x10];
 
-       u8         reserved_6[0x10];
+       u8         reserved_at_80[0x10];
        u8         mark_probability_denominator[0x10];
 
-       u8         reserved_7[0x60];
+       u8         reserved_at_a0[0x60];
 };
 
 struct mlx5_ifc_ppsc_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_20[0x60];
 
-       u8         reserved_3[0x1c];
+       u8         reserved_at_80[0x1c];
        u8         wrps_admin[0x4];
 
-       u8         reserved_4[0x1c];
+       u8         reserved_at_a0[0x1c];
        u8         wrps_status[0x4];
 
-       u8         reserved_5[0x8];
+       u8         reserved_at_c0[0x8];
        u8         up_threshold[0x8];
-       u8         reserved_6[0x8];
+       u8         reserved_at_d0[0x8];
        u8         down_threshold[0x8];
 
-       u8         reserved_7[0x20];
+       u8         reserved_at_e0[0x20];
 
-       u8         reserved_8[0x1c];
+       u8         reserved_at_100[0x1c];
        u8         srps_admin[0x4];
 
-       u8         reserved_9[0x1c];
+       u8         reserved_at_120[0x1c];
        u8         srps_status[0x4];
 
-       u8         reserved_10[0x40];
+       u8         reserved_at_140[0x40];
 };
 
 struct mlx5_ifc_pplr_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_20[0x8];
        u8         lb_cap[0x8];
-       u8         reserved_3[0x8];
+       u8         reserved_at_30[0x8];
        u8         lb_en[0x8];
 };
 
 struct mlx5_ifc_pplm_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_20[0x20];
 
        u8         port_profile_mode[0x8];
        u8         static_port_profile[0x8];
        u8         active_port_profile[0x8];
-       u8         reserved_3[0x8];
+       u8         reserved_at_58[0x8];
 
        u8         retransmission_active[0x8];
        u8         fec_mode_active[0x18];
 
-       u8         reserved_4[0x20];
+       u8         reserved_at_80[0x20];
 };
 
 struct mlx5_ifc_ppcnt_reg_bits {
        u8         swid[0x8];
        u8         local_port[0x8];
        u8         pnat[0x2];
-       u8         reserved_0[0x8];
+       u8         reserved_at_12[0x8];
        u8         grp[0x6];
 
        u8         clr[0x1];
-       u8         reserved_1[0x1c];
+       u8         reserved_at_21[0x1c];
        u8         prio_tc[0x3];
 
        union mlx5_ifc_eth_cntrs_grp_data_layout_auto_bits counter_set;
 };
 
 struct mlx5_ifc_ppad_reg_bits {
-       u8         reserved_0[0x3];
+       u8         reserved_at_0[0x3];
        u8         single_mac[0x1];
-       u8         reserved_1[0x4];
+       u8         reserved_at_4[0x4];
        u8         local_port[0x8];
        u8         mac_47_32[0x10];
 
        u8         mac_31_0[0x20];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_pmtu_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         max_mtu[0x10];
-       u8         reserved_2[0x10];
+       u8         reserved_at_30[0x10];
 
        u8         admin_mtu[0x10];
-       u8         reserved_3[0x10];
+       u8         reserved_at_50[0x10];
 
        u8         oper_mtu[0x10];
-       u8         reserved_4[0x10];
+       u8         reserved_at_70[0x10];
 };
 
 struct mlx5_ifc_pmpr_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         module[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0x18];
+       u8         reserved_at_20[0x18];
        u8         attenuation_5g[0x8];
 
-       u8         reserved_3[0x18];
+       u8         reserved_at_40[0x18];
        u8         attenuation_7g[0x8];
 
-       u8         reserved_4[0x18];
+       u8         reserved_at_60[0x18];
        u8         attenuation_12g[0x8];
 };
 
 struct mlx5_ifc_pmpe_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         module[0x8];
-       u8         reserved_1[0xc];
+       u8         reserved_at_10[0xc];
        u8         module_status[0x4];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_pmpc_reg_bits {
@@ -6479,20 +6495,20 @@ struct mlx5_ifc_pmpc_reg_bits {
 };
 
 struct mlx5_ifc_pmlpn_reg_bits {
-       u8         reserved_0[0x4];
+       u8         reserved_at_0[0x4];
        u8         mlpn_status[0x4];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         e[0x1];
-       u8         reserved_2[0x1f];
+       u8         reserved_at_21[0x1f];
 };
 
 struct mlx5_ifc_pmlp_reg_bits {
        u8         rxtx[0x1];
-       u8         reserved_0[0x7];
+       u8         reserved_at_1[0x7];
        u8         local_port[0x8];
-       u8         reserved_1[0x8];
+       u8         reserved_at_10[0x8];
        u8         width[0x8];
 
        u8         lane0_module_mapping[0x20];
@@ -6503,36 +6519,36 @@ struct mlx5_ifc_pmlp_reg_bits {
 
        u8         lane3_module_mapping[0x20];
 
-       u8         reserved_2[0x160];
+       u8         reserved_at_a0[0x160];
 };
 
 struct mlx5_ifc_pmaos_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         module[0x8];
-       u8         reserved_1[0x4];
+       u8         reserved_at_10[0x4];
        u8         admin_status[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_18[0x4];
        u8         oper_status[0x4];
 
        u8         ase[0x1];
        u8         ee[0x1];
-       u8         reserved_3[0x1c];
+       u8         reserved_at_22[0x1c];
        u8         e[0x2];
 
-       u8         reserved_4[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_plpc_reg_bits {
-       u8         reserved_0[0x4];
+       u8         reserved_at_0[0x4];
        u8         profile_id[0xc];
-       u8         reserved_1[0x4];
+       u8         reserved_at_10[0x4];
        u8         proto_mask[0x4];
-       u8         reserved_2[0x8];
+       u8         reserved_at_18[0x8];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_20[0x10];
        u8         lane_speed[0x10];
 
-       u8         reserved_4[0x17];
+       u8         reserved_at_40[0x17];
        u8         lpbf[0x1];
        u8         fec_mode_policy[0x8];
 
@@ -6545,44 +6561,44 @@ struct mlx5_ifc_plpc_reg_bits {
        u8         retransmission_request_admin[0x8];
        u8         fec_mode_request_admin[0x18];
 
-       u8         reserved_5[0x80];
+       u8         reserved_at_c0[0x80];
 };
 
 struct mlx5_ifc_plib_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x8];
+       u8         reserved_at_10[0x8];
        u8         ib_port[0x8];
 
-       u8         reserved_2[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_plbf_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0xd];
+       u8         reserved_at_10[0xd];
        u8         lbf_mode[0x3];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_20[0x20];
 };
 
 struct mlx5_ifc_pipg_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         dic[0x1];
-       u8         reserved_2[0x19];
+       u8         reserved_at_21[0x19];
        u8         ipg[0x4];
-       u8         reserved_3[0x2];
+       u8         reserved_at_3e[0x2];
 };
 
 struct mlx5_ifc_pifr_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0xe0];
+       u8         reserved_at_20[0xe0];
 
        u8         port_filter[8][0x20];
 
@@ -6590,36 +6606,36 @@ struct mlx5_ifc_pifr_reg_bits {
 };
 
 struct mlx5_ifc_pfcc_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         ppan[0x4];
-       u8         reserved_2[0x4];
+       u8         reserved_at_24[0x4];
        u8         prio_mask_tx[0x8];
-       u8         reserved_3[0x8];
+       u8         reserved_at_30[0x8];
        u8         prio_mask_rx[0x8];
 
        u8         pptx[0x1];
        u8         aptx[0x1];
-       u8         reserved_4[0x6];
+       u8         reserved_at_42[0x6];
        u8         pfctx[0x8];
-       u8         reserved_5[0x10];
+       u8         reserved_at_50[0x10];
 
        u8         pprx[0x1];
        u8         aprx[0x1];
-       u8         reserved_6[0x6];
+       u8         reserved_at_62[0x6];
        u8         pfcrx[0x8];
-       u8         reserved_7[0x10];
+       u8         reserved_at_70[0x10];
 
-       u8         reserved_8[0x80];
+       u8         reserved_at_80[0x80];
 };
 
 struct mlx5_ifc_pelc_reg_bits {
        u8         op[0x4];
-       u8         reserved_0[0x4];
+       u8         reserved_at_4[0x4];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         op_admin[0x8];
        u8         op_capability[0x8];
@@ -6634,28 +6650,28 @@ struct mlx5_ifc_pelc_reg_bits {
 
        u8         active[0x40];
 
-       u8         reserved_2[0x80];
+       u8         reserved_at_140[0x80];
 };
 
 struct mlx5_ifc_peir_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_2[0xc];
+       u8         reserved_at_20[0xc];
        u8         error_count[0x4];
-       u8         reserved_3[0x10];
+       u8         reserved_at_30[0x10];
 
-       u8         reserved_4[0xc];
+       u8         reserved_at_40[0xc];
        u8         lane[0x4];
-       u8         reserved_5[0x8];
+       u8         reserved_at_50[0x8];
        u8         error_type[0x8];
 };
 
 struct mlx5_ifc_pcap_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         local_port[0x8];
-       u8         reserved_1[0x10];
+       u8         reserved_at_10[0x10];
 
        u8         port_capability_mask[4][0x20];
 };
@@ -6663,46 +6679,46 @@ struct mlx5_ifc_pcap_reg_bits {
 struct mlx5_ifc_paos_reg_bits {
        u8         swid[0x8];
        u8         local_port[0x8];
-       u8         reserved_0[0x4];
+       u8         reserved_at_10[0x4];
        u8         admin_status[0x4];
-       u8         reserved_1[0x4];
+       u8         reserved_at_18[0x4];
        u8         oper_status[0x4];
 
        u8         ase[0x1];
        u8         ee[0x1];
-       u8         reserved_2[0x1c];
+       u8         reserved_at_22[0x1c];
        u8         e[0x2];
 
-       u8         reserved_3[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_pamp_reg_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         opamp_group[0x8];
-       u8         reserved_1[0xc];
+       u8         reserved_at_10[0xc];
        u8         opamp_group_type[0x4];
 
        u8         start_index[0x10];
-       u8         reserved_2[0x4];
+       u8         reserved_at_30[0x4];
        u8         num_of_indices[0xc];
 
        u8         index_data[18][0x10];
 };
 
 struct mlx5_ifc_lane_2_module_mapping_bits {
-       u8         reserved_0[0x6];
+       u8         reserved_at_0[0x6];
        u8         rx_lane[0x2];
-       u8         reserved_1[0x6];
+       u8         reserved_at_8[0x6];
        u8         tx_lane[0x2];
-       u8         reserved_2[0x8];
+       u8         reserved_at_10[0x8];
        u8         module[0x8];
 };
 
 struct mlx5_ifc_bufferx_reg_bits {
-       u8         reserved_0[0x6];
+       u8         reserved_at_0[0x6];
        u8         lossy[0x1];
        u8         epsb[0x1];
-       u8         reserved_1[0xc];
+       u8         reserved_at_8[0xc];
        u8         size[0xc];
 
        u8         xoff_threshold[0x10];
@@ -6714,21 +6730,21 @@ struct mlx5_ifc_set_node_in_bits {
 };
 
 struct mlx5_ifc_register_power_settings_bits {
-       u8         reserved_0[0x18];
+       u8         reserved_at_0[0x18];
        u8         power_settings_level[0x8];
 
-       u8         reserved_1[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_register_host_endianness_bits {
        u8         he[0x1];
-       u8         reserved_0[0x1f];
+       u8         reserved_at_1[0x1f];
 
-       u8         reserved_1[0x60];
+       u8         reserved_at_20[0x60];
 };
 
 struct mlx5_ifc_umr_pointer_desc_argument_bits {
-       u8         reserved_0[0x20];
+       u8         reserved_at_0[0x20];
 
        u8         mkey[0x20];
 
@@ -6741,7 +6757,7 @@ struct mlx5_ifc_ud_adrs_vector_bits {
        u8         dc_key[0x40];
 
        u8         ext[0x1];
-       u8         reserved_0[0x7];
+       u8         reserved_at_41[0x7];
        u8         destination_qp_dct[0x18];
 
        u8         static_rate[0x4];
@@ -6750,7 +6766,7 @@ struct mlx5_ifc_ud_adrs_vector_bits {
        u8         mlid[0x7];
        u8         rlid_udp_sport[0x10];
 
-       u8         reserved_1[0x20];
+       u8         reserved_at_80[0x20];
 
        u8         rmac_47_16[0x20];
 
@@ -6758,9 +6774,9 @@ struct mlx5_ifc_ud_adrs_vector_bits {
        u8         tclass[0x8];
        u8         hop_limit[0x8];
 
-       u8         reserved_2[0x1];
+       u8         reserved_at_e0[0x1];
        u8         grh[0x1];
-       u8         reserved_3[0x2];
+       u8         reserved_at_e2[0x2];
        u8         src_addr_index[0x8];
        u8         flow_label[0x14];
 
@@ -6768,27 +6784,27 @@ struct mlx5_ifc_ud_adrs_vector_bits {
 };
 
 struct mlx5_ifc_pages_req_event_bits {
-       u8         reserved_0[0x10];
+       u8         reserved_at_0[0x10];
        u8         function_id[0x10];
 
        u8         num_pages[0x20];
 
-       u8         reserved_1[0xa0];
+       u8         reserved_at_40[0xa0];
 };
 
 struct mlx5_ifc_eqe_bits {
-       u8         reserved_0[0x8];
+       u8         reserved_at_0[0x8];
        u8         event_type[0x8];
-       u8         reserved_1[0x8];
+       u8         reserved_at_10[0x8];
        u8         event_sub_type[0x8];
 
-       u8         reserved_2[0xe0];
+       u8         reserved_at_20[0xe0];
 
        union mlx5_ifc_event_auto_bits event_data;
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_1e0[0x10];
        u8         signature[0x8];
-       u8         reserved_4[0x7];
+       u8         reserved_at_1f8[0x7];
        u8         owner[0x1];
 };
 
@@ -6798,14 +6814,14 @@ enum {
 
 struct mlx5_ifc_cmd_queue_entry_bits {
        u8         type[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         input_length[0x20];
 
        u8         input_mailbox_pointer_63_32[0x20];
 
        u8         input_mailbox_pointer_31_9[0x17];
-       u8         reserved_1[0x9];
+       u8         reserved_at_77[0x9];
 
        u8         command_input_inline_data[16][0x8];
 
@@ -6814,20 +6830,20 @@ struct mlx5_ifc_cmd_queue_entry_bits {
        u8         output_mailbox_pointer_63_32[0x20];
 
        u8         output_mailbox_pointer_31_9[0x17];
-       u8         reserved_2[0x9];
+       u8         reserved_at_1b7[0x9];
 
        u8         output_length[0x20];
 
        u8         token[0x8];
        u8         signature[0x8];
-       u8         reserved_3[0x8];
+       u8         reserved_at_1f0[0x8];
        u8         status[0x7];
        u8         ownership[0x1];
 };
 
 struct mlx5_ifc_cmd_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
@@ -6836,9 +6852,9 @@ struct mlx5_ifc_cmd_out_bits {
 
 struct mlx5_ifc_cmd_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
        u8         command[0][0x20];
@@ -6847,16 +6863,16 @@ struct mlx5_ifc_cmd_in_bits {
 struct mlx5_ifc_cmd_if_box_bits {
        u8         mailbox_data[512][0x8];
 
-       u8         reserved_0[0x180];
+       u8         reserved_at_1000[0x180];
 
        u8         next_pointer_63_32[0x20];
 
        u8         next_pointer_31_10[0x16];
-       u8         reserved_1[0xa];
+       u8         reserved_at_11b6[0xa];
 
        u8         block_number[0x20];
 
-       u8         reserved_2[0x8];
+       u8         reserved_at_11e0[0x8];
        u8         token[0x8];
        u8         ctrl_signature[0x8];
        u8         signature[0x8];
@@ -6866,11 +6882,59 @@ struct mlx5_ifc_mtt_bits {
        u8         ptag_63_32[0x20];
 
        u8         ptag_31_8[0x18];
-       u8         reserved_0[0x6];
+       u8         reserved_at_38[0x6];
        u8         wr_en[0x1];
        u8         rd_en[0x1];
 };
 
+struct mlx5_ifc_query_wol_rol_out_bits {
+       u8         status[0x8];
+       u8         reserved_at_8[0x18];
+
+       u8         syndrome[0x20];
+
+       u8         reserved_at_40[0x10];
+       u8         rol_mode[0x8];
+       u8         wol_mode[0x8];
+
+       u8         reserved_at_60[0x20];
+};
+
+struct mlx5_ifc_query_wol_rol_in_bits {
+       u8         opcode[0x10];
+       u8         reserved_at_10[0x10];
+
+       u8         reserved_at_20[0x10];
+       u8         op_mod[0x10];
+
+       u8         reserved_at_40[0x40];
+};
+
+struct mlx5_ifc_set_wol_rol_out_bits {
+       u8         status[0x8];
+       u8         reserved_at_8[0x18];
+
+       u8         syndrome[0x20];
+
+       u8         reserved_at_40[0x40];
+};
+
+struct mlx5_ifc_set_wol_rol_in_bits {
+       u8         opcode[0x10];
+       u8         reserved_at_10[0x10];
+
+       u8         reserved_at_20[0x10];
+       u8         op_mod[0x10];
+
+       u8         rol_mode_valid[0x1];
+       u8         wol_mode_valid[0x1];
+       u8         reserved_at_42[0xe];
+       u8         rol_mode[0x8];
+       u8         wol_mode[0x8];
+
+       u8         reserved_at_60[0x20];
+};
+
 enum {
        MLX5_INITIAL_SEG_NIC_INTERFACE_FULL_DRIVER  = 0x0,
        MLX5_INITIAL_SEG_NIC_INTERFACE_DISABLED     = 0x1,
@@ -6904,38 +6968,38 @@ struct mlx5_ifc_initial_seg_bits {
        u8         cmd_interface_rev[0x10];
        u8         fw_rev_subminor[0x10];
 
-       u8         reserved_0[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         cmdq_phy_addr_63_32[0x20];
 
        u8         cmdq_phy_addr_31_12[0x14];
-       u8         reserved_1[0x2];
+       u8         reserved_at_b4[0x2];
        u8         nic_interface[0x2];
        u8         log_cmdq_size[0x4];
        u8         log_cmdq_stride[0x4];
 
        u8         command_doorbell_vector[0x20];
 
-       u8         reserved_2[0xf00];
+       u8         reserved_at_e0[0xf00];
 
        u8         initializing[0x1];
-       u8         reserved_3[0x4];
+       u8         reserved_at_fe1[0x4];
        u8         nic_interface_supported[0x3];
-       u8         reserved_4[0x18];
+       u8         reserved_at_fe8[0x18];
 
        struct mlx5_ifc_health_buffer_bits health_buffer;
 
        u8         no_dram_nic_offset[0x20];
 
-       u8         reserved_5[0x6e40];
+       u8         reserved_at_1220[0x6e40];
 
-       u8         reserved_6[0x1f];
+       u8         reserved_at_8060[0x1f];
        u8         clear_int[0x1];
 
        u8         health_syndrome[0x8];
        u8         health_counter[0x18];
 
-       u8         reserved_7[0x17fc0];
+       u8         reserved_at_80a0[0x17fc0];
 };
 
 union mlx5_ifc_ports_control_registers_document_bits {
@@ -6980,44 +7044,44 @@ union mlx5_ifc_ports_control_registers_document_bits {
        struct mlx5_ifc_pvlc_reg_bits pvlc_reg;
        struct mlx5_ifc_slrg_reg_bits slrg_reg;
        struct mlx5_ifc_sltp_reg_bits sltp_reg;
-       u8         reserved_0[0x60e0];
+       u8         reserved_at_0[0x60e0];
 };
 
 union mlx5_ifc_debug_enhancements_document_bits {
        struct mlx5_ifc_health_buffer_bits health_buffer;
-       u8         reserved_0[0x200];
+       u8         reserved_at_0[0x200];
 };
 
 union mlx5_ifc_uplink_pci_interface_document_bits {
        struct mlx5_ifc_initial_seg_bits initial_seg;
-       u8         reserved_0[0x20060];
+       u8         reserved_at_0[0x20060];
 };
 
 struct mlx5_ifc_set_flow_table_root_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_set_flow_table_root_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x40];
+       u8         reserved_at_40[0x40];
 
        u8         table_type[0x8];
-       u8         reserved_3[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_4[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_5[0x140];
+       u8         reserved_at_c0[0x140];
 };
 
 enum {
@@ -7026,39 +7090,84 @@ enum {
 
 struct mlx5_ifc_modify_flow_table_out_bits {
        u8         status[0x8];
-       u8         reserved_0[0x18];
+       u8         reserved_at_8[0x18];
 
        u8         syndrome[0x20];
 
-       u8         reserved_1[0x40];
+       u8         reserved_at_40[0x40];
 };
 
 struct mlx5_ifc_modify_flow_table_in_bits {
        u8         opcode[0x10];
-       u8         reserved_0[0x10];
+       u8         reserved_at_10[0x10];
 
-       u8         reserved_1[0x10];
+       u8         reserved_at_20[0x10];
        u8         op_mod[0x10];
 
-       u8         reserved_2[0x20];
+       u8         reserved_at_40[0x20];
 
-       u8         reserved_3[0x10];
+       u8         reserved_at_60[0x10];
        u8         modify_field_select[0x10];
 
        u8         table_type[0x8];
-       u8         reserved_4[0x18];
+       u8         reserved_at_88[0x18];
 
-       u8         reserved_5[0x8];
+       u8         reserved_at_a0[0x8];
        u8         table_id[0x18];
 
-       u8         reserved_6[0x4];
+       u8         reserved_at_c0[0x4];
        u8         table_miss_mode[0x4];
-       u8         reserved_7[0x18];
+       u8         reserved_at_c8[0x18];
 
-       u8         reserved_8[0x8];
+       u8         reserved_at_e0[0x8];
        u8         table_miss_id[0x18];
 
-       u8         reserved_9[0x100];
+       u8         reserved_at_100[0x100];
+};
+
+struct mlx5_ifc_ets_tcn_config_reg_bits {
+       u8         g[0x1];
+       u8         b[0x1];
+       u8         r[0x1];
+       u8         reserved_at_3[0x9];
+       u8         group[0x4];
+       u8         reserved_at_10[0x9];
+       u8         bw_allocation[0x7];
+
+       u8         reserved_at_20[0xc];
+       u8         max_bw_units[0x4];
+       u8         reserved_at_30[0x8];
+       u8         max_bw_value[0x8];
+};
+
+struct mlx5_ifc_ets_global_config_reg_bits {
+       u8         reserved_at_0[0x2];
+       u8         r[0x1];
+       u8         reserved_at_3[0x1d];
+
+       u8         reserved_at_20[0xc];
+       u8         max_bw_units[0x4];
+       u8         reserved_at_30[0x8];
+       u8         max_bw_value[0x8];
+};
+
+struct mlx5_ifc_qetc_reg_bits {
+       u8                                         reserved_at_0[0x8];
+       u8                                         port_number[0x8];
+       u8                                         reserved_at_10[0x30];
+
+       struct mlx5_ifc_ets_tcn_config_reg_bits    tc_configuration[0x8];
+       struct mlx5_ifc_ets_global_config_reg_bits global_configuration;
+};
+
+struct mlx5_ifc_qtct_reg_bits {
+       u8         reserved_at_0[0x8];
+       u8         port_number[0x8];
+       u8         reserved_at_10[0xd];
+       u8         prio[0x3];
+
+       u8         reserved_at_20[0x1d];
+       u8         tclass[0x3];
 };
 
 #endif /* MLX5_IFC_H */
diff --git a/include/linux/mlx5/port.h b/include/linux/mlx5/port.h
new file mode 100644 (file)
index 0000000..a1d145a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_PORT_H__
+#define __MLX5_PORT_H__
+
+#include <linux/mlx5/driver.h>
+
+int mlx5_set_port_caps(struct mlx5_core_dev *dev, u8 port_num, u32 caps);
+int mlx5_query_port_ptys(struct mlx5_core_dev *dev, u32 *ptys,
+                        int ptys_size, int proto_mask, u8 local_port);
+int mlx5_query_port_proto_cap(struct mlx5_core_dev *dev,
+                             u32 *proto_cap, int proto_mask);
+int mlx5_query_port_proto_admin(struct mlx5_core_dev *dev,
+                               u32 *proto_admin, int proto_mask);
+int mlx5_query_port_link_width_oper(struct mlx5_core_dev *dev,
+                                   u8 *link_width_oper, u8 local_port);
+int mlx5_query_port_proto_oper(struct mlx5_core_dev *dev,
+                              u8 *proto_oper, int proto_mask,
+                              u8 local_port);
+int mlx5_set_port_proto(struct mlx5_core_dev *dev, u32 proto_admin,
+                       int proto_mask);
+int mlx5_set_port_admin_status(struct mlx5_core_dev *dev,
+                              enum mlx5_port_status status);
+int mlx5_query_port_admin_status(struct mlx5_core_dev *dev,
+                                enum mlx5_port_status *status);
+
+int mlx5_set_port_mtu(struct mlx5_core_dev *dev, int mtu, u8 port);
+void mlx5_query_port_max_mtu(struct mlx5_core_dev *dev, int *max_mtu, u8 port);
+void mlx5_query_port_oper_mtu(struct mlx5_core_dev *dev, int *oper_mtu,
+                             u8 port);
+
+int mlx5_query_port_vl_hw_cap(struct mlx5_core_dev *dev,
+                             u8 *vl_hw_cap, u8 local_port);
+
+int mlx5_set_port_pause(struct mlx5_core_dev *dev, u32 rx_pause, u32 tx_pause);
+int mlx5_query_port_pause(struct mlx5_core_dev *dev,
+                         u32 *rx_pause, u32 *tx_pause);
+
+int mlx5_set_port_pfc(struct mlx5_core_dev *dev, u8 pfc_en_tx, u8 pfc_en_rx);
+int mlx5_query_port_pfc(struct mlx5_core_dev *dev, u8 *pfc_en_tx,
+                       u8 *pfc_en_rx);
+
+int mlx5_max_tc(struct mlx5_core_dev *mdev);
+
+int mlx5_set_port_prio_tc(struct mlx5_core_dev *mdev, u8 *prio_tc);
+int mlx5_set_port_tc_group(struct mlx5_core_dev *mdev, u8 *tc_group);
+int mlx5_set_port_tc_bw_alloc(struct mlx5_core_dev *mdev, u8 *tc_bw);
+int mlx5_modify_port_ets_rate_limit(struct mlx5_core_dev *mdev,
+                                   u8 *max_bw_value,
+                                   u8 *max_bw_unit);
+int mlx5_query_port_ets_rate_limit(struct mlx5_core_dev *mdev,
+                                  u8 *max_bw_value,
+                                  u8 *max_bw_unit);
+int mlx5_set_port_wol(struct mlx5_core_dev *mdev, u8 wol_mode);
+int mlx5_query_port_wol(struct mlx5_core_dev *mdev, u8 *wol_mode);
+
+#endif /* __MLX5_PORT_H__ */
index f1cd22f2df1ac50438e7d70bb0df85c44580b8d3..516e149443397dcf712e4e62aca6fb3c78e542b6 100644 (file)
@@ -201,11 +201,13 @@ extern unsigned int kobjsize(const void *objp);
 #endif
 
 #ifdef CONFIG_STACK_GROWSUP
-#define VM_STACK_FLAGS (VM_GROWSUP | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+#define VM_STACK       VM_GROWSUP
 #else
-#define VM_STACK_FLAGS (VM_GROWSDOWN | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+#define VM_STACK       VM_GROWSDOWN
 #endif
 
+#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+
 /*
  * Special vmas that are non-mergable, non-mlock()able.
  * Note: mm/huge_memory.c VM_NO_THP depends on this definition.
@@ -1341,8 +1343,7 @@ static inline int stack_guard_page_end(struct vm_area_struct *vma,
                !vma_growsup(vma->vm_next, addr);
 }
 
-extern struct task_struct *task_of_stack(struct task_struct *task,
-                               struct vm_area_struct *vma, bool in_group);
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t);
 
 extern unsigned long move_page_tables(struct vm_area_struct *vma,
                unsigned long old_addr, struct vm_area_struct *new_vma,
index d3ebb9d21a5334d26e85bc865d318535f5864569..624b78b848b89fae506faa1f4f48ce86297ceace 100644 (file)
@@ -424,9 +424,9 @@ struct mm_struct {
        unsigned long total_vm;         /* Total pages mapped */
        unsigned long locked_vm;        /* Pages that have PG_mlocked set */
        unsigned long pinned_vm;        /* Refcount permanently increased */
-       unsigned long data_vm;          /* VM_WRITE & ~VM_SHARED/GROWSDOWN */
-       unsigned long exec_vm;          /* VM_EXEC & ~VM_WRITE */
-       unsigned long stack_vm;         /* VM_GROWSUP/DOWN */
+       unsigned long data_vm;          /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
+       unsigned long exec_vm;          /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
+       unsigned long stack_vm;         /* VM_STACK */
        unsigned long def_flags;
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long start_brk, brk, start_stack;
index 33bb1b19273e3ad165382f4c7f0f3cd8f8c0b407..7b6c2cfee390e939e13b0f14c92224bcb3aafcf4 100644 (file)
@@ -682,6 +682,12 @@ typedef struct pglist_data {
         */
        unsigned long first_deferred_pfn;
 #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       spinlock_t split_queue_lock;
+       struct list_head split_queue;
+       unsigned long split_queue_len;
+#endif
 } pg_data_t;
 
 #define node_present_pages(nid)        (NODE_DATA(nid)->node_present_pages)
index 4560d8f1545d2cec7e6da19da460fff26151c105..2bb0c308570672e7105b14f85a4215b0f9500207 100644 (file)
@@ -324,6 +324,12 @@ struct module_layout {
 #define __module_layout_align
 #endif
 
+struct mod_kallsyms {
+       Elf_Sym *symtab;
+       unsigned int num_symtab;
+       char *strtab;
+};
+
 struct module {
        enum module_state state;
 
@@ -405,15 +411,10 @@ struct module {
 #endif
 
 #ifdef CONFIG_KALLSYMS
-       /*
-        * We keep the symbol and string tables for kallsyms.
-        * The core_* fields below are temporary, loader-only (they
-        * could really be discarded after module init).
-        */
-       Elf_Sym *symtab, *core_symtab;
-       unsigned int num_symtab, core_num_syms;
-       char *strtab, *core_strtab;
-
+       /* Protected by RCU and/or module_mutex: use rcu_dereference() */
+       struct mod_kallsyms *kallsyms;
+       struct mod_kallsyms core_kallsyms;
+       
        /* Section attributes */
        struct module_sect_attrs *sect_attrs;
 
index 0b4ac7da583a8b2dff7983b4602cb9a81887ea86..49175e4ced11288c535eb41cf967683858d6bc3b 100644 (file)
@@ -215,6 +215,7 @@ int __sock_create(struct net *net, int family, int type, int proto,
 int sock_create(int family, int type, int proto, struct socket **res);
 int sock_create_kern(struct net *net, int family, int type, int proto, struct socket **res);
 int sock_create_lite(int family, int type, int proto, struct socket **res);
+struct socket *sock_alloc(void);
 void sock_release(struct socket *sock);
 int sock_sendmsg(struct socket *sock, struct msghdr *msg);
 int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
index d9654f0eecb3519383441afa6b131ff9a5898485..a734bf43d1902b7e7299d98de54da1d9d303cbd7 100644 (file)
@@ -67,6 +67,8 @@ enum {
        NETIF_F_HW_L2FW_DOFFLOAD_BIT,   /* Allow L2 Forwarding in Hardware */
        NETIF_F_BUSY_POLL_BIT,          /* Busy poll */
 
+       NETIF_F_HW_TC_BIT,              /* Offload TC infrastructure */
+
        /*
         * Add your fresh new feature above and remember to update
         * netdev_features_strings[] in net/core/ethtool.c and maybe
@@ -124,6 +126,7 @@ enum {
 #define NETIF_F_HW_VLAN_STAG_TX        __NETIF_F(HW_VLAN_STAG_TX)
 #define NETIF_F_HW_L2FW_DOFFLOAD       __NETIF_F(HW_L2FW_DOFFLOAD)
 #define NETIF_F_BUSY_POLL      __NETIF_F(BUSY_POLL)
+#define NETIF_F_HW_TC          __NETIF_F(HW_TC)
 
 #define for_each_netdev_feature(mask_addr, bit)        \
        for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
index 219f53c30cb3cd4a9a2fdd1c2a2d3ca343f28bca..be693b34662f9c95ec4de34ed4cf4b558a1e9738 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/neighbour.h>
 #include <uapi/linux/netdevice.h>
 #include <uapi/linux/if_bonding.h>
+#include <uapi/linux/pkt_cls.h>
 
 struct netpoll_info;
 struct device;
@@ -267,6 +268,7 @@ struct header_ops {
        void    (*cache_update)(struct hh_cache *hh,
                                const struct net_device *dev,
                                const unsigned char *haddr);
+       bool    (*validate)(const char *ll_header, unsigned int len);
 };
 
 /* These flag bits are private to the generic network queueing
@@ -778,6 +780,27 @@ static inline bool netdev_phys_item_id_same(struct netdev_phys_item_id *a,
 typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
                                       struct sk_buff *skb);
 
+/* These structures hold the attributes of qdisc and classifiers
+ * that are being passed to the netdevice through the setup_tc op.
+ */
+enum {
+       TC_SETUP_MQPRIO,
+       TC_SETUP_CLSU32,
+       TC_SETUP_CLSFLOWER,
+};
+
+struct tc_cls_u32_offload;
+
+struct tc_to_netdev {
+       unsigned int type;
+       union {
+               u8 tc;
+               struct tc_cls_u32_offload *cls_u32;
+               struct tc_cls_flower_offload *cls_flower;
+       };
+};
+
+
 /*
  * This structure defines the management hooks for network devices.
  * The following hooks can be defined; unless noted otherwise, they are
@@ -1073,6 +1096,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     This function is used to get egress tunnel information for given skb.
  *     This is useful for retrieving outer tunnel header parameters while
  *     sampling packet.
+ * void (*ndo_set_rx_headroom)(struct net_device *dev, int needed_headroom);
+ *     This function is used to specify the headroom that the skb must
+ *     consider when allocation skb during packet reception. Setting
+ *     appropriate rx headroom value allows avoiding skb head copy on
+ *     forward. Setting a negative value reset the rx headroom to the
+ *     default value.
  *
  */
 struct net_device_ops {
@@ -1150,7 +1179,10 @@ struct net_device_ops {
        int                     (*ndo_set_vf_rss_query_en)(
                                                   struct net_device *dev,
                                                   int vf, bool setting);
-       int                     (*ndo_setup_tc)(struct net_device *dev, u8 tc);
+       int                     (*ndo_setup_tc)(struct net_device *dev,
+                                               u32 handle,
+                                               __be16 protocol,
+                                               struct tc_to_netdev *tc);
 #if IS_ENABLED(CONFIG_FCOE)
        int                     (*ndo_fcoe_enable)(struct net_device *dev);
        int                     (*ndo_fcoe_disable)(struct net_device *dev);
@@ -1255,6 +1287,8 @@ struct net_device_ops {
                                                         bool proto_down);
        int                     (*ndo_fill_metadata_dst)(struct net_device *dev,
                                                       struct sk_buff *skb);
+       void                    (*ndo_set_rx_headroom)(struct net_device *dev,
+                                                      int needed_headroom);
 };
 
 /**
@@ -1291,6 +1325,10 @@ struct net_device_ops {
  * @IFF_OPENVSWITCH: device is a Open vSwitch master
  * @IFF_L3MDEV_SLAVE: device is enslaved to an L3 master device
  * @IFF_TEAM: device is a team device
+ * @IFF_RXFH_CONFIGURED: device has had Rx Flow indirection table configured
+ * @IFF_PHONY_HEADROOM: the headroom value is controlled by an external
+ *     entity (i.e. the master device for bridged veth)
+ * @IFF_MACSEC: device is a MACsec device
  */
 enum netdev_priv_flags {
        IFF_802_1Q_VLAN                 = 1<<0,
@@ -1318,6 +1356,9 @@ enum netdev_priv_flags {
        IFF_OPENVSWITCH                 = 1<<22,
        IFF_L3MDEV_SLAVE                = 1<<23,
        IFF_TEAM                        = 1<<24,
+       IFF_RXFH_CONFIGURED             = 1<<25,
+       IFF_PHONY_HEADROOM              = 1<<26,
+       IFF_MACSEC                      = 1<<27,
 };
 
 #define IFF_802_1Q_VLAN                        IFF_802_1Q_VLAN
@@ -1345,6 +1386,8 @@ enum netdev_priv_flags {
 #define IFF_OPENVSWITCH                        IFF_OPENVSWITCH
 #define IFF_L3MDEV_SLAVE               IFF_L3MDEV_SLAVE
 #define IFF_TEAM                       IFF_TEAM
+#define IFF_RXFH_CONFIGURED            IFF_RXFH_CONFIGURED
+#define IFF_MACSEC                     IFF_MACSEC
 
 /**
  *     struct net_device - The DEVICE structure.
@@ -1422,8 +1465,7 @@ enum netdev_priv_flags {
  *     @dma:           DMA channel
  *     @mtu:           Interface MTU value
  *     @type:          Interface hardware type
- *     @hard_header_len: Hardware header length, which means that this is the
- *                       minimum size of a packet.
+ *     @hard_header_len: Maximum hardware header length.
  *
  *     @needed_headroom: Extra headroom the hardware may need, but not in all
  *                       cases can this be guaranteed
@@ -1911,6 +1953,26 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev,
                                    struct sk_buff *skb,
                                    void *accel_priv);
 
+/* returns the headroom that the master device needs to take in account
+ * when forwarding to this dev
+ */
+static inline unsigned netdev_get_fwd_headroom(struct net_device *dev)
+{
+       return dev->priv_flags & IFF_PHONY_HEADROOM ? 0 : dev->needed_headroom;
+}
+
+static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr)
+{
+       if (dev->netdev_ops->ndo_set_rx_headroom)
+               dev->netdev_ops->ndo_set_rx_headroom(dev, new_hr);
+}
+
+/* set the device rx headroom to the dev's default */
+static inline void netdev_reset_rx_headroom(struct net_device *dev)
+{
+       netdev_set_rx_headroom(dev, -1);
+}
+
 /*
  * Net namespace inlines
  */
@@ -2630,6 +2692,24 @@ static inline int dev_parse_header(const struct sk_buff *skb,
        return dev->header_ops->parse(skb, haddr);
 }
 
+/* ll_header must have at least hard_header_len allocated */
+static inline bool dev_validate_header(const struct net_device *dev,
+                                      char *ll_header, int len)
+{
+       if (likely(len >= dev->hard_header_len))
+               return true;
+
+       if (capable(CAP_SYS_RAWIO)) {
+               memset(ll_header + len, 0, dev->hard_header_len - len);
+               return true;
+       }
+
+       if (dev->header_ops && dev->header_ops->validate)
+               return dev->header_ops->validate(ll_header, len);
+
+       return false;
+}
+
 typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len);
 int register_gifconf(unsigned int family, gifconf_func_t *gifconf);
 static inline int unregister_gifconf(unsigned int family)
@@ -3721,7 +3801,7 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
 void *netdev_lower_get_next(struct net_device *dev,
                                struct list_head **iter);
 #define netdev_for_each_lower_dev(dev, ldev, iter) \
-       for (iter = &(dev)->adj_list.lower, \
+       for (iter = (dev)->adj_list.lower.next, \
             ldev = netdev_lower_get_next(dev, &(iter)); \
             ldev; \
             ldev = netdev_lower_get_next(dev, &(iter)))
@@ -3968,6 +4048,11 @@ static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol,
        skb->mac_len = mac_len;
 }
 
+static inline bool netif_is_macsec(const struct net_device *dev)
+{
+       return dev->priv_flags & IFF_MACSEC;
+}
+
 static inline bool netif_is_macvlan(const struct net_device *dev)
 {
        return dev->priv_flags & IFF_MACVLAN;
@@ -4048,6 +4133,11 @@ static inline bool netif_is_lag_port(const struct net_device *dev)
        return netif_is_bond_slave(dev) || netif_is_team_port(dev);
 }
 
+static inline bool netif_is_rxfh_configured(const struct net_device *dev)
+{
+       return dev->priv_flags & IFF_RXFH_CONFIGURED;
+}
+
 /* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */
 static inline void netif_keep_dst(struct net_device *dev)
 {
index 0ad556726181ada44d9f137502b65e6a10c242c7..9230f9aee896facb508fcf23df9e48e842a976c9 100644 (file)
@@ -141,22 +141,6 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
 #ifdef HAVE_JUMP_LABEL
 extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
-
-static inline bool nf_hook_list_active(struct list_head *hook_list,
-                                      u_int8_t pf, unsigned int hook)
-{
-       if (__builtin_constant_p(pf) &&
-           __builtin_constant_p(hook))
-               return static_key_false(&nf_hooks_needed[pf][hook]);
-
-       return !list_empty(hook_list);
-}
-#else
-static inline bool nf_hook_list_active(struct list_head *hook_list,
-                                      u_int8_t pf, unsigned int hook)
-{
-       return !list_empty(hook_list);
-}
 #endif
 
 int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
@@ -177,9 +161,18 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
                                 int (*okfn)(struct net *, struct sock *, struct sk_buff *),
                                 int thresh)
 {
-       struct list_head *hook_list = &net->nf.hooks[pf][hook];
+       struct list_head *hook_list;
+
+#ifdef HAVE_JUMP_LABEL
+       if (__builtin_constant_p(pf) &&
+           __builtin_constant_p(hook) &&
+           !static_key_false(&nf_hooks_needed[pf][hook]))
+               return 1;
+#endif
+
+       hook_list = &net->nf.hooks[pf][hook];
 
-       if (nf_hook_list_active(hook_list, pf, hook)) {
+       if (!list_empty(hook_list)) {
                struct nf_hook_state state;
 
                nf_hook_state_init(&state, hook_list, hook, thresh,
index ba0d9789eb6e95684528ed6e388a13ccd6ee1e53..1d82dd5e9a08ada113978fc9752585d62dfcba98 100644 (file)
@@ -34,8 +34,6 @@ int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
 int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
 
 int nfnetlink_has_listeners(struct net *net, unsigned int group);
-struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
-                                   u32 dst_portid, gfp_t gfp_mask);
 int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
                   unsigned int group, int echo, gfp_t flags);
 int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error);
index c5577410c25d3b6b3520811c994a1f3d20ed1488..80a305b85323a3452c30445a1137a29cce5f1600 100644 (file)
@@ -200,6 +200,9 @@ struct xt_table {
        u_int8_t af;            /* address/protocol family */
        int priority;           /* hook order */
 
+       /* called when table is needed in the given netns */
+       int (*table_init)(struct net *net);
+
        /* A unique name... */
        const char name[XT_TABLE_MAXNAMELEN];
 };
@@ -408,8 +411,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)
        return cnt;
 }
 
-struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
-void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
+struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);
 
 #ifdef CONFIG_COMPAT
 #include <net/compat.h>
index 6f074db2f23def7befbf60dd41792e554503db6c..029b95e8924e02bd5e89f305f39b3df13759a6d7 100644 (file)
@@ -48,10 +48,11 @@ struct arpt_error {
 }
 
 extern void *arpt_alloc_initial_table(const struct xt_table *);
-extern struct xt_table *arpt_register_table(struct net *net,
-                                           const struct xt_table *table,
-                                           const struct arpt_replace *repl);
-extern void arpt_unregister_table(struct xt_table *table);
+int arpt_register_table(struct net *net, const struct xt_table *table,
+                       const struct arpt_replace *repl,
+                       const struct nf_hook_ops *ops, struct xt_table **res);
+void arpt_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops);
 extern unsigned int arpt_do_table(struct sk_buff *skb,
                                  const struct nf_hook_state *state,
                                  struct xt_table *table);
index aa598f942c01a8d549302d570d17b6fa95198569..7bfc5893ec314e247693374131a31f0144da20d3 100644 (file)
 
 extern void ipt_init(void) __init;
 
-extern struct xt_table *ipt_register_table(struct net *net,
-                                          const struct xt_table *table,
-                                          const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct net *net, struct xt_table *table);
+int ipt_register_table(struct net *net, const struct xt_table *table,
+                      const struct ipt_replace *repl,
+                      const struct nf_hook_ops *ops, struct xt_table **res);
+void ipt_unregister_table(struct net *net, struct xt_table *table,
+                         const struct nf_hook_ops *ops);
 
 /* Standard entry. */
 struct ipt_standard {
index 0f76e5c674f9920ecc8ccb56635fa4353ea2136c..b21c392d6012837abb89858e1ea407130583b7d9 100644 (file)
 extern void ip6t_init(void) __init;
 
 extern void *ip6t_alloc_initial_table(const struct xt_table *);
-extern struct xt_table *ip6t_register_table(struct net *net,
-                                           const struct xt_table *table,
-                                           const struct ip6t_replace *repl);
-extern void ip6t_unregister_table(struct net *net, struct xt_table *table);
+int ip6t_register_table(struct net *net, const struct xt_table *table,
+                       const struct ip6t_replace *repl,
+                       const struct nf_hook_ops *ops, struct xt_table **res);
+void ip6t_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops);
 extern unsigned int ip6t_do_table(struct sk_buff *skb,
                                  const struct nf_hook_state *state,
                                  struct xt_table *table);
index 0b41959aab9f8fa4c5901b3ad054e63746c4b74a..da14ab61f3634cae5c9ec1636c2774a6f388083d 100644 (file)
@@ -69,16 +69,6 @@ extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group)
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_has_listeners(struct sock *sk, unsigned int group);
 
-extern struct sk_buff *__netlink_alloc_skb(struct sock *ssk, unsigned int size,
-                                          unsigned int ldiff, u32 dst_portid,
-                                          gfp_t gfp_mask);
-static inline struct sk_buff *
-netlink_alloc_skb(struct sock *ssk, unsigned int size, u32 dst_portid,
-                 gfp_t gfp_mask)
-{
-       return __netlink_alloc_skb(ssk, size, 0, dst_portid, gfp_mask);
-}
-
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
 extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
                             __u32 group, gfp_t allocation);
index 48e0320cd6432463b86cc3d7684d5ecd4ab48651..67300f8e5f2f0248e8651cbe17e5c14e1110ca2c 100644 (file)
@@ -550,9 +550,7 @@ extern int  nfs_readpage_async(struct nfs_open_context *, struct inode *,
 
 static inline loff_t nfs_size_to_loff_t(__u64 size)
 {
-       if (size > (__u64) OFFSET_MAX - 1)
-               return OFFSET_MAX - 1;
-       return (loff_t) size;
+       return min_t(u64, size, OFFSET_MAX);
 }
 
 static inline ino_t
index 791098a08a8765bea64b4137baaf12ef4af62ac8..d320906cf13e5d7d3d443a6249992202eb171f59 100644 (file)
@@ -275,6 +275,7 @@ struct nfs4_layoutcommit_args {
        size_t layoutupdate_len;
        struct page *layoutupdate_page;
        struct page **layoutupdate_pages;
+       __be32 *start_p;
 };
 
 struct nfs4_layoutcommit_res {
index dd10626a615fb160587ecf09f860de36ba583c19..dc6e39696b64c8e925601f598b9cdab5684f1970 100644 (file)
@@ -929,7 +929,7 @@ static inline int of_get_available_child_count(const struct device_node *np)
        return num;
 }
 
-#ifdef CONFIG_OF
+#if defined(CONFIG_OF) && !defined(MODULE)
 #define _OF_DECLARE(table, name, compat, fn, fn_type)                  \
        static const struct of_device_id __of_table_##name              \
                __used __section(__##table##_of_table)                  \
index 27df4a6585daedcc6a74865bf048cfd06a0593ba..27716254dcc54bd6d6ca5e864f58e92fd94ea305 100644 (file)
@@ -988,23 +988,6 @@ static inline int pci_is_managed(struct pci_dev *pdev)
        return pdev->is_managed;
 }
 
-static inline void pci_set_managed_irq(struct pci_dev *pdev, unsigned int irq)
-{
-       pdev->irq = irq;
-       pdev->irq_managed = 1;
-}
-
-static inline void pci_reset_managed_irq(struct pci_dev *pdev)
-{
-       pdev->irq = 0;
-       pdev->irq_managed = 0;
-}
-
-static inline bool pci_has_managed_irq(struct pci_dev *pdev)
-{
-       return pdev->irq_managed && pdev->irq > 0;
-}
-
 void pci_disable_device(struct pci_dev *dev);
 
 extern unsigned int pcibios_max_latency;
index b35a61a481fa0460b3b32591e6dd52f2fa9077e7..0967a246745743b6ee9cd0ed69b947a421ec7bc5 100644 (file)
@@ -397,6 +397,7 @@ struct pmu {
  * enum perf_event_active_state - the states of a event
  */
 enum perf_event_active_state {
+       PERF_EVENT_STATE_DEAD           = -4,
        PERF_EVENT_STATE_EXIT           = -3,
        PERF_EVENT_STATE_ERROR          = -2,
        PERF_EVENT_STATE_OFF            = -1,
@@ -905,7 +906,7 @@ perf_sw_event_sched(u32 event_id, u64 nr, u64 addr)
        }
 }
 
-extern struct static_key_deferred perf_sched_events;
+extern struct static_key_false perf_sched_events;
 
 static __always_inline bool
 perf_sw_migrate_enabled(void)
@@ -924,7 +925,7 @@ static inline void perf_event_task_migrate(struct task_struct *task)
 static inline void perf_event_task_sched_in(struct task_struct *prev,
                                            struct task_struct *task)
 {
-       if (static_key_false(&perf_sched_events.key))
+       if (static_branch_unlikely(&perf_sched_events))
                __perf_event_task_sched_in(prev, task);
 
        if (perf_sw_migrate_enabled() && task->sched_migrated) {
@@ -941,7 +942,7 @@ static inline void perf_event_task_sched_out(struct task_struct *prev,
 {
        perf_sw_event_sched(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 0);
 
-       if (static_key_false(&perf_sched_events.key))
+       if (static_branch_unlikely(&perf_sched_events))
                __perf_event_task_sched_out(prev, next);
 }
 
@@ -964,11 +965,20 @@ DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry);
 
 extern void perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs);
 extern void perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs);
+extern struct perf_callchain_entry *
+get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
+                  bool crosstask, bool add_mark);
+extern int get_callchain_buffers(void);
+extern void put_callchain_buffers(void);
 
-static inline void perf_callchain_store(struct perf_callchain_entry *entry, u64 ip)
+static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip)
 {
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
+       if (entry->nr < PERF_MAX_STACK_DEPTH) {
                entry->ip[entry->nr++] = ip;
+               return 0;
+       } else {
+               return -1; /* no more room, stop walking the stack */
+       }
 }
 
 extern int sysctl_perf_event_paranoid;
index 2d8e49711b6392a591ee352b12c162096d4c89f6..1132953235c0708bd87e1b9eea777bb705f54cb3 100644 (file)
@@ -10,7 +10,7 @@
  * backing is indicated by flags in the high bits of the value.
  */
 typedef struct {
-       unsigned long val;
+       u64 val;
 } pfn_t;
 #endif
 
index 37448ab5fb5c2eddc80b97125ee80ecff4bc1b58..94994810c7c086e8410f3333d919ef5256595ad5 100644 (file)
@@ -9,14 +9,13 @@
  * PFN_DEV - pfn is not covered by system memmap by default
  * PFN_MAP - pfn has a dynamic page mapping established by a device driver
  */
-#define PFN_FLAGS_MASK (((unsigned long) ~PAGE_MASK) \
-               << (BITS_PER_LONG - PAGE_SHIFT))
-#define PFN_SG_CHAIN (1UL << (BITS_PER_LONG - 1))
-#define PFN_SG_LAST (1UL << (BITS_PER_LONG - 2))
-#define PFN_DEV (1UL << (BITS_PER_LONG - 3))
-#define PFN_MAP (1UL << (BITS_PER_LONG - 4))
-
-static inline pfn_t __pfn_to_pfn_t(unsigned long pfn, unsigned long flags)
+#define PFN_FLAGS_MASK (((u64) ~PAGE_MASK) << (BITS_PER_LONG_LONG - PAGE_SHIFT))
+#define PFN_SG_CHAIN (1ULL << (BITS_PER_LONG_LONG - 1))
+#define PFN_SG_LAST (1ULL << (BITS_PER_LONG_LONG - 2))
+#define PFN_DEV (1ULL << (BITS_PER_LONG_LONG - 3))
+#define PFN_MAP (1ULL << (BITS_PER_LONG_LONG - 4))
+
+static inline pfn_t __pfn_to_pfn_t(unsigned long pfn, u64 flags)
 {
        pfn_t pfn_t = { .val = pfn | (flags & PFN_FLAGS_MASK), };
 
@@ -29,7 +28,7 @@ static inline pfn_t pfn_to_pfn_t(unsigned long pfn)
        return __pfn_to_pfn_t(pfn, 0);
 }
 
-extern pfn_t phys_to_pfn_t(phys_addr_t addr, unsigned long flags);
+extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags);
 
 static inline bool pfn_t_has_page(pfn_t pfn)
 {
@@ -87,7 +86,7 @@ static inline pmd_t pfn_t_pmd(pfn_t pfn, pgprot_t pgprot)
 #ifdef __HAVE_ARCH_PTE_DEVMAP
 static inline bool pfn_t_devmap(pfn_t pfn)
 {
-       const unsigned long flags = PFN_DEV|PFN_MAP;
+       const u64 flags = PFN_DEV|PFN_MAP;
 
        return (pfn.val & flags) == flags;
 }
index d6f3641e79332889ba121c1c684e7da1b40a27f8..2abd7918f64ff198ac6d14f85457f7ffccd6f0b7 100644 (file)
@@ -327,8 +327,6 @@ struct phy_c45_device_ids {
 /* phy_device: An instance of a PHY
  *
  * drv: Pointer to the driver for this PHY instance
- * bus: Pointer to the bus this PHY is on
- * dev: driver model device structure for this PHY
  * phy_id: UID for this device found during discovery
  * c45_ids: 802.3-c45 Device Identifers if is_c45.
  * is_c45:  Set to true if this phy uses clause 45 addressing.
@@ -338,7 +336,6 @@ struct phy_c45_device_ids {
  * suspended: Set to true if this phy has been suspended successfully.
  * state: state of the PHY for management purposes
  * dev_flags: Device-specific flags used by the PHY driver.
- * addr: Bus address of PHY
  * link_timeout: The number of timer firings to wait before the
  * giving up on the current attempt at acquiring a link
  * irq: IRQ number of the PHY's interrupt (-1 if none)
diff --git a/include/linux/platform_data/brcmfmac-sdio.h b/include/linux/platform_data/brcmfmac-sdio.h
deleted file mode 100644 (file)
index e75dcbf..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2013 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _LINUX_BRCMFMAC_PLATFORM_H
-#define _LINUX_BRCMFMAC_PLATFORM_H
-
-/*
- * Platform specific driver functions and data. Through the platform specific
- * device data functions can be provided to help the brcmfmac driver to
- * operate with the device in combination with the used platform.
- *
- * Use the platform data in the following (similar) way:
- *
- *
-#include <brcmfmac_platform.h>
-
-
-static void brcmfmac_power_on(void)
-{
-}
-
-static void brcmfmac_power_off(void)
-{
-}
-
-static void brcmfmac_reset(void)
-{
-}
-
-static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = {
-       .power_on               = brcmfmac_power_on,
-       .power_off              = brcmfmac_power_off,
-       .reset                  = brcmfmac_reset
-};
-
-static struct platform_device brcmfmac_device = {
-       .name                   = BRCMFMAC_SDIO_PDATA_NAME,
-       .id                     = PLATFORM_DEVID_NONE,
-       .dev.platform_data      = &brcmfmac_sdio_pdata
-};
-
-void __init brcmfmac_init_pdata(void)
-{
-       brcmfmac_sdio_pdata.oob_irq_supported = true;
-       brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB);
-       brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ |
-                                           IORESOURCE_IRQ_HIGHLEVEL;
-       platform_device_register(&brcmfmac_device);
-}
- *
- *
- * Note: the brcmfmac can be loaded as module or be statically built-in into
- * the kernel. If built-in then do note that it uses module_init (and
- * module_exit) routines which equal device_initcall. So if you intend to
- * create a module with the platform specific data for the brcmfmac and have
- * it built-in to the kernel then use a higher initcall then device_initcall
- * (see init.h). If this is not done then brcmfmac will load without problems
- * but will not pickup the platform data.
- *
- * When the driver does not "detect" platform driver data then it will continue
- * without reporting anything and just assume there is no data needed. Which is
- * probably true for most platforms.
- *
- * Explanation of the platform_data fields:
- *
- * drive_strength: is the preferred drive_strength to be used for the SDIO
- * pins. If 0 then a default value will be used. This is the target drive
- * strength, the exact drive strength which will be used depends on the
- * capabilities of the device.
- *
- * oob_irq_supported: does the board have support for OOB interrupts. SDIO
- * in-band interrupts are relatively slow and for having less overhead on
- * interrupt processing an out of band interrupt can be used. If the HW
- * supports this then enable this by setting this field to true and configure
- * the oob related fields.
- *
- * oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are
- * used for registering the irq using request_irq function.
- *
- * broken_sg_support: flag for broken sg list support of SDIO host controller.
- * Set this to true if the SDIO host controller has higher align requirement
- * than 32 bytes for each scatterlist item.
- *
- * sd_head_align: alignment requirement for start of data buffer
- *
- * sd_sgentry_align: length alignment requirement for each sg entry
- *
- * power_on: This function is called by the brcmfmac when the module gets
- * loaded. This can be particularly useful for low power devices. The platform
- * spcific routine may for example decide to power up the complete device.
- * If there is no use-case for this function then provide NULL.
- *
- * power_off: This function is called by the brcmfmac when the module gets
- * unloaded. At this point the device can be powered down or otherwise be reset.
- * So if an actual power_off is not supported but reset is then reset the device
- * when this function gets called. This can be particularly useful for low power
- * devices. If there is no use-case for this function (either power-down or
- * reset) then provide NULL.
- *
- * reset: This function can get called if the device communication broke down.
- * This functionality is particularly useful in case of SDIO type devices. It is
- * possible to reset a dongle via sdio data interface, but it requires that
- * this is fully functional. This function is chip/module specific and this
- * function should return only after the complete reset has completed.
- */
-
-#define BRCMFMAC_SDIO_PDATA_NAME       "brcmfmac_sdio"
-
-struct brcmfmac_sdio_platform_data {
-       unsigned int drive_strength;
-       bool oob_irq_supported;
-       unsigned int oob_irq_nr;
-       unsigned long oob_irq_flags;
-       bool broken_sg_support;
-       unsigned short sd_head_align;
-       unsigned short sd_sgentry_align;
-       void (*power_on)(void);
-       void (*power_off)(void);
-       void (*reset)(void);
-};
-
-#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
diff --git a/include/linux/platform_data/brcmfmac.h b/include/linux/platform_data/brcmfmac.h
new file mode 100644 (file)
index 0000000..1d30bf2
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 201 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_BRCMFMAC_PLATFORM_H
+#define _LINUX_BRCMFMAC_PLATFORM_H
+
+
+#define BRCMFMAC_PDATA_NAME            "brcmfmac"
+
+#define BRCMFMAC_COUNTRY_BUF_SZ                4
+
+
+/*
+ * Platform specific driver functions and data. Through the platform specific
+ * device data functions and data can be provided to help the brcmfmac driver to
+ * operate with the device in combination with the used platform.
+ */
+
+
+/**
+ * Note: the brcmfmac can be loaded as module or be statically built-in into
+ * the kernel. If built-in then do note that it uses module_init (and
+ * module_exit) routines which equal device_initcall. So if you intend to
+ * create a module with the platform specific data for the brcmfmac and have
+ * it built-in to the kernel then use a higher initcall then device_initcall
+ * (see init.h). If this is not done then brcmfmac will load without problems
+ * but will not pickup the platform data.
+ *
+ * When the driver does not "detect" platform driver data then it will continue
+ * without reporting anything and just assume there is no data needed. Which is
+ * probably true for most platforms.
+ */
+
+/**
+ * enum brcmf_bus_type - Bus type identifier. Currently SDIO, USB and PCIE are
+ *                      supported.
+ */
+enum brcmf_bus_type {
+       BRCMF_BUSTYPE_SDIO,
+       BRCMF_BUSTYPE_USB,
+       BRCMF_BUSTYPE_PCIE
+};
+
+
+/**
+ * struct brcmfmac_sdio_pd - SDIO Device specific platform data.
+ *
+ * @txglomsz:          SDIO txglom size. Use 0 if default of driver is to be
+ *                     used.
+ * @drive_strength:    is the preferred drive_strength to be used for the SDIO
+ *                     pins. If 0 then a default value will be used. This is
+ *                     the target drive strength, the exact drive strength
+ *                     which will be used depends on the capabilities of the
+ *                     device.
+ * @oob_irq_supported: does the board have support for OOB interrupts. SDIO
+ *                     in-band interrupts are relatively slow and for having
+ *                     less overhead on interrupt processing an out of band
+ *                     interrupt can be used. If the HW supports this then
+ *                     enable this by setting this field to true and configure
+ *                     the oob related fields.
+ * @oob_irq_nr,
+ * @oob_irq_flags:     the OOB interrupt information. The values are used for
+ *                     registering the irq using request_irq function.
+ * @broken_sg_support: flag for broken sg list support of SDIO host controller.
+ *                     Set this to true if the SDIO host controller has higher
+ *                     align requirement than 32 bytes for each scatterlist
+ *                     item.
+ * @sd_head_align:     alignment requirement for start of data buffer.
+ * @sd_sgentry_align:  length alignment requirement for each sg entry.
+ * @reset:             This function can get called if the device communication
+ *                     broke down. This functionality is particularly useful in
+ *                     case of SDIO type devices. It is possible to reset a
+ *                     dongle via sdio data interface, but it requires that
+ *                     this is fully functional. This function is chip/module
+ *                     specific and this function should return only after the
+ *                     complete reset has completed.
+ */
+struct brcmfmac_sdio_pd {
+       int             txglomsz;
+       unsigned int    drive_strength;
+       bool            oob_irq_supported;
+       unsigned int    oob_irq_nr;
+       unsigned long   oob_irq_flags;
+       bool            broken_sg_support;
+       unsigned short  sd_head_align;
+       unsigned short  sd_sgentry_align;
+       void            (*reset)(void);
+};
+
+/**
+ * struct brcmfmac_pd_cc_entry - Struct for translating user space country code
+ *                              (iso3166) to firmware country code and
+ *                              revision.
+ *
+ * @iso3166:   iso3166 alpha 2 country code string.
+ * @cc:                firmware country code string.
+ * @rev:       firmware country code revision.
+ */
+struct brcmfmac_pd_cc_entry {
+       char    iso3166[BRCMFMAC_COUNTRY_BUF_SZ];
+       char    cc[BRCMFMAC_COUNTRY_BUF_SZ];
+       s32     rev;
+};
+
+/**
+ * struct brcmfmac_pd_cc - Struct for translating country codes as set by user
+ *                        space to a country code and rev which can be used by
+ *                        firmware.
+ *
+ * @table_size:        number of entries in table (> 0)
+ * @table:     array of 1 or more elements with translation information.
+ */
+struct brcmfmac_pd_cc {
+       int                             table_size;
+       struct brcmfmac_pd_cc_entry     table[0];
+};
+
+/**
+ * struct brcmfmac_pd_device - Device specific platform data. (id/rev/bus_type)
+ *                            is the unique identifier of the device.
+ *
+ * @id:                        ID of the device for which this data is. In case of SDIO
+ *                     or PCIE this is the chipid as identified by chip.c In
+ *                     case of USB this is the chipid as identified by the
+ *                     device query.
+ * @rev:               chip revision, see id.
+ * @bus_type:          The type of bus. Some chipid/rev exist for different bus
+ *                     types. Each bus type has its own set of settings.
+ * @feature_disable:   Bitmask of features to disable (override), See feature.c
+ *                     in brcmfmac for details.
+ * @country_codes:     If available, pointer to struct for translating country
+ *                     codes.
+ * @bus:               Bus specific (union) device settings. Currently only
+ *                     SDIO.
+ */
+struct brcmfmac_pd_device {
+       unsigned int            id;
+       unsigned int            rev;
+       enum brcmf_bus_type     bus_type;
+       unsigned int            feature_disable;
+       struct brcmfmac_pd_cc   *country_codes;
+       union {
+               struct brcmfmac_sdio_pd sdio;
+       } bus;
+};
+
+/**
+ * struct brcmfmac_platform_data - BRCMFMAC specific platform data.
+ *
+ * @power_on:  This function is called by the brcmfmac driver when the module
+ *             gets loaded. This can be particularly useful for low power
+ *             devices. The platform spcific routine may for example decide to
+ *             power up the complete device. If there is no use-case for this
+ *             function then provide NULL.
+ * @power_off: This function is called by the brcmfmac when the module gets
+ *             unloaded. At this point the devices can be powered down or
+ *             otherwise be reset. So if an actual power_off is not supported
+ *             but reset is supported by the devices then reset the devices
+ *             when this function gets called. This can be particularly useful
+ *             for low power devices. If there is no use-case for this
+ *             function then provide NULL.
+ */
+struct brcmfmac_platform_data {
+       void    (*power_on)(void);
+       void    (*power_off)(void);
+       char    *fw_alternative_path;
+       int     device_count;
+       struct brcmfmac_pd_device devices[0];
+};
+
+
+#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
index 998d8f1c3c9172037ef185963f415dbb0fad999f..b50c0492629dbfa9f902f214ad714f1c2df372bc 100644 (file)
@@ -49,6 +49,7 @@ struct bq27xxx_reg_cache {
 
 struct bq27xxx_device_info {
        struct device *dev;
+       int id;
        enum bq27xxx_chip chip;
        const char *name;
        struct bq27xxx_access_methods bus;
index 1d1ba2c5ee7a26f6a35b1835c016a6bd7755fcd8..53ecb37ae56348f13b5ea4597e291503f1d6ec13 100644 (file)
 
 #define CORE_SPQE_PAGE_SIZE_BYTES                       4096
 
+#define X_FINAL_CLEANUP_AGG_INT 1
+
 #define FW_MAJOR_VERSION       8
-#define FW_MINOR_VERSION       4
-#define FW_REVISION_VERSION    2
+#define FW_MINOR_VERSION       7
+#define FW_REVISION_VERSION    3
 #define FW_ENGINEERING_VERSION 0
 
 /***********************/
 /* number of queues in a PF queue group */
 #define QM_PF_QUEUE_GROUP_SIZE 8
 
+/* the size of a single queue element in bytes */
+#define QM_PQ_ELEMENT_SIZE                      4
+
 /* base number of Tx PQs in the CM PQ representation.
  * should be used when storing PQ IDs in CM PQ registers and context
  */
 #define PXP_NUM_ILT_RECORDS_K2 11000
 #define MAX_NUM_ILT_RECORDS MAX(PXP_NUM_ILT_RECORDS_BB, PXP_NUM_ILT_RECORDS_K2)
 
+#define SDM_COMP_TYPE_NONE              0
+#define SDM_COMP_TYPE_WAKE_THREAD       1
+#define SDM_COMP_TYPE_AGG_INT           2
+#define SDM_COMP_TYPE_CM                3
+#define SDM_COMP_TYPE_LOADER            4
+#define SDM_COMP_TYPE_PXP               5
+#define SDM_COMP_TYPE_INDICATE_ERROR    6
+#define SDM_COMP_TYPE_RELEASE_THREAD    7
+#define SDM_COMP_TYPE_RAM               8
+
 /******************/
 /* PBF CONSTANTS  */
 /******************/
@@ -335,7 +350,7 @@ struct event_ring_entry {
 
 /* Multi function mode */
 enum mf_mode {
-       SF,
+       ERROR_MODE /* Unsupported mode */,
        MF_OVLAN,
        MF_NPAR,
        MAX_MF_MODE
@@ -606,4 +621,19 @@ struct status_block {
 #define STATUS_BLOCK_ZERO_PAD3_SHIFT  24
 };
 
+struct tunnel_parsing_flags {
+       u8 flags;
+#define TUNNEL_PARSING_FLAGS_TYPE_MASK              0x3
+#define TUNNEL_PARSING_FLAGS_TYPE_SHIFT             0
+#define TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_MASK  0x1
+#define TUNNEL_PARSING_FLAGS_TENNANT_ID_EXIST_SHIFT 2
+#define TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_MASK     0x3
+#define TUNNEL_PARSING_FLAGS_NEXT_PROTOCOL_SHIFT    3
+#define TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_MASK   0x1
+#define TUNNEL_PARSING_FLAGS_FIRSTHDRIPMATCH_SHIFT  5
+#define TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_MASK     0x1
+#define TUNNEL_PARSING_FLAGS_IPV4_FRAGMENT_SHIFT    6
+#define TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_MASK      0x1
+#define TUNNEL_PARSING_FLAGS_IPV4_OPTIONS_SHIFT     7
+};
 #endif /* __COMMON_HSI__ */
index 320b3373ac1dd834d03102ba79405ede2bce8197..092cb0c1afcb1d1b5267e26f2cc72452dc5f3111 100644 (file)
 #define ETH_MAX_RAMROD_PER_CON                          8
 #define ETH_TX_BD_PAGE_SIZE_BYTES                       4096
 #define ETH_RX_BD_PAGE_SIZE_BYTES                       4096
-#define ETH_RX_SGE_PAGE_SIZE_BYTES                      4096
 #define ETH_RX_CQE_PAGE_SIZE_BYTES                      4096
 #define ETH_RX_NUM_NEXT_PAGE_BDS                        2
-#define ETH_RX_NUM_NEXT_PAGE_SGES                       2
 
 #define ETH_TX_MIN_BDS_PER_NON_LSO_PKT                          1
 #define ETH_TX_MAX_BDS_PER_NON_LSO_PACKET                       18
@@ -34,7 +32,8 @@
 
 #define ETH_NUM_STATISTIC_COUNTERS                      MAX_NUM_VPORTS
 
-#define ETH_REG_CQE_PBL_SIZE                3
+/* Maximum number of buffers, used for RX packet placement */
+#define ETH_RX_MAX_BUFF_PER_PKT             5
 
 /* num of MAC/VLAN filters */
 #define ETH_NUM_MAC_FILTERS                                     512
@@ -54,9 +53,9 @@
 
 /* TPA constants */
 #define ETH_TPA_MAX_AGGS_NUM              64
-#define ETH_TPA_CQE_START_SGL_SIZE        3
-#define ETH_TPA_CQE_CONT_SGL_SIZE         6
-#define ETH_TPA_CQE_END_SGL_SIZE          4
+#define ETH_TPA_CQE_START_LEN_LIST_SIZE   ETH_RX_MAX_BUFF_PER_PKT
+#define ETH_TPA_CQE_CONT_LEN_LIST_SIZE    6
+#define ETH_TPA_CQE_END_LEN_LIST_SIZE     4
 
 /* Queue Zone sizes */
 #define TSTORM_QZONE_SIZE    0
@@ -74,18 +73,18 @@ struct coalescing_timeset {
 
 struct eth_tx_1st_bd_flags {
        u8 bitfields;
+#define ETH_TX_1ST_BD_FLAGS_START_BD_MASK         0x1
+#define ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT        0
 #define ETH_TX_1ST_BD_FLAGS_FORCE_VLAN_MODE_MASK  0x1
-#define ETH_TX_1ST_BD_FLAGS_FORCE_VLAN_MODE_SHIFT 0
+#define ETH_TX_1ST_BD_FLAGS_FORCE_VLAN_MODE_SHIFT 1
 #define ETH_TX_1ST_BD_FLAGS_IP_CSUM_MASK          0x1
-#define ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT         1
+#define ETH_TX_1ST_BD_FLAGS_IP_CSUM_SHIFT         2
 #define ETH_TX_1ST_BD_FLAGS_L4_CSUM_MASK          0x1
-#define ETH_TX_1ST_BD_FLAGS_L4_CSUM_SHIFT         2
+#define ETH_TX_1ST_BD_FLAGS_L4_CSUM_SHIFT         3
 #define ETH_TX_1ST_BD_FLAGS_VLAN_INSERTION_MASK   0x1
-#define ETH_TX_1ST_BD_FLAGS_VLAN_INSERTION_SHIFT  3
+#define ETH_TX_1ST_BD_FLAGS_VLAN_INSERTION_SHIFT  4
 #define ETH_TX_1ST_BD_FLAGS_LSO_MASK              0x1
-#define ETH_TX_1ST_BD_FLAGS_LSO_SHIFT             4
-#define ETH_TX_1ST_BD_FLAGS_START_BD_MASK         0x1
-#define ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT        5
+#define ETH_TX_1ST_BD_FLAGS_LSO_SHIFT             5
 #define ETH_TX_1ST_BD_FLAGS_TUNN_IP_CSUM_MASK     0x1
 #define ETH_TX_1ST_BD_FLAGS_TUNN_IP_CSUM_SHIFT    6
 #define ETH_TX_1ST_BD_FLAGS_TUNN_L4_CSUM_MASK     0x1
@@ -97,38 +96,44 @@ struct eth_tx_data_1st_bd {
        __le16                          vlan;
        u8                              nbds;
        struct eth_tx_1st_bd_flags      bd_flags;
-       __le16                          fw_use_only;
+       __le16                          bitfields;
+#define ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_MASK  0x1
+#define ETH_TX_DATA_1ST_BD_TUNN_CFG_OVERRIDE_SHIFT 0
+#define ETH_TX_DATA_1ST_BD_RESERVED0_MASK          0x1
+#define ETH_TX_DATA_1ST_BD_RESERVED0_SHIFT         1
+#define ETH_TX_DATA_1ST_BD_FW_USE_ONLY_MASK        0x3FFF
+#define ETH_TX_DATA_1ST_BD_FW_USE_ONLY_SHIFT       2
 };
 
 /* The parsing information data for the second tx bd of a given packet. */
 struct eth_tx_data_2nd_bd {
        __le16  tunn_ip_size;
-       __le16  bitfields;
-#define ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_MASK     0x1FFF
-#define ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_SHIFT    0
-#define ETH_TX_DATA_2ND_BD_RESERVED0_MASK                 0x7
-#define ETH_TX_DATA_2ND_BD_RESERVED0_SHIFT                13
-       __le16  bitfields2;
+       __le16  bitfields1;
 #define ETH_TX_DATA_2ND_BD_TUNN_INNER_L2_HDR_SIZE_W_MASK  0xF
 #define ETH_TX_DATA_2ND_BD_TUNN_INNER_L2_HDR_SIZE_W_SHIFT 0
 #define ETH_TX_DATA_2ND_BD_TUNN_INNER_ETH_TYPE_MASK       0x3
 #define ETH_TX_DATA_2ND_BD_TUNN_INNER_ETH_TYPE_SHIFT      4
 #define ETH_TX_DATA_2ND_BD_DEST_PORT_MODE_MASK            0x3
 #define ETH_TX_DATA_2ND_BD_DEST_PORT_MODE_SHIFT           6
+#define ETH_TX_DATA_2ND_BD_START_BD_MASK                  0x1
+#define ETH_TX_DATA_2ND_BD_START_BD_SHIFT                 8
 #define ETH_TX_DATA_2ND_BD_TUNN_TYPE_MASK                 0x3
-#define ETH_TX_DATA_2ND_BD_TUNN_TYPE_SHIFT                8
+#define ETH_TX_DATA_2ND_BD_TUNN_TYPE_SHIFT                9
 #define ETH_TX_DATA_2ND_BD_TUNN_INNER_IPV6_MASK           0x1
-#define ETH_TX_DATA_2ND_BD_TUNN_INNER_IPV6_SHIFT          10
+#define ETH_TX_DATA_2ND_BD_TUNN_INNER_IPV6_SHIFT          11
 #define ETH_TX_DATA_2ND_BD_IPV6_EXT_MASK                  0x1
-#define ETH_TX_DATA_2ND_BD_IPV6_EXT_SHIFT                 11
+#define ETH_TX_DATA_2ND_BD_IPV6_EXT_SHIFT                 12
 #define ETH_TX_DATA_2ND_BD_TUNN_IPV6_EXT_MASK             0x1
-#define ETH_TX_DATA_2ND_BD_TUNN_IPV6_EXT_SHIFT            12
+#define ETH_TX_DATA_2ND_BD_TUNN_IPV6_EXT_SHIFT            13
 #define ETH_TX_DATA_2ND_BD_L4_UDP_MASK                    0x1
-#define ETH_TX_DATA_2ND_BD_L4_UDP_SHIFT                   13
+#define ETH_TX_DATA_2ND_BD_L4_UDP_SHIFT                   14
 #define ETH_TX_DATA_2ND_BD_L4_PSEUDO_CSUM_MODE_MASK       0x1
-#define ETH_TX_DATA_2ND_BD_L4_PSEUDO_CSUM_MODE_SHIFT      14
-#define ETH_TX_DATA_2ND_BD_RESERVED1_MASK                 0x1
-#define ETH_TX_DATA_2ND_BD_RESERVED1_SHIFT                15
+#define ETH_TX_DATA_2ND_BD_L4_PSEUDO_CSUM_MODE_SHIFT      15
+       __le16 bitfields2;
+#define ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_MASK     0x1FFF
+#define ETH_TX_DATA_2ND_BD_L4_HDR_START_OFFSET_W_SHIFT    0
+#define ETH_TX_DATA_2ND_BD_RESERVED0_MASK                 0x7
+#define ETH_TX_DATA_2ND_BD_RESERVED0_SHIFT                13
 };
 
 /* Regular ETH Rx FP CQE. */
@@ -145,11 +150,68 @@ struct eth_fast_path_rx_reg_cqe {
        struct parsing_and_err_flags    pars_flags;
        __le16                          vlan_tag;
        __le32                          rss_hash;
-       __le16                          len_on_bd;
+       __le16                          len_on_first_bd;
        u8                              placement_offset;
-       u8                              reserved;
-       __le16                          pbl[ETH_REG_CQE_PBL_SIZE];
-       u8                              reserved1[10];
+       struct tunnel_parsing_flags     tunnel_pars_flags;
+       u8                              bd_num;
+       u8                              reserved[7];
+       u32                             fw_debug;
+       u8                              reserved1[3];
+       u8                              flags;
+#define ETH_FAST_PATH_RX_REG_CQE_VALID_MASK          0x1
+#define ETH_FAST_PATH_RX_REG_CQE_VALID_SHIFT         0
+#define ETH_FAST_PATH_RX_REG_CQE_VALID_TOGGLE_MASK   0x1
+#define ETH_FAST_PATH_RX_REG_CQE_VALID_TOGGLE_SHIFT  1
+#define ETH_FAST_PATH_RX_REG_CQE_RESERVED2_MASK      0x3F
+#define ETH_FAST_PATH_RX_REG_CQE_RESERVED2_SHIFT     2
+};
+
+/* TPA-continue ETH Rx FP CQE. */
+struct eth_fast_path_rx_tpa_cont_cqe {
+       u8      type;
+       u8      tpa_agg_index;
+       __le16  len_list[ETH_TPA_CQE_CONT_LEN_LIST_SIZE];
+       u8      reserved[5];
+       u8      reserved1;
+       __le16  reserved2[ETH_TPA_CQE_CONT_LEN_LIST_SIZE];
+};
+
+/* TPA-end ETH Rx FP CQE. */
+struct eth_fast_path_rx_tpa_end_cqe {
+       u8      type;
+       u8      tpa_agg_index;
+       __le16  total_packet_len;
+       u8      num_of_bds;
+       u8      end_reason;
+       __le16  num_of_coalesced_segs;
+       __le32  ts_delta;
+       __le16  len_list[ETH_TPA_CQE_END_LEN_LIST_SIZE];
+       u8      reserved1[3];
+       u8      reserved2;
+       __le16  reserved3[ETH_TPA_CQE_END_LEN_LIST_SIZE];
+};
+
+/* TPA-start ETH Rx FP CQE. */
+struct eth_fast_path_rx_tpa_start_cqe {
+       u8      type;
+       u8      bitfields;
+#define ETH_FAST_PATH_RX_TPA_START_CQE_RSS_HASH_TYPE_MASK  0x7
+#define ETH_FAST_PATH_RX_TPA_START_CQE_RSS_HASH_TYPE_SHIFT 0
+#define ETH_FAST_PATH_RX_TPA_START_CQE_TC_MASK             0xF
+#define ETH_FAST_PATH_RX_TPA_START_CQE_TC_SHIFT            3
+#define ETH_FAST_PATH_RX_TPA_START_CQE_RESERVED0_MASK      0x1
+#define ETH_FAST_PATH_RX_TPA_START_CQE_RESERVED0_SHIFT     7
+       __le16  seg_len;
+       struct parsing_and_err_flags pars_flags;
+       __le16  vlan_tag;
+       __le32  rss_hash;
+       __le16  len_on_first_bd;
+       u8      placement_offset;
+       struct tunnel_parsing_flags tunnel_pars_flags;
+       u8      tpa_agg_index;
+       u8      header_len;
+       __le16  ext_bd_len_list[ETH_TPA_CQE_START_LEN_LIST_SIZE];
+       u32     fw_debug;
 };
 
 /* The L4 pseudo checksum mode for Ethernet */
@@ -168,13 +230,26 @@ struct eth_slow_path_rx_cqe {
        u8      type;
        u8      ramrod_cmd_id;
        u8      error_flag;
-       u8      reserved[27];
+       u8      reserved[25];
        __le16  echo;
+       u8      reserved1;
+       u8      flags;
+/* for PMD mode - valid indication */
+#define ETH_SLOW_PATH_RX_CQE_VALID_MASK         0x1
+#define ETH_SLOW_PATH_RX_CQE_VALID_SHIFT        0
+/* for PMD mode - valid toggle indication */
+#define ETH_SLOW_PATH_RX_CQE_VALID_TOGGLE_MASK  0x1
+#define ETH_SLOW_PATH_RX_CQE_VALID_TOGGLE_SHIFT 1
+#define ETH_SLOW_PATH_RX_CQE_RESERVED2_MASK     0x3F
+#define ETH_SLOW_PATH_RX_CQE_RESERVED2_SHIFT    2
 };
 
 /* union for all ETH Rx CQE types */
 union eth_rx_cqe {
        struct eth_fast_path_rx_reg_cqe         fast_path_regular;
+       struct eth_fast_path_rx_tpa_start_cqe   fast_path_tpa_start;
+       struct eth_fast_path_rx_tpa_cont_cqe    fast_path_tpa_cont;
+       struct eth_fast_path_rx_tpa_end_cqe     fast_path_tpa_end;
        struct eth_slow_path_rx_cqe             slow_path;
 };
 
@@ -183,15 +258,18 @@ enum eth_rx_cqe_type {
        ETH_RX_CQE_TYPE_UNUSED,
        ETH_RX_CQE_TYPE_REGULAR,
        ETH_RX_CQE_TYPE_SLOW_PATH,
+       ETH_RX_CQE_TYPE_TPA_START,
+       ETH_RX_CQE_TYPE_TPA_CONT,
+       ETH_RX_CQE_TYPE_TPA_END,
        MAX_ETH_RX_CQE_TYPE
 };
 
 /* ETH Rx producers data */
 struct eth_rx_prod_data {
        __le16  bd_prod;
-       __le16  sge_prod;
        __le16  cqe_prod;
        __le16  reserved;
+       __le16  reserved1;
 };
 
 /* The first tx bd of a given packet */
@@ -211,12 +289,17 @@ struct eth_tx_2nd_bd {
 /* The parsing information data for the third tx bd of a given packet. */
 struct eth_tx_data_3rd_bd {
        __le16  lso_mss;
-       u8      bitfields;
+       __le16  bitfields;
 #define ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_MASK  0xF
 #define ETH_TX_DATA_3RD_BD_TCP_HDR_LEN_DW_SHIFT 0
 #define ETH_TX_DATA_3RD_BD_HDR_NBD_MASK         0xF
 #define ETH_TX_DATA_3RD_BD_HDR_NBD_SHIFT        4
-       u8      resereved0[3];
+#define ETH_TX_DATA_3RD_BD_START_BD_MASK        0x1
+#define ETH_TX_DATA_3RD_BD_START_BD_SHIFT       8
+#define ETH_TX_DATA_3RD_BD_RESERVED0_MASK       0x7F
+#define ETH_TX_DATA_3RD_BD_RESERVED0_SHIFT      9
+       u8      tunn_l4_hdr_start_offset_w;
+       u8      tunn_hdr_size_w;
 };
 
 /* The third tx bd of a given packet */
@@ -226,12 +309,24 @@ struct eth_tx_3rd_bd {
        struct eth_tx_data_3rd_bd       data;
 };
 
+/* Complementary information for the regular tx bd of a given packet. */
+struct eth_tx_data_bd {
+       __le16  reserved0;
+       __le16  bitfields;
+#define ETH_TX_DATA_BD_RESERVED1_MASK  0xFF
+#define ETH_TX_DATA_BD_RESERVED1_SHIFT 0
+#define ETH_TX_DATA_BD_START_BD_MASK   0x1
+#define ETH_TX_DATA_BD_START_BD_SHIFT  8
+#define ETH_TX_DATA_BD_RESERVED2_MASK  0x7F
+#define ETH_TX_DATA_BD_RESERVED2_SHIFT 9
+       __le16 reserved3;
+};
+
 /* The common non-special TX BD ring element */
 struct eth_tx_bd {
        struct regpair  addr;
        __le16          nbytes;
-       __le16          reserved0;
-       __le32          reserved1;
+       struct eth_tx_data_bd   data;
 };
 
 union eth_tx_bd_types {
index 41b9049b57e2475575d076b4f0728234618ce07e..5f8fcaaa6504ef58cc7d1457801b0855d4c55320 100644 (file)
 /* dma_addr_t manip */
 #define DMA_LO_LE(x)            cpu_to_le32(lower_32_bits(x))
 #define DMA_HI_LE(x)            cpu_to_le32(upper_32_bits(x))
+#define DMA_REGPAIR_LE(x, val)  do { \
+                                       (x).hi = DMA_HI_LE((val)); \
+                                       (x).lo = DMA_LO_LE((val)); \
+                               } while (0)
 
 #define HILO_GEN(hi, lo, type)  ((((type)(hi)) << 32) + (lo))
 #define HILO_DMA(hi, lo)        HILO_GEN(hi, lo, dma_addr_t)
index 81ab178e31c15d852154e309b81ad7a24968a039..e1d69834a11fb38c45fe8e6fe0b3d0ad53af7ee4 100644 (file)
@@ -33,10 +33,20 @@ struct qed_update_vport_params {
        u8 vport_id;
        u8 update_vport_active_flg;
        u8 vport_active_flg;
+       u8 update_accept_any_vlan_flg;
+       u8 accept_any_vlan;
        u8 update_rss_flg;
        struct qed_update_vport_rss_params rss_params;
 };
 
+struct qed_start_vport_params {
+       bool remove_inner_vlan;
+       bool gro_enable;
+       bool drop_ttl0;
+       u8 vport_id;
+       u16 mtu;
+};
+
 struct qed_stop_rxq_params {
        u8 rss_id;
        u8 rx_queue_id;
@@ -116,9 +126,7 @@ struct qed_eth_ops {
                             void *cookie);
 
        int (*vport_start)(struct qed_dev *cdev,
-                          u8 vport_id, u16 mtu,
-                          u8 drop_ttl0_flg,
-                          u8 inner_vlan_removal_en_flg);
+                          struct qed_start_vport_params *params);
 
        int (*vport_stop)(struct qed_dev *cdev,
                          u8 vport_id);
index d4a32e87818049101ae21b16f4c55ed3ab8b0fce..1f7599c77cd4185de5579d6c5801655706a982f3 100644 (file)
@@ -80,7 +80,7 @@ struct qed_dev_info {
        u8              num_hwfns;
 
        u8              hw_mac[ETH_ALEN];
-       bool            is_mf;
+       bool            is_mf_default;
 
        /* FW version */
        u16             fw_major;
@@ -360,6 +360,12 @@ enum DP_MODULE {
        /* to be added...up to 0x8000000 */
 };
 
+enum qed_mf_mode {
+       QED_MF_DEFAULT,
+       QED_MF_OVLAN,
+       QED_MF_NPAR,
+};
+
 struct qed_eth_stats {
        u64     no_buff_discards;
        u64     packet_too_big_discard;
@@ -440,6 +446,12 @@ struct qed_eth_stats {
 #define RX_PI           0
 #define TX_PI(tc)       (RX_PI + 1 + tc)
 
+struct qed_sb_cnt_info {
+       int     sb_cnt;
+       int     sb_iov_cnt;
+       int     sb_free_blk;
+};
+
 static inline u16 qed_sb_update_sb_idx(struct qed_sb_info *sb_info)
 {
        u32 prod = 0;
index 7c88ad156a293c0bedcea771b58f3113909b6532..f54be708220760f9a367f4a29ca1cbe7cfb7fba2 100644 (file)
@@ -378,13 +378,29 @@ radix_tree_iter_init(struct radix_tree_iter *iter, unsigned long start)
 void **radix_tree_next_chunk(struct radix_tree_root *root,
                             struct radix_tree_iter *iter, unsigned flags);
 
+/**
+ * radix_tree_iter_retry - retry this chunk of the iteration
+ * @iter:      iterator state
+ *
+ * If we iterate over a tree protected only by the RCU lock, a race
+ * against deletion or creation may result in seeing a slot for which
+ * radix_tree_deref_retry() returns true.  If so, call this function
+ * and continue the iteration.
+ */
+static inline __must_check
+void **radix_tree_iter_retry(struct radix_tree_iter *iter)
+{
+       iter->next_index = iter->index;
+       return NULL;
+}
+
 /**
  * radix_tree_chunk_size - get current chunk size
  *
  * @iter:      pointer to radix tree iterator
  * Returns:    current chunk size
  */
-static __always_inline unsigned
+static __always_inline long
 radix_tree_chunk_size(struct radix_tree_iter *iter)
 {
        return iter->next_index - iter->index;
@@ -418,9 +434,9 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
                        return slot + offset + 1;
                }
        } else {
-               unsigned size = radix_tree_chunk_size(iter) - 1;
+               long size = radix_tree_chunk_size(iter);
 
-               while (size--) {
+               while (--size > 0) {
                        slot++;
                        iter->index++;
                        if (likely(*slot))
index a7a06d1dcf9cb17ee65d1befe1ef6ac62d882d16..a0118d5929a9c9ed17df3b75a8b599472ff1f205 100644 (file)
@@ -152,6 +152,8 @@ void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
 
 # define jiffies       raid6_jiffies()
 # define printk        printf
+# define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
+# define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__)
 # define GFP_KERNEL    0
 # define __get_free_pages(x, y)        ((unsigned long)mmap(NULL, PAGE_SIZE << (y), \
                                                     PROT_READ|PROT_WRITE,   \
index a75840c1aa71414acc43468da6cc8f83ec06c1b8..9c29122037f95283cc02b8af995975e80e059abd 100644 (file)
@@ -34,6 +34,7 @@ extern const struct file_operations random_fops, urandom_fops;
 #endif
 
 unsigned int get_random_int(void);
+unsigned long get_random_long(void);
 unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
 
 u32 prandom_u32(void);
index 14ec1652daf4863c30d471298402611a2da2137a..17d4f849c65e3dcf5dfbbd8100abf1236073ad55 100644 (file)
@@ -318,6 +318,27 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
        likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
 })
 
+/**
+ * list_next_or_null_rcu - get the first element from a list
+ * @head:      the head for the list.
+ * @ptr:        the list head to take the next element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_head within the struct.
+ *
+ * Note that if the ptr is at the end of the list, NULL is returned.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
+ */
+#define list_next_or_null_rcu(head, ptr, type, member) \
+({ \
+       struct list_head *__head = (head); \
+       struct list_head *__ptr = (ptr); \
+       struct list_head *__next = READ_ONCE(__ptr->next); \
+       likely(__next != __head) ? list_entry_rcu(__next, type, \
+                                                 member) : NULL; \
+})
+
 /**
  * list_for_each_entry_rcu     -       iterate over rcu list of given type
  * @pos:       the type * to use as a loop cursor.
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
deleted file mode 100644 (file)
index 20bcb55..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2011, NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- */
-
-
-#ifndef __RFKILL_GPIO_H
-#define __RFKILL_GPIO_H
-
-#include <linux/types.h>
-#include <linux/rfkill.h>
-
-/**
- * struct rfkill_gpio_platform_data - platform data for rfkill gpio device.
- * for unused gpio's, the expected value is -1.
- * @name:              name for the gpio rf kill instance
- */
-
-struct rfkill_gpio_platform_data {
-       char                    *name;
-       enum rfkill_type        type;
-};
-
-#endif /* __RFKILL_GPIO_H */
index d9010789b4e8215cc74a2ffc12e83f3cfd9b73cd..e6a0031d1b1fdc1793200d1fc93f48bf1973ecfc 100644 (file)
@@ -104,7 +104,8 @@ int __must_check rfkill_register(struct rfkill *rfkill);
  *
  * Pause polling -- say transmitter is off for other reasons.
  * NOTE: not necessary for suspend/resume -- in that case the
- * core stops polling anyway
+ * core stops polling anyway (but will also correctly handle
+ * the case of polling having been paused before suspend.)
  */
 void rfkill_pause_polling(struct rfkill *rfkill);
 
@@ -212,6 +213,15 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
  * @rfkill: rfkill struct to query
  */
 bool rfkill_blocked(struct rfkill *rfkill);
+
+/**
+ * rfkill_find_type - Helpper for finding rfkill type by name
+ * @name: the name of the type
+ *
+ * Returns enum rfkill_type that conrresponds the name.
+ */
+enum rfkill_type rfkill_find_type(const char *name);
+
 #else /* !RFKILL */
 static inline struct rfkill * __must_check
 rfkill_alloc(const char *name,
@@ -268,6 +278,12 @@ static inline bool rfkill_blocked(struct rfkill *rfkill)
 {
        return false;
 }
+
+static inline enum rfkill_type rfkill_find_type(const char *name)
+{
+       return RFKILL_TYPE_ALL;
+}
+
 #endif /* RFKILL || RFKILL_MODULE */
 
 
index bdf597c4f0be82965911266ed1668d06510492cb..a07f42bedda32687c94ed574f5a606b19912b042 100644 (file)
@@ -109,20 +109,6 @@ static inline void put_anon_vma(struct anon_vma *anon_vma)
                __put_anon_vma(anon_vma);
 }
 
-static inline void vma_lock_anon_vma(struct vm_area_struct *vma)
-{
-       struct anon_vma *anon_vma = vma->anon_vma;
-       if (anon_vma)
-               down_write(&anon_vma->root->rwsem);
-}
-
-static inline void vma_unlock_anon_vma(struct vm_area_struct *vma)
-{
-       struct anon_vma *anon_vma = vma->anon_vma;
-       if (anon_vma)
-               up_write(&anon_vma->root->rwsem);
-}
-
 static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
 {
        down_write(&anon_vma->root->rwsem);
index 39206751463e699802eac2a8ef4f759d9d5950c3..15d0df9434667922894936216d17bf88120d60cc 100644 (file)
@@ -299,6 +299,7 @@ struct sk_buff;
 #else
 #define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1)
 #endif
+extern int sysctl_max_skb_frags;
 
 typedef struct skb_frag_struct skb_frag_t;
 
@@ -1160,10 +1161,6 @@ static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
        to->l4_hash = from->l4_hash;
 };
 
-static inline void skb_sender_cpu_clear(struct sk_buff *skb)
-{
-}
-
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
 static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)
 {
@@ -1984,6 +1981,30 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
        skb->tail += len;
 }
 
+/**
+ *     skb_tailroom_reserve - adjust reserved_tailroom
+ *     @skb: buffer to alter
+ *     @mtu: maximum amount of headlen permitted
+ *     @needed_tailroom: minimum amount of reserved_tailroom
+ *
+ *     Set reserved_tailroom so that headlen can be as large as possible but
+ *     not larger than mtu and tailroom cannot be smaller than
+ *     needed_tailroom.
+ *     The required headroom should already have been reserved before using
+ *     this function.
+ */
+static inline void skb_tailroom_reserve(struct sk_buff *skb, unsigned int mtu,
+                                       unsigned int needed_tailroom)
+{
+       SKB_LINEAR_ASSERT(skb);
+       if (mtu < skb_tailroom(skb) - needed_tailroom)
+               /* use at most mtu */
+               skb->reserved_tailroom = skb_tailroom(skb) - mtu;
+       else
+               /* use up to all available space */
+               skb->reserved_tailroom = needed_tailroom;
+}
+
 #define ENCAP_TYPE_ETHER       0
 #define ENCAP_TYPE_IPPROTO     1
 
@@ -2630,6 +2651,13 @@ static inline int skb_clone_writable(const struct sk_buff *skb, unsigned int len
               skb_headroom(skb) + len <= skb->hdr_len;
 }
 
+static inline int skb_try_make_writable(struct sk_buff *skb,
+                                       unsigned int write_len)
+{
+       return skb_cloned(skb) && !skb_clone_writable(skb, write_len) &&
+              pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+}
+
 static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom,
                            int cloned)
 {
@@ -3713,19 +3741,18 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
  */
 static inline __wsum lco_csum(struct sk_buff *skb)
 {
-       char *inner_csum_field;
-       __wsum csum;
+       unsigned char *csum_start = skb_checksum_start(skb);
+       unsigned char *l4_hdr = skb_transport_header(skb);
+       __wsum partial;
 
        /* Start with complement of inner checksum adjustment */
-       inner_csum_field = skb->data + skb_checksum_start_offset(skb) +
-                               skb->csum_offset;
-       csum = ~csum_unfold(*(__force __sum16 *)inner_csum_field);
+       partial = ~csum_unfold(*(__force __sum16 *)(csum_start +
+                                                   skb->csum_offset));
+
        /* Add in checksum of our headers (incl. outer checksum
-        * adjustment filled in by caller)
+        * adjustment filled in by caller) and return result.
         */
-       csum = skb_checksum(skb, 0, skb_checksum_start_offset(skb), csum);
-       /* The result is the checksum from skb->data to end of packet */
-       return csum;
+       return csum_partial(l4_hdr, csum_start - l4_hdr, partial);
 }
 
 #endif /* __KERNEL__ */
index 343c13ac4f71f41f370b3bd51c8cd38c9ea75c2f..35cb9264e0d50bb8b8cce8f569d950de2d6694b2 100644 (file)
@@ -44,6 +44,7 @@
 
 #define KNAV_DMA_NUM_EPIB_WORDS                        4
 #define KNAV_DMA_NUM_PS_WORDS                  16
+#define KNAV_DMA_NUM_SW_DATA_WORDS             4
 #define KNAV_DMA_FDQ_PER_CHAN                  4
 
 /* Tx channel scheduling priority */
@@ -142,6 +143,7 @@ struct knav_dma_cfg {
  * @orig_buff:                 buff pointer since 'buff' can be overwritten
  * @epib:                      Extended packet info block
  * @psdata:                    Protocol specific
+ * @sw_data:                   Software private data not touched by h/w
  */
 struct knav_dma_desc {
        __le32  desc_info;
@@ -154,7 +156,7 @@ struct knav_dma_desc {
        __le32  orig_buff;
        __le32  epib[KNAV_DMA_NUM_EPIB_WORDS];
        __le32  psdata[KNAV_DMA_NUM_PS_WORDS];
-       __le32  pad[4];
+       u32     sw_data[KNAV_DMA_NUM_SW_DATA_WORDS];
 } ____cacheline_aligned;
 
 #if IS_ENABLED(CONFIG_KEYSTONE_NAVIGATOR_DMA)
index 5bf59c8493b763c6dc11ccce18da9c0ac6c0da46..73bf6c6a833b37b907bc6f8852356d8976b9662d 100644 (file)
@@ -200,7 +200,9 @@ struct ucred {
 #define AF_ALG         38      /* Algorithm sockets            */
 #define AF_NFC         39      /* NFC sockets                  */
 #define AF_VSOCK       40      /* vSockets                     */
-#define AF_MAX         41      /* For now.. */
+#define AF_KCM         41      /* Kernel Connection Multiplexor*/
+
+#define AF_MAX         42      /* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC      AF_UNSPEC
@@ -246,6 +248,7 @@ struct ucred {
 #define PF_ALG         AF_ALG
 #define PF_NFC         AF_NFC
 #define PF_VSOCK       AF_VSOCK
+#define PF_KCM         AF_KCM
 #define PF_MAX         AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -274,6 +277,7 @@ struct ucred {
 #define MSG_MORE       0x8000  /* Sender will send more */
 #define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */
 #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */
+#define MSG_BATCH      0x40000 /* sendmmsg(): more messages coming */
 #define MSG_EOF         MSG_FIN
 
 #define MSG_FASTOPEN   0x20000000      /* Send data in TCP SYN */
@@ -322,6 +326,7 @@ struct ucred {
 #define SOL_CAIF       278
 #define SOL_ALG                279
 #define SOL_NFC                280
+#define SOL_KCM                281
 
 /* IPX options */
 #define IPX_TYPE       1
index eead8ab93c0a36e402741ee767d3c3bc70128964..4bcf5a61aada05b02d33c33928dc4d7d7e9f0bb2 100644 (file)
@@ -90,7 +90,21 @@ struct stmmac_dma_cfg {
        int pbl;
        int fixed_burst;
        int mixed_burst;
-       int burst_len;
+       bool aal;
+};
+
+#define AXI_BLEN       7
+struct stmmac_axi {
+       bool axi_lpi_en;
+       bool axi_xit_frm;
+       u32 axi_wr_osr_lmt;
+       u32 axi_rd_osr_lmt;
+       bool axi_kbbe;
+       bool axi_axi_all;
+       u32 axi_blen[AXI_BLEN];
+       bool axi_fb;
+       bool axi_mb;
+       bool axi_rb;
 };
 
 struct plat_stmmacenet_data {
@@ -100,6 +114,7 @@ struct plat_stmmacenet_data {
        int interface;
        struct stmmac_mdio_bus_data *mdio_bus_data;
        struct device_node *phy_node;
+       struct device_node *mdio_node;
        struct stmmac_dma_cfg *dma_cfg;
        int clk_csr;
        int has_gmac;
@@ -122,5 +137,6 @@ struct plat_stmmacenet_data {
        int (*init)(struct platform_device *pdev, void *priv);
        void (*exit)(struct platform_device *pdev, void *priv);
        void *bsp_priv;
+       struct stmmac_axi *axi;
 };
 #endif
index 429fdfc3baf59e018d0e198062f894642af8a5bc..925730bc9fc1bb4914410779bdf5ea469ed41c18 100644 (file)
@@ -568,6 +568,8 @@ enum {
        FILTER_DYN_STRING,
        FILTER_PTR_STRING,
        FILTER_TRACE_FN,
+       FILTER_COMM,
+       FILTER_CPU,
 };
 
 extern int trace_event_raw_init(struct trace_event_call *call);
index acd522a91539155db94143d5da4e4848a44a437e..acfdbf353a0b5bc7cfeb6ae58fa7e6a6acfa16ba 100644 (file)
  * See the file COPYING for more details.
  */
 
+#include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/cpumask.h>
 #include <linux/rcupdate.h>
 #include <linux/tracepoint-defs.h>
 
@@ -132,6 +134,9 @@ extern void syscall_unregfunc(void);
                void *it_func;                                          \
                void *__data;                                           \
                                                                        \
+               if (!cpu_online(raw_smp_processor_id()))                \
+                       return;                                         \
+                                                                       \
                if (!(cond))                                            \
                        return;                                         \
                prercu;                                                 \
index cbb20afdbc01cc4a600574446d5b19c33a0d90c1..bb679b48f408217a422d0cd427ede3e05e2e67bd 100644 (file)
@@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s);
 unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
 int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
 
+unsigned long ucs2_utf8size(const ucs2_char_t *src);
+unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src,
+                          unsigned long maxlength);
+
 #endif /* _LINUX_UCS2_STRING_H_ */
index 0e32bc71245ef46b90aa21112e4d2bef42cc5950..ca73c503b92a758ad5ce9b6d022c53c0758951c5 100644 (file)
@@ -311,6 +311,7 @@ enum {
 
        __WQ_DRAINING           = 1 << 16, /* internal: workqueue is draining */
        __WQ_ORDERED            = 1 << 17, /* internal: workqueue is ordered */
+       __WQ_LEGACY             = 1 << 18, /* internal: create*_workqueue() */
 
        WQ_MAX_ACTIVE           = 512,    /* I like 512, better ideas? */
        WQ_MAX_UNBOUND_PER_CPU  = 4,      /* 4 * #cpus for unbound wq */
@@ -411,12 +412,12 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
        alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
 
 #define create_workqueue(name)                                         \
-       alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))
+       alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name))
 #define create_freezable_workqueue(name)                               \
-       alloc_workqueue("%s", WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, \
-                       1, (name))
+       alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND | \
+                       WQ_MEM_RECLAIM, 1, (name))
 #define create_singlethread_workqueue(name)                            \
-       alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name)
+       alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name)
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
index b333c945e57117aa3d80f6ec2df47f6513c82260..d0b5ca5d4e080346e8a657c6c6aee540e47776e7 100644 (file)
@@ -198,6 +198,7 @@ void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
 void wbc_detach_inode(struct writeback_control *wbc);
 void wbc_account_io(struct writeback_control *wbc, struct page *page,
                    size_t bytes);
+void cgroup_writeback_umount(void);
 
 /**
  * inode_attach_wb - associate an inode with its wb
@@ -301,6 +302,10 @@ static inline void wbc_account_io(struct writeback_control *wbc,
 {
 }
 
+static inline void cgroup_writeback_umount(void)
+{
+}
+
 #endif /* CONFIG_CGROUP_WRITEBACK */
 
 /*
index ef03ae56b1c1cc18d9541697b353a01842b50210..8a0f55b6c2ba80e25c67caf89e2050fa58ae322f 100644 (file)
@@ -533,7 +533,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
                const unsigned int requested_sizes[]);
 int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
 int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb);
-int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking);
+int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
+                  bool nonblocking);
 
 int vb2_core_streamon(struct vb2_queue *q, unsigned int type);
 int vb2_core_streamoff(struct vb2_queue *q, unsigned int type);
index 2f6a3f2233edf8e2052c7c5bd5856894bbe7d5eb..da3a77d25fcbe1d32fcf9fff0659e48612a0e0c1 100644 (file)
@@ -75,6 +75,8 @@
 #define LOWPAN_IPHC_MAX_HC_BUF_LEN     (sizeof(struct ipv6hdr) +       \
                                         LOWPAN_IPHC_MAX_HEADER_LEN +   \
                                         LOWPAN_NHC_MAX_HDR_LEN)
+/* SCI/DCI is 4 bit width, so we have maximum 16 entries */
+#define LOWPAN_IPHC_CTX_TABLE_SIZE     (1 << 4)
 
 #define LOWPAN_DISPATCH_IPV6           0x41 /* 01000001 = 65 */
 #define LOWPAN_DISPATCH_IPHC           0x60 /* 011xxxxx = ... */
@@ -98,9 +100,39 @@ enum lowpan_lltypes {
        LOWPAN_LLTYPE_IEEE802154,
 };
 
+enum lowpan_iphc_ctx_flags {
+       LOWPAN_IPHC_CTX_FLAG_ACTIVE,
+       LOWPAN_IPHC_CTX_FLAG_COMPRESSION,
+};
+
+struct lowpan_iphc_ctx {
+       u8 id;
+       struct in6_addr pfx;
+       u8 plen;
+       unsigned long flags;
+};
+
+struct lowpan_iphc_ctx_table {
+       spinlock_t lock;
+       const struct lowpan_iphc_ctx_ops *ops;
+       struct lowpan_iphc_ctx table[LOWPAN_IPHC_CTX_TABLE_SIZE];
+};
+
+static inline bool lowpan_iphc_ctx_is_active(const struct lowpan_iphc_ctx *ctx)
+{
+       return test_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
+}
+
+static inline bool
+lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)
+{
+       return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
+}
+
 struct lowpan_priv {
        enum lowpan_lltypes lltype;
        struct dentry *iface_debugfs;
+       struct lowpan_iphc_ctx_table ctx;
 
        /* must be last */
        u8 priv[0] __aligned(sizeof(void *));
index 9d446f136607e54cd041e57474e608f09d4278ef..2a19fe111c78836629bd914086b17a48f96c472c 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <net/sch_generic.h>
 #include <net/pkt_sched.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 
 struct tcf_common {
        struct hlist_node               tcfc_head;
@@ -65,11 +67,6 @@ static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
        return 0;
 }
 
-static inline void tcf_hashinfo_destroy(struct tcf_hashinfo *hf)
-{
-       kfree(hf->htab);
-}
-
 /* Update lastuse only if needed, to avoid dirtying a cache line.
  * We use a temp variable to avoid fetching jiffies twice.
  */
@@ -81,42 +78,76 @@ static inline void tcf_lastuse_update(struct tcf_t *tm)
                tm->lastuse = now;
 }
 
-#ifdef CONFIG_NET_CLS_ACT
-
-#define ACT_P_CREATED 1
-#define ACT_P_DELETED 1
-
 struct tc_action {
        void                    *priv;
        const struct tc_action_ops      *ops;
        __u32                   type; /* for backward compat(TCA_OLD_COMPAT) */
        __u32                   order;
        struct list_head        list;
+       struct tcf_hashinfo     *hinfo;
 };
 
+#ifdef CONFIG_NET_CLS_ACT
+
+#define ACT_P_CREATED 1
+#define ACT_P_DELETED 1
+
 struct tc_action_ops {
        struct list_head head;
-       struct tcf_hashinfo *hinfo;
        char    kind[IFNAMSIZ];
        __u32   type; /* TBD to match kind */
        struct module           *owner;
        int     (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *);
        int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
        void    (*cleanup)(struct tc_action *, int bind);
-       int     (*lookup)(struct tc_action *, u32);
+       int     (*lookup)(struct net *, struct tc_action *, u32);
        int     (*init)(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act, int ovr,
                        int bind);
-       int     (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
+       int     (*walk)(struct net *, struct sk_buff *,
+                       struct netlink_callback *, int, struct tc_action *);
+};
+
+struct tc_action_net {
+       struct tcf_hashinfo *hinfo;
+       const struct tc_action_ops *ops;
 };
 
-int tcf_hash_search(struct tc_action *a, u32 index);
-u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
-int tcf_hash_check(u32 index, struct tc_action *a, int bind);
-int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
-                   int size, int bind, bool cpustats);
+static inline
+int tc_action_net_init(struct tc_action_net *tn, const struct tc_action_ops *ops,
+                      unsigned int mask)
+{
+       int err = 0;
+
+       tn->hinfo = kmalloc(sizeof(*tn->hinfo), GFP_KERNEL);
+       if (!tn->hinfo)
+               return -ENOMEM;
+       tn->ops = ops;
+       err = tcf_hashinfo_init(tn->hinfo, mask);
+       if (err)
+               kfree(tn->hinfo);
+       return err;
+}
+
+void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
+                         struct tcf_hashinfo *hinfo);
+
+static inline void tc_action_net_exit(struct tc_action_net *tn)
+{
+       tcf_hashinfo_destroy(tn->ops, tn->hinfo);
+}
+
+int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
+                      struct netlink_callback *cb, int type,
+                      struct tc_action *a);
+int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index);
+u32 tcf_hash_new_index(struct tc_action_net *tn);
+int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
+                  int bind);
+int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+                   struct tc_action *a, int size, int bind, bool cpustats);
 void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
-void tcf_hash_insert(struct tc_action *a);
+void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a);
 
 int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);
 
@@ -125,8 +156,8 @@ static inline int tcf_hash_release(struct tc_action *a, bool bind)
        return __tcf_hash_release(a, bind, false);
 }
 
-int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
-int tcf_unregister_action(struct tc_action_ops *a);
+int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
+int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops);
 int tcf_action_destroy(struct list_head *actions, int bind);
 int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
                    struct tcf_result *res);
@@ -140,5 +171,16 @@ int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
 int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
 int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
 int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
+
+#define tc_no_actions(_exts) \
+       (list_empty(&(_exts)->actions))
+
+#define tc_for_each_action(_a, _exts) \
+       list_for_each_entry(a, &(_exts)->actions, list)
+#else /* CONFIG_NET_CLS_ACT */
+
+#define tc_no_actions(_exts) true
+#define tc_for_each_action(_a, _exts) while (0)
+
 #endif /* CONFIG_NET_CLS_ACT */
 #endif
index 2a91a0561a478393ca9e9d2f1993467cc4c5c9cb..9b4c418bebd84ae0a7debfbcc697ee92b136ec99 100644 (file)
@@ -6,8 +6,8 @@
 #include <linux/mutex.h>
 #include <net/sock.h>
 
-void unix_inflight(struct file *fp);
-void unix_notinflight(struct file *fp);
+void unix_inflight(struct user_struct *user, struct file *fp);
+void unix_notinflight(struct user_struct *user, struct file *fp);
 void unix_gc(void);
 void wait_for_unix_gc(void);
 struct sock *unix_get_socket(struct file *filp);
index d4f82edb5cffe0528719dc416e8b28b71460e485..dc71473462ac9f60680dad7c7cce8e9878b1a8a5 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
+#include <linux/leds.h>
 #include <net/bluetooth/hci.h>
 #include <net/bluetooth/hci_sock.h>
 
@@ -396,6 +397,8 @@ struct hci_dev {
        struct delayed_work     rpa_expired;
        bdaddr_t                rpa;
 
+       struct led_trigger      *power_led;
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
index 9bcaaf7cd15ab053a5de9cbf92fd02f0fb0ffaf7..9e1b24c29f0c65ce997d71a566e63125f7a6e248 100644 (file)
@@ -712,6 +712,8 @@ struct cfg80211_acl_data {
  * @p2p_opp_ps: P2P opportunistic PS
  * @acl: ACL configuration used by the drivers which has support for
  *     MAC address based access control
+ * @pbss: If set, start as a PCP instead of AP. Relevant for DMG
+ *     networks.
  */
 struct cfg80211_ap_settings {
        struct cfg80211_chan_def chandef;
@@ -730,6 +732,7 @@ struct cfg80211_ap_settings {
        u8 p2p_ctwindow;
        bool p2p_opp_ps;
        const struct cfg80211_acl_data *acl;
+       bool pbss;
 };
 
 /**
@@ -1888,6 +1891,8 @@ struct cfg80211_ibss_params {
  * @ht_capa_mask:  The bits of ht_capa which are to be used.
  * @vht_capa:  VHT Capability overrides
  * @vht_capa_mask: The bits of vht_capa which are to be used.
+ * @pbss: if set, connect to a PCP instead of AP. Valid for DMG
+ *     networks.
  */
 struct cfg80211_connect_params {
        struct ieee80211_channel *channel;
@@ -1910,6 +1915,7 @@ struct cfg80211_connect_params {
        struct ieee80211_ht_cap ht_capa_mask;
        struct ieee80211_vht_cap vht_capa;
        struct ieee80211_vht_cap vht_capa_mask;
+       bool pbss;
 };
 
 /**
@@ -3489,6 +3495,7 @@ struct cfg80211_cached_keys;
  *     registered for unexpected class 3 frames (AP mode)
  * @conn: (private) cfg80211 software SME connection state machine data
  * @connect_keys: (private) keys to set after connection is established
+ * @conn_bss_type: connecting/connected BSS type
  * @ibss_fixed: (private) IBSS is using fixed BSSID
  * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
  * @event_list: (private) list for internal event processing
@@ -3519,6 +3526,7 @@ struct wireless_dev {
        u8 ssid_len, mesh_id_len, mesh_id_up_len;
        struct cfg80211_conn *conn;
        struct cfg80211_cached_keys *connect_keys;
+       enum ieee80211_bss_type conn_bss_type;
 
        struct list_head event_list;
        spinlock_t event_lock;
index 10a16b5bd1c70b58ee6e02b8515725a93afc5d18..5c30891e84e514518d82f82bff3c9e7d006ab723 100644 (file)
@@ -88,8 +88,11 @@ static inline __wsum
 csum_block_add(__wsum csum, __wsum csum2, int offset)
 {
        u32 sum = (__force u32)csum2;
-       if (offset&1)
-               sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF);
+
+       /* rotate sum to align it with a 16b boundary */
+       if (offset & 1)
+               sum = ror32(sum, 8);
+
        return csum_add(csum, (__force __wsum)sum);
 }
 
@@ -102,10 +105,7 @@ csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
 static inline __wsum
 csum_block_sub(__wsum csum, __wsum csum2, int offset)
 {
-       u32 sum = (__force u32)csum2;
-       if (offset&1)
-               sum = ((sum&0xFF00FF)<<8)+((sum>>8)&0xFF00FF);
-       return csum_sub(csum, (__force __wsum)sum);
+       return csum_block_add(csum, ~csum2, offset);
 }
 
 static inline __wsum csum_unfold(__sum16 n)
@@ -120,6 +120,11 @@ static inline __wsum csum_partial_ext(const void *buff, int len, __wsum sum)
 
 #define CSUM_MANGLED_0 ((__force __sum16)0xffff)
 
+static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
+{
+       *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
+}
+
 static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
 {
        __wsum tmp = csum_sub(~csum_unfold(*sum), (__force __wsum)from);
index 267e70210061d82c22b4b2e91a9ab69cbb2b7ce7..d168aca115ccf0ff4c4ca98107327c533314c618 100644 (file)
@@ -162,12 +162,14 @@ struct codel_vars {
  * struct codel_stats - contains codel shared variables and stats
  * @maxpacket: largest packet we've seen so far
  * @drop_count:        temp count of dropped packets in dequeue()
+ * @drop_len:  bytes of dropped packets in dequeue()
  * ecn_mark:   number of packets we ECN marked instead of dropping
  * ce_mark:    number of packets CE marked because sojourn time was above ce_threshold
  */
 struct codel_stats {
        u32             maxpacket;
        u32             drop_count;
+       u32             drop_len;
        u32             ecn_mark;
        u32             ce_mark;
 };
@@ -308,6 +310,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                                                                  vars->rec_inv_sqrt);
                                        goto end;
                                }
+                               stats->drop_len += qdisc_pkt_len(skb);
                                qdisc_drop(skb, sch);
                                stats->drop_count++;
                                skb = dequeue_func(vars, sch);
@@ -330,6 +333,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                if (params->ecn && INET_ECN_set_ce(skb)) {
                        stats->ecn_mark++;
                } else {
+                       stats->drop_len += qdisc_pkt_len(skb);
                        qdisc_drop(skb, sch);
                        stats->drop_count++;
 
diff --git a/include/net/devlink.h b/include/net/devlink.h
new file mode 100644 (file)
index 0000000..c37d257
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * include/net/devlink.h - Network physical device Netlink interface
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _NET_DEVLINK_H_
+#define _NET_DEVLINK_H_
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <net/net_namespace.h>
+#include <uapi/linux/devlink.h>
+
+struct devlink_ops;
+
+struct devlink {
+       struct list_head list;
+       struct list_head port_list;
+       const struct devlink_ops *ops;
+       struct device *dev;
+       possible_net_t _net;
+       char priv[0] __aligned(NETDEV_ALIGN);
+};
+
+struct devlink_port {
+       struct list_head list;
+       struct devlink *devlink;
+       unsigned index;
+       bool registered;
+       enum devlink_port_type type;
+       enum devlink_port_type desired_type;
+       void *type_dev;
+       bool split;
+       u32 split_group;
+};
+
+struct devlink_ops {
+       size_t priv_size;
+       int (*port_type_set)(struct devlink_port *devlink_port,
+                            enum devlink_port_type port_type);
+       int (*port_split)(struct devlink *devlink, unsigned int port_index,
+                         unsigned int count);
+       int (*port_unsplit)(struct devlink *devlink, unsigned int port_index);
+};
+
+static inline void *devlink_priv(struct devlink *devlink)
+{
+       BUG_ON(!devlink);
+       return &devlink->priv;
+}
+
+static inline struct devlink *priv_to_devlink(void *priv)
+{
+       BUG_ON(!priv);
+       return container_of(priv, struct devlink, priv);
+}
+
+struct ib_device;
+
+#if IS_ENABLED(CONFIG_NET_DEVLINK)
+
+struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size);
+int devlink_register(struct devlink *devlink, struct device *dev);
+void devlink_unregister(struct devlink *devlink);
+void devlink_free(struct devlink *devlink);
+int devlink_port_register(struct devlink *devlink,
+                         struct devlink_port *devlink_port,
+                         unsigned int port_index);
+void devlink_port_unregister(struct devlink_port *devlink_port);
+void devlink_port_type_eth_set(struct devlink_port *devlink_port,
+                              struct net_device *netdev);
+void devlink_port_type_ib_set(struct devlink_port *devlink_port,
+                             struct ib_device *ibdev);
+void devlink_port_type_clear(struct devlink_port *devlink_port);
+void devlink_port_split_set(struct devlink_port *devlink_port,
+                           u32 split_group);
+
+#else
+
+static inline struct devlink *devlink_alloc(const struct devlink_ops *ops,
+                                           size_t priv_size)
+{
+       return kzalloc(sizeof(struct devlink) + priv_size, GFP_KERNEL);
+}
+
+static inline int devlink_register(struct devlink *devlink, struct device *dev)
+{
+       return 0;
+}
+
+static inline void devlink_unregister(struct devlink *devlink)
+{
+}
+
+static inline void devlink_free(struct devlink *devlink)
+{
+       kfree(devlink);
+}
+
+static inline int devlink_port_register(struct devlink *devlink,
+                                       struct devlink_port *devlink_port,
+                                       unsigned int port_index)
+{
+       return 0;
+}
+
+static inline void devlink_port_unregister(struct devlink_port *devlink_port)
+{
+}
+
+static inline void devlink_port_type_eth_set(struct devlink_port *devlink_port,
+                                            struct net_device *netdev)
+{
+}
+
+static inline void devlink_port_type_ib_set(struct devlink_port *devlink_port,
+                                           struct ib_device *ibdev)
+{
+}
+
+static inline void devlink_port_type_clear(struct devlink_port *devlink_port)
+{
+}
+
+static inline void devlink_port_split_set(struct devlink_port *devlink_port,
+                                         u32 split_group)
+{
+}
+
+#endif
+
+#endif /* _NET_DEVLINK_H_ */
index 26a0e86e611e8d3e76f726a6805a31464bcd63c8..26c0a3fa009a8a292a8c69601fdb4dc089ec250c 100644 (file)
@@ -297,15 +297,16 @@ struct dsa_switch_driver {
         * Bridge integration
         */
        int     (*port_join_bridge)(struct dsa_switch *ds, int port,
-                                   u32 br_port_mask);
-       int     (*port_leave_bridge)(struct dsa_switch *ds, int port,
-                                    u32 br_port_mask);
+                                   struct net_device *bridge);
+       int     (*port_leave_bridge)(struct dsa_switch *ds, int port);
        int     (*port_stp_update)(struct dsa_switch *ds, int port,
                                   u8 state);
 
        /*
         * VLAN support
         */
+       int     (*port_vlan_filtering)(struct dsa_switch *ds, int port,
+                                      bool vlan_filtering);
        int     (*port_vlan_prepare)(struct dsa_switch *ds, int port,
                                     const struct switchdev_obj_port_vlan *vlan,
                                     struct switchdev_trans *trans);
@@ -314,9 +315,9 @@ struct dsa_switch_driver {
                                 struct switchdev_trans *trans);
        int     (*port_vlan_del)(struct dsa_switch *ds, int port,
                                 const struct switchdev_obj_port_vlan *vlan);
-       int     (*port_pvid_get)(struct dsa_switch *ds, int port, u16 *pvid);
-       int     (*vlan_getnext)(struct dsa_switch *ds, u16 *vid,
-                               unsigned long *ports, unsigned long *untagged);
+       int     (*port_vlan_dump)(struct dsa_switch *ds, int port,
+                                 struct switchdev_obj_port_vlan *vlan,
+                                 int (*cb)(struct switchdev_obj *obj));
 
        /*
         * Forwarding database
diff --git a/include/net/dst_cache.h b/include/net/dst_cache.h
new file mode 100644 (file)
index 0000000..151acca
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef _NET_DST_CACHE_H
+#define _NET_DST_CACHE_H
+
+#include <linux/jiffies.h>
+#include <net/dst.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_fib.h>
+#endif
+
+struct dst_cache {
+       struct dst_cache_pcpu __percpu *cache;
+       unsigned long reset_ts;
+};
+
+/**
+ *     dst_cache_get - perform cache lookup
+ *     @dst_cache: the cache
+ *
+ *     The caller should use dst_cache_get_ip4() if it need to retrieve the
+ *     source address to be used when xmitting to the cached dst.
+ *     local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
+
+/**
+ *     dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
+ *     @dst_cache: the cache
+ *     @saddr: return value for the retrieved source address
+ *
+ *     local BH must be disabled.
+ */
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
+
+/**
+ *     dst_cache_set_ip4 - store the ipv4 dst into the cache
+ *     @dst_cache: the cache
+ *     @dst: the entry to be cached
+ *     @saddr: the source address to be stored inside the cache
+ *
+ *     local BH must be disabled.
+ */
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      __be32 saddr);
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+/**
+ *     dst_cache_set_ip6 - store the ipv6 dst into the cache
+ *     @dst_cache: the cache
+ *     @dst: the entry to be cached
+ *     @saddr: the source address to be stored inside the cache
+ *
+ *     local BH must be disabled.
+ */
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      const struct in6_addr *addr);
+
+/**
+ *     dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
+ *     @dst_cache: the cache
+ *     @saddr: return value for the retrieved source address
+ *
+ *     local BH must be disabled.
+ */
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
+                                   struct in6_addr *saddr);
+#endif
+
+/**
+ *     dst_cache_reset - invalidate the cache contents
+ *     @dst_cache: the cache
+ *
+ *     This do not free the cached dst to avoid races and contentions.
+ *     the dst will be freed on later cache lookup.
+ */
+static inline void dst_cache_reset(struct dst_cache *dst_cache)
+{
+       dst_cache->reset_ts = jiffies;
+}
+
+/**
+ *     dst_cache_init - initialize the cache, allocating the required storage
+ *     @dst_cache: the cache
+ *     @gfp: allocation flags
+ */
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp);
+
+/**
+ *     dst_cache_destroy - empty the cache and free the allocated storage
+ *     @dst_cache: the cache
+ *
+ *     No synchronization is enforced: it must be called only when the cache
+ *     is unsed.
+ */
+void dst_cache_destroy(struct dst_cache *dst_cache);
+
+#endif
index 30a56ab2ccfb05d7bc9a527ebdc09da19b3d5f7b..5db9f5910428f3741049c3377b1f4ed9a013bed1 100644 (file)
@@ -62,6 +62,7 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
                      sizeof(a->u.tun_info) + a->u.tun_info.options_len);
 }
 
+void metadata_dst_free(struct metadata_dst *);
 struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags);
 struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags);
 
@@ -125,7 +126,7 @@ static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb,
 
        ip_tunnel_key_init(&tun_dst->u.tun_info.key,
                           iph->saddr, iph->daddr, iph->tos, iph->ttl,
-                          0, 0, tunnel_id, flags);
+                          0, 0, 0, tunnel_id, flags);
        return tun_dst;
 }
 
@@ -151,8 +152,11 @@ static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb,
 
        info->key.u.ipv6.src = ip6h->saddr;
        info->key.u.ipv6.dst = ip6h->daddr;
+
        info->key.tos = ipv6_get_dsfield(ip6h);
        info->key.ttl = ip6h->hop_limit;
+       info->key.label = ip6_flowlabel(ip6h);
+
        return tun_dst;
 }
 
index 8c8548cf5888c4535a809494fad454e755ff6749..d3d60dccd19ff636855ea00ef3815047efc37dc9 100644 (file)
@@ -184,4 +184,17 @@ static inline bool flow_keys_have_l4(struct flow_keys *keys)
 
 u32 flow_hash_from_keys(struct flow_keys *keys);
 
+static inline bool dissector_uses_key(const struct flow_dissector *flow_dissector,
+                                     enum flow_dissector_key_id key_id)
+{
+       return flow_dissector->used_keys & (1 << key_id);
+}
+
+static inline void *skb_flow_dissector_target(struct flow_dissector *flow_dissector,
+                                             enum flow_dissector_key_id key_id,
+                                             void *target_container)
+{
+       return ((char *)target_container) + flow_dissector->offset[key_id];
+}
+
 #endif
index 43c0e771f417ae3c36f4fb7a0390f9569f7c9433..8d4608ce8716360924ae68a24ffb25c0171187fc 100644 (file)
@@ -83,7 +83,6 @@ struct genl_family {
  * @attrs: netlink attributes
  * @_net: network namespace
  * @user_ptr: user pointers
- * @dst_sk: destination socket
  */
 struct genl_info {
        u32                     snd_seq;
@@ -94,7 +93,6 @@ struct genl_info {
        struct nlattr **        attrs;
        possible_net_t          _net;
        void *                  user_ptr[2];
-       struct sock *           dst_sk;
 };
 
 static inline struct net *genl_info_net(struct genl_info *info)
@@ -188,8 +186,6 @@ int genl_unregister_family(struct genl_family *family);
 void genl_notify(struct genl_family *family, struct sk_buff *skb,
                 struct genl_info *info, u32 group, gfp_t flags);
 
-struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info,
-                                   gfp_t flags);
 void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
                  struct genl_family *family, int flags, u8 cmd);
 
index 481fe1c9044cfd8b49585139e24df16b0716debf..49dcad4fe99e0ad5de491ef0e0675a3b516aabca 100644 (file)
@@ -270,8 +270,9 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk,
                                            struct sock *newsk,
                                            const struct request_sock *req);
 
-void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req,
-                             struct sock *child);
+struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
+                                     struct request_sock *req,
+                                     struct sock *child);
 void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
                                   unsigned long timeout);
 struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child,
index 12aac0fd6ee7cd9d5963d69a606ebbc5b9981b26..909972aa3acd7e4e3d865800f45056235efc7bef 100644 (file)
@@ -13,6 +13,7 @@ struct netns_frags {
        int                     timeout;
        int                     high_thresh;
        int                     low_thresh;
+       int                     max_dist;
 };
 
 /**
index 1a98f1ca16383d2b9cd0867091e323ab7c81f045..fad74d323bd6b324ef24ff7ff0ce03140c58e1dd 100644 (file)
@@ -240,17 +240,13 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
 }
 #endif
 
+__be32 inet_current_timestamp(void);
+
 /* From inetpeer.c */
 extern int inet_peer_threshold;
 extern int inet_peer_minttl;
 extern int inet_peer_maxttl;
 
-/* From ip_input.c */
-extern int sysctl_ip_early_demux;
-
-/* From ip_output.c */
-extern int sysctl_ip_dynaddr;
-
 void ipfrag_init(void);
 
 void ip_static_sysctl_init(void);
index 0d0ce0b2d8701cb94514933c239996da1cc982ca..499a707765ea68fa010e03716319dcef57de49fe 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/if_tunnel.h>
 #include <linux/ip6_tunnel.h>
 #include <net/ip_tunnels.h>
+#include <net/dst_cache.h>
 
 #define IP6TUNNEL_ERR_TIMEO (30*HZ)
 
@@ -33,12 +34,6 @@ struct __ip6_tnl_parm {
        __be32                  o_key;
 };
 
-struct ip6_tnl_dst {
-       seqlock_t lock;
-       struct dst_entry __rcu *dst;
-       u32 cookie;
-};
-
 /* IPv6 tunnel */
 struct ip6_tnl {
        struct ip6_tnl __rcu *next;     /* next tunnel in list */
@@ -46,7 +41,7 @@ struct ip6_tnl {
        struct net *net;        /* netns for packet i/o */
        struct __ip6_tnl_parm parms;    /* tunnel configuration parameters */
        struct flowi fl;        /* flowi template for xmit */
-       struct ip6_tnl_dst __percpu *dst_cache; /* cached dst */
+       struct dst_cache dst_cache;     /* cached dst */
 
        int err_count;
        unsigned long err_time;
@@ -66,11 +61,6 @@ struct ipv6_tlv_tnl_enc_lim {
        __u8 encap_limit;       /* tunnel encapsulation limit   */
 } __packed;
 
-struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t);
-int ip6_tnl_dst_init(struct ip6_tnl *t);
-void ip6_tnl_dst_destroy(struct ip6_tnl *t);
-void ip6_tnl_dst_reset(struct ip6_tnl *t);
-void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst);
 int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
                const struct in6_addr *raddr);
 int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
index 7029527725ddbb80f7b78e66565b69ad8aad5806..4079fc18ffe4643522178b394ed6d1b54d5a6093 100644 (file)
@@ -61,6 +61,7 @@ struct fib_nh_exception {
        struct rtable __rcu             *fnhe_rth_input;
        struct rtable __rcu             *fnhe_rth_output;
        unsigned long                   fnhe_stamp;
+       struct rcu_head                 rcu;
 };
 
 struct fnhe_hash_bucket {
index bc439f32baa9d3b39bf6de2fa77558cb5cd5d5e7..5dc2e454f866989cd6c2eae974453ed3b3a8cd0b 100644 (file)
@@ -13,6 +13,7 @@
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
 #include <net/lwtunnel.h>
+#include <net/dst_cache.h>
 
 #if IS_ENABLED(CONFIG_IPV6)
 #include <net/ipv6.h>
@@ -47,6 +48,7 @@ struct ip_tunnel_key {
        __be16                  tun_flags;
        u8                      tos;            /* TOS for IPv4, TC for IPv6 */
        u8                      ttl;            /* TTL for IPv4, HL for IPv6 */
+       __be32                  label;          /* Flow Label for IPv6 */
        __be16                  tp_src;
        __be16                  tp_dst;
 };
@@ -57,6 +59,9 @@ struct ip_tunnel_key {
 
 struct ip_tunnel_info {
        struct ip_tunnel_key    key;
+#ifdef CONFIG_DST_CACHE
+       struct dst_cache        dst_cache;
+#endif
        u8                      options_len;
        u8                      mode;
 };
@@ -85,11 +90,6 @@ struct ip_tunnel_prl_entry {
        struct rcu_head                 rcu_head;
 };
 
-struct ip_tunnel_dst {
-       struct dst_entry __rcu          *dst;
-       __be32                           saddr;
-};
-
 struct metadata_dst;
 
 struct ip_tunnel {
@@ -108,7 +108,7 @@ struct ip_tunnel {
        int             tun_hlen;       /* Precalculated header length */
        int             mlink;
 
-       struct ip_tunnel_dst __percpu *dst_cache;
+       struct dst_cache dst_cache;
 
        struct ip_tunnel_parm parms;
 
@@ -141,6 +141,7 @@ struct ip_tunnel {
 #define TUNNEL_CRIT_OPT                __cpu_to_be16(0x0400)
 #define TUNNEL_GENEVE_OPT      __cpu_to_be16(0x0800)
 #define TUNNEL_VXLAN_OPT       __cpu_to_be16(0x1000)
+#define TUNNEL_NOCACHE         __cpu_to_be16(0x2000)
 
 #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT)
 
@@ -181,7 +182,7 @@ int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op,
 
 static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
                                      __be32 saddr, __be32 daddr,
-                                     u8 tos, u8 ttl,
+                                     u8 tos, u8 ttl, __be32 label,
                                      __be16 tp_src, __be16 tp_dst,
                                      __be64 tun_id, __be16 tun_flags)
 {
@@ -192,6 +193,7 @@ static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
               0, IP_TUNNEL_KEY_IPV4_PAD_LEN);
        key->tos = tos;
        key->ttl = ttl;
+       key->label = label;
        key->tun_flags = tun_flags;
 
        /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of
@@ -207,6 +209,20 @@ static inline void ip_tunnel_key_init(struct ip_tunnel_key *key,
                       0, sizeof(*key) - IP_TUNNEL_KEY_SIZE);
 }
 
+static inline bool
+ip_tunnel_dst_cache_usable(const struct sk_buff *skb,
+                          const struct ip_tunnel_info *info)
+{
+       if (skb->mark)
+               return false;
+       if (!info)
+               return true;
+       if (info->key.tun_flags & TUNNEL_NOCACHE)
+               return false;
+
+       return true;
+}
+
 static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info
                                               *tun_info)
 {
@@ -230,6 +246,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
 int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
 int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
                    u8 *protocol, struct flowi4 *fl4);
+int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict);
 int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
 
 struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
@@ -247,7 +264,6 @@ 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);
 int ip_tunnel_encap_setup(struct ip_tunnel *t,
                          struct ip_tunnel_encap *ipencap);
 
@@ -272,7 +288,8 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
        return INET_ECN_encapsulate(tos, inner);
 }
 
-int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto);
+int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto,
+                        bool xnet);
 void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
                   __be32 src, __be32 dst, u8 proto,
                   u8 tos, u8 ttl, __be16 df, bool xnet);
@@ -354,6 +371,17 @@ static inline void ip_tunnel_unneed_metadata(void)
 {
 }
 
+static inline void ip_tunnel_info_opts_get(void *to,
+                                          const struct ip_tunnel_info *info)
+{
+}
+
+static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
+                                          const void *from, int len)
+{
+       info->options_len = 0;
+}
+
 #endif /* CONFIG_INET */
 
 #endif /* __NET_IP_TUNNELS_H */
index 6570f379aba2eb744b0e8522349f0612b01b6814..f3c9857c645dee91a8a850ed5639ae5894dcff73 100644 (file)
@@ -259,8 +259,12 @@ static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
 
        rcu_read_lock();
        opt = rcu_dereference(np->opt);
-       if (opt && !atomic_inc_not_zero(&opt->refcnt))
-               opt = NULL;
+       if (opt) {
+               if (!atomic_inc_not_zero(&opt->refcnt))
+                       opt = NULL;
+               else
+                       opt = rcu_pointer_handoff(opt);
+       }
        rcu_read_unlock();
        return opt;
 }
index 8f81bbbc38fc939070a5761e3af90da62faf8d68..e0f4109e64c6fca9ba87d768c2c7b1220a6557f4 100644 (file)
@@ -439,6 +439,12 @@ int dev_get_wireless_info(char *buffer, char **start, off_t offset, int length);
 /* Send a single event to user space */
 void wireless_send_event(struct net_device *dev, unsigned int cmd,
                         union iwreq_data *wrqu, const char *extra);
+#ifdef CONFIG_WEXT_CORE
+/* flush all previous wext events - if work is done from netdev notifiers */
+void wireless_nlevent_flush(void);
+#else
+static inline void wireless_nlevent_flush(void) {}
+#endif
 
 /* We may need a function to send a stream of events to user space.
  * More on that later... */
diff --git a/include/net/kcm.h b/include/net/kcm.h
new file mode 100644 (file)
index 0000000..2840b58
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Kernel Connection Multiplexor
+ *
+ * Copyright (c) 2016 Tom Herbert <tom@herbertland.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.
+ */
+
+#ifndef __NET_KCM_H_
+#define __NET_KCM_H_
+
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <uapi/linux/kcm.h>
+
+extern unsigned int kcm_net_id;
+
+#define KCM_STATS_ADD(stat, count) ((stat) += (count))
+#define KCM_STATS_INCR(stat) ((stat)++)
+
+struct kcm_psock_stats {
+       unsigned long long rx_msgs;
+       unsigned long long rx_bytes;
+       unsigned long long tx_msgs;
+       unsigned long long tx_bytes;
+       unsigned int rx_aborts;
+       unsigned int rx_mem_fail;
+       unsigned int rx_need_more_hdr;
+       unsigned int rx_msg_too_big;
+       unsigned int rx_msg_timeouts;
+       unsigned int rx_bad_hdr_len;
+       unsigned long long reserved;
+       unsigned long long unreserved;
+       unsigned int tx_aborts;
+};
+
+struct kcm_mux_stats {
+       unsigned long long rx_msgs;
+       unsigned long long rx_bytes;
+       unsigned long long tx_msgs;
+       unsigned long long tx_bytes;
+       unsigned int rx_ready_drops;
+       unsigned int tx_retries;
+       unsigned int psock_attach;
+       unsigned int psock_unattach_rsvd;
+       unsigned int psock_unattach;
+};
+
+struct kcm_stats {
+       unsigned long long rx_msgs;
+       unsigned long long rx_bytes;
+       unsigned long long tx_msgs;
+       unsigned long long tx_bytes;
+};
+
+struct kcm_tx_msg {
+       unsigned int sent;
+       unsigned int fragidx;
+       unsigned int frag_offset;
+       unsigned int msg_flags;
+       struct sk_buff *frag_skb;
+       struct sk_buff *last_skb;
+};
+
+struct kcm_rx_msg {
+       int full_len;
+       int accum_len;
+       int offset;
+       int early_eaten;
+};
+
+/* Socket structure for KCM client sockets */
+struct kcm_sock {
+       struct sock sk;
+       struct kcm_mux *mux;
+       struct list_head kcm_sock_list;
+       int index;
+       u32 done : 1;
+       struct work_struct done_work;
+
+       struct kcm_stats stats;
+
+       /* Transmit */
+       struct kcm_psock *tx_psock;
+       struct work_struct tx_work;
+       struct list_head wait_psock_list;
+       struct sk_buff *seq_skb;
+
+       /* Don't use bit fields here, these are set under different locks */
+       bool tx_wait;
+       bool tx_wait_more;
+
+       /* Receive */
+       struct kcm_psock *rx_psock;
+       struct list_head wait_rx_list; /* KCMs waiting for receiving */
+       bool rx_wait;
+       u32 rx_disabled : 1;
+};
+
+struct bpf_prog;
+
+/* Structure for an attached lower socket */
+struct kcm_psock {
+       struct sock *sk;
+       struct kcm_mux *mux;
+       int index;
+
+       u32 tx_stopped : 1;
+       u32 rx_stopped : 1;
+       u32 done : 1;
+       u32 unattaching : 1;
+
+       void (*save_state_change)(struct sock *sk);
+       void (*save_data_ready)(struct sock *sk);
+       void (*save_write_space)(struct sock *sk);
+
+       struct list_head psock_list;
+
+       struct kcm_psock_stats stats;
+
+       /* Receive */
+       struct sk_buff *rx_skb_head;
+       struct sk_buff **rx_skb_nextp;
+       struct sk_buff *ready_rx_msg;
+       struct list_head psock_ready_list;
+       struct work_struct rx_work;
+       struct delayed_work rx_delayed_work;
+       struct bpf_prog *bpf_prog;
+       struct kcm_sock *rx_kcm;
+       unsigned long long saved_rx_bytes;
+       unsigned long long saved_rx_msgs;
+       struct timer_list rx_msg_timer;
+       unsigned int rx_need_bytes;
+
+       /* Transmit */
+       struct kcm_sock *tx_kcm;
+       struct list_head psock_avail_list;
+       unsigned long long saved_tx_bytes;
+       unsigned long long saved_tx_msgs;
+};
+
+/* Per net MUX list */
+struct kcm_net {
+       struct mutex mutex;
+       struct kcm_psock_stats aggregate_psock_stats;
+       struct kcm_mux_stats aggregate_mux_stats;
+       struct list_head mux_list;
+       int count;
+};
+
+/* Structure for a MUX */
+struct kcm_mux {
+       struct list_head kcm_mux_list;
+       struct rcu_head rcu;
+       struct kcm_net *knet;
+
+       struct list_head kcm_socks;     /* All KCM sockets on MUX */
+       int kcm_socks_cnt;              /* Total KCM socket count for MUX */
+       struct list_head psocks;        /* List of all psocks on MUX */
+       int psocks_cnt;         /* Total attached sockets */
+
+       struct kcm_mux_stats stats;
+       struct kcm_psock_stats aggregate_psock_stats;
+
+       /* Receive */
+       spinlock_t rx_lock ____cacheline_aligned_in_smp;
+       struct list_head kcm_rx_waiters; /* KCMs waiting for receiving */
+       struct list_head psocks_ready;  /* List of psocks with a msg ready */
+       struct sk_buff_head rx_hold_queue;
+
+       /* Transmit */
+       spinlock_t  lock ____cacheline_aligned_in_smp;  /* TX and mux locking */
+       struct list_head psocks_avail;  /* List of available psocks */
+       struct list_head kcm_tx_waiters; /* KCMs waiting for a TX psock */
+};
+
+#ifdef CONFIG_PROC_FS
+int kcm_proc_init(void);
+void kcm_proc_exit(void);
+#else
+static inline int kcm_proc_init(void) { return 0; }
+static inline void kcm_proc_exit(void) { }
+#endif
+
+static inline void aggregate_psock_stats(struct kcm_psock_stats *stats,
+                                        struct kcm_psock_stats *agg_stats)
+{
+       /* Save psock statistics in the mux when psock is being unattached. */
+
+#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat)
+       SAVE_PSOCK_STATS(rx_msgs);
+       SAVE_PSOCK_STATS(rx_bytes);
+       SAVE_PSOCK_STATS(rx_aborts);
+       SAVE_PSOCK_STATS(rx_mem_fail);
+       SAVE_PSOCK_STATS(rx_need_more_hdr);
+       SAVE_PSOCK_STATS(rx_msg_too_big);
+       SAVE_PSOCK_STATS(rx_msg_timeouts);
+       SAVE_PSOCK_STATS(rx_bad_hdr_len);
+       SAVE_PSOCK_STATS(tx_msgs);
+       SAVE_PSOCK_STATS(tx_bytes);
+       SAVE_PSOCK_STATS(reserved);
+       SAVE_PSOCK_STATS(unreserved);
+       SAVE_PSOCK_STATS(tx_aborts);
+#undef SAVE_PSOCK_STATS
+}
+
+static inline void aggregate_mux_stats(struct kcm_mux_stats *stats,
+                                      struct kcm_mux_stats *agg_stats)
+{
+       /* Save psock statistics in the mux when psock is being unattached. */
+
+#define SAVE_MUX_STATS(_stat) (agg_stats->_stat += stats->_stat)
+       SAVE_MUX_STATS(rx_msgs);
+       SAVE_MUX_STATS(rx_bytes);
+       SAVE_MUX_STATS(tx_msgs);
+       SAVE_MUX_STATS(tx_bytes);
+       SAVE_MUX_STATS(rx_ready_drops);
+       SAVE_MUX_STATS(psock_attach);
+       SAVE_MUX_STATS(psock_unattach_rsvd);
+       SAVE_MUX_STATS(psock_unattach);
+#undef SAVE_MUX_STATS
+}
+
+#endif /* __NET_KCM_H_ */
index 5567d46b3cff913ab927e05fefe7c09dc4f2836e..c43a9c73de5e972eeacb99ef5ae1b0a1fd2e1af0 100644 (file)
@@ -39,7 +39,7 @@ struct l3mdev_ops {
 
 #ifdef CONFIG_NET_L3_MASTER_DEV
 
-int l3mdev_master_ifindex_rcu(struct net_device *dev);
+int l3mdev_master_ifindex_rcu(const struct net_device *dev);
 static inline int l3mdev_master_ifindex(struct net_device *dev)
 {
        int ifindex;
@@ -179,7 +179,7 @@ struct dst_entry *l3mdev_rt6_dst_by_oif(struct net *net,
 
 #else
 
-static inline int l3mdev_master_ifindex_rcu(struct net_device *dev)
+static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev)
 {
        return 0;
 }
index 66350ce3e955330c167dd8ffbb5dc1abfb02a6eb..e9f116e29c221561a3c2e0b4797d56d9c9c3ec56 100644 (file)
@@ -170,6 +170,8 @@ static inline int lwtunnel_input(struct sk_buff *skb)
        return -EOPNOTSUPP;
 }
 
-#endif
+#endif /* CONFIG_LWTUNNEL */
+
+#define MODULE_ALIAS_RTNL_LWT(encap_type) MODULE_ALIAS("rtnl-lwt-" __stringify(encap_type))
 
 #endif /* __NET_LWTUNNEL_H */
index 7c30faff245f262a59831132f84f5cb37c2cc8a5..0c09da34b67a7e7ca4ab45fd1da8f132d8bedc63 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2015 Intel Deutschland GmbH
+ * Copyright (C) 2015 - 2016 Intel Deutschland GmbH
  *
  * 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
@@ -298,6 +298,7 @@ struct ieee80211_vif_chanctx_switch {
  *     note that this is only called when it changes after the channel
  *     context had been assigned.
  * @BSS_CHANGED_OCB: OCB join status changed
+ * @BSS_CHANGED_MU_GROUPS: VHT MU-MIMO group id or user position changed
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -323,6 +324,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_BEACON_INFO         = 1<<20,
        BSS_CHANGED_BANDWIDTH           = 1<<21,
        BSS_CHANGED_OCB                 = 1<<22,
+       BSS_CHANGED_MU_GROUPS           = 1<<23,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -435,6 +437,19 @@ struct ieee80211_event {
        } u;
 };
 
+/**
+ * struct ieee80211_mu_group_data - STA's VHT MU-MIMO group data
+ *
+ * This structure describes the group id data of VHT MU-MIMO
+ *
+ * @membership: 64 bits array - a bit is set if station is member of the group
+ * @position: 2 bits per group id indicating the position in the group
+ */
+struct ieee80211_mu_group_data {
+       u8 membership[WLAN_MEMBERSHIP_LEN];
+       u8 position[WLAN_USER_POSITION_LEN];
+};
+
 /**
  * struct ieee80211_bss_conf - holds the BSS's changing parameters
  *
@@ -477,6 +492,7 @@ struct ieee80211_event {
  * @enable_beacon: whether beaconing should be enabled or not
  * @chandef: Channel definition for this BSS -- the hardware might be
  *     configured a higher bandwidth than this BSS uses, for example.
+ * @mu_group: VHT MU-MIMO group membership data
  * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
  *     This field is only valid when the channel is a wide HT/VHT channel.
  *     Note that with TDLS this can be the case (channel is HT, protection must
@@ -535,6 +551,7 @@ struct ieee80211_bss_conf {
        s32 cqm_rssi_thold;
        u32 cqm_rssi_hyst;
        struct cfg80211_chan_def chandef;
+       struct ieee80211_mu_group_data mu_group;
        __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
        int arp_addr_cnt;
        bool qos;
@@ -691,12 +708,14 @@ enum mac80211_tx_info_flags {
  *     protocol frame (e.g. EAP)
  * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
  *     frame (PS-Poll or uAPSD).
+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
  *
  * These flags are used in tx_info->control.flags.
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTRL_PORT_CTRL_PROTO       = BIT(0),
        IEEE80211_TX_CTRL_PS_RESPONSE           = BIT(1),
+       IEEE80211_TX_CTRL_RATE_INJECT           = BIT(2),
 };
 
 /*
@@ -993,6 +1012,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_MACTIME_END: The timestamp passed in the RX status (@mactime
  *     field) is valid and contains the time the last symbol of the MPDU
  *     (including FCS) was received.
+ * @RX_FLAG_MACTIME_PLCP_START: The timestamp passed in the RX status (@mactime
+ *     field) is valid and contains the time the SYNC preamble was received.
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
  * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
  * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
@@ -1014,6 +1035,14 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
  *     is stored in the @ampdu_delimiter_crc field)
  * @RX_FLAG_LDPC: LDPC was used
+ * @RX_FLAG_ONLY_MONITOR: Report frame only to monitor interfaces without
+ *     processing it in any regular way.
+ *     This is useful if drivers offload some frames but still want to report
+ *     them for sniffing purposes.
+ * @RX_FLAG_SKIP_MONITOR: Process and report frame to all interfaces except
+ *     monitor interfaces.
+ *     This is useful if drivers offload some frames but still want to report
+ *     them for sniffing purposes.
  * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
  * @RX_FLAG_10MHZ: 10 MHz (half channel) was used
  * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
@@ -1033,6 +1062,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
 enum mac80211_rx_flags {
        RX_FLAG_MMIC_ERROR              = BIT(0),
        RX_FLAG_DECRYPTED               = BIT(1),
+       RX_FLAG_MACTIME_PLCP_START      = BIT(2),
        RX_FLAG_MMIC_STRIPPED           = BIT(3),
        RX_FLAG_IV_STRIPPED             = BIT(4),
        RX_FLAG_FAILED_FCS_CRC          = BIT(5),
@@ -1046,7 +1076,7 @@ enum mac80211_rx_flags {
        RX_FLAG_HT_GF                   = BIT(13),
        RX_FLAG_AMPDU_DETAILS           = BIT(14),
        RX_FLAG_PN_VALIDATED            = BIT(15),
-       /* bit 16 free */
+       RX_FLAG_DUP_VALIDATED           = BIT(16),
        RX_FLAG_AMPDU_LAST_KNOWN        = BIT(17),
        RX_FLAG_AMPDU_IS_LAST           = BIT(18),
        RX_FLAG_AMPDU_DELIM_CRC_ERROR   = BIT(19),
@@ -1054,6 +1084,8 @@ enum mac80211_rx_flags {
        RX_FLAG_MACTIME_END             = BIT(21),
        RX_FLAG_VHT                     = BIT(22),
        RX_FLAG_LDPC                    = BIT(23),
+       RX_FLAG_ONLY_MONITOR            = BIT(24),
+       RX_FLAG_SKIP_MONITOR            = BIT(25),
        RX_FLAG_STBC_MASK               = BIT(26) | BIT(27),
        RX_FLAG_10MHZ                   = BIT(28),
        RX_FLAG_5MHZ                    = BIT(29),
@@ -1072,6 +1104,7 @@ enum mac80211_rx_flags {
  * @RX_VHT_FLAG_160MHZ: 160 MHz was used
  * @RX_VHT_FLAG_BF: packet was beamformed
  */
+
 enum mac80211_rx_vht_flags {
        RX_VHT_FLAG_80MHZ               = BIT(0),
        RX_VHT_FLAG_160MHZ              = BIT(1),
@@ -1091,6 +1124,8 @@ enum mac80211_rx_vht_flags {
  *     it but can store it and pass it back to the driver for synchronisation
  * @band: the active band when this frame was received
  * @freq: frequency the radio was tuned to when receiving this frame, in MHz
+ *     This field must be set for management frames, but isn't strictly needed
+ *     for data (other) frames - for those it only affects radiotap reporting.
  * @signal: signal strength when receiving this frame, either in dBm, in dB or
  *     unspecified depending on the hardware capabilities flags
  *     @IEEE80211_HW_SIGNAL_*
@@ -1347,6 +1382,7 @@ enum ieee80211_vif_flags {
  * @csa_active: marks whether a channel switch is going on. Internally it is
  *     write-protected by sdata_lock and local->mtx so holding either is fine
  *     for read access.
+ * @mu_mimo_owner: indicates interface owns MU-MIMO capability
  * @driver_flags: flags/capabilities the driver has for this interface,
  *     these need to be set (or cleared) when the interface is added
  *     or, if supported by the driver, the interface type is changed
@@ -1373,6 +1409,7 @@ struct ieee80211_vif {
        u8 addr[ETH_ALEN];
        bool p2p;
        bool csa_active;
+       bool mu_mimo_owner;
 
        u8 cab_queue;
        u8 hw_queue[IEEE80211_NUM_ACS];
@@ -1486,9 +1523,8 @@ enum ieee80211_key_flags {
  *     wants to be given when a frame is transmitted and needs to be
  *     encrypted in hardware.
  * @cipher: The key's cipher suite selector.
- * @tx_pn: PN used for TX on non-TKIP keys, may be used by the driver
- *     as well if it needs to do software PN assignment by itself
- *     (e.g. due to TSO)
+ * @tx_pn: PN used for TX keys, may be used by the driver as well if it
+ *     needs to do software PN assignment by itself (e.g. due to TSO)
  * @flags: key flags, see &enum ieee80211_key_flags.
  * @keyidx: the key index (0-3)
  * @keylen: key material length
@@ -1514,6 +1550,9 @@ struct ieee80211_key_conf {
 
 #define IEEE80211_MAX_PN_LEN   16
 
+#define TKIP_PN_TO_IV16(pn) ((u16)(pn & 0xffff))
+#define TKIP_PN_TO_IV32(pn) ((u32)((pn >> 16) & 0xffffffff))
+
 /**
  * struct ieee80211_key_seq - key sequence counter
  *
@@ -1684,6 +1723,18 @@ struct ieee80211_sta_rates {
  * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
  *     valid if the STA is a TDLS peer in the first place.
  * @mfp: indicates whether the STA uses management frame protection or not.
+ * @max_amsdu_subframes: indicates the maximal number of MSDUs in a single
+ *     A-MSDU. Taken from the Extended Capabilities element. 0 means
+ *     unlimited.
+ * @max_amsdu_len: indicates the maximal length of an A-MSDU in bytes. This
+ *     field is always valid for packets with a VHT preamble. For packets
+ *     with a HT preamble, additional limits apply:
+ *             + If the skb is transmitted as part of a BA agreement, the
+ *               A-MSDU maximal size is min(max_amsdu_len, 4065) bytes.
+ *             + If the skb is not part of a BA aggreement, the A-MSDU maximal
+ *               size is min(max_amsdu_len, 7935) bytes.
+ *     Both additional HT limits must be enforced by the low level driver.
+ *     This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
  * @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
  */
 struct ieee80211_sta {
@@ -1702,6 +1753,8 @@ struct ieee80211_sta {
        bool tdls;
        bool tdls_initiator;
        bool mfp;
+       u8 max_amsdu_subframes;
+       u16 max_amsdu_len;
 
        struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
 
@@ -1910,6 +1963,11 @@ struct ieee80211_txq {
  *     by just its MAC address; this prevents, for example, the same station
  *     from connecting to two virtual AP interfaces at the same time.
  *
+ * @IEEE80211_HW_SUPPORTS_REORDERING_BUFFER: Hardware (or driver) manages the
+ *     reordering buffer internally, guaranteeing mac80211 receives frames in
+ *     order and does not need to manage its own reorder buffer or BA session
+ *     timeout.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -1946,6 +2004,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
        IEEE80211_HW_BEACON_TX_STATUS,
        IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
+       IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
 
        /* keep last, obviously */
        NUM_IEEE80211_HW_FLAGS
@@ -2167,7 +2226,7 @@ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev
  * @hw: the &struct ieee80211_hw to set the MAC address for
  * @addr: the address to set
  */
-static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, const u8 *addr)
 {
        memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
@@ -2683,6 +2742,33 @@ enum ieee80211_ampdu_mlme_action {
        IEEE80211_AMPDU_TX_OPERATIONAL,
 };
 
+/**
+ * struct ieee80211_ampdu_params - AMPDU action parameters
+ *
+ * @action: the ampdu action, value from %ieee80211_ampdu_mlme_action.
+ * @sta: peer of this AMPDU session
+ * @tid: tid of the BA session
+ * @ssn: start sequence number of the session. TX/RX_STOP can pass 0. When
+ *     action is set to %IEEE80211_AMPDU_RX_START the driver passes back the
+ *     actual ssn value used to start the session and writes the value here.
+ * @buf_size: reorder buffer size  (number of subframes). Valid only when the
+ *     action is set to %IEEE80211_AMPDU_RX_START or
+ *     %IEEE80211_AMPDU_TX_OPERATIONAL
+ * @amsdu: indicates the peer's ability to receive A-MSDU within A-MPDU.
+ *     valid when the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL
+ * @timeout: BA session timeout. Valid only when the action is set to
+ *     %IEEE80211_AMPDU_RX_START
+ */
+struct ieee80211_ampdu_params {
+       enum ieee80211_ampdu_mlme_action action;
+       struct ieee80211_sta *sta;
+       u16 tid;
+       u16 ssn;
+       u8 buf_size;
+       bool amsdu;
+       u16 timeout;
+};
+
 /**
  * enum ieee80211_frame_release_type - frame release reason
  * @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
@@ -3027,13 +3113,9 @@ enum ieee80211_reconfig_type {
  * @ampdu_action: Perform a certain A-MPDU action
  *     The RA/TID combination determines the destination and TID we want
  *     the ampdu action to be performed for. The action is defined through
- *     ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
- *     is the first frame we expect to perform the action on. Notice
- *     that TX/RX_STOP can pass NULL for this parameter.
- *     The @buf_size parameter is only valid when the action is set to
- *     %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder
- *     buffer size (number of subframes) for this session -- the driver
- *     may neither send aggregates containing more subframes than this
+ *     ieee80211_ampdu_mlme_action.
+ *     When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
+ *     may neither send aggregates containing more subframes than @buf_size
  *     nor send aggregates in a way that lost frames would exceed the
  *     buffer size. If just limiting the aggregate size, this would be
  *     possible with a buf_size of 8:
@@ -3044,9 +3126,6 @@ enum ieee80211_reconfig_type {
  *     buffer size of 8. Correct ways to retransmit #1 would be:
  *      - TX:       1 or 18 or 81
  *     Even "189" would be wrong since 1 could be lost again.
- *     The @amsdu parameter is valid when the action is set to
- *     %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
- *     to receive A-MSDU within A-MPDU.
  *
  *     Returns a negative error code on failure.
  *     The callback can sleep.
@@ -3388,9 +3467,7 @@ struct ieee80211_ops {
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
-                           enum ieee80211_ampdu_mlme_action action,
-                           struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                           u8 buf_size, bool amsdu);
+                           struct ieee80211_ampdu_params *params);
        int (*get_survey)(struct ieee80211_hw *hw, int idx,
                struct survey_info *survey);
        void (*rfkill_poll)(struct ieee80211_hw *hw);
@@ -4374,21 +4451,19 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
                            struct sk_buff *skb, u8 *p2k);
 
 /**
- * ieee80211_get_key_tx_seq - get key TX sequence counter
+ * ieee80211_tkip_add_iv - write TKIP IV and Ext. IV to pos
  *
+ * @pos: start of crypto header
  * @keyconf: the parameter passed with the set key
- * @seq: buffer to receive the sequence data
+ * @pn: PN to add
  *
- * This function allows a driver to retrieve the current TX IV/PN
- * for the given key. It must not be called if IV generation is
- * offloaded to the device.
+ * Returns: pointer to the octet following IVs (i.e. beginning of
+ * the packet payload)
  *
- * Note that this function may only be called when no TX processing
- * can be done concurrently, for example when queues are stopped
- * and the stop has been synchronized.
+ * This function writes the tkip IV value to pos (which should
+ * point to the crypto header)
  */
-void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
-                             struct ieee80211_key_seq *seq);
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn);
 
 /**
  * ieee80211_get_key_rx_seq - get key RX sequence counter
@@ -4409,23 +4484,6 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
 void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
                              int tid, struct ieee80211_key_seq *seq);
 
-/**
- * ieee80211_set_key_tx_seq - set key TX sequence counter
- *
- * @keyconf: the parameter passed with the set key
- * @seq: new sequence data
- *
- * This function allows a driver to set the current TX IV/PNs for the
- * given key. This is useful when resuming from WoWLAN sleep and the
- * device may have transmitted frames using the PTK, e.g. replies to
- * ARP requests.
- *
- * Note that this function may only be called when no TX processing
- * can be done concurrently.
- */
-void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
-                             struct ieee80211_key_seq *seq);
-
 /**
  * ieee80211_set_key_rx_seq - set key RX sequence counter
  *
@@ -5120,6 +5178,24 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
 void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
                                  const u8 *addr);
 
+/**
+ * ieee80211_mark_rx_ba_filtered_frames - move RX BA window and mark filtered
+ * @pubsta: station struct
+ * @tid: the session's TID
+ * @ssn: starting sequence number of the bitmap, all frames before this are
+ *     assumed to be out of the window after the call
+ * @filtered: bitmap of filtered frames, BIT(0) is the @ssn entry etc.
+ * @received_mpdus: number of received mpdus in firmware
+ *
+ * This function moves the BA window and releases all frames before @ssn, and
+ * marks frames marked in the bitmap as having been filtered. Afterwards, it
+ * checks if any frames in the window starting from @ssn can now be released
+ * (in case they were only waiting for frames that were filtered.)
+ */
+void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
+                                         u16 ssn, u64 filtered,
+                                         u16 received_mpdus);
+
 /**
  * ieee80211_send_bar - send a BlockAckReq frame
  *
@@ -5371,6 +5447,21 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
        return ieee80211_iftype_p2p(vif->type, vif->p2p);
 }
 
+/**
+ * ieee80211_update_mu_groups - set the VHT MU-MIMO groud data
+ *
+ * @vif: the specified virtual interface
+ * @membership: 64 bits array - a bit is set if station is member of the group
+ * @position: 2 bits per group id indicating the position in the group
+ *
+ * Note: This function assumes that the given vif is valid and the position and
+ * membership data is of the correct size and are in the same byte order as the
+ * matching GroupId management frame.
+ * Calls to this function need to be serialized with RX path.
+ */
+void ieee80211_update_mu_groups(struct ieee80211_vif *vif,
+                               const u8 *membership, const u8 *position);
+
 void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
                                   int rssi_min_thold,
                                   int rssi_max_thold);
@@ -5523,4 +5614,19 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid);
  */
 struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
                                     struct ieee80211_txq *txq);
+
+/**
+ * ieee80211_txq_get_depth - get pending frame/byte count of given txq
+ *
+ * The values are not guaranteed to be coherent with regard to each other, i.e.
+ * txq state can change half-way of this function and the caller may end up
+ * with "new" frame_cnt and "old" byte_cnt or vice-versa.
+ *
+ * @txq: pointer obtained from station or virtual interface
+ * @frame_cnt: pointer to store frame count
+ * @byte_cnt: pointer to store byte count
+ */
+void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
+                            unsigned long *frame_cnt,
+                            unsigned long *byte_cnt);
 #endif /* MAC80211_H */
index da574bbdc33393fc927ba7297f7d67d0cf59b06e..2e3cdd2048d2bee45e9d248459b80db5a7d8658e 100644 (file)
@@ -247,8 +247,9 @@ struct ieee802154_ops {
  */
 static inline __le16 ieee802154_get_fc_from_skb(const struct sk_buff *skb)
 {
-       /* return some invalid fc on failure */
-       if (unlikely(skb->len < 2)) {
+       /* check if we can fc at skb_mac_header of sk buffer */
+       if (unlikely(!skb_mac_header_was_set(skb) ||
+                    (skb_tail_pointer(skb) - skb_mac_header(skb)) < 2)) {
                WARN_ON(1);
                return cpu_to_le16(0);
        }
index e2a518b60e19039014e1298f3618046e9e030238..a3f3c11b2526efbaa88fb5857364a4e78618365e 100644 (file)
@@ -2,7 +2,9 @@
 #define _NFT_MASQ_H_
 
 struct nft_masq {
-       u32     flags;
+       u32                     flags;
+       enum nft_registers      sreg_proto_min:8;
+       enum nft_registers      sreg_proto_max:8;
 };
 
 extern const struct nla_policy nft_masq_policy[];
index 848fe80565343dfd864363afd910683e66595f92..a69cde3ce4608879ee3e4056d22ce512eb0c3ba5 100644 (file)
@@ -80,9 +80,13 @@ struct netns_ipv4 {
        int sysctl_tcp_ecn;
        int sysctl_tcp_ecn_fallback;
 
+       int sysctl_ip_default_ttl;
        int sysctl_ip_no_pmtu_disc;
        int sysctl_ip_fwd_use_pmtu;
        int sysctl_ip_nonlocal_bind;
+       /* Shall we try to damage output packets if routing dev changes? */
+       int sysctl_ip_dynaddr;
+       int sysctl_ip_early_demux;
 
        int sysctl_fwmark_reflect;
        int sysctl_tcp_fwmark_accept;
index c0368db6df54d78a1122c45aff412bcafa84b412..10d0848f5b8aa85b47803506f7a70c2dcd5c1364 100644 (file)
@@ -58,7 +58,10 @@ struct netns_ipv6 {
        struct timer_list       ip6_fib_timer;
        struct hlist_head       *fib_table_hash;
        struct fib6_table       *fib6_main_tbl;
+       struct list_head        fib6_walkers;
        struct dst_ops          ip6_dst_ops;
+       rwlock_t                fib6_walker_lock;
+       spinlock_t              fib6_gc_lock;
        unsigned int             ip6_rt_gc_expire;
        unsigned long            ip6_rt_last_gc;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
index bc49967e1a68b933f0a7cd5a66a9f9395f76be00..caa5e18636dfd830e59295ab74d80ffd95bf3f22 100644 (file)
@@ -358,4 +358,69 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
 }
 #endif /* CONFIG_NET_CLS_IND */
 
+struct tc_cls_u32_knode {
+       struct tcf_exts *exts;
+       struct tc_u32_sel *sel;
+       u32 handle;
+       u32 val;
+       u32 mask;
+       u32 link_handle;
+       u8 fshift;
+};
+
+struct tc_cls_u32_hnode {
+       u32 handle;
+       u32 prio;
+       unsigned int divisor;
+};
+
+enum tc_clsu32_command {
+       TC_CLSU32_NEW_KNODE,
+       TC_CLSU32_REPLACE_KNODE,
+       TC_CLSU32_DELETE_KNODE,
+       TC_CLSU32_NEW_HNODE,
+       TC_CLSU32_REPLACE_HNODE,
+       TC_CLSU32_DELETE_HNODE,
+};
+
+struct tc_cls_u32_offload {
+       /* knode values */
+       enum tc_clsu32_command command;
+       union {
+               struct tc_cls_u32_knode knode;
+               struct tc_cls_u32_hnode hnode;
+       };
+};
+
+/* tca flags definitions */
+#define TCA_CLS_FLAGS_SKIP_HW 1
+
+static inline bool tc_should_offload(struct net_device *dev, u32 flags)
+{
+       if (!(dev->features & NETIF_F_HW_TC))
+               return false;
+
+       if (flags & TCA_CLS_FLAGS_SKIP_HW)
+               return false;
+
+       if (!dev->netdev_ops->ndo_setup_tc)
+               return false;
+
+       return true;
+}
+
+enum tc_fl_command {
+       TC_CLSFLOWER_REPLACE,
+       TC_CLSFLOWER_DESTROY,
+};
+
+struct tc_cls_flower_offload {
+       enum tc_fl_command command;
+       unsigned long cookie;
+       struct flow_dissector *dissector;
+       struct fl_flow_key *mask;
+       struct fl_flow_key *key;
+       struct tcf_exts *exts;
+};
+
 #endif
index a3b9ef74a3895dbce95b0eba9b4bb298f7be9d71..9b0a523bb4280023e4429fcc5379cb5d2d2d419a 100644 (file)
@@ -329,14 +329,13 @@ static inline int inet_iif(const struct sk_buff *skb)
        return skb->skb_iif;
 }
 
-extern int sysctl_ip_default_ttl;
-
 static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
 {
        int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT);
+       struct net *net = dev_net(dst->dev);
 
        if (hoplimit == 0)
-               hoplimit = sysctl_ip_default_ttl;
+               hoplimit = net->ipv4.sysctl_ip_default_ttl;
        return hoplimit;
 }
 
index 636a362a0e03574f0564d2f0a7b7a5fecfc1e3bd..46e55f0202a61b9be253422b4c32cee4f9f6d911 100644 (file)
@@ -345,6 +345,12 @@ extern struct Qdisc_ops pfifo_fast_ops;
 extern struct Qdisc_ops mq_qdisc_ops;
 extern struct Qdisc_ops noqueue_qdisc_ops;
 extern const struct Qdisc_ops *default_qdisc_ops;
+static inline const struct Qdisc_ops *
+get_default_qdisc_ops(const struct net_device *dev, int ntx)
+{
+       return ntx < dev->real_num_tx_queues ?
+                       default_qdisc_ops : &pfifo_fast_ops;
+}
 
 struct Qdisc_class_common {
        u32                     classid;
@@ -396,7 +402,8 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
                              struct Qdisc *qdisc);
 void qdisc_reset(struct Qdisc *qdisc);
 void qdisc_destroy(struct Qdisc *qdisc);
-void qdisc_tree_decrease_qlen(struct Qdisc *qdisc, unsigned int n);
+void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n,
+                              unsigned int len);
 struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
                          const struct Qdisc_ops *ops);
 struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
@@ -707,6 +714,23 @@ static inline void qdisc_reset_queue(struct Qdisc *sch)
        sch->qstats.backlog = 0;
 }
 
+static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new,
+                                         struct Qdisc **pold)
+{
+       struct Qdisc *old;
+
+       sch_tree_lock(sch);
+       old = *pold;
+       *pold = new;
+       if (old != NULL) {
+               qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog);
+               qdisc_reset(old);
+       }
+       sch_tree_unlock(sch);
+
+       return old;
+}
+
 static inline unsigned int __qdisc_queue_drop(struct Qdisc *sch,
                                              struct sk_buff_head *list)
 {
index 262532d111f51e3a91a06af785b4721e8fab9d56..59fa93c01d2a16a129298498f1d56556b895acd9 100644 (file)
@@ -21,6 +21,7 @@ struct scm_creds {
 struct scm_fp_list {
        short                   count;
        short                   max;
+       struct user_struct      *user;
        struct file             *fp[SCM_MAX_FD];
 };
 
index 487ef34bbd63ff1cfe511c7ee8b1501593a14de3..efc01743b9d641bf6b16a37780ee0df34b4ec698 100644 (file)
@@ -201,7 +201,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
 struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
                                        const struct sctp_sndrcvinfo *sinfo,
                                        int len, const __u8 flags,
-                                       __u16 ssn);
+                                       __u16 ssn, gfp_t gfp);
 struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
                                  const __u32);
 struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
index 205630bb5010b8ac76b84651b302e488fc1c76ff..9d237669c52c1b673093edbad06afbf34ea8ff44 100644 (file)
@@ -535,7 +535,6 @@ struct sctp_datamsg {
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
                                            struct sctp_sndrcvinfo *,
                                            struct iov_iter *);
-void sctp_datamsg_free(struct sctp_datamsg *);
 void sctp_datamsg_put(struct sctp_datamsg *);
 void sctp_chunk_fail(struct sctp_chunk *, int error);
 int sctp_chunk_abandoned(struct sctp_chunk *);
@@ -656,7 +655,7 @@ void sctp_chunk_free(struct sctp_chunk *);
 void  *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
 struct sctp_chunk *sctp_chunkify(struct sk_buff *,
                                 const struct sctp_association *,
-                                struct sock *);
+                                struct sock *, gfp_t gfp);
 void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *,
                     union sctp_addr *);
 const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
@@ -718,10 +717,10 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *,
                                     __u16 sport, __u16 dport);
 struct sctp_packet *sctp_packet_config(struct sctp_packet *, __u32 vtag, int);
 sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *,
-                                       struct sctp_chunk *, int);
+                                      struct sctp_chunk *, int, gfp_t);
 sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *,
                                      struct sctp_chunk *);
-int sctp_packet_transmit(struct sctp_packet *);
+int sctp_packet_transmit(struct sctp_packet *, gfp_t);
 void sctp_packet_free(struct sctp_packet *);
 
 static inline int sctp_packet_empty(struct sctp_packet *packet)
@@ -1054,7 +1053,7 @@ struct sctp_outq {
 void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
 void sctp_outq_teardown(struct sctp_outq *);
 void sctp_outq_free(struct sctp_outq*);
-int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk);
+int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk, gfp_t);
 int sctp_outq_sack(struct sctp_outq *, struct sctp_chunk *);
 int sctp_outq_is_empty(const struct sctp_outq *);
 void sctp_outq_restart(struct sctp_outq *);
@@ -1062,7 +1061,7 @@ void sctp_outq_restart(struct sctp_outq *);
 void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
                     sctp_retransmit_reason_t);
 void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
-int sctp_outq_uncork(struct sctp_outq *);
+int sctp_outq_uncork(struct sctp_outq *, gfp_t gfp);
 /* Uncork and flush an outqueue.  */
 static inline void sctp_outq_cork(struct sctp_outq *q)
 {
index 592a6bc02b0b535087e9f2afee844b5ea37c666b..93c520b83d10994236c09be729dcd55dcff6dc2b 100644 (file)
@@ -2,6 +2,7 @@
 #define __NET_TC_GACT_H
 
 #include <net/act_api.h>
+#include <linux/tc_act/tc_gact.h>
 
 struct tcf_gact {
        struct tcf_common       common;
@@ -15,4 +16,19 @@ struct tcf_gact {
 #define to_gact(a) \
        container_of(a->priv, struct tcf_gact, common)
 
+static inline bool is_tcf_gact_shot(const struct tc_action *a)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       struct tcf_gact *gact;
+
+       if (a->ops && a->ops->type != TCA_ACT_GACT)
+               return false;
+
+       gact = a->priv;
+       if (gact->tcf_action == TC_ACT_SHOT)
+               return true;
+
+#endif
+       return false;
+}
 #endif /* __NET_TC_GACT_H */
diff --git a/include/net/tc_act/tc_ife.h b/include/net/tc_act/tc_ife.h
new file mode 100644 (file)
index 0000000..dc9a09a
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef __NET_TC_IFE_H
+#define __NET_TC_IFE_H
+
+#include <net/act_api.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+
+#define IFE_METAHDRLEN 2
+struct tcf_ife_info {
+       struct tcf_common common;
+       u8 eth_dst[ETH_ALEN];
+       u8 eth_src[ETH_ALEN];
+       u16 eth_type;
+       u16 flags;
+       /* list of metaids allowed */
+       struct list_head metalist;
+};
+#define to_ife(a) \
+       container_of(a->priv, struct tcf_ife_info, common)
+
+struct tcf_meta_info {
+       const struct tcf_meta_ops *ops;
+       void *metaval;
+       u16 metaid;
+       struct list_head metalist;
+};
+
+struct tcf_meta_ops {
+       u16 metaid; /*Maintainer provided ID */
+       u16 metatype; /*netlink attribute type (look at net/netlink.h) */
+       const char *name;
+       const char *synopsis;
+       struct list_head list;
+       int     (*check_presence)(struct sk_buff *, struct tcf_meta_info *);
+       int     (*encode)(struct sk_buff *, void *, struct tcf_meta_info *);
+       int     (*decode)(struct sk_buff *, void *, u16 len);
+       int     (*get)(struct sk_buff *skb, struct tcf_meta_info *mi);
+       int     (*alloc)(struct tcf_meta_info *, void *);
+       void    (*release)(struct tcf_meta_info *);
+       int     (*validate)(void *val, int len);
+       struct module   *owner;
+};
+
+#define MODULE_ALIAS_IFE_META(metan)   MODULE_ALIAS("ifemeta" __stringify_1(metan))
+
+int ife_get_meta_u32(struct sk_buff *skb, struct tcf_meta_info *mi);
+int ife_get_meta_u16(struct sk_buff *skb, struct tcf_meta_info *mi);
+int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen,
+                       const void *dval);
+int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval);
+int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval);
+int ife_check_meta_u32(u32 metaval, struct tcf_meta_info *mi);
+int ife_encode_meta_u32(u32 metaval, void *skbdata, struct tcf_meta_info *mi);
+int ife_validate_meta_u32(void *val, int len);
+int ife_validate_meta_u16(void *val, int len);
+void ife_release_meta_gen(struct tcf_meta_info *mi);
+int register_ife_op(struct tcf_meta_ops *mops);
+int unregister_ife_op(struct tcf_meta_ops *mops);
+
+#endif /* __NET_TC_IFE_H */
index 0df9a0db4a8e4ac300fcbafdd505f05ffd320782..b496d5ad7d4256761262a2b7fc31ae67b326d6e3 100644 (file)
@@ -20,6 +20,7 @@
 #define __NET_TC_SKBEDIT_H
 
 #include <net/act_api.h>
+#include <linux/tc_act/tc_skbedit.h>
 
 struct tcf_skbedit {
        struct tcf_common       common;
@@ -32,4 +33,19 @@ struct tcf_skbedit {
 #define to_skbedit(a) \
        container_of(a->priv, struct tcf_skbedit, common)
 
+/* Return true iff action is mark */
+static inline bool is_tcf_skbedit_mark(const struct tc_action *a)
+{
+#ifdef CONFIG_NET_CLS_ACT
+       if (a->ops && a->ops->type == TCA_ACT_SKBEDIT)
+               return to_skbedit(a)->flags == SKBEDIT_F_MARK;
+#endif
+       return false;
+}
+
+static inline u32 tcf_skbedit_mark(const struct tc_action *a)
+{
+       return to_skbedit(a)->mark;
+}
+
 #endif /* __NET_TC_SKBEDIT_H */
index 9b2cb0c8d876d96e857d76f6c49956289faa97e1..0302636af98c40869b4703891c128ff87c196416 100644 (file)
@@ -439,7 +439,7 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
 
 void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);
 void tcp_v4_mtu_reduced(struct sock *sk);
-void tcp_req_err(struct sock *sk, u32 seq);
+void tcp_req_err(struct sock *sk, u32 seq, bool abort);
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 struct sock *tcp_create_openreq_child(const struct sock *sk,
                                      struct request_sock *req,
@@ -1816,4 +1816,28 @@ static inline void skb_set_tcp_pure_ack(struct sk_buff *skb)
        skb->truesize = 2;
 }
 
+static inline int tcp_inq(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       int answ;
+
+       if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
+               answ = 0;
+       } else if (sock_flag(sk, SOCK_URGINLINE) ||
+                  !tp->urg_data ||
+                  before(tp->urg_seq, tp->copied_seq) ||
+                  !before(tp->urg_seq, tp->rcv_nxt)) {
+
+               answ = tp->rcv_nxt - tp->copied_seq;
+
+               /* Subtract 1, if FIN was received */
+               if (answ && sock_flag(sk, SOCK_DONE))
+                       answ--;
+       } else {
+               answ = tp->urg_seq - tp->copied_seq;
+       }
+
+       return answ;
+}
+
 #endif /* _TCP_H */
index 97f5adb121a6450fc70d77942d90bee7beb29e5a..b83114077cee33d184a2bef45da1be686f94a72f 100644 (file)
@@ -88,8 +88,8 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
                         struct sk_buff *skb,
                         struct net_device *dev, struct in6_addr *saddr,
                         struct in6_addr *daddr,
-                        __u8 prio, __u8 ttl, __be16 src_port,
-                        __be16 dst_port, bool nocheck);
+                        __u8 prio, __u8 ttl, __be32 label,
+                        __be16 src_port, __be16 dst_port, bool nocheck);
 #endif
 
 void udp_tunnel_sock_release(struct socket *sock);
index 25bd919c9ef0c9fcd91e62884781113d6b7c2d30..a763c96ecde403bd4cc8ddd9f6136685c281be2c 100644 (file)
@@ -24,11 +24,11 @@ struct vxlanhdr {
 };
 
 /* VXLAN header flags. */
-#define VXLAN_HF_VNI BIT(27)
+#define VXLAN_HF_VNI   cpu_to_be32(BIT(27))
 
 #define VXLAN_N_VID     (1u << 24)
 #define VXLAN_VID_MASK  (VXLAN_N_VID - 1)
-#define VXLAN_VNI_MASK  (VXLAN_VID_MASK << 8)
+#define VXLAN_VNI_MASK cpu_to_be32(VXLAN_VID_MASK << 8)
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
 #define VNI_HASH_BITS  10
@@ -55,14 +55,14 @@ struct vxlanhdr {
  */
 
 /* VXLAN-RCO header flags. */
-#define VXLAN_HF_RCO BIT(21)
+#define VXLAN_HF_RCO   cpu_to_be32(BIT(21))
 
 /* Remote checksum offload header option */
-#define VXLAN_RCO_MASK  0x7f    /* Last byte of vni field */
-#define VXLAN_RCO_UDP   0x80    /* Indicate UDP RCO (TCP when not set *) */
-#define VXLAN_RCO_SHIFT 1       /* Left shift of start */
+#define VXLAN_RCO_MASK cpu_to_be32(0x7f)  /* Last byte of vni field */
+#define VXLAN_RCO_UDP  cpu_to_be32(0x80)  /* Indicate UDP RCO (TCP when not set *) */
+#define VXLAN_RCO_SHIFT        1                  /* Left shift of start */
 #define VXLAN_RCO_SHIFT_MASK ((1 << VXLAN_RCO_SHIFT) - 1)
-#define VXLAN_MAX_REMCSUM_START (VXLAN_RCO_MASK << VXLAN_RCO_SHIFT)
+#define VXLAN_MAX_REMCSUM_START (0x7f << VXLAN_RCO_SHIFT)
 
 /*
  * VXLAN Group Based Policy Extension (VXLAN_F_GBP):
@@ -105,9 +105,9 @@ struct vxlanhdr_gbp {
 };
 
 /* VXLAN-GBP header flags. */
-#define VXLAN_HF_GBP BIT(31)
+#define VXLAN_HF_GBP   cpu_to_be32(BIT(31))
 
-#define VXLAN_GBP_USED_BITS (VXLAN_HF_GBP | 0xFFFFFF)
+#define VXLAN_GBP_USED_BITS (VXLAN_HF_GBP | cpu_to_be32(0xFFFFFF))
 
 /* skb->mark mapping
  *
@@ -144,16 +144,17 @@ union vxlan_addr {
 struct vxlan_rdst {
        union vxlan_addr         remote_ip;
        __be16                   remote_port;
-       u32                      remote_vni;
+       __be32                   remote_vni;
        u32                      remote_ifindex;
        struct list_head         list;
        struct rcu_head          rcu;
+       struct dst_cache         dst_cache;
 };
 
 struct vxlan_config {
        union vxlan_addr        remote_ip;
        union vxlan_addr        saddr;
-       u32                     vni;
+       __be32                  vni;
        int                     remote_ifindex;
        int                     mtu;
        __be16                  dst_port;
@@ -161,6 +162,7 @@ struct vxlan_config {
        u16                     port_max;
        u8                      tos;
        u8                      ttl;
+       __be32                  label;
        u32                     flags;
        unsigned long           age_interval;
        unsigned int            addrmax;
@@ -196,7 +198,7 @@ struct vxlan_dev {
 #define VXLAN_F_L2MISS                 0x08
 #define VXLAN_F_L3MISS                 0x10
 #define VXLAN_F_IPV6                   0x20
-#define VXLAN_F_UDP_CSUM               0x40
+#define VXLAN_F_UDP_ZERO_CSUM_TX       0x40
 #define VXLAN_F_UDP_ZERO_CSUM6_TX      0x80
 #define VXLAN_F_UDP_ZERO_CSUM6_RX      0x100
 #define VXLAN_F_REMCSUM_TX             0x200
@@ -261,6 +263,68 @@ static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
 /* IPv6 header + UDP + VXLAN + Ethernet header */
 #define VXLAN6_HEADROOM (40 + 8 + 8 + 14)
 
+static inline struct vxlanhdr *vxlan_hdr(struct sk_buff *skb)
+{
+       return (struct vxlanhdr *)(udp_hdr(skb) + 1);
+}
+
+static inline __be32 vxlan_vni(__be32 vni_field)
+{
+#if defined(__BIG_ENDIAN)
+       return vni_field >> 8;
+#else
+       return (vni_field & VXLAN_VNI_MASK) << 8;
+#endif
+}
+
+static inline __be32 vxlan_vni_field(__be32 vni)
+{
+#if defined(__BIG_ENDIAN)
+       return vni << 8;
+#else
+       return vni >> 8;
+#endif
+}
+
+static inline __be32 vxlan_tun_id_to_vni(__be64 tun_id)
+{
+#if defined(__BIG_ENDIAN)
+       return tun_id;
+#else
+       return tun_id >> 32;
+#endif
+}
+
+static inline __be64 vxlan_vni_to_tun_id(__be32 vni)
+{
+#if defined(__BIG_ENDIAN)
+       return (__be64)vni;
+#else
+       return (__be64)vni << 32;
+#endif
+}
+
+static inline size_t vxlan_rco_start(__be32 vni_field)
+{
+       return be32_to_cpu(vni_field & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
+}
+
+static inline size_t vxlan_rco_offset(__be32 vni_field)
+{
+       return (vni_field & VXLAN_RCO_UDP) ?
+               offsetof(struct udphdr, check) :
+               offsetof(struct tcphdr, check);
+}
+
+static inline __be32 vxlan_compute_rco(unsigned int start, unsigned int offset)
+{
+       __be32 vni_field = cpu_to_be32(start >> VXLAN_RCO_SHIFT);
+
+       if (offset == offsetof(struct udphdr, check))
+               vni_field |= VXLAN_RCO_UDP;
+       return vni_field;
+}
+
 #if IS_ENABLED(CONFIG_VXLAN)
 void vxlan_get_rx_port(struct net_device *netdev);
 #else
index c34c9002460c567a8e7e3e8cd9cb6acb751c97d8..931a47ba45718ad5c329b1085c7fac5319e7448f 100644 (file)
@@ -262,24 +262,22 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
 
 static inline int iboe_get_rate(struct net_device *dev)
 {
-       struct ethtool_cmd cmd;
-       u32 speed;
+       struct ethtool_link_ksettings cmd;
        int err;
 
        rtnl_lock();
-       err = __ethtool_get_settings(dev, &cmd);
+       err = __ethtool_get_link_ksettings(dev, &cmd);
        rtnl_unlock();
        if (err)
                return IB_RATE_PORT_CURRENT;
 
-       speed = ethtool_cmd_speed(&cmd);
-       if (speed >= 40000)
+       if (cmd.base.speed >= 40000)
                return IB_RATE_40_GBPS;
-       else if (speed >= 30000)
+       else if (cmd.base.speed >= 30000)
                return IB_RATE_30_GBPS;
-       else if (speed >= 20000)
+       else if (cmd.base.speed >= 20000)
                return IB_RATE_20_GBPS;
-       else if (speed >= 10000)
+       else if (cmd.base.speed >= 10000)
                return IB_RATE_10_GBPS;
        else
                return IB_RATE_PORT_CURRENT;
index 4dce116bfd80c81ab09aec171817e082723ad74e..9ebab3a8cf0aa2f566fda02a9b3e4e42561ca42c 100644 (file)
@@ -22,7 +22,7 @@ typedef __be32        rxrpc_serial_net_t; /* on-the-wire Rx message serial number */
  * on-the-wire Rx packet header
  * - all multibyte fields should be in network byte order
  */
-struct rxrpc_header {
+struct rxrpc_wire_header {
        __be32          epoch;          /* client boot timestamp */
 
        __be32          cid;            /* connection and channel ID */
@@ -68,10 +68,19 @@ struct rxrpc_header {
 
 } __packed;
 
-#define __rxrpc_header_off(X) offsetof(struct rxrpc_header,X)
-
 extern const char *rxrpc_pkts[];
 
+#define RXRPC_SUPPORTED_PACKET_TYPES (                 \
+               (1 << RXRPC_PACKET_TYPE_DATA) |         \
+               (1 << RXRPC_PACKET_TYPE_ACK) |          \
+               (1 << RXRPC_PACKET_TYPE_BUSY) |         \
+               (1 << RXRPC_PACKET_TYPE_ABORT) |        \
+               (1 << RXRPC_PACKET_TYPE_ACKALL) |       \
+               (1 << RXRPC_PACKET_TYPE_CHALLENGE) |    \
+               (1 << RXRPC_PACKET_TYPE_RESPONSE) |     \
+               /*(1 << RXRPC_PACKET_TYPE_DEBUG) | */   \
+               (1 << RXRPC_PACKET_TYPE_VERSION))
+
 /*****************************************************************************/
 /*
  * jumbo packet secondary header
index e2b712c90d3f22d4bcbb75ded3a296304d23d7c6..c21c38ce74501dbdac327e9cac8b0b6d051a42b0 100644 (file)
@@ -343,7 +343,7 @@ void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus);
 void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus);
 
 void snd_hdac_bus_update_rirb(struct hdac_bus *bus);
-void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
+int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
                                    void (*ack)(struct hdac_bus *,
                                                struct hdac_stream *));
 
index fdabbb4ddba92f801e2952fafaeb997c7fa03a33..f730b91e472f19f97b15ec8982443fe099dd5db4 100644 (file)
@@ -167,6 +167,10 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
 int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count);
+int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+                             unsigned char *buffer, int count);
+int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
+                              int count);
 
 /* main midi functions */
 
index 56cf8e485ef22101ac22b1120704664bf599eaef..28ee5c2e6bcd7b08abeda34669cc2da17f4dcf9a 100644 (file)
@@ -94,5 +94,8 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd,
        sense_reason_t (*exec_cmd)(struct se_cmd *cmd));
 
 bool target_sense_desc_format(struct se_device *dev);
+sector_t target_to_linux_sector(struct se_device *dev, sector_t lb);
+bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib,
+                                      struct request_queue *q, int block_size);
 
 #endif /* TARGET_CORE_BACKEND_H */
index 5d82816cc4e3dbb34068748d95dd86b3bbb5a537..e8c8c08bf575f4de6436d8c090b15f77b6717f2a 100644 (file)
@@ -140,6 +140,8 @@ enum se_cmd_flags_table {
        SCF_COMPARE_AND_WRITE           = 0x00080000,
        SCF_COMPARE_AND_WRITE_POST      = 0x00100000,
        SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000,
+       SCF_ACK_KREF                    = 0x00400000,
+       SCF_USE_CPUID                   = 0x00800000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -187,6 +189,7 @@ enum target_sc_flags_table {
        TARGET_SCF_BIDI_OP              = 0x01,
        TARGET_SCF_ACK_KREF             = 0x02,
        TARGET_SCF_UNKNOWN_SIZE         = 0x04,
+       TARGET_SCF_USE_CPUID    = 0x08,
 };
 
 /* fabric independent task management function values */
@@ -490,8 +493,9 @@ struct se_cmd {
 #define CMD_T_SENT             (1 << 4)
 #define CMD_T_STOP             (1 << 5)
 #define CMD_T_DEV_ACTIVE       (1 << 7)
-#define CMD_T_REQUEST_STOP     (1 << 8)
 #define CMD_T_BUSY             (1 << 9)
+#define CMD_T_TAS              (1 << 10)
+#define CMD_T_FABRIC_STOP      (1 << 11)
        spinlock_t              t_state_lock;
        struct kref             cmd_kref;
        struct completion       t_transport_stop_comp;
@@ -511,9 +515,6 @@ struct se_cmd {
 
        struct list_head        state_list;
 
-       /* old task stop completion, consider merging with some of the above */
-       struct completion       task_stop_comp;
-
        /* backend private data */
        void                    *priv;
 
index fb8a416683828ee23042e4bc397583f95b2cc6c9..67d632f1743ddd9ce351962fd7326f7320743efc 100644 (file)
@@ -90,4 +90,6 @@
 #define SO_ATTACH_REUSEPORT_CBPF       51
 #define SO_ATTACH_REUSEPORT_EBPF       52
 
+#define SO_CNX_ADVICE          53
+
 #endif /* __ASM_GENERIC_SOCKET_H */
index ebd10e6245984fb5c38b6ee13c3861b8e78ed040..e25ebcfbcb48b8422a00d34ec783a698b3488efe 100644 (file)
@@ -173,6 +173,7 @@ header-y += if_hippi.h
 header-y += if_infiniband.h
 header-y += if_link.h
 header-y += if_ltalk.h
+header-y += if_macsec.h
 header-y += if_packet.h
 header-y += if_phonet.h
 header-y += if_plip.h
index 2ee0fde1bf9649739e8663dc480742fdf0ede72f..924f537183fd2f368f4b557df7158537f8416a3b 100644 (file)
@@ -83,6 +83,7 @@ enum bpf_map_type {
        BPF_MAP_TYPE_PERF_EVENT_ARRAY,
        BPF_MAP_TYPE_PERCPU_HASH,
        BPF_MAP_TYPE_PERCPU_ARRAY,
+       BPF_MAP_TYPE_STACK_TRACE,
 };
 
 enum bpf_prog_type {
@@ -100,12 +101,15 @@ enum bpf_prog_type {
 #define BPF_NOEXIST    1 /* create new element if it didn't exist */
 #define BPF_EXIST      2 /* update existing element */
 
+#define BPF_F_NO_PREALLOC      (1U << 0)
+
 union bpf_attr {
        struct { /* anonymous struct used by BPF_MAP_CREATE command */
                __u32   map_type;       /* one of enum bpf_map_type */
                __u32   key_size;       /* size of key in bytes */
                __u32   value_size;     /* size of value in bytes */
                __u32   max_entries;    /* max number of entries in a map */
+               __u32   map_flags;      /* prealloc or not */
        };
 
        struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@@ -272,6 +276,42 @@ enum bpf_func_id {
         */
        BPF_FUNC_perf_event_output,
        BPF_FUNC_skb_load_bytes,
+
+       /**
+        * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id
+        * @ctx: struct pt_regs*
+        * @map: pointer to stack_trace map
+        * @flags: bits 0-7 - numer of stack frames to skip
+        *         bit 8 - collect user stack instead of kernel
+        *         bit 9 - compare stacks by hash only
+        *         bit 10 - if two different stacks hash into the same stackid
+        *                  discard old
+        *         other bits - reserved
+        * Return: >= 0 stackid on success or negative error
+        */
+       BPF_FUNC_get_stackid,
+
+       /**
+        * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff
+        * @from: raw from buffer
+        * @from_size: length of from buffer
+        * @to: raw to buffer
+        * @to_size: length of to buffer
+        * @seed: optional seed
+        * Return: csum result
+        */
+       BPF_FUNC_csum_diff,
+
+       /**
+        * bpf_skb_[gs]et_tunnel_opt(skb, opt, size)
+        * retrieve or populate tunnel options metadata
+        * @skb: pointer to skb
+        * @opt: pointer to raw tunnel option data
+        * @size: size of @opt
+        * Return: 0 on success for set, option size for get
+        */
+       BPF_FUNC_skb_get_tunnel_opt,
+       BPF_FUNC_skb_set_tunnel_opt,
        __BPF_FUNC_MAX_ID,
 };
 
@@ -279,6 +319,7 @@ enum bpf_func_id {
 
 /* BPF_FUNC_skb_store_bytes flags. */
 #define BPF_F_RECOMPUTE_CSUM           (1ULL << 0)
+#define BPF_F_INVALIDATE_HASH          (1ULL << 1)
 
 /* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags.
  * First 4 bits are for passing the header field size.
@@ -287,6 +328,7 @@ enum bpf_func_id {
 
 /* BPF_FUNC_l4_csum_replace flags. */
 #define BPF_F_PSEUDO_HDR               (1ULL << 4)
+#define BPF_F_MARK_MANGLED_0           (1ULL << 5)
 
 /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
 #define BPF_F_INGRESS                  (1ULL << 0)
@@ -294,6 +336,16 @@ enum bpf_func_id {
 /* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
 #define BPF_F_TUNINFO_IPV6             (1ULL << 0)
 
+/* BPF_FUNC_get_stackid flags. */
+#define BPF_F_SKIP_FIELD_MASK          0xffULL
+#define BPF_F_USER_STACK               (1ULL << 8)
+#define BPF_F_FAST_STACK_CMP           (1ULL << 9)
+#define BPF_F_REUSE_STACKID            (1ULL << 10)
+
+/* BPF_FUNC_skb_set_tunnel_key flags. */
+#define BPF_F_ZERO_CSUM_TX             (1ULL << 1)
+#define BPF_F_DONT_FRAGMENT            (1ULL << 2)
+
 /* user accessible mirror of in-kernel sk_buff.
  * new fields can only be added to the end of this structure
  */
@@ -323,6 +375,7 @@ struct bpf_tunnel_key {
        };
        __u8 tunnel_tos;
        __u8 tunnel_ttl;
+       __u32 tunnel_label;
 };
 
 #endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
new file mode 100644 (file)
index 0000000..c9fee57
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * include/uapi/linux/devlink.h - Network physical device Netlink interface
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_DEVLINK_H_
+#define _UAPI_LINUX_DEVLINK_H_
+
+#define DEVLINK_GENL_NAME "devlink"
+#define DEVLINK_GENL_VERSION 0x1
+#define DEVLINK_GENL_MCGRP_CONFIG_NAME "config"
+
+enum devlink_command {
+       /* don't change the order or add anything between, this is ABI! */
+       DEVLINK_CMD_UNSPEC,
+
+       DEVLINK_CMD_GET,                /* can dump */
+       DEVLINK_CMD_SET,
+       DEVLINK_CMD_NEW,
+       DEVLINK_CMD_DEL,
+
+       DEVLINK_CMD_PORT_GET,           /* can dump */
+       DEVLINK_CMD_PORT_SET,
+       DEVLINK_CMD_PORT_NEW,
+       DEVLINK_CMD_PORT_DEL,
+
+       DEVLINK_CMD_PORT_SPLIT,
+       DEVLINK_CMD_PORT_UNSPLIT,
+
+       /* add new commands above here */
+
+       __DEVLINK_CMD_MAX,
+       DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
+};
+
+enum devlink_port_type {
+       DEVLINK_PORT_TYPE_NOTSET,
+       DEVLINK_PORT_TYPE_AUTO,
+       DEVLINK_PORT_TYPE_ETH,
+       DEVLINK_PORT_TYPE_IB,
+};
+
+enum devlink_attr {
+       /* don't change the order or add anything between, this is ABI! */
+       DEVLINK_ATTR_UNSPEC,
+
+       /* bus name + dev name together are a handle for devlink entity */
+       DEVLINK_ATTR_BUS_NAME,                  /* string */
+       DEVLINK_ATTR_DEV_NAME,                  /* string */
+
+       DEVLINK_ATTR_PORT_INDEX,                /* u32 */
+       DEVLINK_ATTR_PORT_TYPE,                 /* u16 */
+       DEVLINK_ATTR_PORT_DESIRED_TYPE,         /* u16 */
+       DEVLINK_ATTR_PORT_NETDEV_IFINDEX,       /* u32 */
+       DEVLINK_ATTR_PORT_NETDEV_NAME,          /* string */
+       DEVLINK_ATTR_PORT_IBDEV_NAME,           /* string */
+       DEVLINK_ATTR_PORT_SPLIT_COUNT,          /* u32 */
+       DEVLINK_ATTR_PORT_SPLIT_GROUP,          /* u32 */
+
+       /* add new attributes above here, update the policy in devlink.c */
+
+       __DEVLINK_ATTR_MAX,
+       DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1
+};
+
+#endif /* _UAPI_LINUX_DEVLINK_H_ */
index 190aea0faaf483952fae4e0be570297084fab93d..2835b07416b7b2e5d476c0f6139a7d71a52ab078 100644 (file)
 #ifndef _UAPI_LINUX_ETHTOOL_H
 #define _UAPI_LINUX_ETHTOOL_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
+#ifndef __KERNEL__
+#include <limits.h> /* for INT_MAX */
+#endif
+
 /* All structures exposed to userland should be defined such that they
  * have the same layout for 32-bit and 64-bit userland.
  */
 
 /**
- * struct ethtool_cmd - link control and status
+ * struct ethtool_cmd - DEPRECATED, link control and status
+ * This structure is DEPRECATED, please use struct ethtool_link_settings.
  * @cmd: Command number = %ETHTOOL_GSET or %ETHTOOL_SSET
  * @supported: Bitmask of %SUPPORTED_* flags for the link modes,
  *     physical connectors and other link features for which the
@@ -1202,10 +1208,29 @@ enum ethtool_sfeatures_retval_bits {
 #define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT)
 #define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT)
 
+#define MAX_NUM_QUEUE          4096
+
+/**
+ * struct ethtool_per_queue_op - apply sub command to the queues in mask.
+ * @cmd: ETHTOOL_PERQUEUE
+ * @sub_command: the sub command which apply to each queues
+ * @queue_mask: Bitmap of the queues which sub command apply to
+ * @data: A complete command structure following for each of the queues addressed
+ */
+struct ethtool_per_queue_op {
+       __u32   cmd;
+       __u32   sub_command;
+       __u32   queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)];
+       char    data[];
+};
 
 /* CMDs currently supported */
-#define ETHTOOL_GSET           0x00000001 /* Get settings. */
-#define ETHTOOL_SSET           0x00000002 /* Set settings. */
+#define ETHTOOL_GSET           0x00000001 /* DEPRECATED, Get settings.
+                                           * Please use ETHTOOL_GLINKSETTINGS
+                                           */
+#define ETHTOOL_SSET           0x00000002 /* DEPRECATED, Set settings.
+                                           * Please use ETHTOOL_SLINKSETTINGS
+                                           */
 #define ETHTOOL_GDRVINFO       0x00000003 /* Get driver info. */
 #define ETHTOOL_GREGS          0x00000004 /* Get NIC registers. */
 #define ETHTOOL_GWOL           0x00000005 /* Get wake-on-lan options. */
@@ -1285,73 +1310,141 @@ enum ethtool_sfeatures_retval_bits {
 #define ETHTOOL_STUNABLE       0x00000049 /* Set tunable configuration */
 #define ETHTOOL_GPHYSTATS      0x0000004a /* get PHY-specific statistics */
 
+#define ETHTOOL_PERQUEUE       0x0000004b /* Set per queue options */
+
+#define ETHTOOL_GLINKSETTINGS  0x0000004c /* Get ethtool_link_settings */
+#define ETHTOOL_SLINKSETTINGS  0x0000004d /* Set ethtool_link_settings */
+
+
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
 #define SPARC_ETH_SSET         ETHTOOL_SSET
 
-#define SUPPORTED_10baseT_Half         (1 << 0)
-#define SUPPORTED_10baseT_Full         (1 << 1)
-#define SUPPORTED_100baseT_Half                (1 << 2)
-#define SUPPORTED_100baseT_Full                (1 << 3)
-#define SUPPORTED_1000baseT_Half       (1 << 4)
-#define SUPPORTED_1000baseT_Full       (1 << 5)
-#define SUPPORTED_Autoneg              (1 << 6)
-#define SUPPORTED_TP                   (1 << 7)
-#define SUPPORTED_AUI                  (1 << 8)
-#define SUPPORTED_MII                  (1 << 9)
-#define SUPPORTED_FIBRE                        (1 << 10)
-#define SUPPORTED_BNC                  (1 << 11)
-#define SUPPORTED_10000baseT_Full      (1 << 12)
-#define SUPPORTED_Pause                        (1 << 13)
-#define SUPPORTED_Asym_Pause           (1 << 14)
-#define SUPPORTED_2500baseX_Full       (1 << 15)
-#define SUPPORTED_Backplane            (1 << 16)
-#define SUPPORTED_1000baseKX_Full      (1 << 17)
-#define SUPPORTED_10000baseKX4_Full    (1 << 18)
-#define SUPPORTED_10000baseKR_Full     (1 << 19)
-#define SUPPORTED_10000baseR_FEC       (1 << 20)
-#define SUPPORTED_20000baseMLD2_Full   (1 << 21)
-#define SUPPORTED_20000baseKR2_Full    (1 << 22)
-#define SUPPORTED_40000baseKR4_Full    (1 << 23)
-#define SUPPORTED_40000baseCR4_Full    (1 << 24)
-#define SUPPORTED_40000baseSR4_Full    (1 << 25)
-#define SUPPORTED_40000baseLR4_Full    (1 << 26)
-#define SUPPORTED_56000baseKR4_Full    (1 << 27)
-#define SUPPORTED_56000baseCR4_Full    (1 << 28)
-#define SUPPORTED_56000baseSR4_Full    (1 << 29)
-#define SUPPORTED_56000baseLR4_Full    (1 << 30)
-
-#define ADVERTISED_10baseT_Half                (1 << 0)
-#define ADVERTISED_10baseT_Full                (1 << 1)
-#define ADVERTISED_100baseT_Half       (1 << 2)
-#define ADVERTISED_100baseT_Full       (1 << 3)
-#define ADVERTISED_1000baseT_Half      (1 << 4)
-#define ADVERTISED_1000baseT_Full      (1 << 5)
-#define ADVERTISED_Autoneg             (1 << 6)
-#define ADVERTISED_TP                  (1 << 7)
-#define ADVERTISED_AUI                 (1 << 8)
-#define ADVERTISED_MII                 (1 << 9)
-#define ADVERTISED_FIBRE               (1 << 10)
-#define ADVERTISED_BNC                 (1 << 11)
-#define ADVERTISED_10000baseT_Full     (1 << 12)
-#define ADVERTISED_Pause               (1 << 13)
-#define ADVERTISED_Asym_Pause          (1 << 14)
-#define ADVERTISED_2500baseX_Full      (1 << 15)
-#define ADVERTISED_Backplane           (1 << 16)
-#define ADVERTISED_1000baseKX_Full     (1 << 17)
-#define ADVERTISED_10000baseKX4_Full   (1 << 18)
-#define ADVERTISED_10000baseKR_Full    (1 << 19)
-#define ADVERTISED_10000baseR_FEC      (1 << 20)
-#define ADVERTISED_20000baseMLD2_Full  (1 << 21)
-#define ADVERTISED_20000baseKR2_Full   (1 << 22)
-#define ADVERTISED_40000baseKR4_Full   (1 << 23)
-#define ADVERTISED_40000baseCR4_Full   (1 << 24)
-#define ADVERTISED_40000baseSR4_Full   (1 << 25)
-#define ADVERTISED_40000baseLR4_Full   (1 << 26)
-#define ADVERTISED_56000baseKR4_Full   (1 << 27)
-#define ADVERTISED_56000baseCR4_Full   (1 << 28)
-#define ADVERTISED_56000baseSR4_Full   (1 << 29)
-#define ADVERTISED_56000baseLR4_Full   (1 << 30)
+/* Link mode bit indices */
+enum ethtool_link_mode_bit_indices {
+       ETHTOOL_LINK_MODE_10baseT_Half_BIT      = 0,
+       ETHTOOL_LINK_MODE_10baseT_Full_BIT      = 1,
+       ETHTOOL_LINK_MODE_100baseT_Half_BIT     = 2,
+       ETHTOOL_LINK_MODE_100baseT_Full_BIT     = 3,
+       ETHTOOL_LINK_MODE_1000baseT_Half_BIT    = 4,
+       ETHTOOL_LINK_MODE_1000baseT_Full_BIT    = 5,
+       ETHTOOL_LINK_MODE_Autoneg_BIT           = 6,
+       ETHTOOL_LINK_MODE_TP_BIT                = 7,
+       ETHTOOL_LINK_MODE_AUI_BIT               = 8,
+       ETHTOOL_LINK_MODE_MII_BIT               = 9,
+       ETHTOOL_LINK_MODE_FIBRE_BIT             = 10,
+       ETHTOOL_LINK_MODE_BNC_BIT               = 11,
+       ETHTOOL_LINK_MODE_10000baseT_Full_BIT   = 12,
+       ETHTOOL_LINK_MODE_Pause_BIT             = 13,
+       ETHTOOL_LINK_MODE_Asym_Pause_BIT        = 14,
+       ETHTOOL_LINK_MODE_2500baseX_Full_BIT    = 15,
+       ETHTOOL_LINK_MODE_Backplane_BIT         = 16,
+       ETHTOOL_LINK_MODE_1000baseKX_Full_BIT   = 17,
+       ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT = 18,
+       ETHTOOL_LINK_MODE_10000baseKR_Full_BIT  = 19,
+       ETHTOOL_LINK_MODE_10000baseR_FEC_BIT    = 20,
+       ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+       ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT = 22,
+       ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT = 23,
+       ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT = 24,
+       ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT = 25,
+       ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT = 26,
+       ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT = 27,
+       ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT = 28,
+       ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT = 29,
+       ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT = 30,
+
+       /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
+        * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
+        * macro for bits > 31. The only way to use indices > 31 is to
+        * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
+        */
+
+       __ETHTOOL_LINK_MODE_LAST
+         = ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
+};
+
+#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name)     \
+       (1UL << (ETHTOOL_LINK_MODE_ ## base_name ## _BIT))
+
+/* DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new SUPPORTED_* macro for bits > 31.
+ */
+#define SUPPORTED_10baseT_Half         __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define SUPPORTED_10baseT_Full         __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define SUPPORTED_100baseT_Half                __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define SUPPORTED_100baseT_Full                __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define SUPPORTED_1000baseT_Half       __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define SUPPORTED_1000baseT_Full       __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define SUPPORTED_Autoneg              __ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define SUPPORTED_TP                   __ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define SUPPORTED_AUI                  __ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define SUPPORTED_MII                  __ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define SUPPORTED_FIBRE                        __ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define SUPPORTED_BNC                  __ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define SUPPORTED_10000baseT_Full      __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define SUPPORTED_Pause                        __ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define SUPPORTED_Asym_Pause           __ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define SUPPORTED_2500baseX_Full       __ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define SUPPORTED_Backplane            __ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define SUPPORTED_1000baseKX_Full      __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define SUPPORTED_10000baseKX4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define SUPPORTED_10000baseKR_Full     __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define SUPPORTED_10000baseR_FEC       __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define SUPPORTED_20000baseMLD2_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define SUPPORTED_20000baseKR2_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define SUPPORTED_40000baseKR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define SUPPORTED_40000baseCR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define SUPPORTED_40000baseSR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define SUPPORTED_40000baseLR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define SUPPORTED_56000baseKR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define SUPPORTED_56000baseCR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define SUPPORTED_56000baseSR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define SUPPORTED_56000baseLR4_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new SUPPORTED_* macro for bits > 31, see
+ * notice above.
+ */
+
+/*
+ * DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new ADERTISE_* macro for bits > 31.
+ */
+#define ADVERTISED_10baseT_Half                __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define ADVERTISED_10baseT_Full                __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define ADVERTISED_100baseT_Half       __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define ADVERTISED_100baseT_Full       __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define ADVERTISED_1000baseT_Half      __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define ADVERTISED_1000baseT_Full      __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define ADVERTISED_Autoneg             __ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define ADVERTISED_TP                  __ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define ADVERTISED_AUI                 __ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define ADVERTISED_MII                 __ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define ADVERTISED_FIBRE               __ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define ADVERTISED_BNC                 __ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define ADVERTISED_10000baseT_Full     __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define ADVERTISED_Pause               __ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define ADVERTISED_Asym_Pause          __ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define ADVERTISED_2500baseX_Full      __ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define ADVERTISED_Backplane           __ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define ADVERTISED_1000baseKX_Full     __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define ADVERTISED_10000baseKX4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define ADVERTISED_10000baseKR_Full    __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define ADVERTISED_10000baseR_FEC      __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define ADVERTISED_20000baseMLD2_Full  __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define ADVERTISED_20000baseKR2_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define ADVERTISED_40000baseKR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define ADVERTISED_40000baseCR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define ADVERTISED_40000baseSR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define ADVERTISED_40000baseLR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define ADVERTISED_56000baseKR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define ADVERTISED_56000baseCR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define ADVERTISED_56000baseSR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define ADVERTISED_56000baseLR4_Full   __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new ADVERTISED_* macro for bits > 31, see
+ * notice above.
+ */
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
@@ -1516,4 +1609,123 @@ enum ethtool_reset_flags {
 };
 #define ETH_RESET_SHARED_SHIFT 16
 
+
+/**
+ * struct ethtool_link_settings - link control and status
+ *
+ * IMPORTANT, Backward compatibility notice: When implementing new
+ *     user-space tools, please first try %ETHTOOL_GLINKSETTINGS, and
+ *     if it succeeds use %ETHTOOL_SLINKSETTINGS to change link
+ *     settings; do not use %ETHTOOL_SSET if %ETHTOOL_GLINKSETTINGS
+ *     succeeded: stick to %ETHTOOL_GLINKSETTINGS/%SLINKSETTINGS in
+ *     that case.  Conversely, if %ETHTOOL_GLINKSETTINGS fails, use
+ *     %ETHTOOL_GSET to query and %ETHTOOL_SSET to change link
+ *     settings; do not use %ETHTOOL_SLINKSETTINGS if
+ *     %ETHTOOL_GLINKSETTINGS failed: stick to
+ *     %ETHTOOL_GSET/%ETHTOOL_SSET in that case.
+ *
+ * @cmd: Command number = %ETHTOOL_GLINKSETTINGS or %ETHTOOL_SLINKSETTINGS
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not
+ *     applicable.  For clause 45 PHYs this is the PRTAD.
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *     either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO
+ *     protocols supported by the interface; 0 if unknown.
+ *     Read-only.
+ * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of
+ *     %ETH_TP_MDI_*.  If the status is unknown or not applicable, the
+ *     value will be %ETH_TP_MDI_INVALID.  Read-only.
+ * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of
+ *     %ETH_TP_MDI_*.  If MDI(-X) control is not implemented, reads
+ *     yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected.
+ *     When written successfully, the link should be renegotiated if
+ *     necessary.
+ * @link_mode_masks_nwords: Number of 32-bit words for each of the
+ *     supported, advertising, lp_advertising link mode bitmaps. For
+ *     %ETHTOOL_GLINKSETTINGS: on entry, number of words passed by user
+ *     (>= 0); on return, if handshake in progress, negative if
+ *     request size unsupported by kernel: absolute value indicates
+ *     kernel recommended size and cmd field is 0, as well as all the
+ *     other fields; otherwise (handshake completed), strictly
+ *     positive to indicate size used by kernel and cmd field is
+ *     %ETHTOOL_GLINKSETTINGS, all other fields populated by driver. For
+ *     %ETHTOOL_SLINKSETTINGS: must be valid on entry, ie. a positive
+ *     value returned previously by %ETHTOOL_GLINKSETTINGS, otherwise
+ *     refused. For drivers: ignore this field (use kernel's
+ *     __ETHTOOL_LINK_MODE_MASK_NBITS instead), any change to it will
+ *     be overwritten by kernel.
+ * @supported: Bitmap with each bit meaning given by
+ *     %ethtool_link_mode_bit_indices for the link modes, physical
+ *     connectors and other link features for which the interface
+ *     supports autonegotiation or auto-detection.  Read-only.
+ * @advertising: Bitmap with each bit meaning given by
+ *     %ethtool_link_mode_bit_indices for the link modes, physical
+ *     connectors and other link features that are advertised through
+ *     autonegotiation or enabled for auto-detection.
+ * @lp_advertising: Bitmap with each bit meaning given by
+ *     %ethtool_link_mode_bit_indices for the link modes, and other
+ *     link features that the link partner advertised through
+ *     autonegotiation; 0 if unknown or not applicable.  Read-only.
+ *
+ * If autonegotiation is disabled, the speed and @duplex represent the
+ * fixed link mode and are writable if the driver supports multiple
+ * link modes.  If it is enabled then they are read-only; if the link
+ * is up they represent the negotiated link mode; if the link is down,
+ * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and
+ * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
+ *
+ * Some hardware interfaces may have multiple PHYs and/or physical
+ * connectors fitted or do not allow the driver to detect which are
+ * fitted.  For these interfaces @port and/or @phy_address may be
+ * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE.
+ * Otherwise, attempts to write different values may be ignored or
+ * rejected.
+ *
+ * Deprecated %ethtool_cmd fields transceiver, maxtxpkt and maxrxpkt
+ * are not available in %ethtool_link_settings. Until all drivers are
+ * converted to ignore them or to the new %ethtool_link_settings API,
+ * for both queries and changes, users should always try
+ * %ETHTOOL_GLINKSETTINGS first, and if it fails with -ENOTSUPP stick
+ * only to %ETHTOOL_GSET and %ETHTOOL_SSET consistently. If it
+ * succeeds, then users should stick to %ETHTOOL_GLINKSETTINGS and
+ * %ETHTOOL_SLINKSETTINGS (which would support drivers implementing
+ * either %ethtool_cmd or %ethtool_link_settings).
+ *
+ * Users should assume that all fields not marked read-only are
+ * writable and subject to validation by the driver.  They should use
+ * %ETHTOOL_GLINKSETTINGS to get the current values before making specific
+ * changes and then applying them with %ETHTOOL_SLINKSETTINGS.
+ *
+ * Drivers that implement %get_link_ksettings and/or
+ * %set_link_ksettings should ignore the @cmd
+ * and @link_mode_masks_nwords fields (any change to them overwritten
+ * by kernel), and rely only on kernel's internal
+ * %__ETHTOOL_LINK_MODE_MASK_NBITS and
+ * %ethtool_link_mode_mask_t. Drivers that implement
+ * %set_link_ksettings() should validate all fields other than @cmd
+ * and @link_mode_masks_nwords that are not described as read-only or
+ * deprecated, and must ignore all fields described as read-only.
+ */
+struct ethtool_link_settings {
+       __u32   cmd;
+       __u32   speed;
+       __u8    duplex;
+       __u8    port;
+       __u8    phy_address;
+       __u8    autoneg;
+       __u8    mdio_support;
+       __u8    eth_tp_mdix;
+       __u8    eth_tp_mdix_ctrl;
+       __s8    link_mode_masks_nwords;
+       __u32   reserved[8];
+       __u32   link_mode_masks[0];
+       /* layout of link_mode_masks fields:
+        * __u32 map_supported[link_mode_masks_nwords];
+        * __u32 map_advertising[link_mode_masks_nwords];
+        * __u32 map_lp_advertising[link_mode_masks_nwords];
+        */
+};
 #endif /* _UAPI_LINUX_ETHTOOL_H */
index ec35472349988fa556f39028d5ea8ecd689b85b0..0536eefff9bfee41c0de6088f38cf84b1d29a12f 100644 (file)
@@ -137,11 +137,17 @@ struct bridge_vlan_info {
 /* Bridge multicast database attributes
  * [MDBA_MDB] = {
  *     [MDBA_MDB_ENTRY] = {
- *         [MDBA_MDB_ENTRY_INFO]
+ *         [MDBA_MDB_ENTRY_INFO] {
+ *             struct br_mdb_entry
+ *             [MDBA_MDB_EATTR attributes]
+ *         }
  *     }
  * }
  * [MDBA_ROUTER] = {
- *    [MDBA_ROUTER_PORT]
+ *    [MDBA_ROUTER_PORT] = {
+ *        u32 ifindex
+ *        [MDBA_ROUTER_PATTR attributes]
+ *    }
  * }
  */
 enum {
@@ -166,6 +172,22 @@ enum {
 };
 #define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1)
 
+/* per mdb entry additional attributes */
+enum {
+       MDBA_MDB_EATTR_UNSPEC,
+       MDBA_MDB_EATTR_TIMER,
+       __MDBA_MDB_EATTR_MAX
+};
+#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
+
+/* multicast router types */
+enum {
+       MDB_RTR_TYPE_DISABLED,
+       MDB_RTR_TYPE_TEMP_QUERY,
+       MDB_RTR_TYPE_PERM,
+       MDB_RTR_TYPE_TEMP
+};
+
 enum {
        MDBA_ROUTER_UNSPEC,
        MDBA_ROUTER_PORT,
@@ -173,6 +195,15 @@ enum {
 };
 #define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
 
+/* router port attributes */
+enum {
+       MDBA_ROUTER_PATTR_UNSPEC,
+       MDBA_ROUTER_PATTR_TIMER,
+       MDBA_ROUTER_PATTR_TYPE,
+       __MDBA_ROUTER_PATTR_MAX
+};
+#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
+
 struct br_port_msg {
        __u8  family;
        __u32 ifindex;
index ea9221b0331adea9b748afdbc761e386d6814b4d..4a93051c578ce49c78140ae17878b3a3bbeba456 100644 (file)
@@ -83,6 +83,7 @@
 #define ETH_P_8021AD   0x88A8          /* 802.1ad Service VLAN         */
 #define ETH_P_802_EX1  0x88B5          /* 802.1 Local Experimental 1.  */
 #define ETH_P_TIPC     0x88CA          /* TIPC                         */
+#define ETH_P_MACSEC   0x88E5          /* 802.1ae MACsec */
 #define ETH_P_8021AH   0x88E7          /* 802.1ah Backbone Service Tag */
 #define ETH_P_MVRP     0x88F5          /* 802.1Q MVRP                  */
 #define ETH_P_1588     0x88F7          /* IEEE 1588 Timesync */
index d452cea5902039e2abd15cbd344a75fd879a6228..8e3f88fa5b59056cb29e7736b5d4d89e08964321 100644 (file)
@@ -413,6 +413,35 @@ enum {
 
 #define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1)
 
+/* MACSEC section */
+enum {
+       IFLA_MACSEC_UNSPEC,
+       IFLA_MACSEC_SCI,
+       IFLA_MACSEC_PORT,
+       IFLA_MACSEC_ICV_LEN,
+       IFLA_MACSEC_CIPHER_SUITE,
+       IFLA_MACSEC_WINDOW,
+       IFLA_MACSEC_ENCODING_SA,
+       IFLA_MACSEC_ENCRYPT,
+       IFLA_MACSEC_PROTECT,
+       IFLA_MACSEC_INC_SCI,
+       IFLA_MACSEC_ES,
+       IFLA_MACSEC_SCB,
+       IFLA_MACSEC_REPLAY_PROTECT,
+       IFLA_MACSEC_VALIDATION,
+       __IFLA_MACSEC_MAX,
+};
+
+#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1)
+
+enum macsec_validation_type {
+       MACSEC_VALIDATE_DISABLED = 0,
+       MACSEC_VALIDATE_CHECK = 1,
+       MACSEC_VALIDATE_STRICT = 2,
+       __MACSEC_VALIDATE_END,
+       MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+};
+
 /* IPVLAN section */
 enum {
        IFLA_IPVLAN_UNSPEC,
@@ -456,6 +485,7 @@ enum {
        IFLA_VXLAN_GBP,
        IFLA_VXLAN_REMCSUM_NOPARTIAL,
        IFLA_VXLAN_COLLECT_METADATA,
+       IFLA_VXLAN_LABEL,
        __IFLA_VXLAN_MAX
 };
 #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
@@ -478,6 +508,7 @@ enum {
        IFLA_GENEVE_UDP_CSUM,
        IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
        IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+       IFLA_GENEVE_LABEL,
        __IFLA_GENEVE_MAX
 };
 #define IFLA_GENEVE_MAX        (__IFLA_GENEVE_MAX - 1)
diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h
new file mode 100644 (file)
index 0000000..26b0d1e
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * include/uapi/linux/if_macsec.h - MACsec device
+ *
+ * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _UAPI_MACSEC_H
+#define _UAPI_MACSEC_H
+
+#include <linux/types.h>
+
+#define MACSEC_GENL_NAME "macsec"
+#define MACSEC_GENL_VERSION 1
+
+#define MACSEC_MAX_KEY_LEN 128
+
+#define DEFAULT_CIPHER_ID   0x0080020001000001ULL
+#define DEFAULT_CIPHER_ALT  0x0080C20001000001ULL
+
+#define MACSEC_MIN_ICV_LEN 8
+#define MACSEC_MAX_ICV_LEN 32
+
+enum macsec_attrs {
+       MACSEC_ATTR_UNSPEC,
+       MACSEC_ATTR_IFINDEX,     /* u32, ifindex of the MACsec netdevice */
+       MACSEC_ATTR_RXSC_CONFIG, /* config, nested macsec_rxsc_attrs */
+       MACSEC_ATTR_SA_CONFIG,   /* config, nested macsec_sa_attrs */
+       MACSEC_ATTR_SECY,        /* dump, nested macsec_secy_attrs */
+       MACSEC_ATTR_TXSA_LIST,   /* dump, nested, macsec_sa_attrs for each TXSA */
+       MACSEC_ATTR_RXSC_LIST,   /* dump, nested, macsec_rxsc_attrs for each RXSC */
+       MACSEC_ATTR_TXSC_STATS,  /* dump, nested, macsec_txsc_stats_attr */
+       MACSEC_ATTR_SECY_STATS,  /* dump, nested, macsec_secy_stats_attr */
+       __MACSEC_ATTR_END,
+       NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
+       MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
+};
+
+enum macsec_secy_attrs {
+       MACSEC_SECY_ATTR_UNSPEC,
+       MACSEC_SECY_ATTR_SCI,
+       MACSEC_SECY_ATTR_ENCODING_SA,
+       MACSEC_SECY_ATTR_WINDOW,
+       MACSEC_SECY_ATTR_CIPHER_SUITE,
+       MACSEC_SECY_ATTR_ICV_LEN,
+       MACSEC_SECY_ATTR_PROTECT,
+       MACSEC_SECY_ATTR_REPLAY,
+       MACSEC_SECY_ATTR_OPER,
+       MACSEC_SECY_ATTR_VALIDATE,
+       MACSEC_SECY_ATTR_ENCRYPT,
+       MACSEC_SECY_ATTR_INC_SCI,
+       MACSEC_SECY_ATTR_ES,
+       MACSEC_SECY_ATTR_SCB,
+       __MACSEC_SECY_ATTR_END,
+       NUM_MACSEC_SECY_ATTR = __MACSEC_SECY_ATTR_END,
+       MACSEC_SECY_ATTR_MAX = __MACSEC_SECY_ATTR_END - 1,
+};
+
+enum macsec_rxsc_attrs {
+       MACSEC_RXSC_ATTR_UNSPEC,
+       MACSEC_RXSC_ATTR_SCI,     /* config/dump, u64 */
+       MACSEC_RXSC_ATTR_ACTIVE,  /* config/dump, u8 0..1 */
+       MACSEC_RXSC_ATTR_SA_LIST, /* dump, nested */
+       MACSEC_RXSC_ATTR_STATS,   /* dump, nested, macsec_rxsc_stats_attr */
+       __MACSEC_RXSC_ATTR_END,
+       NUM_MACSEC_RXSC_ATTR = __MACSEC_RXSC_ATTR_END,
+       MACSEC_RXSC_ATTR_MAX = __MACSEC_RXSC_ATTR_END - 1,
+};
+
+enum macsec_sa_attrs {
+       MACSEC_SA_ATTR_UNSPEC,
+       MACSEC_SA_ATTR_AN,     /* config/dump, u8 0..3 */
+       MACSEC_SA_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+       MACSEC_SA_ATTR_PN,     /* config/dump, u32 */
+       MACSEC_SA_ATTR_KEY,    /* config, data */
+       MACSEC_SA_ATTR_KEYID,  /* config/dump, u64 */
+       MACSEC_SA_ATTR_STATS,  /* dump, nested, macsec_sa_stats_attr */
+       __MACSEC_SA_ATTR_END,
+       NUM_MACSEC_SA_ATTR = __MACSEC_SA_ATTR_END,
+       MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+};
+
+enum macsec_nl_commands {
+       MACSEC_CMD_GET_TXSC,
+       MACSEC_CMD_ADD_RXSC,
+       MACSEC_CMD_DEL_RXSC,
+       MACSEC_CMD_UPD_RXSC,
+       MACSEC_CMD_ADD_TXSA,
+       MACSEC_CMD_DEL_TXSA,
+       MACSEC_CMD_UPD_TXSA,
+       MACSEC_CMD_ADD_RXSA,
+       MACSEC_CMD_DEL_RXSA,
+       MACSEC_CMD_UPD_RXSA,
+};
+
+/* u64 per-RXSC stats */
+enum macsec_rxsc_stats_attr {
+       MACSEC_RXSC_STATS_ATTR_UNSPEC,
+       MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED,
+       MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+       MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA,
+       __MACSEC_RXSC_STATS_ATTR_END,
+       NUM_MACSEC_RXSC_STATS_ATTR = __MACSEC_RXSC_STATS_ATTR_END,
+       MACSEC_RXSC_STATS_ATTR_MAX = __MACSEC_RXSC_STATS_ATTR_END - 1,
+};
+
+/* u32 per-{RX,TX}SA stats */
+enum macsec_sa_stats_attr {
+       MACSEC_SA_STATS_ATTR_UNSPEC,
+       MACSEC_SA_STATS_ATTR_IN_PKTS_OK,
+       MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID,
+       MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID,
+       MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+       MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA,
+       MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED,
+       MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+       __MACSEC_SA_STATS_ATTR_END,
+       NUM_MACSEC_SA_STATS_ATTR = __MACSEC_SA_STATS_ATTR_END,
+       MACSEC_SA_STATS_ATTR_MAX = __MACSEC_SA_STATS_ATTR_END - 1,
+};
+
+/* u64 per-TXSC stats */
+enum macsec_txsc_stats_attr {
+       MACSEC_TXSC_STATS_ATTR_UNSPEC,
+       MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED,
+       MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+       MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED,
+       MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED,
+       __MACSEC_TXSC_STATS_ATTR_END,
+       NUM_MACSEC_TXSC_STATS_ATTR = __MACSEC_TXSC_STATS_ATTR_END,
+       MACSEC_TXSC_STATS_ATTR_MAX = __MACSEC_TXSC_STATS_ATTR_END - 1,
+};
+
+/* u64 per-SecY stats */
+enum macsec_secy_stats_attr {
+       MACSEC_SECY_STATS_ATTR_UNSPEC,
+       MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED,
+       MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI,
+       MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN,
+       __MACSEC_SECY_STATS_ATTR_END,
+       NUM_MACSEC_SECY_STATS_ATTR = __MACSEC_SECY_STATS_ATTR_END,
+       MACSEC_SECY_STATS_ATTR_MAX = __MACSEC_SECY_STATS_ATTR_END - 1,
+};
+
+#endif /* _UAPI_MACSEC_H */
index ec117b65d5a519c7c524b03b20a7522a6b1e1113..395876060f5087983cfae103b8ed8c16c30bde50 100644 (file)
@@ -176,6 +176,7 @@ enum {
        DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
        DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
        DEVCONF_DROP_UNSOLICITED_NA,
+       DEVCONF_KEEP_ADDR_ON_DOWN,
        DEVCONF_MAX
 };
 
diff --git a/include/uapi/linux/kcm.h b/include/uapi/linux/kcm.h
new file mode 100644 (file)
index 0000000..a5a5309
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Kernel Connection Multiplexor
+ *
+ * Copyright (c) 2016 Tom Herbert <tom@herbertland.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.
+ *
+ * User API to clone KCM sockets and attach transport socket to a KCM
+ * multiplexor.
+ */
+
+#ifndef KCM_KERNEL_H
+#define KCM_KERNEL_H
+
+struct kcm_attach {
+       int fd;
+       int bpf_fd;
+};
+
+struct kcm_unattach {
+       int fd;
+};
+
+struct kcm_clone {
+       int fd;
+};
+
+#define SIOCKCMATTACH  (SIOCPROTOPRIVATE + 0)
+#define SIOCKCMUNATTACH        (SIOCPROTOPRIVATE + 1)
+#define SIOCKCMCLONE   (SIOCPROTOPRIVATE + 2)
+
+#define KCMPROTO_CONNECTED     0
+
+/* Socket options */
+#define KCM_RECV_DISABLE       1
+
+#endif
+
index 321e399457f55cdbec5dca462ea26c85b3f7560c..466073f0ce46999b96ad90a8a5f809615b3f1f5b 100644 (file)
@@ -9,5 +9,6 @@
 #define __ALIGN_KERNEL(x, a)           __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
 #define __ALIGN_KERNEL_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 
+#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
 
 #endif /* _UAPI_LINUX_KERNEL_H */
index 1e3c8cb43bd7ac61650da4b6e31ab854af4a7b89..625b38f65764b34fe9d942339ef61a08af817564 100644 (file)
@@ -66,27 +66,33 @@ struct media_device_info {
 /*
  * DVB entities
  */
-#define MEDIA_ENT_F_DTV_DEMOD          (MEDIA_ENT_F_BASE + 1)
-#define MEDIA_ENT_F_TS_DEMUX           (MEDIA_ENT_F_BASE + 2)
-#define MEDIA_ENT_F_DTV_CA             (MEDIA_ENT_F_BASE + 3)
-#define MEDIA_ENT_F_DTV_NET_DECAP      (MEDIA_ENT_F_BASE + 4)
+#define MEDIA_ENT_F_DTV_DEMOD          (MEDIA_ENT_F_BASE + 0x00001)
+#define MEDIA_ENT_F_TS_DEMUX           (MEDIA_ENT_F_BASE + 0x00002)
+#define MEDIA_ENT_F_DTV_CA             (MEDIA_ENT_F_BASE + 0x00003)
+#define MEDIA_ENT_F_DTV_NET_DECAP      (MEDIA_ENT_F_BASE + 0x00004)
 
 /*
- * Connectors
+ * I/O entities
  */
-/* It is a responsibility of the entity drivers to add connectors and links */
-#define MEDIA_ENT_F_CONN_RF            (MEDIA_ENT_F_BASE + 21)
-#define MEDIA_ENT_F_CONN_SVIDEO                (MEDIA_ENT_F_BASE + 22)
-#define MEDIA_ENT_F_CONN_COMPOSITE     (MEDIA_ENT_F_BASE + 23)
-/* For internal test signal generators and other debug connectors */
-#define MEDIA_ENT_F_CONN_TEST          (MEDIA_ENT_F_BASE + 24)
+#define MEDIA_ENT_F_IO_DTV             (MEDIA_ENT_F_BASE + 0x01001)
+#define MEDIA_ENT_F_IO_VBI             (MEDIA_ENT_F_BASE + 0x01002)
+#define MEDIA_ENT_F_IO_SWRADIO         (MEDIA_ENT_F_BASE + 0x01003)
 
 /*
- * I/O entities
+ * Connectors
  */
-#define MEDIA_ENT_F_IO_DTV             (MEDIA_ENT_F_BASE + 31)
-#define MEDIA_ENT_F_IO_VBI             (MEDIA_ENT_F_BASE + 32)
-#define MEDIA_ENT_F_IO_SWRADIO         (MEDIA_ENT_F_BASE + 33)
+/* It is a responsibility of the entity drivers to add connectors and links */
+#ifdef __KERNEL__
+       /*
+        * For now, it should not be used in userspace, as some
+        * definitions may change
+        */
+
+#define MEDIA_ENT_F_CONN_RF            (MEDIA_ENT_F_BASE + 0x30001)
+#define MEDIA_ENT_F_CONN_SVIDEO                (MEDIA_ENT_F_BASE + 0x30002)
+#define MEDIA_ENT_F_CONN_COMPOSITE     (MEDIA_ENT_F_BASE + 0x30003)
+
+#endif
 
 /*
  * Don't touch on those. The ranges MEDIA_ENT_F_OLD_BASE and
@@ -291,14 +297,14 @@ struct media_v2_entity {
        __u32 id;
        char name[64];          /* FIXME: move to a property? (RFC says so) */
        __u32 function;         /* Main function of the entity */
-       __u16 reserved[12];
-};
+       __u32 reserved[6];
+} __attribute__ ((packed));
 
 /* Should match the specific fields at media_intf_devnode */
 struct media_v2_intf_devnode {
        __u32 major;
        __u32 minor;
-};
+} __attribute__ ((packed));
 
 struct media_v2_interface {
        __u32 id;
@@ -310,22 +316,22 @@ struct media_v2_interface {
                struct media_v2_intf_devnode devnode;
                __u32 raw[16];
        };
-};
+} __attribute__ ((packed));
 
 struct media_v2_pad {
        __u32 id;
        __u32 entity_id;
        __u32 flags;
-       __u16 reserved[9];
-};
+       __u32 reserved[5];
+} __attribute__ ((packed));
 
 struct media_v2_link {
        __u32 id;
        __u32 source_id;
        __u32 sink_id;
        __u32 flags;
-       __u32 reserved[5];
-};
+       __u32 reserved[6];
+} __attribute__ ((packed));
 
 struct media_v2_topology {
        __u64 topology_version;
@@ -345,7 +351,7 @@ struct media_v2_topology {
        __u32 num_links;
        __u32 reserved4;
        __u64 ptr_links;
-};
+} __attribute__ ((packed));
 
 static inline void __user *media_get_uptr(__u64 arg)
 {
index ce91215cf7e62cab5832264edaf78f76b08a8205..5062fb5751e1882a509170c2b88278ca3c26f5a2 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _UAPI__LINUX_MROUTE6_H
 #define _UAPI__LINUX_MROUTE6_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/sockios.h>
 
@@ -46,14 +47,8 @@ typedef unsigned short mifi_t;
 typedef        __u32           if_mask;
 #define NIFBITS (sizeof(if_mask) * 8)        /* bits per mask */
 
-#if !defined(__KERNEL__)
-#if !defined(DIV_ROUND_UP)
-#define        DIV_ROUND_UP(x,y)       (((x) + ((y) - 1)) / (y))
-#endif
-#endif
-
 typedef struct if_set {
-       if_mask ifs_bits[DIV_ROUND_UP(IF_SETSIZE, NIFBITS)];
+       if_mask ifs_bits[__KERNEL_DIV_ROUND_UP(IF_SETSIZE, NIFBITS)];
 } if_set;
 
 #define IF_SET(n, p)    ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS)))
index 5b4a4be06e2b9301699db8da20d8df8d10bc0a89..cc68b92124d46108d43241d2b4cc603c2771e5b0 100644 (file)
@@ -66,14 +66,18 @@ struct nd_cmd_ars_cap {
        __u64 length;
        __u32 status;
        __u32 max_ars_out;
+       __u32 clear_err_unit;
+       __u32 reserved;
 } __packed;
 
 struct nd_cmd_ars_start {
        __u64 address;
        __u64 length;
        __u16 type;
-       __u8 reserved[6];
+       __u8 flags;
+       __u8 reserved[5];
        __u32 status;
+       __u32 scrub_time;
 } __packed;
 
 struct nd_cmd_ars_status {
@@ -81,11 +85,14 @@ struct nd_cmd_ars_status {
        __u32 out_length;
        __u64 address;
        __u64 length;
+       __u64 restart_address;
+       __u64 restart_length;
        __u16 type;
+       __u16 flags;
        __u32 num_records;
        struct nd_ars_record {
                __u32 handle;
-               __u32 flags;
+               __u32 reserved;
                __u64 err_address;
                __u64 length;
        } __packed records[0];
index 23cbd34e4ac738de5c1d587be1028b5bca01ef86..45dfad509c4dc63ea11b9a1e75c8c6860a68c1c1 100644 (file)
@@ -19,6 +19,7 @@ enum {
        __NETCONFA_MAX
 };
 #define NETCONFA_MAX   (__NETCONFA_MAX - 1)
+#define NETCONFA_ALL   -1
 
 #define NETCONFA_IFINDEX_ALL           -1
 #define NETCONFA_IFINDEX_DEFAULT       -2
index be41ffc128b832d9ade6ca045736625e21b32e5e..eeffde196f804e2ea386eb5227f620b2371ba6f3 100644 (file)
@@ -681,6 +681,7 @@ enum nft_exthdr_attributes {
  * @NFT_META_IIFGROUP: packet input interface group
  * @NFT_META_OIFGROUP: packet output interface group
  * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
+ * @NFT_META_PRANDOM: a 32bit pseudo-random number
  */
 enum nft_meta_keys {
        NFT_META_LEN,
@@ -707,6 +708,7 @@ enum nft_meta_keys {
        NFT_META_IIFGROUP,
        NFT_META_OIFGROUP,
        NFT_META_CGROUP,
+       NFT_META_PRANDOM,
 };
 
 /**
@@ -949,10 +951,14 @@ enum nft_nat_attributes {
  * enum nft_masq_attributes - nf_tables masquerade expression attributes
  *
  * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
  */
 enum nft_masq_attributes {
        NFTA_MASQ_UNSPEC,
        NFTA_MASQ_FLAGS,
+       NFTA_MASQ_REG_PROTO_MIN,
+       NFTA_MASQ_REG_PROTO_MAX,
        __NFTA_MASQ_MAX
 };
 #define NFTA_MASQ_MAX          (__NFTA_MASQ_MAX - 1)
index f095155d87494b9cd68eca8f0c1458a683ad8479..0dba4e4ed2be21af9f02df5bd844cbb087a51706 100644 (file)
@@ -107,8 +107,10 @@ struct nlmsgerr {
 #define NETLINK_PKTINFO                        3
 #define NETLINK_BROADCAST_ERROR                4
 #define NETLINK_NO_ENOBUFS             5
+#ifndef __KERNEL__
 #define NETLINK_RX_RING                        6
 #define NETLINK_TX_RING                        7
+#endif
 #define NETLINK_LISTEN_ALL_NSID                8
 #define NETLINK_LIST_MEMBERSHIPS       9
 #define NETLINK_CAP_ACK                        10
@@ -134,6 +136,7 @@ struct nl_mmap_hdr {
        __u32           nm_gid;
 };
 
+#ifndef __KERNEL__
 enum nl_mmap_status {
        NL_MMAP_STATUS_UNUSED,
        NL_MMAP_STATUS_RESERVED,
@@ -145,6 +148,7 @@ enum nl_mmap_status {
 #define NL_MMAP_MSG_ALIGNMENT          NLMSG_ALIGNTO
 #define NL_MMAP_MSG_ALIGN(sz)          __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
 #define NL_MMAP_HDRLEN                 NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+#endif
 
 #define NET_MAJOR 36           /* Major 36 is reserved for networking                                          */
 
index f2159d30d1f5a24c76d6e939318603e72faa2637..d79399394b46ef77e9f182dcd1c589b105a7f12c 100644 (file)
@@ -48,6 +48,8 @@ enum {
 
 #define NDIAG_SHOW_MEMINFO     0x00000001 /* show memory info of a socket */
 #define NDIAG_SHOW_GROUPS      0x00000002 /* show groups of a netlink socket */
+#ifndef __KERNEL__
 #define NDIAG_SHOW_RING_CFG    0x00000004 /* show ring configuration */
+#endif
 
 #endif
index 5b7b5ebe7ca8731868e38bfab6218c166cb0317d..5a30a75636338364f0400eeb82954f059da17b22 100644 (file)
@@ -1727,6 +1727,8 @@ enum nl80211_commands {
  *     underlying device supports these minimal RRM features:
  *             %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
  *             %NL80211_FEATURE_QUIET,
+ *     Or, if global RRM is supported, see:
+ *             %NL80211_EXT_FEATURE_RRM
  *     If this flag is used, driver must add the Power Capabilities IE to the
  *     association request. In addition, it must also set the RRM capability
  *     flag in the association request's Capability Info field.
@@ -1789,6 +1791,10 @@ enum nl80211_commands {
  *     thus it must not specify the number of iterations, only the interval
  *     between scans. The scan plans are executed sequentially.
  *     Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
+ * @NL80211_ATTR_PBSS: flag attribute. If set it means operate
+ *     in a PBSS. Specified in %NL80211_CMD_CONNECT to request
+ *     connecting to a PCP, and in %NL80211_CMD_START_AP to start
+ *     a PCP instead of AP. Relevant for DMG networks only.
  *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2164,6 +2170,8 @@ enum nl80211_attrs {
        NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
        NL80211_ATTR_SCHED_SCAN_PLANS,
 
+       NL80211_ATTR_PBSS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -4396,12 +4404,18 @@ enum nl80211_feature_flags {
 /**
  * enum nl80211_ext_feature_index - bit index of extended features.
  * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
+ * @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
+ *     can request to use RRM (see %NL80211_ATTR_USE_RRM) with
+ *     %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
+ *     the ASSOC_REQ_USE_RRM flag in the association request even if
+ *     NL80211_FEATURE_QUIET is not advertized.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
  */
 enum nl80211_ext_feature_index {
        NL80211_EXT_FEATURE_VHT_IBSS,
+       NL80211_EXT_FEATURE_RRM,
 
        /* add new features before the definition below */
        NUM_NL80211_EXT_FEATURES,
index 439873775d49196a93b6f6b7dfaa820574fd462e..c43c5f78b9c457e9e0d1addc02668b0b65e42a9e 100644 (file)
@@ -172,6 +172,7 @@ enum {
        TCA_U32_INDEV,
        TCA_U32_PCNT,
        TCA_U32_MARK,
+       TCA_U32_FLAGS,
        __TCA_U32_MAX
 };
 
@@ -416,6 +417,8 @@ enum {
        TCA_FLOWER_KEY_TCP_DST,         /* be16 */
        TCA_FLOWER_KEY_UDP_SRC,         /* be16 */
        TCA_FLOWER_KEY_UDP_DST,         /* be16 */
+
+       TCA_FLOWER_FLAGS,
        __TCA_FLOWER_MAX,
 };
 
index 058757f7a7339b104f9f44ebd77569cf20f35ef6..2e00dcebebd0700ac835d0d98221ef1cb4717974 100644 (file)
@@ -59,6 +59,8 @@ enum rfkill_type {
  * @RFKILL_OP_DEL: a device was removed
  * @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
  * @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
+ *     into a state, also updating the default state used for devices that
+ *     are hot-plugged later.
  */
 enum rfkill_operation {
        RFKILL_OP_ADD = 0,
diff --git a/include/uapi/linux/tc_act/tc_ife.h b/include/uapi/linux/tc_act/tc_ife.h
new file mode 100644 (file)
index 0000000..d648ff6
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __UAPI_TC_IFE_H
+#define __UAPI_TC_IFE_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_IFE 25
+/* Flag bits for now just encoding/decoding; mutually exclusive */
+#define IFE_ENCODE 1
+#define IFE_DECODE 0
+
+struct tc_ife {
+       tc_gen;
+       __u16 flags;
+};
+
+/*XXX: We need to encode the total number of bytes consumed */
+enum {
+       TCA_IFE_UNSPEC,
+       TCA_IFE_PARMS,
+       TCA_IFE_TM,
+       TCA_IFE_DMAC,
+       TCA_IFE_SMAC,
+       TCA_IFE_TYPE,
+       TCA_IFE_METALST,
+       __TCA_IFE_MAX
+};
+#define TCA_IFE_MAX (__TCA_IFE_MAX - 1)
+
+#define IFE_META_SKBMARK 1
+#define IFE_META_HASHID 2
+#define        IFE_META_PRIO 3
+#define        IFE_META_QMAP 4
+/*Can be overridden at runtime by module option*/
+#define        __IFE_META_MAX 5
+#define IFE_META_MAX (__IFE_META_MAX - 1)
+
+#endif
index 65a77b071e22bec39225799e808b44b35bb1910c..fe95446e9abff381a794c667ebe1321d61d04913 100644 (file)
@@ -196,6 +196,9 @@ struct tcp_info {
        __u64   tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */
        __u32   tcpi_segs_out;       /* RFC4898 tcpEStatsPerfSegsOut */
        __u32   tcpi_segs_in;        /* RFC4898 tcpEStatsPerfSegsIn */
+
+       __u32   tcpi_notsent_bytes;
+       __u32   tcpi_min_rtt;
 };
 
 /* for TCP_MD5SIG socket option */
index 252ffd4801ef68cbfd8b37c58875e816084149a7..4f20dbc4291043ad924158f7769ef408810dd9a0 100644 (file)
@@ -1,16 +1,34 @@
 /******************************************************************************
- * netif.h
+ * xen_netif.h
  *
  * Unified network-device I/O interface for Xen guest OSes.
  *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
  * Copyright (c) 2003-2004, Keir Fraser
  */
 
-#ifndef __XEN_PUBLIC_IO_NETIF_H__
-#define __XEN_PUBLIC_IO_NETIF_H__
+#ifndef __XEN_PUBLIC_IO_XEN_NETIF_H__
+#define __XEN_PUBLIC_IO_XEN_NETIF_H__
 
-#include <xen/interface/io/ring.h>
-#include <xen/interface/grant_table.h>
+#include "ring.h"
+#include "../grant_table.h"
 
 /*
  * Older implementation of Xen network frontend / backend has an
  * that it cannot safely queue packets (as it may not be kicked to send them).
  */
 
- /*
+/*
  * "feature-split-event-channels" is introduced to separate guest TX
- * and RX notificaion. Backend either doesn't support this feature or
- * advertise it via xenstore as 0 (disabled) or 1 (enabled).
+ * and RX notification. Backend either doesn't support this feature or
+ * advertises it via xenstore as 0 (disabled) or 1 (enabled).
  *
  * To make use of this feature, frontend should allocate two event
  * channels for TX and RX, advertise them to backend as
  */
 
 /*
- * This is the 'wire' format for packets:
- *  Request 1: xen_netif_tx_request  -- XEN_NETTXF_* (any flags)
- * [Request 2: xen_netif_extra_info]    (only if request 1 has XEN_NETTXF_extra_info)
- * [Request 3: xen_netif_extra_info]    (only if request 2 has XEN_NETIF_EXTRA_MORE)
- *  Request 4: xen_netif_tx_request  -- XEN_NETTXF_more_data
- *  Request 5: xen_netif_tx_request  -- XEN_NETTXF_more_data
+ * "feature-multicast-control" and "feature-dynamic-multicast-control"
+ * advertise the capability to filter ethernet multicast packets in the
+ * backend. If the frontend wishes to take advantage of this feature then
+ * it may set "request-multicast-control". If the backend only advertises
+ * "feature-multicast-control" then "request-multicast-control" must be set
+ * before the frontend moves into the connected state. The backend will
+ * sample the value on this state transition and any subsequent change in
+ * value will have no effect. However, if the backend also advertises
+ * "feature-dynamic-multicast-control" then "request-multicast-control"
+ * may be set by the frontend at any time. In this case, the backend will
+ * watch the value and re-sample on watch events.
+ *
+ * If the sampled value of "request-multicast-control" is set then the
+ * backend transmit side should no longer flood multicast packets to the
+ * frontend, it should instead drop any multicast packet that does not
+ * match in a filter list.
+ * The list is amended by the frontend by sending dummy transmit requests
+ * containing XEN_NETIF_EXTRA_TYPE_MCAST_{ADD,DEL} extra-info fragments as
+ * specified below.
+ * Note that the filter list may be amended even if the sampled value of
+ * "request-multicast-control" is not set, however the filter should only
+ * be applied if it is set.
+ */
+
+/*
+ * Control ring
+ * ============
+ *
+ * Some features, such as hashing (detailed below), require a
+ * significant amount of out-of-band data to be passed from frontend to
+ * backend. Use of xenstore is not suitable for large quantities of data
+ * because of quota limitations and so a dedicated 'control ring' is used.
+ * The ability of the backend to use a control ring is advertised by
+ * setting:
+ *
+ * /local/domain/X/backend/<domid>/<vif>/feature-ctrl-ring = "1"
+ *
+ * The frontend provides a control ring to the backend by setting:
+ *
+ * /local/domain/<domid>/device/vif/<vif>/ctrl-ring-ref = <gref>
+ * /local/domain/<domid>/device/vif/<vif>/event-channel-ctrl = <port>
+ *
+ * where <gref> is the grant reference of the shared page used to
+ * implement the control ring and <port> is an event channel to be used
+ * as a mailbox interrupt. These keys must be set before the frontend
+ * moves into the connected state.
+ *
+ * The control ring uses a fixed request/response message size and is
+ * balanced (i.e. one request to one response), so operationally it is much
+ * the same as a transmit or receive ring.
+ * Note that there is no requirement that responses are issued in the same
+ * order as requests.
+ */
+
+/*
+ * Hash types
+ * ==========
+ *
+ * For the purposes of the definitions below, 'Packet[]' is an array of
+ * octets containing an IP packet without options, 'Array[X..Y]' means a
+ * sub-array of 'Array' containing bytes X thru Y inclusive, and '+' is
+ * used to indicate concatenation of arrays.
+ */
+
+/*
+ * A hash calculated over an IP version 4 header as follows:
+ *
+ * Buffer[0..8] = Packet[12..15] (source address) +
+ *                Packet[16..19] (destination address)
+ *
+ * Result = Hash(Buffer, 8)
+ */
+#define _XEN_NETIF_CTRL_HASH_TYPE_IPV4 0
+#define XEN_NETIF_CTRL_HASH_TYPE_IPV4 \
+       (1 << _XEN_NETIF_CTRL_HASH_TYPE_IPV4)
+
+/*
+ * A hash calculated over an IP version 4 header and TCP header as
+ * follows:
+ *
+ * Buffer[0..12] = Packet[12..15] (source address) +
+ *                 Packet[16..19] (destination address) +
+ *                 Packet[20..21] (source port) +
+ *                 Packet[22..23] (destination port)
+ *
+ * Result = Hash(Buffer, 12)
+ */
+#define _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP 1
+#define XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP \
+       (1 << _XEN_NETIF_CTRL_HASH_TYPE_IPV4_TCP)
+
+/*
+ * A hash calculated over an IP version 6 header as follows:
+ *
+ * Buffer[0..32] = Packet[8..23]  (source address ) +
+ *                 Packet[24..39] (destination address)
+ *
+ * Result = Hash(Buffer, 32)
+ */
+#define _XEN_NETIF_CTRL_HASH_TYPE_IPV6 2
+#define XEN_NETIF_CTRL_HASH_TYPE_IPV6 \
+       (1 << _XEN_NETIF_CTRL_HASH_TYPE_IPV6)
+
+/*
+ * A hash calculated over an IP version 6 header and TCP header as
+ * follows:
+ *
+ * Buffer[0..36] = Packet[8..23]  (source address) +
+ *                 Packet[24..39] (destination address) +
+ *                 Packet[40..41] (source port) +
+ *                 Packet[42..43] (destination port)
+ *
+ * Result = Hash(Buffer, 36)
+ */
+#define _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP 3
+#define XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP \
+       (1 << _XEN_NETIF_CTRL_HASH_TYPE_IPV6_TCP)
+
+/*
+ * Hash algorithms
+ * ===============
+ */
+
+#define XEN_NETIF_CTRL_HASH_ALGORITHM_NONE 0
+
+/*
+ * Toeplitz hash:
+ */
+
+#define XEN_NETIF_CTRL_HASH_ALGORITHM_TOEPLITZ 1
+
+/*
+ * This algorithm uses a 'key' as well as the data buffer itself.
+ * (Buffer[] and Key[] are treated as shift-registers where the MSB of
+ * Buffer/Key[0] is considered 'left-most' and the LSB of Buffer/Key[N-1]
+ * is the 'right-most').
+ *
+ * Value = 0
+ * For number of bits in Buffer[]
+ *    If (left-most bit of Buffer[] is 1)
+ *        Value ^= left-most 32 bits of Key[]
+ *    Key[] << 1
+ *    Buffer[] << 1
+ *
+ * The code below is provided for convenience where an operating system
+ * does not already provide an implementation.
+ */
+#ifdef XEN_NETIF_DEFINE_TOEPLITZ
+static uint32_t xen_netif_toeplitz_hash(const uint8_t *key,
+                                       unsigned int keylen,
+                                       const uint8_t *buf, unsigned int buflen)
+{
+       unsigned int keyi, bufi;
+       uint64_t prefix = 0;
+       uint64_t hash = 0;
+
+       /* Pre-load prefix with the first 8 bytes of the key */
+       for (keyi = 0; keyi < 8; keyi++) {
+               prefix <<= 8;
+               prefix |= (keyi < keylen) ? key[keyi] : 0;
+       }
+
+       for (bufi = 0; bufi < buflen; bufi++) {
+               uint8_t byte = buf[bufi];
+               unsigned int bit;
+
+               for (bit = 0; bit < 8; bit++) {
+                       if (byte & 0x80)
+                               hash ^= prefix;
+                       prefix <<= 1;
+                       byte <<= 1;
+               }
+
+               /*
+                * 'prefix' has now been left-shifted by 8, so
+                * OR in the next byte.
+                */
+               prefix |= (keyi < keylen) ? key[keyi] : 0;
+               keyi++;
+       }
+
+       /* The valid part of the hash is in the upper 32 bits. */
+       return hash >> 32;
+}
+#endif                         /* XEN_NETIF_DEFINE_TOEPLITZ */
+
+/*
+ * Control requests (struct xen_netif_ctrl_request)
+ * ================================================
+ *
+ * All requests have the following format:
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |    id     |   type    |         data[0]       |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |         data[1]       |         data[2]       |
+ * +-----+-----+-----+-----+-----------------------+
+ *
+ * id: the request identifier, echoed in response.
+ * type: the type of request (see below)
+ * data[]: any data associated with the request (determined by type)
+ */
+
+struct xen_netif_ctrl_request {
+       uint16_t id;
+       uint16_t type;
+
+#define XEN_NETIF_CTRL_TYPE_INVALID               0
+#define XEN_NETIF_CTRL_TYPE_GET_HASH_FLAGS        1
+#define XEN_NETIF_CTRL_TYPE_SET_HASH_FLAGS        2
+#define XEN_NETIF_CTRL_TYPE_SET_HASH_KEY          3
+#define XEN_NETIF_CTRL_TYPE_GET_HASH_MAPPING_SIZE 4
+#define XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE 5
+#define XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING      6
+#define XEN_NETIF_CTRL_TYPE_SET_HASH_ALGORITHM    7
+
+       uint32_t data[3];
+};
+
+/*
+ * Control responses (struct xen_netif_ctrl_response)
+ * ==================================================
+ *
+ * All responses have the following format:
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |    id     |   type    |         status        |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |         data          |
+ * +-----+-----+-----+-----+
+ *
+ * id: the corresponding request identifier
+ * type: the type of the corresponding request
+ * status: the status of request processing
+ * data: any data associated with the response (determined by type and
+ *       status)
+ */
+
+struct xen_netif_ctrl_response {
+       uint16_t id;
+       uint16_t type;
+       uint32_t status;
+
+#define XEN_NETIF_CTRL_STATUS_SUCCESS           0
+#define XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     1
+#define XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER 2
+#define XEN_NETIF_CTRL_STATUS_BUFFER_OVERFLOW   3
+
+       uint32_t data;
+};
+
+/*
+ * Control messages
+ * ================
+ *
+ * XEN_NETIF_CTRL_TYPE_SET_HASH_ALGORITHM
+ * --------------------------------------
+ *
+ * This is sent by the frontend to set the desired hash algorithm.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_SET_HASH_ALGORITHM
+ *  data[0] = a XEN_NETIF_CTRL_HASH_ALGORITHM_* value
+ *  data[1] = 0
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     - Operation not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER - The algorithm is not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS           - Operation successful
+ *
+ * NOTE: Setting data[0] to XEN_NETIF_CTRL_HASH_ALGORITHM_NONE disables
+ *       hashing and the backend is free to choose how it steers packets
+ *       to queues (which is the default behaviour).
+ *
+ * XEN_NETIF_CTRL_TYPE_GET_HASH_FLAGS
+ * ----------------------------------
+ *
+ * This is sent by the frontend to query the types of hash supported by
+ * the backend.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_GET_HASH_FLAGS
+ *  data[0] = 0
+ *  data[1] = 0
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED - Operation not supported
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS       - Operation successful
+ *  data   = supported hash types (if operation was successful)
+ *
+ * NOTE: A valid hash algorithm must be selected before this operation can
+ *       succeed.
+ *
+ * XEN_NETIF_CTRL_TYPE_SET_HASH_FLAGS
+ * ----------------------------------
+ *
+ * This is sent by the frontend to set the types of hash that the backend
+ * should calculate. (See above for hash type definitions).
+ * Note that the 'maximal' type of hash should always be chosen. For
+ * example, if the frontend sets both IPV4 and IPV4_TCP hash types then
+ * the latter hash type should be calculated for any TCP packet and the
+ * former only calculated for non-TCP packets.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_SET_HASH_FLAGS
+ *  data[0] = bitwise OR of XEN_NETIF_CTRL_HASH_TYPE_* values
+ *  data[1] = 0
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     - Operation not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER - One or more flag
+ *                                                     value is invalid or
+ *                                                     unsupported
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS           - Operation successful
+ *  data   = 0
+ *
+ * NOTE: A valid hash algorithm must be selected before this operation can
+ *       succeed.
+ *       Also, setting data[0] to zero disables hashing and the backend
+ *       is free to choose how it steers packets to queues.
+ *
+ * XEN_NETIF_CTRL_TYPE_SET_HASH_KEY
+ * --------------------------------
+ *
+ * This is sent by the frontend to set the key of the hash if the algorithm
+ * requires it. (See hash algorithms above).
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_SET_HASH_KEY
+ *  data[0] = grant reference of page containing the key (assumed to
+ *            start at beginning of grant)
+ *  data[1] = size of key in octets
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     - Operation not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER - Key size is invalid
+ *           XEN_NETIF_CTRL_STATUS_BUFFER_OVERFLOW   - Key size is larger
+ *                                                     than the backend
+ *                                                     supports
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS           - Operation successful
+ *  data   = 0
+ *
+ * NOTE: Any key octets not specified are assumed to be zero (the key
+ *       is assumed to be empty by default) and specifying a new key
+ *       invalidates any previous key, hence specifying a key size of
+ *       zero will clear the key (which ensures that the calculated hash
+ *       will always be zero).
+ *       The maximum size of key is algorithm and backend specific, but
+ *       is also limited by the single grant reference.
+ *       The grant reference may be read-only and must remain valid until
+ *       the response has been processed.
+ *
+ * XEN_NETIF_CTRL_TYPE_GET_HASH_MAPPING_SIZE
+ * -----------------------------------------
+ *
+ * This is sent by the frontend to query the maximum size of mapping
+ * table supported by the backend. The size is specified in terms of
+ * table entries.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_GET_HASH_MAPPING_SIZE
+ *  data[0] = 0
+ *  data[1] = 0
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED - Operation not supported
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS       - Operation successful
+ *  data   = maximum number of entries allowed in the mapping table
+ *           (if operation was successful) or zero if a mapping table is
+ *           not supported (i.e. hash mapping is done only by modular
+ *           arithmetic).
+ *
+ * XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE
+ * -------------------------------------
+ *
+ * This is sent by the frontend to set the actual size of the mapping
+ * table to be used by the backend. The size is specified in terms of
+ * table entries.
+ * Any previous table is invalidated by this message and any new table
+ * is assumed to be zero filled.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE
+ *  data[0] = number of entries in mapping table
+ *  data[1] = 0
+ *  data[2] = 0
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     - Operation not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER - Table size is invalid
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS           - Operation successful
+ *  data   = 0
+ *
+ * NOTE: Setting data[0] to 0 means that hash mapping should be done
+ *       using modular arithmetic.
+ *
+ * XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING
+ * ------------------------------------
+ *
+ * This is sent by the frontend to set the content of the table mapping
+ * hash value to queue number. The backend should calculate the hash from
+ * the packet header, use it as an index into the table (modulo the size
+ * of the table) and then steer the packet to the queue number found at
+ * that index.
+ *
+ * Request:
+ *
+ *  type    = XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING
+ *  data[0] = grant reference of page containing the mapping (sub-)table
+ *            (assumed to start at beginning of grant)
+ *  data[1] = size of (sub-)table in entries
+ *  data[2] = offset, in entries, of sub-table within overall table
+ *
+ * Response:
+ *
+ *  status = XEN_NETIF_CTRL_STATUS_NOT_SUPPORTED     - Operation not
+ *                                                     supported
+ *           XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER - Table size or content
+ *                                                     is invalid
+ *           XEN_NETIF_CTRL_STATUS_BUFFER_OVERFLOW   - Table size is larger
+ *                                                     than the backend
+ *                                                     supports
+ *           XEN_NETIF_CTRL_STATUS_SUCCESS           - Operation successful
+ *  data   = 0
+ *
+ * NOTE: The overall table has the following format:
+ *
+ *          0     1     2     3     4     5     6     7  octet
+ *       +-----+-----+-----+-----+-----+-----+-----+-----+
+ *       |       mapping[0]      |       mapping[1]      |
+ *       +-----+-----+-----+-----+-----+-----+-----+-----+
+ *       |                       .                       |
+ *       |                       .                       |
+ *       |                       .                       |
+ *       +-----+-----+-----+-----+-----+-----+-----+-----+
+ *       |      mapping[N-2]     |      mapping[N-1]     |
+ *       +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ *       where N is specified by a XEN_NETIF_CTRL_TYPE_SET_HASH_MAPPING_SIZE
+ *       message and each  mapping must specifies a queue between 0 and
+ *       "multi-queue-num-queues" (see above).
+ *       The backend may support a mapping table larger than can be
+ *       mapped by a single grant reference. Thus sub-tables within a
+ *       larger table can be individually set by sending multiple messages
+ *       with differing offset values. Specifying a new sub-table does not
+ *       invalidate any table data outside that range.
+ *       The grant reference may be read-only and must remain valid until
+ *       the response has been processed.
+ */
+
+DEFINE_RING_TYPES(xen_netif_ctrl,
+                 struct xen_netif_ctrl_request,
+                 struct xen_netif_ctrl_response);
+
+/*
+ * Guest transmit
+ * ==============
+ *
+ * This is the 'wire' format for transmit (frontend -> backend) packets:
+ *
+ *  Fragment 1: xen_netif_tx_request_t  - flags = XEN_NETTXF_*
+ *                                    size = total packet size
+ * [Extra 1: xen_netif_extra_info_t]    - (only if fragment 1 flags include
+ *                                     XEN_NETTXF_extra_info)
+ *  ...
+ * [Extra N: xen_netif_extra_info_t]    - (only if extra N-1 flags include
+ *                                     XEN_NETIF_EXTRA_MORE)
  *  ...
- *  Request N: xen_netif_tx_request  -- 0
+ *  Fragment N: xen_netif_tx_request_t  - (only if fragment N-1 flags include
+ *                                     XEN_NETTXF_more_data - flags on preceding
+ *                                     extras are not relevant here)
+ *                                    flags = 0
+ *                                    size = fragment size
+ *
+ * NOTE:
+ *
+ * This format slightly is different from that used for receive
+ * (backend -> frontend) packets. Specifically, in a multi-fragment
+ * packet the actual size of fragment 1 can only be determined by
+ * subtracting the sizes of fragments 2..N from the total packet size.
+ *
+ * Ring slot size is 12 octets, however not all request/response
+ * structs use the full size.
+ *
+ * tx request data (xen_netif_tx_request_t)
+ * ------------------------------------
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | grant ref             | offset    | flags     |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | id        | size      |
+ * +-----+-----+-----+-----+
+ *
+ * grant ref: Reference to buffer page.
+ * offset: Offset within buffer page.
+ * flags: XEN_NETTXF_*.
+ * id: request identifier, echoed in response.
+ * size: packet size in bytes.
+ *
+ * tx response (xen_netif_tx_response_t)
+ * ---------------------------------
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | id        | status    | unused                |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | unused                |
+ * +-----+-----+-----+-----+
+ *
+ * id: reflects id in transmit request
+ * status: XEN_NETIF_RSP_*
+ *
+ * Guest receive
+ * =============
+ *
+ * This is the 'wire' format for receive (backend -> frontend) packets:
+ *
+ *  Fragment 1: xen_netif_rx_request_t  - flags = XEN_NETRXF_*
+ *                                    size = fragment size
+ * [Extra 1: xen_netif_extra_info_t]    - (only if fragment 1 flags include
+ *                                     XEN_NETRXF_extra_info)
+ *  ...
+ * [Extra N: xen_netif_extra_info_t]    - (only if extra N-1 flags include
+ *                                     XEN_NETIF_EXTRA_MORE)
+ *  ...
+ *  Fragment N: xen_netif_rx_request_t  - (only if fragment N-1 flags include
+ *                                     XEN_NETRXF_more_data - flags on preceding
+ *                                     extras are not relevant here)
+ *                                    flags = 0
+ *                                    size = fragment size
+ *
+ * NOTE:
+ *
+ * This format slightly is different from that used for transmit
+ * (frontend -> backend) packets. Specifically, in a multi-fragment
+ * packet the size of the packet can only be determined by summing the
+ * sizes of fragments 1..N.
+ *
+ * Ring slot size is 8 octets.
+ *
+ * rx request (xen_netif_rx_request_t)
+ * -------------------------------
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | id        | pad       | gref                  |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * id: request identifier, echoed in response.
+ * gref: reference to incoming granted frame.
+ *
+ * rx response (xen_netif_rx_response_t)
+ * ---------------------------------
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | id        | offset    | flags     | status    |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * id: reflects id in receive request
+ * offset: offset in page of start of received packet
+ * flags: XEN_NETRXF_*
+ * status: -ve: XEN_NETIF_RSP_*; +ve: Rx'ed pkt size.
+ *
+ * NOTE: Historically, to support GSO on the frontend receive side, Linux
+ *       netfront does not make use of the rx response id (because, as
+ *       described below, extra info structures overlay the id field).
+ *       Instead it assumes that responses always appear in the same ring
+ *       slot as their corresponding request. Thus, to maintain
+ *       compatibility, backends must make sure this is the case.
+ *
+ * Extra Info
+ * ==========
+ *
+ * Can be present if initial request or response has NET{T,R}XF_extra_info,
+ * or previous extra request has XEN_NETIF_EXTRA_MORE.
+ *
+ * The struct therefore needs to fit into either a tx or rx slot and
+ * is therefore limited to 8 octets.
+ *
+ * NOTE: Because extra info data overlays the usual request/response
+ *       structures, there is no id information in the opposite direction.
+ *       So, if an extra info overlays an rx response the frontend can
+ *       assume that it is in the same ring slot as the request that was
+ *       consumed to make the slot available, and the backend must ensure
+ *       this assumption is true.
+ *
+ * extra info (xen_netif_extra_info_t)
+ * -------------------------------
+ *
+ * General format:
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |type |flags| type specific data                |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | padding for tx        |
+ * +-----+-----+-----+-----+
+ *
+ * type: XEN_NETIF_EXTRA_TYPE_*
+ * flags: XEN_NETIF_EXTRA_FLAG_*
+ * padding for tx: present only in the tx case due to 8 octet limit
+ *                 from rx case. Not shown in type specific entries
+ *                 below.
+ *
+ * XEN_NETIF_EXTRA_TYPE_GSO:
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |type |flags| size      |type | pad | features  |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * type: Must be XEN_NETIF_EXTRA_TYPE_GSO
+ * flags: XEN_NETIF_EXTRA_FLAG_*
+ * size: Maximum payload size of each segment. For example,
+ *       for TCP this is just the path MSS.
+ * type: XEN_NETIF_GSO_TYPE_*: This determines the protocol of
+ *       the packet and any extra features required to segment the
+ *       packet properly.
+ * features: EN_XEN_NETIF_GSO_FEAT_*: This specifies any extra GSO
+ *           features required to process this packet, such as ECN
+ *           support for TCPv4.
+ *
+ * XEN_NETIF_EXTRA_TYPE_MCAST_{ADD,DEL}:
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |type |flags| addr                              |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * type: Must be XEN_NETIF_EXTRA_TYPE_MCAST_{ADD,DEL}
+ * flags: XEN_NETIF_EXTRA_FLAG_*
+ * addr: address to add/remove
+ *
+ * XEN_NETIF_EXTRA_TYPE_HASH:
+ *
+ * A backend that supports teoplitz hashing is assumed to accept
+ * this type of extra info in transmit packets.
+ * A frontend that enables hashing is assumed to accept
+ * this type of extra info in receive packets.
+ *
+ *    0     1     2     3     4     5     6     7  octet
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * |type |flags|htype| alg |LSB ---- value ---- MSB|
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
+ * type: Must be XEN_NETIF_EXTRA_TYPE_HASH
+ * flags: XEN_NETIF_EXTRA_FLAG_*
+ * htype: Hash type (one of _XEN_NETIF_CTRL_HASH_TYPE_* - see above)
+ * alg: The algorithm used to calculate the hash (one of
+ *      XEN_NETIF_CTRL_HASH_TYPE_ALGORITHM_* - see above)
+ * value: Hash value
  */
 
 /* Protocol checksum field is blank in the packet (hardware offload)? */
-#define _XEN_NETTXF_csum_blank         (0)
-#define  XEN_NETTXF_csum_blank         (1U<<_XEN_NETTXF_csum_blank)
+#define _XEN_NETTXF_csum_blank     (0)
+#define  XEN_NETTXF_csum_blank     (1U<<_XEN_NETTXF_csum_blank)
 
 /* Packet data has been validated against protocol checksum. */
-#define _XEN_NETTXF_data_validated     (1)
-#define  XEN_NETTXF_data_validated     (1U<<_XEN_NETTXF_data_validated)
+#define _XEN_NETTXF_data_validated (1)
+#define  XEN_NETTXF_data_validated (1U<<_XEN_NETTXF_data_validated)
 
 /* Packet continues in the next request descriptor. */
-#define _XEN_NETTXF_more_data          (2)
-#define  XEN_NETTXF_more_data          (1U<<_XEN_NETTXF_more_data)
+#define _XEN_NETTXF_more_data      (2)
+#define  XEN_NETTXF_more_data      (1U<<_XEN_NETTXF_more_data)
 
 /* Packet to be followed by extra descriptor(s). */
-#define _XEN_NETTXF_extra_info         (3)
-#define  XEN_NETTXF_extra_info         (1U<<_XEN_NETTXF_extra_info)
+#define _XEN_NETTXF_extra_info     (3)
+#define  XEN_NETTXF_extra_info     (1U<<_XEN_NETTXF_extra_info)
 
 #define XEN_NETIF_MAX_TX_SIZE 0xFFFF
 struct xen_netif_tx_request {
-    grant_ref_t gref;      /* Reference to buffer page */
-    uint16_t offset;       /* Offset within buffer page */
-    uint16_t flags;        /* XEN_NETTXF_* */
-    uint16_t id;           /* Echoed in response message. */
-    uint16_t size;         /* Packet size in bytes.       */
+       grant_ref_t gref;
+       uint16_t offset;
+       uint16_t flags;
+       uint16_t id;
+       uint16_t size;
 };
 
 /* Types of xen_netif_extra_info descriptors. */
-#define XEN_NETIF_EXTRA_TYPE_NONE      (0)  /* Never used - invalid */
-#define XEN_NETIF_EXTRA_TYPE_GSO       (1)  /* u.gso */
-#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2)  /* u.mcast */
-#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3)  /* u.mcast */
-#define XEN_NETIF_EXTRA_TYPE_MAX       (4)
+#define XEN_NETIF_EXTRA_TYPE_NONE      (0)     /* Never used - invalid */
+#define XEN_NETIF_EXTRA_TYPE_GSO       (1)     /* u.gso */
+#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2)     /* u.mcast */
+#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3)     /* u.mcast */
+#define XEN_NETIF_EXTRA_TYPE_HASH      (4)     /* u.hash */
+#define XEN_NETIF_EXTRA_TYPE_MAX       (5)
 
-/* xen_netif_extra_info flags. */
-#define _XEN_NETIF_EXTRA_FLAG_MORE     (0)
-#define  XEN_NETIF_EXTRA_FLAG_MORE     (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+/* xen_netif_extra_info_t flags. */
+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+#define XEN_NETIF_EXTRA_FLAG_MORE  (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
 
 /* GSO types */
-#define XEN_NETIF_GSO_TYPE_NONE                (0)
-#define XEN_NETIF_GSO_TYPE_TCPV4       (1)
-#define XEN_NETIF_GSO_TYPE_TCPV6       (2)
+#define XEN_NETIF_GSO_TYPE_NONE         (0)
+#define XEN_NETIF_GSO_TYPE_TCPV4        (1)
+#define XEN_NETIF_GSO_TYPE_TCPV6        (2)
 
 /*
- * This structure needs to fit within both netif_tx_request and
- * netif_rx_response for compatibility.
+ * This structure needs to fit within both xen_netif_tx_request_t and
+ * xen_netif_rx_response_t for compatibility.
  */
 struct xen_netif_extra_info {
-       uint8_t type;  /* XEN_NETIF_EXTRA_TYPE_* */
-       uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
-
+       uint8_t type;
+       uint8_t flags;
        union {
                struct {
-                       /*
-                        * Maximum payload size of each segment. For
-                        * example, for TCP this is just the path MSS.
-                        */
                        uint16_t size;
-
-                       /*
-                        * GSO type. This determines the protocol of
-                        * the packet and any extra features required
-                        * to segment the packet properly.
-                        */
-                       uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
-
-                       /* Future expansion. */
+                       uint8_t type;
                        uint8_t pad;
-
-                       /*
-                        * GSO features. This specifies any extra GSO
-                        * features required to process this packet,
-                        * such as ECN support for TCPv4.
-                        */
-                       uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
+                       uint16_t features;
                } gso;
-
                struct {
-                       uint8_t addr[6]; /* Address to add/remove. */
+                       uint8_t addr[6];
                } mcast;
-
+               struct {
+                       uint8_t type;
+                       uint8_t algorithm;
+                       uint8_t value[4];
+               } hash;
                uint16_t pad[3];
        } u;
 };
 
 struct xen_netif_tx_response {
        uint16_t id;
-       int16_t  status;       /* XEN_NETIF_RSP_* */
+       int16_t status;
 };
 
 struct xen_netif_rx_request {
-       uint16_t    id;        /* Echoed in response message.        */
-       grant_ref_t gref;      /* Reference to incoming granted frame */
+       uint16_t id;            /* Echoed in response message.        */
+       uint16_t pad;
+       grant_ref_t gref;
 };
 
 /* Packet data has been validated against protocol checksum. */
-#define _XEN_NETRXF_data_validated     (0)
-#define  XEN_NETRXF_data_validated     (1U<<_XEN_NETRXF_data_validated)
+#define _XEN_NETRXF_data_validated (0)
+#define  XEN_NETRXF_data_validated (1U<<_XEN_NETRXF_data_validated)
 
 /* Protocol checksum field is blank in the packet (hardware offload)? */
-#define _XEN_NETRXF_csum_blank         (1)
-#define  XEN_NETRXF_csum_blank         (1U<<_XEN_NETRXF_csum_blank)
+#define _XEN_NETRXF_csum_blank     (1)
+#define  XEN_NETRXF_csum_blank     (1U<<_XEN_NETRXF_csum_blank)
 
 /* Packet continues in the next request descriptor. */
-#define _XEN_NETRXF_more_data          (2)
-#define  XEN_NETRXF_more_data          (1U<<_XEN_NETRXF_more_data)
+#define _XEN_NETRXF_more_data      (2)
+#define  XEN_NETRXF_more_data      (1U<<_XEN_NETRXF_more_data)
 
 /* Packet to be followed by extra descriptor(s). */
-#define _XEN_NETRXF_extra_info         (3)
-#define  XEN_NETRXF_extra_info         (1U<<_XEN_NETRXF_extra_info)
+#define _XEN_NETRXF_extra_info     (3)
+#define  XEN_NETRXF_extra_info     (1U<<_XEN_NETRXF_extra_info)
 
-/* GSO Prefix descriptor. */
-#define _XEN_NETRXF_gso_prefix         (4)
-#define  XEN_NETRXF_gso_prefix         (1U<<_XEN_NETRXF_gso_prefix)
+/* Packet has GSO prefix. Deprecated but included for compatibility */
+#define _XEN_NETRXF_gso_prefix     (4)
+#define  XEN_NETRXF_gso_prefix     (1U<<_XEN_NETRXF_gso_prefix)
 
 struct xen_netif_rx_response {
-    uint16_t id;
-    uint16_t offset;       /* Offset in page of start of received packet  */
-    uint16_t flags;        /* XEN_NETRXF_* */
-    int16_t  status;       /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+       uint16_t id;
+       uint16_t offset;
+       uint16_t flags;
+       int16_t status;
 };
 
 /*
- * Generate netif ring structures and types.
+ * Generate xen_netif ring structures and types.
  */
 
-DEFINE_RING_TYPES(xen_netif_tx,
-                 struct xen_netif_tx_request,
+DEFINE_RING_TYPES(xen_netif_tx, struct xen_netif_tx_request,
                  struct xen_netif_tx_response);
-DEFINE_RING_TYPES(xen_netif_rx,
-                 struct xen_netif_rx_request,
+DEFINE_RING_TYPES(xen_netif_rx, struct xen_netif_rx_request,
                  struct xen_netif_rx_response);
 
-#define XEN_NETIF_RSP_DROPPED  -2
-#define XEN_NETIF_RSP_ERROR    -1
-#define XEN_NETIF_RSP_OKAY      0
-/* No response: used for auxiliary requests (e.g., xen_netif_extra_info). */
-#define XEN_NETIF_RSP_NULL      1
+#define XEN_NETIF_RSP_DROPPED         -2
+#define XEN_NETIF_RSP_ERROR           -1
+#define XEN_NETIF_RSP_OKAY             0
+/* No response: used for auxiliary requests (e.g., xen_netif_extra_info_t). */
+#define XEN_NETIF_RSP_NULL             1
 
 #endif
index ed3027d0f277a53745b41ea731c4783e3c554bee..331fc1b0b3c7952110f0223d741fc4fa19881d70 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -156,11 +156,12 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
        struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
 
        /*
-        * We raced in the idr lookup or with shm_destroy().  Either way, the
-        * ID is busted.
+        * Callers of shm_lock() must validate the status of the returned ipc
+        * object pointer (as returned by ipc_lock()), and error out as
+        * appropriate.
         */
-       WARN_ON(IS_ERR(ipcp));
-
+       if (IS_ERR(ipcp))
+               return (void *)ipcp;
        return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
@@ -186,18 +187,33 @@ static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
 }
 
 
-/* This is called by fork, once for every shm attach. */
-static void shm_open(struct vm_area_struct *vma)
+static int __shm_open(struct vm_area_struct *vma)
 {
        struct file *file = vma->vm_file;
        struct shm_file_data *sfd = shm_file_data(file);
        struct shmid_kernel *shp;
 
        shp = shm_lock(sfd->ns, sfd->id);
+
+       if (IS_ERR(shp))
+               return PTR_ERR(shp);
+
        shp->shm_atim = get_seconds();
        shp->shm_lprid = task_tgid_vnr(current);
        shp->shm_nattch++;
        shm_unlock(shp);
+       return 0;
+}
+
+/* This is called by fork, once for every shm attach. */
+static void shm_open(struct vm_area_struct *vma)
+{
+       int err = __shm_open(vma);
+       /*
+        * We raced in the idr lookup or with shm_destroy().
+        * Either way, the ID is busted.
+        */
+       WARN_ON_ONCE(err);
 }
 
 /*
@@ -260,6 +276,14 @@ static void shm_close(struct vm_area_struct *vma)
        down_write(&shm_ids(ns).rwsem);
        /* remove from the list of attaches of the shm segment */
        shp = shm_lock(ns, sfd->id);
+
+       /*
+        * We raced in the idr lookup or with shm_destroy().
+        * Either way, the ID is busted.
+        */
+       if (WARN_ON_ONCE(IS_ERR(shp)))
+               goto done; /* no-op */
+
        shp->shm_lprid = task_tgid_vnr(current);
        shp->shm_dtim = get_seconds();
        shp->shm_nattch--;
@@ -267,6 +291,7 @@ static void shm_close(struct vm_area_struct *vma)
                shm_destroy(ns, shp);
        else
                shm_unlock(shp);
+done:
        up_write(&shm_ids(ns).rwsem);
 }
 
@@ -388,17 +413,25 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma)
        struct shm_file_data *sfd = shm_file_data(file);
        int ret;
 
+       /*
+        * In case of remap_file_pages() emulation, the file can represent
+        * removed IPC ID: propogate shm_lock() error to caller.
+        */
+       ret =__shm_open(vma);
+       if (ret)
+               return ret;
+
        ret = sfd->file->f_op->mmap(sfd->file, vma);
-       if (ret != 0)
+       if (ret) {
+               shm_close(vma);
                return ret;
+       }
        sfd->vm_ops = vma->vm_ops;
 #ifdef CONFIG_MMU
        WARN_ON(!sfd->vm_ops->fault);
 #endif
        vma->vm_ops = &shm_vm_ops;
-       shm_open(vma);
-
-       return ret;
+       return 0;
 }
 
 static int shm_release(struct inode *ino, struct file *file)
index 13272582eee00099a45179d82b47556ea0eb3cf9..eed911d091dacebc429393e80120721fc6a8f110 100644 (file)
@@ -1,4 +1,7 @@
 obj-y := core.o
 
 obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o
-obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o
+obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o
+ifeq ($(CONFIG_PERF_EVENTS),y)
+obj-$(CONFIG_BPF_SYSCALL) += stackmap.o
+endif
index bd3bdf2486a7b1aa4744f2bd5045ff21e47812cd..76d5a794e4263bb9a57d2b4576b201173324d27f 100644 (file)
@@ -53,7 +53,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 
        /* check sanity of attributes */
        if (attr->max_entries == 0 || attr->key_size != 4 ||
-           attr->value_size == 0)
+           attr->value_size == 0 || attr->map_flags)
                return ERR_PTR(-EINVAL);
 
        if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
index fd5db8fe9360db2134339d3e3f4ec47032d42772..fff3650d52fc774f7efdf2d289e879a916f44c60 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ * Copyright (c) 2016 Facebook
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
@@ -13,6 +14,7 @@
 #include <linux/jhash.h>
 #include <linux/filter.h>
 #include <linux/vmalloc.h>
+#include "percpu_freelist.h"
 
 struct bucket {
        struct hlist_head head;
@@ -22,6 +24,8 @@ struct bucket {
 struct bpf_htab {
        struct bpf_map map;
        struct bucket *buckets;
+       void *elems;
+       struct pcpu_freelist freelist;
        atomic_t count; /* number of elements in this hashtable */
        u32 n_buckets;  /* number of hash buckets */
        u32 elem_size;  /* size of each element in bytes */
@@ -29,15 +33,86 @@ struct bpf_htab {
 
 /* each htab element is struct htab_elem + key + value */
 struct htab_elem {
-       struct hlist_node hash_node;
-       struct rcu_head rcu;
        union {
-               u32 hash;
-               u32 key_size;
+               struct hlist_node hash_node;
+               struct bpf_htab *htab;
+               struct pcpu_freelist_node fnode;
        };
+       struct rcu_head rcu;
+       u32 hash;
        char key[0] __aligned(8);
 };
 
+static inline void htab_elem_set_ptr(struct htab_elem *l, u32 key_size,
+                                    void __percpu *pptr)
+{
+       *(void __percpu **)(l->key + key_size) = pptr;
+}
+
+static inline void __percpu *htab_elem_get_ptr(struct htab_elem *l, u32 key_size)
+{
+       return *(void __percpu **)(l->key + key_size);
+}
+
+static struct htab_elem *get_htab_elem(struct bpf_htab *htab, int i)
+{
+       return (struct htab_elem *) (htab->elems + i * htab->elem_size);
+}
+
+static void htab_free_elems(struct bpf_htab *htab)
+{
+       int i;
+
+       if (htab->map.map_type != BPF_MAP_TYPE_PERCPU_HASH)
+               goto free_elems;
+
+       for (i = 0; i < htab->map.max_entries; i++) {
+               void __percpu *pptr;
+
+               pptr = htab_elem_get_ptr(get_htab_elem(htab, i),
+                                        htab->map.key_size);
+               free_percpu(pptr);
+       }
+free_elems:
+       vfree(htab->elems);
+}
+
+static int prealloc_elems_and_freelist(struct bpf_htab *htab)
+{
+       int err = -ENOMEM, i;
+
+       htab->elems = vzalloc(htab->elem_size * htab->map.max_entries);
+       if (!htab->elems)
+               return -ENOMEM;
+
+       if (htab->map.map_type != BPF_MAP_TYPE_PERCPU_HASH)
+               goto skip_percpu_elems;
+
+       for (i = 0; i < htab->map.max_entries; i++) {
+               u32 size = round_up(htab->map.value_size, 8);
+               void __percpu *pptr;
+
+               pptr = __alloc_percpu_gfp(size, 8, GFP_USER | __GFP_NOWARN);
+               if (!pptr)
+                       goto free_elems;
+               htab_elem_set_ptr(get_htab_elem(htab, i), htab->map.key_size,
+                                 pptr);
+       }
+
+skip_percpu_elems:
+       err = pcpu_freelist_init(&htab->freelist);
+       if (err)
+               goto free_elems;
+
+       pcpu_freelist_populate(&htab->freelist, htab->elems, htab->elem_size,
+                              htab->map.max_entries);
+       return 0;
+
+free_elems:
+       htab_free_elems(htab);
+       return err;
+}
+
 /* Called from syscall */
 static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
 {
@@ -46,6 +121,10 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
        int err, i;
        u64 cost;
 
+       if (attr->map_flags & ~BPF_F_NO_PREALLOC)
+               /* reserved bits should not be used */
+               return ERR_PTR(-EINVAL);
+
        htab = kzalloc(sizeof(*htab), GFP_USER);
        if (!htab)
                return ERR_PTR(-ENOMEM);
@@ -55,6 +134,7 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
        htab->map.key_size = attr->key_size;
        htab->map.value_size = attr->value_size;
        htab->map.max_entries = attr->max_entries;
+       htab->map.map_flags = attr->map_flags;
 
        /* check sanity of attributes.
         * value_size == 0 may be allowed in the future to use map as a set
@@ -92,7 +172,7 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
        if (percpu)
                htab->elem_size += sizeof(void *);
        else
-               htab->elem_size += htab->map.value_size;
+               htab->elem_size += round_up(htab->map.value_size, 8);
 
        /* prevent zero size kmalloc and check for u32 overflow */
        if (htab->n_buckets == 0 ||
@@ -112,6 +192,11 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
 
        htab->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
 
+       /* if map size is larger than memlock limit, reject it early */
+       err = bpf_map_precharge_memlock(htab->map.pages);
+       if (err)
+               goto free_htab;
+
        err = -ENOMEM;
        htab->buckets = kmalloc_array(htab->n_buckets, sizeof(struct bucket),
                                      GFP_USER | __GFP_NOWARN);
@@ -127,10 +212,16 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
                raw_spin_lock_init(&htab->buckets[i].lock);
        }
 
-       atomic_set(&htab->count, 0);
+       if (!(attr->map_flags & BPF_F_NO_PREALLOC)) {
+               err = prealloc_elems_and_freelist(htab);
+               if (err)
+                       goto free_buckets;
+       }
 
        return &htab->map;
 
+free_buckets:
+       kvfree(htab->buckets);
 free_htab:
        kfree(htab);
        return ERR_PTR(err);
@@ -249,42 +340,42 @@ find_first_elem:
                }
        }
 
-       /* itereated over all buckets and all elements */
+       /* iterated over all buckets and all elements */
        return -ENOENT;
 }
 
-
-static inline void htab_elem_set_ptr(struct htab_elem *l, u32 key_size,
-                                    void __percpu *pptr)
+static void htab_elem_free(struct bpf_htab *htab, struct htab_elem *l)
 {
-       *(void __percpu **)(l->key + key_size) = pptr;
-}
-
-static inline void __percpu *htab_elem_get_ptr(struct htab_elem *l, u32 key_size)
-{
-       return *(void __percpu **)(l->key + key_size);
-}
-
-static void htab_percpu_elem_free(struct htab_elem *l)
-{
-       free_percpu(htab_elem_get_ptr(l, l->key_size));
+       if (htab->map.map_type == BPF_MAP_TYPE_PERCPU_HASH)
+               free_percpu(htab_elem_get_ptr(l, htab->map.key_size));
        kfree(l);
+
 }
 
-static void htab_percpu_elem_free_rcu(struct rcu_head *head)
+static void htab_elem_free_rcu(struct rcu_head *head)
 {
        struct htab_elem *l = container_of(head, struct htab_elem, rcu);
+       struct bpf_htab *htab = l->htab;
 
-       htab_percpu_elem_free(l);
+       /* must increment bpf_prog_active to avoid kprobe+bpf triggering while
+        * we're calling kfree, otherwise deadlock is possible if kprobes
+        * are placed somewhere inside of slub
+        */
+       preempt_disable();
+       __this_cpu_inc(bpf_prog_active);
+       htab_elem_free(htab, l);
+       __this_cpu_dec(bpf_prog_active);
+       preempt_enable();
 }
 
-static void free_htab_elem(struct htab_elem *l, bool percpu, u32 key_size)
+static void free_htab_elem(struct bpf_htab *htab, struct htab_elem *l)
 {
-       if (percpu) {
-               l->key_size = key_size;
-               call_rcu(&l->rcu, htab_percpu_elem_free_rcu);
+       if (!(htab->map.map_flags & BPF_F_NO_PREALLOC)) {
+               pcpu_freelist_push(&htab->freelist, &l->fnode);
        } else {
-               kfree_rcu(l, rcu);
+               atomic_dec(&htab->count);
+               l->htab = htab;
+               call_rcu(&l->rcu, htab_elem_free_rcu);
        }
 }
 
@@ -293,23 +384,39 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
                                         bool percpu, bool onallcpus)
 {
        u32 size = htab->map.value_size;
+       bool prealloc = !(htab->map.map_flags & BPF_F_NO_PREALLOC);
        struct htab_elem *l_new;
        void __percpu *pptr;
 
-       l_new = kmalloc(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN);
-       if (!l_new)
-               return NULL;
+       if (prealloc) {
+               l_new = (struct htab_elem *)pcpu_freelist_pop(&htab->freelist);
+               if (!l_new)
+                       return ERR_PTR(-E2BIG);
+       } else {
+               if (atomic_inc_return(&htab->count) > htab->map.max_entries) {
+                       atomic_dec(&htab->count);
+                       return ERR_PTR(-E2BIG);
+               }
+               l_new = kmalloc(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN);
+               if (!l_new)
+                       return ERR_PTR(-ENOMEM);
+       }
 
        memcpy(l_new->key, key, key_size);
        if (percpu) {
                /* round up value_size to 8 bytes */
                size = round_up(size, 8);
 
-               /* alloc_percpu zero-fills */
-               pptr = __alloc_percpu_gfp(size, 8, GFP_ATOMIC | __GFP_NOWARN);
-               if (!pptr) {
-                       kfree(l_new);
-                       return NULL;
+               if (prealloc) {
+                       pptr = htab_elem_get_ptr(l_new, key_size);
+               } else {
+                       /* alloc_percpu zero-fills */
+                       pptr = __alloc_percpu_gfp(size, 8,
+                                                 GFP_ATOMIC | __GFP_NOWARN);
+                       if (!pptr) {
+                               kfree(l_new);
+                               return ERR_PTR(-ENOMEM);
+                       }
                }
 
                if (!onallcpus) {
@@ -324,7 +431,8 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
                                off += size;
                        }
                }
-               htab_elem_set_ptr(l_new, key_size, pptr);
+               if (!prealloc)
+                       htab_elem_set_ptr(l_new, key_size, pptr);
        } else {
                memcpy(l_new->key + round_up(key_size, 8), value, size);
        }
@@ -336,12 +444,6 @@ static struct htab_elem *alloc_htab_elem(struct bpf_htab *htab, void *key,
 static int check_flags(struct bpf_htab *htab, struct htab_elem *l_old,
                       u64 map_flags)
 {
-       if (!l_old && unlikely(atomic_read(&htab->count) >= htab->map.max_entries))
-               /* if elem with this 'key' doesn't exist and we've reached
-                * max_entries limit, fail insertion of new elem
-                */
-               return -E2BIG;
-
        if (l_old && map_flags == BPF_NOEXIST)
                /* elem already exists */
                return -EEXIST;
@@ -375,13 +477,6 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,
 
        hash = htab_map_hash(key, key_size);
 
-       /* allocate new element outside of the lock, since
-        * we're most likley going to insert it
-        */
-       l_new = alloc_htab_elem(htab, key, value, key_size, hash, false, false);
-       if (!l_new)
-               return -ENOMEM;
-
        b = __select_bucket(htab, hash);
        head = &b->head;
 
@@ -394,21 +489,24 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,
        if (ret)
                goto err;
 
+       l_new = alloc_htab_elem(htab, key, value, key_size, hash, false, false);
+       if (IS_ERR(l_new)) {
+               /* all pre-allocated elements are in use or memory exhausted */
+               ret = PTR_ERR(l_new);
+               goto err;
+       }
+
        /* add new element to the head of the list, so that
         * concurrent search will find it before old elem
         */
        hlist_add_head_rcu(&l_new->hash_node, head);
        if (l_old) {
                hlist_del_rcu(&l_old->hash_node);
-               kfree_rcu(l_old, rcu);
-       } else {
-               atomic_inc(&htab->count);
+               free_htab_elem(htab, l_old);
        }
-       raw_spin_unlock_irqrestore(&b->lock, flags);
-       return 0;
+       ret = 0;
 err:
        raw_spin_unlock_irqrestore(&b->lock, flags);
-       kfree(l_new);
        return ret;
 }
 
@@ -466,12 +564,11 @@ static int __htab_percpu_map_update_elem(struct bpf_map *map, void *key,
        } else {
                l_new = alloc_htab_elem(htab, key, value, key_size,
                                        hash, true, onallcpus);
-               if (!l_new) {
-                       ret = -ENOMEM;
+               if (IS_ERR(l_new)) {
+                       ret = PTR_ERR(l_new);
                        goto err;
                }
                hlist_add_head_rcu(&l_new->hash_node, head);
-               atomic_inc(&htab->count);
        }
        ret = 0;
 err:
@@ -489,7 +586,6 @@ static int htab_percpu_map_update_elem(struct bpf_map *map, void *key,
 static int htab_map_delete_elem(struct bpf_map *map, void *key)
 {
        struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
-       bool percpu = map->map_type == BPF_MAP_TYPE_PERCPU_HASH;
        struct hlist_head *head;
        struct bucket *b;
        struct htab_elem *l;
@@ -511,8 +607,7 @@ static int htab_map_delete_elem(struct bpf_map *map, void *key)
 
        if (l) {
                hlist_del_rcu(&l->hash_node);
-               atomic_dec(&htab->count);
-               free_htab_elem(l, percpu, key_size);
+               free_htab_elem(htab, l);
                ret = 0;
        }
 
@@ -531,17 +626,10 @@ static void delete_all_elements(struct bpf_htab *htab)
 
                hlist_for_each_entry_safe(l, n, head, hash_node) {
                        hlist_del_rcu(&l->hash_node);
-                       atomic_dec(&htab->count);
-                       if (htab->map.map_type == BPF_MAP_TYPE_PERCPU_HASH) {
-                               l->key_size = htab->map.key_size;
-                               htab_percpu_elem_free(l);
-                       } else {
-                               kfree(l);
-                       }
+                       htab_elem_free(htab, l);
                }
        }
 }
-
 /* Called when map->refcnt goes to zero, either from workqueue or from syscall */
 static void htab_map_free(struct bpf_map *map)
 {
@@ -554,10 +642,16 @@ static void htab_map_free(struct bpf_map *map)
         */
        synchronize_rcu();
 
-       /* some of kfree_rcu() callbacks for elements of this map may not have
-        * executed. It's ok. Proceed to free residual elements and map itself
+       /* some of free_htab_elem() callbacks for elements of this map may
+        * not have executed. Wait for them.
         */
-       delete_all_elements(htab);
+       rcu_barrier();
+       if (htab->map.map_flags & BPF_F_NO_PREALLOC) {
+               delete_all_elements(htab);
+       } else {
+               htab_free_elems(htab);
+               pcpu_freelist_destroy(&htab->freelist);
+       }
        kvfree(htab->buckets);
        kfree(htab);
 }
@@ -619,7 +713,13 @@ out:
 int bpf_percpu_hash_update(struct bpf_map *map, void *key, void *value,
                           u64 map_flags)
 {
-       return __htab_percpu_map_update_elem(map, key, value, map_flags, true);
+       int ret;
+
+       rcu_read_lock();
+       ret = __htab_percpu_map_update_elem(map, key, value, map_flags, true);
+       rcu_read_unlock();
+
+       return ret;
 }
 
 static const struct bpf_map_ops htab_percpu_ops = {
index 4504ca66118da0c0735bdb56d9204ba6cb79994b..50da680c479f030588314ed664c8d57200c28990 100644 (file)
@@ -166,7 +166,7 @@ static u64 bpf_get_current_comm(u64 r1, u64 size, u64 r3, u64 r4, u64 r5)
        if (!task)
                return -EINVAL;
 
-       memcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
+       strlcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
        return 0;
 }
 
diff --git a/kernel/bpf/percpu_freelist.c b/kernel/bpf/percpu_freelist.c
new file mode 100644 (file)
index 0000000..5c51d19
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#include "percpu_freelist.h"
+
+int pcpu_freelist_init(struct pcpu_freelist *s)
+{
+       int cpu;
+
+       s->freelist = alloc_percpu(struct pcpu_freelist_head);
+       if (!s->freelist)
+               return -ENOMEM;
+
+       for_each_possible_cpu(cpu) {
+               struct pcpu_freelist_head *head = per_cpu_ptr(s->freelist, cpu);
+
+               raw_spin_lock_init(&head->lock);
+               head->first = NULL;
+       }
+       return 0;
+}
+
+void pcpu_freelist_destroy(struct pcpu_freelist *s)
+{
+       free_percpu(s->freelist);
+}
+
+static inline void __pcpu_freelist_push(struct pcpu_freelist_head *head,
+                                       struct pcpu_freelist_node *node)
+{
+       raw_spin_lock(&head->lock);
+       node->next = head->first;
+       head->first = node;
+       raw_spin_unlock(&head->lock);
+}
+
+void pcpu_freelist_push(struct pcpu_freelist *s,
+                       struct pcpu_freelist_node *node)
+{
+       struct pcpu_freelist_head *head = this_cpu_ptr(s->freelist);
+
+       __pcpu_freelist_push(head, node);
+}
+
+void pcpu_freelist_populate(struct pcpu_freelist *s, void *buf, u32 elem_size,
+                           u32 nr_elems)
+{
+       struct pcpu_freelist_head *head;
+       unsigned long flags;
+       int i, cpu, pcpu_entries;
+
+       pcpu_entries = nr_elems / num_possible_cpus() + 1;
+       i = 0;
+
+       /* disable irq to workaround lockdep false positive
+        * in bpf usage pcpu_freelist_populate() will never race
+        * with pcpu_freelist_push()
+        */
+       local_irq_save(flags);
+       for_each_possible_cpu(cpu) {
+again:
+               head = per_cpu_ptr(s->freelist, cpu);
+               __pcpu_freelist_push(head, buf);
+               i++;
+               buf += elem_size;
+               if (i == nr_elems)
+                       break;
+               if (i % pcpu_entries)
+                       goto again;
+       }
+       local_irq_restore(flags);
+}
+
+struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *s)
+{
+       struct pcpu_freelist_head *head;
+       struct pcpu_freelist_node *node;
+       int orig_cpu, cpu;
+
+       orig_cpu = cpu = raw_smp_processor_id();
+       while (1) {
+               head = per_cpu_ptr(s->freelist, cpu);
+               raw_spin_lock(&head->lock);
+               node = head->first;
+               if (node) {
+                       head->first = node->next;
+                       raw_spin_unlock(&head->lock);
+                       return node;
+               }
+               raw_spin_unlock(&head->lock);
+               cpu = cpumask_next(cpu, cpu_possible_mask);
+               if (cpu >= nr_cpu_ids)
+                       cpu = 0;
+               if (cpu == orig_cpu)
+                       return NULL;
+       }
+}
diff --git a/kernel/bpf/percpu_freelist.h b/kernel/bpf/percpu_freelist.h
new file mode 100644 (file)
index 0000000..3049aae
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#ifndef __PERCPU_FREELIST_H__
+#define __PERCPU_FREELIST_H__
+#include <linux/spinlock.h>
+#include <linux/percpu.h>
+
+struct pcpu_freelist_head {
+       struct pcpu_freelist_node *first;
+       raw_spinlock_t lock;
+};
+
+struct pcpu_freelist {
+       struct pcpu_freelist_head __percpu *freelist;
+};
+
+struct pcpu_freelist_node {
+       struct pcpu_freelist_node *next;
+};
+
+void pcpu_freelist_push(struct pcpu_freelist *, struct pcpu_freelist_node *);
+struct pcpu_freelist_node *pcpu_freelist_pop(struct pcpu_freelist *);
+void pcpu_freelist_populate(struct pcpu_freelist *s, void *buf, u32 elem_size,
+                           u32 nr_elems);
+int pcpu_freelist_init(struct pcpu_freelist *);
+void pcpu_freelist_destroy(struct pcpu_freelist *s);
+#endif
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
new file mode 100644 (file)
index 0000000..499d9e9
--- /dev/null
@@ -0,0 +1,290 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#include <linux/bpf.h>
+#include <linux/jhash.h>
+#include <linux/filter.h>
+#include <linux/vmalloc.h>
+#include <linux/stacktrace.h>
+#include <linux/perf_event.h>
+#include "percpu_freelist.h"
+
+struct stack_map_bucket {
+       struct pcpu_freelist_node fnode;
+       u32 hash;
+       u32 nr;
+       u64 ip[];
+};
+
+struct bpf_stack_map {
+       struct bpf_map map;
+       void *elems;
+       struct pcpu_freelist freelist;
+       u32 n_buckets;
+       struct stack_map_bucket *buckets[];
+};
+
+static int prealloc_elems_and_freelist(struct bpf_stack_map *smap)
+{
+       u32 elem_size = sizeof(struct stack_map_bucket) + smap->map.value_size;
+       int err;
+
+       smap->elems = vzalloc(elem_size * smap->map.max_entries);
+       if (!smap->elems)
+               return -ENOMEM;
+
+       err = pcpu_freelist_init(&smap->freelist);
+       if (err)
+               goto free_elems;
+
+       pcpu_freelist_populate(&smap->freelist, smap->elems, elem_size,
+                              smap->map.max_entries);
+       return 0;
+
+free_elems:
+       vfree(smap->elems);
+       return err;
+}
+
+/* Called from syscall */
+static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
+{
+       u32 value_size = attr->value_size;
+       struct bpf_stack_map *smap;
+       u64 cost, n_buckets;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return ERR_PTR(-EPERM);
+
+       if (attr->map_flags)
+               return ERR_PTR(-EINVAL);
+
+       /* check sanity of attributes */
+       if (attr->max_entries == 0 || attr->key_size != 4 ||
+           value_size < 8 || value_size % 8 ||
+           value_size / 8 > PERF_MAX_STACK_DEPTH)
+               return ERR_PTR(-EINVAL);
+
+       /* hash table size must be power of 2 */
+       n_buckets = roundup_pow_of_two(attr->max_entries);
+
+       cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap);
+       if (cost >= U32_MAX - PAGE_SIZE)
+               return ERR_PTR(-E2BIG);
+
+       smap = kzalloc(cost, GFP_USER | __GFP_NOWARN);
+       if (!smap) {
+               smap = vzalloc(cost);
+               if (!smap)
+                       return ERR_PTR(-ENOMEM);
+       }
+
+       err = -E2BIG;
+       cost += n_buckets * (value_size + sizeof(struct stack_map_bucket));
+       if (cost >= U32_MAX - PAGE_SIZE)
+               goto free_smap;
+
+       smap->map.map_type = attr->map_type;
+       smap->map.key_size = attr->key_size;
+       smap->map.value_size = value_size;
+       smap->map.max_entries = attr->max_entries;
+       smap->n_buckets = n_buckets;
+       smap->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
+
+       err = bpf_map_precharge_memlock(smap->map.pages);
+       if (err)
+               goto free_smap;
+
+       err = get_callchain_buffers();
+       if (err)
+               goto free_smap;
+
+       err = prealloc_elems_and_freelist(smap);
+       if (err)
+               goto put_buffers;
+
+       return &smap->map;
+
+put_buffers:
+       put_callchain_buffers();
+free_smap:
+       kvfree(smap);
+       return ERR_PTR(err);
+}
+
+static u64 bpf_get_stackid(u64 r1, u64 r2, u64 flags, u64 r4, u64 r5)
+{
+       struct pt_regs *regs = (struct pt_regs *) (long) r1;
+       struct bpf_map *map = (struct bpf_map *) (long) r2;
+       struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+       struct perf_callchain_entry *trace;
+       struct stack_map_bucket *bucket, *new_bucket, *old_bucket;
+       u32 max_depth = map->value_size / 8;
+       /* stack_map_alloc() checks that max_depth <= PERF_MAX_STACK_DEPTH */
+       u32 init_nr = PERF_MAX_STACK_DEPTH - max_depth;
+       u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
+       u32 hash, id, trace_nr, trace_len;
+       bool user = flags & BPF_F_USER_STACK;
+       bool kernel = !user;
+       u64 *ips;
+
+       if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
+                              BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID)))
+               return -EINVAL;
+
+       trace = get_perf_callchain(regs, init_nr, kernel, user, false, false);
+
+       if (unlikely(!trace))
+               /* couldn't fetch the stack trace */
+               return -EFAULT;
+
+       /* get_perf_callchain() guarantees that trace->nr >= init_nr
+        * and trace-nr <= PERF_MAX_STACK_DEPTH, so trace_nr <= max_depth
+        */
+       trace_nr = trace->nr - init_nr;
+
+       if (trace_nr <= skip)
+               /* skipping more than usable stack trace */
+               return -EFAULT;
+
+       trace_nr -= skip;
+       trace_len = trace_nr * sizeof(u64);
+       ips = trace->ip + skip + init_nr;
+       hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0);
+       id = hash & (smap->n_buckets - 1);
+       bucket = READ_ONCE(smap->buckets[id]);
+
+       if (bucket && bucket->hash == hash) {
+               if (flags & BPF_F_FAST_STACK_CMP)
+                       return id;
+               if (bucket->nr == trace_nr &&
+                   memcmp(bucket->ip, ips, trace_len) == 0)
+                       return id;
+       }
+
+       /* this call stack is not in the map, try to add it */
+       if (bucket && !(flags & BPF_F_REUSE_STACKID))
+               return -EEXIST;
+
+       new_bucket = (struct stack_map_bucket *)
+               pcpu_freelist_pop(&smap->freelist);
+       if (unlikely(!new_bucket))
+               return -ENOMEM;
+
+       memcpy(new_bucket->ip, ips, trace_len);
+       new_bucket->hash = hash;
+       new_bucket->nr = trace_nr;
+
+       old_bucket = xchg(&smap->buckets[id], new_bucket);
+       if (old_bucket)
+               pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
+       return id;
+}
+
+const struct bpf_func_proto bpf_get_stackid_proto = {
+       .func           = bpf_get_stackid,
+       .gpl_only       = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_CONST_MAP_PTR,
+       .arg3_type      = ARG_ANYTHING,
+};
+
+/* Called from eBPF program */
+static void *stack_map_lookup_elem(struct bpf_map *map, void *key)
+{
+       return NULL;
+}
+
+/* Called from syscall */
+int bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
+{
+       struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+       struct stack_map_bucket *bucket, *old_bucket;
+       u32 id = *(u32 *)key, trace_len;
+
+       if (unlikely(id >= smap->n_buckets))
+               return -ENOENT;
+
+       bucket = xchg(&smap->buckets[id], NULL);
+       if (!bucket)
+               return -ENOENT;
+
+       trace_len = bucket->nr * sizeof(u64);
+       memcpy(value, bucket->ip, trace_len);
+       memset(value + trace_len, 0, map->value_size - trace_len);
+
+       old_bucket = xchg(&smap->buckets[id], bucket);
+       if (old_bucket)
+               pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
+       return 0;
+}
+
+static int stack_map_get_next_key(struct bpf_map *map, void *key, void *next_key)
+{
+       return -EINVAL;
+}
+
+static int stack_map_update_elem(struct bpf_map *map, void *key, void *value,
+                                u64 map_flags)
+{
+       return -EINVAL;
+}
+
+/* Called from syscall or from eBPF program */
+static int stack_map_delete_elem(struct bpf_map *map, void *key)
+{
+       struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+       struct stack_map_bucket *old_bucket;
+       u32 id = *(u32 *)key;
+
+       if (unlikely(id >= smap->n_buckets))
+               return -E2BIG;
+
+       old_bucket = xchg(&smap->buckets[id], NULL);
+       if (old_bucket) {
+               pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
+               return 0;
+       } else {
+               return -ENOENT;
+       }
+}
+
+/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
+static void stack_map_free(struct bpf_map *map)
+{
+       struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
+
+       /* wait for bpf programs to complete before freeing stack map */
+       synchronize_rcu();
+
+       vfree(smap->elems);
+       pcpu_freelist_destroy(&smap->freelist);
+       kvfree(smap);
+       put_callchain_buffers();
+}
+
+static const struct bpf_map_ops stack_map_ops = {
+       .map_alloc = stack_map_alloc,
+       .map_free = stack_map_free,
+       .map_get_next_key = stack_map_get_next_key,
+       .map_lookup_elem = stack_map_lookup_elem,
+       .map_update_elem = stack_map_update_elem,
+       .map_delete_elem = stack_map_delete_elem,
+};
+
+static struct bpf_map_type_list stack_map_type __read_mostly = {
+       .ops = &stack_map_ops,
+       .type = BPF_MAP_TYPE_STACK_TRACE,
+};
+
+static int __init register_stack_map(void)
+{
+       bpf_register_map_type(&stack_map_type);
+       return 0;
+}
+late_initcall(register_stack_map);
index c95a753c2007966a752c2c2a5eda00e6a0a39072..2a2efe1bc76c7a2ef2e0a4af3ebec7f988a4b4a6 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/filter.h>
 #include <linux/version.h>
 
+DEFINE_PER_CPU(int, bpf_prog_active);
+
 int sysctl_unprivileged_bpf_disabled __read_mostly;
 
 static LIST_HEAD(bpf_map_types);
@@ -46,6 +48,19 @@ void bpf_register_map_type(struct bpf_map_type_list *tl)
        list_add(&tl->list_node, &bpf_map_types);
 }
 
+int bpf_map_precharge_memlock(u32 pages)
+{
+       struct user_struct *user = get_current_user();
+       unsigned long memlock_limit, cur;
+
+       memlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+       cur = atomic_long_read(&user->locked_vm);
+       free_uid(user);
+       if (cur + pages > memlock_limit)
+               return -EPERM;
+       return 0;
+}
+
 static int bpf_map_charge_memlock(struct bpf_map *map)
 {
        struct user_struct *user = get_current_user();
@@ -151,7 +166,7 @@ int bpf_map_new_fd(struct bpf_map *map)
                   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
                   sizeof(attr->CMD##_LAST_FIELD)) != NULL
 
-#define BPF_MAP_CREATE_LAST_FIELD max_entries
+#define BPF_MAP_CREATE_LAST_FIELD map_flags
 /* called via syscall */
 static int map_create(union bpf_attr *attr)
 {
@@ -229,6 +244,11 @@ static void __user *u64_to_ptr(__u64 val)
        return (void __user *) (unsigned long) val;
 }
 
+int __weak bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
+{
+       return -ENOTSUPP;
+}
+
 /* last field in 'union bpf_attr' used by this command */
 #define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
 
@@ -275,6 +295,8 @@ static int map_lookup_elem(union bpf_attr *attr)
                err = bpf_percpu_hash_copy(map, key, value);
        } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
                err = bpf_percpu_array_copy(map, key, value);
+       } else if (map->map_type == BPF_MAP_TYPE_STACK_TRACE) {
+               err = bpf_stackmap_copy(map, key, value);
        } else {
                rcu_read_lock();
                ptr = map->ops->map_lookup_elem(map, key);
@@ -347,6 +369,11 @@ static int map_update_elem(union bpf_attr *attr)
        if (copy_from_user(value, uvalue, value_size) != 0)
                goto free_value;
 
+       /* must increment bpf_prog_active to avoid kprobe+bpf triggering from
+        * inside bpf map update or delete otherwise deadlocks are possible
+        */
+       preempt_disable();
+       __this_cpu_inc(bpf_prog_active);
        if (map->map_type == BPF_MAP_TYPE_PERCPU_HASH) {
                err = bpf_percpu_hash_update(map, key, value, attr->flags);
        } else if (map->map_type == BPF_MAP_TYPE_PERCPU_ARRAY) {
@@ -356,6 +383,8 @@ static int map_update_elem(union bpf_attr *attr)
                err = map->ops->map_update_elem(map, key, value, attr->flags);
                rcu_read_unlock();
        }
+       __this_cpu_dec(bpf_prog_active);
+       preempt_enable();
 
 free_value:
        kfree(value);
@@ -394,9 +423,13 @@ static int map_delete_elem(union bpf_attr *attr)
        if (copy_from_user(key, ukey, map->key_size) != 0)
                goto free_key;
 
+       preempt_disable();
+       __this_cpu_inc(bpf_prog_active);
        rcu_read_lock();
        err = map->ops->map_delete_elem(map, key);
        rcu_read_unlock();
+       __this_cpu_dec(bpf_prog_active);
+       preempt_enable();
 
 free_key:
        kfree(key);
index d1d3e8f57de907764fe3080632062485f5639443..2e08f8e9b771f032a17e0305c60fcd6f0403e6f5 100644 (file)
@@ -246,6 +246,7 @@ static const struct {
        {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call},
        {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read},
        {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output},
+       {BPF_MAP_TYPE_STACK_TRACE, BPF_FUNC_get_stackid},
 };
 
 static void print_verifier_state(struct verifier_env *env)
@@ -778,15 +779,24 @@ static int check_xadd(struct verifier_env *env, struct bpf_insn *insn)
  * bytes from that pointer, make sure that it's within stack boundary
  * and all elements of stack are initialized
  */
-static int check_stack_boundary(struct verifier_env *env,
-                               int regno, int access_size)
+static int check_stack_boundary(struct verifier_env *env, int regno,
+                               int access_size, bool zero_size_allowed)
 {
        struct verifier_state *state = &env->cur_state;
        struct reg_state *regs = state->regs;
        int off, i;
 
-       if (regs[regno].type != PTR_TO_STACK)
+       if (regs[regno].type != PTR_TO_STACK) {
+               if (zero_size_allowed && access_size == 0 &&
+                   regs[regno].type == CONST_IMM &&
+                   regs[regno].imm  == 0)
+                       return 0;
+
+               verbose("R%d type=%s expected=%s\n", regno,
+                       reg_type_str[regs[regno].type],
+                       reg_type_str[PTR_TO_STACK]);
                return -EACCES;
+       }
 
        off = regs[regno].imm;
        if (off >= 0 || off < -MAX_BPF_STACK || off + access_size > 0 ||
@@ -829,15 +839,24 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                return 0;
        }
 
-       if (arg_type == ARG_PTR_TO_STACK || arg_type == ARG_PTR_TO_MAP_KEY ||
+       if (arg_type == ARG_PTR_TO_MAP_KEY ||
            arg_type == ARG_PTR_TO_MAP_VALUE) {
                expected_type = PTR_TO_STACK;
-       } else if (arg_type == ARG_CONST_STACK_SIZE) {
+       } else if (arg_type == ARG_CONST_STACK_SIZE ||
+                  arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
                expected_type = CONST_IMM;
        } else if (arg_type == ARG_CONST_MAP_PTR) {
                expected_type = CONST_PTR_TO_MAP;
        } else if (arg_type == ARG_PTR_TO_CTX) {
                expected_type = PTR_TO_CTX;
+       } else if (arg_type == ARG_PTR_TO_STACK) {
+               expected_type = PTR_TO_STACK;
+               /* One exception here. In case function allows for NULL to be
+                * passed in as argument, it's a CONST_IMM type. Final test
+                * happens during stack boundary checking.
+                */
+               if (reg->type == CONST_IMM && reg->imm == 0)
+                       expected_type = CONST_IMM;
        } else {
                verbose("unsupported arg_type %d\n", arg_type);
                return -EFAULT;
@@ -867,8 +886,8 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                        verbose("invalid map_ptr to access map->key\n");
                        return -EACCES;
                }
-               err = check_stack_boundary(env, regno, (*mapp)->key_size);
-
+               err = check_stack_boundary(env, regno, (*mapp)->key_size,
+                                          false);
        } else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
                /* bpf_map_xxx(..., map_ptr, ..., value) call:
                 * check [value, value + map->value_size) validity
@@ -878,9 +897,12 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                        verbose("invalid map_ptr to access map->value\n");
                        return -EACCES;
                }
-               err = check_stack_boundary(env, regno, (*mapp)->value_size);
+               err = check_stack_boundary(env, regno, (*mapp)->value_size,
+                                          false);
+       } else if (arg_type == ARG_CONST_STACK_SIZE ||
+                  arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
+               bool zero_size_allowed = (arg_type == ARG_CONST_STACK_SIZE_OR_ZERO);
 
-       } else if (arg_type == ARG_CONST_STACK_SIZE) {
                /* bpf_xxx(..., buf, len) call will access 'len' bytes
                 * from stack pointer 'buf'. Check it
                 * note: regno == len, regno - 1 == buf
@@ -890,7 +912,8 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
                        verbose("ARG_CONST_STACK_SIZE cannot be first argument\n");
                        return -EACCES;
                }
-               err = check_stack_boundary(env, regno - 1, reg->imm);
+               err = check_stack_boundary(env, regno - 1, reg->imm,
+                                          zero_size_allowed);
        }
 
        return err;
@@ -911,8 +934,11 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id)
                 * don't allow any other map type to be passed into
                 * the special func;
                 */
-               if (bool_func && bool_map != bool_func)
+               if (bool_func && bool_map != bool_func) {
+                       verbose("cannot pass map_type %d into func %d\n",
+                               map->map_type, func_id);
                        return -EINVAL;
+               }
        }
 
        return 0;
@@ -2082,7 +2108,7 @@ static void adjust_branches(struct bpf_prog *prog, int pos, int delta)
                /* adjust offset of jmps if necessary */
                if (i < pos && i + insn->off + 1 > pos)
                        insn->off += delta;
-               else if (i > pos && i + insn->off + 1 < pos)
+               else if (i > pos + delta && i + insn->off + 1 <= pos + delta)
                        insn->off -= delta;
        }
 }
index c03a640ef6da265db01b93c2970ab6b2da7abd67..d27904c193daa1d8a8680522093254cfde376177 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/atomic.h>
+#include <linux/cpuset.h>
 #include <net/sock.h>
 
 /*
@@ -2739,6 +2740,7 @@ out_unlock_rcu:
 out_unlock_threadgroup:
        percpu_up_write(&cgroup_threadgroup_rwsem);
        cgroup_kn_unlock(of->kn);
+       cpuset_post_attach_flush();
        return ret ?: nbytes;
 }
 
@@ -4655,14 +4657,15 @@ static void css_free_work_fn(struct work_struct *work)
 
        if (ss) {
                /* css free path */
+               struct cgroup_subsys_state *parent = css->parent;
                int id = css->id;
 
-               if (css->parent)
-                       css_put(css->parent);
-
                ss->css_free(css);
                cgroup_idr_remove(&ss->css_idr, id);
                cgroup_put(cgrp);
+
+               if (parent)
+                       css_put(parent);
        } else {
                /* cgroup free path */
                atomic_dec(&cgrp->root->nr_cgrps);
@@ -4758,6 +4761,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
        INIT_LIST_HEAD(&css->sibling);
        INIT_LIST_HEAD(&css->children);
        css->serial_nr = css_serial_nr_next++;
+       atomic_set(&css->online_cnt, 0);
 
        if (cgroup_parent(cgrp)) {
                css->parent = cgroup_css(cgroup_parent(cgrp), ss);
@@ -4780,6 +4784,10 @@ static int online_css(struct cgroup_subsys_state *css)
        if (!ret) {
                css->flags |= CSS_ONLINE;
                rcu_assign_pointer(css->cgroup->subsys[ss->id], css);
+
+               atomic_inc(&css->online_cnt);
+               if (css->parent)
+                       atomic_inc(&css->parent->online_cnt);
        }
        return ret;
 }
@@ -5017,10 +5025,15 @@ static void css_killed_work_fn(struct work_struct *work)
                container_of(work, struct cgroup_subsys_state, destroy_work);
 
        mutex_lock(&cgroup_mutex);
-       offline_css(css);
-       mutex_unlock(&cgroup_mutex);
 
-       css_put(css);
+       do {
+               offline_css(css);
+               css_put(css);
+               /* @css can't go away while we're holding cgroup_mutex */
+               css = css->parent;
+       } while (css && atomic_dec_and_test(&css->online_cnt));
+
+       mutex_unlock(&cgroup_mutex);
 }
 
 /* css kill confirmation processing requires process context, bounce */
@@ -5029,8 +5042,10 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
        struct cgroup_subsys_state *css =
                container_of(ref, struct cgroup_subsys_state, refcnt);
 
-       INIT_WORK(&css->destroy_work, css_killed_work_fn);
-       queue_work(cgroup_destroy_wq, &css->destroy_work);
+       if (atomic_dec_and_test(&css->online_cnt)) {
+               INIT_WORK(&css->destroy_work, css_killed_work_fn);
+               queue_work(cgroup_destroy_wq, &css->destroy_work);
+       }
 }
 
 /**
index 3e945fcd81796f954a7e1c81ae95e78bd1a91dba..41989ab4db571cbf93d1a12738bc9afc3411e019 100644 (file)
@@ -287,6 +287,8 @@ static struct cpuset top_cpuset = {
 static DEFINE_MUTEX(cpuset_mutex);
 static DEFINE_SPINLOCK(callback_lock);
 
+static struct workqueue_struct *cpuset_migrate_mm_wq;
+
 /*
  * CPU / memory hotplug is handled asynchronously.
  */
@@ -972,31 +974,51 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
 }
 
 /*
- * cpuset_migrate_mm
- *
- *    Migrate memory region from one set of nodes to another.
- *
- *    Temporarilly set tasks mems_allowed to target nodes of migration,
- *    so that the migration code can allocate pages on these nodes.
- *
- *    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
- *    migrating memory region.
+ * Migrate memory region from one set of nodes to another.  This is
+ * performed asynchronously as it can be called from process migration path
+ * holding locks involved in process management.  All mm migrations are
+ * performed in the queued order and can be waited for by flushing
+ * cpuset_migrate_mm_wq.
  */
 
+struct cpuset_migrate_mm_work {
+       struct work_struct      work;
+       struct mm_struct        *mm;
+       nodemask_t              from;
+       nodemask_t              to;
+};
+
+static void cpuset_migrate_mm_workfn(struct work_struct *work)
+{
+       struct cpuset_migrate_mm_work *mwork =
+               container_of(work, struct cpuset_migrate_mm_work, work);
+
+       /* on a wq worker, no need to worry about %current's mems_allowed */
+       do_migrate_pages(mwork->mm, &mwork->from, &mwork->to, MPOL_MF_MOVE_ALL);
+       mmput(mwork->mm);
+       kfree(mwork);
+}
+
 static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
                                                        const nodemask_t *to)
 {
-       struct task_struct *tsk = current;
-
-       tsk->mems_allowed = *to;
+       struct cpuset_migrate_mm_work *mwork;
 
-       do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
+       mwork = kzalloc(sizeof(*mwork), GFP_KERNEL);
+       if (mwork) {
+               mwork->mm = mm;
+               mwork->from = *from;
+               mwork->to = *to;
+               INIT_WORK(&mwork->work, cpuset_migrate_mm_workfn);
+               queue_work(cpuset_migrate_mm_wq, &mwork->work);
+       } else {
+               mmput(mm);
+       }
+}
 
-       rcu_read_lock();
-       guarantee_online_mems(task_cs(tsk), &tsk->mems_allowed);
-       rcu_read_unlock();
+void cpuset_post_attach_flush(void)
+{
+       flush_workqueue(cpuset_migrate_mm_wq);
 }
 
 /*
@@ -1097,7 +1119,8 @@ static void update_tasks_nodemask(struct cpuset *cs)
                mpol_rebind_mm(mm, &cs->mems_allowed);
                if (migrate)
                        cpuset_migrate_mm(mm, &cs->old_mems_allowed, &newmems);
-               mmput(mm);
+               else
+                       mmput(mm);
        }
        css_task_iter_end(&it);
 
@@ -1545,11 +1568,11 @@ static void cpuset_attach(struct cgroup_taskset *tset)
                         * @old_mems_allowed is the right nodesets that we
                         * migrate mm from.
                         */
-                       if (is_memory_migrate(cs)) {
+                       if (is_memory_migrate(cs))
                                cpuset_migrate_mm(mm, &oldcs->old_mems_allowed,
                                                  &cpuset_attach_nodemask_to);
-                       }
-                       mmput(mm);
+                       else
+                               mmput(mm);
                }
        }
 
@@ -1714,6 +1737,7 @@ out_unlock:
        mutex_unlock(&cpuset_mutex);
        kernfs_unbreak_active_protection(of->kn);
        css_put(&cs->css);
+       flush_workqueue(cpuset_migrate_mm_wq);
        return retval ?: nbytes;
 }
 
@@ -2359,6 +2383,9 @@ void __init cpuset_init_smp(void)
        top_cpuset.effective_mems = node_states[N_MEMORY];
 
        register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
+
+       cpuset_migrate_mm_wq = alloc_ordered_workqueue("cpuset_migrate_mm", 0);
+       BUG_ON(!cpuset_migrate_mm_wq);
 }
 
 /**
index 9c418002b8c1fa15217b3390250453b492849344..343c22f5e867de2bbe6c2220535b413a6ea0f4ed 100644 (file)
@@ -159,15 +159,24 @@ put_callchain_entry(int rctx)
 struct perf_callchain_entry *
 perf_callchain(struct perf_event *event, struct pt_regs *regs)
 {
-       int rctx;
-       struct perf_callchain_entry *entry;
-
-       int kernel = !event->attr.exclude_callchain_kernel;
-       int user   = !event->attr.exclude_callchain_user;
+       bool kernel = !event->attr.exclude_callchain_kernel;
+       bool user   = !event->attr.exclude_callchain_user;
+       /* Disallow cross-task user callchains. */
+       bool crosstask = event->ctx->task && event->ctx->task != current;
 
        if (!kernel && !user)
                return NULL;
 
+       return get_perf_callchain(regs, 0, kernel, user, crosstask, true);
+}
+
+struct perf_callchain_entry *
+get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user,
+                  bool crosstask, bool add_mark)
+{
+       struct perf_callchain_entry *entry;
+       int rctx;
+
        entry = get_callchain_entry(&rctx);
        if (rctx == -1)
                return NULL;
@@ -175,10 +184,11 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
        if (!entry)
                goto exit_put;
 
-       entry->nr = 0;
+       entry->nr = init_nr;
 
        if (kernel && !user_mode(regs)) {
-               perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
+               if (add_mark)
+                       perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
                perf_callchain_kernel(entry, regs);
        }
 
@@ -191,13 +201,11 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
                }
 
                if (regs) {
-                       /*
-                        * Disallow cross-task user callchains.
-                        */
-                       if (event->ctx->task && event->ctx->task != current)
+                       if (crosstask)
                                goto exit_put;
 
-                       perf_callchain_store(entry, PERF_CONTEXT_USER);
+                       if (add_mark)
+                               perf_callchain_store(entry, PERF_CONTEXT_USER);
                        perf_callchain_user(entry, regs);
                }
        }
index 5946460b24250a264f75c442099bb52ca06b0269..614614821f00a02928439b068903904d81233808 100644 (file)
@@ -64,8 +64,17 @@ static void remote_function(void *data)
        struct task_struct *p = tfc->p;
 
        if (p) {
-               tfc->ret = -EAGAIN;
-               if (task_cpu(p) != smp_processor_id() || !task_curr(p))
+               /* -EAGAIN */
+               if (task_cpu(p) != smp_processor_id())
+                       return;
+
+               /*
+                * Now that we're on right CPU with IRQs disabled, we can test
+                * if we hit the right task without races.
+                */
+
+               tfc->ret = -ESRCH; /* No such (running) process */
+               if (p != current)
                        return;
        }
 
@@ -92,13 +101,17 @@ task_function_call(struct task_struct *p, remote_function_f func, void *info)
                .p      = p,
                .func   = func,
                .info   = info,
-               .ret    = -ESRCH, /* No such (running) process */
+               .ret    = -EAGAIN,
        };
+       int ret;
 
-       if (task_curr(p))
-               smp_call_function_single(task_cpu(p), remote_function, &data, 1);
+       do {
+               ret = smp_call_function_single(task_cpu(p), remote_function, &data, 1);
+               if (!ret)
+                       ret = data.ret;
+       } while (ret == -EAGAIN);
 
-       return data.ret;
+       return ret;
 }
 
 /**
@@ -169,19 +182,6 @@ static bool is_kernel_event(struct perf_event *event)
  *    rely on ctx->is_active and therefore cannot use event_function_call().
  *    See perf_install_in_context().
  *
- * This is because we need a ctx->lock serialized variable (ctx->is_active)
- * to reliably determine if a particular task/context is scheduled in. The
- * task_curr() use in task_function_call() is racy in that a remote context
- * switch is not a single atomic operation.
- *
- * As is, the situation is 'safe' because we set rq->curr before we do the
- * actual context switch. This means that task_curr() will fail early, but
- * we'll continue spinning on ctx->is_active until we've passed
- * perf_event_task_sched_out().
- *
- * Without this ctx->lock serialized variable we could have race where we find
- * the task (and hence the context) would not be active while in fact they are.
- *
  * If ctx->nr_events, then ctx->is_active and cpuctx->task_ctx are set.
  */
 
@@ -212,7 +212,7 @@ static int event_function(void *info)
         */
        if (ctx->task) {
                if (ctx->task != current) {
-                       ret = -EAGAIN;
+                       ret = -ESRCH;
                        goto unlock;
                }
 
@@ -276,10 +276,10 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
                return;
        }
 
-again:
        if (task == TASK_TOMBSTONE)
                return;
 
+again:
        if (!task_function_call(task, event_function, &efs))
                return;
 
@@ -289,13 +289,15 @@ again:
         * a concurrent perf_event_context_sched_out().
         */
        task = ctx->task;
-       if (task != TASK_TOMBSTONE) {
-               if (ctx->is_active) {
-                       raw_spin_unlock_irq(&ctx->lock);
-                       goto again;
-               }
-               func(event, NULL, ctx, data);
+       if (task == TASK_TOMBSTONE) {
+               raw_spin_unlock_irq(&ctx->lock);
+               return;
        }
+       if (ctx->is_active) {
+               raw_spin_unlock_irq(&ctx->lock);
+               goto again;
+       }
+       func(event, NULL, ctx, data);
        raw_spin_unlock_irq(&ctx->lock);
 }
 
@@ -314,6 +316,7 @@ again:
 enum event_type_t {
        EVENT_FLEXIBLE = 0x1,
        EVENT_PINNED = 0x2,
+       EVENT_TIME = 0x4,
        EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED,
 };
 
@@ -321,7 +324,13 @@ enum event_type_t {
  * perf_sched_events : >0 events exist
  * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu
  */
-struct static_key_deferred perf_sched_events __read_mostly;
+
+static void perf_sched_delayed(struct work_struct *work);
+DEFINE_STATIC_KEY_FALSE(perf_sched_events);
+static DECLARE_DELAYED_WORK(perf_sched_work, perf_sched_delayed);
+static DEFINE_MUTEX(perf_sched_mutex);
+static atomic_t perf_sched_count;
+
 static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
 static DEFINE_PER_CPU(int, perf_sched_cb_usages);
 
@@ -1288,16 +1297,18 @@ static u64 perf_event_time(struct perf_event *event)
 
 /*
  * Update the total_time_enabled and total_time_running fields for a event.
- * The caller of this function needs to hold the ctx->lock.
  */
 static void update_event_times(struct perf_event *event)
 {
        struct perf_event_context *ctx = event->ctx;
        u64 run_end;
 
+       lockdep_assert_held(&ctx->lock);
+
        if (event->state < PERF_EVENT_STATE_INACTIVE ||
            event->group_leader->state < PERF_EVENT_STATE_INACTIVE)
                return;
+
        /*
         * in cgroup mode, time_enabled represents
         * the time the event was enabled AND active
@@ -1645,7 +1656,7 @@ out:
 
 static bool is_orphaned_event(struct perf_event *event)
 {
-       return event->state == PERF_EVENT_STATE_EXIT;
+       return event->state == PERF_EVENT_STATE_DEAD;
 }
 
 static inline int pmu_filter_match(struct perf_event *event)
@@ -1690,14 +1701,14 @@ event_sched_out(struct perf_event *event,
 
        perf_pmu_disable(event->pmu);
 
+       event->tstamp_stopped = tstamp;
+       event->pmu->del(event, 0);
+       event->oncpu = -1;
        event->state = PERF_EVENT_STATE_INACTIVE;
        if (event->pending_disable) {
                event->pending_disable = 0;
                event->state = PERF_EVENT_STATE_OFF;
        }
-       event->tstamp_stopped = tstamp;
-       event->pmu->del(event, 0);
-       event->oncpu = -1;
 
        if (!is_software_event(event))
                cpuctx->active_oncpu--;
@@ -1732,7 +1743,6 @@ group_sched_out(struct perf_event *group_event,
 }
 
 #define DETACH_GROUP   0x01UL
-#define DETACH_STATE   0x02UL
 
 /*
  * Cross CPU call to remove a performance event
@@ -1752,8 +1762,6 @@ __perf_remove_from_context(struct perf_event *event,
        if (flags & DETACH_GROUP)
                perf_group_detach(event);
        list_del_event(event, ctx);
-       if (flags & DETACH_STATE)
-               event->state = PERF_EVENT_STATE_EXIT;
 
        if (!ctx->nr_events && ctx->is_active) {
                ctx->is_active = 0;
@@ -2063,14 +2071,27 @@ static void add_event_to_ctx(struct perf_event *event,
        event->tstamp_stopped = tstamp;
 }
 
-static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
-                              struct perf_event_context *ctx);
+static void ctx_sched_out(struct perf_event_context *ctx,
+                         struct perf_cpu_context *cpuctx,
+                         enum event_type_t event_type);
 static void
 ctx_sched_in(struct perf_event_context *ctx,
             struct perf_cpu_context *cpuctx,
             enum event_type_t event_type,
             struct task_struct *task);
 
+static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
+                              struct perf_event_context *ctx)
+{
+       if (!cpuctx->task_ctx)
+               return;
+
+       if (WARN_ON_ONCE(ctx != cpuctx->task_ctx))
+               return;
+
+       ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+}
+
 static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
                                struct perf_event_context *ctx,
                                struct task_struct *task)
@@ -2097,49 +2118,68 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
 /*
  * Cross CPU call to install and enable a performance event
  *
- * Must be called with ctx->mutex held
+ * Very similar to remote_function() + event_function() but cannot assume that
+ * things like ctx->is_active and cpuctx->task_ctx are set.
  */
 static int  __perf_install_in_context(void *info)
 {
-       struct perf_event_context *ctx = info;
+       struct perf_event *event = info;
+       struct perf_event_context *ctx = event->ctx;
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        struct perf_event_context *task_ctx = cpuctx->task_ctx;
+       bool activate = true;
+       int ret = 0;
 
        raw_spin_lock(&cpuctx->ctx.lock);
        if (ctx->task) {
                raw_spin_lock(&ctx->lock);
-               /*
-                * If we hit the 'wrong' task, we've since scheduled and
-                * everything should be sorted, nothing to do!
-                */
                task_ctx = ctx;
-               if (ctx->task != current)
+
+               /* If we're on the wrong CPU, try again */
+               if (task_cpu(ctx->task) != smp_processor_id()) {
+                       ret = -ESRCH;
                        goto unlock;
+               }
 
                /*
-                * If task_ctx is set, it had better be to us.
+                * If we're on the right CPU, see if the task we target is
+                * current, if not we don't have to activate the ctx, a future
+                * context switch will do that for us.
                 */
-               WARN_ON_ONCE(cpuctx->task_ctx != ctx && cpuctx->task_ctx);
+               if (ctx->task != current)
+                       activate = false;
+               else
+                       WARN_ON_ONCE(cpuctx->task_ctx && cpuctx->task_ctx != ctx);
+
        } else if (task_ctx) {
                raw_spin_lock(&task_ctx->lock);
        }
 
-       ctx_resched(cpuctx, task_ctx);
+       if (activate) {
+               ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+               add_event_to_ctx(event, ctx);
+               ctx_resched(cpuctx, task_ctx);
+       } else {
+               add_event_to_ctx(event, ctx);
+       }
+
 unlock:
        perf_ctx_unlock(cpuctx, task_ctx);
 
-       return 0;
+       return ret;
 }
 
 /*
- * Attach a performance event to a context
+ * Attach a performance event to a context.
+ *
+ * Very similar to event_function_call, see comment there.
  */
 static void
 perf_install_in_context(struct perf_event_context *ctx,
                        struct perf_event *event,
                        int cpu)
 {
-       struct task_struct *task = NULL;
+       struct task_struct *task = READ_ONCE(ctx->task);
 
        lockdep_assert_held(&ctx->mutex);
 
@@ -2147,40 +2187,46 @@ perf_install_in_context(struct perf_event_context *ctx,
        if (event->cpu != -1)
                event->cpu = cpu;
 
+       if (!task) {
+               cpu_function_call(cpu, __perf_install_in_context, event);
+               return;
+       }
+
+       /*
+        * Should not happen, we validate the ctx is still alive before calling.
+        */
+       if (WARN_ON_ONCE(task == TASK_TOMBSTONE))
+               return;
+
        /*
         * Installing events is tricky because we cannot rely on ctx->is_active
         * to be set in case this is the nr_events 0 -> 1 transition.
-        *
-        * So what we do is we add the event to the list here, which will allow
-        * a future context switch to DTRT and then send a racy IPI. If the IPI
-        * fails to hit the right task, this means a context switch must have
-        * happened and that will have taken care of business.
         */
-       raw_spin_lock_irq(&ctx->lock);
-       task = ctx->task;
+again:
        /*
-        * Worse, we cannot even rely on the ctx actually existing anymore. If
-        * between find_get_context() and perf_install_in_context() the task
-        * went through perf_event_exit_task() its dead and we should not be
-        * adding new events.
+        * Cannot use task_function_call() because we need to run on the task's
+        * CPU regardless of whether its current or not.
         */
-       if (task == TASK_TOMBSTONE) {
+       if (!cpu_function_call(task_cpu(task), __perf_install_in_context, event))
+               return;
+
+       raw_spin_lock_irq(&ctx->lock);
+       task = ctx->task;
+       if (WARN_ON_ONCE(task == TASK_TOMBSTONE)) {
+               /*
+                * Cannot happen because we already checked above (which also
+                * cannot happen), and we hold ctx->mutex, which serializes us
+                * against perf_event_exit_task_context().
+                */
                raw_spin_unlock_irq(&ctx->lock);
                return;
        }
-       update_context_time(ctx);
+       raw_spin_unlock_irq(&ctx->lock);
        /*
-        * Update cgrp time only if current cgrp matches event->cgrp.
-        * Must be done before calling add_event_to_ctx().
+        * Since !ctx->is_active doesn't mean anything, we must IPI
+        * unconditionally.
         */
-       update_cgrp_time_from_event(event);
-       add_event_to_ctx(event, ctx);
-       raw_spin_unlock_irq(&ctx->lock);
-
-       if (task)
-               task_function_call(task, __perf_install_in_context, ctx);
-       else
-               cpu_function_call(cpu, __perf_install_in_context, ctx);
+       goto again;
 }
 
 /*
@@ -2219,17 +2265,18 @@ static void __perf_event_enable(struct perf_event *event,
            event->state <= PERF_EVENT_STATE_ERROR)
                return;
 
-       update_context_time(ctx);
+       if (ctx->is_active)
+               ctx_sched_out(ctx, cpuctx, EVENT_TIME);
+
        __perf_event_mark_enabled(event);
 
        if (!ctx->is_active)
                return;
 
        if (!event_filter_match(event)) {
-               if (is_cgroup_event(event)) {
-                       perf_cgroup_set_timestamp(current, ctx); // XXX ?
+               if (is_cgroup_event(event))
                        perf_cgroup_defer_enabled(event);
-               }
+               ctx_sched_in(ctx, cpuctx, EVENT_TIME, current);
                return;
        }
 
@@ -2237,8 +2284,10 @@ static void __perf_event_enable(struct perf_event *event,
         * If the event is in a group and isn't the group leader,
         * then don't put it on unless the group is on.
         */
-       if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE)
+       if (leader != event && leader->state != PERF_EVENT_STATE_ACTIVE) {
+               ctx_sched_in(ctx, cpuctx, EVENT_TIME, current);
                return;
+       }
 
        task_ctx = cpuctx->task_ctx;
        if (ctx->task)
@@ -2344,24 +2393,33 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        }
 
        ctx->is_active &= ~event_type;
+       if (!(ctx->is_active & EVENT_ALL))
+               ctx->is_active = 0;
+
        if (ctx->task) {
                WARN_ON_ONCE(cpuctx->task_ctx != ctx);
                if (!ctx->is_active)
                        cpuctx->task_ctx = NULL;
        }
 
-       update_context_time(ctx);
-       update_cgrp_time_from_cpuctx(cpuctx);
-       if (!ctx->nr_active)
+       is_active ^= ctx->is_active; /* changed bits */
+
+       if (is_active & EVENT_TIME) {
+               /* update (and stop) ctx time */
+               update_context_time(ctx);
+               update_cgrp_time_from_cpuctx(cpuctx);
+       }
+
+       if (!ctx->nr_active || !(is_active & EVENT_ALL))
                return;
 
        perf_pmu_disable(ctx->pmu);
-       if ((is_active & EVENT_PINNED) && (event_type & EVENT_PINNED)) {
+       if (is_active & EVENT_PINNED) {
                list_for_each_entry(event, &ctx->pinned_groups, group_entry)
                        group_sched_out(event, cpuctx, ctx);
        }
 
-       if ((is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE)) {
+       if (is_active & EVENT_FLEXIBLE) {
                list_for_each_entry(event, &ctx->flexible_groups, group_entry)
                        group_sched_out(event, cpuctx, ctx);
        }
@@ -2641,18 +2699,6 @@ void __perf_event_task_sched_out(struct task_struct *task,
                perf_cgroup_sched_out(task, next);
 }
 
-static void task_ctx_sched_out(struct perf_cpu_context *cpuctx,
-                              struct perf_event_context *ctx)
-{
-       if (!cpuctx->task_ctx)
-               return;
-
-       if (WARN_ON_ONCE(ctx != cpuctx->task_ctx))
-               return;
-
-       ctx_sched_out(ctx, cpuctx, EVENT_ALL);
-}
-
 /*
  * Called with IRQs disabled
  */
@@ -2735,7 +2781,7 @@ ctx_sched_in(struct perf_event_context *ctx,
        if (likely(!ctx->nr_events))
                return;
 
-       ctx->is_active |= event_type;
+       ctx->is_active |= (event_type | EVENT_TIME);
        if (ctx->task) {
                if (!is_active)
                        cpuctx->task_ctx = ctx;
@@ -2743,18 +2789,24 @@ ctx_sched_in(struct perf_event_context *ctx,
                        WARN_ON_ONCE(cpuctx->task_ctx != ctx);
        }
 
-       now = perf_clock();
-       ctx->timestamp = now;
-       perf_cgroup_set_timestamp(task, ctx);
+       is_active ^= ctx->is_active; /* changed bits */
+
+       if (is_active & EVENT_TIME) {
+               /* start ctx time */
+               now = perf_clock();
+               ctx->timestamp = now;
+               perf_cgroup_set_timestamp(task, ctx);
+       }
+
        /*
         * First go through the list and put on any pinned groups
         * in order to give them the best chance of going on.
         */
-       if (!(is_active & EVENT_PINNED) && (event_type & EVENT_PINNED))
+       if (is_active & EVENT_PINNED)
                ctx_pinned_sched_in(ctx, cpuctx);
 
        /* Then walk through the lower prio flexible groups */
-       if (!(is_active & EVENT_FLEXIBLE) && (event_type & EVENT_FLEXIBLE))
+       if (is_active & EVENT_FLEXIBLE)
                ctx_flexible_sched_in(ctx, cpuctx);
 }
 
@@ -3120,6 +3172,7 @@ static void perf_event_enable_on_exec(int ctxn)
 
        cpuctx = __get_cpu_context(ctx);
        perf_ctx_lock(cpuctx, ctx);
+       ctx_sched_out(ctx, cpuctx, EVENT_TIME);
        list_for_each_entry(event, &ctx->event_list, event_entry)
                enabled |= event_enable_on_exec(event, ctx);
 
@@ -3537,12 +3590,22 @@ static void unaccount_event(struct perf_event *event)
        if (has_branch_stack(event))
                dec = true;
 
-       if (dec)
-               static_key_slow_dec_deferred(&perf_sched_events);
+       if (dec) {
+               if (!atomic_add_unless(&perf_sched_count, -1, 1))
+                       schedule_delayed_work(&perf_sched_work, HZ);
+       }
 
        unaccount_event_cpu(event, event->cpu);
 }
 
+static void perf_sched_delayed(struct work_struct *work)
+{
+       mutex_lock(&perf_sched_mutex);
+       if (atomic_dec_and_test(&perf_sched_count))
+               static_branch_disable(&perf_sched_events);
+       mutex_unlock(&perf_sched_mutex);
+}
+
 /*
  * The following implement mutual exclusion of events on "exclusive" pmus
  * (PERF_PMU_CAP_EXCLUSIVE). Such pmus can only have one event scheduled
@@ -3752,30 +3815,42 @@ static void put_event(struct perf_event *event)
  */
 int perf_event_release_kernel(struct perf_event *event)
 {
-       struct perf_event_context *ctx;
+       struct perf_event_context *ctx = event->ctx;
        struct perf_event *child, *tmp;
 
+       /*
+        * If we got here through err_file: fput(event_file); we will not have
+        * attached to a context yet.
+        */
+       if (!ctx) {
+               WARN_ON_ONCE(event->attach_state &
+                               (PERF_ATTACH_CONTEXT|PERF_ATTACH_GROUP));
+               goto no_ctx;
+       }
+
        if (!is_kernel_event(event))
                perf_remove_from_owner(event);
 
        ctx = perf_event_ctx_lock(event);
        WARN_ON_ONCE(ctx->parent_ctx);
-       perf_remove_from_context(event, DETACH_GROUP | DETACH_STATE);
-       perf_event_ctx_unlock(event, ctx);
+       perf_remove_from_context(event, DETACH_GROUP);
 
+       raw_spin_lock_irq(&ctx->lock);
        /*
-        * At this point we must have event->state == PERF_EVENT_STATE_EXIT,
-        * either from the above perf_remove_from_context() or through
-        * perf_event_exit_event().
+        * Mark this even as STATE_DEAD, there is no external reference to it
+        * anymore.
         *
-        * Therefore, anybody acquiring event->child_mutex after the below
-        * loop _must_ also see this, most importantly inherit_event() which
-        * will avoid placing more children on the list.
+        * Anybody acquiring event->child_mutex after the below loop _must_
+        * also see this, most importantly inherit_event() which will avoid
+        * placing more children on the list.
         *
         * Thus this guarantees that we will in fact observe and kill _ALL_
         * child events.
         */
-       WARN_ON_ONCE(event->state != PERF_EVENT_STATE_EXIT);
+       event->state = PERF_EVENT_STATE_DEAD;
+       raw_spin_unlock_irq(&ctx->lock);
+
+       perf_event_ctx_unlock(event, ctx);
 
 again:
        mutex_lock(&event->child_mutex);
@@ -3830,8 +3905,8 @@ again:
        }
        mutex_unlock(&event->child_mutex);
 
-       /* Must be the last reference */
-       put_event(event);
+no_ctx:
+       put_event(event); /* Must be the 'last' reference */
        return 0;
 }
 EXPORT_SYMBOL_GPL(perf_event_release_kernel);
@@ -3988,7 +4063,7 @@ static bool is_event_hup(struct perf_event *event)
 {
        bool no_children;
 
-       if (event->state != PERF_EVENT_STATE_EXIT)
+       if (event->state > PERF_EVENT_STATE_EXIT)
                return false;
 
        mutex_lock(&event->child_mutex);
@@ -7769,8 +7844,28 @@ static void account_event(struct perf_event *event)
        if (is_cgroup_event(event))
                inc = true;
 
-       if (inc)
-               static_key_slow_inc(&perf_sched_events.key);
+       if (inc) {
+               if (atomic_inc_not_zero(&perf_sched_count))
+                       goto enabled;
+
+               mutex_lock(&perf_sched_mutex);
+               if (!atomic_read(&perf_sched_count)) {
+                       static_branch_enable(&perf_sched_events);
+                       /*
+                        * Guarantee that all CPUs observe they key change and
+                        * call the perf scheduling hooks before proceeding to
+                        * install events that need them.
+                        */
+                       synchronize_sched();
+               }
+               /*
+                * Now that we have waited for the sync_sched(), allow further
+                * increments to by-pass the mutex.
+                */
+               atomic_inc(&perf_sched_count);
+               mutex_unlock(&perf_sched_mutex);
+       }
+enabled:
 
        account_event_cpu(event, event->cpu);
 }
@@ -8389,10 +8484,19 @@ SYSCALL_DEFINE5(perf_event_open,
        if (move_group) {
                gctx = group_leader->ctx;
                mutex_lock_double(&gctx->mutex, &ctx->mutex);
+               if (gctx->task == TASK_TOMBSTONE) {
+                       err = -ESRCH;
+                       goto err_locked;
+               }
        } else {
                mutex_lock(&ctx->mutex);
        }
 
+       if (ctx->task == TASK_TOMBSTONE) {
+               err = -ESRCH;
+               goto err_locked;
+       }
+
        if (!perf_event_validate_size(event)) {
                err = -E2BIG;
                goto err_locked;
@@ -8509,7 +8613,12 @@ err_context:
        perf_unpin_context(ctx);
        put_ctx(ctx);
 err_alloc:
-       free_event(event);
+       /*
+        * If event_file is set, the fput() above will have called ->release()
+        * and that will take care of freeing the event.
+        */
+       if (!event_file)
+               free_event(event);
 err_cpus:
        put_online_cpus();
 err_task:
@@ -8563,12 +8672,14 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
 
        WARN_ON_ONCE(ctx->parent_ctx);
        mutex_lock(&ctx->mutex);
+       if (ctx->task == TASK_TOMBSTONE) {
+               err = -ESRCH;
+               goto err_unlock;
+       }
+
        if (!exclusive_event_installable(event, ctx)) {
-               mutex_unlock(&ctx->mutex);
-               perf_unpin_context(ctx);
-               put_ctx(ctx);
                err = -EBUSY;
-               goto err_free;
+               goto err_unlock;
        }
 
        perf_install_in_context(ctx, event, cpu);
@@ -8577,6 +8688,10 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
 
        return event;
 
+err_unlock:
+       mutex_unlock(&ctx->mutex);
+       perf_unpin_context(ctx);
+       put_ctx(ctx);
 err_free:
        free_event(event);
 err:
@@ -8695,7 +8810,7 @@ perf_event_exit_event(struct perf_event *child_event,
        if (parent_event)
                perf_group_detach(child_event);
        list_del_event(child_event, child_ctx);
-       child_event->state = PERF_EVENT_STATE_EXIT; /* see perf_event_release_kernel() */
+       child_event->state = PERF_EVENT_STATE_EXIT; /* is_event_hup() */
        raw_spin_unlock_irq(&child_ctx->lock);
 
        /*
@@ -9206,7 +9321,7 @@ static void perf_event_init_cpu(int cpu)
        struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
        mutex_lock(&swhash->hlist_mutex);
-       if (swhash->hlist_refcount > 0) {
+       if (swhash->hlist_refcount > 0 && !swevent_hlist_deref(swhash)) {
                struct swevent_hlist *hlist;
 
                hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu));
@@ -9282,11 +9397,9 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
        switch (action & ~CPU_TASKS_FROZEN) {
 
        case CPU_UP_PREPARE:
-       case CPU_DOWN_FAILED:
                perf_event_init_cpu(cpu);
                break;
 
-       case CPU_UP_CANCELED:
        case CPU_DOWN_PREPARE:
                perf_event_exit_cpu(cpu);
                break;
@@ -9315,9 +9428,6 @@ void __init perf_event_init(void)
        ret = init_hw_breakpoint();
        WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
 
-       /* do not patch jump label more than once per second */
-       jump_label_rate_limit(&perf_sched_events, HZ);
-
        /*
         * Build time assertion that we keep the data_head at the intended
         * location.  IOW, validation we got the __reserved[] size right.
index 2bbad9c1274c3199338e653bbb5c8bd640815fa7..4199b6d193f58143ec8ccfe16a055a0c5d54608c 100644 (file)
@@ -182,8 +182,6 @@ DEFINE_OUTPUT_COPY(__output_copy_user, arch_perf_out_copy_user)
 /* Callchain handling */
 extern struct perf_callchain_entry *
 perf_callchain(struct perf_event *event, struct pt_regs *regs);
-extern int get_callchain_buffers(void);
-extern void put_callchain_buffers(void);
 
 static inline int get_recursion_context(int *recursion)
 {
index 60ace56618f6c222de90e569bf1702b6dba05e26..716547fdb8731dcc395d70f2664ec6fb22378db6 100644 (file)
@@ -292,7 +292,7 @@ LIST_HEAD(all_lock_classes);
 #define __classhashfn(key)     hash_long((unsigned long)key, CLASSHASH_BITS)
 #define classhashentry(key)    (classhash_table + __classhashfn((key)))
 
-static struct list_head classhash_table[CLASSHASH_SIZE];
+static struct hlist_head classhash_table[CLASSHASH_SIZE];
 
 /*
  * We put the lock dependency chains into a hash-table as well, to cache
@@ -303,7 +303,7 @@ static struct list_head classhash_table[CLASSHASH_SIZE];
 #define __chainhashfn(chain)   hash_long(chain, CHAINHASH_BITS)
 #define chainhashentry(chain)  (chainhash_table + __chainhashfn((chain)))
 
-static struct list_head chainhash_table[CHAINHASH_SIZE];
+static struct hlist_head chainhash_table[CHAINHASH_SIZE];
 
 /*
  * The hash key of the lock dependency chains is a hash itself too:
@@ -666,7 +666,7 @@ static inline struct lock_class *
 look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
 {
        struct lockdep_subclass_key *key;
-       struct list_head *hash_head;
+       struct hlist_head *hash_head;
        struct lock_class *class;
 
 #ifdef CONFIG_DEBUG_LOCKDEP
@@ -719,7 +719,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return NULL;
 
-       list_for_each_entry_rcu(class, hash_head, hash_entry) {
+       hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key) {
                        /*
                         * Huh! same key, different name? Did someone trample
@@ -742,7 +742,7 @@ static inline struct lock_class *
 register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
 {
        struct lockdep_subclass_key *key;
-       struct list_head *hash_head;
+       struct hlist_head *hash_head;
        struct lock_class *class;
 
        DEBUG_LOCKS_WARN_ON(!irqs_disabled());
@@ -774,7 +774,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
         * We have to do the hash-walk again, to avoid races
         * with another CPU:
         */
-       list_for_each_entry_rcu(class, hash_head, hash_entry) {
+       hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
                if (class->key == key)
                        goto out_unlock_set;
        }
@@ -805,7 +805,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
         * We use RCU's safe list-add method to make
         * parallel walking of the hash-list safe:
         */
-       list_add_tail_rcu(&class->hash_entry, hash_head);
+       hlist_add_head_rcu(&class->hash_entry, hash_head);
        /*
         * Add it to the global list of classes:
         */
@@ -1822,7 +1822,7 @@ check_deadlock(struct task_struct *curr, struct held_lock *next,
  */
 static int
 check_prev_add(struct task_struct *curr, struct held_lock *prev,
-              struct held_lock *next, int distance, int trylock_loop)
+              struct held_lock *next, int distance, int *stack_saved)
 {
        struct lock_list *entry;
        int ret;
@@ -1883,8 +1883,11 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
                }
        }
 
-       if (!trylock_loop && !save_trace(&trace))
-               return 0;
+       if (!*stack_saved) {
+               if (!save_trace(&trace))
+                       return 0;
+               *stack_saved = 1;
+       }
 
        /*
         * Ok, all validations passed, add the new lock
@@ -1907,6 +1910,8 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
         * Debugging printouts:
         */
        if (verbose(hlock_class(prev)) || verbose(hlock_class(next))) {
+               /* We drop graph lock, so another thread can overwrite trace. */
+               *stack_saved = 0;
                graph_unlock();
                printk("\n new dependency: ");
                print_lock_name(hlock_class(prev));
@@ -1929,7 +1934,7 @@ static int
 check_prevs_add(struct task_struct *curr, struct held_lock *next)
 {
        int depth = curr->lockdep_depth;
-       int trylock_loop = 0;
+       int stack_saved = 0;
        struct held_lock *hlock;
 
        /*
@@ -1956,7 +1961,7 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
                 */
                if (hlock->read != 2 && hlock->check) {
                        if (!check_prev_add(curr, hlock, next,
-                                               distance, trylock_loop))
+                                               distance, &stack_saved))
                                return 0;
                        /*
                         * Stop after the first non-trylock entry,
@@ -1979,7 +1984,6 @@ check_prevs_add(struct task_struct *curr, struct held_lock *next)
                if (curr->held_locks[depth].irq_context !=
                                curr->held_locks[depth-1].irq_context)
                        break;
-               trylock_loop = 1;
        }
        return 1;
 out_bug:
@@ -2017,7 +2021,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
                                     u64 chain_key)
 {
        struct lock_class *class = hlock_class(hlock);
-       struct list_head *hash_head = chainhashentry(chain_key);
+       struct hlist_head *hash_head = chainhashentry(chain_key);
        struct lock_chain *chain;
        struct held_lock *hlock_curr;
        int i, j;
@@ -2033,7 +2037,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
         * We can walk it lock-free, because entries only get added
         * to the hash:
         */
-       list_for_each_entry_rcu(chain, hash_head, entry) {
+       hlist_for_each_entry_rcu(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
 cache_hit:
                        debug_atomic_inc(chain_lookup_hits);
@@ -2057,7 +2061,7 @@ cache_hit:
        /*
         * We have to walk the chain again locked - to avoid duplicates:
         */
-       list_for_each_entry(chain, hash_head, entry) {
+       hlist_for_each_entry(chain, hash_head, entry) {
                if (chain->chain_key == chain_key) {
                        graph_unlock();
                        goto cache_hit;
@@ -2091,7 +2095,7 @@ cache_hit:
                }
                chain_hlocks[chain->base + j] = class - lock_classes;
        }
-       list_add_tail_rcu(&chain->entry, hash_head);
+       hlist_add_head_rcu(&chain->entry, hash_head);
        debug_atomic_inc(chain_lookup_misses);
        inc_chains();
 
@@ -3875,7 +3879,7 @@ void lockdep_reset(void)
        nr_process_chains = 0;
        debug_locks = 1;
        for (i = 0; i < CHAINHASH_SIZE; i++)
-               INIT_LIST_HEAD(chainhash_table + i);
+               INIT_HLIST_HEAD(chainhash_table + i);
        raw_local_irq_restore(flags);
 }
 
@@ -3894,7 +3898,7 @@ static void zap_class(struct lock_class *class)
        /*
         * Unhash the class and remove it from the all_lock_classes list:
         */
-       list_del_rcu(&class->hash_entry);
+       hlist_del_rcu(&class->hash_entry);
        list_del_rcu(&class->lock_entry);
 
        RCU_INIT_POINTER(class->key, NULL);
@@ -3917,7 +3921,7 @@ static inline int within(const void *addr, void *start, unsigned long size)
 void lockdep_free_key_range(void *start, unsigned long size)
 {
        struct lock_class *class;
-       struct list_head *head;
+       struct hlist_head *head;
        unsigned long flags;
        int i;
        int locked;
@@ -3930,9 +3934,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
         */
        for (i = 0; i < CLASSHASH_SIZE; i++) {
                head = classhash_table + i;
-               if (list_empty(head))
-                       continue;
-               list_for_each_entry_rcu(class, head, hash_entry) {
+               hlist_for_each_entry_rcu(class, head, hash_entry) {
                        if (within(class->key, start, size))
                                zap_class(class);
                        else if (within(class->name, start, size))
@@ -3962,7 +3964,7 @@ void lockdep_free_key_range(void *start, unsigned long size)
 void lockdep_reset_lock(struct lockdep_map *lock)
 {
        struct lock_class *class;
-       struct list_head *head;
+       struct hlist_head *head;
        unsigned long flags;
        int i, j;
        int locked;
@@ -3987,9 +3989,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
        locked = graph_lock();
        for (i = 0; i < CLASSHASH_SIZE; i++) {
                head = classhash_table + i;
-               if (list_empty(head))
-                       continue;
-               list_for_each_entry_rcu(class, head, hash_entry) {
+               hlist_for_each_entry_rcu(class, head, hash_entry) {
                        int match = 0;
 
                        for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
@@ -4027,10 +4027,10 @@ void lockdep_init(void)
                return;
 
        for (i = 0; i < CLASSHASH_SIZE; i++)
-               INIT_LIST_HEAD(classhash_table + i);
+               INIT_HLIST_HEAD(classhash_table + i);
 
        for (i = 0; i < CHAINHASH_SIZE; i++)
-               INIT_LIST_HEAD(chainhash_table + i);
+               INIT_HLIST_HEAD(chainhash_table + i);
 
        lockdep_initialized = 1;
 }
index 70ee3775de24ebcf2e80ab2fdad21eaad24dd2fe..b981a7b023f04c356df5b852f60caeae232fdf45 100644 (file)
@@ -114,7 +114,7 @@ EXPORT_SYMBOL(memunmap);
 
 static void devm_memremap_release(struct device *dev, void *res)
 {
-       memunmap(res);
+       memunmap(*(void **)res);
 }
 
 static int devm_memremap_match(struct device *dev, void *res, void *match_data)
@@ -136,8 +136,10 @@ void *devm_memremap(struct device *dev, resource_size_t offset,
        if (addr) {
                *ptr = addr;
                devres_add(dev, ptr);
-       } else
+       } else {
                devres_free(ptr);
+               return ERR_PTR(-ENXIO);
+       }
 
        return addr;
 }
@@ -150,7 +152,7 @@ void devm_memunmap(struct device *dev, void *addr)
 }
 EXPORT_SYMBOL(devm_memunmap);
 
-pfn_t phys_to_pfn_t(phys_addr_t addr, unsigned long flags)
+pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags)
 {
        return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags);
 }
index 8358f4697c0c3aea77aba802833660d4082b7c13..794ebe8e878d55cf9a0b94a1ae7a994ac4dec80b 100644 (file)
@@ -303,6 +303,9 @@ struct load_info {
        struct _ddebug *debug;
        unsigned int num_debug;
        bool sig_ok;
+#ifdef CONFIG_KALLSYMS
+       unsigned long mod_kallsyms_init_off;
+#endif
        struct {
                unsigned int sym, str, mod, vers, info, pcpu;
        } index;
@@ -981,6 +984,8 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
                mod->exit();
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
+       ftrace_release_mod(mod);
+
        async_synchronize_full();
 
        /* Store the name of the last unloaded module for diagnostic purposes */
@@ -2480,10 +2485,21 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        strsect->sh_flags |= SHF_ALLOC;
        strsect->sh_entsize = get_offset(mod, &mod->init_layout.size, strsect,
                                         info->index.str) | INIT_OFFSET_MASK;
-       mod->init_layout.size = debug_align(mod->init_layout.size);
        pr_debug("\t%s\n", info->secstrings + strsect->sh_name);
+
+       /* We'll tack temporary mod_kallsyms on the end. */
+       mod->init_layout.size = ALIGN(mod->init_layout.size,
+                                     __alignof__(struct mod_kallsyms));
+       info->mod_kallsyms_init_off = mod->init_layout.size;
+       mod->init_layout.size += sizeof(struct mod_kallsyms);
+       mod->init_layout.size = debug_align(mod->init_layout.size);
 }
 
+/*
+ * We use the full symtab and strtab which layout_symtab arranged to
+ * be appended to the init section.  Later we switch to the cut-down
+ * core-only ones.
+ */
 static void add_kallsyms(struct module *mod, const struct load_info *info)
 {
        unsigned int i, ndst;
@@ -2492,29 +2508,34 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
        char *s;
        Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
 
-       mod->symtab = (void *)symsec->sh_addr;
-       mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+       /* Set up to point into init section. */
+       mod->kallsyms = mod->init_layout.base + info->mod_kallsyms_init_off;
+
+       mod->kallsyms->symtab = (void *)symsec->sh_addr;
+       mod->kallsyms->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
        /* Make sure we get permanent strtab: don't use info->strtab. */
-       mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
+       mod->kallsyms->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
 
        /* Set types up while we still have access to sections. */
-       for (i = 0; i < mod->num_symtab; i++)
-               mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
-
-       mod->core_symtab = dst = mod->core_layout.base + info->symoffs;
-       mod->core_strtab = s = mod->core_layout.base + info->stroffs;
-       src = mod->symtab;
-       for (ndst = i = 0; i < mod->num_symtab; i++) {
+       for (i = 0; i < mod->kallsyms->num_symtab; i++)
+               mod->kallsyms->symtab[i].st_info
+                       = elf_type(&mod->kallsyms->symtab[i], info);
+
+       /* Now populate the cut down core kallsyms for after init. */
+       mod->core_kallsyms.symtab = dst = mod->core_layout.base + info->symoffs;
+       mod->core_kallsyms.strtab = s = mod->core_layout.base + info->stroffs;
+       src = mod->kallsyms->symtab;
+       for (ndst = i = 0; i < mod->kallsyms->num_symtab; i++) {
                if (i == 0 ||
                    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum,
                                   info->index.pcpu)) {
                        dst[ndst] = src[i];
-                       dst[ndst++].st_name = s - mod->core_strtab;
-                       s += strlcpy(s, &mod->strtab[src[i].st_name],
+                       dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
+                       s += strlcpy(s, &mod->kallsyms->strtab[src[i].st_name],
                                     KSYM_NAME_LEN) + 1;
                }
        }
-       mod->core_num_syms = ndst;
+       mod->core_kallsyms.num_symtab = ndst;
 }
 #else
 static inline void layout_symtab(struct module *mod, struct load_info *info)
@@ -3263,9 +3284,8 @@ static noinline int do_init_module(struct module *mod)
        module_put(mod);
        trim_init_extable(mod);
 #ifdef CONFIG_KALLSYMS
-       mod->num_symtab = mod->core_num_syms;
-       mod->symtab = mod->core_symtab;
-       mod->strtab = mod->core_strtab;
+       /* Switch to core kallsyms now init is done: kallsyms may be walking! */
+       rcu_assign_pointer(mod->kallsyms, &mod->core_kallsyms);
 #endif
        mod_tree_remove_init(mod);
        disable_ro_nx(&mod->init_layout);
@@ -3295,6 +3315,7 @@ fail:
        module_put(mod);
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
+       ftrace_release_mod(mod);
        free_module(mod);
        wake_up_all(&module_wq);
        return ret;
@@ -3371,6 +3392,7 @@ static int complete_formation(struct module *mod, struct load_info *info)
        mod->state = MODULE_STATE_COMING;
        mutex_unlock(&module_mutex);
 
+       ftrace_module_enable(mod);
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_COMING, mod);
        return 0;
@@ -3496,7 +3518,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        /* Module is ready to execute: parsing args may do that. */
        after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-                                 -32768, 32767, NULL,
+                                 -32768, 32767, mod,
                                  unknown_module_param_cb);
        if (IS_ERR(after_dashes)) {
                err = PTR_ERR(after_dashes);
@@ -3627,6 +3649,11 @@ static inline int is_arm_mapping_symbol(const char *str)
               && (str[2] == '\0' || str[2] == '.');
 }
 
+static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
+{
+       return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
+}
+
 static const char *get_ksymbol(struct module *mod,
                               unsigned long addr,
                               unsigned long *size,
@@ -3634,6 +3661,7 @@ static const char *get_ksymbol(struct module *mod,
 {
        unsigned int i, best = 0;
        unsigned long nextval;
+       struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
 
        /* At worse, next value is at end of module */
        if (within_module_init(addr, mod))
@@ -3643,32 +3671,32 @@ static const char *get_ksymbol(struct module *mod,
 
        /* Scan for closest preceding symbol, and next symbol. (ELF
           starts real symbols at 1). */
-       for (i = 1; i < mod->num_symtab; i++) {
-               if (mod->symtab[i].st_shndx == SHN_UNDEF)
+       for (i = 1; i < kallsyms->num_symtab; i++) {
+               if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
                        continue;
 
                /* We ignore unnamed symbols: they're uninformative
                 * and inserted at a whim. */
-               if (mod->symtab[i].st_value <= addr
-                   && mod->symtab[i].st_value > mod->symtab[best].st_value
-                   && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-                   && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
+               if (*symname(kallsyms, i) == '\0'
+                   || is_arm_mapping_symbol(symname(kallsyms, i)))
+                       continue;
+
+               if (kallsyms->symtab[i].st_value <= addr
+                   && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
                        best = i;
-               if (mod->symtab[i].st_value > addr
-                   && mod->symtab[i].st_value < nextval
-                   && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-                   && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
-                       nextval = mod->symtab[i].st_value;
+               if (kallsyms->symtab[i].st_value > addr
+                   && kallsyms->symtab[i].st_value < nextval)
+                       nextval = kallsyms->symtab[i].st_value;
        }
 
        if (!best)
                return NULL;
 
        if (size)
-               *size = nextval - mod->symtab[best].st_value;
+               *size = nextval - kallsyms->symtab[best].st_value;
        if (offset)
-               *offset = addr - mod->symtab[best].st_value;
-       return mod->strtab + mod->symtab[best].st_name;
+               *offset = addr - kallsyms->symtab[best].st_value;
+       return symname(kallsyms, best);
 }
 
 /* For kallsyms to ask for address resolution.  NULL means not found.  Careful
@@ -3758,19 +3786,21 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               struct mod_kallsyms *kallsyms;
+
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               if (symnum < mod->num_symtab) {
-                       *value = mod->symtab[symnum].st_value;
-                       *type = mod->symtab[symnum].st_info;
-                       strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
-                               KSYM_NAME_LEN);
+               kallsyms = rcu_dereference_sched(mod->kallsyms);
+               if (symnum < kallsyms->num_symtab) {
+                       *value = kallsyms->symtab[symnum].st_value;
+                       *type = kallsyms->symtab[symnum].st_info;
+                       strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, *value, mod);
                        preempt_enable();
                        return 0;
                }
-               symnum -= mod->num_symtab;
+               symnum -= kallsyms->num_symtab;
        }
        preempt_enable();
        return -ERANGE;
@@ -3779,11 +3809,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 static unsigned long mod_find_symname(struct module *mod, const char *name)
 {
        unsigned int i;
+       struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
 
-       for (i = 0; i < mod->num_symtab; i++)
-               if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&
-                   mod->symtab[i].st_info != 'U')
-                       return mod->symtab[i].st_value;
+       for (i = 0; i < kallsyms->num_symtab; i++)
+               if (strcmp(name, symname(kallsyms, i)) == 0 &&
+                   kallsyms->symtab[i].st_info != 'U')
+                       return kallsyms->symtab[i].st_value;
        return 0;
 }
 
@@ -3822,11 +3853,14 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
        module_assert_mutex();
 
        list_for_each_entry(mod, &modules, list) {
+               /* We hold module_mutex: no need for rcu_dereference_sched */
+               struct mod_kallsyms *kallsyms = mod->kallsyms;
+
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               for (i = 0; i < mod->num_symtab; i++) {
-                       ret = fn(data, mod->strtab + mod->symtab[i].st_name,
-                                mod, mod->symtab[i].st_value);
+               for (i = 0; i < kallsyms->num_symtab; i++) {
+                       ret = fn(data, symname(kallsyms, i),
+                                mod, kallsyms->symtab[i].st_value);
                        if (ret != 0)
                                return ret;
                }
index 09c0597840b02dc260c65baafdd1fde0715bcbb4..3669d1bfc4254213e0e42dacab374624d74cdd5c 100644 (file)
@@ -1083,9 +1083,10 @@ struct resource * __request_region(struct resource *parent,
                if (!conflict)
                        break;
                if (conflict != parent) {
-                       parent = conflict;
-                       if (!(conflict->flags & IORESOURCE_BUSY))
+                       if (!(conflict->flags & IORESOURCE_BUSY)) {
+                               parent = conflict;
                                continue;
+                       }
                }
                if (conflict->flags & flags & IORESOURCE_MUXED) {
                        add_wait_queue(&muxed_resource_wait, &wait);
index cd64c979d0e1857aceb8f9f4383c507ad5fa6809..57b939c81bce5d06fa587df8915f05affbe22b82 100644 (file)
@@ -420,7 +420,7 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se,
         * entity.
         */
        if (dl_time_before(dl_se->deadline, rq_clock(rq))) {
-               printk_deferred_once("sched: DL replenish lagged to much\n");
+               printk_deferred_once("sched: DL replenish lagged too much\n");
                dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline;
                dl_se->runtime = pi_se->dl_runtime;
        }
index f3f1f7a972fd40f3d437d6bf3b5db2cacaffe6ca..0508544c8ced0d96913905dc53af68f38b6ee618 100644 (file)
@@ -3508,8 +3508,10 @@ static int sigsuspend(sigset_t *set)
        current->saved_sigmask = current->blocked;
        set_current_blocked(set);
 
-       __set_current_state(TASK_INTERRUPTIBLE);
-       schedule();
+       while (!signal_pending(current)) {
+               __set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+       }
        set_restore_sigmask();
        return -ERESTARTNOHAND;
 }
index 326a75e884dbf3f46513538861a028c7be459f09..3e4ffb3ace5faf371bfbfa0655a9845a96ef9c08 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/ctype.h>
 #include "trace.h"
 
-static DEFINE_PER_CPU(int, bpf_prog_active);
-
 /**
  * trace_call_bpf - invoke BPF program
  * @prog: BPF program
@@ -299,6 +297,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
                return &bpf_perf_event_read_proto;
        case BPF_FUNC_perf_event_output:
                return &bpf_perf_event_output_proto;
+       case BPF_FUNC_get_stackid:
+               return &bpf_get_stackid_proto;
        default:
                return NULL;
        }
index eca592f977b260689dc48911f867375b20ad5c8b..57a6eea8469408e7aba78669107eb3a1740362e4 100644 (file)
@@ -4961,7 +4961,7 @@ void ftrace_release_mod(struct module *mod)
        mutex_unlock(&ftrace_lock);
 }
 
-static void ftrace_module_enable(struct module *mod)
+void ftrace_module_enable(struct module *mod)
 {
        struct dyn_ftrace *rec;
        struct ftrace_page *pg;
@@ -5038,38 +5038,8 @@ void ftrace_module_init(struct module *mod)
        ftrace_process_locs(mod, mod->ftrace_callsites,
                            mod->ftrace_callsites + mod->num_ftrace_callsites);
 }
-
-static int ftrace_module_notify(struct notifier_block *self,
-                               unsigned long val, void *data)
-{
-       struct module *mod = data;
-
-       switch (val) {
-       case MODULE_STATE_COMING:
-               ftrace_module_enable(mod);
-               break;
-       case MODULE_STATE_GOING:
-               ftrace_release_mod(mod);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-#else
-static int ftrace_module_notify(struct notifier_block *self,
-                               unsigned long val, void *data)
-{
-       return 0;
-}
 #endif /* CONFIG_MODULES */
 
-struct notifier_block ftrace_module_nb = {
-       .notifier_call = ftrace_module_notify,
-       .priority = INT_MIN,    /* Run after anything that can remove kprobes */
-};
-
 void __init ftrace_init(void)
 {
        extern unsigned long __start_mcount_loc[];
@@ -5098,10 +5068,6 @@ void __init ftrace_init(void)
                                  __start_mcount_loc,
                                  __stop_mcount_loc);
 
-       ret = register_module_notifier(&ftrace_module_nb);
-       if (ret)
-               pr_warning("Failed to register trace ftrace module exit notifier\n");
-
        set_ftrace_early_filters();
 
        return;
index f333e57c4614a2a6aaac04061003f73cd3a6d844..05ddc0820771eb7bc456aab9e2f0e5167ce7f023 100644 (file)
@@ -97,16 +97,16 @@ trace_find_event_field(struct trace_event_call *call, char *name)
        struct ftrace_event_field *field;
        struct list_head *head;
 
-       field = __find_event_field(&ftrace_generic_fields, name);
+       head = trace_get_fields(call);
+       field = __find_event_field(head, name);
        if (field)
                return field;
 
-       field = __find_event_field(&ftrace_common_fields, name);
+       field = __find_event_field(&ftrace_generic_fields, name);
        if (field)
                return field;
 
-       head = trace_get_fields(call);
-       return __find_event_field(head, name);
+       return __find_event_field(&ftrace_common_fields, name);
 }
 
 static int __trace_define_field(struct list_head *head, const char *type,
@@ -171,8 +171,10 @@ static int trace_define_generic_fields(void)
 {
        int ret;
 
-       __generic_field(int, cpu, FILTER_OTHER);
-       __generic_field(char *, comm, FILTER_PTR_STRING);
+       __generic_field(int, CPU, FILTER_CPU);
+       __generic_field(int, cpu, FILTER_CPU);
+       __generic_field(char *, COMM, FILTER_COMM);
+       __generic_field(char *, comm, FILTER_COMM);
 
        return ret;
 }
@@ -869,7 +871,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                 * The ftrace subsystem is for showing formats only.
                 * They can not be enabled or disabled via the event files.
                 */
-               if (call->class && call->class->reg)
+               if (call->class && call->class->reg &&
+                   !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
                        return file;
        }
 
index f93a219b18daaa92ed314ad7ac4ba8e0ed3c4c09..6816302542b28158a4756373f5b3a57ed1a907fa 100644 (file)
@@ -1043,13 +1043,14 @@ static int init_pred(struct filter_parse_state *ps,
                return -EINVAL;
        }
 
-       if (is_string_field(field)) {
+       if (field->filter_type == FILTER_COMM) {
+               filter_build_regex(pred);
+               fn = filter_pred_comm;
+               pred->regex.field_len = TASK_COMM_LEN;
+       } else if (is_string_field(field)) {
                filter_build_regex(pred);
 
-               if (!strcmp(field->name, "comm")) {
-                       fn = filter_pred_comm;
-                       pred->regex.field_len = TASK_COMM_LEN;
-               } else if (field->filter_type == FILTER_STATIC_STRING) {
+               if (field->filter_type == FILTER_STATIC_STRING) {
                        fn = filter_pred_string;
                        pred->regex.field_len = field->size;
                } else if (field->filter_type == FILTER_DYN_STRING)
@@ -1072,7 +1073,7 @@ static int init_pred(struct filter_parse_state *ps,
                }
                pred->val = val;
 
-               if (!strcmp(field->name, "cpu"))
+               if (field->filter_type == FILTER_CPU)
                        fn = filter_pred_cpu;
                else
                        fn = select_comparison_fn(pred->op, field->size,
index dda9e6742950305f36fbe920f9fe0c6f68d83fbf..2a1abbaca10ec96126f3d8e380244214f77ee2a8 100644 (file)
@@ -125,6 +125,13 @@ check_stack(unsigned long ip, unsigned long *stack)
                        break;
        }
 
+       /*
+        * Some archs may not have the passed in ip in the dump.
+        * If that happens, we need to show everything.
+        */
+       if (i == stack_trace_max.nr_entries)
+               i = 0;
+
        /*
         * Now find where in the stack these are.
         */
@@ -149,7 +156,11 @@ check_stack(unsigned long ip, unsigned long *stack)
                for (; p < top && i < stack_trace_max.nr_entries; p++) {
                        if (stack_dump_trace[i] == ULONG_MAX)
                                break;
-                       if (*p == stack_dump_trace[i]) {
+                       /*
+                        * The READ_ONCE_NOCHECK is used to let KASAN know that
+                        * this is not a stack-out-of-bounds error.
+                        */
+                       if ((READ_ONCE_NOCHECK(*p)) == stack_dump_trace[i]) {
                                stack_dump_trace[x] = stack_dump_trace[i++];
                                this_size = stack_trace_index[x++] =
                                        (top - p) * sizeof(unsigned long);
index 61a0264e28f9b5917c0e8a60bb9668b21e59c4b2..7ff5dc7d2ac5f47395bc3be8484c642c5d577b6b 100644 (file)
@@ -301,7 +301,23 @@ static DEFINE_SPINLOCK(wq_mayday_lock);    /* protects wq->maydays list */
 static LIST_HEAD(workqueues);          /* PR: list of all workqueues */
 static bool workqueue_freezing;                /* PL: have wqs started freezing? */
 
-static cpumask_var_t wq_unbound_cpumask; /* PL: low level cpumask for all unbound wqs */
+/* PL: allowable cpus for unbound wqs and work items */
+static cpumask_var_t wq_unbound_cpumask;
+
+/* CPU where unbound work was last round robin scheduled from this CPU */
+static DEFINE_PER_CPU(int, wq_rr_cpu_last);
+
+/*
+ * Local execution of unbound work items is no longer guaranteed.  The
+ * following always forces round-robin CPU selection on unbound work items
+ * to uncover usages which depend on it.
+ */
+#ifdef CONFIG_DEBUG_WQ_FORCE_RR_CPU
+static bool wq_debug_force_rr_cpu = true;
+#else
+static bool wq_debug_force_rr_cpu = false;
+#endif
+module_param_named(debug_force_rr_cpu, wq_debug_force_rr_cpu, bool, 0644);
 
 /* the per-cpu worker pools */
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS],
@@ -570,6 +586,16 @@ static struct pool_workqueue *unbound_pwq_by_node(struct workqueue_struct *wq,
                                                  int node)
 {
        assert_rcu_or_wq_mutex_or_pool_mutex(wq);
+
+       /*
+        * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a
+        * delayed item is pending.  The plan is to keep CPU -> NODE
+        * mapping valid and stable across CPU on/offlines.  Once that
+        * happens, this workaround can be removed.
+        */
+       if (unlikely(node == NUMA_NO_NODE))
+               return wq->dfl_pwq;
+
        return rcu_dereference_raw(wq->numa_pwq_tbl[node]);
 }
 
@@ -1298,6 +1324,39 @@ static bool is_chained_work(struct workqueue_struct *wq)
        return worker && worker->current_pwq->wq == wq;
 }
 
+/*
+ * When queueing an unbound work item to a wq, prefer local CPU if allowed
+ * by wq_unbound_cpumask.  Otherwise, round robin among the allowed ones to
+ * avoid perturbing sensitive tasks.
+ */
+static int wq_select_unbound_cpu(int cpu)
+{
+       static bool printed_dbg_warning;
+       int new_cpu;
+
+       if (likely(!wq_debug_force_rr_cpu)) {
+               if (cpumask_test_cpu(cpu, wq_unbound_cpumask))
+                       return cpu;
+       } else if (!printed_dbg_warning) {
+               pr_warn("workqueue: round-robin CPU selection forced, expect performance impact\n");
+               printed_dbg_warning = true;
+       }
+
+       if (cpumask_empty(wq_unbound_cpumask))
+               return cpu;
+
+       new_cpu = __this_cpu_read(wq_rr_cpu_last);
+       new_cpu = cpumask_next_and(new_cpu, wq_unbound_cpumask, cpu_online_mask);
+       if (unlikely(new_cpu >= nr_cpu_ids)) {
+               new_cpu = cpumask_first_and(wq_unbound_cpumask, cpu_online_mask);
+               if (unlikely(new_cpu >= nr_cpu_ids))
+                       return cpu;
+       }
+       __this_cpu_write(wq_rr_cpu_last, new_cpu);
+
+       return new_cpu;
+}
+
 static void __queue_work(int cpu, struct workqueue_struct *wq,
                         struct work_struct *work)
 {
@@ -1323,7 +1382,7 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
                return;
 retry:
        if (req_cpu == WORK_CPU_UNBOUND)
-               cpu = raw_smp_processor_id();
+               cpu = wq_select_unbound_cpu(raw_smp_processor_id());
 
        /* pwq which will be used unless @work is executing elsewhere */
        if (!(wq->flags & WQ_UNBOUND))
@@ -1464,13 +1523,13 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
        timer_stats_timer_set_start_info(&dwork->timer);
 
        dwork->wq = wq;
-       /* timer isn't guaranteed to run in this cpu, record earlier */
-       if (cpu == WORK_CPU_UNBOUND)
-               cpu = raw_smp_processor_id();
        dwork->cpu = cpu;
        timer->expires = jiffies + delay;
 
-       add_timer_on(timer, cpu);
+       if (unlikely(cpu != WORK_CPU_UNBOUND))
+               add_timer_on(timer, cpu);
+       else
+               add_timer(timer);
 }
 
 /**
@@ -2355,7 +2414,8 @@ static void check_flush_dependency(struct workqueue_struct *target_wq,
        WARN_ONCE(current->flags & PF_MEMALLOC,
                  "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%pf",
                  current->pid, current->comm, target_wq->name, target_func);
-       WARN_ONCE(worker && (worker->current_pwq->wq->flags & WQ_MEM_RECLAIM),
+       WARN_ONCE(worker && ((worker->current_pwq->wq->flags &
+                             (WQ_MEM_RECLAIM | __WQ_LEGACY)) == WQ_MEM_RECLAIM),
                  "workqueue: WQ_MEM_RECLAIM %s:%pf is flushing !WQ_MEM_RECLAIM %s:%pf",
                  worker->current_pwq->wq->name, worker->current_func,
                  target_wq->name, target_func);
index ecb9e75614bf87f1e368074d6ef84bfe3f1003b8..60d09e9e8e8b7ad5b11a55c033223d3651178372 100644 (file)
@@ -1400,6 +1400,21 @@ config RCU_EQS_DEBUG
 
 endmenu # "RCU Debugging"
 
+config DEBUG_WQ_FORCE_RR_CPU
+       bool "Force round-robin CPU selection for unbound work items"
+       depends on DEBUG_KERNEL
+       default n
+       help
+         Workqueue used to implicitly guarantee that work items queued
+         without explicit CPU specified are put on the local CPU.  This
+         guarantee is no longer true and while local CPU is still
+         preferred work items may be put on foreign CPUs.  Kernel
+         parameter "workqueue.debug_force_rr_cpu" is added to force
+         round-robin CPU selection to flush out usages which depend on the
+         now broken guarantee.  This config option enables the debug
+         feature by default.  When enabled, memory and cache locality will
+         be impacted.
+
 config DEBUG_BLOCK_EXT_DEVT
         bool "Force extended block device numbers and spread them"
        depends on DEBUG_KERNEL
@@ -1738,6 +1753,14 @@ config TEST_KSTRTOX
 config TEST_PRINTF
        tristate "Test printf() family of functions at runtime"
 
+config TEST_BITMAP
+       tristate "Test bitmap_*() family of functions at runtime"
+       default n
+       help
+         Enable this option to test the bitmap functions at boot.
+
+         If unsure, say N.
+
 config TEST_RHASHTABLE
        tristate "Perform selftest on resizable hash table"
        default n
index 49518fb48cabb6d8c35b4a90b7d17917ebbfb211..e07c1ba9ba1339a80dac79d59255d80d600b096e 100644 (file)
@@ -18,6 +18,8 @@ config UBSAN_SANITIZE_ALL
          This option activates instrumentation for the entire kernel.
          If you don't enable this option, you have to explicitly specify
          UBSAN_SANITIZE := y for the files/directories you want to check for UB.
+         Enabling this option will get kernel image size increased
+         significantly.
 
 config UBSAN_ALIGNMENT
        bool "Enable checking of pointers alignment"
@@ -25,5 +27,5 @@ config UBSAN_ALIGNMENT
        default y if !HAVE_EFFICIENT_UNALIGNED_ACCESS
        help
          This option enables detection of unaligned memory accesses.
-         Enabling this option on architectures that support unalligned
+         Enabling this option on architectures that support unaligned
          accesses may produce a lot of false positives.
index a7c26a41a738bd1dee37a0654cc87e5c51d65653..dda4039588b1d82e354161877016119dc0afbe2b 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
 obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
 obj-$(CONFIG_TEST_PRINTF) += test_printf.o
+obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
index 814814397cce39b5b0a4aafa3571062a6468e8cf..c66da508cbf7826a769d25f24786252c958482a4 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -1059,6 +1061,93 @@ int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order)
 }
 EXPORT_SYMBOL(bitmap_allocate_region);
 
+/**
+ * bitmap_from_u32array - copy the contents of a u32 array of bits to bitmap
+ *     @bitmap: array of unsigned longs, the destination bitmap, non NULL
+ *     @nbits: number of bits in @bitmap
+ *     @buf: array of u32 (in host byte order), the source bitmap, non NULL
+ *     @nwords: number of u32 words in @buf
+ *
+ * copy min(nbits, 32*nwords) bits from @buf to @bitmap, remaining
+ * bits between nword and nbits in @bitmap (if any) are cleared. In
+ * last word of @bitmap, the bits beyond nbits (if any) are kept
+ * unchanged.
+ *
+ * Return the number of bits effectively copied.
+ */
+unsigned int
+bitmap_from_u32array(unsigned long *bitmap, unsigned int nbits,
+                    const u32 *buf, unsigned int nwords)
+{
+       unsigned int dst_idx, src_idx;
+
+       for (src_idx = dst_idx = 0; dst_idx < BITS_TO_LONGS(nbits); ++dst_idx) {
+               unsigned long part = 0;
+
+               if (src_idx < nwords)
+                       part = buf[src_idx++];
+
+#if BITS_PER_LONG == 64
+               if (src_idx < nwords)
+                       part |= ((unsigned long) buf[src_idx++]) << 32;
+#endif
+
+               if (dst_idx < nbits/BITS_PER_LONG)
+                       bitmap[dst_idx] = part;
+               else {
+                       unsigned long mask = BITMAP_LAST_WORD_MASK(nbits);
+
+                       bitmap[dst_idx] = (bitmap[dst_idx] & ~mask)
+                               | (part & mask);
+               }
+       }
+
+       return min_t(unsigned int, nbits, 32*nwords);
+}
+EXPORT_SYMBOL(bitmap_from_u32array);
+
+/**
+ * bitmap_to_u32array - copy the contents of bitmap to a u32 array of bits
+ *     @buf: array of u32 (in host byte order), the dest bitmap, non NULL
+ *     @nwords: number of u32 words in @buf
+ *     @bitmap: array of unsigned longs, the source bitmap, non NULL
+ *     @nbits: number of bits in @bitmap
+ *
+ * copy min(nbits, 32*nwords) bits from @bitmap to @buf. Remaining
+ * bits after nbits in @buf (if any) are cleared.
+ *
+ * Return the number of bits effectively copied.
+ */
+unsigned int
+bitmap_to_u32array(u32 *buf, unsigned int nwords,
+                  const unsigned long *bitmap, unsigned int nbits)
+{
+       unsigned int dst_idx = 0, src_idx = 0;
+
+       while (dst_idx < nwords) {
+               unsigned long part = 0;
+
+               if (src_idx < BITS_TO_LONGS(nbits)) {
+                       part = bitmap[src_idx];
+                       if (src_idx >= nbits/BITS_PER_LONG)
+                               part &= BITMAP_LAST_WORD_MASK(nbits);
+                       src_idx++;
+               }
+
+               buf[dst_idx++] = part & 0xffffffffUL;
+
+#if BITS_PER_LONG == 64
+               if (dst_idx < nwords) {
+                       part >>= 32;
+                       buf[dst_idx++] = part & 0xffffffffUL;
+               }
+#endif
+       }
+
+       return min_t(unsigned int, nbits, 32*nwords);
+}
+EXPORT_SYMBOL(bitmap_to_u32array);
+
 /**
  * bitmap_copy_le - copy a bitmap, putting the bits into little-endian order.
  * @dst:   destination buffer
index 6745c6230db3403629048256968443f51b777655..c30d07e99dba4cc32be6aeb4d353d79058509b4b 100644 (file)
@@ -25,6 +25,7 @@ static atomic_t dump_lock = ATOMIC_INIT(-1);
 
 asmlinkage __visible void dump_stack(void)
 {
+       unsigned long flags;
        int was_locked;
        int old;
        int cpu;
@@ -33,9 +34,8 @@ asmlinkage __visible void dump_stack(void)
         * Permit this cpu to perform nested stack dumps while serialising
         * against other CPUs
         */
-       preempt_disable();
-
 retry:
+       local_irq_save(flags);
        cpu = smp_processor_id();
        old = atomic_cmpxchg(&dump_lock, -1, cpu);
        if (old == -1) {
@@ -43,6 +43,7 @@ retry:
        } else if (old == cpu) {
                was_locked = 1;
        } else {
+               local_irq_restore(flags);
                cpu_relax();
                goto retry;
        }
@@ -52,7 +53,7 @@ retry:
        if (!was_locked)
                atomic_set(&dump_lock, -1);
 
-       preempt_enable();
+       local_irq_restore(flags);
 }
 #else
 asmlinkage __visible void dump_stack(void)
index d74cf7a29afdb043112fee5c9ad7b37a631a9985..0507fa5d84c534917d0842a453bdbcaba386422a 100644 (file)
@@ -282,9 +282,9 @@ void klist_iter_init_node(struct klist *k, struct klist_iter *i,
                          struct klist_node *n)
 {
        i->i_klist = k;
-       i->i_cur = n;
-       if (n)
-               kref_get(&n->n_ref);
+       i->i_cur = NULL;
+       if (n && kref_get_unless_zero(&n->n_ref))
+               i->i_cur = n;
 }
 EXPORT_SYMBOL_GPL(klist_iter_init_node);
 
index fcf5d98574ce46871dca087d2c803dbfb67c0b81..6b79e9026e24894000a2bdf4180db80f8190b357 100644 (file)
@@ -1019,9 +1019,13 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                return 0;
 
        radix_tree_for_each_slot(slot, root, &iter, first_index) {
-               results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+               results[ret] = rcu_dereference_raw(*slot);
                if (!results[ret])
                        continue;
+               if (radix_tree_is_indirect_ptr(results[ret])) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
                if (++ret == max_items)
                        break;
        }
@@ -1098,9 +1102,13 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
                return 0;
 
        radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) {
-               results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+               results[ret] = rcu_dereference_raw(*slot);
                if (!results[ret])
                        continue;
+               if (radix_tree_is_indirect_ptr(results[ret])) {
+                       slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
                if (++ret == max_items)
                        break;
        }
index 12111910ccd076aaa1d01cbb9a9623306514a6cd..510d1ce7d4d23287fe866d2fd6649d5d66215fb5 100644 (file)
@@ -255,6 +255,7 @@ void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
                prandom_warmup(state);
        }
 }
+EXPORT_SYMBOL(prandom_seed_full_state);
 
 /*
  *     Generate better values after random number generator
index bafa9933fa768d6f76e4ade1296c873a3c38c139..004fc70fc56a3d06947f9e89c60e40e272ce551c 100644 (file)
@@ -598,9 +598,9 @@ EXPORT_SYMBOL(sg_miter_next);
  *
  * Description:
  *   Stops mapping iterator @miter.  @miter should have been started
- *   started using sg_miter_start().  A stopped iteration can be
- *   resumed by calling sg_miter_next() on it.  This is useful when
- *   resources (kmap) need to be released during iteration.
+ *   using sg_miter_start().  A stopped iteration can be resumed by
+ *   calling sg_miter_next() on it.  This is useful when resources (kmap)
+ *   need to be released during iteration.
  *
  * Context:
  *   Preemption disabled if the SG_MITER_ATOMIC is set.  Don't care
index 98866a770770c8bba0acf7bdbacea4699d9f14bf..25b5cbfb7615bd63da19677c877b9e49c3f519e3 100644 (file)
@@ -327,36 +327,67 @@ out:
 }
 
 #define string_get_size_maxbuf 16
-#define test_string_get_size_one(size, blk_size, units, exp_result)            \
+#define test_string_get_size_one(size, blk_size, exp_result10, exp_result2)    \
        do {                                                                   \
-               BUILD_BUG_ON(sizeof(exp_result) >= string_get_size_maxbuf);    \
-               __test_string_get_size((size), (blk_size), (units),            \
-                                      (exp_result));                          \
+               BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf);  \
+               BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf);   \
+               __test_string_get_size((size), (blk_size), (exp_result10),     \
+                                      (exp_result2));                         \
        } while (0)
 
 
-static __init void __test_string_get_size(const u64 size, const u64 blk_size,
-                                         const enum string_size_units units,
-                                         const char *exp_result)
+static __init void test_string_get_size_check(const char *units,
+                                             const char *exp,
+                                             char *res,
+                                             const u64 size,
+                                             const u64 blk_size)
 {
-       char buf[string_get_size_maxbuf];
-
-       string_get_size(size, blk_size, units, buf, sizeof(buf));
-       if (!memcmp(buf, exp_result, strlen(exp_result) + 1))
+       if (!memcmp(res, exp, strlen(exp) + 1))
                return;
 
-       buf[sizeof(buf) - 1] = '\0';
-       pr_warn("Test 'test_string_get_size_one' failed!\n");
-       pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %d\n",
+       res[string_get_size_maxbuf - 1] = '\0';
+
+       pr_warn("Test 'test_string_get_size' failed!\n");
+       pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
                size, blk_size, units);
-       pr_warn("expected: '%s', got '%s'\n", exp_result, buf);
+       pr_warn("expected: '%s', got '%s'\n", exp, res);
+}
+
+static __init void __test_string_get_size(const u64 size, const u64 blk_size,
+                                         const char *exp_result10,
+                                         const char *exp_result2)
+{
+       char buf10[string_get_size_maxbuf];
+       char buf2[string_get_size_maxbuf];
+
+       string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10));
+       string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2));
+
+       test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10,
+                                  size, blk_size);
+
+       test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2,
+                                  size, blk_size);
 }
 
 static __init void test_string_get_size(void)
 {
-       test_string_get_size_one(16384, 512, STRING_UNITS_2, "8.00 MiB");
-       test_string_get_size_one(8192, 4096, STRING_UNITS_10, "32.7 MB");
-       test_string_get_size_one(1, 512, STRING_UNITS_10, "512 B");
+       /* small values */
+       test_string_get_size_one(0, 512, "0 B", "0 B");
+       test_string_get_size_one(1, 512, "512 B", "512 B");
+       test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
+
+       /* normal values */
+       test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
+       test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
+       test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
+
+       /* weird block sizes */
+       test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
+
+       /* huge values */
+       test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB");
+       test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
 }
 
 static int __init test_string_helpers_init(void)
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
new file mode 100644 (file)
index 0000000..e2cbd43
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Test cases for printf facility.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitmap.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+static unsigned total_tests __initdata;
+static unsigned failed_tests __initdata;
+
+static char pbl_buffer[PAGE_SIZE] __initdata;
+
+
+static bool __init
+__check_eq_uint(const char *srcfile, unsigned int line,
+               const unsigned int exp_uint, unsigned int x)
+{
+       if (exp_uint != x) {
+               pr_warn("[%s:%u] expected %u, got %u\n",
+                       srcfile, line, exp_uint, x);
+               return false;
+       }
+       return true;
+}
+
+
+static bool __init
+__check_eq_bitmap(const char *srcfile, unsigned int line,
+                 const unsigned long *exp_bmap, unsigned int exp_nbits,
+                 const unsigned long *bmap, unsigned int nbits)
+{
+       if (exp_nbits != nbits) {
+               pr_warn("[%s:%u] bitmap length mismatch: expected %u, got %u\n",
+                       srcfile, line, exp_nbits, nbits);
+               return false;
+       }
+
+       if (!bitmap_equal(exp_bmap, bmap, nbits)) {
+               pr_warn("[%s:%u] bitmaps contents differ: expected \"%*pbl\", got \"%*pbl\"\n",
+                       srcfile, line,
+                       exp_nbits, exp_bmap, nbits, bmap);
+               return false;
+       }
+       return true;
+}
+
+static bool __init
+__check_eq_pbl(const char *srcfile, unsigned int line,
+              const char *expected_pbl,
+              const unsigned long *bitmap, unsigned int nbits)
+{
+       snprintf(pbl_buffer, sizeof(pbl_buffer), "%*pbl", nbits, bitmap);
+       if (strcmp(expected_pbl, pbl_buffer)) {
+               pr_warn("[%s:%u] expected \"%s\", got \"%s\"\n",
+                       srcfile, line,
+                       expected_pbl, pbl_buffer);
+               return false;
+       }
+       return true;
+}
+
+static bool __init
+__check_eq_u32_array(const char *srcfile, unsigned int line,
+                    const u32 *exp_arr, unsigned int exp_len,
+                    const u32 *arr, unsigned int len)
+{
+       if (exp_len != len) {
+               pr_warn("[%s:%u] array length differ: expected %u, got %u\n",
+                       srcfile, line,
+                       exp_len, len);
+               return false;
+       }
+
+       if (memcmp(exp_arr, arr, len*sizeof(*arr))) {
+               pr_warn("[%s:%u] array contents differ\n", srcfile, line);
+               print_hex_dump(KERN_WARNING, "  exp:  ", DUMP_PREFIX_OFFSET,
+                              32, 4, exp_arr, exp_len*sizeof(*exp_arr), false);
+               print_hex_dump(KERN_WARNING, "  got:  ", DUMP_PREFIX_OFFSET,
+                              32, 4, arr, len*sizeof(*arr), false);
+               return false;
+       }
+
+       return true;
+}
+
+#define __expect_eq(suffix, ...)                                       \
+       ({                                                              \
+               int result = 0;                                         \
+               total_tests++;                                          \
+               if (!__check_eq_ ## suffix(__FILE__, __LINE__,          \
+                                          ##__VA_ARGS__)) {            \
+                       failed_tests++;                                 \
+                       result = 1;                                     \
+               }                                                       \
+               result;                                                 \
+       })
+
+#define expect_eq_uint(...)            __expect_eq(uint, ##__VA_ARGS__)
+#define expect_eq_bitmap(...)          __expect_eq(bitmap, ##__VA_ARGS__)
+#define expect_eq_pbl(...)             __expect_eq(pbl, ##__VA_ARGS__)
+#define expect_eq_u32_array(...)       __expect_eq(u32_array, ##__VA_ARGS__)
+
+static void __init test_zero_fill_copy(void)
+{
+       DECLARE_BITMAP(bmap1, 1024);
+       DECLARE_BITMAP(bmap2, 1024);
+
+       bitmap_zero(bmap1, 1024);
+       bitmap_zero(bmap2, 1024);
+
+       /* single-word bitmaps */
+       expect_eq_pbl("", bmap1, 23);
+
+       bitmap_fill(bmap1, 19);
+       expect_eq_pbl("0-18", bmap1, 1024);
+
+       bitmap_copy(bmap2, bmap1, 23);
+       expect_eq_pbl("0-18", bmap2, 1024);
+
+       bitmap_fill(bmap2, 23);
+       expect_eq_pbl("0-22", bmap2, 1024);
+
+       bitmap_copy(bmap2, bmap1, 23);
+       expect_eq_pbl("0-18", bmap2, 1024);
+
+       bitmap_zero(bmap1, 23);
+       expect_eq_pbl("", bmap1, 1024);
+
+       /* multi-word bitmaps */
+       bitmap_zero(bmap1, 1024);
+       expect_eq_pbl("", bmap1, 1024);
+
+       bitmap_fill(bmap1, 109);
+       expect_eq_pbl("0-108", bmap1, 1024);
+
+       bitmap_copy(bmap2, bmap1, 1024);
+       expect_eq_pbl("0-108", bmap2, 1024);
+
+       bitmap_fill(bmap2, 1024);
+       expect_eq_pbl("0-1023", bmap2, 1024);
+
+       bitmap_copy(bmap2, bmap1, 1024);
+       expect_eq_pbl("0-108", bmap2, 1024);
+
+       /* the following tests assume a 32- or 64-bit arch (even 128b
+        * if we care)
+        */
+
+       bitmap_fill(bmap2, 1024);
+       bitmap_copy(bmap2, bmap1, 109);  /* ... but 0-padded til word length */
+       expect_eq_pbl("0-108,128-1023", bmap2, 1024);
+
+       bitmap_fill(bmap2, 1024);
+       bitmap_copy(bmap2, bmap1, 97);  /* ... but aligned on word length */
+       expect_eq_pbl("0-108,128-1023", bmap2, 1024);
+
+       bitmap_zero(bmap2, 97);  /* ... but 0-padded til word length */
+       expect_eq_pbl("128-1023", bmap2, 1024);
+}
+
+static void __init test_bitmap_u32_array_conversions(void)
+{
+       DECLARE_BITMAP(bmap1, 1024);
+       DECLARE_BITMAP(bmap2, 1024);
+       u32 exp_arr[32], arr[32];
+       unsigned nbits;
+
+       for (nbits = 0 ; nbits < 257 ; ++nbits) {
+               const unsigned int used_u32s = DIV_ROUND_UP(nbits, 32);
+               unsigned int i, rv;
+
+               bitmap_zero(bmap1, nbits);
+               bitmap_set(bmap1, nbits, 1024 - nbits);  /* garbage */
+
+               memset(arr, 0xff, sizeof(arr));
+               rv = bitmap_to_u32array(arr, used_u32s, bmap1, nbits);
+               expect_eq_uint(nbits, rv);
+
+               memset(exp_arr, 0xff, sizeof(exp_arr));
+               memset(exp_arr, 0, used_u32s*sizeof(*exp_arr));
+               expect_eq_u32_array(exp_arr, 32, arr, 32);
+
+               bitmap_fill(bmap2, 1024);
+               rv = bitmap_from_u32array(bmap2, nbits, arr, used_u32s);
+               expect_eq_uint(nbits, rv);
+               expect_eq_bitmap(bmap1, 1024, bmap2, 1024);
+
+               for (i = 0 ; i < nbits ; ++i) {
+                       /*
+                        * test conversion bitmap -> u32[]
+                        */
+
+                       bitmap_zero(bmap1, 1024);
+                       __set_bit(i, bmap1);
+                       bitmap_set(bmap1, nbits, 1024 - nbits);  /* garbage */
+
+                       memset(arr, 0xff, sizeof(arr));
+                       rv = bitmap_to_u32array(arr, used_u32s, bmap1, nbits);
+                       expect_eq_uint(nbits, rv);
+
+                       /* 1st used u32 words contain expected bit set, the
+                        * remaining words are left unchanged (0xff)
+                        */
+                       memset(exp_arr, 0xff, sizeof(exp_arr));
+                       memset(exp_arr, 0, used_u32s*sizeof(*exp_arr));
+                       exp_arr[i/32] = (1U<<(i%32));
+                       expect_eq_u32_array(exp_arr, 32, arr, 32);
+
+
+                       /* same, with longer array to fill
+                        */
+                       memset(arr, 0xff, sizeof(arr));
+                       rv = bitmap_to_u32array(arr, 32, bmap1, nbits);
+                       expect_eq_uint(nbits, rv);
+
+                       /* 1st used u32 words contain expected bit set, the
+                        * remaining words are all 0s
+                        */
+                       memset(exp_arr, 0, sizeof(exp_arr));
+                       exp_arr[i/32] = (1U<<(i%32));
+                       expect_eq_u32_array(exp_arr, 32, arr, 32);
+
+                       /*
+                        * test conversion u32[] -> bitmap
+                        */
+
+                       /* the 1st nbits of bmap2 are identical to
+                        * bmap1, the remaining bits of bmap2 are left
+                        * unchanged (all 1s)
+                        */
+                       bitmap_fill(bmap2, 1024);
+                       rv = bitmap_from_u32array(bmap2, nbits,
+                                                 exp_arr, used_u32s);
+                       expect_eq_uint(nbits, rv);
+
+                       expect_eq_bitmap(bmap1, 1024, bmap2, 1024);
+
+                       /* same, with more bits to fill
+                        */
+                       memset(arr, 0xff, sizeof(arr));  /* garbage */
+                       memset(arr, 0, used_u32s*sizeof(u32));
+                       arr[i/32] = (1U<<(i%32));
+
+                       bitmap_fill(bmap2, 1024);
+                       rv = bitmap_from_u32array(bmap2, 1024, arr, used_u32s);
+                       expect_eq_uint(used_u32s*32, rv);
+
+                       /* the 1st nbits of bmap2 are identical to
+                        * bmap1, the remaining bits of bmap2 are cleared
+                        */
+                       bitmap_zero(bmap1, 1024);
+                       __set_bit(i, bmap1);
+                       expect_eq_bitmap(bmap1, 1024, bmap2, 1024);
+
+
+                       /*
+                        * test short conversion bitmap -> u32[] (1
+                        * word too short)
+                        */
+                       if (used_u32s > 1) {
+                               bitmap_zero(bmap1, 1024);
+                               __set_bit(i, bmap1);
+                               bitmap_set(bmap1, nbits,
+                                          1024 - nbits);  /* garbage */
+                               memset(arr, 0xff, sizeof(arr));
+
+                               rv = bitmap_to_u32array(arr, used_u32s - 1,
+                                                       bmap1, nbits);
+                               expect_eq_uint((used_u32s - 1)*32, rv);
+
+                               /* 1st used u32 words contain expected
+                                * bit set, the remaining words are
+                                * left unchanged (0xff)
+                                */
+                               memset(exp_arr, 0xff, sizeof(exp_arr));
+                               memset(exp_arr, 0,
+                                      (used_u32s-1)*sizeof(*exp_arr));
+                               if ((i/32) < (used_u32s - 1))
+                                       exp_arr[i/32] = (1U<<(i%32));
+                               expect_eq_u32_array(exp_arr, 32, arr, 32);
+                       }
+
+                       /*
+                        * test short conversion u32[] -> bitmap (3
+                        * bits too short)
+                        */
+                       if (nbits > 3) {
+                               memset(arr, 0xff, sizeof(arr));  /* garbage */
+                               memset(arr, 0, used_u32s*sizeof(*arr));
+                               arr[i/32] = (1U<<(i%32));
+
+                               bitmap_zero(bmap1, 1024);
+                               rv = bitmap_from_u32array(bmap1, nbits - 3,
+                                                         arr, used_u32s);
+                               expect_eq_uint(nbits - 3, rv);
+
+                               /* we are expecting the bit < nbits -
+                                * 3 (none otherwise), and the rest of
+                                * bmap1 unchanged (0-filled)
+                                */
+                               bitmap_zero(bmap2, 1024);
+                               if (i < nbits - 3)
+                                       __set_bit(i, bmap2);
+                               expect_eq_bitmap(bmap2, 1024, bmap1, 1024);
+
+                               /* do the same with bmap1 initially
+                                * 1-filled
+                                */
+
+                               bitmap_fill(bmap1, 1024);
+                               rv = bitmap_from_u32array(bmap1, nbits - 3,
+                                                        arr, used_u32s);
+                               expect_eq_uint(nbits - 3, rv);
+
+                               /* we are expecting the bit < nbits -
+                                * 3 (none otherwise), and the rest of
+                                * bmap1 unchanged (1-filled)
+                                */
+                               bitmap_zero(bmap2, 1024);
+                               if (i < nbits - 3)
+                                       __set_bit(i, bmap2);
+                               bitmap_set(bmap2, nbits-3, 1024 - nbits + 3);
+                               expect_eq_bitmap(bmap2, 1024, bmap1, 1024);
+                       }
+               }
+       }
+}
+
+static int __init test_bitmap_init(void)
+{
+       test_zero_fill_copy();
+       test_bitmap_u32_array_conversions();
+
+       if (failed_tests == 0)
+               pr_info("all %u tests passed\n", total_tests);
+       else
+               pr_warn("failed %u out of %u tests\n",
+                       failed_tests, total_tests);
+
+       return failed_tests ? -EINVAL : 0;
+}
+
+static void __exit test_bitmap_cleanup(void)
+{
+}
+
+module_init(test_bitmap_init);
+module_exit(test_bitmap_cleanup);
+
+MODULE_AUTHOR("david decotigny <david.decotigny@googlers.com>");
+MODULE_LICENSE("GPL");
index 6f500ef2301d893c9b2c737747fc355974ff4a19..f0b323abb4c64a566700d9d265f4451174847eaa 100644 (file)
@@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
         }
 }
 EXPORT_SYMBOL(ucs2_strncmp);
+
+unsigned long
+ucs2_utf8size(const ucs2_char_t *src)
+{
+       unsigned long i;
+       unsigned long j = 0;
+
+       for (i = 0; i < ucs2_strlen(src); i++) {
+               u16 c = src[i];
+
+               if (c >= 0x800)
+                       j += 3;
+               else if (c >= 0x80)
+                       j += 2;
+               else
+                       j += 1;
+       }
+
+       return j;
+}
+EXPORT_SYMBOL(ucs2_utf8size);
+
+/*
+ * copy at most maxlength bytes of whole utf8 characters to dest from the
+ * ucs2 string src.
+ *
+ * The return value is the number of characters copied, not including the
+ * final NUL character.
+ */
+unsigned long
+ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength)
+{
+       unsigned int i;
+       unsigned long j = 0;
+       unsigned long limit = ucs2_strnlen(src, maxlength);
+
+       for (i = 0; maxlength && i < limit; i++) {
+               u16 c = src[i];
+
+               if (c >= 0x800) {
+                       if (maxlength < 3)
+                               break;
+                       maxlength -= 3;
+                       dest[j++] = 0xe0 | (c & 0xf000) >> 12;
+                       dest[j++] = 0x80 | (c & 0x0fc0) >> 6;
+                       dest[j++] = 0x80 | (c & 0x003f);
+               } else if (c >= 0x80) {
+                       if (maxlength < 2)
+                               break;
+                       maxlength -= 2;
+                       dest[j++] = 0xc0 | (c & 0x7c0) >> 6;
+                       dest[j++] = 0x80 | (c & 0x03f);
+               } else {
+                       maxlength -= 1;
+                       dest[j++] = c & 0x7f;
+               }
+       }
+       if (maxlength)
+               dest[j] = '\0';
+       return j;
+}
+EXPORT_SYMBOL(ucs2_as_utf8);
index 48ff9c36644d64c324c5c243212f282e406dce2f..f44e178e6edec22e2f7c405f8cb433b2be935f83 100644 (file)
@@ -1590,22 +1590,23 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                        return buf;
                }
        case 'K':
-               /*
-                * %pK cannot be used in IRQ context because its test
-                * for CAP_SYSLOG would be meaningless.
-                */
-               if (kptr_restrict && (in_irq() || in_serving_softirq() ||
-                                     in_nmi())) {
-                       if (spec.field_width == -1)
-                               spec.field_width = default_width;
-                       return string(buf, end, "pK-error", spec);
-               }
-
                switch (kptr_restrict) {
                case 0:
                        /* Always print %pK values */
                        break;
                case 1: {
+                       const struct cred *cred;
+
+                       /*
+                        * kptr_restrict==1 cannot be used in IRQ context
+                        * because its test for CAP_SYSLOG would be meaningless.
+                        */
+                       if (in_irq() || in_serving_softirq() || in_nmi()) {
+                               if (spec.field_width == -1)
+                                       spec.field_width = default_width;
+                               return string(buf, end, "pK-error", spec);
+                       }
+
                        /*
                         * Only print the real pointer value if the current
                         * process has CAP_SYSLOG and is running with the
@@ -1615,8 +1616,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                         * leak pointer values if a binary opens a file using
                         * %pK and then elevates privileges before reading it.
                         */
-                       const struct cred *cred = current_cred();
-
+                       cred = current_cred();
                        if (!has_capability_noaudit(current, CAP_SYSLOG) ||
                            !uid_eq(cred->euid, cred->uid) ||
                            !gid_eq(cred->egid, cred->gid))
index 97a4e06b15c00dfd7f8b8bc0f1e1e4610b769938..03cbfa072f42a7378ed57b8b1060641b31e7d97e 100644 (file)
@@ -624,7 +624,7 @@ config ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT
        bool
 
 config DEFERRED_STRUCT_PAGE_INIT
-       bool "Defer initialisation of struct pages to kswapd"
+       bool "Defer initialisation of struct pages to kthreads"
        default n
        depends on ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT
        depends on MEMORY_HOTPLUG
@@ -633,9 +633,10 @@ config DEFERRED_STRUCT_PAGE_INIT
          single thread. On very large machines this can take a considerable
          amount of time. If this option is set, large machines will bring up
          a subset of memmap at boot and then initialise the rest in parallel
-         when kswapd starts. This has a potential performance impact on
-         processes running early in the lifetime of the systemm until kswapd
-         finishes the initialisation.
+         by starting one-off "pgdatinitX" kernel thread for each node X. This
+         has a potential performance impact on processes running early in the
+         lifetime of the system until these kthreads finish the
+         initialisation.
 
 config IDLE_PAGE_TRACKING
        bool "Enable idle page tracking"
index cc5d29d2da9b4b36be3fde383267ff10c59e1422..c554d173a65fa640186b058e5e97be68b48c7ea5 100644 (file)
@@ -328,7 +328,7 @@ static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi,
        return 0;
 
 out_destroy_stat:
-       while (--i)
+       while (i--)
                percpu_counter_destroy(&wb->stat[i]);
        fprop_local_destroy_percpu(&wb->completions);
 out_put_cong:
@@ -989,7 +989,7 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout)
                 * here rather than calling cond_resched().
                 */
                if (current->flags & PF_WQ_WORKER)
-                       schedule_timeout(1);
+                       schedule_timeout_uninterruptible(1);
                else
                        cond_resched();
 
index bc943867d68c68dab4109fe715c8d37d6c72757a..3461d97ecb30bfe18d1ed50729e5147aa2ad7e6d 100644 (file)
@@ -446,7 +446,8 @@ int filemap_write_and_wait(struct address_space *mapping)
 {
        int err = 0;
 
-       if (mapping->nrpages) {
+       if ((!dax_mapping(mapping) && mapping->nrpages) ||
+           (dax_mapping(mapping) && mapping->nrexceptional)) {
                err = filemap_fdatawrite(mapping);
                /*
                 * Even if the above returned error, the pages may be
@@ -482,13 +483,8 @@ int filemap_write_and_wait_range(struct address_space *mapping,
 {
        int err = 0;
 
-       if (dax_mapping(mapping) && mapping->nrexceptional) {
-               err = dax_writeback_mapping_range(mapping, lstart, lend);
-               if (err)
-                       return err;
-       }
-
-       if (mapping->nrpages) {
+       if ((!dax_mapping(mapping) && mapping->nrpages) ||
+           (dax_mapping(mapping) && mapping->nrexceptional)) {
                err = __filemap_fdatawrite_range(mapping, lstart, lend,
                                                 WB_SYNC_ALL);
                /* See comment of filemap_write_and_wait() */
@@ -1890,6 +1886,7 @@ EXPORT_SYMBOL(generic_file_read_iter);
  * page_cache_read - adds requested page to the page cache if not already there
  * @file:      file to read
  * @offset:    page index
+ * @gfp_mask:  memory allocation flags
  *
  * This adds the requested page to the page cache if it isn't already there,
  * and schedules an I/O to read in its contents from disk.
index b64a36175884e07604b0e216bc2d545a2892dcb7..7bf19ffa21999c13fa1f24dc01a6bda77217688c 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -430,10 +430,8 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
                         * Anon pages in shared mappings are surprising: now
                         * just reject it.
                         */
-                       if (!is_cow_mapping(vm_flags)) {
-                               WARN_ON_ONCE(vm_flags & VM_MAYWRITE);
+                       if (!is_cow_mapping(vm_flags))
                                return -EFAULT;
-                       }
                }
        } else if (!(vm_flags & VM_READ)) {
                if (!(gup_flags & FOLL_FORCE))
index fd3a07b3e6f4e086b2111c312a78512bed927f9b..e10a4fee88d2bcf1f4bba89285391cbadfb96098 100644 (file)
@@ -138,9 +138,6 @@ static struct khugepaged_scan khugepaged_scan = {
        .mm_head = LIST_HEAD_INIT(khugepaged_scan.mm_head),
 };
 
-static DEFINE_SPINLOCK(split_queue_lock);
-static LIST_HEAD(split_queue);
-static unsigned long split_queue_len;
 static struct shrinker deferred_split_shrinker;
 
 static void set_recommended_min_free_kbytes(void)
@@ -861,7 +858,8 @@ static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm,
                return false;
        entry = mk_pmd(zero_page, vma->vm_page_prot);
        entry = pmd_mkhuge(entry);
-       pgtable_trans_huge_deposit(mm, pmd, pgtable);
+       if (pgtable)
+               pgtable_trans_huge_deposit(mm, pmd, pgtable);
        set_pmd_at(mm, haddr, pmd, entry);
        atomic_long_inc(&mm->nr_ptes);
        return true;
@@ -1039,13 +1037,15 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
        spinlock_t *dst_ptl, *src_ptl;
        struct page *src_page;
        pmd_t pmd;
-       pgtable_t pgtable;
+       pgtable_t pgtable = NULL;
        int ret;
 
-       ret = -ENOMEM;
-       pgtable = pte_alloc_one(dst_mm, addr);
-       if (unlikely(!pgtable))
-               goto out;
+       if (!vma_is_dax(vma)) {
+               ret = -ENOMEM;
+               pgtable = pte_alloc_one(dst_mm, addr);
+               if (unlikely(!pgtable))
+                       goto out;
+       }
 
        dst_ptl = pmd_lock(dst_mm, dst_pmd);
        src_ptl = pmd_lockptr(src_mm, src_pmd);
@@ -1076,7 +1076,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                goto out_unlock;
        }
 
-       if (pmd_trans_huge(pmd)) {
+       if (!vma_is_dax(vma)) {
                /* thp accounting separate from pmd_devmap accounting */
                src_page = pmd_page(pmd);
                VM_BUG_ON_PAGE(!PageHead(src_page), src_page);
@@ -1700,7 +1700,8 @@ bool move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
                pmd = pmdp_huge_get_and_clear(mm, old_addr, old_pmd);
                VM_BUG_ON(!pmd_none(*new_pmd));
 
-               if (pmd_move_must_withdraw(new_ptl, old_ptl)) {
+               if (pmd_move_must_withdraw(new_ptl, old_ptl) &&
+                               vma_is_anonymous(vma)) {
                        pgtable_t pgtable;
                        pgtable = pgtable_trans_huge_withdraw(mm, old_pmd);
                        pgtable_trans_huge_deposit(mm, new_pmd, pgtable);
@@ -2835,6 +2836,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
        pgtable_t pgtable;
        pmd_t _pmd;
        bool young, write, dirty;
+       unsigned long addr;
        int i;
 
        VM_BUG_ON(haddr & ~HPAGE_PMD_MASK);
@@ -2860,10 +2862,11 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
        young = pmd_young(*pmd);
        dirty = pmd_dirty(*pmd);
 
+       pmdp_huge_split_prepare(vma, haddr, pmd);
        pgtable = pgtable_trans_huge_withdraw(mm, pmd);
        pmd_populate(mm, &_pmd, pgtable);
 
-       for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+       for (i = 0, addr = haddr; i < HPAGE_PMD_NR; i++, addr += PAGE_SIZE) {
                pte_t entry, *pte;
                /*
                 * Note that NUMA hinting access restrictions are not
@@ -2884,9 +2887,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
                }
                if (dirty)
                        SetPageDirty(page + i);
-               pte = pte_offset_map(&_pmd, haddr);
+               pte = pte_offset_map(&_pmd, addr);
                BUG_ON(!pte_none(*pte));
-               set_pte_at(mm, haddr, pte, entry);
+               set_pte_at(mm, addr, pte, entry);
                atomic_inc(&page[i]._mapcount);
                pte_unmap(pte);
        }
@@ -2936,7 +2939,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
        pmd_populate(mm, pmd, pgtable);
 
        if (freeze) {
-               for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+               for (i = 0; i < HPAGE_PMD_NR; i++) {
                        page_remove_rmap(page + i, false);
                        put_page(page + i);
                }
@@ -3358,6 +3361,7 @@ int total_mapcount(struct page *page)
 int split_huge_page_to_list(struct page *page, struct list_head *list)
 {
        struct page *head = compound_head(page);
+       struct pglist_data *pgdata = NODE_DATA(page_to_nid(head));
        struct anon_vma *anon_vma;
        int count, mapcount, ret;
        bool mlocked;
@@ -3401,19 +3405,19 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                lru_add_drain();
 
        /* Prevent deferred_split_scan() touching ->_count */
-       spin_lock_irqsave(&split_queue_lock, flags);
+       spin_lock_irqsave(&pgdata->split_queue_lock, flags);
        count = page_count(head);
        mapcount = total_mapcount(head);
        if (!mapcount && count == 1) {
                if (!list_empty(page_deferred_list(head))) {
-                       split_queue_len--;
+                       pgdata->split_queue_len--;
                        list_del(page_deferred_list(head));
                }
-               spin_unlock_irqrestore(&split_queue_lock, flags);
+               spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
                __split_huge_page(page, list);
                ret = 0;
        } else if (IS_ENABLED(CONFIG_DEBUG_VM) && mapcount) {
-               spin_unlock_irqrestore(&split_queue_lock, flags);
+               spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
                pr_alert("total_mapcount: %u, page_count(): %u\n",
                                mapcount, count);
                if (PageTail(page))
@@ -3421,7 +3425,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
                dump_page(page, "total_mapcount(head) > 0");
                BUG();
        } else {
-               spin_unlock_irqrestore(&split_queue_lock, flags);
+               spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
                unfreeze_page(anon_vma, head);
                ret = -EBUSY;
        }
@@ -3436,64 +3440,65 @@ out:
 
 void free_transhuge_page(struct page *page)
 {
+       struct pglist_data *pgdata = NODE_DATA(page_to_nid(page));
        unsigned long flags;
 
-       spin_lock_irqsave(&split_queue_lock, flags);
+       spin_lock_irqsave(&pgdata->split_queue_lock, flags);
        if (!list_empty(page_deferred_list(page))) {
-               split_queue_len--;
+               pgdata->split_queue_len--;
                list_del(page_deferred_list(page));
        }
-       spin_unlock_irqrestore(&split_queue_lock, flags);
+       spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
        free_compound_page(page);
 }
 
 void deferred_split_huge_page(struct page *page)
 {
+       struct pglist_data *pgdata = NODE_DATA(page_to_nid(page));
        unsigned long flags;
 
        VM_BUG_ON_PAGE(!PageTransHuge(page), page);
 
-       spin_lock_irqsave(&split_queue_lock, flags);
+       spin_lock_irqsave(&pgdata->split_queue_lock, flags);
        if (list_empty(page_deferred_list(page))) {
-               list_add_tail(page_deferred_list(page), &split_queue);
-               split_queue_len++;
+               list_add_tail(page_deferred_list(page), &pgdata->split_queue);
+               pgdata->split_queue_len++;
        }
-       spin_unlock_irqrestore(&split_queue_lock, flags);
+       spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
 }
 
 static unsigned long deferred_split_count(struct shrinker *shrink,
                struct shrink_control *sc)
 {
-       /*
-        * Split a page from split_queue will free up at least one page,
-        * at most HPAGE_PMD_NR - 1. We don't track exact number.
-        * Let's use HPAGE_PMD_NR / 2 as ballpark.
-        */
-       return ACCESS_ONCE(split_queue_len) * HPAGE_PMD_NR / 2;
+       struct pglist_data *pgdata = NODE_DATA(sc->nid);
+       return ACCESS_ONCE(pgdata->split_queue_len);
 }
 
 static unsigned long deferred_split_scan(struct shrinker *shrink,
                struct shrink_control *sc)
 {
+       struct pglist_data *pgdata = NODE_DATA(sc->nid);
        unsigned long flags;
        LIST_HEAD(list), *pos, *next;
        struct page *page;
        int split = 0;
 
-       spin_lock_irqsave(&split_queue_lock, flags);
-       list_splice_init(&split_queue, &list);
-
+       spin_lock_irqsave(&pgdata->split_queue_lock, flags);
        /* Take pin on all head pages to avoid freeing them under us */
-       list_for_each_safe(pos, next, &list) {
+       list_for_each_safe(pos, next, &pgdata->split_queue) {
                page = list_entry((void *)pos, struct page, mapping);
                page = compound_head(page);
-               /* race with put_compound_page() */
-               if (!get_page_unless_zero(page)) {
+               if (get_page_unless_zero(page)) {
+                       list_move(page_deferred_list(page), &list);
+               } else {
+                       /* We lost race with put_compound_page() */
                        list_del_init(page_deferred_list(page));
-                       split_queue_len--;
+                       pgdata->split_queue_len--;
                }
+               if (!--sc->nr_to_scan)
+                       break;
        }
-       spin_unlock_irqrestore(&split_queue_lock, flags);
+       spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
 
        list_for_each_safe(pos, next, &list) {
                page = list_entry((void *)pos, struct page, mapping);
@@ -3505,17 +3510,24 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
                put_page(page);
        }
 
-       spin_lock_irqsave(&split_queue_lock, flags);
-       list_splice_tail(&list, &split_queue);
-       spin_unlock_irqrestore(&split_queue_lock, flags);
+       spin_lock_irqsave(&pgdata->split_queue_lock, flags);
+       list_splice_tail(&list, &pgdata->split_queue);
+       spin_unlock_irqrestore(&pgdata->split_queue_lock, flags);
 
-       return split * HPAGE_PMD_NR / 2;
+       /*
+        * Stop shrinker if we didn't split any page, but the queue is empty.
+        * This can happen if pages were freed under us.
+        */
+       if (!split && list_empty(&pgdata->split_queue))
+               return SHRINK_STOP;
+       return split;
 }
 
 static struct shrinker deferred_split_shrinker = {
        .count_objects = deferred_split_count,
        .scan_objects = deferred_split_scan,
        .seeks = DEFAULT_SEEKS,
+       .flags = SHRINKER_NUMA_AWARE,
 };
 
 #ifdef CONFIG_DEBUG_FS
index 12908dcf58316afd3f4b14d379a8e139249cd396..01f2b48c8618a9f973eeb11f2162b75bb8cf67d4 100644 (file)
@@ -1001,7 +1001,7 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed)
                ((node = hstate_next_node_to_free(hs, mask)) || 1);     \
                nr_nodes--)
 
-#if defined(CONFIG_CMA) && defined(CONFIG_X86_64)
+#if defined(CONFIG_X86_64) && ((defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA))
 static void destroy_compound_gigantic_page(struct page *page,
                                        unsigned int order)
 {
@@ -1214,8 +1214,8 @@ void free_huge_page(struct page *page)
 
        set_page_private(page, 0);
        page->mapping = NULL;
-       BUG_ON(page_count(page));
-       BUG_ON(page_mapcount(page));
+       VM_BUG_ON_PAGE(page_count(page), page);
+       VM_BUG_ON_PAGE(page_mapcount(page), page);
        restore_reserve = PagePrivate(page);
        ClearPagePrivate(page);
 
@@ -1286,6 +1286,7 @@ static void prep_compound_gigantic_page(struct page *page, unsigned int order)
                set_page_count(p, 0);
                set_compound_head(p, page);
        }
+       atomic_set(compound_mapcount_ptr(page), -1);
 }
 
 /*
@@ -2629,8 +2630,10 @@ static int __init hugetlb_init(void)
                        hugetlb_add_hstate(HUGETLB_PAGE_ORDER);
        }
        default_hstate_idx = hstate_index(size_to_hstate(default_hstate_size));
-       if (default_hstate_max_huge_pages)
-               default_hstate.max_huge_pages = default_hstate_max_huge_pages;
+       if (default_hstate_max_huge_pages) {
+               if (!default_hstate.max_huge_pages)
+                       default_hstate.max_huge_pages = default_hstate_max_huge_pages;
+       }
 
        hugetlb_init_hstates();
        gather_bootmem_prealloc();
index ed8b5ffcf9b16fbfcf3ccba0d182957980ad45ab..a38a21ebddb454540fc1dcae83be516ffc7cdf26 100644 (file)
@@ -216,6 +216,37 @@ static inline bool is_cow_mapping(vm_flags_t flags)
        return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
 }
 
+/*
+ * These three helpers classifies VMAs for virtual memory accounting.
+ */
+
+/*
+ * Executable code area - executable, not writable, not stack
+ */
+static inline bool is_exec_mapping(vm_flags_t flags)
+{
+       return (flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC;
+}
+
+/*
+ * Stack area - atomatically grows in one direction
+ *
+ * VM_GROWSUP / VM_GROWSDOWN VMAs are always private anonymous:
+ * do_mmap() forbids all other combinations.
+ */
+static inline bool is_stack_mapping(vm_flags_t flags)
+{
+       return (flags & VM_STACK) == VM_STACK;
+}
+
+/*
+ * Data area - private, writable, not stack
+ */
+static inline bool is_data_mapping(vm_flags_t flags)
+{
+       return (flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE;
+}
+
 /* mm/util.c */
 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
                struct vm_area_struct *prev, struct rb_node *rb_parent);
index d2ed81e59a94c3f81674ead9e84d51ca8ebd9950..dd7989929f13ae16e265bff30fd958f1f13993cb 100644 (file)
@@ -1448,7 +1448,7 @@ void __init __memblock_free_late(phys_addr_t base, phys_addr_t size)
  * Remaining API functions
  */
 
-phys_addr_t __init memblock_phys_mem_size(void)
+phys_addr_t __init_memblock memblock_phys_mem_size(void)
 {
        return memblock.memory.total_size;
 }
index 93ce37989471174439d8973f19b12e776e218cc3..8132787ae4d509d475ed6a77705076ddfee30630 100644 (file)
@@ -2237,11 +2237,6 @@ static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma,
 
        page_cache_get(old_page);
 
-       /*
-        * Only catch write-faults on shared writable pages,
-        * read-only shared pages can get COWed by
-        * get_user_pages(.write=1, .force=1).
-        */
        if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
                int tmp;
 
@@ -3409,8 +3404,18 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (unlikely(pmd_none(*pmd)) &&
            unlikely(__pte_alloc(mm, vma, pmd, address)))
                return VM_FAULT_OOM;
-       /* if an huge pmd materialized from under us just retry later */
-       if (unlikely(pmd_trans_huge(*pmd) || pmd_devmap(*pmd)))
+       /*
+        * If a huge pmd materialized under us just retry later.  Use
+        * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd
+        * didn't become pmd_trans_huge under us and then back to pmd_none, as
+        * a result of MADV_DONTNEED running immediately after a huge pmd fault
+        * in a different thread of this mm, in turn leading to a misleading
+        * pmd_trans_huge() retval.  All we have to ensure is that it is a
+        * regular pmd that we can walk with pte_offset_map() and we can do that
+        * through an atomic read in C, which is what pmd_trans_unstable()
+        * provides.
+        */
+       if (unlikely(pmd_trans_unstable(pmd) || pmd_devmap(*pmd)))
                return 0;
        /*
         * A regular pmd is established and it can't morph into a huge pmd
index 27d135408a22057a5b166e7eb2bf2e080bbd33f2..4c4187c0e1deeb25bdbf5eb383132d27feb9be90 100644 (file)
@@ -548,8 +548,7 @@ retry:
                        goto retry;
                }
 
-               if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
-                       migrate_page_add(page, qp->pagelist, flags);
+               migrate_page_add(page, qp->pagelist, flags);
        }
        pte_unmap_unlock(pte - 1, ptl);
        cond_resched();
@@ -625,7 +624,7 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
        unsigned long endvma = vma->vm_end;
        unsigned long flags = qp->flags;
 
-       if (vma->vm_flags & VM_PFNMAP)
+       if (!vma_migratable(vma))
                return 1;
 
        if (endvma > end)
@@ -644,16 +643,13 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end,
 
        if (flags & MPOL_MF_LAZY) {
                /* Similar to task_numa_work, skip inaccessible VMAs */
-               if (vma_migratable(vma) &&
-                       vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))
+               if (vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))
                        change_prot_numa(vma, start, endvma);
                return 1;
        }
 
-       if ((flags & MPOL_MF_STRICT) ||
-           ((flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) &&
-            vma_migratable(vma)))
-               /* queue pages from current vma */
+       /* queue pages from current vma */
+       if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
                return 0;
        return 1;
 }
index b1034f9c77e7d5a9bdbe60692396e5584c6991fc..3ad0fea5c4387c5b6ff1d8fb513b73488b9180f2 100644 (file)
@@ -1582,7 +1582,7 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
                                         (GFP_HIGHUSER_MOVABLE |
                                          __GFP_THISNODE | __GFP_NOMEMALLOC |
                                          __GFP_NORETRY | __GFP_NOWARN) &
-                                        ~(__GFP_IO | __GFP_FS), 0);
+                                        ~__GFP_RECLAIM, 0);
 
        return newpage;
 }
index 84b12624ceb01d83762172634179825b086961fd..76d1ec29149bf25f5e6ffe3e56e86467efccc641 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -42,6 +42,7 @@
 #include <linux/memory.h>
 #include <linux/printk.h>
 #include <linux/userfaultfd_k.h>
+#include <linux/moduleparam.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -69,6 +70,8 @@ const int mmap_rnd_compat_bits_max = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX;
 int mmap_rnd_compat_bits __read_mostly = CONFIG_ARCH_MMAP_RND_COMPAT_BITS;
 #endif
 
+static bool ignore_rlimit_data = true;
+core_param(ignore_rlimit_data, ignore_rlimit_data, bool, 0644);
 
 static void unmap_region(struct mm_struct *mm,
                struct vm_area_struct *vma, struct vm_area_struct *prev,
@@ -387,8 +390,9 @@ static long vma_compute_subtree_gap(struct vm_area_struct *vma)
 }
 
 #ifdef CONFIG_DEBUG_VM_RB
-static int browse_rb(struct rb_root *root)
+static int browse_rb(struct mm_struct *mm)
 {
+       struct rb_root *root = &mm->mm_rb;
        int i = 0, j, bug = 0;
        struct rb_node *nd, *pn = NULL;
        unsigned long prev = 0, pend = 0;
@@ -411,12 +415,14 @@ static int browse_rb(struct rb_root *root)
                                  vma->vm_start, vma->vm_end);
                        bug = 1;
                }
+               spin_lock(&mm->page_table_lock);
                if (vma->rb_subtree_gap != vma_compute_subtree_gap(vma)) {
                        pr_emerg("free gap %lx, correct %lx\n",
                               vma->rb_subtree_gap,
                               vma_compute_subtree_gap(vma));
                        bug = 1;
                }
+               spin_unlock(&mm->page_table_lock);
                i++;
                pn = nd;
                prev = vma->vm_start;
@@ -453,12 +459,16 @@ static void validate_mm(struct mm_struct *mm)
        struct vm_area_struct *vma = mm->mmap;
 
        while (vma) {
+               struct anon_vma *anon_vma = vma->anon_vma;
                struct anon_vma_chain *avc;
 
-               vma_lock_anon_vma(vma);
-               list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
-                       anon_vma_interval_tree_verify(avc);
-               vma_unlock_anon_vma(vma);
+               if (anon_vma) {
+                       anon_vma_lock_read(anon_vma);
+                       list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
+                               anon_vma_interval_tree_verify(avc);
+                       anon_vma_unlock_read(anon_vma);
+               }
+
                highest_address = vma->vm_end;
                vma = vma->vm_next;
                i++;
@@ -472,7 +482,7 @@ static void validate_mm(struct mm_struct *mm)
                          mm->highest_vm_end, highest_address);
                bug = 1;
        }
-       i = browse_rb(&mm->mm_rb);
+       i = browse_rb(mm);
        if (i != mm->map_count) {
                if (i != -1)
                        pr_emerg("map_count %d rb %d\n", mm->map_count, i);
@@ -2139,32 +2149,27 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
 int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 {
        struct mm_struct *mm = vma->vm_mm;
-       int error;
+       int error = 0;
 
        if (!(vma->vm_flags & VM_GROWSUP))
                return -EFAULT;
 
-       /*
-        * We must make sure the anon_vma is allocated
-        * so that the anon_vma locking is not a noop.
-        */
+       /* Guard against wrapping around to address 0. */
+       if (address < PAGE_ALIGN(address+4))
+               address = PAGE_ALIGN(address+4);
+       else
+               return -ENOMEM;
+
+       /* We must make sure the anon_vma is allocated. */
        if (unlikely(anon_vma_prepare(vma)))
                return -ENOMEM;
-       vma_lock_anon_vma(vma);
 
        /*
         * vma->vm_start/vm_end cannot change under us because the caller
         * is required to hold the mmap_sem in read mode.  We need the
         * anon_vma lock to serialize against concurrent expand_stacks.
-        * Also guard against wrapping around to address 0.
         */
-       if (address < PAGE_ALIGN(address+4))
-               address = PAGE_ALIGN(address+4);
-       else {
-               vma_unlock_anon_vma(vma);
-               return -ENOMEM;
-       }
-       error = 0;
+       anon_vma_lock_write(vma->anon_vma);
 
        /* Somebody else might have raced and expanded it already */
        if (address > vma->vm_end) {
@@ -2182,7 +2187,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                                 * updates, but we only hold a shared mmap_sem
                                 * lock here, so we need to protect against
                                 * concurrent vma expansions.
-                                * vma_lock_anon_vma() doesn't help here, as
+                                * anon_vma_lock_write() doesn't help here, as
                                 * we don't guarantee that all growable vmas
                                 * in a mm share the same root anon vma.
                                 * So, we reuse mm->page_table_lock to guard
@@ -2205,7 +2210,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
                        }
                }
        }
-       vma_unlock_anon_vma(vma);
+       anon_vma_unlock_write(vma->anon_vma);
        khugepaged_enter_vma_merge(vma, vma->vm_flags);
        validate_mm(mm);
        return error;
@@ -2221,25 +2226,21 @@ int expand_downwards(struct vm_area_struct *vma,
        struct mm_struct *mm = vma->vm_mm;
        int error;
 
-       /*
-        * We must make sure the anon_vma is allocated
-        * so that the anon_vma locking is not a noop.
-        */
-       if (unlikely(anon_vma_prepare(vma)))
-               return -ENOMEM;
-
        address &= PAGE_MASK;
        error = security_mmap_addr(address);
        if (error)
                return error;
 
-       vma_lock_anon_vma(vma);
+       /* We must make sure the anon_vma is allocated. */
+       if (unlikely(anon_vma_prepare(vma)))
+               return -ENOMEM;
 
        /*
         * vma->vm_start/vm_end cannot change under us because the caller
         * is required to hold the mmap_sem in read mode.  We need the
         * anon_vma lock to serialize against concurrent expand_stacks.
         */
+       anon_vma_lock_write(vma->anon_vma);
 
        /* Somebody else might have raced and expanded it already */
        if (address < vma->vm_start) {
@@ -2257,7 +2258,7 @@ int expand_downwards(struct vm_area_struct *vma,
                                 * updates, but we only hold a shared mmap_sem
                                 * lock here, so we need to protect against
                                 * concurrent vma expansions.
-                                * vma_lock_anon_vma() doesn't help here, as
+                                * anon_vma_lock_write() doesn't help here, as
                                 * we don't guarantee that all growable vmas
                                 * in a mm share the same root anon vma.
                                 * So, we reuse mm->page_table_lock to guard
@@ -2278,7 +2279,7 @@ int expand_downwards(struct vm_area_struct *vma,
                        }
                }
        }
-       vma_unlock_anon_vma(vma);
+       anon_vma_unlock_write(vma->anon_vma);
        khugepaged_enter_vma_merge(vma, vma->vm_flags);
        validate_mm(mm);
        return error;
@@ -2663,12 +2664,29 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        if (!vma || !(vma->vm_flags & VM_SHARED))
                goto out;
 
-       if (start < vma->vm_start || start + size > vma->vm_end)
+       if (start < vma->vm_start)
                goto out;
 
-       if (pgoff == linear_page_index(vma, start)) {
-               ret = 0;
-               goto out;
+       if (start + size > vma->vm_end) {
+               struct vm_area_struct *next;
+
+               for (next = vma->vm_next; next; next = next->vm_next) {
+                       /* hole between vmas ? */
+                       if (next->vm_start != next->vm_prev->vm_end)
+                               goto out;
+
+                       if (next->vm_file != vma->vm_file)
+                               goto out;
+
+                       if (next->vm_flags != vma->vm_flags)
+                               goto out;
+
+                       if (start + size <= next->vm_end)
+                               break;
+               }
+
+               if (!next)
+                       goto out;
        }
 
        prot |= vma->vm_flags & VM_READ ? PROT_READ : 0;
@@ -2678,9 +2696,16 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
        flags &= MAP_NONBLOCK;
        flags |= MAP_SHARED | MAP_FIXED | MAP_POPULATE;
        if (vma->vm_flags & VM_LOCKED) {
+               struct vm_area_struct *tmp;
                flags |= MAP_LOCKED;
+
                /* drop PG_Mlocked flag for over-mapped range */
-               munlock_vma_pages_range(vma, start, start + size);
+               for (tmp = vma; tmp->vm_start >= start + size;
+                               tmp = tmp->vm_next) {
+                       munlock_vma_pages_range(tmp,
+                                       max(tmp->vm_start, start),
+                                       min(tmp->vm_end, start + size));
+               }
        }
 
        file = get_file(vma->vm_file);
@@ -2982,9 +3007,17 @@ bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages)
        if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT)
                return false;
 
-       if ((flags & (VM_WRITE | VM_SHARED | (VM_STACK_FLAGS &
-                               (VM_GROWSUP | VM_GROWSDOWN)))) == VM_WRITE)
-               return mm->data_vm + npages <= rlimit(RLIMIT_DATA);
+       if (is_data_mapping(flags) &&
+           mm->data_vm + npages > rlimit(RLIMIT_DATA) >> PAGE_SHIFT) {
+               if (ignore_rlimit_data)
+                       pr_warn_once("%s (%d): VmData %lu exceed data ulimit "
+                                    "%lu. Will be forbidden soon.\n",
+                                    current->comm, current->pid,
+                                    (mm->data_vm + npages) << PAGE_SHIFT,
+                                    rlimit(RLIMIT_DATA));
+               else
+                       return false;
+       }
 
        return true;
 }
@@ -2993,11 +3026,11 @@ void vm_stat_account(struct mm_struct *mm, vm_flags_t flags, long npages)
 {
        mm->total_vm += npages;
 
-       if ((flags & (VM_EXEC | VM_WRITE)) == VM_EXEC)
+       if (is_exec_mapping(flags))
                mm->exec_vm += npages;
-       else if (flags & (VM_STACK_FLAGS & (VM_GROWSUP | VM_GROWSDOWN)))
+       else if (is_stack_mapping(flags))
                mm->stack_vm += npages;
-       else if ((flags & (VM_WRITE | VM_SHARED)) == VM_WRITE)
+       else if (is_data_mapping(flags))
                mm->data_vm += npages;
 }
 
index 8eb7bb40dc40b6e8e89d05fbb7e05f8c836e05da..f7cb3d4d9c2eb55d74738e374faa3bfa37251686 100644 (file)
@@ -160,9 +160,11 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                }
 
                if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) {
-                       if (next - addr != HPAGE_PMD_SIZE)
+                       if (next - addr != HPAGE_PMD_SIZE) {
                                split_huge_pmd(vma, pmd, addr);
-                       else {
+                               if (pmd_none(*pmd))
+                                       continue;
+                       } else {
                                int nr_ptes = change_huge_pmd(vma, pmd, addr,
                                                newprot, prot_numa);
 
index d77946a997f798ecc25ccaee2886139ff9d9a587..8eeba02fc99137b5a47996750159de8a455e2c4d 100644 (file)
@@ -210,6 +210,8 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
                                }
                        }
                        split_huge_pmd(vma, old_pmd, old_addr);
+                       if (pmd_none(*old_pmd))
+                               continue;
                        VM_BUG_ON(pmd_trans_huge(*old_pmd));
                }
                if (pmd_none(*new_pmd) && __pte_alloc(new_vma->vm_mm, new_vma,
index 63358d9f9aa98eff0848879b0503b5d80b9ea8d0..838ca8bb64f7376062fc6670c759a27d7f59c7e3 100644 (file)
@@ -5209,6 +5209,11 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
        spin_lock_init(&pgdat->numabalancing_migrate_lock);
        pgdat->numabalancing_migrate_nr_pages = 0;
        pgdat->numabalancing_migrate_next_window = jiffies;
+#endif
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       spin_lock_init(&pgdat->split_queue_lock);
+       INIT_LIST_HEAD(&pgdat->split_queue);
+       pgdat->split_queue_len = 0;
 #endif
        init_waitqueue_head(&pgdat->kswapd_wait);
        init_waitqueue_head(&pgdat->pfmemalloc_wait);
@@ -6615,7 +6620,7 @@ bool is_pageblock_removable_nolock(struct page *page)
        return !has_unmovable_pages(zone, page, 0, true);
 }
 
-#ifdef CONFIG_CMA
+#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)
 
 static unsigned long pfn_max_align_down(unsigned long pfn)
 {
index 9d4767698a1cd6988d4f71b37ef3f384eff5b3b1..06a005b979a763cb4afbf0e57fe9c7f70d2c0c92 100644 (file)
@@ -90,9 +90,9 @@ pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address,
  * ARCHes with special requirements for evicting THP backing TLB entries can
  * implement this. Otherwise also, it can help optimize normal TLB flush in
  * THP regime. stock flush_tlb_range() typically has optimization to nuke the
- * entire TLB TLB if flush span is greater than a threshhold, which will
+ * entire TLB if flush span is greater than a threshold, which will
  * likely be true for a single huge page. Thus a single thp flush will
- * invalidate the entire TLB which is not desitable.
+ * invalidate the entire TLB which is not desirable.
  * e.g. see arch/arc: flush_pmd_tlb_range
  */
 #define flush_pmd_tlb_range(vma, addr, end)    flush_tlb_range(vma, addr, end)
@@ -195,7 +195,9 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address,
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
        VM_BUG_ON(pmd_trans_huge(*pmdp));
        pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
-       flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
+
+       /* collapse entails shooting down ptes not pmd */
+       flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
        return pmd;
 }
 #endif
index 6ecc697a8bc4670a3910fdcdc155196ee71a539a..621fbcb35a366abf0d979cf48c5476cff1e609f5 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2275,7 +2275,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
 
        err = setup_cpu_cache(cachep, gfp);
        if (err) {
-               __kmem_cache_shutdown(cachep);
+               __kmem_cache_release(cachep);
                return err;
        }
 
@@ -2413,13 +2413,14 @@ int __kmem_cache_shrink(struct kmem_cache *cachep, bool deactivate)
 }
 
 int __kmem_cache_shutdown(struct kmem_cache *cachep)
+{
+       return __kmem_cache_shrink(cachep, false);
+}
+
+void __kmem_cache_release(struct kmem_cache *cachep)
 {
        int i;
        struct kmem_cache_node *n;
-       int rc = __kmem_cache_shrink(cachep, false);
-
-       if (rc)
-               return rc;
 
        free_percpu(cachep->cpu_cache);
 
@@ -2430,7 +2431,6 @@ int __kmem_cache_shutdown(struct kmem_cache *cachep)
                kfree(n);
                cachep->node[i] = NULL;
        }
-       return 0;
 }
 
 /*
index 834ad240c0bb13980fbe10fb29aba166dcff3f28..2eedacea439de698bdf2103f54ae936fe40de48d 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -140,6 +140,7 @@ static inline unsigned long kmem_cache_flags(unsigned long object_size,
 #define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS)
 
 int __kmem_cache_shutdown(struct kmem_cache *);
+void __kmem_cache_release(struct kmem_cache *);
 int __kmem_cache_shrink(struct kmem_cache *, bool);
 void slab_kmem_cache_release(struct kmem_cache *);
 
index b50aef01ccf7ea97aa621dc63cfd66e111ee3dae..065b7bdabdc30c5b763b368d84e2057fcde3eb5a 100644 (file)
@@ -693,6 +693,7 @@ static inline int shutdown_memcg_caches(struct kmem_cache *s,
 
 void slab_kmem_cache_release(struct kmem_cache *s)
 {
+       __kmem_cache_release(s);
        destroy_memcg_params(s);
        kfree_const(s->name);
        kmem_cache_free(kmem_cache, s);
index 17e8f8cc7c534adca165f6d0e9b546e2f8484148..5ec158054ffe0b2ddf20c01276403f1984108dcb 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -630,6 +630,10 @@ int __kmem_cache_shutdown(struct kmem_cache *c)
        return 0;
 }
 
+void __kmem_cache_release(struct kmem_cache *c)
+{
+}
+
 int __kmem_cache_shrink(struct kmem_cache *d, bool deactivate)
 {
        return 0;
index 2e1355ac056b02a51778b2b1eef770b276626309..d8fbd4a6ed599882489143665ca750eb7613fd65 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1592,18 +1592,12 @@ static inline void add_partial(struct kmem_cache_node *n,
        __add_partial(n, page, tail);
 }
 
-static inline void
-__remove_partial(struct kmem_cache_node *n, struct page *page)
-{
-       list_del(&page->lru);
-       n->nr_partial--;
-}
-
 static inline void remove_partial(struct kmem_cache_node *n,
                                        struct page *page)
 {
        lockdep_assert_held(&n->list_lock);
-       __remove_partial(n, page);
+       list_del(&page->lru);
+       n->nr_partial--;
 }
 
 /*
@@ -3184,6 +3178,12 @@ static void free_kmem_cache_nodes(struct kmem_cache *s)
        }
 }
 
+void __kmem_cache_release(struct kmem_cache *s)
+{
+       free_percpu(s->cpu_slab);
+       free_kmem_cache_nodes(s);
+}
+
 static int init_kmem_cache_nodes(struct kmem_cache *s)
 {
        int node;
@@ -3443,28 +3443,31 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
 
 /*
  * Attempt to free all partial slabs on a node.
- * This is called from kmem_cache_close(). We must be the last thread
- * using the cache and therefore we do not need to lock anymore.
+ * This is called from __kmem_cache_shutdown(). We must take list_lock
+ * because sysfs file might still access partial list after the shutdowning.
  */
 static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 {
        struct page *page, *h;
 
+       BUG_ON(irqs_disabled());
+       spin_lock_irq(&n->list_lock);
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
-                       __remove_partial(n, page);
+                       remove_partial(n, page);
                        discard_slab(s, page);
                } else {
                        list_slab_objects(s, page,
-                       "Objects remaining in %s on kmem_cache_close()");
+                       "Objects remaining in %s on __kmem_cache_shutdown()");
                }
        }
+       spin_unlock_irq(&n->list_lock);
 }
 
 /*
  * Release all resources used by a slab cache.
  */
-static inline int kmem_cache_close(struct kmem_cache *s)
+int __kmem_cache_shutdown(struct kmem_cache *s)
 {
        int node;
        struct kmem_cache_node *n;
@@ -3476,16 +3479,9 @@ static inline int kmem_cache_close(struct kmem_cache *s)
                if (n->nr_partial || slabs_node(s, node))
                        return 1;
        }
-       free_percpu(s->cpu_slab);
-       free_kmem_cache_nodes(s);
        return 0;
 }
 
-int __kmem_cache_shutdown(struct kmem_cache *s)
-{
-       return kmem_cache_close(s);
-}
-
 /********************************************************************
  *             Kmalloc subsystem
  *******************************************************************/
@@ -3980,7 +3976,7 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
        memcg_propagate_slab_attrs(s);
        err = sysfs_slab_add(s);
        if (err)
-               kmem_cache_close(s);
+               __kmem_cache_release(s);
 
        return err;
 }
index c108a6542d05d3e1c880c1f6ab540ced62156e54..4fb14ca5a41967696a6f769189eb5a59c6a91c0f 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -230,36 +230,11 @@ void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
 }
 
 /* Check if the vma is being used as a stack by this task */
-static int vm_is_stack_for_task(struct task_struct *t,
-                               struct vm_area_struct *vma)
+int vma_is_stack_for_task(struct vm_area_struct *vma, struct task_struct *t)
 {
        return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t));
 }
 
-/*
- * Check if the vma is being used as a stack.
- * If is_group is non-zero, check in the entire thread group or else
- * just check in the current task. Returns the task_struct of the task
- * that the vma is stack for. Must be called under rcu_read_lock().
- */
-struct task_struct *task_of_stack(struct task_struct *task,
-                               struct vm_area_struct *vma, bool in_group)
-{
-       if (vm_is_stack_for_task(task, vma))
-               return task;
-
-       if (in_group) {
-               struct task_struct *t;
-
-               for_each_thread(task, t) {
-                       if (vm_is_stack_for_task(t, vma))
-                               return t;
-               }
-       }
-
-       return NULL;
-}
-
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
index 9a6c0704211c856c300f67057fc202e25c9657ab..149fdf6c5c56f927f3613538c61b3c5831c80af9 100644 (file)
@@ -248,9 +248,8 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree,
 
        if (tree) {
                spin_lock(&vmpr->sr_lock);
-               vmpr->tree_scanned += scanned;
+               scanned = vmpr->tree_scanned += scanned;
                vmpr->tree_reclaimed += reclaimed;
-               scanned = vmpr->scanned;
                spin_unlock(&vmpr->sr_lock);
 
                if (scanned < vmpressure_win)
index eb3dd37ccd7c727dcc0b6030f62c183097b956bb..71b1c29948dba30aab0a894ddc7c84eb62acde2b 100644 (file)
@@ -1443,7 +1443,7 @@ int isolate_lru_page(struct page *page)
        int ret = -EBUSY;
 
        VM_BUG_ON_PAGE(!page_count(page), page);
-       VM_BUG_ON_PAGE(PageTail(page), page);
+       WARN_RATELIMIT(PageTail(page), "trying to isolate tail page");
 
        if (PageLRU(page)) {
                struct zone *zone = page_zone(page);
index 40b2c74ddf16d69abc52574c469d9f22dd49cf03..084c6725b3734430483e7ea4fcf74e2ab67f7bfa 100644 (file)
@@ -1396,10 +1396,15 @@ static void vmstat_update(struct work_struct *w)
                 * Counters were updated so we expect more updates
                 * to occur in the future. Keep on running the
                 * update worker thread.
+                * If we were marked on cpu_stat_off clear the flag
+                * so that vmstat_shepherd doesn't schedule us again.
                 */
-               queue_delayed_work_on(smp_processor_id(), vmstat_wq,
-                       this_cpu_ptr(&vmstat_work),
-                       round_jiffies_relative(sysctl_stat_interval));
+               if (!cpumask_test_and_clear_cpu(smp_processor_id(),
+                                               cpu_stat_off)) {
+                       queue_delayed_work_on(smp_processor_id(), vmstat_wq,
+                               this_cpu_ptr(&vmstat_work),
+                               round_jiffies_relative(sysctl_stat_interval));
+               }
        } else {
                /*
                 * We did not update any counters so the app may be in
@@ -1417,18 +1422,6 @@ static void vmstat_update(struct work_struct *w)
  * until the diffs stay at zero. The function is used by NOHZ and can only be
  * invoked when tick processing is not active.
  */
-void quiet_vmstat(void)
-{
-       if (system_state != SYSTEM_RUNNING)
-               return;
-
-       do {
-               if (!cpumask_test_and_set_cpu(smp_processor_id(), cpu_stat_off))
-                       cancel_delayed_work(this_cpu_ptr(&vmstat_work));
-
-       } while (refresh_cpu_vm_stats(false));
-}
-
 /*
  * Check if the diffs for a certain cpu indicate that
  * an update is needed.
@@ -1452,6 +1445,30 @@ static bool need_update(int cpu)
        return false;
 }
 
+void quiet_vmstat(void)
+{
+       if (system_state != SYSTEM_RUNNING)
+               return;
+
+       /*
+        * If we are already in hands of the shepherd then there
+        * is nothing for us to do here.
+        */
+       if (cpumask_test_and_set_cpu(smp_processor_id(), cpu_stat_off))
+               return;
+
+       if (!need_update(smp_processor_id()))
+               return;
+
+       /*
+        * Just refresh counters and do not care about the pending delayed
+        * vmstat_update. It doesn't fire that often to matter and canceling
+        * it would be too expensive from this path.
+        * vmstat_shepherd will take care about that for us.
+        */
+       refresh_cpu_vm_stats(false);
+}
+
 
 /*
  * Shepherd worker thread that checks the
@@ -1469,18 +1486,25 @@ static void vmstat_shepherd(struct work_struct *w)
 
        get_online_cpus();
        /* Check processors whose vmstat worker threads have been disabled */
-       for_each_cpu(cpu, cpu_stat_off)
-               if (need_update(cpu) &&
-                       cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
-
-                       queue_delayed_work_on(cpu, vmstat_wq,
-                               &per_cpu(vmstat_work, cpu), 0);
+       for_each_cpu(cpu, cpu_stat_off) {
+               struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
 
+               if (need_update(cpu)) {
+                       if (cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
+                               queue_delayed_work_on(cpu, vmstat_wq, dw, 0);
+               } else {
+                       /*
+                        * Cancel the work if quiet_vmstat has put this
+                        * cpu on cpu_stat_off because the work item might
+                        * be still scheduled
+                        */
+                       cancel_delayed_work(dw);
+               }
+       }
        put_online_cpus();
 
        schedule_delayed_work(&shepherd,
                round_jiffies_relative(sysctl_stat_interval));
-
 }
 
 static void __init start_shepherd_timer(void)
@@ -1488,7 +1512,7 @@ static void __init start_shepherd_timer(void)
        int cpu;
 
        for_each_possible_cpu(cpu)
-               INIT_DELAYED_WORK(per_cpu_ptr(&vmstat_work, cpu),
+               INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu),
                        vmstat_update);
 
        if (!alloc_cpumask_var(&cpu_stat_off, GFP_KERNEL))
index faf65baed617d5c5b39d9cadd5ef0264ea546d59..34e44c0c08368eb5699dd101c4a2c3f35adadfab 100644 (file)
@@ -20,7 +20,7 @@
 int lowpan_register_netdevice(struct net_device *dev,
                              enum lowpan_lltypes lltype)
 {
-       int ret;
+       int i, ret;
 
        dev->addr_len = EUI64_ADDR_LEN;
        dev->type = ARPHRD_6LOWPAN;
@@ -29,6 +29,10 @@ int lowpan_register_netdevice(struct net_device *dev,
 
        lowpan_priv(dev)->lltype = lltype;
 
+       spin_lock_init(&lowpan_priv(dev)->ctx.lock);
+       for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
+               lowpan_priv(dev)->ctx.table[i].id = i;
+
        ret = register_netdevice(dev);
        if (ret < 0)
                return ret;
@@ -68,6 +72,32 @@ void lowpan_unregister_netdev(struct net_device *dev)
 }
 EXPORT_SYMBOL(lowpan_unregister_netdev);
 
+static int lowpan_event(struct notifier_block *unused,
+                       unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       int i;
+
+       if (dev->type != ARPHRD_6LOWPAN)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_DOWN:
+               for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
+                       clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
+                                 &lowpan_priv(dev)->ctx.table[i].flags);
+               break;
+       default:
+               return NOTIFY_DONE;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block lowpan_notifier = {
+       .notifier_call = lowpan_event,
+};
+
 static int __init lowpan_module_init(void)
 {
        int ret;
@@ -76,6 +106,12 @@ static int __init lowpan_module_init(void)
        if (ret < 0)
                return ret;
 
+       ret = register_netdevice_notifier(&lowpan_notifier);
+       if (ret < 0) {
+               lowpan_debugfs_exit();
+               return ret;
+       }
+
        request_module_nowait("ipv6");
 
        request_module_nowait("nhc_dest");
@@ -92,6 +128,7 @@ static int __init lowpan_module_init(void)
 static void __exit lowpan_module_exit(void)
 {
        lowpan_debugfs_exit();
+       unregister_netdevice_notifier(&lowpan_notifier);
 }
 
 module_init(lowpan_module_init);
index 88eef84df0fc124275e83f58ff78248ffe389a5c..aa49ff4ce6fda9886d10c90b45ae96fdb66f41f0 100644 (file)
 
 #include "6lowpan_i.h"
 
+#define LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS        8
+
 static struct dentry *lowpan_debugfs;
 
+static int lowpan_ctx_flag_active_set(void *data, u64 val)
+{
+       struct lowpan_iphc_ctx *ctx = data;
+
+       if (val != 0 && val != 1)
+               return -EINVAL;
+
+       if (val)
+               set_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
+       else
+               clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
+
+       return 0;
+}
+
+static int lowpan_ctx_flag_active_get(void *data, u64 *val)
+{
+       *val = lowpan_iphc_ctx_is_active(data);
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_active_fops,
+                       lowpan_ctx_flag_active_get,
+                       lowpan_ctx_flag_active_set, "%llu\n");
+
+static int lowpan_ctx_flag_c_set(void *data, u64 val)
+{
+       struct lowpan_iphc_ctx *ctx = data;
+
+       if (val != 0 && val != 1)
+               return -EINVAL;
+
+       if (val)
+               set_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
+       else
+               clear_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
+
+       return 0;
+}
+
+static int lowpan_ctx_flag_c_get(void *data, u64 *val)
+{
+       *val = lowpan_iphc_ctx_is_compression(data);
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_flag_c_fops, lowpan_ctx_flag_c_get,
+                       lowpan_ctx_flag_c_set, "%llu\n");
+
+static int lowpan_ctx_plen_set(void *data, u64 val)
+{
+       struct lowpan_iphc_ctx *ctx = data;
+       struct lowpan_iphc_ctx_table *t =
+               container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
+
+       if (val > 128)
+               return -EINVAL;
+
+       spin_lock_bh(&t->lock);
+       ctx->plen = val;
+       spin_unlock_bh(&t->lock);
+
+       return 0;
+}
+
+static int lowpan_ctx_plen_get(void *data, u64 *val)
+{
+       struct lowpan_iphc_ctx *ctx = data;
+       struct lowpan_iphc_ctx_table *t =
+               container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
+
+       spin_lock_bh(&t->lock);
+       *val = ctx->plen;
+       spin_unlock_bh(&t->lock);
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(lowpan_ctx_plen_fops, lowpan_ctx_plen_get,
+                       lowpan_ctx_plen_set, "%llu\n");
+
+static int lowpan_ctx_pfx_show(struct seq_file *file, void *offset)
+{
+       struct lowpan_iphc_ctx *ctx = file->private;
+       struct lowpan_iphc_ctx_table *t =
+               container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
+
+       spin_lock_bh(&t->lock);
+       seq_printf(file, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                  be16_to_cpu(ctx->pfx.s6_addr16[0]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[1]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[2]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[3]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[4]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[5]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[6]),
+                  be16_to_cpu(ctx->pfx.s6_addr16[7]));
+       spin_unlock_bh(&t->lock);
+
+       return 0;
+}
+
+static int lowpan_ctx_pfx_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, lowpan_ctx_pfx_show, inode->i_private);
+}
+
+static ssize_t lowpan_ctx_pfx_write(struct file *fp,
+                                   const char __user *user_buf, size_t count,
+                                   loff_t *ppos)
+{
+       char buf[128] = {};
+       struct seq_file *file = fp->private_data;
+       struct lowpan_iphc_ctx *ctx = file->private;
+       struct lowpan_iphc_ctx_table *t =
+               container_of(ctx, struct lowpan_iphc_ctx_table, table[ctx->id]);
+       int status = count, n, i;
+       unsigned int addr[8];
+
+       if (copy_from_user(&buf, user_buf, min_t(size_t, sizeof(buf) - 1,
+                                                count))) {
+               status = -EFAULT;
+               goto out;
+       }
+
+       n = sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+                  &addr[0], &addr[1], &addr[2], &addr[3], &addr[4],
+                  &addr[5], &addr[6], &addr[7]);
+       if (n != LOWPAN_DEBUGFS_CTX_PFX_NUM_ARGS) {
+               status = -EINVAL;
+               goto out;
+       }
+
+       spin_lock_bh(&t->lock);
+       for (i = 0; i < 8; i++)
+               ctx->pfx.s6_addr16[i] = cpu_to_be16(addr[i] & 0xffff);
+       spin_unlock_bh(&t->lock);
+
+out:
+       return status;
+}
+
+const struct file_operations lowpan_ctx_pfx_fops = {
+       .open           = lowpan_ctx_pfx_open,
+       .read           = seq_read,
+       .write          = lowpan_ctx_pfx_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
+                                      struct dentry *ctx, u8 id)
+{
+       struct lowpan_priv *lpriv = lowpan_priv(dev);
+       struct dentry *dentry, *root;
+       char buf[32];
+
+       WARN_ON_ONCE(id > LOWPAN_IPHC_CTX_TABLE_SIZE);
+
+       sprintf(buf, "%d", id);
+
+       root = debugfs_create_dir(buf, ctx);
+       if (!root)
+               return -EINVAL;
+
+       dentry = debugfs_create_file("active", 0644, root,
+                                    &lpriv->ctx.table[id],
+                                    &lowpan_ctx_flag_active_fops);
+       if (!dentry)
+               return -EINVAL;
+
+       dentry = debugfs_create_file("compression", 0644, root,
+                                    &lpriv->ctx.table[id],
+                                    &lowpan_ctx_flag_c_fops);
+       if (!dentry)
+               return -EINVAL;
+
+       dentry = debugfs_create_file("prefix", 0644, root,
+                                    &lpriv->ctx.table[id],
+                                    &lowpan_ctx_pfx_fops);
+       if (!dentry)
+               return -EINVAL;
+
+       dentry = debugfs_create_file("prefix_len", 0644, root,
+                                    &lpriv->ctx.table[id],
+                                    &lowpan_ctx_plen_fops);
+       if (!dentry)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int lowpan_context_show(struct seq_file *file, void *offset)
+{
+       struct lowpan_iphc_ctx_table *t = file->private;
+       int i;
+
+       seq_printf(file, "%3s|%-43s|%c\n", "cid", "prefix", 'C');
+       seq_puts(file, "-------------------------------------------------\n");
+
+       spin_lock_bh(&t->lock);
+       for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
+               if (!lowpan_iphc_ctx_is_active(&t->table[i]))
+                       continue;
+
+               seq_printf(file, "%3d|%39pI6c/%-3d|%d\n", t->table[i].id,
+                          &t->table[i].pfx, t->table[i].plen,
+                          lowpan_iphc_ctx_is_compression(&t->table[i]));
+       }
+       spin_unlock_bh(&t->lock);
+
+       return 0;
+}
+
+static int lowpan_context_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, lowpan_context_show, inode->i_private);
+}
+
+const struct file_operations lowpan_context_fops = {
+       .open           = lowpan_context_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 int lowpan_dev_debugfs_init(struct net_device *dev)
 {
        struct lowpan_priv *lpriv = lowpan_priv(dev);
+       struct dentry *contexts, *dentry;
+       int ret, i;
 
        /* creating the root */
        lpriv->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
        if (!lpriv->iface_debugfs)
                goto fail;
 
+       contexts = debugfs_create_dir("contexts", lpriv->iface_debugfs);
+       if (!contexts)
+               goto remove_root;
+
+       dentry = debugfs_create_file("show", 0644, contexts,
+                                    &lowpan_priv(dev)->ctx,
+                                    &lowpan_context_fops);
+       if (!dentry)
+               goto remove_root;
+
+       for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
+               ret = lowpan_dev_debugfs_ctx_init(dev, contexts, i);
+               if (ret < 0)
+                       goto remove_root;
+       }
+
        return 0;
 
+remove_root:
+       lowpan_dev_debugfs_exit(dev);
 fail:
        return -EINVAL;
 }
index 346b5c1a91851efd16b22695a7a1259c1cca9139..72172514fea063a34ed2e1314d1a996db6a38015 100644 (file)
@@ -56,6 +56,7 @@
 /* special link-layer handling */
 #include <net/mac802154.h>
 
+#include "6lowpan_i.h"
 #include "nhc.h"
 
 /* Values of fields within the IPHC encoding first byte */
         (((a)->s6_addr16[6]) == 0) &&          \
         (((a)->s6_addr[14]) == 0))
 
+#define LOWPAN_IPHC_CID_DCI(cid)       (cid & 0x0f)
+#define LOWPAN_IPHC_CID_SCI(cid)       ((cid & 0xf0) >> 4)
+
 static inline void iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
                                                const void *lladdr)
 {
@@ -195,6 +199,98 @@ static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
        }
 }
 
+static struct lowpan_iphc_ctx *
+lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
+{
+       struct lowpan_iphc_ctx *ret = &lowpan_priv(dev)->ctx.table[id];
+
+       if (!lowpan_iphc_ctx_is_active(ret))
+               return NULL;
+
+       return ret;
+}
+
+static struct lowpan_iphc_ctx *
+lowpan_iphc_ctx_get_by_addr(const struct net_device *dev,
+                           const struct in6_addr *addr)
+{
+       struct lowpan_iphc_ctx *table = lowpan_priv(dev)->ctx.table;
+       struct lowpan_iphc_ctx *ret = NULL;
+       struct in6_addr addr_pfx;
+       u8 addr_plen;
+       int i;
+
+       for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
+               /* Check if context is valid. A context that is not valid
+                * MUST NOT be used for compression.
+                */
+               if (!lowpan_iphc_ctx_is_active(&table[i]) ||
+                   !lowpan_iphc_ctx_is_compression(&table[i]))
+                       continue;
+
+               ipv6_addr_prefix(&addr_pfx, addr, table[i].plen);
+
+               /* if prefix len < 64, the remaining bits until 64th bit is
+                * zero. Otherwise we use table[i]->plen.
+                */
+               if (table[i].plen < 64)
+                       addr_plen = 64;
+               else
+                       addr_plen = table[i].plen;
+
+               if (ipv6_prefix_equal(&addr_pfx, &table[i].pfx, addr_plen)) {
+                       /* remember first match */
+                       if (!ret) {
+                               ret = &table[i];
+                               continue;
+                       }
+
+                       /* get the context with longest prefix len */
+                       if (table[i].plen > ret->plen)
+                               ret = &table[i];
+               }
+       }
+
+       return ret;
+}
+
+static struct lowpan_iphc_ctx *
+lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
+                                 const struct in6_addr *addr)
+{
+       struct lowpan_iphc_ctx *table = lowpan_priv(dev)->ctx.table;
+       struct lowpan_iphc_ctx *ret = NULL;
+       struct in6_addr addr_mcast, network_pfx = {};
+       int i;
+
+       /* init mcast address with  */
+       memcpy(&addr_mcast, addr, sizeof(*addr));
+
+       for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) {
+               /* Check if context is valid. A context that is not valid
+                * MUST NOT be used for compression.
+                */
+               if (!lowpan_iphc_ctx_is_active(&table[i]) ||
+                   !lowpan_iphc_ctx_is_compression(&table[i]))
+                       continue;
+
+               /* setting plen */
+               addr_mcast.s6_addr[3] = table[i].plen;
+               /* get network prefix to copy into multicast address */
+               ipv6_addr_prefix(&network_pfx, &table[i].pfx,
+                                table[i].plen);
+               /* setting network prefix */
+               memcpy(&addr_mcast.s6_addr[4], &network_pfx, 8);
+
+               if (ipv6_addr_equal(addr, &addr_mcast)) {
+                       ret = &table[i];
+                       break;
+               }
+       }
+
+       return ret;
+}
+
 /* Uncompress address function for source and
  * destination address(non-multicast).
  *
@@ -259,30 +355,59 @@ static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
 /* Uncompress address function for source context
  * based address(non-multicast).
  */
-static int uncompress_context_based_src_addr(struct sk_buff *skb,
-                                            struct in6_addr *ipaddr,
-                                            u8 address_mode)
+static int uncompress_ctx_addr(struct sk_buff *skb,
+                              const struct net_device *dev,
+                              const struct lowpan_iphc_ctx *ctx,
+                              struct in6_addr *ipaddr, u8 address_mode,
+                              const void *lladdr)
 {
+       bool fail;
+
        switch (address_mode) {
-       case LOWPAN_IPHC_SAM_00:
-               /* unspec address ::
+       /* SAM and DAM are the same here */
+       case LOWPAN_IPHC_DAM_00:
+               fail = false;
+               /* SAM_00 -> unspec address ::
                 * Do nothing, address is already ::
+                *
+                * DAM 00 -> reserved should never occur.
                 */
                break;
        case LOWPAN_IPHC_SAM_01:
-               /* TODO */
+       case LOWPAN_IPHC_DAM_01:
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
+               ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
+               break;
        case LOWPAN_IPHC_SAM_10:
-               /* TODO */
+       case LOWPAN_IPHC_DAM_10:
+               ipaddr->s6_addr[11] = 0xFF;
+               ipaddr->s6_addr[12] = 0xFE;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
+               ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
+               break;
        case LOWPAN_IPHC_SAM_11:
-               /* TODO */
-               netdev_warn(skb->dev, "SAM value 0x%x not supported\n",
-                           address_mode);
-               return -EINVAL;
+       case LOWPAN_IPHC_DAM_11:
+               fail = false;
+               switch (lowpan_priv(dev)->lltype) {
+               case LOWPAN_LLTYPE_IEEE802154:
+                       iphc_uncompress_802154_lladdr(ipaddr, lladdr);
+                       break;
+               default:
+                       iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
+                       break;
+               }
+               ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
+               break;
        default:
                pr_debug("Invalid sam value: 0x%x\n", address_mode);
                return -EINVAL;
        }
 
+       if (fail) {
+               pr_debug("Failed to fetch skb data\n");
+               return -EIO;
+       }
+
        raw_dump_inline(NULL,
                        "Reconstructed context based ipv6 src addr is",
                        ipaddr->s6_addr, 16);
@@ -346,6 +471,30 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
        return 0;
 }
 
+static int lowpan_uncompress_multicast_ctx_daddr(struct sk_buff *skb,
+                                                struct lowpan_iphc_ctx *ctx,
+                                                struct in6_addr *ipaddr,
+                                                u8 address_mode)
+{
+       struct in6_addr network_pfx = {};
+       bool fail;
+
+       ipaddr->s6_addr[0] = 0xFF;
+       fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 2);
+       fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[12], 4);
+       if (fail)
+               return -EIO;
+
+       /* take prefix_len and network prefix from the context */
+       ipaddr->s6_addr[3] = ctx->plen;
+       /* get network prefix to copy into multicast address */
+       ipv6_addr_prefix(&network_pfx, &ctx->pfx, ctx->plen);
+       /* setting network prefix */
+       memcpy(&ipaddr->s6_addr[4], &network_pfx, 8);
+
+       return 0;
+}
+
 /* get the ecn values from iphc tf format and set it to ipv6hdr */
 static inline void lowpan_iphc_tf_set_ecn(struct ipv6hdr *hdr, const u8 *tf)
 {
@@ -459,7 +608,8 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
                             const void *daddr, const void *saddr)
 {
        struct ipv6hdr hdr = {};
-       u8 iphc0, iphc1;
+       struct lowpan_iphc_ctx *ci;
+       u8 iphc0, iphc1, cid = 0;
        int err;
 
        raw_dump_table(__func__, "raw skb data dump uncompressed",
@@ -469,12 +619,14 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
            lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1)))
                return -EINVAL;
 
-       /* another if the CID flag is set */
-       if (iphc1 & LOWPAN_IPHC_CID)
-               return -ENOTSUPP;
-
        hdr.version = 6;
 
+       /* default CID = 0, another if the CID flag is set */
+       if (iphc1 & LOWPAN_IPHC_CID) {
+               if (lowpan_fetch_skb(skb, &cid, sizeof(cid)))
+                       return -EINVAL;
+       }
+
        err = lowpan_iphc_tf_decompress(skb, &hdr,
                                        iphc0 & LOWPAN_IPHC_TF_MASK);
        if (err < 0)
@@ -500,10 +652,17 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
        }
 
        if (iphc1 & LOWPAN_IPHC_SAC) {
-               /* Source address context based uncompression */
+               spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
+               ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid));
+               if (!ci) {
+                       spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+                       return -EINVAL;
+               }
+
                pr_debug("SAC bit is set. Handle context based source address.\n");
-               err = uncompress_context_based_src_addr(skb, &hdr.saddr,
-                                                       iphc1 & LOWPAN_IPHC_SAM_MASK);
+               err = uncompress_ctx_addr(skb, dev, ci, &hdr.saddr,
+                                         iphc1 & LOWPAN_IPHC_SAM_MASK, saddr);
+               spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
        } else {
                /* Source address uncompression */
                pr_debug("source address stateless compression\n");
@@ -515,27 +674,52 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
        if (err)
                return -EINVAL;
 
-       /* check for Multicast Compression */
-       if (iphc1 & LOWPAN_IPHC_M) {
-               if (iphc1 & LOWPAN_IPHC_DAC) {
-                       pr_debug("dest: context-based mcast compression\n");
-                       /* TODO: implement this */
-               } else {
-                       err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
-                                                               iphc1 & LOWPAN_IPHC_DAM_MASK);
+       switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) {
+       case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC:
+               spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
+               ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
+               if (!ci) {
+                       spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+                       return -EINVAL;
+               }
 
-                       if (err)
-                               return -EINVAL;
+               /* multicast with context */
+               pr_debug("dest: context-based mcast compression\n");
+               err = lowpan_uncompress_multicast_ctx_daddr(skb, ci,
+                                                           &hdr.daddr,
+                                                           iphc1 & LOWPAN_IPHC_DAM_MASK);
+               spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+               break;
+       case LOWPAN_IPHC_M:
+               /* multicast */
+               err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
+                                                       iphc1 & LOWPAN_IPHC_DAM_MASK);
+               break;
+       case LOWPAN_IPHC_DAC:
+               spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
+               ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
+               if (!ci) {
+                       spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+                       return -EINVAL;
                }
-       } else {
+
+               /* Destination address context based uncompression */
+               pr_debug("DAC bit is set. Handle context based destination address.\n");
+               err = uncompress_ctx_addr(skb, dev, ci, &hdr.daddr,
+                                         iphc1 & LOWPAN_IPHC_DAM_MASK, daddr);
+               spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+               break;
+       default:
                err = uncompress_addr(skb, dev, &hdr.daddr,
                                      iphc1 & LOWPAN_IPHC_DAM_MASK, daddr);
                pr_debug("dest: stateless compression mode %d dest %pI6c\n",
                         iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr);
-               if (err)
-                       return -EINVAL;
+               break;
        }
 
+       if (err)
+               return -EINVAL;
+
        /* Next header data uncompression */
        if (iphc0 & LOWPAN_IPHC_NH) {
                err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
@@ -585,6 +769,58 @@ static const u8 lowpan_iphc_dam_to_sam_value[] = {
        [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
 };
 
+static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct in6_addr *ipaddr,
+                                  const struct lowpan_iphc_ctx *ctx,
+                                  const unsigned char *lladdr, bool sam)
+{
+       struct in6_addr tmp = {};
+       u8 dam;
+
+       /* check for SAM/DAM = 11 */
+       memcpy(&tmp.s6_addr[8], lladdr, 8);
+       /* second bit-flip (Universe/Local) is done according RFC2464 */
+       tmp.s6_addr[8] ^= 0x02;
+       /* context information are always used */
+       ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+       if (ipv6_addr_equal(&tmp, ipaddr)) {
+               dam = LOWPAN_IPHC_DAM_11;
+               goto out;
+       }
+
+       memset(&tmp, 0, sizeof(tmp));
+       /* check for SAM/DAM = 01 */
+       tmp.s6_addr[11] = 0xFF;
+       tmp.s6_addr[12] = 0xFE;
+       memcpy(&tmp.s6_addr[14], &ipaddr->s6_addr[14], 2);
+       /* context information are always used */
+       ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+       if (ipv6_addr_equal(&tmp, ipaddr)) {
+               lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[14], 2);
+               dam = LOWPAN_IPHC_DAM_10;
+               goto out;
+       }
+
+       memset(&tmp, 0, sizeof(tmp));
+       /* check for SAM/DAM = 10, should always match */
+       memcpy(&tmp.s6_addr[8], &ipaddr->s6_addr[8], 8);
+       /* context information are always used */
+       ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+       if (ipv6_addr_equal(&tmp, ipaddr)) {
+               lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[8], 8);
+               dam = LOWPAN_IPHC_DAM_01;
+               goto out;
+       }
+
+       WARN_ONCE(1, "context found but no address mode matched\n");
+       return LOWPAN_IPHC_DAM_00;
+out:
+
+       if (sam)
+               return lowpan_iphc_dam_to_sam_value[dam];
+       else
+               return dam;
+}
+
 static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr,
                                  const unsigned char *lladdr, bool sam)
 {
@@ -708,6 +944,21 @@ static u8 lowpan_iphc_tf_compress(u8 **hc_ptr, const struct ipv6hdr *hdr)
        return val;
 }
 
+static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr,
+                                             const struct lowpan_iphc_ctx *ctx,
+                                             const struct in6_addr *ipaddr)
+{
+       u8 data[6];
+
+       /* flags/scope, reserved (RIID) */
+       memcpy(data, &ipaddr->s6_addr[1], 2);
+       /* group ID */
+       memcpy(&data[1], &ipaddr->s6_addr[11], 4);
+       lowpan_push_hc_data(hc_ptr, data, 6);
+
+       return LOWPAN_IPHC_DAM_00;
+}
+
 static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr,
                                          const struct in6_addr *ipaddr)
 {
@@ -742,10 +993,11 @@ static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr,
 int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
                           const void *daddr, const void *saddr)
 {
-       u8 iphc0, iphc1, *hc_ptr;
+       u8 iphc0, iphc1, *hc_ptr, cid = 0;
        struct ipv6hdr *hdr;
        u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
-       int ret, addr_type;
+       struct lowpan_iphc_ctx *dci, *sci, dci_entry, sci_entry;
+       int ret, ipv6_daddr_type, ipv6_saddr_type;
 
        if (skb->protocol != htons(ETH_P_IPV6))
                return -EINVAL;
@@ -769,14 +1021,38 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
        iphc0 = LOWPAN_DISPATCH_IPHC;
        iphc1 = 0;
 
-       /* TODO: context lookup */
-
        raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
        raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);
 
        raw_dump_table(__func__, "sending raw skb network uncompressed packet",
                       skb->data, skb->len);
 
+       ipv6_daddr_type = ipv6_addr_type(&hdr->daddr);
+       spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
+       if (ipv6_daddr_type & IPV6_ADDR_MULTICAST)
+               dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr);
+       else
+               dci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->daddr);
+       if (dci) {
+               memcpy(&dci_entry, dci, sizeof(*dci));
+               cid |= dci->id;
+       }
+       spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+
+       spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
+       sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr);
+       if (sci) {
+               memcpy(&sci_entry, sci, sizeof(*sci));
+               cid |= (sci->id << 4);
+       }
+       spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
+
+       /* if cid is zero it will be compressed */
+       if (cid) {
+               iphc1 |= LOWPAN_IPHC_CID;
+               lowpan_push_hc_data(&hc_ptr, &cid, sizeof(cid));
+       }
+
        /* Traffic Class, Flow Label compression */
        iphc0 |= lowpan_iphc_tf_compress(&hc_ptr, hdr);
 
@@ -813,39 +1089,64 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
                                    sizeof(hdr->hop_limit));
        }
 
-       addr_type = ipv6_addr_type(&hdr->saddr);
+       ipv6_saddr_type = ipv6_addr_type(&hdr->saddr);
        /* source address compression */
-       if (addr_type == IPV6_ADDR_ANY) {
+       if (ipv6_saddr_type == IPV6_ADDR_ANY) {
                pr_debug("source address is unspecified, setting SAC\n");
                iphc1 |= LOWPAN_IPHC_SAC;
        } else {
-               if (addr_type & IPV6_ADDR_LINKLOCAL) {
-                       iphc1 |= lowpan_compress_addr_64(&hc_ptr, &hdr->saddr,
-                                                        saddr, true);
-                       pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
-                                &hdr->saddr, iphc1);
+               if (sci) {
+                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->saddr,
+                                                         &sci_entry, saddr,
+                                                         true);
+                       iphc1 |= LOWPAN_IPHC_SAC;
                } else {
-                       pr_debug("send the full source address\n");
-                       lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16);
+                       if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL) {
+                               iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+                                                                &hdr->saddr,
+                                                                saddr, true);
+                               pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
+                                        &hdr->saddr, iphc1);
+                       } else {
+                               pr_debug("send the full source address\n");
+                               lowpan_push_hc_data(&hc_ptr,
+                                                   hdr->saddr.s6_addr, 16);
+                       }
                }
        }
 
-       addr_type = ipv6_addr_type(&hdr->daddr);
        /* destination address compression */
-       if (addr_type & IPV6_ADDR_MULTICAST) {
+       if (ipv6_daddr_type & IPV6_ADDR_MULTICAST) {
                pr_debug("destination address is multicast: ");
                iphc1 |= LOWPAN_IPHC_M;
-               iphc1 |= lowpan_iphc_mcast_addr_compress(&hc_ptr, &hdr->daddr);
+               if (dci) {
+                       iphc1 |= lowpan_iphc_mcast_ctx_addr_compress(&hc_ptr,
+                                                                    &dci_entry,
+                                                                    &hdr->daddr);
+                       iphc1 |= LOWPAN_IPHC_DAC;
+               } else {
+                       iphc1 |= lowpan_iphc_mcast_addr_compress(&hc_ptr,
+                                                                &hdr->daddr);
+               }
        } else {
-               if (addr_type & IPV6_ADDR_LINKLOCAL) {
-                       /* TODO: context lookup */
-                       iphc1 |= lowpan_compress_addr_64(&hc_ptr, &hdr->daddr,
-                                                        daddr, false);
-                       pr_debug("dest address unicast link-local %pI6c "
-                                "iphc1 0x%02x\n", &hdr->daddr, iphc1);
+               if (dci) {
+                       iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->daddr,
+                                                         &dci_entry, daddr,
+                                                         false);
+                       iphc1 |= LOWPAN_IPHC_DAC;
                } else {
-                       pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
-                       lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16);
+                       if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL) {
+                               iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+                                                                &hdr->daddr,
+                                                                daddr, false);
+                               pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",
+                                        &hdr->daddr, iphc1);
+                       } else {
+                               pr_debug("dest address unicast %pI6c\n",
+                                        &hdr->daddr);
+                               lowpan_push_hc_data(&hc_ptr,
+                                                   hdr->daddr.s6_addr, 16);
+                       }
                }
        }
 
index d2cd9de4b7241dcc8c1df5fd7832b3b317799923..69929c05c8438e59c5205c72eb6d1b763e374b68 100644 (file)
@@ -261,7 +261,6 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
         * hope the underlying device can handle it.
         */
        new_dev->mtu = real_dev->mtu;
-       new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT);
 
        vlan = vlan_dev_priv(new_dev);
        vlan->vlan_proto = htons(ETH_P_8021Q);
index ad5e2fd1012c4c1fdfedf010055acfae003646e4..e416a4038a1293f71c12c28fd3ee9a8170950116 100644 (file)
@@ -621,12 +621,12 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
        return features;
 }
 
-static int vlan_ethtool_get_settings(struct net_device *dev,
-                                    struct ethtool_cmd *cmd)
+static int vlan_ethtool_get_link_ksettings(struct net_device *dev,
+                                          struct ethtool_link_ksettings *cmd)
 {
        const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
 
-       return __ethtool_get_settings(vlan->real_dev, cmd);
+       return __ethtool_get_link_ksettings(vlan->real_dev, cmd);
 }
 
 static void vlan_ethtool_get_drvinfo(struct net_device *dev,
@@ -741,7 +741,7 @@ static int vlan_dev_get_iflink(const struct net_device *dev)
 }
 
 static const struct ethtool_ops vlan_ethtool_ops = {
-       .get_settings           = vlan_ethtool_get_settings,
+       .get_link_ksettings     = vlan_ethtool_get_link_ksettings,
        .get_drvinfo            = vlan_ethtool_get_drvinfo,
        .get_link               = ethtool_op_get_link,
        .get_ts_info            = vlan_ethtool_get_ts_info,
@@ -799,6 +799,7 @@ void vlan_setup(struct net_device *dev)
        ether_setup(dev);
 
        dev->priv_flags         |= IFF_802_1Q_VLAN | IFF_NO_QUEUE;
+       dev->priv_flags         |= IFF_UNICAST_FLT;
        dev->priv_flags         &= ~IFF_TX_SKB_SHARING;
        netif_keep_dst(dev);
 
index ae63cf72a953ca0f733b7b9e8cfb61dc9012da3c..5f1446c9f09813c3a05e4e0f01b6861f83d01535 100644 (file)
@@ -184,12 +184,11 @@ int vlan_proc_add_dev(struct net_device *vlandev)
 /*
  *     Delete directory entry for VLAN device.
  */
-int vlan_proc_rem_dev(struct net_device *vlandev)
+void vlan_proc_rem_dev(struct net_device *vlandev)
 {
        /** NOTE:  This will consume the memory pointed to by dent, it seems. */
        proc_remove(vlan_dev_priv(vlandev)->dent);
        vlan_dev_priv(vlandev)->dent = NULL;
-       return 0;
 }
 
 /****** Proc filesystem entry points ****************************************/
index 063f60a3d5cc2ee05c724dd76e647596d677fddf..8838a2e92eb696c2ce199692bc2d87856d4a109d 100644 (file)
@@ -5,7 +5,7 @@
 struct net;
 
 int vlan_proc_init(struct net *net);
-int vlan_proc_rem_dev(struct net_device *vlandev);
+void vlan_proc_rem_dev(struct net_device *vlandev);
 int vlan_proc_add_dev(struct net_device *vlandev);
 void vlan_proc_cleanup(struct net *net);
 
@@ -14,7 +14,7 @@ void vlan_proc_cleanup(struct net *net);
 #define vlan_proc_init(net)    (0)
 #define vlan_proc_cleanup(net) do {} while (0)
 #define vlan_proc_add_dev(dev) ({(void)(dev), 0; })
-#define vlan_proc_rem_dev(dev) ({(void)(dev), 0; })
+#define vlan_proc_rem_dev(dev) do {} while (0)
 #endif
 
 #endif /* !(__BEN_VLAN_PROC_INC__) */
index 174354618f8a65536c0657544ef16a9dee2d0ae5..10640d5f8beefd84d41b8d3eff2758c3757e9f6b 100644 (file)
@@ -360,6 +360,7 @@ source "net/can/Kconfig"
 source "net/irda/Kconfig"
 source "net/bluetooth/Kconfig"
 source "net/rxrpc/Kconfig"
+source "net/kcm/Kconfig"
 
 config FIB_RULES
        bool
@@ -392,6 +393,26 @@ config LWTUNNEL
          weight tunnel endpoint. Tunnel encapsulation parameters are stored
          with light weight tunnel state associated with fib routes.
 
+config DST_CACHE
+       bool "dst cache"
+       default n
+
+config NET_DEVLINK
+       tristate "Network physical/parent device Netlink interface"
+       help
+         Network physical/parent device Netlink interface provides
+         infrastructure to support access to physical chip-wide config and
+         monitoring.
+
+config MAY_USE_DEVLINK
+       tristate
+       default m if NET_DEVLINK=m
+       default y if NET_DEVLINK=y || NET_DEVLINK=n
+       help
+         Drivers using the devlink infrastructure should have a dependency
+         on MAY_USE_DEVLINK to ensure they do not cause link errors when
+         devlink is a loadable module and the driver using it is built-in.
+
 endif   # if NET
 
 # Used by archs to tell that they support BPF_JIT
index a5d04098dfce8693c46785f6c0dfa90bd23f4187..81d14119eab5416e8576f1fffa5109d752784143 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_IRDA)            += irda/
 obj-$(CONFIG_BT)               += bluetooth/
 obj-$(CONFIG_SUNRPC)           += sunrpc/
 obj-$(CONFIG_AF_RXRPC)         += rxrpc/
+obj-$(CONFIG_AF_KCM)           += kcm/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_L2TP)             += l2tp/
 obj-$(CONFIG_DECNET)           += decnet/
index d5871ac493eb10c984b9e74f2beee3049bc79645..f066781be3c856b8ae192c6b74d614597297a872 100644 (file)
@@ -1625,7 +1625,7 @@ static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
 
                rt = atrtr_find(&at_hint);
        }
-       err = ENETUNREACH;
+       err = -ENETUNREACH;
        if (!rt)
                goto out;
 
index b563a3f5f2a8a33932418965920ed58b80511f88..2fa3be96510161190365ff59b48ec8a293037853 100644 (file)
@@ -228,8 +228,23 @@ netdev_tx_t ax25_ip_xmit(struct sk_buff *skb)
 }
 #endif
 
+static bool ax25_validate_header(const char *header, unsigned int len)
+{
+       ax25_digi digi;
+
+       if (!len)
+               return false;
+
+       if (header[0])
+               return true;
+
+       return ax25_addr_parse(header + 1, len - 1, NULL, NULL, &digi, NULL,
+                              NULL);
+}
+
 const struct header_ops ax25_header_ops = {
        .create = ax25_hard_header,
+       .validate = ax25_validate_header,
 };
 
 EXPORT_SYMBOL(ax25_header_ops);
index 2dd40e5ea030a1bbebdfbcad89ccdda78dfd36e9..f66930ee3c0b06a753c41bf70cafc0e14de330a5 100644 (file)
@@ -15,6 +15,20 @@ config BATMAN_ADV
           https://www.open-mesh.org/ for more information and user space
           tools.
 
+config BATMAN_ADV_BATMAN_V
+       bool "B.A.T.M.A.N. V protocol (experimental)"
+       depends on BATMAN_ADV && CFG80211=y || (CFG80211=m && BATMAN_ADV=m)
+       default n
+       help
+         This option enables the B.A.T.M.A.N. V protocol, the successor
+         of the currently used B.A.T.M.A.N. IV protocol. The main
+         changes include splitting of the OGM protocol into a neighbor
+         discovery protocol (Echo Location Protocol, ELP) and a new OGM
+         Protocol OGMv2 for flooding protocol information through the
+         network, as well as a throughput based metric.
+         B.A.T.M.A.N. V is currently considered experimental and not
+         compatible to B.A.T.M.A.N. IV networks.
+
 config BATMAN_ADV_BLA
        bool "Bridge Loop Avoidance"
        depends on BATMAN_ADV && INET
index 207e2af316c7bcfc64955a711bc4dc756ab46b9c..797cf2fc88c158338ab71f160255269005f95232 100644 (file)
@@ -18,6 +18,9 @@
 
 obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
 batman-adv-y += bat_iv_ogm.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o
+batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_ogm.o
 batman-adv-y += bitarray.o
 batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o
 batman-adv-$(CONFIG_DEBUG_FS) += debugfs.o
index a7485d676088c367eb56b98a7030aca21c29374d..03dafd33d23b086ce43892981dbeb8fd8036b1bb 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (C) 2011-2016  B.A.T.M.A.N. contributors:
  *
- * Marek Lindner
+ * Marek Lindner, Linus Lüssing
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
 #ifndef _NET_BATMAN_ADV_BAT_ALGO_H_
 #define _NET_BATMAN_ADV_BAT_ALGO_H_
 
+struct batadv_priv;
+
 int batadv_iv_init(void);
 
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+
+int batadv_v_init(void);
+int batadv_v_mesh_init(struct batadv_priv *bat_priv);
+void batadv_v_mesh_free(struct batadv_priv *bat_priv);
+
+#else
+
+static inline int batadv_v_init(void)
+{
+       return 0;
+}
+
+static inline int batadv_v_mesh_init(struct batadv_priv *bat_priv)
+{
+       return 0;
+}
+
+static inline void batadv_v_mesh_free(struct batadv_priv *bat_priv)
+{
+}
+
+#endif /* CONFIG_BATMAN_ADV_BATMAN_V */
+
 #endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */
index bf0e7d6f12bb157318332327c2a7d39f74e37db1..cb2d1b9b034058c454fa0b7c5c14e6491ed41b1d 100644 (file)
@@ -287,8 +287,8 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
 
 free_orig_node:
        /* free twice, as batadv_orig_node_new sets refcount to 2 */
-       batadv_orig_node_free_ref(orig_node);
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
+       batadv_orig_node_put(orig_node);
 
        return NULL;
 }
@@ -478,7 +478,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
                batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
                batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
                                   skb->len + ETH_HLEN);
-               batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+               batadv_send_broadcast_skb(skb, hard_iface);
        }
 }
 
@@ -515,7 +515,7 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 /**
@@ -617,7 +617,7 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return res;
 }
 
@@ -711,9 +711,9 @@ out_nomem:
        if (!own_packet)
                atomic_inc(&bat_priv->batman_queue_left);
 out_free_outgoing:
-       batadv_hardif_free_ref(if_outgoing);
+       batadv_hardif_put(if_outgoing);
 out_free_incoming:
-       batadv_hardif_free_ref(if_incoming);
+       batadv_hardif_put(if_incoming);
 }
 
 /* aggregate a new packet into the existing ogm packet */
@@ -958,7 +958,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 /**
@@ -1005,7 +1005,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                    tmp_neigh_node->if_incoming == if_incoming &&
                    kref_get_unless_zero(&tmp_neigh_node->refcount)) {
                        if (WARN(neigh_node, "too many matching neigh_nodes"))
-                               batadv_neigh_node_free_ref(neigh_node);
+                               batadv_neigh_node_put(neigh_node);
                        neigh_node = tmp_neigh_node;
                        continue;
                }
@@ -1026,7 +1026,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                neigh_ifinfo->bat_iv.tq_avg = tq_avg;
                spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
 
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
                neigh_ifinfo = NULL;
        }
 
@@ -1041,7 +1041,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                                                     ethhdr->h_source,
                                                     orig_node, orig_tmp);
 
-               batadv_orig_node_free_ref(orig_tmp);
+               batadv_orig_node_put(orig_tmp);
                if (!neigh_node)
                        goto unlock;
        } else {
@@ -1116,13 +1116,13 @@ unlock:
        rcu_read_unlock();
 out:
        if (neigh_node)
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
        if (neigh_ifinfo)
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
        if (router_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_ifinfo);
+               batadv_neigh_ifinfo_put(router_ifinfo);
 }
 
 /**
@@ -1192,7 +1192,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
        if (neigh_ifinfo) {
                neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
        } else {
                neigh_rq_count = 0;
        }
@@ -1265,7 +1265,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
 
 out:
        if (neigh_node)
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
        return ret;
 }
 
@@ -1306,7 +1306,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 
        orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
        if (WARN_ON(!orig_ifinfo)) {
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
                return 0;
        }
 
@@ -1353,7 +1353,7 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
                packet_count = bitmap_weight(bitmap,
                                             BATADV_TQ_LOCAL_WINDOW_SIZE);
                neigh_ifinfo->bat_iv.real_packet_count = packet_count;
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
        }
        rcu_read_unlock();
 
@@ -1367,8 +1367,8 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 
 out:
        spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-       batadv_orig_node_free_ref(orig_node);
-       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+       batadv_orig_node_put(orig_node);
+       batadv_orig_ifinfo_put(orig_ifinfo);
        return ret;
 }
 
@@ -1514,7 +1514,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
                                          ogm_packet, if_incoming,
                                          if_outgoing, dup_status);
        }
-       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+       batadv_orig_ifinfo_put(orig_ifinfo);
 
        /* only forward for specific interface, not for the default one. */
        if (if_outgoing == BATADV_IF_DEFAULT)
@@ -1563,18 +1563,18 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
 
 out_neigh:
        if ((orig_neigh_node) && (!is_single_hop_neigh))
-               batadv_orig_node_free_ref(orig_neigh_node);
+               batadv_orig_node_put(orig_neigh_node);
 out:
        if (router_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_ifinfo);
+               batadv_neigh_ifinfo_put(router_ifinfo);
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
        if (router_router)
-               batadv_neigh_node_free_ref(router_router);
+               batadv_neigh_node_put(router_router);
        if (orig_neigh_router)
-               batadv_neigh_node_free_ref(orig_neigh_router);
+               batadv_neigh_node_put(orig_neigh_router);
        if (hardif_neigh)
-               batadv_hardif_neigh_free_ref(hardif_neigh);
+               batadv_hardif_neigh_put(hardif_neigh);
 
        kfree_skb(skb_priv);
 }
@@ -1697,7 +1697,7 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
 
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Drop packet: originator packet from myself (via neighbor)\n");
-               batadv_orig_node_free_ref(orig_neigh_node);
+               batadv_orig_node_put(orig_neigh_node);
                return;
        }
 
@@ -1735,7 +1735,7 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
        }
        rcu_read_unlock();
 
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
 }
 
 static int batadv_iv_ogm_receive(struct sk_buff *skb,
@@ -1805,7 +1805,7 @@ batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
                           neigh_node->addr,
                           n_ifinfo->bat_iv.tq_avg);
 
-               batadv_neigh_ifinfo_free_ref(n_ifinfo);
+               batadv_neigh_ifinfo_put(n_ifinfo);
        }
 }
 
@@ -1868,9 +1868,9 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
                        batman_count++;
 
 next:
-                       batadv_neigh_node_free_ref(neigh_node);
+                       batadv_neigh_node_put(neigh_node);
                        if (n_ifinfo)
-                               batadv_neigh_ifinfo_free_ref(n_ifinfo);
+                               batadv_neigh_ifinfo_put(n_ifinfo);
                }
                rcu_read_unlock();
        }
@@ -1964,9 +1964,9 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
 
 out:
        if (neigh1_ifinfo)
-               batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+               batadv_neigh_ifinfo_put(neigh1_ifinfo);
        if (neigh2_ifinfo)
-               batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
+               batadv_neigh_ifinfo_put(neigh2_ifinfo);
 
        return diff;
 }
@@ -2007,9 +2007,9 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
 
 out:
        if (neigh1_ifinfo)
-               batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+               batadv_neigh_ifinfo_put(neigh1_ifinfo);
        if (neigh2_ifinfo)
-               batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
+               batadv_neigh_ifinfo_put(neigh2_ifinfo);
 
        return ret;
 }
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
new file mode 100644 (file)
index 0000000..3315b9a
--- /dev/null
@@ -0,0 +1,347 @@
+/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing, Marek Lindner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bat_algo.h"
+#include "main.h"
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/netdevice.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "bat_v_elp.h"
+#include "bat_v_ogm.h"
+#include "hash.h"
+#include "originator.h"
+#include "packet.h"
+
+static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+       int ret;
+
+       ret = batadv_v_elp_iface_enable(hard_iface);
+       if (ret < 0)
+               return ret;
+
+       ret = batadv_v_ogm_iface_enable(hard_iface);
+       if (ret < 0)
+               batadv_v_elp_iface_disable(hard_iface);
+
+       /* enable link throughput auto-detection by setting the throughput
+        * override to zero
+        */
+       atomic_set(&hard_iface->bat_v.throughput_override, 0);
+
+       return ret;
+}
+
+static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
+{
+       batadv_v_elp_iface_disable(hard_iface);
+}
+
+static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
+{
+       batadv_v_elp_primary_iface_set(hard_iface);
+       batadv_v_ogm_primary_iface_set(hard_iface);
+}
+
+static void
+batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
+{
+       ewma_throughput_init(&hardif_neigh->bat_v.throughput);
+       INIT_WORK(&hardif_neigh->bat_v.metric_work,
+                 batadv_v_elp_throughput_metric_update);
+}
+
+static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
+{
+}
+
+static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
+{
+}
+
+/**
+ * batadv_v_orig_print_neigh - print neighbors for the originator table
+ * @orig_node: the orig_node for which the neighbors are printed
+ * @if_outgoing: outgoing interface for these entries
+ * @seq: debugfs table seq_file struct
+ *
+ * Must be called while holding an rcu lock.
+ */
+static void
+batadv_v_orig_print_neigh(struct batadv_orig_node *orig_node,
+                         struct batadv_hard_iface *if_outgoing,
+                         struct seq_file *seq)
+{
+       struct batadv_neigh_node *neigh_node;
+       struct batadv_neigh_ifinfo *n_ifinfo;
+
+       hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+               n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+               if (!n_ifinfo)
+                       continue;
+
+               seq_printf(seq, " %pM (%9u.%1u)",
+                          neigh_node->addr,
+                          n_ifinfo->bat_v.throughput / 10,
+                          n_ifinfo->bat_v.throughput % 10);
+
+               batadv_neigh_ifinfo_put(n_ifinfo);
+       }
+}
+
+/**
+ * batadv_v_hardif_neigh_print - print a single ELP neighbour node
+ * @seq: neighbour table seq_file struct
+ * @hardif_neigh: hardif neighbour information
+ */
+static void
+batadv_v_hardif_neigh_print(struct seq_file *seq,
+                           struct batadv_hardif_neigh_node *hardif_neigh)
+{
+       int last_secs, last_msecs;
+       u32 throughput;
+
+       last_secs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) / 1000;
+       last_msecs = jiffies_to_msecs(jiffies - hardif_neigh->last_seen) % 1000;
+       throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
+
+       seq_printf(seq, "%pM %4i.%03is (%9u.%1u) [%10s]\n",
+                  hardif_neigh->addr, last_secs, last_msecs, throughput / 10,
+                  throughput % 10, hardif_neigh->if_incoming->net_dev->name);
+}
+
+/**
+ * batadv_v_neigh_print - print the single hop neighbour list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @seq: neighbour table seq_file struct
+ */
+static void batadv_v_neigh_print(struct batadv_priv *bat_priv,
+                                struct seq_file *seq)
+{
+       struct net_device *net_dev = (struct net_device *)seq->private;
+       struct batadv_hardif_neigh_node *hardif_neigh;
+       struct batadv_hard_iface *hard_iface;
+       int batman_count = 0;
+
+       seq_printf(seq, "  %-15s %s (%11s) [%10s]\n", "Neighbor",
+                  "last-seen", "throughput", "IF");
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->soft_iface != net_dev)
+                       continue;
+
+               hlist_for_each_entry_rcu(hardif_neigh,
+                                        &hard_iface->neigh_list, list) {
+                       batadv_v_hardif_neigh_print(seq, hardif_neigh);
+                       batman_count++;
+               }
+       }
+       rcu_read_unlock();
+
+       if (batman_count == 0)
+               seq_puts(seq, "No batman nodes in range ...\n");
+}
+
+/**
+ * batadv_v_orig_print - print the originator table
+ * @bat_priv: the bat priv with all the soft interface information
+ * @seq: debugfs table seq_file struct
+ * @if_outgoing: the outgoing interface for which this should be printed
+ */
+static void batadv_v_orig_print(struct batadv_priv *bat_priv,
+                               struct seq_file *seq,
+                               struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_node *neigh_node;
+       struct batadv_hashtable *hash = bat_priv->orig_hash;
+       int last_seen_msecs, last_seen_secs;
+       struct batadv_orig_node *orig_node;
+       struct batadv_neigh_ifinfo *n_ifinfo;
+       unsigned long last_seen_jiffies;
+       struct hlist_head *head;
+       int batman_count = 0;
+       u32 i;
+
+       seq_printf(seq, "  %-15s %s (%11s) %17s [%10s]: %20s ...\n",
+                  "Originator", "last-seen", "throughput", "Nexthop",
+                  "outgoingIF", "Potential nexthops");
+
+       for (i = 0; i < hash->size; i++) {
+               head = &hash->table[i];
+
+               rcu_read_lock();
+               hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
+                       neigh_node = batadv_orig_router_get(orig_node,
+                                                           if_outgoing);
+                       if (!neigh_node)
+                               continue;
+
+                       n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
+                                                          if_outgoing);
+                       if (!n_ifinfo)
+                               goto next;
+
+                       last_seen_jiffies = jiffies - orig_node->last_seen;
+                       last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
+                       last_seen_secs = last_seen_msecs / 1000;
+                       last_seen_msecs = last_seen_msecs % 1000;
+
+                       seq_printf(seq, "%pM %4i.%03is (%9u.%1u) %pM [%10s]:",
+                                  orig_node->orig, last_seen_secs,
+                                  last_seen_msecs,
+                                  n_ifinfo->bat_v.throughput / 10,
+                                  n_ifinfo->bat_v.throughput % 10,
+                                  neigh_node->addr,
+                                  neigh_node->if_incoming->net_dev->name);
+
+                       batadv_v_orig_print_neigh(orig_node, if_outgoing, seq);
+                       seq_puts(seq, "\n");
+                       batman_count++;
+
+next:
+                       batadv_neigh_node_put(neigh_node);
+                       if (n_ifinfo)
+                               batadv_neigh_ifinfo_put(n_ifinfo);
+               }
+               rcu_read_unlock();
+       }
+
+       if (batman_count == 0)
+               seq_puts(seq, "No batman nodes in range ...\n");
+}
+
+static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
+                             struct batadv_hard_iface *if_outgoing1,
+                             struct batadv_neigh_node *neigh2,
+                             struct batadv_hard_iface *if_outgoing2)
+{
+       struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
+
+       ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+       ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+       if (WARN_ON(!ifinfo1 || !ifinfo2))
+               return 0;
+
+       return ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
+}
+
+static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
+                                 struct batadv_hard_iface *if_outgoing1,
+                                 struct batadv_neigh_node *neigh2,
+                                 struct batadv_hard_iface *if_outgoing2)
+{
+       struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
+       u32 threshold;
+
+       ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+       ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+       threshold = ifinfo1->bat_v.throughput / 4;
+       threshold = ifinfo1->bat_v.throughput - threshold;
+
+       return ifinfo2->bat_v.throughput > threshold;
+}
+
+static struct batadv_algo_ops batadv_batman_v __read_mostly = {
+       .name = "BATMAN_V",
+       .bat_iface_enable = batadv_v_iface_enable,
+       .bat_iface_disable = batadv_v_iface_disable,
+       .bat_iface_update_mac = batadv_v_iface_update_mac,
+       .bat_primary_iface_set = batadv_v_primary_iface_set,
+       .bat_hardif_neigh_init = batadv_v_hardif_neigh_init,
+       .bat_ogm_emit = batadv_v_ogm_emit,
+       .bat_ogm_schedule = batadv_v_ogm_schedule,
+       .bat_orig_print = batadv_v_orig_print,
+       .bat_neigh_cmp = batadv_v_neigh_cmp,
+       .bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob,
+       .bat_neigh_print = batadv_v_neigh_print,
+};
+
+/**
+ * batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a
+ *  mesh
+ * @bat_priv: the object representing the mesh interface to initialise
+ *
+ * Return: 0 on success or a negative error code otherwise
+ */
+int batadv_v_mesh_init(struct batadv_priv *bat_priv)
+{
+       return batadv_v_ogm_init(bat_priv);
+}
+
+/**
+ * batadv_v_mesh_free - free the B.A.T.M.A.N. V private resources for a mesh
+ * @bat_priv: the object representing the mesh interface to free
+ */
+void batadv_v_mesh_free(struct batadv_priv *bat_priv)
+{
+       batadv_v_ogm_free(bat_priv);
+}
+
+/**
+ * batadv_v_init - B.A.T.M.A.N. V initialization function
+ *
+ * Description: Takes care of initializing all the subcomponents.
+ * It is invoked upon module load only.
+ *
+ * Return: 0 on success or a negative error code otherwise
+ */
+int __init batadv_v_init(void)
+{
+       int ret;
+
+       /* B.A.T.M.A.N. V echo location protocol packet  */
+       ret = batadv_recv_handler_register(BATADV_ELP,
+                                          batadv_v_elp_packet_recv);
+       if (ret < 0)
+               return ret;
+
+       ret = batadv_recv_handler_register(BATADV_OGM2,
+                                          batadv_v_ogm_packet_recv);
+       if (ret < 0)
+               goto elp_unregister;
+
+       ret = batadv_algo_register(&batadv_batman_v);
+       if (ret < 0)
+               goto ogm_unregister;
+
+       return ret;
+
+ogm_unregister:
+       batadv_recv_handler_unregister(BATADV_OGM2);
+
+elp_unregister:
+       batadv_recv_handler_unregister(BATADV_ELP);
+
+       return ret;
+}
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
new file mode 100644 (file)
index 0000000..3844e7e
--- /dev/null
@@ -0,0 +1,515 @@
+/* Copyright (C) 2011-2016 B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing, Marek Lindner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bat_v_elp.h"
+#include "main.h"
+
+#include <linux/atomic.h>
+#include <linux/byteorder/generic.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/fs.h>
+#include <linux/if_ether.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <net/cfg80211.h>
+
+#include "bat_algo.h"
+#include "bat_v_ogm.h"
+#include "hard-interface.h"
+#include "originator.h"
+#include "packet.h"
+#include "routing.h"
+#include "send.h"
+
+/**
+ * batadv_v_elp_start_timer - restart timer for ELP periodic work
+ * @hard_iface: the interface for which the timer has to be reset
+ */
+static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
+{
+       unsigned int msecs;
+
+       msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
+       msecs += prandom_u32() % (2 * BATADV_JITTER);
+
+       queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
+                          msecs_to_jiffies(msecs));
+}
+
+/**
+ * batadv_v_elp_get_throughput - get the throughput towards a neighbour
+ * @neigh: the neighbour for which the throughput has to be obtained
+ *
+ * Return: The throughput towards the given neighbour in multiples of 100kpbs
+ *         (a value of '1' equals to 0.1Mbps, '10' equals 1Mbps, etc).
+ */
+static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
+{
+       struct batadv_hard_iface *hard_iface = neigh->if_incoming;
+       struct ethtool_link_ksettings link_settings;
+       struct station_info sinfo;
+       u32 throughput;
+       int ret;
+
+       /* if the user specified a customised value for this interface, then
+        * return it directly
+        */
+       throughput =  atomic_read(&hard_iface->bat_v.throughput_override);
+       if (throughput != 0)
+               return throughput;
+
+       /* if this is a wireless device, then ask its throughput through
+        * cfg80211 API
+        */
+       if (batadv_is_wifi_netdev(hard_iface->net_dev)) {
+               if (hard_iface->net_dev->ieee80211_ptr) {
+                       ret = cfg80211_get_station(hard_iface->net_dev,
+                                                  neigh->addr, &sinfo);
+                       if (ret == -ENOENT) {
+                               /* Node is not associated anymore! It would be
+                                * possible to delete this neighbor. For now set
+                                * the throughput metric to 0.
+                                */
+                               return 0;
+                       }
+                       if (!ret)
+                               return sinfo.expected_throughput / 100;
+               }
+
+               /* unsupported WiFi driver version */
+               goto default_throughput;
+       }
+
+       /* if not a wifi interface, check if this device provides data via
+        * ethtool (e.g. an Ethernet adapter)
+        */
+       memset(&link_settings, 0, sizeof(link_settings));
+       rtnl_lock();
+       ret = __ethtool_get_link_ksettings(hard_iface->net_dev, &link_settings);
+       rtnl_unlock();
+       if (ret == 0) {
+               /* link characteristics might change over time */
+               if (link_settings.base.duplex == DUPLEX_FULL)
+                       hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
+               else
+                       hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
+
+               throughput = link_settings.base.speed;
+               if (throughput && (throughput != SPEED_UNKNOWN))
+                       return throughput * 10;
+       }
+
+default_throughput:
+       if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) {
+               batadv_info(hard_iface->soft_iface,
+                           "WiFi driver or ethtool info does not provide information about link speeds on interface %s, therefore defaulting to hardcoded throughput values of %u.%1u Mbps. Consider overriding the throughput manually or checking your driver.\n",
+                           hard_iface->net_dev->name,
+                           BATADV_THROUGHPUT_DEFAULT_VALUE / 10,
+                           BATADV_THROUGHPUT_DEFAULT_VALUE % 10);
+               hard_iface->bat_v.flags |= BATADV_WARNING_DEFAULT;
+       }
+
+       /* if none of the above cases apply, return the base_throughput */
+       return BATADV_THROUGHPUT_DEFAULT_VALUE;
+}
+
+/**
+ * batadv_v_elp_throughput_metric_update - worker updating the throughput metric
+ *  of a single hop neighbour
+ * @work: the work queue item
+ */
+void batadv_v_elp_throughput_metric_update(struct work_struct *work)
+{
+       struct batadv_hardif_neigh_node_bat_v *neigh_bat_v;
+       struct batadv_hardif_neigh_node *neigh;
+
+       neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v,
+                                  metric_work);
+       neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node,
+                            bat_v);
+
+       ewma_throughput_add(&neigh->bat_v.throughput,
+                           batadv_v_elp_get_throughput(neigh));
+
+       /* decrement refcounter to balance increment performed before scheduling
+        * this task
+        */
+       batadv_hardif_neigh_put(neigh);
+}
+
+/**
+ * batadv_v_elp_wifi_neigh_probe - send link probing packets to a neighbour
+ * @neigh: the neighbour to probe
+ *
+ * Sends a predefined number of unicast wifi packets to a given neighbour in
+ * order to trigger the throughput estimation on this link by the RC algorithm.
+ * Packets are sent only if there there is not enough payload unicast traffic
+ * towards this neighbour..
+ *
+ * Return: True on success and false in case of error during skb preparation.
+ */
+static bool
+batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)
+{
+       struct batadv_hard_iface *hard_iface = neigh->if_incoming;
+       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+       unsigned long last_tx_diff;
+       struct sk_buff *skb;
+       int probe_len, i;
+       int elp_skb_len;
+
+       /* this probing routine is for Wifi neighbours only */
+       if (!batadv_is_wifi_netdev(hard_iface->net_dev))
+               return true;
+
+       /* probe the neighbor only if no unicast packets have been sent
+        * to it in the last 100 milliseconds: this is the rate control
+        * algorithm sampling interval (minstrel). In this way, if not
+        * enough traffic has been sent to the neighbor, batman-adv can
+        * generate 2 probe packets and push the RC algorithm to perform
+        * the sampling
+        */
+       last_tx_diff = jiffies_to_msecs(jiffies - neigh->bat_v.last_unicast_tx);
+       if (last_tx_diff <= BATADV_ELP_PROBE_MAX_TX_DIFF)
+               return true;
+
+       probe_len = max_t(int, sizeof(struct batadv_elp_packet),
+                         BATADV_ELP_MIN_PROBE_SIZE);
+
+       for (i = 0; i < BATADV_ELP_PROBES_PER_NODE; i++) {
+               elp_skb_len = hard_iface->bat_v.elp_skb->len;
+               skb = skb_copy_expand(hard_iface->bat_v.elp_skb, 0,
+                                     probe_len - elp_skb_len,
+                                     GFP_ATOMIC);
+               if (!skb)
+                       return false;
+
+               /* Tell the skb to get as big as the allocated space (we want
+                * the packet to be exactly of that size to make the link
+                * throughput estimation effective.
+                */
+               skb_put(skb, probe_len - hard_iface->bat_v.elp_skb->len);
+
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Sending unicast (probe) ELP packet on interface %s to %pM\n",
+                          hard_iface->net_dev->name, neigh->addr);
+
+               batadv_send_skb_packet(skb, hard_iface, neigh->addr);
+       }
+
+       return true;
+}
+
+/**
+ * batadv_v_elp_periodic_work - ELP periodic task per interface
+ * @work: work queue item
+ *
+ * Emits broadcast ELP message in regular intervals.
+ */
+static void batadv_v_elp_periodic_work(struct work_struct *work)
+{
+       struct batadv_hardif_neigh_node *hardif_neigh;
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_hard_iface_bat_v *bat_v;
+       struct batadv_elp_packet *elp_packet;
+       struct batadv_priv *bat_priv;
+       struct sk_buff *skb;
+       u32 elp_interval;
+
+       bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
+       hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
+       bat_priv = netdev_priv(hard_iface->soft_iface);
+
+       if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+               goto out;
+
+       /* we are in the process of shutting this interface down */
+       if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
+           (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
+               goto out;
+
+       /* the interface was enabled but may not be ready yet */
+       if (hard_iface->if_status != BATADV_IF_ACTIVE)
+               goto restart_timer;
+
+       skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
+       if (!skb)
+               goto restart_timer;
+
+       elp_packet = (struct batadv_elp_packet *)skb->data;
+       elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
+       elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
+       elp_packet->elp_interval = htonl(elp_interval);
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Sending broadcast ELP packet on interface %s, seqno %u\n",
+                  hard_iface->net_dev->name,
+                  atomic_read(&hard_iface->bat_v.elp_seqno));
+
+       batadv_send_broadcast_skb(skb, hard_iface);
+
+       atomic_inc(&hard_iface->bat_v.elp_seqno);
+
+       /* The throughput metric is updated on each sent packet. This way, if a
+        * node is dead and no longer sends packets, batman-adv is still able to
+        * react timely to its death.
+        *
+        * The throughput metric is updated by following these steps:
+        * 1) if the hard_iface is wifi => send a number of unicast ELPs for
+        *    probing/sampling to each neighbor
+        * 2) update the throughput metric value of each neighbor (note that the
+        *    value retrieved in this step might be 100ms old because the
+        *    probing packets at point 1) could still be in the HW queue)
+        */
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(hardif_neigh, &hard_iface->neigh_list, list) {
+               if (!batadv_v_elp_wifi_neigh_probe(hardif_neigh))
+                       /* if something goes wrong while probing, better to stop
+                        * sending packets immediately and reschedule the task
+                        */
+                       break;
+
+               if (!kref_get_unless_zero(&hardif_neigh->refcount))
+                       continue;
+
+               /* Reading the estimated throughput from cfg80211 is a task that
+                * may sleep and that is not allowed in an rcu protected
+                * context. Therefore schedule a task for that.
+                */
+               queue_work(batadv_event_workqueue,
+                          &hardif_neigh->bat_v.metric_work);
+       }
+       rcu_read_unlock();
+
+restart_timer:
+       batadv_v_elp_start_timer(hard_iface);
+out:
+       return;
+}
+
+/**
+ * batadv_v_elp_iface_enable - setup the ELP interface private resources
+ * @hard_iface: interface for which the data has to be prepared
+ *
+ * Return: 0 on success or a -ENOMEM in case of failure.
+ */
+int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+       struct batadv_elp_packet *elp_packet;
+       unsigned char *elp_buff;
+       u32 random_seqno;
+       size_t size;
+       int res = -ENOMEM;
+
+       size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN;
+       hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
+       if (!hard_iface->bat_v.elp_skb)
+               goto out;
+
+       skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
+       elp_buff = skb_push(hard_iface->bat_v.elp_skb, BATADV_ELP_HLEN);
+       elp_packet = (struct batadv_elp_packet *)elp_buff;
+       memset(elp_packet, 0, BATADV_ELP_HLEN);
+
+       elp_packet->packet_type = BATADV_ELP;
+       elp_packet->version = BATADV_COMPAT_VERSION;
+
+       /* randomize initial seqno to avoid collision */
+       get_random_bytes(&random_seqno, sizeof(random_seqno));
+       atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
+       atomic_set(&hard_iface->bat_v.elp_interval, 500);
+
+       /* assume full-duplex by default */
+       hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
+
+       /* warn the user (again) if there is no throughput data is available */
+       hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT;
+
+       if (batadv_is_wifi_netdev(hard_iface->net_dev))
+               hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
+
+       INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
+                         batadv_v_elp_periodic_work);
+       batadv_v_elp_start_timer(hard_iface);
+       res = 0;
+
+out:
+       return res;
+}
+
+/**
+ * batadv_v_elp_iface_disable - release ELP interface private resources
+ * @hard_iface: interface for which the resources have to be released
+ */
+void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
+{
+       cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
+
+       dev_kfree_skb(hard_iface->bat_v.elp_skb);
+       hard_iface->bat_v.elp_skb = NULL;
+}
+
+/**
+ * batadv_v_elp_primary_iface_set - change internal data to reflect the new
+ *  primary interface
+ * @primary_iface: the new primary interface
+ */
+void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
+{
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_elp_packet *elp_packet;
+       struct sk_buff *skb;
+
+       /* update orig field of every elp iface belonging to this mesh */
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (primary_iface->soft_iface != hard_iface->soft_iface)
+                       continue;
+
+               if (!hard_iface->bat_v.elp_skb)
+                       continue;
+
+               skb = hard_iface->bat_v.elp_skb;
+               elp_packet = (struct batadv_elp_packet *)skb->data;
+               ether_addr_copy(elp_packet->orig,
+                               primary_iface->net_dev->dev_addr);
+       }
+       rcu_read_unlock();
+}
+
+/**
+ * batadv_v_elp_neigh_update - update an ELP neighbour node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @neigh_addr: the neighbour interface address
+ * @if_incoming: the interface the packet was received through
+ * @elp_packet: the received ELP packet
+ *
+ * Updates the ELP neighbour node state with the data received within the new
+ * ELP packet.
+ */
+static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
+                                     u8 *neigh_addr,
+                                     struct batadv_hard_iface *if_incoming,
+                                     struct batadv_elp_packet *elp_packet)
+
+{
+       struct batadv_neigh_node *neigh;
+       struct batadv_orig_node *orig_neigh;
+       struct batadv_hardif_neigh_node *hardif_neigh;
+       s32 seqno_diff;
+       s32 elp_latest_seqno;
+
+       orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig);
+       if (!orig_neigh)
+               return;
+
+       neigh = batadv_neigh_node_new(orig_neigh, if_incoming, neigh_addr);
+       if (!neigh)
+               goto orig_free;
+
+       hardif_neigh = batadv_hardif_neigh_get(if_incoming, neigh_addr);
+       if (!hardif_neigh)
+               goto neigh_free;
+
+       elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno;
+       seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno;
+
+       /* known or older sequence numbers are ignored. However always adopt
+        * if the router seems to have been restarted.
+        */
+       if (seqno_diff < 1 && seqno_diff > -BATADV_ELP_MAX_AGE)
+               goto hardif_free;
+
+       neigh->last_seen = jiffies;
+       hardif_neigh->last_seen = jiffies;
+       hardif_neigh->bat_v.elp_latest_seqno = ntohl(elp_packet->seqno);
+       hardif_neigh->bat_v.elp_interval = ntohl(elp_packet->elp_interval);
+
+hardif_free:
+       if (hardif_neigh)
+               batadv_hardif_neigh_put(hardif_neigh);
+neigh_free:
+       if (neigh)
+               batadv_neigh_node_put(neigh);
+orig_free:
+       if (orig_neigh)
+               batadv_orig_node_put(orig_neigh);
+}
+
+/**
+ * batadv_v_elp_packet_recv - main ELP packet handler
+ * @skb: the received packet
+ * @if_incoming: the interface this packet was received through
+ *
+ * Return: NET_RX_SUCCESS and consumes the skb if the packet was peoperly
+ * processed or NET_RX_DROP in case of failure.
+ */
+int batadv_v_elp_packet_recv(struct sk_buff *skb,
+                            struct batadv_hard_iface *if_incoming)
+{
+       struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct batadv_elp_packet *elp_packet;
+       struct batadv_hard_iface *primary_if;
+       struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+       bool ret;
+
+       ret = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
+       if (!ret)
+               return NET_RX_DROP;
+
+       if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
+               return NET_RX_DROP;
+
+       /* did we receive a B.A.T.M.A.N. V ELP packet on an interface
+        * that does not have B.A.T.M.A.N. V ELP enabled ?
+        */
+       if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
+               return NET_RX_DROP;
+
+       elp_packet = (struct batadv_elp_packet *)skb->data;
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Received ELP packet from %pM seqno %u ORIG: %pM\n",
+                  ethhdr->h_source, ntohl(elp_packet->seqno),
+                  elp_packet->orig);
+
+       primary_if = batadv_primary_if_get_selected(bat_priv);
+       if (!primary_if)
+               goto out;
+
+       batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
+                                 elp_packet);
+
+out:
+       if (primary_if)
+               batadv_hardif_put(primary_if);
+       consume_skb(skb);
+       return NET_RX_SUCCESS;
+}
diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h
new file mode 100644 (file)
index 0000000..e95f1bc
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
+ *
+ * Linus Lüssing, Marek Lindner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "main.h"
+
+#ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_
+#define _NET_BATMAN_ADV_BAT_V_ELP_H_
+
+struct sk_buff;
+struct work_struct;
+
+int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
+void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
+void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface);
+int batadv_v_elp_packet_recv(struct sk_buff *skb,
+                            struct batadv_hard_iface *if_incoming);
+void batadv_v_elp_throughput_metric_update(struct work_struct *work);
+
+#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
new file mode 100644 (file)
index 0000000..d9bcbe6
--- /dev/null
@@ -0,0 +1,833 @@
+/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "bat_v_ogm.h"
+#include "main.h"
+
+#include <linux/atomic.h>
+#include <linux/byteorder/generic.h>
+#include <linux/errno.h>
+#include <linux/etherdevice.h>
+#include <linux/fs.h>
+#include <linux/if_ether.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "hard-interface.h"
+#include "hash.h"
+#include "originator.h"
+#include "packet.h"
+#include "routing.h"
+#include "send.h"
+#include "translation-table.h"
+
+/**
+ * batadv_v_ogm_orig_get - retrieve and possibly create an originator node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the address of the originator
+ *
+ * Return: the orig_node corresponding to the specified address. If such object
+ * does not exist it is allocated here. In case of allocation failure returns
+ * NULL.
+ */
+struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
+                                              const u8 *addr)
+{
+       struct batadv_orig_node *orig_node;
+       int hash_added;
+
+       orig_node = batadv_orig_hash_find(bat_priv, addr);
+       if (orig_node)
+               return orig_node;
+
+       orig_node = batadv_orig_node_new(bat_priv, addr);
+       if (!orig_node)
+               return NULL;
+
+       hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
+                                    batadv_choose_orig, orig_node,
+                                    &orig_node->hash_entry);
+       if (hash_added != 0) {
+               /* orig_node->refcounter is initialised to 2 by
+                * batadv_orig_node_new()
+                */
+               batadv_orig_node_put(orig_node);
+               batadv_orig_node_put(orig_node);
+               orig_node = NULL;
+       }
+
+       return orig_node;
+}
+
+/**
+ * batadv_v_ogm_start_timer - restart the OGM sending timer
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
+{
+       unsigned long msecs;
+       /* this function may be invoked in different contexts (ogm rescheduling
+        * or hard_iface activation), but the work timer should not be reset
+        */
+       if (delayed_work_pending(&bat_priv->bat_v.ogm_wq))
+               return;
+
+       msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
+       msecs += prandom_u32() % (2 * BATADV_JITTER);
+       queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq,
+                          msecs_to_jiffies(msecs));
+}
+
+/**
+ * batadv_v_ogm_send_to_if - send a batman ogm using a given interface
+ * @skb: the OGM to send
+ * @hard_iface: the interface to use to send the OGM
+ */
+static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
+                                   struct batadv_hard_iface *hard_iface)
+{
+       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+       if (hard_iface->if_status != BATADV_IF_ACTIVE)
+               return;
+
+       batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_TX);
+       batadv_add_counter(bat_priv, BATADV_CNT_MGMT_TX_BYTES,
+                          skb->len + ETH_HLEN);
+
+       batadv_send_broadcast_skb(skb, hard_iface);
+}
+
+/**
+ * batadv_v_ogm_send - periodic worker broadcasting the own OGM
+ * @work: work queue item
+ */
+static void batadv_v_ogm_send(struct work_struct *work)
+{
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_priv_bat_v *bat_v;
+       struct batadv_priv *bat_priv;
+       struct batadv_ogm2_packet *ogm_packet;
+       struct sk_buff *skb, *skb_tmp;
+       unsigned char *ogm_buff, *pkt_buff;
+       int ogm_buff_len;
+       u16 tvlv_len = 0;
+
+       bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
+       bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
+
+       if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+               goto out;
+
+       ogm_buff = bat_priv->bat_v.ogm_buff;
+       ogm_buff_len = bat_priv->bat_v.ogm_buff_len;
+       /* tt changes have to be committed before the tvlv data is
+        * appended as it may alter the tt tvlv container
+        */
+       batadv_tt_local_commit_changes(bat_priv);
+       tvlv_len = batadv_tvlv_container_ogm_append(bat_priv, &ogm_buff,
+                                                   &ogm_buff_len,
+                                                   BATADV_OGM2_HLEN);
+
+       bat_priv->bat_v.ogm_buff = ogm_buff;
+       bat_priv->bat_v.ogm_buff_len = ogm_buff_len;
+
+       skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff_len);
+       if (!skb)
+               goto reschedule;
+
+       skb_reserve(skb, ETH_HLEN);
+       pkt_buff = skb_put(skb, ogm_buff_len);
+       memcpy(pkt_buff, ogm_buff, ogm_buff_len);
+
+       ogm_packet = (struct batadv_ogm2_packet *)skb->data;
+       ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
+       atomic_inc(&bat_priv->bat_v.ogm_seqno);
+       ogm_packet->tvlv_len = htons(tvlv_len);
+
+       /* broadcast on every interface */
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->soft_iface != bat_priv->soft_iface)
+                       continue;
+
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Sending own OGM2 packet (originator %pM, seqno %u, throughput %u, TTL %d) on interface %s [%pM]\n",
+                          ogm_packet->orig, ntohl(ogm_packet->seqno),
+                          ntohl(ogm_packet->throughput), ogm_packet->ttl,
+                          hard_iface->net_dev->name,
+                          hard_iface->net_dev->dev_addr);
+
+               /* this skb gets consumed by batadv_v_ogm_send_to_if() */
+               skb_tmp = skb_clone(skb, GFP_ATOMIC);
+               if (!skb_tmp)
+                       break;
+
+               batadv_v_ogm_send_to_if(skb_tmp, hard_iface);
+       }
+       rcu_read_unlock();
+
+       consume_skb(skb);
+
+reschedule:
+       batadv_v_ogm_start_timer(bat_priv);
+out:
+       return;
+}
+
+/**
+ * batadv_v_ogm_iface_enable - prepare an interface for B.A.T.M.A.N. V
+ * @hard_iface: the interface to prepare
+ *
+ * Takes care of scheduling own OGM sending routine for this interface.
+ *
+ * Return: 0 on success or a negative error code otherwise
+ */
+int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+{
+       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+
+       batadv_v_ogm_start_timer(bat_priv);
+
+       return 0;
+}
+
+/**
+ * batadv_v_ogm_primary_iface_set - set a new primary interface
+ * @primary_iface: the new primary interface
+ */
+void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
+{
+       struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
+       struct batadv_ogm2_packet *ogm_packet;
+
+       if (!bat_priv->bat_v.ogm_buff)
+               return;
+
+       ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
+       ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
+}
+
+/**
+ * batadv_v_ogm_orig_update - update the originator status based on the received
+ *  OGM
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the originator to update
+ * @neigh_node: the neighbour the OGM has been received from (to update)
+ * @ogm2: the received OGM
+ * @if_outgoing: the interface where this OGM is going to be forwarded through
+ */
+static void
+batadv_v_ogm_orig_update(struct batadv_priv *bat_priv,
+                        struct batadv_orig_node *orig_node,
+                        struct batadv_neigh_node *neigh_node,
+                        const struct batadv_ogm2_packet *ogm2,
+                        struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_ifinfo *router_ifinfo = NULL, *neigh_ifinfo = NULL;
+       struct batadv_neigh_node *router = NULL;
+       s32 neigh_seq_diff;
+       u32 neigh_last_seqno;
+       u32 router_last_seqno;
+       u32 router_throughput, neigh_throughput;
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Searching and updating originator entry of received packet\n");
+
+       /* if this neighbor already is our next hop there is nothing
+        * to change
+        */
+       router = batadv_orig_router_get(orig_node, if_outgoing);
+       if (router == neigh_node)
+               goto out;
+
+       /* don't consider neighbours with worse throughput.
+        * also switch route if this seqno is BATADV_V_MAX_ORIGDIFF newer than
+        * the last received seqno from our best next hop.
+        */
+       if (router) {
+               router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
+               neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+
+               /* if these are not allocated, something is wrong. */
+               if (!router_ifinfo || !neigh_ifinfo)
+                       goto out;
+
+               neigh_last_seqno = neigh_ifinfo->bat_v.last_seqno;
+               router_last_seqno = router_ifinfo->bat_v.last_seqno;
+               neigh_seq_diff = neigh_last_seqno - router_last_seqno;
+               router_throughput = router_ifinfo->bat_v.throughput;
+               neigh_throughput = neigh_ifinfo->bat_v.throughput;
+
+               if ((neigh_seq_diff < BATADV_OGM_MAX_ORIGDIFF) &&
+                   (router_throughput >= neigh_throughput))
+                       goto out;
+       }
+
+       batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
+
+out:
+       if (router_ifinfo)
+               batadv_neigh_ifinfo_put(router_ifinfo);
+       if (neigh_ifinfo)
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
+       if (router)
+               batadv_neigh_node_put(router);
+}
+
+/**
+ * batadv_v_forward_penalty - apply a penalty to the throughput metric forwarded
+ *  with B.A.T.M.A.N. V OGMs
+ * @bat_priv: the bat priv with all the soft interface information
+ * @if_incoming: the interface where the OGM has been received
+ * @if_outgoing: the interface where the OGM has to be forwarded to
+ * @throughput: the current throughput
+ *
+ * Apply a penalty on the current throughput metric value based on the
+ * characteristic of the interface where the OGM has been received. The return
+ * value is computed as follows:
+ * - throughput * 50%          if the incoming and outgoing interface are the
+ *                             same WiFi interface and the throughput is above
+ *                             1MBit/s
+ * - throughput                if the outgoing interface is the default
+ *                             interface (i.e. this OGM is processed for the
+ *                             internal table and not forwarded)
+ * - throughput * hop penalty  otherwise
+ *
+ * Return: the penalised throughput metric.
+ */
+static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv,
+                                   struct batadv_hard_iface *if_incoming,
+                                   struct batadv_hard_iface *if_outgoing,
+                                   u32 throughput)
+{
+       int hop_penalty = atomic_read(&bat_priv->hop_penalty);
+       int hop_penalty_max = BATADV_TQ_MAX_VALUE;
+
+       /* Don't apply hop penalty in default originator table. */
+       if (if_outgoing == BATADV_IF_DEFAULT)
+               return throughput;
+
+       /* Forwarding on the same WiFi interface cuts the throughput in half
+        * due to the store & forward characteristics of WIFI.
+        * Very low throughput values are the exception.
+        */
+       if ((throughput > 10) &&
+           (if_incoming == if_outgoing) &&
+           !(if_incoming->bat_v.flags & BATADV_FULL_DUPLEX))
+               return throughput / 2;
+
+       /* hop penalty of 255 equals 100% */
+       return throughput * (hop_penalty_max - hop_penalty) / hop_penalty_max;
+}
+
+/**
+ * batadv_v_ogm_forward - forward an OGM to the given outgoing interface
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ogm_received: previously received OGM to be forwarded
+ * @throughput: throughput to announce, may vary per outgoing interface
+ * @if_incoming: the interface on which this OGM was received on
+ * @if_outgoing: the interface to which the OGM has to be forwarded to
+ *
+ * Forward an OGM to an interface after having altered the throughput metric and
+ * the TTL value contained in it. The original OGM isn't modified.
+ */
+static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
+                                const struct batadv_ogm2_packet *ogm_received,
+                                u32 throughput,
+                                struct batadv_hard_iface *if_incoming,
+                                struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_ogm2_packet *ogm_forward;
+       unsigned char *skb_buff;
+       struct sk_buff *skb;
+       size_t packet_len;
+       u16 tvlv_len;
+
+       if (ogm_received->ttl <= 1) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n");
+               return;
+       }
+
+       tvlv_len = ntohs(ogm_received->tvlv_len);
+
+       packet_len = BATADV_OGM2_HLEN + tvlv_len;
+       skb = netdev_alloc_skb_ip_align(if_outgoing->net_dev,
+                                       ETH_HLEN + packet_len);
+       if (!skb)
+               return;
+
+       skb_reserve(skb, ETH_HLEN);
+       skb_buff = skb_put(skb, packet_len);
+       memcpy(skb_buff, ogm_received, packet_len);
+
+       /* apply forward penalty */
+       ogm_forward = (struct batadv_ogm2_packet *)skb_buff;
+       ogm_forward->throughput = htonl(throughput);
+       ogm_forward->ttl--;
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Forwarding OGM2 packet on %s: throughput %u, ttl %u, received via %s\n",
+                  if_outgoing->net_dev->name, throughput, ogm_forward->ttl,
+                  if_incoming->net_dev->name);
+
+       batadv_v_ogm_send_to_if(skb, if_outgoing);
+}
+
+/**
+ * batadv_v_ogm_metric_update - update route metric based on OGM
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ogm2: OGM2 structure
+ * @orig_node: Originator structure for which the OGM has been received
+ * @neigh_node: the neigh_node through with the OGM has been received
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ *
+ * Return:
+ *  1  if the OGM is new,
+ *  0  if it is not new but valid,
+ *  <0 on error (e.g. old OGM)
+ */
+static int batadv_v_ogm_metric_update(struct batadv_priv *bat_priv,
+                                     const struct batadv_ogm2_packet *ogm2,
+                                     struct batadv_orig_node *orig_node,
+                                     struct batadv_neigh_node *neigh_node,
+                                     struct batadv_hard_iface *if_incoming,
+                                     struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+       struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
+       bool protection_started = false;
+       int ret = -EINVAL;
+       u32 path_throughput;
+       s32 seq_diff;
+
+       orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+       if (!orig_ifinfo)
+               goto out;
+
+       seq_diff = ntohl(ogm2->seqno) - orig_ifinfo->last_real_seqno;
+
+       if (!hlist_empty(&orig_node->neigh_list) &&
+           batadv_window_protected(bat_priv, seq_diff,
+                                   BATADV_OGM_MAX_AGE,
+                                   &orig_ifinfo->batman_seqno_reset,
+                                   &protection_started)) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: packet within window protection time from %pM\n",
+                          ogm2->orig);
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Last reset: %ld, %ld\n",
+                          orig_ifinfo->batman_seqno_reset, jiffies);
+               goto out;
+       }
+
+       /* drop packets with old seqnos, however accept the first packet after
+        * a host has been rebooted.
+        */
+       if ((seq_diff < 0) && !protection_started)
+               goto out;
+
+       neigh_node->last_seen = jiffies;
+
+       orig_node->last_seen = jiffies;
+
+       orig_ifinfo->last_real_seqno = ntohl(ogm2->seqno);
+       orig_ifinfo->last_ttl = ogm2->ttl;
+
+       neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+       if (!neigh_ifinfo)
+               goto out;
+
+       path_throughput = batadv_v_forward_penalty(bat_priv, if_incoming,
+                                                  if_outgoing,
+                                                  ntohl(ogm2->throughput));
+       neigh_ifinfo->bat_v.throughput = path_throughput;
+       neigh_ifinfo->bat_v.last_seqno = ntohl(ogm2->seqno);
+       neigh_ifinfo->last_ttl = ogm2->ttl;
+
+       if (seq_diff > 0 || protection_started)
+               ret = 1;
+       else
+               ret = 0;
+out:
+       if (orig_ifinfo)
+               batadv_orig_ifinfo_put(orig_ifinfo);
+       if (neigh_ifinfo)
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
+
+       return ret;
+}
+
+/**
+ * batadv_v_ogm_route_update - update routes based on OGM
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: the Ethernet header of the OGM2
+ * @ogm2: OGM2 structure
+ * @orig_node: Originator structure for which the OGM has been received
+ * @neigh_node: the neigh_node through with the OGM has been received
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ */
+static void batadv_v_ogm_route_update(struct batadv_priv *bat_priv,
+                                     const struct ethhdr *ethhdr,
+                                     const struct batadv_ogm2_packet *ogm2,
+                                     struct batadv_orig_node *orig_node,
+                                     struct batadv_neigh_node *neigh_node,
+                                     struct batadv_hard_iface *if_incoming,
+                                     struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_node *router = NULL;
+       struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
+       struct batadv_orig_node *orig_neigh_node = NULL;
+       struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+       struct batadv_neigh_node *orig_neigh_router = NULL;
+
+       neigh_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+       if (!neigh_ifinfo)
+               goto out;
+
+       orig_neigh_node = batadv_v_ogm_orig_get(bat_priv, ethhdr->h_source);
+       if (!orig_neigh_node)
+               goto out;
+
+       orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
+                                                  if_outgoing);
+
+       /* drop packet if sender is not a direct neighbor and if we
+        * don't route towards it
+        */
+       router = batadv_orig_router_get(orig_node, if_outgoing);
+       if (router && router->orig_node != orig_node && !orig_neigh_router) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: OGM via unknown neighbor!\n");
+               goto out;
+       }
+
+       if (router)
+               batadv_neigh_node_put(router);
+
+       /* Update routes, and check if the OGM is from the best next hop */
+       batadv_v_ogm_orig_update(bat_priv, orig_node, neigh_node, ogm2,
+                                if_outgoing);
+
+       orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+       if (!orig_ifinfo)
+               goto out;
+
+       /* don't forward the same seqno twice on one interface */
+       if (orig_ifinfo->last_seqno_forwarded == ntohl(ogm2->seqno))
+               goto out;
+
+       /* acquire possibly updated router */
+       router = batadv_orig_router_get(orig_node, if_outgoing);
+
+       /* strict rule: forward packets coming from the best next hop only */
+       if (neigh_node != router)
+               goto out;
+
+       /* only forward for specific interface, not for the default one. */
+       if (if_outgoing != BATADV_IF_DEFAULT) {
+               orig_ifinfo->last_seqno_forwarded = ntohl(ogm2->seqno);
+               batadv_v_ogm_forward(bat_priv, ogm2,
+                                    neigh_ifinfo->bat_v.throughput,
+                                    if_incoming, if_outgoing);
+       }
+
+out:
+       if (orig_ifinfo)
+               batadv_orig_ifinfo_put(orig_ifinfo);
+       if (router)
+               batadv_neigh_node_put(router);
+       if (orig_neigh_router)
+               batadv_neigh_node_put(orig_neigh_router);
+       if (orig_neigh_node)
+               batadv_orig_node_put(orig_neigh_node);
+       if (neigh_ifinfo)
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
+}
+
+/**
+ * batadv_v_ogm_process_per_outif - process a batman v OGM for an outgoing if
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: the Ethernet header of the OGM2
+ * @ogm2: OGM2 structure
+ * @orig_node: Originator structure for which the OGM has been received
+ * @neigh_node: the neigh_node through with the OGM has been received
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ */
+static void
+batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
+                              const struct ethhdr *ethhdr,
+                              const struct batadv_ogm2_packet *ogm2,
+                              struct batadv_orig_node *orig_node,
+                              struct batadv_neigh_node *neigh_node,
+                              struct batadv_hard_iface *if_incoming,
+                              struct batadv_hard_iface *if_outgoing)
+{
+       int seqno_age;
+
+       /* first, update the metric with according sanity checks */
+       seqno_age = batadv_v_ogm_metric_update(bat_priv, ogm2, orig_node,
+                                              neigh_node, if_incoming,
+                                              if_outgoing);
+
+       /* outdated sequence numbers are to be discarded */
+       if (seqno_age < 0)
+               return;
+
+       /* only unknown & newer OGMs contain TVLVs we are interested in */
+       if ((seqno_age > 0) && (if_outgoing == BATADV_IF_DEFAULT))
+               batadv_tvlv_containers_process(bat_priv, true, orig_node,
+                                              NULL, NULL,
+                                              (unsigned char *)(ogm2 + 1),
+                                              ntohs(ogm2->tvlv_len));
+
+       /* if the metric update went through, update routes if needed */
+       batadv_v_ogm_route_update(bat_priv, ethhdr, ogm2, orig_node,
+                                 neigh_node, if_incoming, if_outgoing);
+}
+
+/**
+ * batadv_v_ogm_aggr_packet - checks if there is another OGM aggregated
+ * @buff_pos: current position in the skb
+ * @packet_len: total length of the skb
+ * @tvlv_len: tvlv length of the previously considered OGM
+ *
+ * Return: true if there is enough space for another OGM, false otherwise.
+ */
+static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
+                                    __be16 tvlv_len)
+{
+       int next_buff_pos = 0;
+
+       next_buff_pos += buff_pos + BATADV_OGM2_HLEN;
+       next_buff_pos += ntohs(tvlv_len);
+
+       return (next_buff_pos <= packet_len) &&
+              (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
+}
+
+/**
+ * batadv_v_ogm_process - process an incoming batman v OGM
+ * @skb: the skb containing the OGM
+ * @ogm_offset: offset to the OGM which should be processed (for aggregates)
+ * @if_incoming: the interface where this packet was receved
+ */
+static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
+                                struct batadv_hard_iface *if_incoming)
+{
+       struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct ethhdr *ethhdr;
+       struct batadv_orig_node *orig_node = NULL;
+       struct batadv_hardif_neigh_node *hardif_neigh = NULL;
+       struct batadv_neigh_node *neigh_node = NULL;
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_ogm2_packet *ogm_packet;
+       u32 ogm_throughput, link_throughput, path_throughput;
+
+       ethhdr = eth_hdr(skb);
+       ogm_packet = (struct batadv_ogm2_packet *)(skb->data + ogm_offset);
+
+       ogm_throughput = ntohl(ogm_packet->throughput);
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Received OGM2 packet via NB: %pM, IF: %s [%pM] (from OG: %pM, seqno %u, troughput %u, TTL %u, V %u, tvlv_len %u)\n",
+                  ethhdr->h_source, if_incoming->net_dev->name,
+                  if_incoming->net_dev->dev_addr, ogm_packet->orig,
+                  ntohl(ogm_packet->seqno), ogm_throughput, ogm_packet->ttl,
+                  ogm_packet->version, ntohs(ogm_packet->tvlv_len));
+
+       /* If the troughput metric is 0, immediately drop the packet. No need to
+        * create orig_node / neigh_node for an unusable route.
+        */
+       if (ogm_throughput == 0) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: originator packet with troughput metric of 0\n");
+               return;
+       }
+
+       /* require ELP packets be to received from this neighbor first */
+       hardif_neigh = batadv_hardif_neigh_get(if_incoming, ethhdr->h_source);
+       if (!hardif_neigh) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: OGM via unknown neighbor!\n");
+               goto out;
+       }
+
+       orig_node = batadv_v_ogm_orig_get(bat_priv, ogm_packet->orig);
+       if (!orig_node)
+               return;
+
+       neigh_node = batadv_neigh_node_new(orig_node, if_incoming,
+                                          ethhdr->h_source);
+       if (!neigh_node)
+               goto out;
+
+       /* Update the received throughput metric to match the link
+        * characteristic:
+        *  - If this OGM traveled one hop so far (emitted by single hop
+        *    neighbor) the path throughput metric equals the link throughput.
+        *  - For OGMs traversing more than hop the path throughput metric is
+        *    the smaller of the path throughput and the link throughput.
+        */
+       link_throughput = ewma_throughput_read(&hardif_neigh->bat_v.throughput);
+       path_throughput = min_t(u32, link_throughput, ogm_throughput);
+       ogm_packet->throughput = htonl(path_throughput);
+
+       batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet, orig_node,
+                                      neigh_node, if_incoming,
+                                      BATADV_IF_DEFAULT);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->if_status != BATADV_IF_ACTIVE)
+                       continue;
+
+               if (hard_iface->soft_iface != bat_priv->soft_iface)
+                       continue;
+
+               batadv_v_ogm_process_per_outif(bat_priv, ethhdr, ogm_packet,
+                                              orig_node, neigh_node,
+                                              if_incoming, hard_iface);
+       }
+       rcu_read_unlock();
+out:
+       if (orig_node)
+               batadv_orig_node_put(orig_node);
+       if (neigh_node)
+               batadv_neigh_node_put(neigh_node);
+       if (hardif_neigh)
+               batadv_hardif_neigh_put(hardif_neigh);
+}
+
+/**
+ * batadv_v_ogm_packet_recv - OGM2 receiving handler
+ * @skb: the received OGM
+ * @if_incoming: the interface where this OGM has been received
+ *
+ * Return: NET_RX_SUCCESS and consume the skb on success or returns NET_RX_DROP
+ * (without freeing the skb) on failure
+ */
+int batadv_v_ogm_packet_recv(struct sk_buff *skb,
+                            struct batadv_hard_iface *if_incoming)
+{
+       struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct batadv_ogm2_packet *ogm_packet;
+       struct ethhdr *ethhdr = eth_hdr(skb);
+       int ogm_offset;
+       u8 *packet_pos;
+       int ret = NET_RX_DROP;
+
+       /* did we receive a OGM2 packet on an interface that does not have
+        * B.A.T.M.A.N. V enabled ?
+        */
+       if (strcmp(bat_priv->bat_algo_ops->name, "BATMAN_V") != 0)
+               return NET_RX_DROP;
+
+       if (!batadv_check_management_packet(skb, if_incoming, BATADV_OGM2_HLEN))
+               return NET_RX_DROP;
+
+       if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
+               return NET_RX_DROP;
+
+       ogm_packet = (struct batadv_ogm2_packet *)skb->data;
+
+       if (batadv_is_my_mac(bat_priv, ogm_packet->orig))
+               return NET_RX_DROP;
+
+       batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
+       batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
+                          skb->len + ETH_HLEN);
+
+       ogm_offset = 0;
+       ogm_packet = (struct batadv_ogm2_packet *)skb->data;
+
+       while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
+                                       ogm_packet->tvlv_len)) {
+               batadv_v_ogm_process(skb, ogm_offset, if_incoming);
+
+               ogm_offset += BATADV_OGM2_HLEN;
+               ogm_offset += ntohs(ogm_packet->tvlv_len);
+
+               packet_pos = skb->data + ogm_offset;
+               ogm_packet = (struct batadv_ogm2_packet *)packet_pos;
+       }
+
+       ret = NET_RX_SUCCESS;
+       consume_skb(skb);
+
+       return ret;
+}
+
+/**
+ * batadv_v_ogm_init - initialise the OGM2 engine
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Return: 0 on success or a negative error code in case of failure
+ */
+int batadv_v_ogm_init(struct batadv_priv *bat_priv)
+{
+       struct batadv_ogm2_packet *ogm_packet;
+       unsigned char *ogm_buff;
+       u32 random_seqno;
+
+       bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
+       ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
+       if (!ogm_buff)
+               return -ENOMEM;
+
+       bat_priv->bat_v.ogm_buff = ogm_buff;
+       ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
+       ogm_packet->packet_type = BATADV_OGM2;
+       ogm_packet->version = BATADV_COMPAT_VERSION;
+       ogm_packet->ttl = BATADV_TTL;
+       ogm_packet->flags = BATADV_NO_FLAGS;
+       ogm_packet->throughput = htonl(BATADV_THROUGHPUT_MAX_VALUE);
+
+       /* randomize initial seqno to avoid collision */
+       get_random_bytes(&random_seqno, sizeof(random_seqno));
+       atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
+       INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
+
+       return 0;
+}
+
+/**
+ * batadv_v_ogm_free - free OGM private resources
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_v_ogm_free(struct batadv_priv *bat_priv)
+{
+       cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
+
+       kfree(bat_priv->bat_v.ogm_buff);
+       bat_priv->bat_v.ogm_buff = NULL;
+       bat_priv->bat_v.ogm_buff_len = 0;
+}
diff --git a/net/batman-adv/bat_v_ogm.h b/net/batman-adv/bat_v_ogm.h
new file mode 100644 (file)
index 0000000..d849c75
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2013-2016 B.A.T.M.A.N. contributors:
+ *
+ * Antonio Quartulli
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BATMAN_ADV_BATADV_V_OGM_H_
+#define _BATMAN_ADV_BATADV_V_OGM_H_
+
+#include <linux/types.h>
+
+struct batadv_hard_iface;
+struct batadv_priv;
+struct sk_buff;
+
+int batadv_v_ogm_init(struct batadv_priv *bat_priv);
+void batadv_v_ogm_free(struct batadv_priv *bat_priv);
+int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface);
+struct batadv_orig_node *batadv_v_ogm_orig_get(struct batadv_priv *bat_priv,
+                                              const u8 *addr);
+void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface);
+int batadv_v_ogm_packet_recv(struct sk_buff *skb,
+                            struct batadv_hard_iface *if_incoming);
+
+#endif /* _BATMAN_ADV_BATADV_V_OGM_H_ */
index 7781f39c174dd1fcb39a4b7efe940f7e373bcdfc..0a6c8b824a007a61077771d154462757431e810e 100644 (file)
@@ -159,12 +159,11 @@ static void batadv_backbone_gw_release(struct kref *ref)
 }
 
 /**
- * batadv_backbone_gw_free_ref - decrement the backbone gw refcounter and
- *  possibly release it
+ * batadv_backbone_gw_put - decrement the backbone gw refcounter and possibly
+ *  release it
  * @backbone_gw: backbone gateway to be free'd
  */
-static void
-batadv_backbone_gw_free_ref(struct batadv_bla_backbone_gw *backbone_gw)
+static void batadv_backbone_gw_put(struct batadv_bla_backbone_gw *backbone_gw)
 {
        kref_put(&backbone_gw->refcount, batadv_backbone_gw_release);
 }
@@ -180,16 +179,16 @@ static void batadv_claim_release(struct kref *ref)
 
        claim = container_of(ref, struct batadv_bla_claim, refcount);
 
-       batadv_backbone_gw_free_ref(claim->backbone_gw);
+       batadv_backbone_gw_put(claim->backbone_gw);
        kfree_rcu(claim, rcu);
 }
 
 /**
- * batadv_claim_free_ref - decrement the claim refcounter and possibly
+ * batadv_claim_put - decrement the claim refcounter and possibly
  *  release it
  * @claim: claim to be free'd
  */
-static void batadv_claim_free_ref(struct batadv_bla_claim *claim)
+static void batadv_claim_put(struct batadv_bla_claim *claim)
 {
        kref_put(&claim->refcount, batadv_claim_release);
 }
@@ -305,7 +304,7 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
                        if (claim->backbone_gw != backbone_gw)
                                continue;
 
-                       batadv_claim_free_ref(claim);
+                       batadv_claim_put(claim);
                        hlist_del_rcu(&claim->hash_entry);
                }
                spin_unlock_bh(list_lock);
@@ -424,7 +423,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac,
        netif_rx(skb);
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 /**
@@ -486,7 +485,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig,
        if (orig_node) {
                batadv_tt_global_del_orig(bat_priv, orig_node, vid,
                                          "became a backbone gateway");
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        }
 
        if (own_backbone) {
@@ -524,7 +523,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
                return;
 
        backbone_gw->lasttime = jiffies;
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
 }
 
 /**
@@ -573,7 +572,7 @@ static void batadv_bla_answer_request(struct batadv_priv *bat_priv,
 
        /* finally, send an announcement frame */
        batadv_bla_send_announce(bat_priv, backbone_gw);
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
 }
 
 /**
@@ -682,7 +681,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
                spin_lock_bh(&claim->backbone_gw->crc_lock);
                claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
                spin_unlock_bh(&claim->backbone_gw->crc_lock);
-               batadv_backbone_gw_free_ref(claim->backbone_gw);
+               batadv_backbone_gw_put(claim->backbone_gw);
        }
        /* set (new) backbone gw */
        kref_get(&backbone_gw->refcount);
@@ -694,7 +693,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
        backbone_gw->lasttime = jiffies;
 
 claim_free_ref:
-       batadv_claim_free_ref(claim);
+       batadv_claim_put(claim);
 }
 
 /**
@@ -719,14 +718,14 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
 
        batadv_hash_remove(bat_priv->bla.claim_hash, batadv_compare_claim,
                           batadv_choose_claim, claim);
-       batadv_claim_free_ref(claim); /* reference from the hash is gone */
+       batadv_claim_put(claim); /* reference from the hash is gone */
 
        spin_lock_bh(&claim->backbone_gw->crc_lock);
        claim->backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
        spin_unlock_bh(&claim->backbone_gw->crc_lock);
 
        /* don't need the reference from hash_find() anymore */
-       batadv_claim_free_ref(claim);
+       batadv_claim_put(claim);
 }
 
 /**
@@ -783,7 +782,7 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
                }
        }
 
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
        return 1;
 }
 
@@ -854,7 +853,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv,
                   claim_addr, BATADV_PRINT_VID(vid), backbone_gw->orig);
 
        batadv_bla_del_claim(bat_priv, claim_addr, vid);
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
        return 1;
 }
 
@@ -891,7 +890,7 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv,
 
        /* TODO: we could call something like tt_local_del() here. */
 
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
        return 1;
 }
 
@@ -965,7 +964,7 @@ static int batadv_check_claim_group(struct batadv_priv *bat_priv,
                bla_dst_own->group = bla_dst->group;
        }
 
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
 
        return 2;
 }
@@ -1154,7 +1153,7 @@ purge_now:
                        batadv_bla_del_backbone_claims(backbone_gw);
 
                        hlist_del_rcu(&backbone_gw->hash_entry);
-                       batadv_backbone_gw_free_ref(backbone_gw);
+                       batadv_backbone_gw_put(backbone_gw);
                }
                spin_unlock_bh(list_lock);
        }
@@ -1282,7 +1281,7 @@ void batadv_bla_status_update(struct net_device *net_dev)
         * so just call that one.
         */
        batadv_bla_update_orig_address(bat_priv, primary_if, primary_if);
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
 }
 
 /**
@@ -1356,7 +1355,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 
        queue_delayed_work(batadv_event_workqueue, &bat_priv->bla.work,
                           msecs_to_jiffies(BATADV_BLA_PERIOD_LENGTH));
@@ -1395,7 +1394,7 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
        if (primary_if) {
                crc = crc16(0, primary_if->net_dev->dev_addr, ETH_ALEN);
                bat_priv->bla.claim_dest.group = htons(crc);
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        } else {
                bat_priv->bla.claim_dest.group = 0; /* will be set later */
        }
@@ -1571,7 +1570,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
        if (!backbone_gw)
                return 0;
 
-       batadv_backbone_gw_free_ref(backbone_gw);
+       batadv_backbone_gw_put(backbone_gw);
        return 1;
 }
 
@@ -1599,7 +1598,7 @@ void batadv_bla_free(struct batadv_priv *bat_priv)
                bat_priv->bla.backbone_hash = NULL;
        }
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 /**
@@ -1692,9 +1691,9 @@ handled:
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (claim)
-               batadv_claim_free_ref(claim);
+               batadv_claim_put(claim);
        return ret;
 }
 
@@ -1781,9 +1780,9 @@ handled:
        ret = 1;
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (claim)
-               batadv_claim_free_ref(claim);
+               batadv_claim_put(claim);
        return ret;
 }
 
@@ -1839,7 +1838,7 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
@@ -1904,6 +1903,6 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
index e3261118130aaa1bf4ae3b1610aa8cbaa9cffcff..e96d7c745b4a1de6444284f38207ed599925ac2e 100644 (file)
@@ -77,11 +77,11 @@ static void batadv_dat_entry_release(struct kref *ref)
 }
 
 /**
- * batadv_dat_entry_free_ref - decrement the dat_entry refcounter and possibly
+ * batadv_dat_entry_put - decrement the dat_entry refcounter and possibly
  *  release it
  * @dat_entry: dat_entry to be free'd
  */
-static void batadv_dat_entry_free_ref(struct batadv_dat_entry *dat_entry)
+static void batadv_dat_entry_put(struct batadv_dat_entry *dat_entry)
 {
        kref_put(&dat_entry->refcount, batadv_dat_entry_release);
 }
@@ -135,7 +135,7 @@ static void __batadv_dat_purge(struct batadv_priv *bat_priv,
                                continue;
 
                        hlist_del_rcu(&dat_entry->hash_entry);
-                       batadv_dat_entry_free_ref(dat_entry);
+                       batadv_dat_entry_put(dat_entry);
                }
                spin_unlock_bh(list_lock);
        }
@@ -349,7 +349,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
 
        if (unlikely(hash_added != 0)) {
                /* remove the reference for the hash */
-               batadv_dat_entry_free_ref(dat_entry);
+               batadv_dat_entry_put(dat_entry);
                goto out;
        }
 
@@ -358,7 +358,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
 
 out:
        if (dat_entry)
-               batadv_dat_entry_free_ref(dat_entry);
+               batadv_dat_entry_put(dat_entry);
 }
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
@@ -547,7 +547,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
 
                        max = tmp_max;
                        if (max_orig_node)
-                               batadv_orig_node_free_ref(max_orig_node);
+                               batadv_orig_node_put(max_orig_node);
                        max_orig_node = orig_node;
                }
                rcu_read_unlock();
@@ -654,9 +654,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
                        goto free_neigh;
                }
 
-               send_status = batadv_send_skb_packet(tmp_skb,
-                                                    neigh_node->if_incoming,
-                                                    neigh_node->addr);
+               send_status = batadv_send_unicast_skb(tmp_skb, neigh_node);
                if (send_status == NET_XMIT_SUCCESS) {
                        /* count the sent packet */
                        switch (packet_subtype) {
@@ -674,9 +672,9 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
                        ret = true;
                }
 free_neigh:
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
 free_orig:
-               batadv_orig_node_free_ref(cand[i].orig_node);
+               batadv_orig_node_put(cand[i].orig_node);
        }
 
 out:
@@ -840,7 +838,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
@@ -1029,7 +1027,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
        }
 out:
        if (dat_entry)
-               batadv_dat_entry_free_ref(dat_entry);
+               batadv_dat_entry_put(dat_entry);
        return ret;
 }
 
@@ -1109,7 +1107,7 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
        }
 out:
        if (dat_entry)
-               batadv_dat_entry_free_ref(dat_entry);
+               batadv_dat_entry_put(dat_entry);
        if (ret)
                kfree_skb(skb);
        return ret;
@@ -1262,6 +1260,6 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 
 out:
        if (dat_entry)
-               batadv_dat_entry_free_ref(dat_entry);
+               batadv_dat_entry_put(dat_entry);
        return ret;
 }
index 55656e84bc7e1a143615ad097ea5a492e2451474..e6956d0746a20f91c51d256c231ddfe4f2626c26 100644 (file)
@@ -378,16 +378,15 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb,
                                   skb->len + ETH_HLEN);
 
                packet->ttl--;
-               batadv_send_skb_packet(skb, neigh_node->if_incoming,
-                                      neigh_node->addr);
+               batadv_send_unicast_skb(skb, neigh_node);
                ret = true;
        }
 
 out:
        if (orig_node_dst)
-               batadv_orig_node_free_ref(orig_node_dst);
+               batadv_orig_node_put(orig_node_dst);
        if (neigh_node)
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
        return ret;
 }
 
@@ -486,8 +485,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
                batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
                batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
                                   skb_fragment->len + ETH_HLEN);
-               batadv_send_skb_packet(skb_fragment, neigh_node->if_incoming,
-                                      neigh_node->addr);
+               batadv_send_unicast_skb(skb_fragment, neigh_node);
                frag_header.no++;
 
                /* The initial check in this function should cover this case */
@@ -506,13 +504,13 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
        batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
        batadv_add_counter(bat_priv, BATADV_CNT_FRAG_TX_BYTES,
                           skb->len + ETH_HLEN);
-       batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+       batadv_send_unicast_skb(skb, neigh_node);
 
        ret = true;
 
 out_err:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 
        return ret;
 }
index 261866e38502bbe45044b330a5984eb997349568..c59aff5ccac8a63f191a669eafcfdba7a270fd75 100644 (file)
@@ -71,16 +71,15 @@ static void batadv_gw_node_release(struct kref *ref)
 
        gw_node = container_of(ref, struct batadv_gw_node, refcount);
 
-       batadv_orig_node_free_ref(gw_node->orig_node);
+       batadv_orig_node_put(gw_node->orig_node);
        kfree_rcu(gw_node, rcu);
 }
 
 /**
- * batadv_gw_node_free_ref - decrement the gw_node refcounter and possibly
- *  release it
+ * batadv_gw_node_put - decrement the gw_node refcounter and possibly release it
  * @gw_node: gateway node to free
  */
-static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
+static void batadv_gw_node_put(struct batadv_gw_node *gw_node)
 {
        kref_put(&gw_node->refcount, batadv_gw_node_release);
 }
@@ -125,7 +124,7 @@ unlock:
        rcu_read_unlock();
 out:
        if (gw_node)
-               batadv_gw_node_free_ref(gw_node);
+               batadv_gw_node_put(gw_node);
        return orig_node;
 }
 
@@ -143,7 +142,7 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
        rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node);
 
        if (curr_gw_node)
-               batadv_gw_node_free_ref(curr_gw_node);
+               batadv_gw_node_put(curr_gw_node);
 
        spin_unlock_bh(&bat_priv->gw.list_lock);
 }
@@ -204,7 +203,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
                            ((tmp_gw_factor == max_gw_factor) &&
                             (tq_avg > max_tq))) {
                                if (curr_gw)
-                                       batadv_gw_node_free_ref(curr_gw);
+                                       batadv_gw_node_put(curr_gw);
                                curr_gw = gw_node;
                                kref_get(&curr_gw->refcount);
                        }
@@ -219,7 +218,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
                          */
                        if (tq_avg > max_tq) {
                                if (curr_gw)
-                                       batadv_gw_node_free_ref(curr_gw);
+                                       batadv_gw_node_put(curr_gw);
                                curr_gw = gw_node;
                                kref_get(&curr_gw->refcount);
                        }
@@ -232,12 +231,12 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
                if (tmp_gw_factor > max_gw_factor)
                        max_gw_factor = tmp_gw_factor;
 
-               batadv_gw_node_free_ref(gw_node);
+               batadv_gw_node_put(gw_node);
 
 next:
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
                if (router_ifinfo)
-                       batadv_neigh_ifinfo_free_ref(router_ifinfo);
+                       batadv_neigh_ifinfo_put(router_ifinfo);
        }
        rcu_read_unlock();
 
@@ -273,7 +272,7 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
         */
        batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL, NULL);
 
-       batadv_gw_node_free_ref(curr_gw);
+       batadv_gw_node_put(curr_gw);
 }
 
 void batadv_gw_election(struct batadv_priv *bat_priv)
@@ -348,13 +347,13 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
 
 out:
        if (curr_gw)
-               batadv_gw_node_free_ref(curr_gw);
+               batadv_gw_node_put(curr_gw);
        if (next_gw)
-               batadv_gw_node_free_ref(next_gw);
+               batadv_gw_node_put(next_gw);
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
        if (router_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_ifinfo);
+               batadv_neigh_ifinfo_put(router_ifinfo);
 }
 
 void batadv_gw_check_election(struct batadv_priv *bat_priv,
@@ -415,15 +414,15 @@ reselect:
        batadv_gw_reselect(bat_priv);
 out:
        if (curr_gw_orig)
-               batadv_orig_node_free_ref(curr_gw_orig);
+               batadv_orig_node_put(curr_gw_orig);
        if (router_gw)
-               batadv_neigh_node_free_ref(router_gw);
+               batadv_neigh_node_put(router_gw);
        if (router_orig)
-               batadv_neigh_node_free_ref(router_orig);
+               batadv_neigh_node_put(router_orig);
        if (router_gw_tq)
-               batadv_neigh_ifinfo_free_ref(router_gw_tq);
+               batadv_neigh_ifinfo_put(router_gw_tq);
        if (router_orig_tq)
-               batadv_neigh_ifinfo_free_ref(router_orig_tq);
+               batadv_neigh_ifinfo_put(router_orig_tq);
 }
 
 /**
@@ -446,7 +445,7 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 
        gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
        if (!gw_node) {
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
                return;
        }
 
@@ -545,22 +544,23 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
                 * gets dereferenced.
                 */
                spin_lock_bh(&bat_priv->gw.list_lock);
-               hlist_del_init_rcu(&gw_node->list);
+               if (!hlist_unhashed(&gw_node->list)) {
+                       hlist_del_init_rcu(&gw_node->list);
+                       batadv_gw_node_put(gw_node);
+               }
                spin_unlock_bh(&bat_priv->gw.list_lock);
 
-               batadv_gw_node_free_ref(gw_node);
-
                curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
                if (gw_node == curr_gw)
                        batadv_gw_reselect(bat_priv);
 
                if (curr_gw)
-                       batadv_gw_node_free_ref(curr_gw);
+                       batadv_gw_node_put(curr_gw);
        }
 
 out:
        if (gw_node)
-               batadv_gw_node_free_ref(gw_node);
+               batadv_gw_node_put(gw_node);
 }
 
 void batadv_gw_node_delete(struct batadv_priv *bat_priv,
@@ -583,7 +583,7 @@ void batadv_gw_node_free(struct batadv_priv *bat_priv)
        hlist_for_each_entry_safe(gw_node, node_tmp,
                                  &bat_priv->gw.list, list) {
                hlist_del_init_rcu(&gw_node->list);
-               batadv_gw_node_free_ref(gw_node);
+               batadv_gw_node_put(gw_node);
        }
        spin_unlock_bh(&bat_priv->gw.list_lock);
 }
@@ -620,12 +620,12 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
        ret = seq_has_overflowed(seq) ? -1 : 0;
 
        if (curr_gw)
-               batadv_gw_node_free_ref(curr_gw);
+               batadv_gw_node_put(curr_gw);
 out:
        if (router_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_ifinfo);
+               batadv_neigh_ifinfo_put(router_ifinfo);
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
        return ret;
 }
 
@@ -662,7 +662,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
@@ -856,7 +856,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
                        goto out;
 
                curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
-               batadv_neigh_ifinfo_free_ref(curr_ifinfo);
+               batadv_neigh_ifinfo_put(curr_ifinfo);
 
                break;
        case BATADV_GW_MODE_OFF:
@@ -874,18 +874,18 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 
        if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
                out_of_range = true;
-       batadv_neigh_ifinfo_free_ref(old_ifinfo);
+       batadv_neigh_ifinfo_put(old_ifinfo);
 
 out:
        if (orig_dst_node)
-               batadv_orig_node_free_ref(orig_dst_node);
+               batadv_orig_node_put(orig_dst_node);
        if (curr_gw)
-               batadv_gw_node_free_ref(curr_gw);
+               batadv_gw_node_put(curr_gw);
        if (gw_node)
-               batadv_gw_node_free_ref(gw_node);
+               batadv_gw_node_put(gw_node);
        if (neigh_old)
-               batadv_neigh_node_free_ref(neigh_old);
+               batadv_neigh_node_put(neigh_old);
        if (neigh_curr)
-               batadv_neigh_node_free_ref(neigh_curr);
+               batadv_neigh_node_put(neigh_curr);
        return out_of_range;
 }
index 5ee04f7140af7bf9d459488b8c886d8df8873cd3..4423047889e1e6483d62602ff4d9334a6516b908 100644 (file)
@@ -40,8 +40,8 @@
  *
  * Return: false on parse error and true otherwise.
  */
-static bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
-                                   const char *description, u32 *throughput)
+bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
+                            const char *description, u32 *throughput)
 {
        enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
        u64 lthroughput;
index b58346350024dbe3eab5f365d3a59073953b59a3..8a5e1ddf1175ccb3f8e20169d9bd584e0327df86 100644 (file)
@@ -49,5 +49,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
 void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv);
 void batadv_gw_init(struct batadv_priv *bat_priv);
 void batadv_gw_free(struct batadv_priv *bat_priv);
+bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
+                            const char *description, u32 *throughput);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
index fb2d9c058ed047255ab8a1fc605d1bcb9591d60a..b22b2775a0a5ff706c17ea06c39c9bb092da1f9a 100644 (file)
@@ -83,6 +83,28 @@ out:
        return hard_iface;
 }
 
+/**
+ * batadv_mutual_parents - check if two devices are each others parent
+ * @dev1: 1st net_device
+ * @dev2: 2nd net_device
+ *
+ * veth devices come in pairs and each is the parent of the other!
+ *
+ * Return: true if the devices are each others parent, otherwise false
+ */
+static bool batadv_mutual_parents(const struct net_device *dev1,
+                                 const struct net_device *dev2)
+{
+       int dev1_parent_iflink = dev_get_iflink(dev1);
+       int dev2_parent_iflink = dev_get_iflink(dev2);
+
+       if (!dev1_parent_iflink || !dev2_parent_iflink)
+               return false;
+
+       return (dev1_parent_iflink == dev2->ifindex) &&
+              (dev2_parent_iflink == dev1->ifindex);
+}
+
 /**
  * batadv_is_on_batman_iface - check if a device is a batman iface descendant
  * @net_dev: the device to check
@@ -116,6 +138,9 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
        if (WARN(!parent_dev, "Cannot find parent device"))
                return false;
 
+       if (batadv_mutual_parents(net_dev, parent_dev))
+               return false;
+
        ret = batadv_is_on_batman_iface(parent_dev);
 
        return ret;
@@ -201,7 +226,7 @@ static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
        batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 static void batadv_primary_if_select(struct batadv_priv *bat_priv,
@@ -225,7 +250,7 @@ static void batadv_primary_if_select(struct batadv_priv *bat_priv,
 
 out:
        if (curr_hard_iface)
-               batadv_hardif_free_ref(curr_hard_iface);
+               batadv_hardif_put(curr_hard_iface);
 }
 
 static bool
@@ -384,7 +409,7 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 static void
@@ -537,7 +562,7 @@ err_dev:
        hard_iface->soft_iface = NULL;
        dev_put(soft_iface);
 err:
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
        return ret;
 }
 
@@ -568,7 +593,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
                batadv_primary_if_select(bat_priv, new_if);
 
                if (new_if)
-                       batadv_hardif_free_ref(new_if);
+                       batadv_hardif_put(new_if);
        }
 
        bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
@@ -591,11 +616,11 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
        }
 
        hard_iface->soft_iface = NULL;
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 /**
@@ -614,7 +639,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work)
 
        batadv_debugfs_del_hardif(hard_iface);
        batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
 }
 
 static struct batadv_hard_iface *
@@ -769,10 +794,10 @@ static int batadv_hard_if_event(struct notifier_block *this,
        }
 
 hardif_put:
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return NOTIFY_DONE;
 }
 
index 5cecc6bc1b1ec2493bc866bd93d35cbd09a88331..d74f1983f33e1d430dbc332da510f6d24247aab7 100644 (file)
@@ -64,11 +64,11 @@ void batadv_update_min_mtu(struct net_device *soft_iface);
 void batadv_hardif_release(struct kref *ref);
 
 /**
- * batadv_hardif_free_ref - decrement the hard interface refcounter and possibly
+ * batadv_hardif_put - decrement the hard interface refcounter and possibly
  *  release it
  * @hard_iface: the hard interface to free
  */
-static inline void batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
+static inline void batadv_hardif_put(struct batadv_hard_iface *hard_iface)
 {
        kref_put(&hard_iface->refcount, batadv_hardif_release);
 }
index a69da37bbad57dbcfc01d75406d0011ea83ec805..14d0013b387ed4cfbf797884857414ae8bf0e7f7 100644 (file)
@@ -278,7 +278,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
 
        ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
 
-       batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
+       batadv_send_unicast_skb(skb, neigh_node);
        goto out;
 
 dst_unreach:
@@ -288,11 +288,11 @@ free_skb:
        kfree_skb(skb);
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (neigh_node)
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return len;
 }
 
index 568c5503f63765e74bcd2f3f060d3770602ba646..d64ddb961979ae083ba99907b07fc090a3dfe775 100644 (file)
@@ -87,6 +87,7 @@ static int __init batadv_init(void)
 
        batadv_recv_handler_init();
 
+       batadv_v_init();
        batadv_iv_init();
        batadv_nc_init();
 
@@ -159,6 +160,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
        INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
        INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
 
+       ret = batadv_v_mesh_init(bat_priv);
+       if (ret < 0)
+               goto err;
+
        ret = batadv_originator_init(bat_priv);
        if (ret < 0)
                goto err;
@@ -201,6 +206,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
        batadv_purge_outstanding_packets(bat_priv, NULL);
 
        batadv_gw_node_free(bat_priv);
+
+       batadv_v_mesh_free(bat_priv);
        batadv_nc_mesh_free(bat_priv);
        batadv_dat_free(bat_priv);
        batadv_bla_free(bat_priv);
@@ -287,7 +294,7 @@ batadv_seq_print_text_primary_if_get(struct seq_file *seq)
        seq_printf(seq,
                   "BATMAN mesh %s disabled - primary interface not active\n",
                   net_dev->name);
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
        primary_if = NULL;
 
 out:
@@ -638,12 +645,11 @@ static void batadv_tvlv_handler_release(struct kref *ref)
 }
 
 /**
- * batadv_tvlv_handler_free_ref - decrement the tvlv container refcounter and
+ * batadv_tvlv_handler_put - decrement the tvlv container refcounter and
  *  possibly release it
  * @tvlv_handler: the tvlv handler to free
  */
-static void
-batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler)
+static void batadv_tvlv_handler_put(struct batadv_tvlv_handler *tvlv_handler)
 {
        kref_put(&tvlv_handler->refcount, batadv_tvlv_handler_release);
 }
@@ -695,11 +701,11 @@ static void batadv_tvlv_container_release(struct kref *ref)
 }
 
 /**
- * batadv_tvlv_container_free_ref - decrement the tvlv container refcounter and
+ * batadv_tvlv_container_put - decrement the tvlv container refcounter and
  *  possibly release it
  * @tvlv: the tvlv container to free
  */
-static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv)
+static void batadv_tvlv_container_put(struct batadv_tvlv_container *tvlv)
 {
        kref_put(&tvlv->refcount, batadv_tvlv_container_release);
 }
@@ -785,8 +791,8 @@ static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv,
        hlist_del(&tvlv->list);
 
        /* first call to decrement the counter, second call to free */
-       batadv_tvlv_container_free_ref(tvlv);
-       batadv_tvlv_container_free_ref(tvlv);
+       batadv_tvlv_container_put(tvlv);
+       batadv_tvlv_container_put(tvlv);
 }
 
 /**
@@ -1031,7 +1037,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
                                                src, dst, tvlv_value,
                                                tvlv_value_cont_len);
                if (tvlv_handler)
-                       batadv_tvlv_handler_free_ref(tvlv_handler);
+                       batadv_tvlv_handler_put(tvlv_handler);
                tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
                tvlv_value_len -= tvlv_value_cont_len;
        }
@@ -1111,7 +1117,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv,
 
        tvlv_handler = batadv_tvlv_handler_get(bat_priv, type, version);
        if (tvlv_handler) {
-               batadv_tvlv_handler_free_ref(tvlv_handler);
+               batadv_tvlv_handler_put(tvlv_handler);
                return;
        }
 
@@ -1148,11 +1154,11 @@ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv,
        if (!tvlv_handler)
                return;
 
-       batadv_tvlv_handler_free_ref(tvlv_handler);
+       batadv_tvlv_handler_put(tvlv_handler);
        spin_lock_bh(&bat_priv->tvlv.handler_list_lock);
        hlist_del_rcu(&tvlv_handler->list);
        spin_unlock_bh(&bat_priv->tvlv.handler_list_lock);
-       batadv_tvlv_handler_free_ref(tvlv_handler);
+       batadv_tvlv_handler_put(tvlv_handler);
 }
 
 /**
@@ -1212,7 +1218,7 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src,
        if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
                kfree_skb(skb);
 out:
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
 }
 
 /**
@@ -1262,7 +1268,7 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
        vlan = batadv_softif_vlan_get(bat_priv, vid);
        if (vlan) {
                ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
-               batadv_softif_vlan_free_ref(vlan);
+               batadv_softif_vlan_put(vlan);
        }
 
        return ap_isolation_enabled;
index 32dfc9e578af6344b79cb0a48d516203a04d60b7..db453363183445843c7fd210ed3bd0d9cbd9dd1f 100644 (file)
 #define BATADV_DRIVER_DEVICE "batman-adv"
 
 #ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2016.0"
+#define BATADV_SOURCE_VERSION "2016.1"
 #endif
 
 /* B.A.T.M.A.N. parameters */
 
 #define BATADV_TQ_MAX_VALUE 255
+#define BATADV_THROUGHPUT_MAX_VALUE 0xFFFFFFFF
 #define BATADV_JITTER 20
 
 /* Time To Live of broadcast messages */
 #define BATADV_TQ_LOCAL_BIDRECT_RECV_MINIMUM 1
 #define BATADV_TQ_TOTAL_BIDRECT_LIMIT 1
 
+/* B.A.T.M.A.N. V */
+#define BATADV_THROUGHPUT_DEFAULT_VALUE 10 /* 1 Mbps */
+#define BATADV_ELP_PROBES_PER_NODE 2
+#define BATADV_ELP_MIN_PROBE_SIZE 200 /* bytes */
+#define BATADV_ELP_PROBE_MAX_TX_DIFF 100 /* milliseconds */
+#define BATADV_ELP_MAX_AGE 64
+#define BATADV_OGM_MAX_ORIGDIFF 5
+#define BATADV_OGM_MAX_AGE 64
+
 /* number of OGMs sent with the last tt diff */
 #define BATADV_TT_OGM_APPEND_MAX 3
 
  */
 #define BATADV_TQ_SIMILARITY_THRESHOLD 50
 
-/* how much worse secondary interfaces may be to be considered as bonding
- * candidates
- */
-#define BATADV_BONDING_TQ_THRESHOLD    50
-
 /* should not be bigger than 512 bytes or change the size of
  * forw_packet->direct_link_flags
  */
index a4eb8ee4abb1710378162d4d89682ef8d03d05d5..b41719b6487a40cd8571461b8eec03a60c7f4cfe 100644 (file)
@@ -218,16 +218,16 @@ static void batadv_nc_node_release(struct kref *ref)
 
        nc_node = container_of(ref, struct batadv_nc_node, refcount);
 
-       batadv_orig_node_free_ref(nc_node->orig_node);
+       batadv_orig_node_put(nc_node->orig_node);
        kfree_rcu(nc_node, rcu);
 }
 
 /**
- * batadv_nc_node_free_ref - decrement the nc_node refcounter and possibly
+ * batadv_nc_node_put - decrement the nc_node refcounter and possibly
  *  release it
  * @nc_node: nc_node to be free'd
  */
-static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node)
+static void batadv_nc_node_put(struct batadv_nc_node *nc_node)
 {
        kref_put(&nc_node->refcount, batadv_nc_node_release);
 }
@@ -247,11 +247,11 @@ static void batadv_nc_path_release(struct kref *ref)
 }
 
 /**
- * batadv_nc_path_free_ref - decrement the nc_path refcounter and possibly
+ * batadv_nc_path_put - decrement the nc_path refcounter and possibly
  *  release it
  * @nc_path: nc_path to be free'd
  */
-static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path)
+static void batadv_nc_path_put(struct batadv_nc_path *nc_path)
 {
        kref_put(&nc_path->refcount, batadv_nc_path_release);
 }
@@ -263,7 +263,7 @@ static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path)
 static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet)
 {
        kfree_skb(nc_packet->skb);
-       batadv_nc_path_free_ref(nc_packet->nc_path);
+       batadv_nc_path_put(nc_packet->nc_path);
        kfree(nc_packet);
 }
 
@@ -356,7 +356,7 @@ batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
                           "Removing nc_node %pM -> %pM\n",
                           nc_node->addr, nc_node->orig_node->orig);
                list_del_rcu(&nc_node->list);
-               batadv_nc_node_free_ref(nc_node);
+               batadv_nc_node_put(nc_node);
        }
        spin_unlock_bh(lock);
 }
@@ -467,7 +467,7 @@ static void batadv_nc_purge_paths(struct batadv_priv *bat_priv,
                                   "Remove nc_path %pM -> %pM\n",
                                   nc_path->prev_hop, nc_path->next_hop);
                        hlist_del_rcu(&nc_path->hash_entry);
-                       batadv_nc_path_free_ref(nc_path);
+                       batadv_nc_path_put(nc_path);
                }
                spin_unlock_bh(lock);
        }
@@ -575,9 +575,7 @@ batadv_nc_hash_find(struct batadv_hashtable *hash,
  */
 static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
 {
-       batadv_send_skb_packet(nc_packet->skb,
-                              nc_packet->neigh_node->if_incoming,
-                              nc_packet->nc_path->next_hop);
+       batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
        nc_packet->skb = NULL;
        batadv_nc_packet_free(nc_packet);
 }
@@ -772,7 +770,7 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
 
        last_ttl = orig_ifinfo->last_ttl;
        last_real_seqno = orig_ifinfo->last_real_seqno;
-       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+       batadv_orig_ifinfo_put(orig_ifinfo);
 
        if (last_real_seqno != ntohl(ogm_packet->seqno))
                return false;
@@ -942,9 +940,9 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
 
 out:
        if (in_nc_node)
-               batadv_nc_node_free_ref(in_nc_node);
+               batadv_nc_node_put(in_nc_node);
        if (out_nc_node)
-               batadv_nc_node_free_ref(out_nc_node);
+               batadv_nc_node_put(out_nc_node);
 }
 
 /**
@@ -1067,11 +1065,11 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        struct batadv_unicast_packet *packet1;
        struct batadv_unicast_packet *packet2;
        struct batadv_coded_packet *coded_packet;
-       struct batadv_neigh_node *neigh_tmp, *router_neigh;
-       struct batadv_neigh_node *router_coding = NULL;
+       struct batadv_neigh_node *neigh_tmp, *router_neigh, *first_dest;
+       struct batadv_neigh_node *router_coding = NULL, *second_dest;
        struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
        struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
-       u8 *first_source, *first_dest, *second_source, *second_dest;
+       u8 *first_source, *second_source;
        __be32 packet_id1, packet_id2;
        size_t count;
        bool res = false;
@@ -1114,9 +1112,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
         */
        if (tq_weighted_neigh >= tq_weighted_coding) {
                /* Destination from nc_packet is selected for MAC-header */
-               first_dest = nc_packet->nc_path->next_hop;
+               first_dest = nc_packet->neigh_node;
                first_source = nc_packet->nc_path->prev_hop;
-               second_dest = neigh_node->addr;
+               second_dest = neigh_node;
                second_source = ethhdr->h_source;
                packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
                packet2 = (struct batadv_unicast_packet *)skb->data;
@@ -1125,9 +1123,9 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
                                              skb->data + sizeof(*packet2));
        } else {
                /* Destination for skb is selected for MAC-header */
-               first_dest = neigh_node->addr;
+               first_dest = neigh_node;
                first_source = ethhdr->h_source;
-               second_dest = nc_packet->nc_path->next_hop;
+               second_dest = nc_packet->neigh_node;
                second_source = nc_packet->nc_path->prev_hop;
                packet1 = (struct batadv_unicast_packet *)skb->data;
                packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
@@ -1169,7 +1167,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        coded_packet->first_ttvn = packet1->ttvn;
 
        /* Info about second unicast packet */
-       ether_addr_copy(coded_packet->second_dest, second_dest);
+       ether_addr_copy(coded_packet->second_dest, second_dest->addr);
        ether_addr_copy(coded_packet->second_source, second_source);
        ether_addr_copy(coded_packet->second_orig_dest, packet2->dest);
        coded_packet->second_crc = packet_id2;
@@ -1224,17 +1222,17 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        batadv_nc_packet_free(nc_packet);
 
        /* Send the coded packet and return true */
-       batadv_send_skb_packet(skb_dest, neigh_node->if_incoming, first_dest);
+       batadv_send_unicast_skb(skb_dest, first_dest);
        res = true;
 out:
        if (router_neigh)
-               batadv_neigh_node_free_ref(router_neigh);
+               batadv_neigh_node_put(router_neigh);
        if (router_coding)
-               batadv_neigh_node_free_ref(router_coding);
+               batadv_neigh_node_put(router_coding);
        if (router_neigh_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo);
+               batadv_neigh_ifinfo_put(router_neigh_ifinfo);
        if (router_coding_ifinfo)
-               batadv_neigh_ifinfo_free_ref(router_coding_ifinfo);
+               batadv_neigh_ifinfo_put(router_coding_ifinfo);
        return res;
 }
 
@@ -1372,7 +1370,7 @@ batadv_nc_skb_src_search(struct batadv_priv *bat_priv,
        }
        rcu_read_unlock();
 
-       batadv_orig_node_free_ref(orig_node);
+       batadv_orig_node_put(orig_node);
        return nc_packet;
 }
 
@@ -1555,7 +1553,7 @@ bool batadv_nc_skb_forward(struct sk_buff *skb,
        return true;
 
 free_nc_path:
-       batadv_nc_path_free_ref(nc_path);
+       batadv_nc_path_put(nc_path);
 out:
        /* Packet is not consumed */
        return false;
@@ -1617,7 +1615,7 @@ void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
 free_skb:
        kfree_skb(skb);
 free_nc_path:
-       batadv_nc_path_free_ref(nc_path);
+       batadv_nc_path_put(nc_path);
 out:
        return;
 }
@@ -1950,7 +1948,7 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
index eacd0e5a02381e2dfe53106b0ed76878888805d5..e4cbb0753e37ff6681a20e8912df1f4ad1e74a05 100644 (file)
@@ -151,11 +151,11 @@ static void batadv_orig_node_vlan_release(struct kref *ref)
 }
 
 /**
- * batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly
- *  release the originator-vlan object
+ * batadv_orig_node_vlan_put - decrement the refcounter and possibly release
+ *  the originator-vlan object
  * @orig_vlan: the originator-vlan object to release
  */
-void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan)
+void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan)
 {
        kref_put(&orig_vlan->refcount, batadv_orig_node_vlan_release);
 }
@@ -196,17 +196,17 @@ static void batadv_neigh_ifinfo_release(struct kref *ref)
        neigh_ifinfo = container_of(ref, struct batadv_neigh_ifinfo, refcount);
 
        if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
-               batadv_hardif_free_ref(neigh_ifinfo->if_outgoing);
+               batadv_hardif_put(neigh_ifinfo->if_outgoing);
 
        kfree_rcu(neigh_ifinfo, rcu);
 }
 
 /**
- * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly release
+ * batadv_neigh_ifinfo_put - decrement the refcounter and possibly release
  *  the neigh_ifinfo
  * @neigh_ifinfo: the neigh_ifinfo object to release
  */
-void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
+void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo)
 {
        kref_put(&neigh_ifinfo->refcount, batadv_neigh_ifinfo_release);
 }
@@ -227,16 +227,16 @@ static void batadv_hardif_neigh_release(struct kref *ref)
        hlist_del_init_rcu(&hardif_neigh->list);
        spin_unlock_bh(&hardif_neigh->if_incoming->neigh_list_lock);
 
-       batadv_hardif_free_ref(hardif_neigh->if_incoming);
+       batadv_hardif_put(hardif_neigh->if_incoming);
        kfree_rcu(hardif_neigh, rcu);
 }
 
 /**
- * batadv_hardif_neigh_free_ref - decrement the hardif neighbors refcounter
+ * batadv_hardif_neigh_put - decrement the hardif neighbors refcounter
  *  and possibly release it
  * @hardif_neigh: hardif neigh neighbor to free
  */
-void batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh)
+void batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh)
 {
        kref_put(&hardif_neigh->refcount, batadv_hardif_neigh_release);
 }
@@ -259,31 +259,31 @@ static void batadv_neigh_node_release(struct kref *ref)
 
        hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
                                  &neigh_node->ifinfo_list, list) {
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
        }
 
        hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming,
                                               neigh_node->addr);
        if (hardif_neigh) {
                /* batadv_hardif_neigh_get() increases refcount too */
-               batadv_hardif_neigh_free_ref(hardif_neigh);
-               batadv_hardif_neigh_free_ref(hardif_neigh);
+               batadv_hardif_neigh_put(hardif_neigh);
+               batadv_hardif_neigh_put(hardif_neigh);
        }
 
        if (bao->bat_neigh_free)
                bao->bat_neigh_free(neigh_node);
 
-       batadv_hardif_free_ref(neigh_node->if_incoming);
+       batadv_hardif_put(neigh_node->if_incoming);
 
        kfree_rcu(neigh_node, rcu);
 }
 
 /**
- * batadv_neigh_node_free_ref - decrement the neighbors refcounter and possibly
+ * batadv_neigh_node_put - decrement the neighbors refcounter and possibly
  *  release it
  * @neigh_node: neigh neighbor to free
  */
-void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
+void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node)
 {
        kref_put(&neigh_node->refcount, batadv_neigh_node_release);
 }
@@ -544,7 +544,7 @@ batadv_hardif_neigh_create(struct batadv_hard_iface *hard_iface,
 
        hardif_neigh = kzalloc(sizeof(*hardif_neigh), GFP_ATOMIC);
        if (!hardif_neigh) {
-               batadv_hardif_free_ref(hard_iface);
+               batadv_hardif_put(hard_iface);
                goto out;
        }
 
@@ -681,7 +681,7 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
 
 out:
        if (hardif_neigh)
-               batadv_hardif_neigh_free_ref(hardif_neigh);
+               batadv_hardif_neigh_put(hardif_neigh);
        return neigh_node;
 }
 
@@ -707,7 +707,7 @@ int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset)
                   primary_if->net_dev->dev_addr, net_dev->name,
                   bat_priv->bat_algo_ops->name);
 
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
 
        if (!bat_priv->bat_algo_ops->bat_neigh_print) {
                seq_puts(seq,
@@ -732,22 +732,22 @@ static void batadv_orig_ifinfo_release(struct kref *ref)
        orig_ifinfo = container_of(ref, struct batadv_orig_ifinfo, refcount);
 
        if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
-               batadv_hardif_free_ref(orig_ifinfo->if_outgoing);
+               batadv_hardif_put(orig_ifinfo->if_outgoing);
 
        /* this is the last reference to this object */
        router = rcu_dereference_protected(orig_ifinfo->router, true);
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 
        kfree_rcu(orig_ifinfo, rcu);
 }
 
 /**
- * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly release
+ * batadv_orig_ifinfo_put - decrement the refcounter and possibly release
  *  the orig_ifinfo
  * @orig_ifinfo: the orig_ifinfo object to release
  */
-void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
+void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo)
 {
        kref_put(&orig_ifinfo->refcount, batadv_orig_ifinfo_release);
 }
@@ -793,13 +793,13 @@ static void batadv_orig_node_release(struct kref *ref)
        hlist_for_each_entry_safe(neigh_node, node_tmp,
                                  &orig_node->neigh_list, list) {
                hlist_del_rcu(&neigh_node->list);
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
        }
 
        hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
                                  &orig_node->ifinfo_list, list) {
                hlist_del_rcu(&orig_ifinfo->list);
-               batadv_orig_ifinfo_free_ref(orig_ifinfo);
+               batadv_orig_ifinfo_put(orig_ifinfo);
        }
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
@@ -810,11 +810,11 @@ static void batadv_orig_node_release(struct kref *ref)
 }
 
 /**
- * batadv_orig_node_free_ref - decrement the orig node refcounter and possibly
+ * batadv_orig_node_put - decrement the orig node refcounter and possibly
  *  release it
  * @orig_node: the orig node to free
  */
-void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node)
+void batadv_orig_node_put(struct batadv_orig_node *orig_node)
 {
        kref_put(&orig_node->refcount, batadv_orig_node_release);
 }
@@ -843,7 +843,7 @@ void batadv_originator_free(struct batadv_priv *bat_priv)
                hlist_for_each_entry_safe(orig_node, node_tmp,
                                          head, hash_entry) {
                        hlist_del_rcu(&orig_node->hash_entry);
-                       batadv_orig_node_free_ref(orig_node);
+                       batadv_orig_node_put(orig_node);
                }
                spin_unlock_bh(list_lock);
        }
@@ -917,7 +917,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
         * Immediately release vlan since it is not needed anymore in this
         * context
         */
-       batadv_orig_node_vlan_free_ref(vlan);
+       batadv_orig_node_vlan_put(vlan);
 
        for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) {
                INIT_HLIST_HEAD(&orig_node->fragments[i].head);
@@ -966,7 +966,7 @@ batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv,
                           neigh->addr, if_outgoing->net_dev->name);
 
                hlist_del_rcu(&neigh_ifinfo->list);
-               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               batadv_neigh_ifinfo_put(neigh_ifinfo);
        }
 
        spin_unlock_bh(&neigh->ifinfo_lock);
@@ -1012,10 +1012,10 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
                ifinfo_purged = true;
 
                hlist_del_rcu(&orig_ifinfo->list);
-               batadv_orig_ifinfo_free_ref(orig_ifinfo);
+               batadv_orig_ifinfo_put(orig_ifinfo);
                if (orig_node->last_bonding_candidate == orig_ifinfo) {
                        orig_node->last_bonding_candidate = NULL;
-                       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+                       batadv_orig_ifinfo_put(orig_ifinfo);
                }
        }
 
@@ -1069,7 +1069,7 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
                        neigh_purged = true;
 
                        hlist_del_rcu(&neigh_node->list);
-                       batadv_neigh_node_free_ref(neigh_node);
+                       batadv_neigh_node_put(neigh_node);
                } else {
                        /* only necessary if not the whole neighbor is to be
                         * deleted, but some interface has been removed.
@@ -1108,7 +1108,7 @@ batadv_find_best_neighbor(struct batadv_priv *bat_priv,
                        continue;
 
                if (best)
-                       batadv_neigh_node_free_ref(best);
+                       batadv_neigh_node_put(best);
 
                best = neigh;
        }
@@ -1154,7 +1154,7 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
        batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
                            best_neigh_node);
        if (best_neigh_node)
-               batadv_neigh_node_free_ref(best_neigh_node);
+               batadv_neigh_node_put(best_neigh_node);
 
        /* ... then for all other interfaces. */
        rcu_read_lock();
@@ -1171,7 +1171,7 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                batadv_update_route(bat_priv, orig_node, hard_iface,
                                    best_neigh_node);
                if (best_neigh_node)
-                       batadv_neigh_node_free_ref(best_neigh_node);
+                       batadv_neigh_node_put(best_neigh_node);
        }
        rcu_read_unlock();
 
@@ -1204,7 +1204,7 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
                                batadv_tt_global_del_orig(orig_node->bat_priv,
                                                          orig_node, -1,
                                                          "originator timed out");
-                               batadv_orig_node_free_ref(orig_node);
+                               batadv_orig_node_put(orig_node);
                                continue;
                        }
 
@@ -1250,7 +1250,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
                   primary_if->net_dev->dev_addr, net_dev->name,
                   bat_priv->bat_algo_ops->name);
 
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
 
        if (!bat_priv->bat_algo_ops->bat_orig_print) {
                seq_puts(seq,
@@ -1306,7 +1306,7 @@ int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
 
 out:
        if (hard_iface)
-               batadv_hardif_free_ref(hard_iface);
+               batadv_hardif_put(hard_iface);
        return 0;
 }
 
index 99507408f4cf27a75675d37102383440dfbb794f..4e8b67f110511302b42add7d5aa517510b6f7380 100644 (file)
@@ -37,19 +37,19 @@ int batadv_compare_orig(const struct hlist_node *node, const void *data2);
 int batadv_originator_init(struct batadv_priv *bat_priv);
 void batadv_originator_free(struct batadv_priv *bat_priv);
 void batadv_purge_orig_ref(struct batadv_priv *bat_priv);
-void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node);
+void batadv_orig_node_put(struct batadv_orig_node *orig_node);
 struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
                                              const u8 *addr);
 struct batadv_hardif_neigh_node *
 batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
                        const u8 *neigh_addr);
 void
-batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh);
+batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh);
 struct batadv_neigh_node *
 batadv_neigh_node_new(struct batadv_orig_node *orig_node,
                      struct batadv_hard_iface *hard_iface,
                      const u8 *neigh_addr);
-void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node);
+void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node);
 struct batadv_neigh_node *
 batadv_orig_router_get(struct batadv_orig_node *orig_node,
                       const struct batadv_hard_iface *if_outgoing);
@@ -59,7 +59,7 @@ batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
 struct batadv_neigh_ifinfo *
 batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
                        struct batadv_hard_iface *if_outgoing);
-void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
+void batadv_neigh_ifinfo_put(struct batadv_neigh_ifinfo *neigh_ifinfo);
 
 int batadv_hardif_neigh_seq_print_text(struct seq_file *seq, void *offset);
 
@@ -69,7 +69,7 @@ batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
 struct batadv_orig_ifinfo *
 batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
                       struct batadv_hard_iface *if_outgoing);
-void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
+void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
 
 int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
@@ -83,7 +83,7 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
 struct batadv_orig_node_vlan *
 batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
                          unsigned short vid);
-void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan);
+void batadv_orig_node_vlan_put(struct batadv_orig_node_vlan *orig_vlan);
 
 /* hashfunction to choose an entry in a hash table of given size
  * hash algorithm from http://en.wikipedia.org/wiki/Hash_table
index e7f915181abaedd51dfda248d7a9d08bf66fecb0..8a8d7ca1a5cf16542bcee9e21ac7a5673aaf11f2 100644 (file)
@@ -26,6 +26,8 @@
  * @BATADV_IV_OGM: originator messages for B.A.T.M.A.N. IV
  * @BATADV_BCAST: broadcast packets carrying broadcast payload
  * @BATADV_CODED: network coded packets
+ * @BATADV_ELP: echo location packets for B.A.T.M.A.N. V
+ * @BATADV_OGM2: originator messages for B.A.T.M.A.N. V
  *
  * @BATADV_UNICAST: unicast packets carrying unicast payload traffic
  * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original
@@ -40,6 +42,8 @@ enum batadv_packettype {
        BATADV_IV_OGM           = 0x00,
        BATADV_BCAST            = 0x01,
        BATADV_CODED            = 0x02,
+       BATADV_ELP              = 0x03,
+       BATADV_OGM2             = 0x04,
        /* 0x40 - 0x7f: unicast */
 #define BATADV_UNICAST_MIN     0x40
        BATADV_UNICAST          = 0x40,
@@ -234,6 +238,51 @@ struct batadv_ogm_packet {
 
 #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet)
 
+/**
+ * struct batadv_ogm2_packet - ogm2 (routing protocol) packet
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the general header
+ * @ttl: time to live for this packet, part of the general header
+ * @flags: reseved for routing relevant flags - currently always 0
+ * @seqno: sequence number
+ * @orig: originator mac address
+ * @tvlv_len: length of the appended tvlv buffer (in bytes)
+ * @throughput: the currently flooded path throughput
+ */
+struct batadv_ogm2_packet {
+       u8     packet_type;
+       u8     version;
+       u8     ttl;
+       u8     flags;
+       __be32 seqno;
+       u8     orig[ETH_ALEN];
+       __be16 tvlv_len;
+       __be32 throughput;
+       /* __packed is not needed as the struct size is divisible by 4,
+        * and the largest data type in this struct has a size of 4.
+        */
+};
+
+#define BATADV_OGM2_HLEN sizeof(struct batadv_ogm2_packet)
+
+/**
+ * struct batadv_elp_packet - elp (neighbor discovery) packet
+ * @packet_type: batman-adv packet type, part of the general header
+ * @version: batman-adv protocol version, part of the genereal header
+ * @orig: originator mac address
+ * @seqno: sequence number
+ * @elp_interval: currently used ELP sending interval in ms
+ */
+struct batadv_elp_packet {
+       u8     packet_type;
+       u8     version;
+       u8     orig[ETH_ALEN];
+       __be32 seqno;
+       __be32 elp_interval;
+};
+
+#define BATADV_ELP_HLEN sizeof(struct batadv_elp_packet)
+
 /**
  * struct batadv_icmp_header - common members among all the ICMP packets
  * @packet_type: batman-adv packet type, part of the general header
index 205310b56c2b6ab1038cab688e1992b227401113..4dd646a52f1a16ca297a3cdb1abeff56206df166 100644 (file)
@@ -98,7 +98,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
        }
 
        if (curr_router)
-               batadv_neigh_node_free_ref(curr_router);
+               batadv_neigh_node_put(curr_router);
 
        /* increase refcount of new best neighbor */
        if (neigh_node && !kref_get_unless_zero(&neigh_node->refcount))
@@ -107,11 +107,11 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
        spin_lock_bh(&orig_node->neigh_list_lock);
        rcu_assign_pointer(orig_ifinfo->router, neigh_node);
        spin_unlock_bh(&orig_node->neigh_list_lock);
-       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+       batadv_orig_ifinfo_put(orig_ifinfo);
 
        /* decrease refcount of previous best neighbor */
        if (curr_router)
-               batadv_neigh_node_free_ref(curr_router);
+               batadv_neigh_node_put(curr_router);
 }
 
 /**
@@ -138,7 +138,7 @@ void batadv_update_route(struct batadv_priv *bat_priv,
 
 out:
        if (router)
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 }
 
 /**
@@ -269,9 +269,9 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -317,9 +317,9 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv,
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -403,7 +403,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -545,16 +545,16 @@ batadv_find_router(struct batadv_priv *bat_priv,
 next:
                /* free references */
                if (cand_router) {
-                       batadv_neigh_node_free_ref(cand_router);
+                       batadv_neigh_node_put(cand_router);
                        cand_router = NULL;
                }
-               batadv_orig_ifinfo_free_ref(cand);
+               batadv_orig_ifinfo_put(cand);
        }
        rcu_read_unlock();
 
        /* last_bonding_candidate is reset below, remove the old reference. */
        if (orig_node->last_bonding_candidate)
-               batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
+               batadv_orig_ifinfo_put(orig_node->last_bonding_candidate);
 
        /* After finding candidates, handle the three cases:
         * 1) there is a next candidate, use that
@@ -562,17 +562,17 @@ next:
         * 3) there is no candidate at all, return the default router
         */
        if (next_candidate) {
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 
                /* remove references to first candidate, we don't need it. */
                if (first_candidate) {
-                       batadv_neigh_node_free_ref(first_candidate_router);
-                       batadv_orig_ifinfo_free_ref(first_candidate);
+                       batadv_neigh_node_put(first_candidate_router);
+                       batadv_orig_ifinfo_put(first_candidate);
                }
                router = next_candidate_router;
                orig_node->last_bonding_candidate = next_candidate;
        } else if (first_candidate) {
-               batadv_neigh_node_free_ref(router);
+               batadv_neigh_node_put(router);
 
                /* refcounting has already been done in the loop above. */
                router = first_candidate_router;
@@ -649,7 +649,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
 
@@ -702,9 +702,9 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
        ret = true;
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
 
        return ret;
 }
@@ -768,7 +768,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
                        return 0;
 
                curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn);
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        }
 
        /* check if the TTVN contained in the packet is fresher than what the
@@ -808,7 +808,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 
        ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
 
-       batadv_hardif_free_ref(primary_if);
+       batadv_hardif_put(primary_if);
 
        unicast_packet->ttvn = curr_ttvn;
 
@@ -908,7 +908,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
 
 rx_success:
                if (orig_node)
-                       batadv_orig_node_free_ref(orig_node);
+                       batadv_orig_node_put(orig_node);
 
                return NET_RX_SUCCESS;
        }
@@ -1019,7 +1019,7 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
 
 out:
        if (orig_node_src)
-               batadv_orig_node_free_ref(orig_node_src);
+               batadv_orig_node_put(orig_node_src);
 
        return ret;
 }
@@ -1124,6 +1124,6 @@ spin_unlock:
        spin_unlock_bh(&orig_node->bcast_seqno_lock);
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return ret;
 }
index d8b03fd604e0f7e6970a44f66615b145b22575e9..3ce06e0a91b1c125cdf5ff594db57529a2deaacf 100644 (file)
 
 static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
 
-/* send out an already prepared packet to the given address via the
- * specified batman interface
+/**
+ * batadv_send_skb_packet - send an already prepared packet
+ * @skb: the packet to send
+ * @hard_iface: the interface to use to send the broadcast packet
+ * @dst_addr: the payload destination
+ *
+ * Send out an already prepared packet to the given neighbor or broadcast it
+ * using the specified interface. Either hard_iface or neigh_node must be not
+ * NULL.
+ * If neigh_node is NULL, then the packet is broadcasted using hard_iface,
+ * otherwise it is sent as unicast to the given neighbor.
+ *
+ * Return: NET_TX_DROP in case of error or the result of dev_queue_xmit(skb)
+ * otherwise
  */
 int batadv_send_skb_packet(struct sk_buff *skb,
                           struct batadv_hard_iface *hard_iface,
                           const u8 *dst_addr)
 {
-       struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
+       struct batadv_priv *bat_priv;
        struct ethhdr *ethhdr;
 
+       bat_priv = netdev_priv(hard_iface->soft_iface);
+
        if (hard_iface->if_status != BATADV_IF_ACTIVE)
                goto send_skb_err;
 
@@ -100,6 +114,35 @@ send_skb_err:
        return NET_XMIT_DROP;
 }
 
+int batadv_send_broadcast_skb(struct sk_buff *skb,
+                             struct batadv_hard_iface *hard_iface)
+{
+       return batadv_send_skb_packet(skb, hard_iface, batadv_broadcast_addr);
+}
+
+int batadv_send_unicast_skb(struct sk_buff *skb,
+                           struct batadv_neigh_node *neigh)
+{
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       struct batadv_hardif_neigh_node *hardif_neigh;
+#endif
+       int ret;
+
+       ret = batadv_send_skb_packet(skb, neigh->if_incoming, neigh->addr);
+
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       hardif_neigh = batadv_hardif_neigh_get(neigh->if_incoming, neigh->addr);
+
+       if ((hardif_neigh) && (ret != NET_XMIT_DROP))
+               hardif_neigh->bat_v.last_unicast_tx = jiffies;
+
+       if (hardif_neigh)
+               batadv_hardif_neigh_put(hardif_neigh);
+#endif
+
+       return ret;
+}
+
 /**
  * batadv_send_skb_to_orig - Lookup next-hop and transmit skb.
  * @skb: Packet to be transmitted.
@@ -146,14 +189,13 @@ int batadv_send_skb_to_orig(struct sk_buff *skb,
        if (recv_if && batadv_nc_skb_forward(skb, neigh_node)) {
                ret = NET_XMIT_POLICED;
        } else {
-               batadv_send_skb_packet(skb, neigh_node->if_incoming,
-                                      neigh_node->addr);
+               batadv_send_unicast_skb(skb, neigh_node);
                ret = NET_XMIT_SUCCESS;
        }
 
 out:
        if (neigh_node)
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_put(neigh_node);
 
        return ret;
 }
@@ -246,7 +288,7 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
        ret = true;
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return ret;
 }
 
@@ -317,7 +359,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        if (ret == NET_XMIT_DROP)
                kfree_skb(skb);
        return ret;
@@ -409,9 +451,9 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
 {
        kfree_skb(forw_packet->skb);
        if (forw_packet->if_incoming)
-               batadv_hardif_free_ref(forw_packet->if_incoming);
+               batadv_hardif_put(forw_packet->if_incoming);
        if (forw_packet->if_outgoing)
-               batadv_hardif_free_ref(forw_packet->if_outgoing);
+               batadv_hardif_put(forw_packet->if_outgoing);
        kfree(forw_packet);
 }
 
@@ -497,7 +539,7 @@ out_and_inc:
        atomic_inc(&bat_priv->bcast_queue_left);
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return NETDEV_TX_BUSY;
 }
 
@@ -538,8 +580,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
                /* send a copy of the saved skb */
                skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
                if (skb1)
-                       batadv_send_skb_packet(skb1, hard_iface,
-                                              batadv_broadcast_addr);
+                       batadv_send_broadcast_skb(skb1, hard_iface);
        }
        rcu_read_unlock();
 
index 7ff95cada2e743c6981fe443528133c590771b44..6fd7270d8ce68e44446464afdc24de013416f520 100644 (file)
 struct sk_buff;
 struct work_struct;
 
-int batadv_send_skb_packet(struct sk_buff *skb,
-                          struct batadv_hard_iface *hard_iface,
-                          const u8 *dst_addr);
 int batadv_send_skb_to_orig(struct sk_buff *skb,
                            struct batadv_orig_node *orig_node,
                            struct batadv_hard_iface *recv_if);
+int batadv_send_skb_packet(struct sk_buff *skb,
+                          struct batadv_hard_iface *hard_iface,
+                          const u8 *dst_addr);
+int batadv_send_broadcast_skb(struct sk_buff *skb,
+                             struct batadv_hard_iface *hard_iface);
+int batadv_send_unicast_skb(struct sk_buff *skb,
+                           struct batadv_neigh_node *neigh_node);
 void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface);
 int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
                                    const struct sk_buff *skb,
index d4490ff75edd6494bf188cf622bfc2b367e450f8..0710379491bffc0627c35f0ed5ba6bbf535bb1bb 100644 (file)
@@ -377,7 +377,7 @@ dropped_freed:
        batadv_inc_counter(bat_priv, BATADV_CNT_TX_DROPPED);
 end:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return NETDEV_TX_OK;
 }
 
@@ -497,11 +497,11 @@ static void batadv_softif_vlan_release(struct kref *ref)
 }
 
 /**
- * batadv_softif_vlan_free_ref - decrease the vlan object refcounter and
+ * batadv_softif_vlan_put - decrease the vlan object refcounter and
  *  possibly release it
  * @vlan: the vlan object to release
  */
-void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
+void batadv_softif_vlan_put(struct batadv_softif_vlan *vlan)
 {
        if (!vlan)
                return;
@@ -552,7 +552,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
 
        vlan = batadv_softif_vlan_get(bat_priv, vid);
        if (vlan) {
-               batadv_softif_vlan_free_ref(vlan);
+               batadv_softif_vlan_put(vlan);
                return -EEXIST;
        }
 
@@ -601,7 +601,7 @@ static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
                               vlan->vid, "vlan interface destroyed", false);
 
        batadv_sysfs_del_vlan(bat_priv, vlan);
-       batadv_softif_vlan_free_ref(vlan);
+       batadv_softif_vlan_put(vlan);
 }
 
 /**
@@ -646,7 +646,7 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
        if (!vlan->kobj) {
                ret = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
                if (ret) {
-                       batadv_softif_vlan_free_ref(vlan);
+                       batadv_softif_vlan_put(vlan);
                        return ret;
                }
        }
@@ -693,7 +693,7 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
        batadv_softif_destroy_vlan(bat_priv, vlan);
 
        /* finally free the vlan object */
-       batadv_softif_vlan_free_ref(vlan);
+       batadv_softif_vlan_put(vlan);
 
        return 0;
 }
@@ -749,7 +749,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
        vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
        if (vlan) {
                batadv_softif_destroy_vlan(bat_priv, vlan);
-               batadv_softif_vlan_free_ref(vlan);
+               batadv_softif_vlan_put(vlan);
        }
 
        batadv_sysfs_del_meshif(soft_iface);
@@ -878,7 +878,7 @@ static int batadv_softif_slave_add(struct net_device *dev,
 
 out:
        if (hard_iface)
-               batadv_hardif_free_ref(hard_iface);
+               batadv_hardif_put(hard_iface);
        return ret;
 }
 
@@ -905,7 +905,7 @@ static int batadv_softif_slave_del(struct net_device *dev,
 
 out:
        if (hard_iface)
-               batadv_hardif_free_ref(hard_iface);
+               batadv_hardif_put(hard_iface);
        return ret;
 }
 
index d17cfbacf8093fb125ace2965ee8dcaec4c60a2d..9ae265703d237462541b356b6cacaa47774c27ba 100644 (file)
@@ -34,7 +34,7 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
 int batadv_softif_is_valid(const struct net_device *net_dev);
 extern struct rtnl_link_ops batadv_link_ops;
 int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
-void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan);
+void batadv_softif_vlan_put(struct batadv_softif_vlan *softif_vlan);
 struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
                                                  unsigned short vid);
 
index ab4382ba3855ebbe1464e8c773e396677ee8657a..e7cf51333a36455b6288f3c1b029eb3a187939d5 100644 (file)
@@ -216,7 +216,7 @@ ssize_t batadv_store_vlan_##_name(struct kobject *kobj,                     \
                                              attr, &vlan->_name,       \
                                              bat_priv->soft_iface);    \
                                                                        \
-       batadv_softif_vlan_free_ref(vlan);                              \
+       batadv_softif_vlan_put(vlan);                                   \
        return res;                                                     \
 }
 
@@ -231,7 +231,7 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj,                      \
                             atomic_read(&vlan->_name) == 0 ?           \
                             "disabled" : "enabled");                   \
                                                                        \
-       batadv_softif_vlan_free_ref(vlan);                              \
+       batadv_softif_vlan_put(vlan);                                   \
        return res;                                                     \
 }
 
@@ -242,6 +242,55 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj,                     \
        static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \
                                batadv_store_vlan_##_name)
 
+#define BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min, _max, _post_func)        \
+ssize_t batadv_store_##_name(struct kobject *kobj,                     \
+                            struct attribute *attr, char *buff,        \
+                            size_t count)                              \
+{                                                                      \
+       struct net_device *net_dev = batadv_kobj_to_netdev(kobj);       \
+       struct batadv_hard_iface *hard_iface;                           \
+       ssize_t length;                                                 \
+                                                                       \
+       hard_iface = batadv_hardif_get_by_netdev(net_dev);              \
+       if (!hard_iface)                                                \
+               return 0;                                               \
+                                                                       \
+       length = __batadv_store_uint_attr(buff, count, _min, _max,      \
+                                         _post_func, attr,             \
+                                         &hard_iface->_var, net_dev);  \
+                                                                       \
+       batadv_hardif_put(hard_iface);                          \
+       return length;                                                  \
+}
+
+#define BATADV_ATTR_HIF_SHOW_UINT(_name, _var)                         \
+ssize_t batadv_show_##_name(struct kobject *kobj,                      \
+                           struct attribute *attr, char *buff)         \
+{                                                                      \
+       struct net_device *net_dev = batadv_kobj_to_netdev(kobj);       \
+       struct batadv_hard_iface *hard_iface;                           \
+       ssize_t length;                                                 \
+                                                                       \
+       hard_iface = batadv_hardif_get_by_netdev(net_dev);              \
+       if (!hard_iface)                                                \
+               return 0;                                               \
+                                                                       \
+       length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_var)); \
+                                                                       \
+       batadv_hardif_put(hard_iface);                          \
+       return length;                                                  \
+}
+
+/* Use this, if you are going to set [name] in hard_iface to an
+ * unsigned integer value
+ */
+#define BATADV_ATTR_HIF_UINT(_name, _var, _mode, _min, _max, _post_func)\
+       static BATADV_ATTR_HIF_STORE_UINT(_name, _var, _min,            \
+                                         _max, _post_func)             \
+       static BATADV_ATTR_HIF_SHOW_UINT(_name, _var)                   \
+       static BATADV_ATTR(_name, _mode, batadv_show_##_name,           \
+                          batadv_store_##_name)
+
 static int batadv_store_bool_attr(char *buff, size_t count,
                                  struct net_device *net_dev,
                                  const char *attr_name, atomic_t *attr,
@@ -771,7 +820,7 @@ static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
 
        length = sprintf(buff, "%s\n", ifname);
 
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
 
        return length;
 }
@@ -795,7 +844,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
        if (strlen(buff) >= IFNAMSIZ) {
                pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n",
                       buff);
-               batadv_hardif_free_ref(hard_iface);
+               batadv_hardif_put(hard_iface);
                return -EINVAL;
        }
 
@@ -829,7 +878,7 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
 unlock:
        rtnl_unlock();
 out:
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
        return ret;
 }
 
@@ -863,18 +912,99 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
                break;
        }
 
-       batadv_hardif_free_ref(hard_iface);
+       batadv_hardif_put(hard_iface);
 
        return length;
 }
 
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+
+/**
+ * batadv_store_throughput_override - parse and store throughput override
+ *  entered by the user
+ * @kobj: kobject representing the private mesh sysfs directory
+ * @attr: the batman-adv attribute the user is interacting with
+ * @buff: the buffer containing the user data
+ * @count: number of bytes in the buffer
+ *
+ * Return: 'count' on success or a negative error code in case of failure
+ */
+static ssize_t batadv_store_throughput_override(struct kobject *kobj,
+                                               struct attribute *attr,
+                                               char *buff, size_t count)
+{
+       struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+       struct batadv_hard_iface *hard_iface;
+       u32 tp_override;
+       u32 old_tp_override;
+       bool ret;
+
+       hard_iface = batadv_hardif_get_by_netdev(net_dev);
+       if (!hard_iface)
+               return -EINVAL;
+
+       if (buff[count - 1] == '\n')
+               buff[count - 1] = '\0';
+
+       ret = batadv_parse_throughput(net_dev, buff, "throughput_override",
+                                     &tp_override);
+       if (!ret)
+               return count;
+
+       old_tp_override = atomic_read(&hard_iface->bat_v.throughput_override);
+       if (old_tp_override == tp_override)
+               goto out;
+
+       batadv_info(net_dev, "%s: Changing from: %u.%u MBit to: %u.%u MBit\n",
+                   "throughput_override",
+                   old_tp_override / 10, old_tp_override % 10,
+                   tp_override / 10, tp_override % 10);
+
+       atomic_set(&hard_iface->bat_v.throughput_override, tp_override);
+
+out:
+       batadv_hardif_put(hard_iface);
+       return count;
+}
+
+static ssize_t batadv_show_throughput_override(struct kobject *kobj,
+                                              struct attribute *attr,
+                                              char *buff)
+{
+       struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+       struct batadv_hard_iface *hard_iface;
+       u32 tp_override;
+
+       hard_iface = batadv_hardif_get_by_netdev(net_dev);
+       if (!hard_iface)
+               return -EINVAL;
+
+       tp_override = atomic_read(&hard_iface->bat_v.throughput_override);
+
+       return sprintf(buff, "%u.%u MBit\n", tp_override / 10,
+                      tp_override % 10);
+}
+
+#endif
+
 static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
                   batadv_store_mesh_iface);
 static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+BATADV_ATTR_HIF_UINT(elp_interval, bat_v.elp_interval, S_IRUGO | S_IWUSR,
+                    2 * BATADV_JITTER, INT_MAX, NULL);
+static BATADV_ATTR(throughput_override, S_IRUGO | S_IWUSR,
+                  batadv_show_throughput_override,
+                  batadv_store_throughput_override);
+#endif
 
 static struct batadv_attribute *batadv_batman_attrs[] = {
        &batadv_attr_mesh_iface,
        &batadv_attr_iface_status,
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       &batadv_attr_elp_interval,
+       &batadv_attr_throughput_override,
+#endif
        NULL,
 };
 
index 11882793f0a4fc89212e85969efbcdb08ef79bd6..0b43e86328a59bb42f7200380b840b0209fd26a1 100644 (file)
@@ -219,12 +219,12 @@ static void batadv_tt_local_entry_release(struct kref *ref)
 }
 
 /**
- * batadv_tt_local_entry_free_ref - decrement the tt_local_entry refcounter and
+ * batadv_tt_local_entry_put - decrement the tt_local_entry refcounter and
  *  possibly release it
  * @tt_local_entry: tt_local_entry to be free'd
  */
 static void
-batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
+batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)
 {
        kref_put(&tt_local_entry->common.refcount,
                 batadv_tt_local_entry_release);
@@ -247,12 +247,12 @@ static void batadv_tt_global_entry_release(struct kref *ref)
 }
 
 /**
- * batadv_tt_global_entry_free_ref - decrement the tt_global_entry refcounter
- *  and possibly release it
+ * batadv_tt_global_entry_put - decrement the tt_global_entry refcounter and
+ *  possibly release it
  * @tt_global_entry: tt_global_entry to be free'd
  */
 static void
-batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
+batadv_tt_global_entry_put(struct batadv_tt_global_entry *tt_global_entry)
 {
        kref_put(&tt_global_entry->common.refcount,
                 batadv_tt_global_entry_release);
@@ -278,7 +278,7 @@ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
                return 0;
 
        count = atomic_read(&tt_global_entry->orig_list_count);
-       batadv_tt_global_entry_free_ref(tt_global_entry);
+       batadv_tt_global_entry_put(tt_global_entry);
 
        return count;
 }
@@ -301,7 +301,7 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
 
        atomic_add(v, &vlan->tt.num_entries);
 
-       batadv_softif_vlan_free_ref(vlan);
+       batadv_softif_vlan_put(vlan);
 }
 
 /**
@@ -346,12 +346,14 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
 
        if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
                spin_lock_bh(&orig_node->vlan_list_lock);
-               hlist_del_init_rcu(&vlan->list);
+               if (!hlist_unhashed(&vlan->list)) {
+                       hlist_del_init_rcu(&vlan->list);
+                       batadv_orig_node_vlan_put(vlan);
+               }
                spin_unlock_bh(&orig_node->vlan_list_lock);
-               batadv_orig_node_vlan_free_ref(vlan);
        }
 
-       batadv_orig_node_vlan_free_ref(vlan);
+       batadv_orig_node_vlan_put(vlan);
 }
 
 /**
@@ -390,17 +392,17 @@ static void batadv_tt_orig_list_entry_release(struct kref *ref)
        orig_entry = container_of(ref, struct batadv_tt_orig_list_entry,
                                  refcount);
 
-       batadv_orig_node_free_ref(orig_entry->orig_node);
+       batadv_orig_node_put(orig_entry->orig_node);
        kfree_rcu(orig_entry, rcu);
 }
 
 /**
- * batadv_tt_orig_list_entry_free_ref - decrement the tt orig entry refcounter
- *  and possibly release it
+ * batadv_tt_orig_list_entry_put - decrement the tt orig entry refcounter and
+ *  possibly release it
  * @orig_entry: tt orig entry to be free'd
  */
 static void
-batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
+batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
 {
        kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
 }
@@ -559,7 +561,7 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
 
        batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
                           batadv_choose_tt, &tt_global->common);
-       batadv_tt_global_entry_free_ref(tt_global);
+       batadv_tt_global_entry_put(tt_global);
 }
 
 /**
@@ -685,8 +687,8 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
 
        if (unlikely(hash_added != 0)) {
                /* remove the reference for the hash */
-               batadv_tt_local_entry_free_ref(tt_local);
-               batadv_softif_vlan_free_ref(vlan);
+               batadv_tt_local_entry_put(tt_local);
+               batadv_softif_vlan_put(vlan);
                goto out;
        }
 
@@ -752,9 +754,9 @@ out:
        if (in_dev)
                dev_put(in_dev);
        if (tt_local)
-               batadv_tt_local_entry_free_ref(tt_local);
+               batadv_tt_local_entry_put(tt_local);
        if (tt_global)
-               batadv_tt_global_entry_free_ref(tt_global);
+               batadv_tt_global_entry_put(tt_global);
        return ret;
 }
 
@@ -1052,13 +1054,13 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
                                   no_purge ? 0 : last_seen_msecs,
                                   vlan->tt.crc);
 
-                       batadv_softif_vlan_free_ref(vlan);
+                       batadv_softif_vlan_put(vlan);
                }
                rcu_read_unlock();
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
@@ -1135,19 +1137,19 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
                goto out;
 
        /* extra call to free the local tt entry */
-       batadv_tt_local_entry_free_ref(tt_local_entry);
+       batadv_tt_local_entry_put(tt_local_entry);
 
        /* decrease the reference held for this vlan */
        vlan = batadv_softif_vlan_get(bat_priv, vid);
        if (!vlan)
                goto out;
 
-       batadv_softif_vlan_free_ref(vlan);
-       batadv_softif_vlan_free_ref(vlan);
+       batadv_softif_vlan_put(vlan);
+       batadv_softif_vlan_put(vlan);
 
 out:
        if (tt_local_entry)
-               batadv_tt_local_entry_free_ref(tt_local_entry);
+               batadv_tt_local_entry_put(tt_local_entry);
 
        return curr_flags;
 }
@@ -1243,11 +1245,11 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
                        vlan = batadv_softif_vlan_get(bat_priv,
                                                      tt_common_entry->vid);
                        if (vlan) {
-                               batadv_softif_vlan_free_ref(vlan);
-                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_put(vlan);
+                               batadv_softif_vlan_put(vlan);
                        }
 
-                       batadv_tt_local_entry_free_ref(tt_local);
+                       batadv_tt_local_entry_put(tt_local);
                }
                spin_unlock_bh(list_lock);
        }
@@ -1343,7 +1345,7 @@ batadv_tt_global_entry_has_orig(const struct batadv_tt_global_entry *entry,
        orig_entry = batadv_tt_global_orig_entry_find(entry, orig_node);
        if (orig_entry) {
                found = true;
-               batadv_tt_orig_list_entry_free_ref(orig_entry);
+               batadv_tt_orig_list_entry_put(orig_entry);
        }
 
        return found;
@@ -1384,7 +1386,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
 
 out:
        if (orig_entry)
-               batadv_tt_orig_list_entry_free_ref(orig_entry);
+               batadv_tt_orig_list_entry_put(orig_entry);
 }
 
 /**
@@ -1465,7 +1467,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 
                if (unlikely(hash_added != 0)) {
                        /* remove the reference for the hash */
-                       batadv_tt_global_entry_free_ref(tt_global_entry);
+                       batadv_tt_global_entry_put(tt_global_entry);
                        goto out_remove;
                }
        } else {
@@ -1551,9 +1553,9 @@ out_remove:
 
 out:
        if (tt_global_entry)
-               batadv_tt_global_entry_free_ref(tt_global_entry);
+               batadv_tt_global_entry_put(tt_global_entry);
        if (tt_local_entry)
-               batadv_tt_local_entry_free_ref(tt_local_entry);
+               batadv_tt_local_entry_put(tt_local_entry);
        return ret;
 }
 
@@ -1584,20 +1586,20 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
                if (best_router &&
                    bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
                                       best_router, BATADV_IF_DEFAULT) <= 0) {
-                       batadv_neigh_node_free_ref(router);
+                       batadv_neigh_node_put(router);
                        continue;
                }
 
                /* release the refcount for the "old" best */
                if (best_router)
-                       batadv_neigh_node_free_ref(best_router);
+                       batadv_neigh_node_put(best_router);
 
                best_entry = orig_entry;
                best_router = router;
        }
 
        if (best_router)
-               batadv_neigh_node_free_ref(best_router);
+               batadv_neigh_node_put(best_router);
 
        return best_entry;
 }
@@ -1650,7 +1652,7 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
                           ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
                           ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
 
-               batadv_orig_node_vlan_free_ref(vlan);
+               batadv_orig_node_vlan_put(vlan);
        }
 
 print_list:
@@ -1682,7 +1684,7 @@ print_list:
                           ((flags & BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
                           ((flags & BATADV_TT_CLIENT_TEMP) ? 'T' : '.'));
 
-               batadv_orig_node_vlan_free_ref(vlan);
+               batadv_orig_node_vlan_put(vlan);
        }
 }
 
@@ -1723,7 +1725,7 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
        }
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        return 0;
 }
 
@@ -1751,7 +1753,7 @@ _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
         * being part of a list
         */
        hlist_del_rcu(&orig_entry->list);
-       batadv_tt_orig_list_entry_free_ref(orig_entry);
+       batadv_tt_orig_list_entry_put(orig_entry);
 }
 
 /* deletes the orig list of a tt_global_entry */
@@ -1907,9 +1909,9 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
 
 out:
        if (tt_global_entry)
-               batadv_tt_global_entry_free_ref(tt_global_entry);
+               batadv_tt_global_entry_put(tt_global_entry);
        if (local_entry)
-               batadv_tt_local_entry_free_ref(local_entry);
+               batadv_tt_local_entry_put(local_entry);
 }
 
 /**
@@ -1963,7 +1965,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
                                           tt_global->common.addr,
                                           BATADV_PRINT_VID(vid), message);
                                hlist_del_rcu(&tt_common_entry->hash_entry);
-                               batadv_tt_global_entry_free_ref(tt_global);
+                               batadv_tt_global_entry_put(tt_global);
                        }
                }
                spin_unlock_bh(list_lock);
@@ -2026,7 +2028,7 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
 
                        hlist_del_rcu(&tt_common->hash_entry);
 
-                       batadv_tt_global_entry_free_ref(tt_global);
+                       batadv_tt_global_entry_put(tt_global);
                }
                spin_unlock_bh(list_lock);
        }
@@ -2058,7 +2060,7 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
                        tt_global = container_of(tt_common_entry,
                                                 struct batadv_tt_global_entry,
                                                 common);
-                       batadv_tt_global_entry_free_ref(tt_global);
+                       batadv_tt_global_entry_put(tt_global);
                }
                spin_unlock_bh(list_lock);
        }
@@ -2139,9 +2141,9 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 
 out:
        if (tt_global_entry)
-               batadv_tt_global_entry_free_ref(tt_global_entry);
+               batadv_tt_global_entry_put(tt_global_entry);
        if (tt_local_entry)
-               batadv_tt_local_entry_free_ref(tt_local_entry);
+               batadv_tt_local_entry_put(tt_local_entry);
 
        return orig_node;
 }
@@ -2501,7 +2503,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
                        return false;
 
                crc = vlan->tt.crc;
-               batadv_orig_node_vlan_free_ref(vlan);
+               batadv_orig_node_vlan_put(vlan);
 
                if (crc != ntohl(tt_vlan_tmp->crc))
                        return false;
@@ -2636,7 +2638,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv,
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        if (ret && tt_req_node) {
                spin_lock_bh(&bat_priv->tt.req_list_lock);
                /* hlist_del_init() verifies tt_req_node still is in the list */
@@ -2774,9 +2776,9 @@ unlock:
 
 out:
        if (res_dst_orig_node)
-               batadv_orig_node_free_ref(res_dst_orig_node);
+               batadv_orig_node_put(res_dst_orig_node);
        if (req_dst_orig_node)
-               batadv_orig_node_free_ref(req_dst_orig_node);
+               batadv_orig_node_put(req_dst_orig_node);
        kfree(tvlv_tt_data);
        return ret;
 }
@@ -2891,9 +2893,9 @@ unlock:
 out:
        spin_unlock_bh(&bat_priv->tt.commit_lock);
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
        kfree(tvlv_tt_data);
        /* The packet was for this host, so it doesn't need to be re-routed */
        return true;
@@ -2979,7 +2981,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
 }
 
 static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
@@ -3021,7 +3023,7 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
        ret = true;
 out:
        if (tt_local_entry)
-               batadv_tt_local_entry_free_ref(tt_local_entry);
+               batadv_tt_local_entry_put(tt_local_entry);
        return ret;
 }
 
@@ -3085,7 +3087,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
        spin_unlock_bh(&bat_priv->tt.req_list_lock);
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
 }
 
 static void batadv_tt_roam_list_free(struct batadv_priv *bat_priv)
@@ -3216,7 +3218,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client,
 
 out:
        if (primary_if)
-               batadv_hardif_free_ref(primary_if);
+               batadv_hardif_put(primary_if);
 }
 
 static void batadv_tt_purge(struct work_struct *work)
@@ -3340,11 +3342,11 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
                        /* decrease the reference held for this vlan */
                        vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
                        if (vlan) {
-                               batadv_softif_vlan_free_ref(vlan);
-                               batadv_softif_vlan_free_ref(vlan);
+                               batadv_softif_vlan_put(vlan);
+                               batadv_softif_vlan_put(vlan);
                        }
 
-                       batadv_tt_local_entry_free_ref(tt_local);
+                       batadv_tt_local_entry_put(tt_local);
                }
                spin_unlock_bh(list_lock);
        }
@@ -3427,11 +3429,11 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,
        ret = true;
 
 out:
-       batadv_softif_vlan_free_ref(vlan);
+       batadv_softif_vlan_put(vlan);
        if (tt_global_entry)
-               batadv_tt_global_entry_free_ref(tt_global_entry);
+               batadv_tt_global_entry_put(tt_global_entry);
        if (tt_local_entry)
-               batadv_tt_local_entry_free_ref(tt_local_entry);
+               batadv_tt_local_entry_put(tt_local_entry);
        return ret;
 }
 
@@ -3541,7 +3543,7 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
                goto out;
 
        ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
-       batadv_tt_global_entry_free_ref(tt_global_entry);
+       batadv_tt_global_entry_put(tt_global_entry);
 out:
        return ret;
 }
@@ -3567,7 +3569,7 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
                goto out;
 
        ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
-       batadv_tt_local_entry_free_ref(tt_local_entry);
+       batadv_tt_local_entry_put(tt_local_entry);
 out:
        return ret;
 }
@@ -3800,7 +3802,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 
 out:
        if (orig_node)
-               batadv_orig_node_free_ref(orig_node);
+               batadv_orig_node_put(orig_node);
        return NET_RX_SUCCESS;
 }
 
@@ -3861,7 +3863,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
 
        ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
 
-       batadv_tt_global_entry_free_ref(tt);
+       batadv_tt_global_entry_put(tt);
 
        return ret;
 }
index 612de23178e64c72891b04abe445689b9cc6f171..9abfb3e73c3448a9612c9c282166fe5e18b44327 100644 (file)
@@ -22,6 +22,7 @@
 #error only "main.h" can be included directly
 #endif
 
+#include <linux/average.h>
 #include <linux/bitops.h>
 #include <linux/compiler.h>
 #include <linux/if_ether.h>
@@ -85,6 +86,36 @@ struct batadv_hard_iface_bat_iv {
        atomic_t ogm_seqno;
 };
 
+/**
+ * enum batadv_v_hard_iface_flags - interface flags useful to B.A.T.M.A.N. V
+ * @BATADV_FULL_DUPLEX: tells if the connection over this link is full-duplex
+ * @BATADV_WARNING_DEFAULT: tells whether we have warned the user that no
+ *  throughput data is available for this interface and that default values are
+ *  assumed.
+ */
+enum batadv_v_hard_iface_flags {
+       BATADV_FULL_DUPLEX      = BIT(0),
+       BATADV_WARNING_DEFAULT  = BIT(1),
+};
+
+/**
+ * struct batadv_hard_iface_bat_v - per hard-interface B.A.T.M.A.N. V data
+ * @elp_interval: time interval between two ELP transmissions
+ * @elp_seqno: current ELP sequence number
+ * @elp_skb: base skb containing the ELP message to send
+ * @elp_wq: workqueue used to schedule ELP transmissions
+ * @throughput_override: throughput override to disable link auto-detection
+ * @flags: interface specific flags
+ */
+struct batadv_hard_iface_bat_v {
+       atomic_t elp_interval;
+       atomic_t elp_seqno;
+       struct sk_buff *elp_skb;
+       struct delayed_work elp_wq;
+       atomic_t throughput_override;
+       u8 flags;
+};
+
 /**
  * struct batadv_hard_iface - network device known to batman-adv
  * @list: list node for batadv_hardif_list
@@ -99,6 +130,7 @@ struct batadv_hard_iface_bat_iv {
  * @soft_iface: the batman-adv interface which uses this network interface
  * @rcu: struct used for freeing in an RCU-safe manner
  * @bat_iv: per hard-interface B.A.T.M.A.N. IV data
+ * @bat_v: per hard-interface B.A.T.M.A.N. V data
  * @cleanup_work: work queue callback item for hard-interface deinit
  * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
  * @neigh_list: list of unique single hop neighbors via this interface
@@ -116,6 +148,9 @@ struct batadv_hard_iface {
        struct net_device *soft_iface;
        struct rcu_head rcu;
        struct batadv_hard_iface_bat_iv bat_iv;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       struct batadv_hard_iface_bat_v bat_v;
+#endif
        struct work_struct cleanup_work;
        struct dentry *debug_dir;
        struct hlist_head neigh_list;
@@ -130,6 +165,7 @@ struct batadv_hard_iface {
  * @router: router that should be used to reach this originator
  * @last_real_seqno: last and best known sequence number
  * @last_ttl: ttl of last received packet
+ * @last_seqno_forwarded: seqno of the OGM which was forwarded last
  * @batman_seqno_reset: time when the batman seqno window was reset
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
@@ -140,6 +176,7 @@ struct batadv_orig_ifinfo {
        struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
        u32 last_real_seqno;
        u8 last_ttl;
+       u32 last_seqno_forwarded;
        unsigned long batman_seqno_reset;
        struct kref refcount;
        struct rcu_head rcu;
@@ -346,12 +383,32 @@ struct batadv_gw_node {
        struct rcu_head rcu;
 };
 
+DECLARE_EWMA(throughput, 1024, 8)
+
+/**
+ * struct batadv_hardif_neigh_node_bat_v - B.A.T.M.A.N. V private neighbor
+ *  information
+ * @throughput: ewma link throughput towards this neighbor
+ * @elp_interval: time interval between two ELP transmissions
+ * @elp_latest_seqno: latest and best known ELP sequence number
+ * @last_unicast_tx: when the last unicast packet has been sent to this neighbor
+ * @metric_work: work queue callback item for metric update
+ */
+struct batadv_hardif_neigh_node_bat_v {
+       struct ewma_throughput throughput;
+       u32 elp_interval;
+       u32 elp_latest_seqno;
+       unsigned long last_unicast_tx;
+       struct work_struct metric_work;
+};
+
 /**
  * struct batadv_hardif_neigh_node - unique neighbor per hard-interface
  * @list: list node for batadv_hard_iface::neigh_list
  * @addr: the MAC address of the neighboring interface
  * @if_incoming: pointer to incoming hard-interface
  * @last_seen: when last packet via this neighbor was received
+ * @bat_v: B.A.T.M.A.N. V private data
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in a RCU-safe manner
  */
@@ -360,6 +417,9 @@ struct batadv_hardif_neigh_node {
        u8 addr[ETH_ALEN];
        struct batadv_hard_iface *if_incoming;
        unsigned long last_seen;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       struct batadv_hardif_neigh_node_bat_v bat_v;
+#endif
        struct kref refcount;
        struct rcu_head rcu;
 };
@@ -406,11 +466,23 @@ struct batadv_neigh_ifinfo_bat_iv {
        u8 real_packet_count;
 };
 
+/**
+ * struct batadv_neigh_ifinfo_bat_v - neighbor information per outgoing
+ *  interface for B.A.T.M.A.N. V
+ * @throughput: last throughput metric received from originator via this neigh
+ * @last_seqno: last sequence number known for this neighbor
+ */
+struct batadv_neigh_ifinfo_bat_v {
+       u32 throughput;
+       u32 last_seqno;
+};
+
 /**
  * struct batadv_neigh_ifinfo - neighbor information per outgoing interface
  * @list: list node for batadv_neigh_node::ifinfo_list
  * @if_outgoing: pointer to outgoing hard-interface
  * @bat_iv: B.A.T.M.A.N. IV private structure
+ * @bat_v: B.A.T.M.A.N. V private data
  * @last_ttl: last received ttl from this neigh node
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in a RCU-safe manner
@@ -419,6 +491,9 @@ struct batadv_neigh_ifinfo {
        struct hlist_node list;
        struct batadv_hard_iface *if_outgoing;
        struct batadv_neigh_ifinfo_bat_iv bat_iv;
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       struct batadv_neigh_ifinfo_bat_v bat_v;
+#endif
        u8 last_ttl;
        struct kref refcount;
        struct rcu_head rcu;
@@ -750,6 +825,20 @@ struct batadv_softif_vlan {
        struct rcu_head rcu;
 };
 
+/**
+ * struct batadv_priv_bat_v - B.A.T.M.A.N. V per soft-interface private data
+ * @ogm_buff: buffer holding the OGM packet
+ * @ogm_buff_len: length of the OGM packet buffer
+ * @ogm_seqno: OGM sequence number - used to identify each OGM
+ * @ogm_wq: workqueue used to schedule OGM transmissions
+ */
+struct batadv_priv_bat_v {
+       unsigned char *ogm_buff;
+       int ogm_buff_len;
+       atomic_t ogm_seqno;
+       struct delayed_work ogm_wq;
+};
+
 /**
  * struct batadv_priv - per mesh interface data
  * @mesh_state: current status of the mesh (inactive/active/deactivating)
@@ -804,6 +893,7 @@ struct batadv_softif_vlan {
  * @mcast: multicast data
  * @network_coding: bool indicating whether network coding is enabled
  * @nc: network coding data
+ * @bat_v: B.A.T.M.A.N. V per soft-interface private data
  */
 struct batadv_priv {
        atomic_t mesh_state;
@@ -869,6 +959,9 @@ struct batadv_priv {
        atomic_t network_coding;
        struct batadv_priv_nc nc;
 #endif /* CONFIG_BATMAN_ADV_NC */
+#ifdef CONFIG_BATMAN_ADV_BATMAN_V
+       struct batadv_priv_bat_v bat_v;
+#endif
 };
 
 /**
index 95d1a66ba03aa20095932a1c45f9f76af2cc1393..06c31b9a68b0bce3cc4f28224c3c23864f78e7c9 100644 (file)
@@ -69,6 +69,15 @@ config BT_6LOWPAN
        help
          IPv6 compression over Bluetooth Low Energy.
 
+config BT_LEDS
+       bool "Enable LED triggers"
+       depends on BT
+       depends on LEDS_CLASS
+       select LEDS_TRIGGERS
+       help
+         This option selects a few LED triggers for different
+         Bluetooth events.
+
 config BT_SELFTEST
        bool "Bluetooth self testing support"
        depends on BT && DEBUG_KERNEL
index 2b15ae8c1def06642682c488a9439f0e57feeb13..b3ff12eb9b6dcdaa590bacc997cbe2e0e566783e 100644 (file)
@@ -17,6 +17,7 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
 
 bluetooth-$(CONFIG_BT_BREDR) += sco.o
 bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
+bluetooth-$(CONFIG_BT_LEDS) += leds.o
 bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
 bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o
 
index 47bcef7547967ce544ff0cf5ea7dabecdd080d90..2713fc86e85abd780d9bccfb2bb11cb353d4fcb9 100644 (file)
@@ -40,6 +40,7 @@
 #include "hci_request.h"
 #include "hci_debugfs.h"
 #include "smp.h"
+#include "leds.h"
 
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
@@ -1395,6 +1396,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
                hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
                set_bit(HCI_UP, &hdev->flags);
                hci_sock_dev_event(hdev, HCI_DEV_UP);
+               hci_leds_update_powered(hdev, true);
                if (!hci_dev_test_flag(hdev, HCI_SETUP) &&
                    !hci_dev_test_flag(hdev, HCI_CONFIG) &&
                    !hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
@@ -1532,6 +1534,8 @@ int hci_dev_do_close(struct hci_dev *hdev)
                return 0;
        }
 
+       hci_leds_update_powered(hdev, false);
+
        /* Flush RX and TX works */
        flush_work(&hdev->tx_work);
        flush_work(&hdev->rx_work);
@@ -2017,6 +2021,7 @@ static void hci_power_on(struct work_struct *work)
        if (test_bit(HCI_UP, &hdev->flags) &&
            hci_dev_test_flag(hdev, HCI_MGMT) &&
            hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
+               cancel_delayed_work(&hdev->power_off);
                hci_req_sync_lock(hdev);
                err = __hci_req_hci_power_on(hdev);
                hci_req_sync_unlock(hdev);
@@ -3067,6 +3072,8 @@ int hci_register_dev(struct hci_dev *hdev)
        if (error < 0)
                goto err_wqueue;
 
+       hci_leds_init(hdev);
+
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
                                    hdev);
@@ -4112,8 +4119,10 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status,
                        break;
                }
 
-               *req_complete = bt_cb(skb)->hci.req_complete;
-               *req_complete_skb = bt_cb(skb)->hci.req_complete_skb;
+               if (bt_cb(skb)->hci.req_flags & HCI_REQ_SKB)
+                       *req_complete_skb = bt_cb(skb)->hci.req_complete_skb;
+               else
+                       *req_complete = bt_cb(skb)->hci.req_complete;
                kfree_skb(skb);
        }
        spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
diff --git a/net/bluetooth/leds.c b/net/bluetooth/leds.c
new file mode 100644 (file)
index 0000000..8319c84
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015, Heiner Kallweit <hkallweit1@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.
+ */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "leds.h"
+
+struct hci_basic_led_trigger {
+       struct led_trigger      led_trigger;
+       struct hci_dev          *hdev;
+};
+
+#define to_hci_basic_led_trigger(arg) container_of(arg, \
+                       struct hci_basic_led_trigger, led_trigger)
+
+void hci_leds_update_powered(struct hci_dev *hdev, bool enabled)
+{
+       if (hdev->power_led)
+               led_trigger_event(hdev->power_led,
+                                 enabled ? LED_FULL : LED_OFF);
+}
+
+static void power_activate(struct led_classdev *led_cdev)
+{
+       struct hci_basic_led_trigger *htrig;
+       bool powered;
+
+       htrig = to_hci_basic_led_trigger(led_cdev->trigger);
+       powered = test_bit(HCI_UP, &htrig->hdev->flags);
+
+       led_trigger_event(led_cdev->trigger, powered ? LED_FULL : LED_OFF);
+}
+
+static struct led_trigger *led_allocate_basic(struct hci_dev *hdev,
+                       void (*activate)(struct led_classdev *led_cdev),
+                       const char *name)
+{
+       struct hci_basic_led_trigger *htrig;
+
+       htrig = devm_kzalloc(&hdev->dev, sizeof(*htrig), GFP_KERNEL);
+       if (!htrig)
+               return NULL;
+
+       htrig->hdev = hdev;
+       htrig->led_trigger.activate = activate;
+       htrig->led_trigger.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+                                                "%s-%s", hdev->name,
+                                                name);
+       if (!htrig->led_trigger.name)
+               goto err_alloc;
+
+       if (devm_led_trigger_register(&hdev->dev, &htrig->led_trigger))
+               goto err_register;
+
+       return &htrig->led_trigger;
+
+err_register:
+       devm_kfree(&hdev->dev, (void *)htrig->led_trigger.name);
+err_alloc:
+       devm_kfree(&hdev->dev, htrig);
+       return NULL;
+}
+
+void hci_leds_init(struct hci_dev *hdev)
+{
+       /* initialize power_led */
+       hdev->power_led = led_allocate_basic(hdev, power_activate, "power");
+}
diff --git a/net/bluetooth/leds.h b/net/bluetooth/leds.h
new file mode 100644 (file)
index 0000000..a9c4d6e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2015, Heiner Kallweit <hkallweit1@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.
+ */
+
+#if IS_ENABLED(CONFIG_BT_LEDS)
+void hci_leds_update_powered(struct hci_dev *hdev, bool enabled);
+void hci_leds_init(struct hci_dev *hdev);
+#else
+static inline void hci_leds_update_powered(struct hci_dev *hdev,
+                                          bool enabled) {}
+static inline void hci_leds_init(struct hci_dev *hdev) {}
+#endif
index 82e3e97050173542b5d6094ebc4db81324198b18..dcea4f4c62b3b43d701fb68a74a6aa1a1e0aa8cf 100644 (file)
@@ -723,6 +723,8 @@ int br_fdb_dump(struct sk_buff *skb,
                struct net_bridge_fdb_entry *f;
 
                hlist_for_each_entry_rcu(f, &br->hash[i], hlist) {
+                       int err;
+
                        if (idx < cb->args[0])
                                goto skip;
 
@@ -741,12 +743,15 @@ int br_fdb_dump(struct sk_buff *skb,
                        if (!filter_dev && f->dst)
                                goto skip;
 
-                       if (fdb_fill_info(skb, br, f,
-                                         NETLINK_CB(cb->skb).portid,
-                                         cb->nlh->nlmsg_seq,
-                                         RTM_NEWNEIGH,
-                                         NLM_F_MULTI) < 0)
+                       err = fdb_fill_info(skb, br, f,
+                                           NETLINK_CB(cb->skb).portid,
+                                           cb->nlh->nlmsg_seq,
+                                           RTM_NEWNEIGH,
+                                           NLM_F_MULTI);
+                       if (err < 0) {
+                               cb->args[1] = err;
                                break;
+                       }
 skip:
                        ++idx;
                }
index fcdb86dd5a239cceb0fb79d8e422f6fc56d14f0a..f47759f05b6d5eb0574e890e656eb42dea0bbf80 100644 (file)
@@ -44,7 +44,6 @@ int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb
 
        skb_push(skb, ETH_HLEN);
        br_drop_fake_rtable(skb);
-       skb_sender_cpu_clear(skb);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL &&
            (skb->protocol == htons(ETH_P_8021Q) ||
index c367b3e1b5ac21f0d482c330569ac6280aa4467d..a73df3315df9f86b861b87e8f5d73bdbdf64bf44 100644 (file)
  */
 static int port_cost(struct net_device *dev)
 {
-       struct ethtool_cmd ecmd;
+       struct ethtool_link_ksettings ecmd;
 
-       if (!__ethtool_get_settings(dev, &ecmd)) {
-               switch (ethtool_cmd_speed(&ecmd)) {
+       if (!__ethtool_get_link_ksettings(dev, &ecmd)) {
+               switch (ecmd.base.speed) {
                case SPEED_10000:
                        return 2;
                case SPEED_1000:
@@ -223,6 +223,31 @@ static void destroy_nbp_rcu(struct rcu_head *head)
        destroy_nbp(p);
 }
 
+static unsigned get_max_headroom(struct net_bridge *br)
+{
+       unsigned max_headroom = 0;
+       struct net_bridge_port *p;
+
+       list_for_each_entry(p, &br->port_list, list) {
+               unsigned dev_headroom = netdev_get_fwd_headroom(p->dev);
+
+               if (dev_headroom > max_headroom)
+                       max_headroom = dev_headroom;
+       }
+
+       return max_headroom;
+}
+
+static void update_headroom(struct net_bridge *br, int new_hr)
+{
+       struct net_bridge_port *p;
+
+       list_for_each_entry(p, &br->port_list, list)
+               netdev_set_rx_headroom(p->dev, new_hr);
+
+       br->dev->needed_headroom = new_hr;
+}
+
 /* Delete port(interface) from bridge is done in two steps.
  * via RCU. First step, marks device as down. That deletes
  * all the timers and stops new packets from flowing through.
@@ -248,6 +273,9 @@ static void del_nbp(struct net_bridge_port *p)
        br_ifinfo_notify(RTM_DELLINK, p);
 
        list_del_rcu(&p->list);
+       if (netdev_get_fwd_headroom(dev) == br->dev->needed_headroom)
+               update_headroom(br, get_max_headroom(br));
+       netdev_reset_rx_headroom(dev);
 
        nbp_vlan_flush(p);
        br_fdb_delete_by_port(br, p, 0, 1);
@@ -438,6 +466,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 {
        struct net_bridge_port *p;
        int err = 0;
+       unsigned br_hr, dev_hr;
        bool changed_addr;
 
        /* Don't allow bridging non-ethernet like devices, or DSA-enabled
@@ -505,8 +534,12 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        netdev_update_features(br->dev);
 
-       if (br->dev->needed_headroom < dev->needed_headroom)
-               br->dev->needed_headroom = dev->needed_headroom;
+       br_hr = br->dev->needed_headroom;
+       dev_hr = netdev_get_fwd_headroom(dev);
+       if (br_hr < dev_hr)
+               update_headroom(br, dev_hr);
+       else
+               netdev_set_rx_headroom(dev, br_hr);
 
        if (br_fdb_insert(br, p, dev->dev_addr, 0))
                netdev_err(dev, "failed insert local address bridge forwarding table\n");
index ac089286526ef8b94f39b869275b1f5ff07834ad..253bc77eda3bd1106021a7d93ba6854964f0a935 100644 (file)
@@ -20,7 +20,7 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
 {
        struct net_bridge *br = netdev_priv(dev);
        struct net_bridge_port *p;
-       struct nlattr *nest;
+       struct nlattr *nest, *port_nest;
 
        if (!br->multicast_router || hlist_empty(&br->router_list))
                return 0;
@@ -30,8 +30,20 @@ static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
                return -EMSGSIZE;
 
        hlist_for_each_entry_rcu(p, &br->router_list, rlist) {
-               if (p && nla_put_u32(skb, MDBA_ROUTER_PORT, p->dev->ifindex))
+               if (!p)
+                       continue;
+               port_nest = nla_nest_start(skb, MDBA_ROUTER_PORT);
+               if (!port_nest)
+                       goto fail;
+               if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) ||
+                   nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER,
+                               br_timer_value(&p->multicast_router_timer)) ||
+                   nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE,
+                              p->multicast_router)) {
+                       nla_nest_cancel(skb, port_nest);
                        goto fail;
+               }
+               nla_nest_end(skb, port_nest);
        }
 
        nla_nest_end(skb, nest);
@@ -88,26 +100,41 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
                        for (pp = &mp->ports;
                             (p = rcu_dereference(*pp)) != NULL;
                              pp = &p->next) {
+                               struct nlattr *nest_ent;
+                               struct br_mdb_entry e;
+
                                port = p->port;
-                               if (port) {
-                                       struct br_mdb_entry e;
-                                       memset(&e, 0, sizeof(e));
-                                       e.ifindex = port->dev->ifindex;
-                                       e.vid = p->addr.vid;
-                                       __mdb_entry_fill_flags(&e, p->flags);
-                                       if (p->addr.proto == htons(ETH_P_IP))
-                                               e.addr.u.ip4 = p->addr.u.ip4;
+                               if (!port)
+                                       continue;
+
+                               memset(&e, 0, sizeof(e));
+                               e.ifindex = port->dev->ifindex;
+                               e.vid = p->addr.vid;
+                               __mdb_entry_fill_flags(&e, p->flags);
+                               if (p->addr.proto == htons(ETH_P_IP))
+                                       e.addr.u.ip4 = p->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-                                       if (p->addr.proto == htons(ETH_P_IPV6))
-                                               e.addr.u.ip6 = p->addr.u.ip6;
+                               if (p->addr.proto == htons(ETH_P_IPV6))
+                                       e.addr.u.ip6 = p->addr.u.ip6;
 #endif
-                                       e.addr.proto = p->addr.proto;
-                                       if (nla_put(skb, MDBA_MDB_ENTRY_INFO, sizeof(e), &e)) {
-                                               nla_nest_cancel(skb, nest2);
-                                               err = -EMSGSIZE;
-                                               goto out;
-                                       }
+                               e.addr.proto = p->addr.proto;
+                               nest_ent = nla_nest_start(skb,
+                                                         MDBA_MDB_ENTRY_INFO);
+                               if (!nest_ent) {
+                                       nla_nest_cancel(skb, nest2);
+                                       err = -EMSGSIZE;
+                                       goto out;
+                               }
+                               if (nla_put_nohdr(skb, sizeof(e), &e) ||
+                                   nla_put_u32(skb,
+                                               MDBA_MDB_EATTR_TIMER,
+                                               br_timer_value(&p->timer))) {
+                                       nla_nest_cancel(skb, nest_ent);
+                                       nla_nest_cancel(skb, nest2);
+                                       err = -EMSGSIZE;
+                                       goto out;
                                }
+                               nla_nest_end(skb, nest_ent);
                        }
                        nla_nest_end(skb, nest2);
                skip:
@@ -437,8 +464,8 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
        mp = br_mdb_ip_get(mdb, group);
        if (!mp) {
                mp = br_multicast_new_group(br, port, group);
-               err = PTR_ERR(mp);
-               if (IS_ERR(mp))
+               err = PTR_ERR_OR_ZERO(mp);
+               if (err)
                        return err;
        }
 
index 8b6e4249be1b09a37047988424c8c60c9d38290e..a4c15df2b7920301f7d12918dc21a1d6f2474352 100644 (file)
@@ -759,13 +759,17 @@ static void br_multicast_router_expired(unsigned long data)
        struct net_bridge *br = port->br;
 
        spin_lock(&br->multicast_lock);
-       if (port->multicast_router != 1 ||
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM ||
            timer_pending(&port->multicast_router_timer) ||
            hlist_unhashed(&port->rlist))
                goto out;
 
        hlist_del_init_rcu(&port->rlist);
        br_rtr_notify(br->dev, port, RTM_DELMDB);
+       /* Don't allow timer refresh if the router expired */
+       if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+               port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
 
 out:
        spin_unlock(&br->multicast_lock);
@@ -912,7 +916,7 @@ static void br_ip6_multicast_port_query_expired(unsigned long data)
 
 void br_multicast_add_port(struct net_bridge_port *port)
 {
-       port->multicast_router = 1;
+       port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
 
        setup_timer(&port->multicast_router_timer, br_multicast_router_expired,
                    (unsigned long)port);
@@ -959,7 +963,8 @@ void br_multicast_enable_port(struct net_bridge_port *port)
 #if IS_ENABLED(CONFIG_IPV6)
        br_multicast_enable(&port->ip6_own_query);
 #endif
-       if (port->multicast_router == 2 && hlist_unhashed(&port->rlist))
+       if (port->multicast_router == MDB_RTR_TYPE_PERM &&
+           hlist_unhashed(&port->rlist))
                br_multicast_add_router(br, port);
 
 out:
@@ -980,6 +985,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
        if (!hlist_unhashed(&port->rlist)) {
                hlist_del_init_rcu(&port->rlist);
                br_rtr_notify(br->dev, port, RTM_DELMDB);
+               /* Don't allow timer refresh if disabling */
+               if (port->multicast_router == MDB_RTR_TYPE_TEMP)
+                       port->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        }
        del_timer(&port->multicast_router_timer);
        del_timer(&port->ip4_own_query.timer);
@@ -1227,13 +1235,14 @@ static void br_multicast_mark_router(struct net_bridge *br,
        unsigned long now = jiffies;
 
        if (!port) {
-               if (br->multicast_router == 1)
+               if (br->multicast_router == MDB_RTR_TYPE_TEMP_QUERY)
                        mod_timer(&br->multicast_router_timer,
                                  now + br->multicast_querier_interval);
                return;
        }
 
-       if (port->multicast_router != 1)
+       if (port->multicast_router == MDB_RTR_TYPE_DISABLED ||
+           port->multicast_router == MDB_RTR_TYPE_PERM)
                return;
 
        br_multicast_add_router(br, port);
@@ -1713,7 +1722,7 @@ void br_multicast_init(struct net_bridge *br)
        br->hash_elasticity = 4;
        br->hash_max = 512;
 
-       br->multicast_router = 1;
+       br->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
        br->multicast_querier = 0;
        br->multicast_query_use_ifaddr = 0;
        br->multicast_last_member_count = 2;
@@ -1823,11 +1832,11 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
        spin_lock_bh(&br->multicast_lock);
 
        switch (val) {
-       case 0:
-       case 2:
+       case MDB_RTR_TYPE_DISABLED:
+       case MDB_RTR_TYPE_PERM:
                del_timer(&br->multicast_router_timer);
                /* fall through */
-       case 1:
+       case MDB_RTR_TYPE_TEMP_QUERY:
                br->multicast_router = val;
                err = 0;
                break;
@@ -1838,37 +1847,53 @@ int br_multicast_set_router(struct net_bridge *br, unsigned long val)
        return err;
 }
 
+static void __del_port_router(struct net_bridge_port *p)
+{
+       if (hlist_unhashed(&p->rlist))
+               return;
+       hlist_del_init_rcu(&p->rlist);
+       br_rtr_notify(p->br->dev, p, RTM_DELMDB);
+}
+
 int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
 {
        struct net_bridge *br = p->br;
+       unsigned long now = jiffies;
        int err = -EINVAL;
 
        spin_lock(&br->multicast_lock);
-
-       switch (val) {
-       case 0:
-       case 1:
-       case 2:
-               p->multicast_router = val;
+       if (p->multicast_router == val) {
+               /* Refresh the temp router port timer */
+               if (p->multicast_router == MDB_RTR_TYPE_TEMP)
+                       mod_timer(&p->multicast_router_timer,
+                                 now + br->multicast_querier_interval);
                err = 0;
-
-               if (val < 2 && !hlist_unhashed(&p->rlist)) {
-                       hlist_del_init_rcu(&p->rlist);
-                       br_rtr_notify(br->dev, p, RTM_DELMDB);
-               }
-
-               if (val == 1)
-                       break;
-
+               goto unlock;
+       }
+       switch (val) {
+       case MDB_RTR_TYPE_DISABLED:
+               p->multicast_router = MDB_RTR_TYPE_DISABLED;
+               __del_port_router(p);
+               del_timer(&p->multicast_router_timer);
+               break;
+       case MDB_RTR_TYPE_TEMP_QUERY:
+               p->multicast_router = MDB_RTR_TYPE_TEMP_QUERY;
+               __del_port_router(p);
+               break;
+       case MDB_RTR_TYPE_PERM:
+               p->multicast_router = MDB_RTR_TYPE_PERM;
                del_timer(&p->multicast_router_timer);
-
-               if (val == 0)
-                       break;
-
                br_multicast_add_router(br, p);
                break;
+       case MDB_RTR_TYPE_TEMP:
+               p->multicast_router = MDB_RTR_TYPE_TEMP;
+               br_multicast_mark_router(br, p);
+               break;
+       default:
+               goto unlock;
        }
-
+       err = 0;
+unlock:
        spin_unlock(&br->multicast_lock);
 
        return err;
index 7ddbe7ec81d61d4971b919c5988e7bed93436dec..44114a94c576ac8bc55aed54d3b3a22dbf0a4301 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/addrconf.h>
 #include <net/route.h>
 #include <net/netfilter/br_netfilter.h>
+#include <net/netns/generic.h>
 
 #include <asm/uaccess.h>
 #include "br_private.h"
 #include <linux/sysctl.h>
 #endif
 
+static int brnf_net_id __read_mostly;
+
+struct brnf_net {
+       bool enabled;
+};
+
 #ifdef CONFIG_SYSCTL
 static struct ctl_table_header *brnf_sysctl_header;
 static int brnf_call_iptables __read_mostly = 1;
@@ -938,6 +945,53 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
        },
 };
 
+static int brnf_device_event(struct notifier_block *unused, unsigned long event,
+                            void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct brnf_net *brnet;
+       struct net *net;
+       int ret;
+
+       if (event != NETDEV_REGISTER || !(dev->priv_flags & IFF_EBRIDGE))
+               return NOTIFY_DONE;
+
+       ASSERT_RTNL();
+
+       net = dev_net(dev);
+       brnet = net_generic(net, brnf_net_id);
+       if (brnet->enabled)
+               return NOTIFY_OK;
+
+       ret = nf_register_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
+       if (ret)
+               return NOTIFY_BAD;
+
+       brnet->enabled = true;
+       return NOTIFY_OK;
+}
+
+static void __net_exit brnf_exit_net(struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       if (!brnet->enabled)
+               return;
+
+       nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
+       brnet->enabled = false;
+}
+
+static struct pernet_operations brnf_net_ops __read_mostly = {
+       .exit = brnf_exit_net,
+       .id   = &brnf_net_id,
+       .size = sizeof(struct brnf_net),
+};
+
+static struct notifier_block brnf_notifier __read_mostly = {
+       .notifier_call = brnf_device_event,
+};
+
 #ifdef CONFIG_SYSCTL
 static
 int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
@@ -1003,16 +1057,23 @@ static int __init br_netfilter_init(void)
 {
        int ret;
 
-       ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+       ret = register_pernet_subsys(&brnf_net_ops);
        if (ret < 0)
                return ret;
 
+       ret = register_netdevice_notifier(&brnf_notifier);
+       if (ret < 0) {
+               unregister_pernet_subsys(&brnf_net_ops);
+               return ret;
+       }
+
 #ifdef CONFIG_SYSCTL
        brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
        if (brnf_sysctl_header == NULL) {
                printk(KERN_WARNING
                       "br_netfilter: can't register to sysctl.\n");
-               nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+               unregister_netdevice_notifier(&brnf_notifier);
+               unregister_pernet_subsys(&brnf_net_ops);
                return -ENOMEM;
        }
 #endif
@@ -1024,7 +1085,8 @@ static int __init br_netfilter_init(void)
 static void __exit br_netfilter_fini(void)
 {
        RCU_INIT_POINTER(nf_br_ops, NULL);
-       nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+       unregister_netdevice_notifier(&brnf_notifier);
+       unregister_pernet_subsys(&brnf_net_ops);
 #ifdef CONFIG_SYSCTL
        unregister_net_sysctl_table(brnf_sysctl_header);
 #endif
index 40197ff8918abab433c563dd92186479652ed84d..e9c635eae24de298ac028b8d3d80034dd6d93391 100644 (file)
@@ -598,7 +598,6 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state)
                return -ENETDOWN;
 
        br_set_state(p, state);
-       br_log_state(p);
        br_port_state_selection(p->br);
        return 0;
 }
index 302ab0a43725845c5ec7a1ffb30db59bfaf16db5..1b5d145dfcbf28beb5d7dfd3a28fcdaf919e26aa 100644 (file)
@@ -900,7 +900,6 @@ static inline void br_nf_core_fini(void) {}
 #endif
 
 /* br_stp.c */
-void br_log_state(const struct net_bridge_port *p);
 void br_set_state(struct net_bridge_port *p, unsigned int state);
 struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no);
 void br_init_port(struct net_bridge_port *p);
index b3cca126b103d24ddaee0b13d7eb73f4e8617f3a..e23449094188c084b061136a776597b6607e242a 100644 (file)
@@ -30,13 +30,6 @@ static const char *const br_port_state_names[] = {
        [BR_STATE_BLOCKING] = "blocking",
 };
 
-void br_log_state(const struct net_bridge_port *p)
-{
-       br_info(p->br, "port %u(%s) entered %s state\n",
-               (unsigned int) p->port_no, p->dev->name,
-               br_port_state_names[p->state]);
-}
-
 void br_set_state(struct net_bridge_port *p, unsigned int state)
 {
        struct switchdev_attr attr = {
@@ -52,6 +45,10 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
        if (err && err != -EOPNOTSUPP)
                br_warn(p->br, "error setting offload STP state on port %u(%s)\n",
                                (unsigned int) p->port_no, p->dev->name);
+       else
+               br_info(p->br, "port %u(%s) entered %s state\n",
+                               (unsigned int) p->port_no, p->dev->name,
+                               br_port_state_names[p->state]);
 }
 
 /* called under bridge lock */
@@ -126,7 +123,6 @@ static void br_root_port_block(const struct net_bridge *br,
                  (unsigned int) p->port_no, p->dev->name);
 
        br_set_state(p, BR_STATE_LISTENING);
-       br_log_state(p);
        br_ifinfo_notify(RTM_NEWLINK, p);
 
        if (br->forward_delay > 0)
@@ -407,7 +403,6 @@ static void br_make_blocking(struct net_bridge_port *p)
                        br_topology_change_detection(p->br);
 
                br_set_state(p, BR_STATE_BLOCKING);
-               br_log_state(p);
                br_ifinfo_notify(RTM_NEWLINK, p);
 
                del_timer(&p->forward_delay_timer);
@@ -431,7 +426,6 @@ static void br_make_forwarding(struct net_bridge_port *p)
        else
                br_set_state(p, BR_STATE_LEARNING);
 
-       br_log_state(p);
        br_ifinfo_notify(RTM_NEWLINK, p);
 
        if (br->forward_delay != 0)
@@ -568,6 +562,14 @@ int br_set_max_age(struct net_bridge *br, unsigned long val)
 
 }
 
+/* Set time interval that dynamic forwarding entries live
+ * For pure software bridge, allow values outside the 802.1
+ * standard specification for special cases:
+ *  0 - entry never ages (all permanant)
+ *  1 - entry disappears (no persistance)
+ *
+ * Offloaded switch entries maybe more restrictive
+ */
 int br_set_ageing_time(struct net_bridge *br, u32 ageing_time)
 {
        struct switchdev_attr attr = {
@@ -579,9 +581,6 @@ int br_set_ageing_time(struct net_bridge *br, u32 ageing_time)
        unsigned long t = clock_t_to_jiffies(ageing_time);
        int err;
 
-       if (t < BR_MIN_AGEING_TIME || t > BR_MAX_AGEING_TIME)
-               return -ERANGE;
-
        err = switchdev_port_attr_set(br->dev, &attr);
        if (err)
                return err;
index a31ac6ad76a22344e106e90ca9d943055b95ea1b..984d462630072a8a013a3ba041304564e1bd83f6 100644 (file)
@@ -102,7 +102,6 @@ void br_stp_enable_port(struct net_bridge_port *p)
 {
        br_init_port(p);
        br_port_state_selection(p->br);
-       br_log_state(p);
        br_ifinfo_notify(RTM_NEWLINK, p);
 }
 
@@ -118,7 +117,6 @@ void br_stp_disable_port(struct net_bridge_port *p)
        p->topology_change_ack = 0;
        p->config_pending = 0;
 
-       br_log_state(p);
        br_ifinfo_notify(RTM_NEWLINK, p);
 
        del_timer(&p->message_age_timer);
index 5f0f5af0ec35bf8c216935713a9d5f803456e1ab..da058b85aa2260c6148034917e96944eefd85e28 100644 (file)
@@ -98,7 +98,6 @@ static void br_forward_delay_timer_expired(unsigned long arg)
                        br_topology_change_detection(br);
                netif_carrier_on(br->dev);
        }
-       br_log_state(p);
        rcu_read_lock();
        br_ifinfo_notify(RTM_NEWLINK, p);
        rcu_read_unlock();
index 85e43af4af7a5b2956b149479725fce96c343439..9309bb4f2a5b240edcea6f9c3a4a45d2c6413874 100644 (file)
@@ -955,6 +955,13 @@ err_rhtbl:
  */
 int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
 {
+       struct switchdev_obj_port_vlan v = {
+               .obj.orig_dev = port->dev,
+               .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
+               .flags = flags,
+               .vid_begin = vid,
+               .vid_end = vid,
+       };
        struct net_bridge_vlan *vlan;
        int ret;
 
@@ -962,6 +969,10 @@ int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
 
        vlan = br_vlan_find(nbp_vlan_group(port), vid);
        if (vlan) {
+               /* Pass the flags to the hardware bridge */
+               ret = switchdev_port_obj_add(port->dev, &v.obj);
+               if (ret && ret != -EOPNOTSUPP)
+                       return ret;
                __vlan_add_flags(vlan, flags);
                return 0;
        }
index fdba3d9fbff3bac00b8acc68d1eaeda2e492e820..adc8d7221dbbc135fa3506a713c70c1130c51ad6 100644 (file)
@@ -48,6 +48,7 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb,
        struct iphdr *niph;
        const struct tcphdr *oth;
        struct tcphdr _oth;
+       struct net *net = sock_net(oldskb->sk);
 
        if (!nft_bridge_iphdr_validate(oldskb))
                return;
@@ -63,9 +64,9 @@ static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
-                                  sysctl_ip_default_ttl);
+                                  net->ipv4.sysctl_ip_default_ttl);
        nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
-       niph->ttl       = sysctl_ip_default_ttl;
+       niph->ttl       = net->ipv4.sysctl_ip_default_ttl;
        niph->tot_len   = htons(nskb->len);
        ip_send_check(niph);
 
@@ -85,6 +86,7 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb,
        void *payload;
        __wsum csum;
        u8 proto;
+       struct net *net = sock_net(oldskb->sk);
 
        if (oldskb->csum_bad || !nft_bridge_iphdr_validate(oldskb))
                return;
@@ -119,7 +121,7 @@ static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb,
 
        skb_reserve(nskb, LL_MAX_HEADER);
        niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
-                                  sysctl_ip_default_ttl);
+                                  net->ipv4.sysctl_ip_default_ttl);
 
        skb_reset_transport_header(nskb);
        icmph = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
index 61d7617d924912347325a5db483172794e6df33a..b82440e1fcb4f3fe8a25e121416360cc23f8fada 100644 (file)
@@ -159,7 +159,7 @@ static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
                tmppkt = NULL;
 
                /* Verify that length is correct */
-               err = EPROTO;
+               err = -EPROTO;
                if (rfml->pdu_size != cfpkt_getlen(pkt) - RFM_HEAD_SIZE + 1)
                        goto out;
        }
index 393bfb22d5bbafd83c20f5953b98c6709b637452..5fcfb98f309efb5018f84628902cd1711fc36705 100644 (file)
@@ -403,6 +403,7 @@ static int is_out(const struct crush_map *map,
  * @local_retries: localized retries
  * @local_fallback_retries: localized fallback retries
  * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose)
+ * @stable: stable mode starts rep=0 in the recursive call for all replicas
  * @vary_r: pass r to recursive calls
  * @out2: second output vector for leaf items (if @recurse_to_leaf)
  * @parent_r: r value passed from the parent
@@ -419,6 +420,7 @@ static int crush_choose_firstn(const struct crush_map *map,
                               unsigned int local_fallback_retries,
                               int recurse_to_leaf,
                               unsigned int vary_r,
+                              unsigned int stable,
                               int *out2,
                               int parent_r)
 {
@@ -433,13 +435,13 @@ static int crush_choose_firstn(const struct crush_map *map,
        int collide, reject;
        int count = out_size;
 
-       dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d tries %d recurse_tries %d local_retries %d local_fallback_retries %d parent_r %d\n",
+       dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d tries %d recurse_tries %d local_retries %d local_fallback_retries %d parent_r %d stable %d\n",
                recurse_to_leaf ? "_LEAF" : "",
                bucket->id, x, outpos, numrep,
                tries, recurse_tries, local_retries, local_fallback_retries,
-               parent_r);
+               parent_r, stable);
 
-       for (rep = outpos; rep < numrep && count > 0 ; rep++) {
+       for (rep = stable ? 0 : outpos; rep < numrep && count > 0 ; rep++) {
                /* keep trying until we get a non-out, non-colliding item */
                ftotal = 0;
                skip_rep = 0;
@@ -512,13 +514,14 @@ static int crush_choose_firstn(const struct crush_map *map,
                                                if (crush_choose_firstn(map,
                                                         map->buckets[-1-item],
                                                         weight, weight_max,
-                                                        x, outpos+1, 0,
+                                                        x, stable ? 1 : outpos+1, 0,
                                                         out2, outpos, count,
                                                         recurse_tries, 0,
                                                         local_retries,
                                                         local_fallback_retries,
                                                         0,
                                                         vary_r,
+                                                        stable,
                                                         NULL,
                                                         sub_r) <= outpos)
                                                        /* didn't get leaf */
@@ -816,6 +819,7 @@ int crush_do_rule(const struct crush_map *map,
        int choose_local_fallback_retries = map->choose_local_fallback_tries;
 
        int vary_r = map->chooseleaf_vary_r;
+       int stable = map->chooseleaf_stable;
 
        if ((__u32)ruleno >= map->max_rules) {
                dprintk(" bad ruleno %d\n", ruleno);
@@ -835,7 +839,8 @@ int crush_do_rule(const struct crush_map *map,
                case CRUSH_RULE_TAKE:
                        if ((curstep->arg1 >= 0 &&
                             curstep->arg1 < map->max_devices) ||
-                           (-1-curstep->arg1 < map->max_buckets &&
+                           (-1-curstep->arg1 >= 0 &&
+                            -1-curstep->arg1 < map->max_buckets &&
                             map->buckets[-1-curstep->arg1])) {
                                w[0] = curstep->arg1;
                                wsize = 1;
@@ -869,6 +874,11 @@ int crush_do_rule(const struct crush_map *map,
                                vary_r = curstep->arg1;
                        break;
 
+               case CRUSH_RULE_SET_CHOOSELEAF_STABLE:
+                       if (curstep->arg1 >= 0)
+                               stable = curstep->arg1;
+                       break;
+
                case CRUSH_RULE_CHOOSELEAF_FIRSTN:
                case CRUSH_RULE_CHOOSE_FIRSTN:
                        firstn = 1;
@@ -888,6 +898,7 @@ int crush_do_rule(const struct crush_map *map,
                        osize = 0;
 
                        for (i = 0; i < wsize; i++) {
+                               int bno;
                                /*
                                 * see CRUSH_N, CRUSH_N_MINUS macros.
                                 * basically, numrep <= 0 means relative to
@@ -900,6 +911,13 @@ int crush_do_rule(const struct crush_map *map,
                                                continue;
                                }
                                j = 0;
+                               /* make sure bucket id is valid */
+                               bno = -1 - w[i];
+                               if (bno < 0 || bno >= map->max_buckets) {
+                                       /* w[i] is probably CRUSH_ITEM_NONE */
+                                       dprintk("  bad w[i] %d\n", w[i]);
+                                       continue;
+                               }
                                if (firstn) {
                                        int recurse_tries;
                                        if (choose_leaf_tries)
@@ -911,7 +929,7 @@ int crush_do_rule(const struct crush_map *map,
                                                recurse_tries = choose_tries;
                                        osize += crush_choose_firstn(
                                                map,
-                                               map->buckets[-1-w[i]],
+                                               map->buckets[bno],
                                                weight, weight_max,
                                                x, numrep,
                                                curstep->arg2,
@@ -923,6 +941,7 @@ int crush_do_rule(const struct crush_map *map,
                                                choose_local_fallback_retries,
                                                recurse_to_leaf,
                                                vary_r,
+                                               stable,
                                                c+osize,
                                                0);
                                } else {
@@ -930,7 +949,7 @@ int crush_do_rule(const struct crush_map *map,
                                                    numrep : (result_max-osize));
                                        crush_choose_indep(
                                                map,
-                                               map->buckets[-1-w[i]],
+                                               map->buckets[bno],
                                                weight, weight_max,
                                                x, out_size, numrep,
                                                curstep->arg2,
index 9cfedf565f5b236b5ede7974466cf62af6ad995c..9382619a405b8da854c82b041a137a670399567f 100644 (file)
@@ -1197,6 +1197,13 @@ static bool ceph_msg_data_advance(struct ceph_msg_data_cursor *cursor,
        return new_piece;
 }
 
+static size_t sizeof_footer(struct ceph_connection *con)
+{
+       return (con->peer_features & CEPH_FEATURE_MSG_AUTH) ?
+           sizeof(struct ceph_msg_footer) :
+           sizeof(struct ceph_msg_footer_old);
+}
+
 static void prepare_message_data(struct ceph_msg *msg, u32 data_len)
 {
        BUG_ON(!msg);
@@ -2335,9 +2342,9 @@ static int read_partial_message(struct ceph_connection *con)
                        ceph_pr_addr(&con->peer_addr.in_addr),
                        seq, con->in_seq + 1);
                con->in_base_pos = -front_len - middle_len - data_len -
-                       sizeof(m->footer);
+                       sizeof_footer(con);
                con->in_tag = CEPH_MSGR_TAG_READY;
-               return 0;
+               return 1;
        } else if ((s64)seq - (s64)con->in_seq > 1) {
                pr_err("read_partial_message bad seq %lld expected %lld\n",
                       seq, con->in_seq + 1);
@@ -2360,10 +2367,10 @@ static int read_partial_message(struct ceph_connection *con)
                        /* skip this message */
                        dout("alloc_msg said skip message\n");
                        con->in_base_pos = -front_len - middle_len - data_len -
-                               sizeof(m->footer);
+                               sizeof_footer(con);
                        con->in_tag = CEPH_MSGR_TAG_READY;
                        con->in_seq++;
-                       return 0;
+                       return 1;
                }
 
                BUG_ON(!con->in_msg);
index f8f235930d887adf1df94314b18c719638328df0..5bc053778feddd0e35fe73480317be25345da61c 100644 (file)
@@ -1770,6 +1770,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
        u32 osdmap_epoch;
        int already_completed;
        u32 bytes;
+       u8 decode_redir;
        unsigned int i;
 
        tid = le64_to_cpu(msg->hdr.tid);
@@ -1841,6 +1842,15 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                p += 8 + 4; /* skip replay_version */
                p += 8; /* skip user_version */
 
+               if (le16_to_cpu(msg->hdr.version) >= 7)
+                       ceph_decode_8_safe(&p, end, decode_redir, bad_put);
+               else
+                       decode_redir = 1;
+       } else {
+               decode_redir = 0;
+       }
+
+       if (decode_redir) {
                err = ceph_redirect_decode(&p, end, &redir);
                if (err)
                        goto bad_put;
@@ -2843,8 +2853,8 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        mutex_lock(&osdc->request_mutex);
        req = __lookup_request(osdc, tid);
        if (!req) {
-               pr_warn("%s osd%d tid %llu unknown, skipping\n",
-                       __func__, osd->o_osd, tid);
+               dout("%s osd%d tid %llu unknown, skipping\n", __func__,
+                    osd->o_osd, tid);
                m = NULL;
                *skip = 1;
                goto out;
index 7d8f581d9f1f7987b8d7051160c34f42ad2f5e73..243574c8cf33807fcaf9374530358f1e44080764 100644 (file)
@@ -342,23 +342,32 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
         c->choose_local_tries = ceph_decode_32(p);
         c->choose_local_fallback_tries =  ceph_decode_32(p);
         c->choose_total_tries = ceph_decode_32(p);
-        dout("crush decode tunable choose_local_tries = %d",
+        dout("crush decode tunable choose_local_tries = %d\n",
              c->choose_local_tries);
-        dout("crush decode tunable choose_local_fallback_tries = %d",
+        dout("crush decode tunable choose_local_fallback_tries = %d\n",
              c->choose_local_fallback_tries);
-        dout("crush decode tunable choose_total_tries = %d",
+        dout("crush decode tunable choose_total_tries = %d\n",
              c->choose_total_tries);
 
        ceph_decode_need(p, end, sizeof(u32), done);
        c->chooseleaf_descend_once = ceph_decode_32(p);
-       dout("crush decode tunable chooseleaf_descend_once = %d",
+       dout("crush decode tunable chooseleaf_descend_once = %d\n",
             c->chooseleaf_descend_once);
 
        ceph_decode_need(p, end, sizeof(u8), done);
        c->chooseleaf_vary_r = ceph_decode_8(p);
-       dout("crush decode tunable chooseleaf_vary_r = %d",
+       dout("crush decode tunable chooseleaf_vary_r = %d\n",
             c->chooseleaf_vary_r);
 
+       /* skip straw_calc_version, allowed_bucket_algs */
+       ceph_decode_need(p, end, sizeof(u8) + sizeof(u32), done);
+       *p += sizeof(u8) + sizeof(u32);
+
+       ceph_decode_need(p, end, sizeof(u8), done);
+       c->chooseleaf_stable = ceph_decode_8(p);
+       dout("crush decode tunable chooseleaf_stable = %d\n",
+            c->chooseleaf_stable);
+
 done:
        dout("crush_decode success\n");
        return c;
index 0b835de04de3d8bb25361eb73e711278f27a1b49..014422e2561fcb19bb1c3fd7bc9cf8989aa1a7dd 100644 (file)
@@ -24,3 +24,5 @@ obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o
 obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
 obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
 obj-$(CONFIG_LWTUNNEL) += lwtunnel.o
+obj-$(CONFIG_DST_CACHE) += dst_cache.o
+obj-$(CONFIG_NET_DEVLINK) += devlink.o
index 3f4071a84a03fb018fb97d881d55eee68a015326..edb7179bc0517af0bde9e917f7b440ce9f8a9409 100644 (file)
@@ -5389,12 +5389,12 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter)
 {
        struct netdev_adjacent *lower;
 
-       lower = list_entry((*iter)->next, struct netdev_adjacent, list);
+       lower = list_entry(*iter, struct netdev_adjacent, list);
 
        if (&lower->list == &dev->adj_list.lower)
                return NULL;
 
-       *iter = &lower->list;
+       *iter = lower->list.next;
 
        return lower->dev;
 }
@@ -7440,8 +7440,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
        setup(dev);
 
-       if (!dev->tx_queue_len)
+       if (!dev->tx_queue_len) {
                dev->priv_flags |= IFF_NO_QUEUE;
+               dev->tx_queue_len = 1;
+       }
 
        dev->num_tx_queues = txqs;
        dev->real_num_tx_queues = txqs;
diff --git a/net/core/devlink.c b/net/core/devlink.c
new file mode 100644 (file)
index 0000000..590fa56
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * net/core/devlink.c - Network physical/parent device Netlink interface
+ *
+ * Heavily inspired by net/wireless/
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <rdma/ib_verbs.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+#include <net/rtnetlink.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <net/devlink.h>
+
+static LIST_HEAD(devlink_list);
+
+/* devlink_mutex
+ *
+ * An overall lock guarding every operation coming from userspace.
+ * It also guards devlink devices list and it is taken when
+ * driver registers/unregisters it.
+ */
+static DEFINE_MUTEX(devlink_mutex);
+
+/* devlink_port_mutex
+ *
+ * Shared lock to guard lists of ports in all devlink devices.
+ */
+static DEFINE_MUTEX(devlink_port_mutex);
+
+static struct net *devlink_net(const struct devlink *devlink)
+{
+       return read_pnet(&devlink->_net);
+}
+
+static void devlink_net_set(struct devlink *devlink, struct net *net)
+{
+       write_pnet(&devlink->_net, net);
+}
+
+static struct devlink *devlink_get_from_attrs(struct net *net,
+                                             struct nlattr **attrs)
+{
+       struct devlink *devlink;
+       char *busname;
+       char *devname;
+
+       if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
+               return ERR_PTR(-EINVAL);
+
+       busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
+       devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
+
+       list_for_each_entry(devlink, &devlink_list, list) {
+               if (strcmp(devlink->dev->bus->name, busname) == 0 &&
+                   strcmp(dev_name(devlink->dev), devname) == 0 &&
+                   net_eq(devlink_net(devlink), net))
+                       return devlink;
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
+static struct devlink *devlink_get_from_info(struct genl_info *info)
+{
+       return devlink_get_from_attrs(genl_info_net(info), info->attrs);
+}
+
+static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
+                                                     int port_index)
+{
+       struct devlink_port *devlink_port;
+
+       list_for_each_entry(devlink_port, &devlink->port_list, list) {
+               if (devlink_port->index == port_index)
+                       return devlink_port;
+       }
+       return NULL;
+}
+
+static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
+{
+       return devlink_port_get_by_index(devlink, port_index);
+}
+
+static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
+                                                       struct nlattr **attrs)
+{
+       if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
+               u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
+               struct devlink_port *devlink_port;
+
+               devlink_port = devlink_port_get_by_index(devlink, port_index);
+               if (!devlink_port)
+                       return ERR_PTR(-ENODEV);
+               return devlink_port;
+       }
+       return ERR_PTR(-EINVAL);
+}
+
+static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
+                                                      struct genl_info *info)
+{
+       return devlink_port_get_from_attrs(devlink, info->attrs);
+}
+
+#define DEVLINK_NL_FLAG_NEED_PORT      BIT(0)
+
+static int devlink_nl_pre_doit(const struct genl_ops *ops,
+                              struct sk_buff *skb, struct genl_info *info)
+{
+       struct devlink *devlink;
+
+       mutex_lock(&devlink_mutex);
+       devlink = devlink_get_from_info(info);
+       if (IS_ERR(devlink)) {
+               mutex_unlock(&devlink_mutex);
+               return PTR_ERR(devlink);
+       }
+       info->user_ptr[0] = devlink;
+       if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
+               struct devlink_port *devlink_port;
+
+               mutex_lock(&devlink_port_mutex);
+               devlink_port = devlink_port_get_from_info(devlink, info);
+               if (IS_ERR(devlink_port)) {
+                       mutex_unlock(&devlink_port_mutex);
+                       mutex_unlock(&devlink_mutex);
+                       return PTR_ERR(devlink_port);
+               }
+               info->user_ptr[1] = devlink_port;
+       }
+       return 0;
+}
+
+static void devlink_nl_post_doit(const struct genl_ops *ops,
+                                struct sk_buff *skb, struct genl_info *info)
+{
+       if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT)
+               mutex_unlock(&devlink_port_mutex);
+       mutex_unlock(&devlink_mutex);
+}
+
+static struct genl_family devlink_nl_family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = DEVLINK_GENL_NAME,
+       .version        = DEVLINK_GENL_VERSION,
+       .maxattr        = DEVLINK_ATTR_MAX,
+       .netnsok        = true,
+       .pre_doit       = devlink_nl_pre_doit,
+       .post_doit      = devlink_nl_post_doit,
+};
+
+enum devlink_multicast_groups {
+       DEVLINK_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group devlink_nl_mcgrps[] = {
+       [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
+};
+
+static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
+{
+       if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
+               return -EMSGSIZE;
+       if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
+               return -EMSGSIZE;
+       return 0;
+}
+
+static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
+                          enum devlink_command cmd, u32 portid,
+                          u32 seq, int flags)
+{
+       void *hdr;
+
+       hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       if (devlink_nl_put_handle(msg, devlink))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
+{
+       struct sk_buff *msg;
+       int err;
+
+       WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
+       if (err) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+                               msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
+                               struct devlink_port *devlink_port,
+                               enum devlink_command cmd, u32 portid,
+                               u32 seq, int flags)
+{
+       void *hdr;
+
+       hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       if (devlink_nl_put_handle(msg, devlink))
+               goto nla_put_failure;
+       if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
+               goto nla_put_failure;
+       if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
+               goto nla_put_failure;
+       if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
+           nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
+                       devlink_port->desired_type))
+               goto nla_put_failure;
+       if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
+               struct net_device *netdev = devlink_port->type_dev;
+
+               if (netdev &&
+                   (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
+                                netdev->ifindex) ||
+                    nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
+                                   netdev->name)))
+                       goto nla_put_failure;
+       }
+       if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
+               struct ib_device *ibdev = devlink_port->type_dev;
+
+               if (ibdev &&
+                   nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
+                                  ibdev->name))
+                       goto nla_put_failure;
+       }
+       if (devlink_port->split &&
+           nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
+                       devlink_port->split_group))
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static void devlink_port_notify(struct devlink_port *devlink_port,
+                               enum devlink_command cmd)
+{
+       struct devlink *devlink = devlink_port->devlink;
+       struct sk_buff *msg;
+       int err;
+
+       if (!devlink_port->registered)
+               return;
+
+       WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
+       if (err) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
+                               msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       struct sk_buff *msg;
+       int err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
+                             info->snd_portid, info->snd_seq, 0);
+       if (err) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
+                                    struct netlink_callback *cb)
+{
+       struct devlink *devlink;
+       int start = cb->args[0];
+       int idx = 0;
+       int err;
+
+       mutex_lock(&devlink_mutex);
+       list_for_each_entry(devlink, &devlink_list, list) {
+               if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+                       continue;
+               if (idx < start) {
+                       idx++;
+                       continue;
+               }
+               err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
+                                     NETLINK_CB(cb->skb).portid,
+                                     cb->nlh->nlmsg_seq, NLM_F_MULTI);
+               if (err)
+                       goto out;
+               idx++;
+       }
+out:
+       mutex_unlock(&devlink_mutex);
+
+       cb->args[0] = idx;
+       return msg->len;
+}
+
+static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
+                                       struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       struct devlink_port *devlink_port = info->user_ptr[1];
+       struct sk_buff *msg;
+       int err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       err = devlink_nl_port_fill(msg, devlink, devlink_port,
+                                  DEVLINK_CMD_PORT_NEW,
+                                  info->snd_portid, info->snd_seq, 0);
+       if (err) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
+                                         struct netlink_callback *cb)
+{
+       struct devlink *devlink;
+       struct devlink_port *devlink_port;
+       int start = cb->args[0];
+       int idx = 0;
+       int err;
+
+       mutex_lock(&devlink_mutex);
+       mutex_lock(&devlink_port_mutex);
+       list_for_each_entry(devlink, &devlink_list, list) {
+               if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+                       continue;
+               list_for_each_entry(devlink_port, &devlink->port_list, list) {
+                       if (idx < start) {
+                               idx++;
+                               continue;
+                       }
+                       err = devlink_nl_port_fill(msg, devlink, devlink_port,
+                                                  DEVLINK_CMD_NEW,
+                                                  NETLINK_CB(cb->skb).portid,
+                                                  cb->nlh->nlmsg_seq,
+                                                  NLM_F_MULTI);
+                       if (err)
+                               goto out;
+                       idx++;
+               }
+       }
+out:
+       mutex_unlock(&devlink_port_mutex);
+       mutex_unlock(&devlink_mutex);
+
+       cb->args[0] = idx;
+       return msg->len;
+}
+
+static int devlink_port_type_set(struct devlink *devlink,
+                                struct devlink_port *devlink_port,
+                                enum devlink_port_type port_type)
+
+{
+       int err;
+
+       if (devlink->ops && devlink->ops->port_type_set) {
+               if (port_type == DEVLINK_PORT_TYPE_NOTSET)
+                       return -EINVAL;
+               err = devlink->ops->port_type_set(devlink_port, port_type);
+               if (err)
+                       return err;
+               devlink_port->desired_type = port_type;
+               devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+               return 0;
+       }
+       return -EOPNOTSUPP;
+}
+
+static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
+                                       struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       struct devlink_port *devlink_port = info->user_ptr[1];
+       int err;
+
+       if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
+               enum devlink_port_type port_type;
+
+               port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
+               err = devlink_port_type_set(devlink, devlink_port, port_type);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int devlink_port_split(struct devlink *devlink,
+                             u32 port_index, u32 count)
+
+{
+       if (devlink->ops && devlink->ops->port_split)
+               return devlink->ops->port_split(devlink, port_index, count);
+       return -EOPNOTSUPP;
+}
+
+static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
+                                         struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       u32 port_index;
+       u32 count;
+
+       if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
+           !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
+               return -EINVAL;
+
+       port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
+       count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
+       return devlink_port_split(devlink, port_index, count);
+}
+
+static int devlink_port_unsplit(struct devlink *devlink, u32 port_index)
+
+{
+       if (devlink->ops && devlink->ops->port_unsplit)
+               return devlink->ops->port_unsplit(devlink, port_index);
+       return -EOPNOTSUPP;
+}
+
+static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
+                                           struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       u32 port_index;
+
+       if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
+               return -EINVAL;
+
+       port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
+       return devlink_port_unsplit(devlink, port_index);
+}
+
+static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
+       [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
+       [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
+       [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
+       [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
+       [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
+};
+
+static const struct genl_ops devlink_nl_ops[] = {
+       {
+               .cmd = DEVLINK_CMD_GET,
+               .doit = devlink_nl_cmd_get_doit,
+               .dumpit = devlink_nl_cmd_get_dumpit,
+               .policy = devlink_nl_policy,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_GET,
+               .doit = devlink_nl_cmd_port_get_doit,
+               .dumpit = devlink_nl_cmd_port_get_dumpit,
+               .policy = devlink_nl_policy,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_SET,
+               .doit = devlink_nl_cmd_port_set_doit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_SPLIT,
+               .doit = devlink_nl_cmd_port_split_doit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_UNSPLIT,
+               .doit = devlink_nl_cmd_port_unsplit_doit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+/**
+ *     devlink_alloc - Allocate new devlink instance resources
+ *
+ *     @ops: ops
+ *     @priv_size: size of user private data
+ *
+ *     Allocate new devlink instance resources, including devlink index
+ *     and name.
+ */
+struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
+{
+       struct devlink *devlink;
+
+       devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
+       if (!devlink)
+               return NULL;
+       devlink->ops = ops;
+       devlink_net_set(devlink, &init_net);
+       INIT_LIST_HEAD(&devlink->port_list);
+       return devlink;
+}
+EXPORT_SYMBOL_GPL(devlink_alloc);
+
+/**
+ *     devlink_register - Register devlink instance
+ *
+ *     @devlink: devlink
+ */
+int devlink_register(struct devlink *devlink, struct device *dev)
+{
+       mutex_lock(&devlink_mutex);
+       devlink->dev = dev;
+       list_add_tail(&devlink->list, &devlink_list);
+       devlink_notify(devlink, DEVLINK_CMD_NEW);
+       mutex_unlock(&devlink_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devlink_register);
+
+/**
+ *     devlink_unregister - Unregister devlink instance
+ *
+ *     @devlink: devlink
+ */
+void devlink_unregister(struct devlink *devlink)
+{
+       mutex_lock(&devlink_mutex);
+       devlink_notify(devlink, DEVLINK_CMD_DEL);
+       list_del(&devlink->list);
+       mutex_unlock(&devlink_mutex);
+}
+EXPORT_SYMBOL_GPL(devlink_unregister);
+
+/**
+ *     devlink_free - Free devlink instance resources
+ *
+ *     @devlink: devlink
+ */
+void devlink_free(struct devlink *devlink)
+{
+       kfree(devlink);
+}
+EXPORT_SYMBOL_GPL(devlink_free);
+
+/**
+ *     devlink_port_register - Register devlink port
+ *
+ *     @devlink: devlink
+ *     @devlink_port: devlink port
+ *     @port_index
+ *
+ *     Register devlink port with provided port index. User can use
+ *     any indexing, even hw-related one. devlink_port structure
+ *     is convenient to be embedded inside user driver private structure.
+ *     Note that the caller should take care of zeroing the devlink_port
+ *     structure.
+ */
+int devlink_port_register(struct devlink *devlink,
+                         struct devlink_port *devlink_port,
+                         unsigned int port_index)
+{
+       mutex_lock(&devlink_port_mutex);
+       if (devlink_port_index_exists(devlink, port_index)) {
+               mutex_unlock(&devlink_port_mutex);
+               return -EEXIST;
+       }
+       devlink_port->devlink = devlink;
+       devlink_port->index = port_index;
+       devlink_port->type = DEVLINK_PORT_TYPE_NOTSET;
+       devlink_port->registered = true;
+       list_add_tail(&devlink_port->list, &devlink->port_list);
+       mutex_unlock(&devlink_port_mutex);
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devlink_port_register);
+
+/**
+ *     devlink_port_unregister - Unregister devlink port
+ *
+ *     @devlink_port: devlink port
+ */
+void devlink_port_unregister(struct devlink_port *devlink_port)
+{
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
+       mutex_lock(&devlink_port_mutex);
+       list_del(&devlink_port->list);
+       mutex_unlock(&devlink_port_mutex);
+}
+EXPORT_SYMBOL_GPL(devlink_port_unregister);
+
+static void __devlink_port_type_set(struct devlink_port *devlink_port,
+                                   enum devlink_port_type type,
+                                   void *type_dev)
+{
+       devlink_port->type = type;
+       devlink_port->type_dev = type_dev;
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+}
+
+/**
+ *     devlink_port_type_eth_set - Set port type to Ethernet
+ *
+ *     @devlink_port: devlink port
+ *     @netdev: related netdevice
+ */
+void devlink_port_type_eth_set(struct devlink_port *devlink_port,
+                              struct net_device *netdev)
+{
+       return __devlink_port_type_set(devlink_port,
+                                      DEVLINK_PORT_TYPE_ETH, netdev);
+}
+EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
+
+/**
+ *     devlink_port_type_ib_set - Set port type to InfiniBand
+ *
+ *     @devlink_port: devlink port
+ *     @ibdev: related IB device
+ */
+void devlink_port_type_ib_set(struct devlink_port *devlink_port,
+                             struct ib_device *ibdev)
+{
+       return __devlink_port_type_set(devlink_port,
+                                      DEVLINK_PORT_TYPE_IB, ibdev);
+}
+EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
+
+/**
+ *     devlink_port_type_clear - Clear port type
+ *
+ *     @devlink_port: devlink port
+ */
+void devlink_port_type_clear(struct devlink_port *devlink_port)
+{
+       return __devlink_port_type_set(devlink_port,
+                                      DEVLINK_PORT_TYPE_NOTSET, NULL);
+}
+EXPORT_SYMBOL_GPL(devlink_port_type_clear);
+
+/**
+ *     devlink_port_split_set - Set port is split
+ *
+ *     @devlink_port: devlink port
+ *     @split_group: split group - identifies group split port is part of
+ */
+void devlink_port_split_set(struct devlink_port *devlink_port,
+                           u32 split_group)
+{
+       devlink_port->split = true;
+       devlink_port->split_group = split_group;
+       devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
+}
+EXPORT_SYMBOL_GPL(devlink_port_split_set);
+
+static int __init devlink_module_init(void)
+{
+       return genl_register_family_with_ops_groups(&devlink_nl_family,
+                                                   devlink_nl_ops,
+                                                   devlink_nl_mcgrps);
+}
+
+static void __exit devlink_module_exit(void)
+{
+       genl_unregister_family(&devlink_nl_family);
+}
+
+module_init(devlink_module_init);
+module_exit(devlink_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
+MODULE_DESCRIPTION("Network physical device Netlink interface");
+MODULE_ALIAS_GENL_FAMILY(DEVLINK_GENL_NAME);
index a1656e3b8d72a66ff56656284205129ecfd30b3e..b5cbbe07f78608aac0f48712160629be29a9b0a2 100644 (file)
@@ -265,7 +265,7 @@ again:
        lwtstate_put(dst->lwtstate);
 
        if (dst->flags & DST_METADATA)
-               kfree(dst);
+               metadata_dst_free((struct metadata_dst *)dst);
        else
                kmem_cache_free(dst->ops->kmem_cachep, dst);
 
@@ -395,6 +395,14 @@ struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags)
 }
 EXPORT_SYMBOL_GPL(metadata_dst_alloc);
 
+void metadata_dst_free(struct metadata_dst *md_dst)
+{
+#ifdef CONFIG_DST_CACHE
+       dst_cache_destroy(&md_dst->u.tun_info.dst_cache);
+#endif
+       kfree(md_dst);
+}
+
 struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags)
 {
        int cpu;
diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
new file mode 100644 (file)
index 0000000..3938f3f
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * net/core/dst_cache.c - dst entry cache
+ *
+ * Copyright (c) 2016 Paolo Abeni <pabeni@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <net/dst_cache.h>
+#include <net/route.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_fib.h>
+#endif
+#include <uapi/linux/in.h>
+
+struct dst_cache_pcpu {
+       unsigned long refresh_ts;
+       struct dst_entry *dst;
+       u32 cookie;
+       union {
+               struct in_addr in_saddr;
+               struct in6_addr in6_saddr;
+       };
+};
+
+void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
+                              struct dst_entry *dst, u32 cookie)
+{
+       dst_release(dst_cache->dst);
+       if (dst)
+               dst_hold(dst);
+
+       dst_cache->cookie = cookie;
+       dst_cache->dst = dst;
+}
+
+struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
+                                       struct dst_cache_pcpu *idst)
+{
+       struct dst_entry *dst;
+
+       dst = idst->dst;
+       if (!dst)
+               goto fail;
+
+       /* the cache already hold a dst reference; it can't go away */
+       dst_hold(dst);
+
+       if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) ||
+                    (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) {
+               dst_cache_per_cpu_dst_set(idst, NULL, 0);
+               dst_release(dst);
+               goto fail;
+       }
+       return dst;
+
+fail:
+       idst->refresh_ts = jiffies;
+       return NULL;
+}
+
+struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
+{
+       if (!dst_cache->cache)
+               return NULL;
+
+       return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
+}
+EXPORT_SYMBOL_GPL(dst_cache_get);
+
+struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
+{
+       struct dst_cache_pcpu *idst;
+       struct dst_entry *dst;
+
+       if (!dst_cache->cache)
+               return NULL;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst = dst_cache_per_cpu_get(dst_cache, idst);
+       if (!dst)
+               return NULL;
+
+       *saddr = idst->in_saddr.s_addr;
+       return container_of(dst, struct rtable, dst);
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip4);
+
+void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      __be32 saddr)
+{
+       struct dst_cache_pcpu *idst;
+
+       if (!dst_cache->cache)
+               return;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst_cache_per_cpu_dst_set(idst, dst, 0);
+       idst->in_saddr.s_addr = saddr;
+}
+EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
+
+#if IS_ENABLED(CONFIG_IPV6)
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+                      const struct in6_addr *addr)
+{
+       struct dst_cache_pcpu *idst;
+
+       if (!dst_cache->cache)
+               return;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst,
+                                 rt6_get_cookie((struct rt6_info *)dst));
+       idst->in6_saddr = *addr;
+}
+EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
+
+struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
+                                   struct in6_addr *saddr)
+{
+       struct dst_cache_pcpu *idst;
+       struct dst_entry *dst;
+
+       if (!dst_cache->cache)
+               return NULL;
+
+       idst = this_cpu_ptr(dst_cache->cache);
+       dst = dst_cache_per_cpu_get(dst_cache, idst);
+       if (!dst)
+               return NULL;
+
+       *saddr = idst->in6_saddr;
+       return dst;
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip6);
+#endif
+
+int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
+{
+       dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu,
+                                           gfp | __GFP_ZERO);
+       if (!dst_cache->cache)
+               return -ENOMEM;
+
+       dst_cache_reset(dst_cache);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dst_cache_init);
+
+void dst_cache_destroy(struct dst_cache *dst_cache)
+{
+       int i;
+
+       if (!dst_cache->cache)
+               return;
+
+       for_each_possible_cpu(i)
+               dst_release(per_cpu_ptr(dst_cache->cache, i)->dst);
+
+       free_percpu(dst_cache->cache);
+}
+EXPORT_SYMBOL_GPL(dst_cache_destroy);
index 453c803f1c8713da0138041e2b59534aae6b8206..2966cd0d7c934c50f0b5c49f10ac38deb288c1fd 100644 (file)
@@ -98,6 +98,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_RXALL_BIT] =            "rx-all",
        [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
        [NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
+       [NETIF_F_HW_TC_BIT] =            "hw-tc-offload",
 };
 
 static const char
@@ -386,43 +387,461 @@ static int __ethtool_set_flags(struct net_device *dev, u32 data)
        return 0;
 }
 
-int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static void convert_legacy_u32_to_link_mode(unsigned long *dst, u32 legacy_u32)
 {
+       bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
+       dst[0] = legacy_u32;
+}
+
+/* return false if src had higher bits set. lower bits always updated. */
+static bool convert_link_mode_to_legacy_u32(u32 *legacy_u32,
+                                           const unsigned long *src)
+{
+       bool retval = true;
+
+       /* TODO: following test will soon always be true */
+       if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
+               __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
+
+               bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
+               bitmap_fill(ext, 32);
+               bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
+               if (bitmap_intersects(ext, src,
+                                     __ETHTOOL_LINK_MODE_MASK_NBITS)) {
+                       /* src mask goes beyond bit 31 */
+                       retval = false;
+               }
+       }
+       *legacy_u32 = src[0];
+       return retval;
+}
+
+/* return false if legacy contained non-0 deprecated fields
+ * transceiver/maxtxpkt/maxrxpkt. rest of ksettings always updated
+ */
+static bool
+convert_legacy_settings_to_link_ksettings(
+       struct ethtool_link_ksettings *link_ksettings,
+       const struct ethtool_cmd *legacy_settings)
+{
+       bool retval = true;
+
+       memset(link_ksettings, 0, sizeof(*link_ksettings));
+
+       /* This is used to tell users that driver is still using these
+        * deprecated legacy fields, and they should not use
+        * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
+        */
+       if (legacy_settings->transceiver ||
+           legacy_settings->maxtxpkt ||
+           legacy_settings->maxrxpkt)
+               retval = false;
+
+       convert_legacy_u32_to_link_mode(
+               link_ksettings->link_modes.supported,
+               legacy_settings->supported);
+       convert_legacy_u32_to_link_mode(
+               link_ksettings->link_modes.advertising,
+               legacy_settings->advertising);
+       convert_legacy_u32_to_link_mode(
+               link_ksettings->link_modes.lp_advertising,
+               legacy_settings->lp_advertising);
+       link_ksettings->base.speed
+               = ethtool_cmd_speed(legacy_settings);
+       link_ksettings->base.duplex
+               = legacy_settings->duplex;
+       link_ksettings->base.port
+               = legacy_settings->port;
+       link_ksettings->base.phy_address
+               = legacy_settings->phy_address;
+       link_ksettings->base.autoneg
+               = legacy_settings->autoneg;
+       link_ksettings->base.mdio_support
+               = legacy_settings->mdio_support;
+       link_ksettings->base.eth_tp_mdix
+               = legacy_settings->eth_tp_mdix;
+       link_ksettings->base.eth_tp_mdix_ctrl
+               = legacy_settings->eth_tp_mdix_ctrl;
+       return retval;
+}
+
+/* return false if ksettings link modes had higher bits
+ * set. legacy_settings always updated (best effort)
+ */
+static bool
+convert_link_ksettings_to_legacy_settings(
+       struct ethtool_cmd *legacy_settings,
+       const struct ethtool_link_ksettings *link_ksettings)
+{
+       bool retval = true;
+
+       memset(legacy_settings, 0, sizeof(*legacy_settings));
+       /* this also clears the deprecated fields in legacy structure:
+        * __u8         transceiver;
+        * __u32        maxtxpkt;
+        * __u32        maxrxpkt;
+        */
+
+       retval &= convert_link_mode_to_legacy_u32(
+               &legacy_settings->supported,
+               link_ksettings->link_modes.supported);
+       retval &= convert_link_mode_to_legacy_u32(
+               &legacy_settings->advertising,
+               link_ksettings->link_modes.advertising);
+       retval &= convert_link_mode_to_legacy_u32(
+               &legacy_settings->lp_advertising,
+               link_ksettings->link_modes.lp_advertising);
+       ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
+       legacy_settings->duplex
+               = link_ksettings->base.duplex;
+       legacy_settings->port
+               = link_ksettings->base.port;
+       legacy_settings->phy_address
+               = link_ksettings->base.phy_address;
+       legacy_settings->autoneg
+               = link_ksettings->base.autoneg;
+       legacy_settings->mdio_support
+               = link_ksettings->base.mdio_support;
+       legacy_settings->eth_tp_mdix
+               = link_ksettings->base.eth_tp_mdix;
+       legacy_settings->eth_tp_mdix_ctrl
+               = link_ksettings->base.eth_tp_mdix_ctrl;
+       return retval;
+}
+
+/* number of 32-bit words to store the user's link mode bitmaps */
+#define __ETHTOOL_LINK_MODE_MASK_NU32                  \
+       DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
+
+/* layout of the struct passed from/to userland */
+struct ethtool_link_usettings {
+       struct ethtool_link_settings base;
+       struct {
+               __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
+               __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
+               __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
+       } link_modes;
+};
+
+/* Internal kernel helper to query a device ethtool_link_settings.
+ *
+ * Backward compatibility note: for compatibility with legacy drivers
+ * that implement only the ethtool_cmd API, this has to work with both
+ * drivers implementing get_link_ksettings API and drivers
+ * implementing get_settings API. When drivers implement get_settings
+ * and report ethtool_cmd deprecated fields
+ * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored
+ * because the resulting struct ethtool_link_settings does not report them.
+ */
+int __ethtool_get_link_ksettings(struct net_device *dev,
+                                struct ethtool_link_ksettings *link_ksettings)
+{
+       int err;
+       struct ethtool_cmd cmd;
+
        ASSERT_RTNL();
 
+       if (dev->ethtool_ops->get_link_ksettings) {
+               memset(link_ksettings, 0, sizeof(*link_ksettings));
+               return dev->ethtool_ops->get_link_ksettings(dev,
+                                                           link_ksettings);
+       }
+
+       /* driver doesn't support %ethtool_link_ksettings API. revert to
+        * legacy %ethtool_cmd API, unless it's not supported either.
+        * TODO: remove when ethtool_ops::get_settings disappears internally
+        */
        if (!dev->ethtool_ops->get_settings)
                return -EOPNOTSUPP;
 
-       memset(cmd, 0, sizeof(struct ethtool_cmd));
-       cmd->cmd = ETHTOOL_GSET;
-       return dev->ethtool_ops->get_settings(dev, cmd);
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cmd = ETHTOOL_GSET;
+       err = dev->ethtool_ops->get_settings(dev, &cmd);
+       if (err < 0)
+               return err;
+
+       /* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt
+        */
+       convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd);
+       return err;
 }
-EXPORT_SYMBOL(__ethtool_get_settings);
+EXPORT_SYMBOL(__ethtool_get_link_ksettings);
 
-static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+/* convert ethtool_link_usettings in user space to a kernel internal
+ * ethtool_link_ksettings. return 0 on success, errno on error.
+ */
+static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
+                                        const void __user *from)
 {
-       int err;
-       struct ethtool_cmd cmd;
+       struct ethtool_link_usettings link_usettings;
+
+       if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
+               return -EFAULT;
+
+       memcpy(&to->base, &link_usettings.base, sizeof(to->base));
+       bitmap_from_u32array(to->link_modes.supported,
+                            __ETHTOOL_LINK_MODE_MASK_NBITS,
+                            link_usettings.link_modes.supported,
+                            __ETHTOOL_LINK_MODE_MASK_NU32);
+       bitmap_from_u32array(to->link_modes.advertising,
+                            __ETHTOOL_LINK_MODE_MASK_NBITS,
+                            link_usettings.link_modes.advertising,
+                            __ETHTOOL_LINK_MODE_MASK_NU32);
+       bitmap_from_u32array(to->link_modes.lp_advertising,
+                            __ETHTOOL_LINK_MODE_MASK_NBITS,
+                            link_usettings.link_modes.lp_advertising,
+                            __ETHTOOL_LINK_MODE_MASK_NU32);
+
+       return 0;
+}
+
+/* convert a kernel internal ethtool_link_ksettings to
+ * ethtool_link_usettings in user space. return 0 on success, errno on
+ * error.
+ */
+static int
+store_link_ksettings_for_user(void __user *to,
+                             const struct ethtool_link_ksettings *from)
+{
+       struct ethtool_link_usettings link_usettings;
+
+       memcpy(&link_usettings.base, &from->base, sizeof(link_usettings));
+       bitmap_to_u32array(link_usettings.link_modes.supported,
+                          __ETHTOOL_LINK_MODE_MASK_NU32,
+                          from->link_modes.supported,
+                          __ETHTOOL_LINK_MODE_MASK_NBITS);
+       bitmap_to_u32array(link_usettings.link_modes.advertising,
+                          __ETHTOOL_LINK_MODE_MASK_NU32,
+                          from->link_modes.advertising,
+                          __ETHTOOL_LINK_MODE_MASK_NBITS);
+       bitmap_to_u32array(link_usettings.link_modes.lp_advertising,
+                          __ETHTOOL_LINK_MODE_MASK_NU32,
+                          from->link_modes.lp_advertising,
+                          __ETHTOOL_LINK_MODE_MASK_NBITS);
+
+       if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
+               return -EFAULT;
+
+       return 0;
+}
+
+/* Query device for its ethtool_link_settings.
+ *
+ * Backward compatibility note: this function must fail when driver
+ * does not implement ethtool::get_link_ksettings, even if legacy
+ * ethtool_ops::get_settings is implemented. This tells new versions
+ * of ethtool that they should use the legacy API %ETHTOOL_GSET for
+ * this driver, so that they can correctly access the ethtool_cmd
+ * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
+ * implements ethtool_ops::get_settings anymore.
+ */
+static int ethtool_get_link_ksettings(struct net_device *dev,
+                                     void __user *useraddr)
+{
+       int err = 0;
+       struct ethtool_link_ksettings link_ksettings;
 
-       err = __ethtool_get_settings(dev, &cmd);
+       ASSERT_RTNL();
+
+       if (!dev->ethtool_ops->get_link_ksettings)
+               return -EOPNOTSUPP;
+
+       /* handle bitmap nbits handshake */
+       if (copy_from_user(&link_ksettings.base, useraddr,
+                          sizeof(link_ksettings.base)))
+               return -EFAULT;
+
+       if (__ETHTOOL_LINK_MODE_MASK_NU32
+           != link_ksettings.base.link_mode_masks_nwords) {
+               /* wrong link mode nbits requested */
+               memset(&link_ksettings, 0, sizeof(link_ksettings));
+               /* keep cmd field reset to 0 */
+               /* send back number of words required as negative val */
+               compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
+                                  "need too many bits for link modes!");
+               link_ksettings.base.link_mode_masks_nwords
+                       = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);
+
+               /* copy the base fields back to user, not the link
+                * mode bitmaps
+                */
+               if (copy_to_user(useraddr, &link_ksettings.base,
+                                sizeof(link_ksettings.base)))
+                       return -EFAULT;
+
+               return 0;
+       }
+
+       /* handshake successful: user/kernel agree on
+        * link_mode_masks_nwords
+        */
+
+       memset(&link_ksettings, 0, sizeof(link_ksettings));
+       err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
        if (err < 0)
                return err;
 
+       /* make sure we tell the right values to user */
+       link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
+       link_ksettings.base.link_mode_masks_nwords
+               = __ETHTOOL_LINK_MODE_MASK_NU32;
+
+       return store_link_ksettings_for_user(useraddr, &link_ksettings);
+}
+
+/* Update device ethtool_link_settings.
+ *
+ * Backward compatibility note: this function must fail when driver
+ * does not implement ethtool::set_link_ksettings, even if legacy
+ * ethtool_ops::set_settings is implemented. This tells new versions
+ * of ethtool that they should use the legacy API %ETHTOOL_SSET for
+ * this driver, so that they can correctly update the ethtool_cmd
+ * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
+ * implements ethtool_ops::get_settings anymore.
+ */
+static int ethtool_set_link_ksettings(struct net_device *dev,
+                                     void __user *useraddr)
+{
+       int err;
+       struct ethtool_link_ksettings link_ksettings;
+
+       ASSERT_RTNL();
+
+       if (!dev->ethtool_ops->set_link_ksettings)
+               return -EOPNOTSUPP;
+
+       /* make sure nbits field has expected value */
+       if (copy_from_user(&link_ksettings.base, useraddr,
+                          sizeof(link_ksettings.base)))
+               return -EFAULT;
+
+       if (__ETHTOOL_LINK_MODE_MASK_NU32
+           != link_ksettings.base.link_mode_masks_nwords)
+               return -EINVAL;
+
+       /* copy the whole structure, now that we know it has expected
+        * format
+        */
+       err = load_link_ksettings_from_user(&link_ksettings, useraddr);
+       if (err)
+               return err;
+
+       /* re-check nwords field, just in case */
+       if (__ETHTOOL_LINK_MODE_MASK_NU32
+           != link_ksettings.base.link_mode_masks_nwords)
+               return -EINVAL;
+
+       return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+}
+
+static void
+warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
+{
+       char name[sizeof(current->comm)];
+
+       pr_info_once("warning: `%s' uses legacy ethtool link settings API, %s\n",
+                    get_task_comm(name, current), details);
+}
+
+/* Query device for its ethtool_cmd settings.
+ *
+ * Backward compatibility note: for compatibility with legacy ethtool,
+ * this has to work with both drivers implementing get_link_ksettings
+ * API and drivers implementing get_settings API. When drivers
+ * implement get_link_ksettings and report higher link mode bits, a
+ * kernel warning is logged once (with name of 1st driver/device) to
+ * recommend user to upgrade ethtool, but the command is successful
+ * (only the lower link mode bits reported back to user).
+ */
+static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_cmd cmd;
+
+       ASSERT_RTNL();
+
+       if (dev->ethtool_ops->get_link_ksettings) {
+               /* First, use link_ksettings API if it is supported */
+               int err;
+               struct ethtool_link_ksettings link_ksettings;
+
+               memset(&link_ksettings, 0, sizeof(link_ksettings));
+               err = dev->ethtool_ops->get_link_ksettings(dev,
+                                                          &link_ksettings);
+               if (err < 0)
+                       return err;
+               if (!convert_link_ksettings_to_legacy_settings(&cmd,
+                                                              &link_ksettings))
+                       warn_incomplete_ethtool_legacy_settings_conversion(
+                               "link modes are only partially reported");
+
+               /* send a sensible cmd tag back to user */
+               cmd.cmd = ETHTOOL_GSET;
+       } else {
+               /* driver doesn't support %ethtool_link_ksettings
+                * API. revert to legacy %ethtool_cmd API, unless it's
+                * not supported either.
+                */
+               int err;
+
+               if (!dev->ethtool_ops->get_settings)
+                       return -EOPNOTSUPP;
+
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.cmd = ETHTOOL_GSET;
+               err = dev->ethtool_ops->get_settings(dev, &cmd);
+               if (err < 0)
+                       return err;
+       }
+
        if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
                return -EFAULT;
+
        return 0;
 }
 
+/* Update device link settings with given ethtool_cmd.
+ *
+ * Backward compatibility note: for compatibility with legacy ethtool,
+ * this has to work with both drivers implementing set_link_ksettings
+ * API and drivers implementing set_settings API. When drivers
+ * implement set_link_ksettings and user's request updates deprecated
+ * ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
+ * warning is logged once (with name of 1st driver/device) to
+ * recommend user to upgrade ethtool, and the request is rejected.
+ */
 static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_cmd cmd;
 
-       if (!dev->ethtool_ops->set_settings)
-               return -EOPNOTSUPP;
+       ASSERT_RTNL();
 
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
                return -EFAULT;
 
+       /* first, try new %ethtool_link_ksettings API. */
+       if (dev->ethtool_ops->set_link_ksettings) {
+               struct ethtool_link_ksettings link_ksettings;
+
+               if (!convert_legacy_settings_to_link_ksettings(&link_ksettings,
+                                                              &cmd))
+                       return -EINVAL;
+
+               link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS;
+               link_ksettings.base.link_mode_masks_nwords
+                       = __ETHTOOL_LINK_MODE_MASK_NU32;
+               return dev->ethtool_ops->set_link_ksettings(dev,
+                                                           &link_ksettings);
+       }
+
+       /* legacy %ethtool_cmd API */
+
+       /* TODO: return -EOPNOTSUPP when ethtool_ops::get_settings
+        * disappears internally
+        */
+
+       if (!dev->ethtool_ops->set_settings)
+               return -EOPNOTSUPP;
+
        return dev->ethtool_ops->set_settings(dev, &cmd);
 }
 
@@ -642,6 +1061,37 @@ void netdev_rss_key_fill(void *buffer, size_t len)
 }
 EXPORT_SYMBOL(netdev_rss_key_fill);
 
+static int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max)
+{
+       u32 dev_size, current_max = 0;
+       u32 *indir;
+       int ret;
+
+       if (!dev->ethtool_ops->get_rxfh_indir_size ||
+           !dev->ethtool_ops->get_rxfh)
+               return -EOPNOTSUPP;
+       dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev);
+       if (dev_size == 0)
+               return -EOPNOTSUPP;
+
+       indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
+       if (!indir)
+               return -ENOMEM;
+
+       ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL);
+       if (ret)
+               goto out;
+
+       while (dev_size--)
+               current_max = max(current_max, indir[dev_size]);
+
+       *max = current_max;
+
+out:
+       kfree(indir);
+       return ret;
+}
+
 static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev,
                                                     void __user *useraddr)
 {
@@ -738,6 +1188,14 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
        }
 
        ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE);
+       if (ret)
+               goto out;
+
+       /* indicate whether rxfh was set to default */
+       if (user_size == 0)
+               dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
+       else
+               dev->priv_flags |= IFF_RXFH_CONFIGURED;
 
 out:
        kfree(indir);
@@ -897,6 +1355,14 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
        }
 
        ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc);
+       if (ret)
+               goto out;
+
+       /* indicate whether rxfh was set to default */
+       if (rxfh.indir_size == 0)
+               dev->priv_flags &= ~IFF_RXFH_CONFIGURED;
+       else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE)
+               dev->priv_flags |= IFF_RXFH_CONFIGURED;
 
 out:
        kfree(rss_config);
@@ -1227,14 +1693,31 @@ static noinline_for_stack int ethtool_get_channels(struct net_device *dev,
 static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
                                                   void __user *useraddr)
 {
-       struct ethtool_channels channels;
+       struct ethtool_channels channels, max;
+       u32 max_rx_in_use = 0;
 
-       if (!dev->ethtool_ops->set_channels)
+       if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&channels, useraddr, sizeof(channels)))
                return -EFAULT;
 
+       dev->ethtool_ops->get_channels(dev, &max);
+
+       /* ensure new counts are within the maximums */
+       if ((channels.rx_count > max.max_rx) ||
+           (channels.tx_count > max.max_tx) ||
+           (channels.combined_count > max.max_combined) ||
+           (channels.other_count > max.max_other))
+               return -EINVAL;
+
+       /* ensure the new Rx count fits within the configured Rx flow
+        * indirection table settings */
+       if (netif_is_rxfh_configured(dev) &&
+           !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) &&
+           (channels.combined_count + channels.rx_count) <= max_rx_in_use)
+           return -EINVAL;
+
        return dev->ethtool_ops->set_channels(dev, &channels);
 }
 
@@ -1823,13 +2306,121 @@ out:
        return ret;
 }
 
+static int ethtool_get_per_queue_coalesce(struct net_device *dev,
+                                         void __user *useraddr,
+                                         struct ethtool_per_queue_op *per_queue_opt)
+{
+       u32 bit;
+       int ret;
+       DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
+
+       if (!dev->ethtool_ops->get_per_queue_coalesce)
+               return -EOPNOTSUPP;
+
+       useraddr += sizeof(*per_queue_opt);
+
+       bitmap_from_u32array(queue_mask,
+                            MAX_NUM_QUEUE,
+                            per_queue_opt->queue_mask,
+                            DIV_ROUND_UP(MAX_NUM_QUEUE, 32));
+
+       for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
+               struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
+
+               ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, &coalesce);
+               if (ret != 0)
+                       return ret;
+               if (copy_to_user(useraddr, &coalesce, sizeof(coalesce)))
+                       return -EFAULT;
+               useraddr += sizeof(coalesce);
+       }
+
+       return 0;
+}
+
+static int ethtool_set_per_queue_coalesce(struct net_device *dev,
+                                         void __user *useraddr,
+                                         struct ethtool_per_queue_op *per_queue_opt)
+{
+       u32 bit;
+       int i, ret = 0;
+       int n_queue;
+       struct ethtool_coalesce *backup = NULL, *tmp = NULL;
+       DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE);
+
+       if ((!dev->ethtool_ops->set_per_queue_coalesce) ||
+           (!dev->ethtool_ops->get_per_queue_coalesce))
+               return -EOPNOTSUPP;
+
+       useraddr += sizeof(*per_queue_opt);
+
+       bitmap_from_u32array(queue_mask,
+                            MAX_NUM_QUEUE,
+                            per_queue_opt->queue_mask,
+                            DIV_ROUND_UP(MAX_NUM_QUEUE, 32));
+       n_queue = bitmap_weight(queue_mask, MAX_NUM_QUEUE);
+       tmp = backup = kmalloc_array(n_queue, sizeof(*backup), GFP_KERNEL);
+       if (!backup)
+               return -ENOMEM;
+
+       for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) {
+               struct ethtool_coalesce coalesce;
+
+               ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, tmp);
+               if (ret != 0)
+                       goto roll_back;
+
+               tmp++;
+
+               if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) {
+                       ret = -EFAULT;
+                       goto roll_back;
+               }
+
+               ret = dev->ethtool_ops->set_per_queue_coalesce(dev, bit, &coalesce);
+               if (ret != 0)
+                       goto roll_back;
+
+               useraddr += sizeof(coalesce);
+       }
+
+roll_back:
+       if (ret != 0) {
+               tmp = backup;
+               for_each_set_bit(i, queue_mask, bit) {
+                       dev->ethtool_ops->set_per_queue_coalesce(dev, i, tmp);
+                       tmp++;
+               }
+       }
+       kfree(backup);
+
+       return ret;
+}
+
+static int ethtool_set_per_queue(struct net_device *dev, void __user *useraddr)
+{
+       struct ethtool_per_queue_op per_queue_opt;
+
+       if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt)))
+               return -EFAULT;
+
+       switch (per_queue_opt.sub_command) {
+       case ETHTOOL_GCOALESCE:
+               return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt);
+       case ETHTOOL_SCOALESCE:
+               return ethtool_set_per_queue_coalesce(dev, useraddr, &per_queue_opt);
+       default:
+               return -EOPNOTSUPP;
+       };
+}
+
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
 
 int dev_ethtool(struct net *net, struct ifreq *ifr)
 {
        struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
        void __user *useraddr = ifr->ifr_data;
-       u32 ethcmd;
+       u32 ethcmd, sub_cmd;
        int rc;
        netdev_features_t old_features;
 
@@ -1839,8 +2430,14 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
                return -EFAULT;
 
+       if (ethcmd == ETHTOOL_PERQUEUE) {
+               if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd)))
+                       return -EFAULT;
+       } else {
+               sub_cmd = ethcmd;
+       }
        /* Allow some commands to be done by anyone */
-       switch (ethcmd) {
+       switch (sub_cmd) {
        case ETHTOOL_GSET:
        case ETHTOOL_GDRVINFO:
        case ETHTOOL_GMSGLVL:
@@ -2070,6 +2667,15 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GPHYSTATS:
                rc = ethtool_get_phy_stats(dev, useraddr);
                break;
+       case ETHTOOL_PERQUEUE:
+               rc = ethtool_set_per_queue(dev, useraddr);
+               break;
+       case ETHTOOL_GLINKSETTINGS:
+               rc = ethtool_get_link_ksettings(dev, useraddr);
+               break;
+       case ETHTOOL_SLINKSETTINGS:
+               rc = ethtool_set_link_ksettings(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
index 2a6e9562f1ab0c57b78e025c59a118524137fb1e..6fc3893a6170517d3e41f3b4243bf76af5f55bcf 100644 (file)
@@ -530,12 +530,14 @@ do_pass:
                        *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_TMP);
                        break;
 
-               /* RET_K, RET_A are remaped into 2 insns. */
+               /* RET_K is remaped into 2 insns. RET_A case doesn't need an
+                * extra mov as BPF_REG_0 is already mapped into BPF_REG_A.
+                */
                case BPF_RET | BPF_A:
                case BPF_RET | BPF_K:
-                       *insn++ = BPF_MOV32_RAW(BPF_RVAL(fp->code) == BPF_K ?
-                                               BPF_K : BPF_X, BPF_REG_0,
-                                               BPF_REG_A, fp->k);
+                       if (BPF_RVAL(fp->code) == BPF_K)
+                               *insn++ = BPF_MOV32_RAW(BPF_K, BPF_REG_0,
+                                                       0, fp->k);
                        *insn = BPF_EXIT_INSN();
                        break;
 
@@ -1333,18 +1335,25 @@ int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk)
        return 0;
 }
 
-#define BPF_LDST_LEN 16U
+struct bpf_scratchpad {
+       union {
+               __be32 diff[MAX_BPF_STACK / sizeof(__be32)];
+               u8     buff[MAX_BPF_STACK];
+       };
+};
+
+static DEFINE_PER_CPU(struct bpf_scratchpad, bpf_sp);
 
 static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags)
 {
+       struct bpf_scratchpad *sp = this_cpu_ptr(&bpf_sp);
        struct sk_buff *skb = (struct sk_buff *) (long) r1;
        int offset = (int) r2;
        void *from = (void *) (long) r3;
        unsigned int len = (unsigned int) r4;
-       char buf[BPF_LDST_LEN];
        void *ptr;
 
-       if (unlikely(flags & ~(BPF_F_RECOMPUTE_CSUM)))
+       if (unlikely(flags & ~(BPF_F_RECOMPUTE_CSUM | BPF_F_INVALIDATE_HASH)))
                return -EINVAL;
 
        /* bpf verifier guarantees that:
@@ -1355,14 +1364,12 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags)
         *
         * so check for invalid 'offset' and too large 'len'
         */
-       if (unlikely((u32) offset > 0xffff || len > sizeof(buf)))
+       if (unlikely((u32) offset > 0xffff || len > sizeof(sp->buff)))
                return -EFAULT;
-
-       if (unlikely(skb_cloned(skb) &&
-                    !skb_clone_writable(skb, offset + len)))
+       if (unlikely(skb_try_make_writable(skb, offset + len)))
                return -EFAULT;
 
-       ptr = skb_header_pointer(skb, offset, len, buf);
+       ptr = skb_header_pointer(skb, offset, len, sp->buff);
        if (unlikely(!ptr))
                return -EFAULT;
 
@@ -1371,17 +1378,19 @@ static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 flags)
 
        memcpy(ptr, from, len);
 
-       if (ptr == buf)
+       if (ptr == sp->buff)
                /* skb_store_bits cannot return -EFAULT here */
                skb_store_bits(skb, offset, ptr, len);
 
        if (flags & BPF_F_RECOMPUTE_CSUM)
                skb_postpush_rcsum(skb, ptr, len);
+       if (flags & BPF_F_INVALIDATE_HASH)
+               skb_clear_hash(skb);
 
        return 0;
 }
 
-const struct bpf_func_proto bpf_skb_store_bytes_proto = {
+static const struct bpf_func_proto bpf_skb_store_bytes_proto = {
        .func           = bpf_skb_store_bytes,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1400,7 +1409,7 @@ static u64 bpf_skb_load_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
        unsigned int len = (unsigned int) r4;
        void *ptr;
 
-       if (unlikely((u32) offset > 0xffff || len > BPF_LDST_LEN))
+       if (unlikely((u32) offset > 0xffff || len > MAX_BPF_STACK))
                return -EFAULT;
 
        ptr = skb_header_pointer(skb, offset, len, to);
@@ -1412,7 +1421,7 @@ static u64 bpf_skb_load_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
        return 0;
 }
 
-const struct bpf_func_proto bpf_skb_load_bytes_proto = {
+static const struct bpf_func_proto bpf_skb_load_bytes_proto = {
        .func           = bpf_skb_load_bytes,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1432,9 +1441,7 @@ static u64 bpf_l3_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
                return -EINVAL;
        if (unlikely((u32) offset > 0xffff))
                return -EFAULT;
-
-       if (unlikely(skb_cloned(skb) &&
-                    !skb_clone_writable(skb, offset + sizeof(sum))))
+       if (unlikely(skb_try_make_writable(skb, offset + sizeof(sum))))
                return -EFAULT;
 
        ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum);
@@ -1442,6 +1449,12 @@ static u64 bpf_l3_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
                return -EFAULT;
 
        switch (flags & BPF_F_HDR_FIELD_MASK) {
+       case 0:
+               if (unlikely(from != 0))
+                       return -EINVAL;
+
+               csum_replace_by_diff(ptr, to);
+               break;
        case 2:
                csum_replace2(ptr, from, to);
                break;
@@ -1459,7 +1472,7 @@ static u64 bpf_l3_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
        return 0;
 }
 
-const struct bpf_func_proto bpf_l3_csum_replace_proto = {
+static const struct bpf_func_proto bpf_l3_csum_replace_proto = {
        .func           = bpf_l3_csum_replace,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1474,23 +1487,31 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
 {
        struct sk_buff *skb = (struct sk_buff *) (long) r1;
        bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
+       bool is_mmzero = flags & BPF_F_MARK_MANGLED_0;
        int offset = (int) r2;
        __sum16 sum, *ptr;
 
-       if (unlikely(flags & ~(BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK)))
+       if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_PSEUDO_HDR |
+                              BPF_F_HDR_FIELD_MASK)))
                return -EINVAL;
        if (unlikely((u32) offset > 0xffff))
                return -EFAULT;
-
-       if (unlikely(skb_cloned(skb) &&
-                    !skb_clone_writable(skb, offset + sizeof(sum))))
+       if (unlikely(skb_try_make_writable(skb, offset + sizeof(sum))))
                return -EFAULT;
 
        ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum);
        if (unlikely(!ptr))
                return -EFAULT;
+       if (is_mmzero && !*ptr)
+               return 0;
 
        switch (flags & BPF_F_HDR_FIELD_MASK) {
+       case 0:
+               if (unlikely(from != 0))
+                       return -EINVAL;
+
+               inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo);
+               break;
        case 2:
                inet_proto_csum_replace2(ptr, skb, from, to, is_pseudo);
                break;
@@ -1501,6 +1522,8 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
                return -EINVAL;
        }
 
+       if (is_mmzero && !*ptr)
+               *ptr = CSUM_MANGLED_0;
        if (ptr == &sum)
                /* skb_store_bits guaranteed to not return -EFAULT here */
                skb_store_bits(skb, offset, ptr, sizeof(sum));
@@ -1508,7 +1531,7 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
        return 0;
 }
 
-const struct bpf_func_proto bpf_l4_csum_replace_proto = {
+static const struct bpf_func_proto bpf_l4_csum_replace_proto = {
        .func           = bpf_l4_csum_replace,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1519,6 +1542,45 @@ const struct bpf_func_proto bpf_l4_csum_replace_proto = {
        .arg5_type      = ARG_ANYTHING,
 };
 
+static u64 bpf_csum_diff(u64 r1, u64 from_size, u64 r3, u64 to_size, u64 seed)
+{
+       struct bpf_scratchpad *sp = this_cpu_ptr(&bpf_sp);
+       u64 diff_size = from_size + to_size;
+       __be32 *from = (__be32 *) (long) r1;
+       __be32 *to   = (__be32 *) (long) r3;
+       int i, j = 0;
+
+       /* This is quite flexible, some examples:
+        *
+        * from_size == 0, to_size > 0,  seed := csum --> pushing data
+        * from_size > 0,  to_size == 0, seed := csum --> pulling data
+        * from_size > 0,  to_size > 0,  seed := 0    --> diffing data
+        *
+        * Even for diffing, from_size and to_size don't need to be equal.
+        */
+       if (unlikely(((from_size | to_size) & (sizeof(__be32) - 1)) ||
+                    diff_size > sizeof(sp->diff)))
+               return -EINVAL;
+
+       for (i = 0; i < from_size / sizeof(__be32); i++, j++)
+               sp->diff[j] = ~from[i];
+       for (i = 0; i <   to_size / sizeof(__be32); i++, j++)
+               sp->diff[j] = to[i];
+
+       return csum_partial(sp->diff, diff_size, seed);
+}
+
+static const struct bpf_func_proto bpf_csum_diff_proto = {
+       .func           = bpf_csum_diff,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_STACK,
+       .arg2_type      = ARG_CONST_STACK_SIZE_OR_ZERO,
+       .arg3_type      = ARG_PTR_TO_STACK,
+       .arg4_type      = ARG_CONST_STACK_SIZE_OR_ZERO,
+       .arg5_type      = ARG_ANYTHING,
+};
+
 static u64 bpf_clone_redirect(u64 r1, u64 ifindex, u64 flags, u64 r4, u64 r5)
 {
        struct sk_buff *skb = (struct sk_buff *) (long) r1, *skb2;
@@ -1543,11 +1605,10 @@ static u64 bpf_clone_redirect(u64 r1, u64 ifindex, u64 flags, u64 r4, u64 r5)
        }
 
        skb2->dev = dev;
-       skb_sender_cpu_clear(skb2);
        return dev_queue_xmit(skb2);
 }
 
-const struct bpf_func_proto bpf_clone_redirect_proto = {
+static const struct bpf_func_proto bpf_clone_redirect_proto = {
        .func           = bpf_clone_redirect,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1596,11 +1657,10 @@ int skb_do_redirect(struct sk_buff *skb)
        }
 
        skb->dev = dev;
-       skb_sender_cpu_clear(skb);
        return dev_queue_xmit(skb);
 }
 
-const struct bpf_func_proto bpf_redirect_proto = {
+static const struct bpf_func_proto bpf_redirect_proto = {
        .func           = bpf_redirect,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1682,6 +1742,13 @@ bool bpf_helper_changes_skb_data(void *func)
                return true;
        if (func == bpf_skb_vlan_pop)
                return true;
+       if (func == bpf_skb_store_bytes)
+               return true;
+       if (func == bpf_l3_csum_replace)
+               return true;
+       if (func == bpf_l4_csum_replace)
+               return true;
+
        return false;
 }
 
@@ -1703,12 +1770,15 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                return -EPROTO;
        if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
                switch (size) {
+               case offsetof(struct bpf_tunnel_key, tunnel_label):
+                       goto set_compat;
                case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
                        /* Fixup deprecated structure layouts here, so we have
                         * a common path later on.
                         */
                        if (ip_tunnel_info_af(info) != AF_INET)
                                return -EINVAL;
+set_compat:
                        to = (struct bpf_tunnel_key *)compat;
                        break;
                default:
@@ -1720,11 +1790,13 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        to->tunnel_tos = info->key.tos;
        to->tunnel_ttl = info->key.ttl;
 
-       if (flags & BPF_F_TUNINFO_IPV6)
+       if (flags & BPF_F_TUNINFO_IPV6) {
                memcpy(to->remote_ipv6, &info->key.u.ipv6.src,
                       sizeof(to->remote_ipv6));
-       else
+               to->tunnel_label = be32_to_cpu(info->key.label);
+       } else {
                to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src);
+       }
 
        if (unlikely(size != sizeof(struct bpf_tunnel_key)))
                memcpy((void *)(long) r2, to, size);
@@ -1732,7 +1804,7 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        return 0;
 }
 
-const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
+static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
        .func           = bpf_skb_get_tunnel_key,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1742,6 +1814,32 @@ const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = {
        .arg4_type      = ARG_ANYTHING,
 };
 
+static u64 bpf_skb_get_tunnel_opt(u64 r1, u64 r2, u64 size, u64 r4, u64 r5)
+{
+       struct sk_buff *skb = (struct sk_buff *) (long) r1;
+       u8 *to = (u8 *) (long) r2;
+       const struct ip_tunnel_info *info = skb_tunnel_info(skb);
+
+       if (unlikely(!info ||
+                    !(info->key.tun_flags & TUNNEL_OPTIONS_PRESENT)))
+               return -ENOENT;
+       if (unlikely(size < info->options_len))
+               return -ENOMEM;
+
+       ip_tunnel_info_opts_get(to, info);
+
+       return info->options_len;
+}
+
+static const struct bpf_func_proto bpf_skb_get_tunnel_opt_proto = {
+       .func           = bpf_skb_get_tunnel_opt,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_PTR_TO_STACK,
+       .arg3_type      = ARG_CONST_STACK_SIZE,
+};
+
 static struct metadata_dst __percpu *md_dst;
 
 static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
@@ -1752,10 +1850,12 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        u8 compat[sizeof(struct bpf_tunnel_key)];
        struct ip_tunnel_info *info;
 
-       if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6)))
+       if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX |
+                              BPF_F_DONT_FRAGMENT)))
                return -EINVAL;
        if (unlikely(size != sizeof(struct bpf_tunnel_key))) {
                switch (size) {
+               case offsetof(struct bpf_tunnel_key, tunnel_label):
                case offsetof(struct bpf_tunnel_key, remote_ipv6[1]):
                        /* Fixup deprecated structure layouts here, so we have
                         * a common path later on.
@@ -1768,6 +1868,8 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                        return -EINVAL;
                }
        }
+       if (unlikely(!(flags & BPF_F_TUNINFO_IPV6) && from->tunnel_label))
+               return -EINVAL;
 
        skb_dst_drop(skb);
        dst_hold((struct dst_entry *) md);
@@ -1776,7 +1878,10 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
        info = &md->u.tun_info;
        info->mode = IP_TUNNEL_INFO_TX;
 
-       info->key.tun_flags = TUNNEL_KEY;
+       info->key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE;
+       if (flags & BPF_F_DONT_FRAGMENT)
+               info->key.tun_flags |= TUNNEL_DONT_FRAGMENT;
+
        info->key.tun_id = cpu_to_be64(from->tunnel_id);
        info->key.tos = from->tunnel_tos;
        info->key.ttl = from->tunnel_ttl;
@@ -1785,14 +1890,18 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5)
                info->mode |= IP_TUNNEL_INFO_IPV6;
                memcpy(&info->key.u.ipv6.dst, from->remote_ipv6,
                       sizeof(from->remote_ipv6));
+               info->key.label = cpu_to_be32(from->tunnel_label) &
+                                 IPV6_FLOWLABEL_MASK;
        } else {
                info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4);
+               if (flags & BPF_F_ZERO_CSUM_TX)
+                       info->key.tun_flags &= ~TUNNEL_CSUM;
        }
 
        return 0;
 }
 
-const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
+static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
        .func           = bpf_skb_set_tunnel_key,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1802,17 +1911,58 @@ const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = {
        .arg4_type      = ARG_ANYTHING,
 };
 
-static const struct bpf_func_proto *bpf_get_skb_set_tunnel_key_proto(void)
+#define BPF_TUNLEN_MAX 255
+
+static u64 bpf_skb_set_tunnel_opt(u64 r1, u64 r2, u64 size, u64 r4, u64 r5)
+{
+       struct sk_buff *skb = (struct sk_buff *) (long) r1;
+       u8 *from = (u8 *) (long) r2;
+       struct ip_tunnel_info *info = skb_tunnel_info(skb);
+       const struct metadata_dst *md = this_cpu_ptr(md_dst);
+
+       if (unlikely(info != &md->u.tun_info || (size & (sizeof(u32) - 1))))
+               return -EINVAL;
+       if (unlikely(size > BPF_TUNLEN_MAX))
+               return -ENOMEM;
+
+       ip_tunnel_info_opts_set(info, from, size);
+
+       return 0;
+}
+
+static const struct bpf_func_proto bpf_skb_set_tunnel_opt_proto = {
+       .func           = bpf_skb_set_tunnel_opt,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_CTX,
+       .arg2_type      = ARG_PTR_TO_STACK,
+       .arg3_type      = ARG_CONST_STACK_SIZE,
+};
+
+static const struct bpf_func_proto *
+bpf_get_skb_set_tunnel_proto(enum bpf_func_id which)
 {
        if (!md_dst) {
-               /* race is not possible, since it's called from
-                * verifier that is holding verifier mutex
+               BUILD_BUG_ON(FIELD_SIZEOF(struct ip_tunnel_info,
+                                         options_len) != 1);
+
+               /* Race is not possible, since it's called from verifier
+                * that is holding verifier mutex.
                 */
-               md_dst = metadata_dst_alloc_percpu(0, GFP_KERNEL);
+               md_dst = metadata_dst_alloc_percpu(BPF_TUNLEN_MAX,
+                                                  GFP_KERNEL);
                if (!md_dst)
                        return NULL;
        }
-       return &bpf_skb_set_tunnel_key_proto;
+
+       switch (which) {
+       case BPF_FUNC_skb_set_tunnel_key:
+               return &bpf_skb_set_tunnel_key_proto;
+       case BPF_FUNC_skb_set_tunnel_opt:
+               return &bpf_skb_set_tunnel_opt_proto;
+       default:
+               return NULL;
+       }
 }
 
 static const struct bpf_func_proto *
@@ -1849,6 +1999,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
                return &bpf_skb_store_bytes_proto;
        case BPF_FUNC_skb_load_bytes:
                return &bpf_skb_load_bytes_proto;
+       case BPF_FUNC_csum_diff:
+               return &bpf_csum_diff_proto;
        case BPF_FUNC_l3_csum_replace:
                return &bpf_l3_csum_replace_proto;
        case BPF_FUNC_l4_csum_replace:
@@ -1864,7 +2016,11 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
        case BPF_FUNC_skb_get_tunnel_key:
                return &bpf_skb_get_tunnel_key_proto;
        case BPF_FUNC_skb_set_tunnel_key:
-               return bpf_get_skb_set_tunnel_key_proto();
+               return bpf_get_skb_set_tunnel_proto(func_id);
+       case BPF_FUNC_skb_get_tunnel_opt:
+               return &bpf_skb_get_tunnel_opt_proto;
+       case BPF_FUNC_skb_set_tunnel_opt:
+               return bpf_get_skb_set_tunnel_proto(func_id);
        case BPF_FUNC_redirect:
                return &bpf_redirect_proto;
        case BPF_FUNC_get_route_realm:
index d79699c9d1b9eb9f250254e360b2d5a7b4ff6e34..a669dea146c61b2f7f5b1feaf46512b135ee28f7 100644 (file)
 #include <net/flow_dissector.h>
 #include <scsi/fc/fc_fcoe.h>
 
-static bool dissector_uses_key(const struct flow_dissector *flow_dissector,
-                              enum flow_dissector_key_id key_id)
-{
-       return flow_dissector->used_keys & (1 << key_id);
-}
-
 static void dissector_set_key(struct flow_dissector *flow_dissector,
                              enum flow_dissector_key_id key_id)
 {
        flow_dissector->used_keys |= (1 << key_id);
 }
 
-static void *skb_flow_dissector_target(struct flow_dissector *flow_dissector,
-                                      enum flow_dissector_key_id key_id,
-                                      void *target_container)
-{
-       return ((char *) target_container) + flow_dissector->offset[key_id];
-}
-
 void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
                             const struct flow_dissector_key *key,
                             unsigned int key_count)
@@ -178,15 +165,16 @@ ip:
 
                ip_proto = iph->protocol;
 
-               if (!dissector_uses_key(flow_dissector,
-                                       FLOW_DISSECTOR_KEY_IPV4_ADDRS))
-                       break;
+               if (dissector_uses_key(flow_dissector,
+                                      FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+                       key_addrs = skb_flow_dissector_target(flow_dissector,
+                                                             FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                             target_container);
 
-               key_addrs = skb_flow_dissector_target(flow_dissector,
-                             FLOW_DISSECTOR_KEY_IPV4_ADDRS, target_container);
-               memcpy(&key_addrs->v4addrs, &iph->saddr,
-                      sizeof(key_addrs->v4addrs));
-               key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+                       memcpy(&key_addrs->v4addrs, &iph->saddr,
+                              sizeof(key_addrs->v4addrs));
+                       key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
+               }
 
                if (ip_is_fragment(iph)) {
                        key_control->flags |= FLOW_DIS_IS_FRAGMENT;
@@ -208,7 +196,6 @@ ip:
        case htons(ETH_P_IPV6): {
                const struct ipv6hdr *iph;
                struct ipv6hdr _iph;
-               __be32 flow_label;
 
 ipv6:
                iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
@@ -220,18 +207,21 @@ ipv6:
 
                if (dissector_uses_key(flow_dissector,
                                       FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
-                       struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs;
-
-                       key_ipv6_addrs = skb_flow_dissector_target(flow_dissector,
-                                                                  FLOW_DISSECTOR_KEY_IPV6_ADDRS,
-                                                                  target_container);
+                       key_addrs = skb_flow_dissector_target(flow_dissector,
+                                                             FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                             target_container);
 
-                       memcpy(key_ipv6_addrs, &iph->saddr, sizeof(*key_ipv6_addrs));
+                       memcpy(&key_addrs->v6addrs, &iph->saddr,
+                              sizeof(key_addrs->v6addrs));
                        key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
                }
 
-               flow_label = ip6_flowlabel(iph);
-               if (flow_label) {
+               if ((dissector_uses_key(flow_dissector,
+                                       FLOW_DISSECTOR_KEY_FLOW_LABEL) ||
+                    (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) &&
+                   ip6_flowlabel(iph)) {
+                       __be32 flow_label = ip6_flowlabel(iph);
+
                        if (dissector_uses_key(flow_dissector,
                                               FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
                                key_tags = skb_flow_dissector_target(flow_dissector,
@@ -336,8 +326,11 @@ mpls:
        }
 
        case htons(ETH_P_FCOE):
-               key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
-               /* fall through */
+               if ((hlen - nhoff) < FCOE_HEADER_LEN)
+                       goto out_bad;
+
+               nhoff += FCOE_HEADER_LEN;
+               goto out_good;
        default:
                goto out_bad;
        }
@@ -396,6 +389,13 @@ ip_proto_again:
                                goto out_bad;
                        proto = eth->h_proto;
                        nhoff += sizeof(*eth);
+
+                       /* Cap headers that we access via pointers at the
+                        * end of the Ethernet header as our maximum alignment
+                        * at that point is only 2 bytes.
+                        */
+                       if (NET_IP_ALIGN)
+                               hlen = nhoff;
                }
 
                key_control->flags |= FLOW_DIS_ENCAPSULATION;
@@ -437,13 +437,12 @@ ip_proto_again:
                key_control->flags |= FLOW_DIS_IS_FRAGMENT;
 
                nhoff += sizeof(_fh);
+               ip_proto = fh->nexthdr;
 
                if (!(fh->frag_off & htons(IP6_OFFSET))) {
                        key_control->flags |= FLOW_DIS_FIRST_FRAG;
-                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
-                               ip_proto = fh->nexthdr;
+                       if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)
                                goto ip_proto_again;
-                       }
                }
                goto out_good;
        }
@@ -730,6 +729,11 @@ u32 __skb_get_poff(const struct sk_buff *skb, void *data,
 {
        u32 poff = keys->control.thoff;
 
+       /* skip L4 headers for fragments after the first */
+       if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) &&
+           !(keys->control.flags & FLOW_DIS_FIRST_FRAG))
+               return poff;
+
        switch (keys->basic.ip_proto) {
        case IPPROTO_TCP: {
                /* access doff as u8 to avoid unaligned access */
index 299cfc24d88832c3580450fcd824ae7b4fdd10c1..669ecc9f884eabab925a1ef02ec834a7d22e6f4b 100644 (file)
 #include <net/rtnetlink.h>
 #include <net/ip6_fib.h>
 
+#ifdef CONFIG_MODULES
+
+static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
+{
+       /* Only lwt encaps implemented without using an interface for
+        * the encap need to return a string here.
+        */
+       switch (encap_type) {
+       case LWTUNNEL_ENCAP_MPLS:
+               return "MPLS";
+       case LWTUNNEL_ENCAP_ILA:
+               return "ILA";
+       case LWTUNNEL_ENCAP_IP6:
+       case LWTUNNEL_ENCAP_IP:
+       case LWTUNNEL_ENCAP_NONE:
+       case __LWTUNNEL_ENCAP_MAX:
+               /* should not have got here */
+               WARN_ON(1);
+               break;
+       }
+       return NULL;
+}
+
+#endif /* CONFIG_MODULES */
+
 struct lwtunnel_state *lwtunnel_state_alloc(int encap_len)
 {
        struct lwtunnel_state *lws;
@@ -85,6 +110,18 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
        ret = -EOPNOTSUPP;
        rcu_read_lock();
        ops = rcu_dereference(lwtun_encaps[encap_type]);
+#ifdef CONFIG_MODULES
+       if (!ops) {
+               const char *encap_type_str = lwtunnel_encap_str(encap_type);
+
+               if (encap_type_str) {
+                       rcu_read_unlock();
+                       request_module("rtnl-lwt-%s", encap_type_str);
+                       rcu_read_lock();
+                       ops = rcu_dereference(lwtun_encaps[encap_type]);
+               }
+       }
+#endif
        if (likely(ops && ops->build_state))
                ret = ops->build_state(dev, encap, family, cfg, lws);
        rcu_read_unlock();
index da7dbc237a5f4c2f98aee3bf5f95a78f6768707e..2b3f76fe65f49f8018c63aa44b345262fb40cde7 100644 (file)
@@ -29,7 +29,6 @@
 
 #ifdef CONFIG_SYSFS
 static const char fmt_hex[] = "%#x\n";
-static const char fmt_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
 static const char fmt_ulong[] = "%lu\n";
 static const char fmt_u64[] = "%llu\n";
@@ -199,9 +198,10 @@ static ssize_t speed_show(struct device *dev,
                return restart_syscall();
 
        if (netif_running(netdev)) {
-               struct ethtool_cmd cmd;
-               if (!__ethtool_get_settings(netdev, &cmd))
-                       ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+               struct ethtool_link_ksettings cmd;
+
+               if (!__ethtool_get_link_ksettings(netdev, &cmd))
+                       ret = sprintf(buf, fmt_dec, cmd.base.speed);
        }
        rtnl_unlock();
        return ret;
@@ -218,10 +218,12 @@ static ssize_t duplex_show(struct device *dev,
                return restart_syscall();
 
        if (netif_running(netdev)) {
-               struct ethtool_cmd cmd;
-               if (!__ethtool_get_settings(netdev, &cmd)) {
+               struct ethtool_link_ksettings cmd;
+
+               if (!__ethtool_get_link_ksettings(netdev, &cmd)) {
                        const char *duplex;
-                       switch (cmd.duplex) {
+
+                       switch (cmd.base.duplex) {
                        case DUPLEX_HALF:
                                duplex = "half";
                                break;
index 0260c84ed83c4a678022db87babc1d0f863b787f..11fce17274f6ce14e22ded0e2e9c046492c5f895 100644 (file)
@@ -9,7 +9,6 @@
  * Authors:    Thomas Graf <tgraf@suug.ch>
  */
 
-#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/cgroup.h>
 #include <linux/fdtable.h>
index f1efbc39ef6be94dc720814dc59a14dae1269cfd..2ec86fc552df6e2bd07981fb2ade76305d2545b6 100644 (file)
@@ -11,7 +11,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/string.h>
index 1474cfd2dc1ce25d58182d4e13d836227b89c28d..20999aa596dd0296bbfec23f1ea5dda0a4adf244 100644 (file)
@@ -2856,7 +2856,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                *vlan_encapsulated_proto = htons(ETH_P_IP);
        }
 
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb_set_network_header(skb, skb->len);
        iph = (struct iphdr *) skb_put(skb, sizeof(struct iphdr));
 
@@ -2983,7 +2983,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                *vlan_encapsulated_proto = htons(ETH_P_IPV6);
        }
 
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb_set_network_header(skb, skb->len);
        iph = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
 
index 62737f437c8e0f0e7d3faf0fdabed905bc2444cf..d2d9e5ebf58ea827f8e0b5aaa85cea23cd3b77dd 100644 (file)
@@ -1391,15 +1391,6 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
        [IFLA_VF_TRUST]         = { .len = sizeof(struct ifla_vf_trust) },
 };
 
-static const struct nla_policy ifla_vf_stats_policy[IFLA_VF_STATS_MAX + 1] = {
-       [IFLA_VF_STATS_RX_PACKETS]      = { .type = NLA_U64 },
-       [IFLA_VF_STATS_TX_PACKETS]      = { .type = NLA_U64 },
-       [IFLA_VF_STATS_RX_BYTES]        = { .type = NLA_U64 },
-       [IFLA_VF_STATS_TX_BYTES]        = { .type = NLA_U64 },
-       [IFLA_VF_STATS_BROADCAST]       = { .type = NLA_U64 },
-       [IFLA_VF_STATS_MULTICAST]       = { .type = NLA_U64 },
-};
-
 static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
        [IFLA_PORT_VF]          = { .type = NLA_U32 },
        [IFLA_PORT_PROFILE]     = { .type = NLA_STRING,
@@ -2979,6 +2970,7 @@ int ndo_dflt_fdb_dump(struct sk_buff *skb,
        nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->mc);
 out:
        netif_addr_unlock_bh(dev);
+       cb->args[1] = err;
        return idx;
 }
 EXPORT_SYMBOL(ndo_dflt_fdb_dump);
@@ -3012,6 +3004,7 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
                ops = br_dev->netdev_ops;
        }
 
+       cb->args[1] = 0;
        for_each_netdev(net, dev) {
                if (brport_idx && (dev->ifindex != brport_idx))
                        continue;
@@ -3039,12 +3032,16 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
                                idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev,
                                                         idx);
                }
+               if (cb->args[1] == -EMSGSIZE)
+                       break;
 
                if (dev->netdev_ops->ndo_fdb_dump)
                        idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL,
                                                            idx);
                else
                        idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx);
+               if (cb->args[1] == -EMSGSIZE)
+                       break;
 
                cops = NULL;
        }
index 14596fb3717270d62fa70544b7ec2496de96e1ce..2696aefdc148887138d46f98dc0a678ce2699512 100644 (file)
@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
                *fplp = fpl;
                fpl->count = 0;
                fpl->max = SCM_MAX_FD;
+               fpl->user = NULL;
        }
        fpp = &fpl->fp[fpl->count];
 
@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
                *fpp++ = file;
                fpl->count++;
        }
+
+       if (!fpl->user)
+               fpl->user = get_uid(current_user());
+
        return num;
 }
 
@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm)
                scm->fp = NULL;
                for (i=fpl->count-1; i>=0; i--)
                        fput(fpl->fp[i]);
+               free_uid(fpl->user);
                kfree(fpl);
        }
 }
@@ -336,6 +342,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
                for (i = 0; i < fpl->count; i++)
                        get_file(fpl->fp[i]);
                new_fpl->max = new_fpl->count;
+               new_fpl->user = get_uid(fpl->user);
        }
        return new_fpl;
 }
index a5bd067ec1a3b85b59249129e8e4d9813e16ca7a..f044f970f1a63c9040ec7c763e2b19a690b55269 100644 (file)
@@ -79,6 +79,8 @@
 
 struct kmem_cache *skbuff_head_cache __read_mostly;
 static struct kmem_cache *skbuff_fclone_cache __read_mostly;
+int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
+EXPORT_SYMBOL(sysctl_max_skb_frags);
 
 /**
  *     skb_panic - private function for out-of-line support
@@ -799,9 +801,9 @@ void napi_consume_skb(struct sk_buff *skb, int budget)
        if (unlikely(!skb))
                return;
 
-       /* if budget is 0 assume netpoll w/ IRQs disabled */
+       /* Zero budget indicate non-NAPI context called us, like netpoll */
        if (unlikely(!budget)) {
-               dev_consume_skb_irq(skb);
+               dev_consume_skb_any(skb);
                return;
        }
 
@@ -1916,6 +1918,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
                              struct splice_pipe_desc *spd, struct sock *sk)
 {
        int seg;
+       struct sk_buff *iter;
 
        /* map the linear part :
         * If skb->head_frag is set, this 'linear' part is backed by a
@@ -1942,6 +1945,19 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
                        return true;
        }
 
+       skb_walk_frags(skb, iter) {
+               if (*offset >= iter->len) {
+                       *offset -= iter->len;
+                       continue;
+               }
+               /* __skb_splice_bits() only fails if the output has no room
+                * left, so no point in going over the frag_list for the error
+                * case.
+                */
+               if (__skb_splice_bits(iter, pipe, offset, len, spd, sk))
+                       return true;
+       }
+
        return false;
 }
 
@@ -1968,9 +1984,7 @@ ssize_t skb_socket_splice(struct sock *sk,
 
 /*
  * Map data from the skb to a pipe. Should handle both the linear part,
- * the fragments, and the frag list. It does NOT handle frag lists within
- * the frag list, if such a thing exists. We'd probably need to recurse to
- * handle that cleanly.
+ * the fragments, and the frag list.
  */
 int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
                    struct pipe_inode_info *pipe, unsigned int tlen,
@@ -1989,29 +2003,10 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
                .ops = &nosteal_pipe_buf_ops,
                .spd_release = sock_spd_release,
        };
-       struct sk_buff *frag_iter;
        int ret = 0;
 
-       /*
-        * __skb_splice_bits() only fails if the output has no room left,
-        * so no point in going over the frag_list for the error case.
-        */
-       if (__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk))
-               goto done;
-       else if (!tlen)
-               goto done;
+       __skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk);
 
-       /*
-        * now see if we have a frag_list to map
-        */
-       skb_walk_frags(skb, frag_iter) {
-               if (!tlen)
-                       break;
-               if (__skb_splice_bits(frag_iter, pipe, &offset, &tlen, &spd, sk))
-                       break;
-       }
-
-done:
        if (spd.nr_pages)
                ret = splice_cb(sk, pipe, &spd);
 
@@ -3020,6 +3015,24 @@ int skb_append_pagefrags(struct sk_buff *skb, struct page *page,
 }
 EXPORT_SYMBOL_GPL(skb_append_pagefrags);
 
+/**
+ *     skb_push_rcsum - push skb and update receive checksum
+ *     @skb: buffer to update
+ *     @len: length of data pulled
+ *
+ *     This function performs an skb_push on the packet and updates
+ *     the CHECKSUM_COMPLETE checksum.  It should be used on
+ *     receive path processing instead of skb_push unless you know
+ *     that the checksum difference is zero (e.g., a valid IP header)
+ *     or you are setting ip_summed to CHECKSUM_NONE.
+ */
+static unsigned char *skb_push_rcsum(struct sk_buff *skb, unsigned len)
+{
+       skb_push(skb, len);
+       skb_postpush_rcsum(skb, skb->data, len);
+       return skb->data;
+}
+
 /**
  *     skb_pull_rcsum - pull skb and update receive checksum
  *     @skb: buffer to update
@@ -4165,9 +4178,9 @@ struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb,
        if (!pskb_may_pull(skb_chk, offset))
                goto err;
 
-       __skb_pull(skb_chk, offset);
+       skb_pull_rcsum(skb_chk, offset);
        ret = skb_chkf(skb_chk);
-       __skb_push(skb_chk, offset);
+       skb_push_rcsum(skb_chk, offset);
 
        if (ret)
                goto err;
@@ -4300,7 +4313,6 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->skb_iif = 0;
        skb->ignore_df = 0;
        skb_dst_drop(skb);
-       skb_sender_cpu_clear(skb);
        secpath_reset(skb);
        nf_reset(skb);
        nf_reset_trace(skb);
@@ -4496,9 +4508,7 @@ int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
                skb->mac_len += VLAN_HLEN;
                __skb_pull(skb, offset);
 
-               if (skb->ip_summed == CHECKSUM_COMPLETE)
-                       skb->csum = csum_add(skb->csum, csum_partial(skb->data
-                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));
+               skb_postpush_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN);
        }
        __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
        return 0;
index 46dc8ad7d0501d9fec698930d85798371d7932ea..4493ff820c2c0a13d5e257f26aae4284aa0b474a 100644 (file)
@@ -987,6 +987,10 @@ set_rcvbuf:
                sk->sk_incoming_cpu = val;
                break;
 
+       case SO_CNX_ADVICE:
+               if (val == 1)
+                       dst_negative_advice(sk);
+               break;
        default:
                ret = -ENOPROTOOPT;
                break;
index 95b6139d710c46825d1e43f825188d81fcb70f60..a6beb7b6ae556dff501413d6661d9c4655502e36 100644 (file)
@@ -26,6 +26,7 @@ static int zero = 0;
 static int one = 1;
 static int min_sndbuf = SOCK_MIN_SNDBUF;
 static int min_rcvbuf = SOCK_MIN_RCVBUF;
+static int max_skb_frags = MAX_SKB_FRAGS;
 
 static int net_msg_warn;       /* Unused, but still a sysctl */
 
@@ -392,6 +393,15 @@ static struct ctl_table net_core_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "max_skb_frags",
+               .data           = &sysctl_max_skb_frags,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
+               .extra2         = &max_skb_frags,
+       },
        { }
 };
 
index 1e0c600c83ae26eba44d380d689ab81b6eb94e70..b5672e5fe64966f89454357586bbccd797c97b94 100644 (file)
@@ -824,26 +824,26 @@ lookup:
 
        if (sk->sk_state == DCCP_NEW_SYN_RECV) {
                struct request_sock *req = inet_reqsk(sk);
-               struct sock *nsk = NULL;
+               struct sock *nsk;
 
                sk = req->rsk_listener;
-               if (likely(sk->sk_state == DCCP_LISTEN)) {
-                       nsk = dccp_check_req(sk, skb, req);
-               } else {
+               if (unlikely(sk->sk_state != DCCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
                }
+               sock_hold(sk);
+               nsk = dccp_check_req(sk, skb, req);
                if (!nsk) {
                        reqsk_put(req);
-                       goto discard_it;
+                       goto discard_and_relse;
                }
                if (nsk == sk) {
-                       sock_hold(sk);
                        reqsk_put(req);
                } else if (dccp_child_process(sk, nsk, skb)) {
                        dccp_v4_ctl_send_reset(sk, skb);
-                       goto discard_it;
+                       goto discard_and_relse;
                } else {
+                       sock_put(sk);
                        return 0;
                }
        }
index 45cbe85f0940a1cab573ee33ebecd95a006a12cf..4663a01d503991c138c56da530544791832fee5f 100644 (file)
@@ -691,26 +691,26 @@ lookup:
 
        if (sk->sk_state == DCCP_NEW_SYN_RECV) {
                struct request_sock *req = inet_reqsk(sk);
-               struct sock *nsk = NULL;
+               struct sock *nsk;
 
                sk = req->rsk_listener;
-               if (likely(sk->sk_state == DCCP_LISTEN)) {
-                       nsk = dccp_check_req(sk, skb, req);
-               } else {
+               if (unlikely(sk->sk_state != DCCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
                }
+               sock_hold(sk);
+               nsk = dccp_check_req(sk, skb, req);
                if (!nsk) {
                        reqsk_put(req);
-                       goto discard_it;
+                       goto discard_and_relse;
                }
                if (nsk == sk) {
-                       sock_hold(sk);
                        reqsk_put(req);
                } else if (dccp_child_process(sk, nsk, skb)) {
                        dccp_v6_ctl_send_reset(sk, skb);
-                       goto discard_it;
+                       goto discard_and_relse;
                } else {
+                       sock_put(sk);
                        return 0;
                }
        }
index fa4daba8db55c7297b80499b0fb96c60fb096322..d8fb47fcad051cf5d0e362b64d0967d0a0579a28 100644 (file)
@@ -935,6 +935,14 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
 {
        int i;
 
+       dst->master_netdev->dsa_ptr = NULL;
+
+       /* If we used a tagging format that doesn't have an ethertype
+        * field, make sure that all packets from this point get sent
+        * without the tag and go through the regular receive path.
+        */
+       wmb();
+
        for (i = 0; i < dst->pd->nr_chips; i++) {
                struct dsa_switch *ds = dst->ds[i];
 
@@ -988,14 +996,6 @@ static int dsa_suspend(struct device *d)
        struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
        int i, ret = 0;
 
-       dst->master_netdev->dsa_ptr = NULL;
-
-       /* If we used a tagging format that doesn't have an ethertype
-        * field, make sure that all packets from this point get sent
-        * without the tag and go through the regular receive path.
-        */
-       wmb();
-
        for (i = 0; i < dst->pd->nr_chips; i++) {
                struct dsa_switch *ds = dst->ds[i];
 
index 40b9ca72aae3da05c924b2d7adaa0825acfd398d..27bf03d11670cd982b072bc02bf0331b0308e6b4 100644 (file)
@@ -201,47 +201,6 @@ out:
        return 0;
 }
 
-static int dsa_bridge_check_vlan_range(struct dsa_switch *ds,
-                                      const struct net_device *bridge,
-                                      u16 vid_begin, u16 vid_end)
-{
-       struct dsa_slave_priv *p;
-       struct net_device *dev, *vlan_br;
-       DECLARE_BITMAP(members, DSA_MAX_PORTS);
-       DECLARE_BITMAP(untagged, DSA_MAX_PORTS);
-       u16 vid;
-       int member, err;
-
-       if (!ds->drv->vlan_getnext || !vid_begin)
-               return -EOPNOTSUPP;
-
-       vid = vid_begin - 1;
-
-       do {
-               err = ds->drv->vlan_getnext(ds, &vid, members, untagged);
-               if (err)
-                       break;
-
-               if (vid > vid_end)
-                       break;
-
-               member = find_first_bit(members, DSA_MAX_PORTS);
-               if (member == DSA_MAX_PORTS)
-                       continue;
-
-               dev = ds->ports[member];
-               p = netdev_priv(dev);
-               vlan_br = p->bridge_dev;
-               if (vlan_br == bridge)
-                       continue;
-
-               netdev_dbg(vlan_br, "hardware VLAN %d already in use\n", vid);
-               return -EOPNOTSUPP;
-       } while (vid < vid_end);
-
-       return err == -ENOENT ? 0 : err;
-}
-
 static int dsa_slave_port_vlan_add(struct net_device *dev,
                                   const struct switchdev_obj_port_vlan *vlan,
                                   struct switchdev_trans *trans)
@@ -254,15 +213,6 @@ static int dsa_slave_port_vlan_add(struct net_device *dev,
                if (!ds->drv->port_vlan_prepare || !ds->drv->port_vlan_add)
                        return -EOPNOTSUPP;
 
-               /* If the requested port doesn't belong to the same bridge as
-                * the VLAN members, fallback to software VLAN (hopefully).
-                */
-               err = dsa_bridge_check_vlan_range(ds, p->bridge_dev,
-                                                 vlan->vid_begin,
-                                                 vlan->vid_end);
-               if (err)
-                       return err;
-
                err = ds->drv->port_vlan_prepare(ds, p->port, vlan, trans);
                if (err)
                        return err;
@@ -293,41 +243,11 @@ static int dsa_slave_port_vlan_dump(struct net_device *dev,
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct dsa_switch *ds = p->parent;
-       DECLARE_BITMAP(members, DSA_MAX_PORTS);
-       DECLARE_BITMAP(untagged, DSA_MAX_PORTS);
-       u16 pvid, vid = 0;
-       int err;
-
-       if (!ds->drv->vlan_getnext || !ds->drv->port_pvid_get)
-               return -EOPNOTSUPP;
-
-       err = ds->drv->port_pvid_get(ds, p->port, &pvid);
-       if (err)
-               return err;
-
-       for (;;) {
-               err = ds->drv->vlan_getnext(ds, &vid, members, untagged);
-               if (err)
-                       break;
-
-               if (!test_bit(p->port, members))
-                       continue;
-
-               memset(vlan, 0, sizeof(*vlan));
-               vlan->vid_begin = vlan->vid_end = vid;
 
-               if (vid == pvid)
-                       vlan->flags |= BRIDGE_VLAN_INFO_PVID;
+       if (ds->drv->port_vlan_dump)
+               return ds->drv->port_vlan_dump(ds, p->port, vlan, cb);
 
-               if (test_bit(p->port, untagged))
-                       vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
-
-               err = cb(&vlan->obj);
-               if (err)
-                       break;
-       }
-
-       return err == -ENOENT ? 0 : err;
+       return -EOPNOTSUPP;
 }
 
 static int dsa_slave_port_fdb_add(struct net_device *dev,
@@ -385,31 +305,6 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
-/* Return a bitmask of all ports being currently bridged within a given bridge
- * device. Note that on leave, the mask will still return the bitmask of ports
- * currently bridged, prior to port removal, and this is exactly what we want.
- */
-static u32 dsa_slave_br_port_mask(struct dsa_switch *ds,
-                                 struct net_device *bridge)
-{
-       struct dsa_slave_priv *p;
-       unsigned int port;
-       u32 mask = 0;
-
-       for (port = 0; port < DSA_MAX_PORTS; port++) {
-               if (!dsa_is_port_initialized(ds, port))
-                       continue;
-
-               p = netdev_priv(ds->ports[port]);
-
-               if (ds->ports[port]->priv_flags & IFF_BRIDGE_PORT &&
-                   p->bridge_dev == bridge)
-                       mask |= 1 << port;
-       }
-
-       return mask;
-}
-
 static int dsa_slave_stp_update(struct net_device *dev, u8 state)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
@@ -422,6 +317,24 @@ static int dsa_slave_stp_update(struct net_device *dev, u8 state)
        return ret;
 }
 
+static int dsa_slave_vlan_filtering(struct net_device *dev,
+                                   const struct switchdev_attr *attr,
+                                   struct switchdev_trans *trans)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       /* bridge skips -EOPNOTSUPP, so skip the prepare phase */
+       if (switchdev_trans_ph_prepare(trans))
+               return 0;
+
+       if (ds->drv->port_vlan_filtering)
+               return ds->drv->port_vlan_filtering(ds, p->port,
+                                                   attr->u.vlan_filtering);
+
+       return 0;
+}
+
 static int dsa_slave_port_attr_set(struct net_device *dev,
                                   const struct switchdev_attr *attr,
                                   struct switchdev_trans *trans)
@@ -438,6 +351,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev,
                        ret = ds->drv->port_stp_update(ds, p->port,
                                                       attr->u.stp_state);
                break;
+       case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING:
+               ret = dsa_slave_vlan_filtering(dev, attr, trans);
+               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -533,8 +449,7 @@ static int dsa_slave_bridge_port_join(struct net_device *dev,
        p->bridge_dev = br;
 
        if (ds->drv->port_join_bridge)
-               ret = ds->drv->port_join_bridge(ds, p->port,
-                                               dsa_slave_br_port_mask(ds, br));
+               ret = ds->drv->port_join_bridge(ds, p->port, br);
 
        return ret;
 }
@@ -547,8 +462,7 @@ static int dsa_slave_bridge_port_leave(struct net_device *dev)
 
 
        if (ds->drv->port_leave_bridge)
-               ret = ds->drv->port_leave_bridge(ds, p->port,
-                                                dsa_slave_br_port_mask(ds, p->bridge_dev));
+               ret = ds->drv->port_leave_bridge(ds, p->port);
 
        p->bridge_dev = NULL;
 
@@ -1194,7 +1108,6 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        if (ret) {
                netdev_err(master, "error %d registering interface %s\n",
                           ret, slave_dev->name);
-               phy_disconnect(p->phy);
                ds->ports[port] = NULL;
                free_netdev(slave_dev);
                return ret;
@@ -1205,6 +1118,7 @@ int dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        ret = dsa_slave_phy_setup(p, slave_dev);
        if (ret) {
                netdev_err(master, "error %d setting up slave phy\n", ret);
+               unregister_netdev(slave_dev);
                free_netdev(slave_dev);
                return ret;
        }
index 103871784e5085a8f16b792d2b059ea97cff9721..66dff5e3d7728bc9d302fdf6c207a6c03197affa 100644 (file)
@@ -125,6 +125,7 @@ EXPORT_SYMBOL(eth_header);
  */
 u32 eth_get_headlen(void *data, unsigned int len)
 {
+       const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG;
        const struct ethhdr *eth = (const struct ethhdr *)data;
        struct flow_keys keys;
 
@@ -134,7 +135,7 @@ u32 eth_get_headlen(void *data, unsigned int len)
 
        /* parse any remaining L2/L3 headers, check for L4 */
        if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto,
-                                           sizeof(*eth), len, 0))
+                                           sizeof(*eth), len, flags))
                return max_t(u32, keys.control.thoff, sizeof(*eth));
 
        /* parse for any L4 headers */
index 737c87a2a41e0299aecff8d56c30b637c6baa02e..0023c904881246ab00432c1bcb3454df1c79636a 100644 (file)
@@ -207,7 +207,7 @@ static int lowpan_device_event(struct notifier_block *unused,
        struct net_device *wdev = netdev_notifier_info_to_dev(ptr);
 
        if (wdev->type != ARPHRD_IEEE802154)
-               goto out;
+               return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_UNREGISTER:
@@ -219,11 +219,10 @@ static int lowpan_device_event(struct notifier_block *unused,
                        lowpan_dellink(wdev->ieee802154_ptr->lowpan_dev, NULL);
                break;
        default:
-               break;
+               return NOTIFY_DONE;
        }
 
-out:
-       return NOTIFY_DONE;
+       return NOTIFY_OK;
 }
 
 static struct notifier_block lowpan_dev_notifier = {
index 775824720b6b57d68460fc8e05915e479f221414..238225b0c97084750d0707309c146cc17b4a2401 100644 (file)
@@ -186,6 +186,7 @@ config NET_IPGRE_DEMUX
 
 config NET_IP_TUNNEL
        tristate
+       select DST_CACHE
        default n
 
 config NET_IPGRE
@@ -405,14 +406,6 @@ config INET_XFRM_MODE_BEET
 
          If unsure, say Y.
 
-config INET_LRO
-       tristate "Large Receive Offload (ipv4/tcp)"
-       default y
-       ---help---
-         Support for Large Receive Offload (ipv4/tcp).
-
-         If unsure, say Y.
-
 config INET_DIAG
        tristate "INET: socket monitoring interface"
        default y
index 62c049b647e93424219ad61fbeaec15429cfa9ab..bfa133691cde646f2948b52260d3ef4db7a90b01 100644 (file)
@@ -32,7 +32,6 @@ obj-$(CONFIG_INET_ESP) += esp4.o
 obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
 obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
 obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
-obj-$(CONFIG_INET_LRO) += inet_lro.o
 obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
 obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
 obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
index eade66db214e99b42a732c5c8aa8c3744984a06c..0cc923f83e107b429521ef809a5a308c06680e7e 100644 (file)
@@ -1095,12 +1095,6 @@ void inet_unregister_protosw(struct inet_protosw *p)
 }
 EXPORT_SYMBOL(inet_unregister_protosw);
 
-/*
- *      Shall we try to damage output packets if routing dev changes?
- */
-
-int sysctl_ip_dynaddr __read_mostly;
-
 static int inet_sk_reselect_saddr(struct sock *sk)
 {
        struct inet_sock *inet = inet_sk(sk);
@@ -1131,7 +1125,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
        if (new_saddr == old_saddr)
                return 0;
 
-       if (sysctl_ip_dynaddr > 1) {
+       if (sock_net(sk)->ipv4.sysctl_ip_dynaddr > 1) {
                pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n",
                        __func__, &old_saddr, &new_saddr);
        }
@@ -1186,7 +1180,7 @@ int inet_sk_rebuild_header(struct sock *sk)
                 * Other protocols have to map its equivalent state to TCP_SYN_SENT.
                 * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
                 */
-               if (!sysctl_ip_dynaddr ||
+               if (!sock_net(sk)->ipv4.sysctl_ip_dynaddr ||
                    sk->sk_state != TCP_SYN_SENT ||
                    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
                    (err = inet_sk_reselect_saddr(sk)) != 0)
@@ -1386,6 +1380,32 @@ out:
        return pp;
 }
 
+#define SECONDS_PER_DAY        86400
+
+/* inet_current_timestamp - Return IP network timestamp
+ *
+ * Return milliseconds since midnight in network byte order.
+ */
+__be32 inet_current_timestamp(void)
+{
+       u32 secs;
+       u32 msecs;
+       struct timespec64 ts;
+
+       ktime_get_real_ts64(&ts);
+
+       /* Get secs since midnight. */
+       (void)div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs);
+       /* Convert to msecs. */
+       msecs = secs * MSEC_PER_SEC;
+       /* Convert nsec to msec. */
+       msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC;
+
+       /* Convert to network byte order. */
+       return htons(msecs);
+}
+EXPORT_SYMBOL(inet_current_timestamp);
+
 int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        if (sk->sk_family == AF_INET)
index c102eb5ac55c8e3d496821886f874c769abf7cc8..c34c7544d1db2ac1c580585a204b8f459f9a3a43 100644 (file)
@@ -665,7 +665,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
         */
 
        if (!in_dev)
-               goto out;
+               goto out_free_skb;
 
        arp = arp_hdr(skb);
 
@@ -673,7 +673,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
        default:
                if (arp->ar_pro != htons(ETH_P_IP) ||
                    htons(dev_type) != arp->ar_hrd)
-                       goto out;
+                       goto out_free_skb;
                break;
        case ARPHRD_ETHER:
        case ARPHRD_FDDI:
@@ -690,17 +690,17 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
                if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
                     arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
                    arp->ar_pro != htons(ETH_P_IP))
-                       goto out;
+                       goto out_free_skb;
                break;
        case ARPHRD_AX25:
                if (arp->ar_pro != htons(AX25_P_IP) ||
                    arp->ar_hrd != htons(ARPHRD_AX25))
-                       goto out;
+                       goto out_free_skb;
                break;
        case ARPHRD_NETROM:
                if (arp->ar_pro != htons(AX25_P_IP) ||
                    arp->ar_hrd != htons(ARPHRD_NETROM))
-                       goto out;
+                       goto out_free_skb;
                break;
        }
 
@@ -708,7 +708,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
 
        if (arp->ar_op != htons(ARPOP_REPLY) &&
            arp->ar_op != htons(ARPOP_REQUEST))
-               goto out;
+               goto out_free_skb;
 
 /*
  *     Extract fields
@@ -733,7 +733,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
  */
        if (ipv4_is_multicast(tip) ||
            (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))
-               goto out;
+               goto out_free_skb;
 
  /*
   *    For some 802.11 wireless deployments (and possibly other networks),
@@ -741,7 +741,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
   *    and thus should not be accepted.
   */
        if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))
-               goto out;
+               goto out_free_skb;
 
 /*
  *     Special case: We must set Frame Relay source Q.922 address
@@ -778,7 +778,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
                    !arp_ignore(in_dev, sip, tip))
                        arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,
                                     sha, dev->dev_addr, sha, reply_dst);
-               goto out;
+               goto out_consume_skb;
        }
 
        if (arp->ar_op == htons(ARPOP_REQUEST) &&
@@ -803,7 +803,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
                                        neigh_release(n);
                                }
                        }
-                       goto out;
+                       goto out_consume_skb;
                } else if (IN_DEV_FORWARD(in_dev)) {
                        if (addr_type == RTN_UNICAST  &&
                            (arp_fwd_proxy(in_dev, dev, rt) ||
@@ -826,7 +826,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
                                                       in_dev->arp_parms, skb);
                                        goto out_free_dst;
                                }
-                               goto out;
+                               goto out_consume_skb;
                        }
                }
        }
@@ -876,11 +876,16 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
                neigh_release(n);
        }
 
-out:
+out_consume_skb:
        consume_skb(skb);
+
 out_free_dst:
        dst_release(reply_dst);
-       return 0;
+       return NET_RX_SUCCESS;
+
+out_free_skb:
+       kfree_skb(skb);
+       return NET_RX_DROP;
 }
 
 static void parp_redo(struct sk_buff *skb)
@@ -924,11 +929,11 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
 
 consumeskb:
        consume_skb(skb);
-       return 0;
+       return NET_RX_SUCCESS;
 freeskb:
        kfree_skb(skb);
 out_of_mem:
-       return 0;
+       return NET_RX_DROP;
 }
 
 /*
index 3d835313575e07446cd39ce53f9e42bb16e1d0de..65e76a48382c6e212fe42135f59f3636eba5ea4a 100644 (file)
@@ -1194,6 +1194,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        __be32 addr = 0;
        struct in_device *in_dev;
        struct net *net = dev_net(dev);
+       int master_idx;
 
        rcu_read_lock();
        in_dev = __in_dev_get_rcu(dev);
@@ -1214,12 +1215,33 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
        if (addr)
                goto out_unlock;
 no_in_dev:
+       master_idx = l3mdev_master_ifindex_rcu(dev);
+
+       /* For VRFs, the VRF device takes the place of the loopback device,
+        * with addresses on it being preferred.  Note in such cases the
+        * loopback device will be among the devices that fail the master_idx
+        * equality check in the loop below.
+        */
+       if (master_idx &&
+           (dev = dev_get_by_index_rcu(net, master_idx)) &&
+           (in_dev = __in_dev_get_rcu(dev))) {
+               for_primary_ifa(in_dev) {
+                       if (ifa->ifa_scope != RT_SCOPE_LINK &&
+                           ifa->ifa_scope <= scope) {
+                               addr = ifa->ifa_local;
+                               goto out_unlock;
+                       }
+               } endfor_ifa(in_dev);
+       }
 
        /* Not loopback addresses on loopback should be preferred
           in this case. It is important that lo is the first interface
           in dev_base list.
         */
        for_each_netdev_rcu(net, dev) {
+               if (l3mdev_master_ifindex_rcu(dev) != master_idx)
+                       continue;
+
                in_dev = __in_dev_get_rcu(dev);
                if (!in_dev)
                        continue;
@@ -1731,17 +1753,20 @@ static int inet_netconf_msgsize_devconf(int type)
 {
        int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
                   + nla_total_size(4); /* NETCONFA_IFINDEX */
+       bool all = false;
 
-       /* type -1 is used for ALL */
-       if (type == -1 || type == NETCONFA_FORWARDING)
+       if (type == NETCONFA_ALL)
+               all = true;
+
+       if (all || type == NETCONFA_FORWARDING)
                size += nla_total_size(4);
-       if (type == -1 || type == NETCONFA_RP_FILTER)
+       if (all || type == NETCONFA_RP_FILTER)
                size += nla_total_size(4);
-       if (type == -1 || type == NETCONFA_MC_FORWARDING)
+       if (all || type == NETCONFA_MC_FORWARDING)
                size += nla_total_size(4);
-       if (type == -1 || type == NETCONFA_PROXY_NEIGH)
+       if (all || type == NETCONFA_PROXY_NEIGH)
                size += nla_total_size(4);
-       if (type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
+       if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
                size += nla_total_size(4);
 
        return size;
@@ -1754,36 +1779,39 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
 {
        struct nlmsghdr  *nlh;
        struct netconfmsg *ncm;
+       bool all = false;
 
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
                        flags);
        if (!nlh)
                return -EMSGSIZE;
 
+       if (type == NETCONFA_ALL)
+               all = true;
+
        ncm = nlmsg_data(nlh);
        ncm->ncm_family = AF_INET;
 
        if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
                goto nla_put_failure;
 
-       /* type -1 is used for ALL */
-       if ((type == -1 || type == NETCONFA_FORWARDING) &&
+       if ((all || type == NETCONFA_FORWARDING) &&
            nla_put_s32(skb, NETCONFA_FORWARDING,
                        IPV4_DEVCONF(*devconf, FORWARDING)) < 0)
                goto nla_put_failure;
-       if ((type == -1 || type == NETCONFA_RP_FILTER) &&
+       if ((all || type == NETCONFA_RP_FILTER) &&
            nla_put_s32(skb, NETCONFA_RP_FILTER,
                        IPV4_DEVCONF(*devconf, RP_FILTER)) < 0)
                goto nla_put_failure;
-       if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
+       if ((all || type == NETCONFA_MC_FORWARDING) &&
            nla_put_s32(skb, NETCONFA_MC_FORWARDING,
                        IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
                goto nla_put_failure;
-       if ((type == -1 || type == NETCONFA_PROXY_NEIGH) &&
+       if ((all || type == NETCONFA_PROXY_NEIGH) &&
            nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
                        IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
                goto nla_put_failure;
-       if ((type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
+       if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
            nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
                        IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0)
                goto nla_put_failure;
@@ -1847,7 +1875,7 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
        if (err < 0)
                goto errout;
 
-       err = EINVAL;
+       err = -EINVAL;
        if (!tb[NETCONFA_IFINDEX])
                goto errout;
 
@@ -1871,14 +1899,14 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb,
        }
 
        err = -ENOBUFS;
-       skb = nlmsg_new(inet_netconf_msgsize_devconf(-1), GFP_ATOMIC);
+       skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_ATOMIC);
        if (!skb)
                goto errout;
 
        err = inet_netconf_fill_devconf(skb, ifindex, devconf,
                                        NETLINK_CB(in_skb).portid,
                                        nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
-                                       -1);
+                                       NETCONFA_ALL);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */
                WARN_ON(err == -EMSGSIZE);
@@ -1922,7 +1950,7 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
                                                      cb->nlh->nlmsg_seq,
                                                      RTM_NEWNETCONF,
                                                      NLM_F_MULTI,
-                                                     -1) < 0) {
+                                                     NETCONFA_ALL) < 0) {
                                rcu_read_unlock();
                                goto done;
                        }
@@ -1938,7 +1966,7 @@ cont:
                                              NETLINK_CB(cb->skb).portid,
                                              cb->nlh->nlmsg_seq,
                                              RTM_NEWNETCONF, NLM_F_MULTI,
-                                             -1) < 0)
+                                             NETCONFA_ALL) < 0)
                        goto done;
                else
                        h++;
@@ -1949,7 +1977,7 @@ cont:
                                              NETLINK_CB(cb->skb).portid,
                                              cb->nlh->nlmsg_seq,
                                              RTM_NEWNETCONF, NLM_F_MULTI,
-                                             -1) < 0)
+                                             NETCONFA_ALL) < 0)
                        goto done;
                else
                        h++;
index 88dab0c1670c355c21b3c0aecd253e85ec2fd28f..780484243e144006d8ee409b0377ee4eb4db6dd9 100644 (file)
@@ -319,8 +319,6 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
 
        skb_gro_pull(skb, hdrlen);
 
-       flush = 0;
-
        for (p = *head; p; p = p->next) {
                const struct guehdr *guehdr2;
 
@@ -352,6 +350,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head,
                goto out_unlock;
 
        pp = ops->callbacks.gro_receive(head, skb);
+       flush = 0;
 
 out_unlock:
        rcu_read_unlock();
index 003b0ebbcfdda5347037dd6c3d07db3fbbe702db..540866dbd27d6663d4647a5eb1a4e8445b1e6a18 100644 (file)
@@ -24,7 +24,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
        __be16 protocol = skb->protocol;
        u16 mac_len = skb->mac_len;
        int gre_offset, outer_hlen;
-       bool need_csum;
+       bool need_csum, ufo;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
                                ~(SKB_GSO_TCPV4 |
@@ -58,8 +58,20 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
        need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
        skb->encap_hdr_csum = need_csum;
 
+       ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
+
        features &= skb->dev->hw_enc_features;
 
+       /* The only checksum offload we care about from here on out is the
+        * outer one so strip the existing checksum feature flags based
+        * on the fact that we will be computing our checksum in software.
+        */
+       if (ufo) {
+               features &= ~NETIF_F_CSUM_MASK;
+               if (!need_csum)
+                       features |= NETIF_F_HW_CSUM;
+       }
+
        /* segment inner packet. */
        segs = skb_mac_gso_segment(skb, features);
        if (IS_ERR_OR_NULL(segs)) {
@@ -75,8 +87,11 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
                struct gre_base_hdr *greh;
                __be32 *pcsum;
 
-               skb_reset_inner_headers(skb);
-               skb->encapsulation = 1;
+               /* Set up inner headers if we are offloading inner checksum */
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       skb_reset_inner_headers(skb);
+                       skb->encapsulation = 1;
+               }
 
                skb->mac_len = mac_len;
                skb->protocol = protocol;
@@ -160,8 +175,6 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
                                             null_compute_pseudo);
        }
 
-       flush = 0;
-
        for (p = *head; p; p = p->next) {
                const struct gre_base_hdr *greh2;
 
@@ -198,6 +211,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
        skb_gro_postpull_rcsum(skb, greh, grehlen);
 
        pp = ptype->callbacks.gro_receive(head, skb);
+       flush = 0;
 
 out_unlock:
        rcu_read_unlock();
index 36e26977c9088c1dbd09cd13e9a5e2c43369fe31..6333489771ed07bb2509500a2e48fed05643281a 100644 (file)
@@ -931,7 +931,6 @@ static bool icmp_echo(struct sk_buff *skb)
  */
 static bool icmp_timestamp(struct sk_buff *skb)
 {
-       struct timespec tv;
        struct icmp_bxm icmp_param;
        /*
         *      Too short.
@@ -942,9 +941,7 @@ static bool icmp_timestamp(struct sk_buff *skb)
        /*
         *      Fill in the current time as ms since midnight UT:
         */
-       getnstimeofday(&tv);
-       icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC +
-                                        tv.tv_nsec / NSEC_PER_MSEC);
+       icmp_param.data.times[1] = inet_current_timestamp();
        icmp_param.data.times[2] = icmp_param.data.times[1];
        if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
                BUG();
index 7c95335bf85eee105dfe65bfcf9a8448dc83305f..9b4ca87f70bab4e0174b804fac30f949b27d7457 100644 (file)
@@ -350,9 +350,8 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
 
-       skb->reserved_tailroom = skb_end_offset(skb) -
-                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
+       skb_tailroom_reserve(skb, mtu, tlen);
 
        skb_reset_network_header(skb);
        pip = ip_hdr(skb);
@@ -1224,7 +1223,9 @@ static void igmp_group_dropped(struct ip_mc_list *im)
 static void igmp_group_added(struct ip_mc_list *im)
 {
        struct in_device *in_dev = im->interface;
+#ifdef CONFIG_IP_MULTICAST
        struct net *net = dev_net(in_dev->dev);
+#endif
 
        if (im->loaded == 0) {
                im->loaded = 1;
@@ -1316,7 +1317,9 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
 void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 {
        struct ip_mc_list *im;
+#ifdef CONFIG_IP_MULTICAST
        struct net *net = dev_net(in_dev->dev);
+#endif
 
        ASSERT_RTNL();
 
@@ -1643,7 +1646,9 @@ void ip_mc_down(struct in_device *in_dev)
 
 void ip_mc_init_dev(struct in_device *in_dev)
 {
+#ifdef CONFIG_IP_MULTICAST
        struct net *net = dev_net(in_dev->dev);
+#endif
        ASSERT_RTNL();
 
 #ifdef CONFIG_IP_MULTICAST
@@ -1662,7 +1667,9 @@ void ip_mc_init_dev(struct in_device *in_dev)
 void ip_mc_up(struct in_device *in_dev)
 {
        struct ip_mc_list *pmc;
+#ifdef CONFIG_IP_MULTICAST
        struct net *net = dev_net(in_dev->dev);
+#endif
 
        ASSERT_RTNL();
 
@@ -2923,6 +2930,12 @@ static int __net_init igmp_net_init(struct net *net)
                goto out_sock;
        }
 
+       /* Sysctl initialization */
+       net->ipv4.sysctl_igmp_max_memberships = 20;
+       net->ipv4.sysctl_igmp_max_msf = 10;
+       /* IGMP reports for link-local multicast groups are enabled by default */
+       net->ipv4.sysctl_igmp_llm_reports = 1;
+       net->ipv4.sysctl_igmp_qrv = 2;
        return 0;
 
 out_sock:
index 3d28c6d5c3c3e9851a3c85d8cca390e294cc0dfa..bc5196ea1bdfac8e4c8c918eaaf1d3af5f854968 100644 (file)
@@ -202,6 +202,7 @@ tb_found:
 
                if (((tb->fastreuse > 0 && reuse) ||
                     (tb->fastreuseport > 0 &&
+                     !rcu_access_pointer(sk->sk_reuseport_cb) &&
                      sk->sk_reuseport && uid_eq(tb->fastuid, uid))) &&
                    smallest_size == -1)
                        goto success;
@@ -782,14 +783,16 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req,
        reqsk_put(req);
 }
 
-void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req,
-                             struct sock *child)
+struct sock *inet_csk_reqsk_queue_add(struct sock *sk,
+                                     struct request_sock *req,
+                                     struct sock *child)
 {
        struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
 
        spin_lock(&queue->rskq_lock);
        if (unlikely(sk->sk_state != TCP_LISTEN)) {
                inet_child_forget(sk, req, child);
+               child = NULL;
        } else {
                req->sk = child;
                req->dl_next = NULL;
@@ -801,6 +804,7 @@ void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req,
                sk_acceptq_added(sk);
        }
        spin_unlock(&queue->rskq_lock);
+       return child;
 }
 EXPORT_SYMBOL(inet_csk_reqsk_queue_add);
 
@@ -810,11 +814,8 @@ struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child,
        if (own_req) {
                inet_csk_reqsk_queue_drop(sk, req);
                reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req);
-               inet_csk_reqsk_queue_add(sk, req, child);
-               /* Warning: caller must not call reqsk_put(req);
-                * child stole last reference on it.
-                */
-               return child;
+               if (inet_csk_reqsk_queue_add(sk, req, child))
+                       return child;
        }
        /* Too bad, another child took ownership of the request, undo. */
        bh_unlock_sock(child);
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
deleted file mode 100644 (file)
index f17ea49..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- *  linux/net/ipv4/inet_lro.c
- *
- *  Large Receive Offload (ipv4 / tcp)
- *
- *  (C) Copyright IBM Corp. 2007
- *
- *  Authors:
- *       Jan-Bernd Themann <themann@de.ibm.com>
- *       Christoph Raisch <raisch@de.ibm.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include <linux/module.h>
-#include <linux/if_vlan.h>
-#include <linux/inet_lro.h>
-#include <net/checksum.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jan-Bernd Themann <themann@de.ibm.com>");
-MODULE_DESCRIPTION("Large Receive Offload (ipv4 / tcp)");
-
-#define TCP_HDR_LEN(tcph) (tcph->doff << 2)
-#define IP_HDR_LEN(iph) (iph->ihl << 2)
-#define TCP_PAYLOAD_LENGTH(iph, tcph) \
-       (ntohs(iph->tot_len) - IP_HDR_LEN(iph) - TCP_HDR_LEN(tcph))
-
-#define IPH_LEN_WO_OPTIONS 5
-#define TCPH_LEN_WO_OPTIONS 5
-#define TCPH_LEN_W_TIMESTAMP 8
-
-#define LRO_MAX_PG_HLEN 64
-
-#define LRO_INC_STATS(lro_mgr, attr) { lro_mgr->stats.attr++; }
-
-/*
- * Basic tcp checks whether packet is suitable for LRO
- */
-
-static int lro_tcp_ip_check(const struct iphdr *iph, const struct tcphdr *tcph,
-                           int len, const struct net_lro_desc *lro_desc)
-{
-        /* check ip header: don't aggregate padded frames */
-       if (ntohs(iph->tot_len) != len)
-               return -1;
-
-       if (TCP_PAYLOAD_LENGTH(iph, tcph) == 0)
-               return -1;
-
-       if (iph->ihl != IPH_LEN_WO_OPTIONS)
-               return -1;
-
-       if (tcph->cwr || tcph->ece || tcph->urg || !tcph->ack ||
-           tcph->rst || tcph->syn || tcph->fin)
-               return -1;
-
-       if (INET_ECN_is_ce(ipv4_get_dsfield(iph)))
-               return -1;
-
-       if (tcph->doff != TCPH_LEN_WO_OPTIONS &&
-           tcph->doff != TCPH_LEN_W_TIMESTAMP)
-               return -1;
-
-       /* check tcp options (only timestamp allowed) */
-       if (tcph->doff == TCPH_LEN_W_TIMESTAMP) {
-               __be32 *topt = (__be32 *)(tcph + 1);
-
-               if (*topt != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
-                                  | (TCPOPT_TIMESTAMP << 8)
-                                  | TCPOLEN_TIMESTAMP))
-                       return -1;
-
-               /* timestamp should be in right order */
-               topt++;
-               if (lro_desc && after(ntohl(lro_desc->tcp_rcv_tsval),
-                                     ntohl(*topt)))
-                       return -1;
-
-               /* timestamp reply should not be zero */
-               topt++;
-               if (*topt == 0)
-                       return -1;
-       }
-
-       return 0;
-}
-
-static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
-{
-       struct iphdr *iph = lro_desc->iph;
-       struct tcphdr *tcph = lro_desc->tcph;
-       __be32 *p;
-       __wsum tcp_hdr_csum;
-
-       tcph->ack_seq = lro_desc->tcp_ack;
-       tcph->window = lro_desc->tcp_window;
-
-       if (lro_desc->tcp_saw_tstamp) {
-               p = (__be32 *)(tcph + 1);
-               *(p+2) = lro_desc->tcp_rcv_tsecr;
-       }
-
-       csum_replace2(&iph->check, iph->tot_len, htons(lro_desc->ip_tot_len));
-       iph->tot_len = htons(lro_desc->ip_tot_len);
-
-       tcph->check = 0;
-       tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), 0);
-       lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum);
-       tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                       lro_desc->ip_tot_len -
-                                       IP_HDR_LEN(iph), IPPROTO_TCP,
-                                       lro_desc->data_csum);
-}
-
-static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len)
-{
-       __wsum tcp_csum;
-       __wsum tcp_hdr_csum;
-       __wsum tcp_ps_hdr_csum;
-
-       tcp_csum = ~csum_unfold(tcph->check);
-       tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), tcp_csum);
-
-       tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
-                                            len + TCP_HDR_LEN(tcph),
-                                            IPPROTO_TCP, 0);
-
-       return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum),
-                       tcp_ps_hdr_csum);
-}
-
-static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
-                         struct iphdr *iph, struct tcphdr *tcph)
-{
-       int nr_frags;
-       __be32 *ptr;
-       u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
-
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       lro_desc->parent = skb;
-       lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]);
-       lro_desc->iph = iph;
-       lro_desc->tcph = tcph;
-       lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
-       lro_desc->tcp_ack = tcph->ack_seq;
-       lro_desc->tcp_window = tcph->window;
-
-       lro_desc->pkt_aggr_cnt = 1;
-       lro_desc->ip_tot_len = ntohs(iph->tot_len);
-
-       if (tcph->doff == 8) {
-               ptr = (__be32 *)(tcph+1);
-               lro_desc->tcp_saw_tstamp = 1;
-               lro_desc->tcp_rcv_tsval = *(ptr+1);
-               lro_desc->tcp_rcv_tsecr = *(ptr+2);
-       }
-
-       lro_desc->mss = tcp_data_len;
-       lro_desc->active = 1;
-
-       lro_desc->data_csum = lro_tcp_data_csum(iph, tcph,
-                                               tcp_data_len);
-}
-
-static inline void lro_clear_desc(struct net_lro_desc *lro_desc)
-{
-       memset(lro_desc, 0, sizeof(struct net_lro_desc));
-}
-
-static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
-                          struct tcphdr *tcph, int tcp_data_len)
-{
-       struct sk_buff *parent = lro_desc->parent;
-       __be32 *topt;
-
-       lro_desc->pkt_aggr_cnt++;
-       lro_desc->ip_tot_len += tcp_data_len;
-       lro_desc->tcp_next_seq += tcp_data_len;
-       lro_desc->tcp_window = tcph->window;
-       lro_desc->tcp_ack = tcph->ack_seq;
-
-       /* don't update tcp_rcv_tsval, would not work with PAWS */
-       if (lro_desc->tcp_saw_tstamp) {
-               topt = (__be32 *) (tcph + 1);
-               lro_desc->tcp_rcv_tsecr = *(topt + 2);
-       }
-
-       lro_desc->data_csum = csum_block_add(lro_desc->data_csum,
-                                            lro_tcp_data_csum(iph, tcph,
-                                                              tcp_data_len),
-                                            parent->len);
-
-       parent->len += tcp_data_len;
-       parent->data_len += tcp_data_len;
-       if (tcp_data_len > lro_desc->mss)
-               lro_desc->mss = tcp_data_len;
-}
-
-static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb,
-                          struct iphdr *iph, struct tcphdr *tcph)
-{
-       struct sk_buff *parent = lro_desc->parent;
-       int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
-
-       lro_add_common(lro_desc, iph, tcph, tcp_data_len);
-
-       skb_pull(skb, (skb->len - tcp_data_len));
-       parent->truesize += skb->truesize;
-
-       if (lro_desc->last_skb)
-               lro_desc->last_skb->next = skb;
-       else
-               skb_shinfo(parent)->frag_list = skb;
-
-       lro_desc->last_skb = skb;
-}
-
-
-static int lro_check_tcp_conn(struct net_lro_desc *lro_desc,
-                             struct iphdr *iph,
-                             struct tcphdr *tcph)
-{
-       if ((lro_desc->iph->saddr != iph->saddr) ||
-           (lro_desc->iph->daddr != iph->daddr) ||
-           (lro_desc->tcph->source != tcph->source) ||
-           (lro_desc->tcph->dest != tcph->dest))
-               return -1;
-       return 0;
-}
-
-static struct net_lro_desc *lro_get_desc(struct net_lro_mgr *lro_mgr,
-                                        struct net_lro_desc *lro_arr,
-                                        struct iphdr *iph,
-                                        struct tcphdr *tcph)
-{
-       struct net_lro_desc *lro_desc = NULL;
-       struct net_lro_desc *tmp;
-       int max_desc = lro_mgr->max_desc;
-       int i;
-
-       for (i = 0; i < max_desc; i++) {
-               tmp = &lro_arr[i];
-               if (tmp->active)
-                       if (!lro_check_tcp_conn(tmp, iph, tcph)) {
-                               lro_desc = tmp;
-                               goto out;
-                       }
-       }
-
-       for (i = 0; i < max_desc; i++) {
-               if (!lro_arr[i].active) {
-                       lro_desc = &lro_arr[i];
-                       goto out;
-               }
-       }
-
-       LRO_INC_STATS(lro_mgr, no_desc);
-out:
-       return lro_desc;
-}
-
-static void lro_flush(struct net_lro_mgr *lro_mgr,
-                     struct net_lro_desc *lro_desc)
-{
-       if (lro_desc->pkt_aggr_cnt > 1)
-               lro_update_tcp_ip_header(lro_desc);
-
-       skb_shinfo(lro_desc->parent)->gso_size = lro_desc->mss;
-
-       if (lro_mgr->features & LRO_F_NAPI)
-               netif_receive_skb(lro_desc->parent);
-       else
-               netif_rx(lro_desc->parent);
-
-       LRO_INC_STATS(lro_mgr, flushed);
-       lro_clear_desc(lro_desc);
-}
-
-static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
-                         void *priv)
-{
-       struct net_lro_desc *lro_desc;
-       struct iphdr *iph;
-       struct tcphdr *tcph;
-       u64 flags;
-       int vlan_hdr_len = 0;
-
-       if (!lro_mgr->get_skb_header ||
-           lro_mgr->get_skb_header(skb, (void *)&iph, (void *)&tcph,
-                                   &flags, priv))
-               goto out;
-
-       if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
-               goto out;
-
-       lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
-       if (!lro_desc)
-               goto out;
-
-       if ((skb->protocol == htons(ETH_P_8021Q)) &&
-           !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID))
-               vlan_hdr_len = VLAN_HLEN;
-
-       if (!lro_desc->active) { /* start new lro session */
-               if (lro_tcp_ip_check(iph, tcph, skb->len - vlan_hdr_len, NULL))
-                       goto out;
-
-               skb->ip_summed = lro_mgr->ip_summed_aggr;
-               lro_init_desc(lro_desc, skb, iph, tcph);
-               LRO_INC_STATS(lro_mgr, aggregated);
-               return 0;
-       }
-
-       if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
-               goto out2;
-
-       if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc))
-               goto out2;
-
-       lro_add_packet(lro_desc, skb, iph, tcph);
-       LRO_INC_STATS(lro_mgr, aggregated);
-
-       if ((lro_desc->pkt_aggr_cnt >= lro_mgr->max_aggr) ||
-           lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu))
-               lro_flush(lro_mgr, lro_desc);
-
-       return 0;
-
-out2: /* send aggregated SKBs to stack */
-       lro_flush(lro_mgr, lro_desc);
-
-out:
-       return 1;
-}
-
-void lro_receive_skb(struct net_lro_mgr *lro_mgr,
-                    struct sk_buff *skb,
-                    void *priv)
-{
-       if (__lro_proc_skb(lro_mgr, skb, priv)) {
-               if (lro_mgr->features & LRO_F_NAPI)
-                       netif_receive_skb(skb);
-               else
-                       netif_rx(skb);
-       }
-}
-EXPORT_SYMBOL(lro_receive_skb);
-
-void lro_flush_all(struct net_lro_mgr *lro_mgr)
-{
-       int i;
-       struct net_lro_desc *lro_desc = lro_mgr->lro_arr;
-
-       for (i = 0; i < lro_mgr->max_desc; i++) {
-               if (lro_desc[i].active)
-                       lro_flush(lro_mgr, &lro_desc[i]);
-       }
-}
-EXPORT_SYMBOL(lro_flush_all);
index da0d7ce85844a9ed0732883ac363ab2de62f3a9b..af18f1e4889eec42a162a370c2d0d049fe2a82bb 100644 (file)
@@ -71,7 +71,6 @@ static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *s
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
-       skb_sender_cpu_clear(skb);
        return dst_output(net, sk, skb);
 }
 
index 187c6fcc3027779ba31d0721eb4a7389addaaf8a..efbd47d1a53155496e236eb7d4d0c893ef533d1c 100644 (file)
@@ -54,8 +54,6 @@
  * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c
  * as well. Or notify me, at least. --ANK
  */
-
-static int sysctl_ipfrag_max_dist __read_mostly = 64;
 static const char ip_frag_cache_name[] = "ip4-frags";
 
 struct ipfrag_skb_cb
@@ -150,7 +148,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
        qp->daddr = arg->iph->daddr;
        qp->vif = arg->vif;
        qp->user = arg->user;
-       qp->peer = sysctl_ipfrag_max_dist ?
+       qp->peer = q->net->max_dist ?
                inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, arg->vif, 1) :
                NULL;
 }
@@ -275,7 +273,7 @@ static struct ipq *ip_find(struct net *net, struct iphdr *iph,
 static int ip_frag_too_far(struct ipq *qp)
 {
        struct inet_peer *peer = qp->peer;
-       unsigned int max = sysctl_ipfrag_max_dist;
+       unsigned int max = qp->q.net->max_dist;
        unsigned int start, end;
 
        int rc;
@@ -749,6 +747,14 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
+       {
+               .procname       = "ipfrag_max_dist",
+               .data           = &init_net.ipv4.frags.max_dist,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero
+       },
        { }
 };
 
@@ -762,14 +768,6 @@ static struct ctl_table ip4_frags_ctl_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .procname       = "ipfrag_max_dist",
-               .data           = &sysctl_ipfrag_max_dist,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero
-       },
        { }
 };
 
@@ -790,10 +788,7 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net)
                table[1].data = &net->ipv4.frags.low_thresh;
                table[1].extra2 = &net->ipv4.frags.high_thresh;
                table[2].data = &net->ipv4.frags.timeout;
-
-               /* Don't export sysctls to unprivileged users */
-               if (net->user_ns != &init_user_ns)
-                       table[0].procname = NULL;
+               table[3].data = &net->ipv4.frags.max_dist;
        }
 
        hdr = register_net_sysctl(net, "net/ipv4", table);
@@ -865,6 +860,8 @@ static int __net_init ipv4_frags_init_net(struct net *net)
         */
        net->ipv4.frags.timeout = IP_FRAG_TIME;
 
+       net->ipv4.frags.max_dist = 64;
+
        res = inet_frags_init_net(&net->ipv4.frags);
        if (res)
                return res;
index 65748db44285e45ee909eeac6f21f14d617eab90..31936d387cfd58b75218d340f683880e486c7351 100644 (file)
@@ -238,7 +238,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                                return -EINVAL;
                }
        }
-       return iptunnel_pull_header(skb, hdr_len, tpi->proto);
+       return iptunnel_pull_header(skb, hdr_len, tpi->proto, false);
 }
 
 static void ipgre_err(struct sk_buff *skb, u32 info,
@@ -527,11 +527,12 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip_tunnel_info *tun_info;
        const struct ip_tunnel_key *key;
+       struct rtable *rt = NULL;
        struct flowi4 fl;
-       struct rtable *rt;
        int min_headroom;
        int tunnel_hlen;
        __be16 df, flags;
+       bool use_cache;
        int err;
 
        tun_info = skb_tunnel_info(skb);
@@ -540,9 +541,17 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev)
                goto err_free_skb;
 
        key = &tun_info->key;
-       rt = gre_get_rt(skb, dev, &fl, key);
-       if (IS_ERR(rt))
-               goto err_free_skb;
+       use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
+       if (use_cache)
+               rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl.saddr);
+       if (!rt) {
+               rt = gre_get_rt(skb, dev, &fl, key);
+               if (IS_ERR(rt))
+                               goto err_free_skb;
+               if (use_cache)
+                       dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
+                                         fl.saddr);
+       }
 
        tunnel_hlen = ip_gre_calc_hlen(key->tun_flags);
 
@@ -1063,8 +1072,9 @@ static const struct net_device_ops gre_tap_netdev_ops = {
 static void ipgre_tap_setup(struct net_device *dev)
 {
        ether_setup(dev);
-       dev->netdev_ops         = &gre_tap_netdev_ops;
-       dev->priv_flags         |= IFF_LIVE_ADDR_CHANGE;
+       dev->netdev_ops = &gre_tap_netdev_ops;
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+       dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
        ip_tunnel_setup(dev, gre_tap_net_id);
 }
 
@@ -1249,6 +1259,14 @@ struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
        err = ipgre_newlink(net, dev, tb, NULL);
        if (err < 0)
                goto out;
+
+       /* openvswitch users expect packet sizes to be unrestricted,
+        * so set the largest MTU we can.
+        */
+       err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false);
+       if (err)
+               goto out;
+
        return dev;
 out:
        free_netdev(dev);
index 852002f64c68455474123f5bb66abb0bd5583e41..e3d782746d9db79b0ad03d1059316bebb73207a4 100644 (file)
@@ -308,15 +308,12 @@ drop:
        return true;
 }
 
-int sysctl_ip_early_demux __read_mostly = 1;
-EXPORT_SYMBOL(sysctl_ip_early_demux);
-
 static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        const struct iphdr *iph = ip_hdr(skb);
        struct rtable *rt;
 
-       if (sysctl_ip_early_demux &&
+       if (net->ipv4.sysctl_ip_early_demux &&
            !skb_dst(skb) &&
            !skb->sk &&
            !ip_is_fragment(iph)) {
index bd246792360b4b8dcda2c13328ea5f01bb603e06..4d158ff1def1a8fae218b268c7e66224eed95adf 100644 (file)
@@ -58,10 +58,9 @@ void ip_options_build(struct sk_buff *skb, struct ip_options *opt,
                if (opt->ts_needaddr)
                        ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt);
                if (opt->ts_needtime) {
-                       struct timespec tv;
                        __be32 midtime;
-                       getnstimeofday(&tv);
-                       midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC);
+
+                       midtime = inet_current_timestamp();
                        memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
                }
                return;
@@ -415,11 +414,10 @@ int ip_options_compile(struct net *net,
                                        break;
                                }
                                if (timeptr) {
-                                       struct timespec tv;
-                                       u32  midtime;
-                                       getnstimeofday(&tv);
-                                       midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC;
-                                       put_unaligned_be32(midtime, timeptr);
+                                       __be32 midtime;
+
+                                       midtime = inet_current_timestamp();
+                                       memcpy(timeptr, &midtime, 4);
                                        opt->is_changed = 1;
                                }
                        } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) {
index 64878efa045c132d1ce511c326c2da04fc77a895..124bf0a663283502deb03397343160d493a378b1 100644 (file)
@@ -79,9 +79,6 @@
 #include <linux/netlink.h>
 #include <linux/tcp.h>
 
-int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
-EXPORT_SYMBOL(sysctl_ip_default_ttl);
-
 static int
 ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
            unsigned int mtu,
@@ -1236,13 +1233,16 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
        if (!skb)
                return -EINVAL;
 
-       cork->length += size;
        if ((size + skb->len > mtu) &&
            (sk->sk_protocol == IPPROTO_UDP) &&
            (rt->dst.dev->features & NETIF_F_UFO)) {
+               if (skb->ip_summed != CHECKSUM_PARTIAL)
+                       return -EOPNOTSUPP;
+
                skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
        }
+       cork->length += size;
 
        while (size > 0) {
                if (skb_is_gso(skb)) {
index 92808f147ef5bafa61ce538ec5cb99df8945e45d..035ad645a8d9d8abd55321ad2bcd0e44d1d0fc3c 100644 (file)
@@ -249,6 +249,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc,
                switch (cmsg->cmsg_type) {
                case IP_RETOPTS:
                        err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
+
+                       /* Our caller is responsible for freeing ipc->opt */
                        err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg),
                                             err < 40 ? err : 40);
                        if (err)
@@ -1341,10 +1343,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                val = inet->tos;
                break;
        case IP_TTL:
+       {
+               struct net *net = sock_net(sk);
                val = (inet->uc_ttl == -1 ?
-                      sysctl_ip_default_ttl :
+                      net->ipv4.sysctl_ip_default_ttl :
                       inet->uc_ttl);
                break;
+       }
        case IP_HDRINCL:
                val = inet->hdrincl;
                break;
index c7bd72e9b544848d10a490b010e0a30c4d5e4c21..6aad0192443d49966785f0de67ee30934775dfca 100644 (file)
@@ -68,61 +68,6 @@ static unsigned int ip_tunnel_hash(__be32 key, __be32 remote)
                         IP_TNL_HASH_BITS);
 }
 
-static void __tunnel_dst_set(struct ip_tunnel_dst *idst,
-                            struct dst_entry *dst, __be32 saddr)
-{
-       struct dst_entry *old_dst;
-
-       dst_clone(dst);
-       old_dst = xchg((__force struct dst_entry **)&idst->dst, dst);
-       dst_release(old_dst);
-       idst->saddr = saddr;
-}
-
-static noinline void tunnel_dst_set(struct ip_tunnel *t,
-                          struct dst_entry *dst, __be32 saddr)
-{
-       __tunnel_dst_set(raw_cpu_ptr(t->dst_cache), dst, saddr);
-}
-
-static void tunnel_dst_reset(struct ip_tunnel *t)
-{
-       tunnel_dst_set(t, NULL, 0);
-}
-
-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, 0);
-}
-EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
-
-static struct rtable *tunnel_rtable_get(struct ip_tunnel *t,
-                                       u32 cookie, __be32 *saddr)
-{
-       struct ip_tunnel_dst *idst;
-       struct dst_entry *dst;
-
-       rcu_read_lock();
-       idst = raw_cpu_ptr(t->dst_cache);
-       dst = rcu_dereference(idst->dst);
-       if (dst && !atomic_inc_not_zero(&dst->__refcnt))
-               dst = NULL;
-       if (dst) {
-               if (!dst->obsolete || dst->ops->check(dst, cookie)) {
-                       *saddr = idst->saddr;
-               } else {
-                       tunnel_dst_reset(t);
-                       dst_release(dst);
-                       dst = NULL;
-               }
-       }
-       rcu_read_unlock();
-       return (struct rtable *)dst;
-}
-
 static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
                                __be16 flags, __be32 key)
 {
@@ -381,7 +326,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
 
                if (!IS_ERR(rt)) {
                        tdev = rt->dst.dev;
-                       tunnel_dst_set(tunnel, &rt->dst, fl4.saddr);
+                       dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
+                                         fl4.saddr);
                        ip_rt_put(rt);
                }
                if (dev->type != ARPHRD_ETHER)
@@ -661,6 +607,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
        connected = (tunnel->parms.iph.daddr != 0);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        dst = tnl_params->daddr;
        if (dst == 0) {
                /* NBMA tunnel */
@@ -729,7 +677,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
                goto tx_error;
 
-       rt = connected ? tunnel_rtable_get(tunnel, 0, &fl4.saddr) : NULL;
+       rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) :
+                        NULL;
 
        if (!rt) {
                rt = ip_route_output_key(tunnel->net, &fl4);
@@ -739,7 +688,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                        goto tx_error;
                }
                if (connected)
-                       tunnel_dst_set(tunnel, &rt->dst, fl4.saddr);
+                       dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
+                                         fl4.saddr);
        }
 
        if (rt->dst.dev == dev) {
@@ -758,7 +708,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                                tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
 
-                       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                        dst_link_failure(skb);
                } else
                        tunnel->err_count = 0;
@@ -836,7 +785,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
                if (set_mtu)
                        dev->mtu = mtu;
        }
-       ip_tunnel_dst_reset_all(t);
+       dst_cache_reset(&t->dst_cache);
        netdev_state_change(dev);
 }
 
@@ -943,17 +892,31 @@ done:
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
 
-int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        int t_hlen = tunnel->hlen + sizeof(struct iphdr);
+       int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
 
-       if (new_mtu < 68 ||
-           new_mtu > 0xFFF8 - dev->hard_header_len - t_hlen)
+       if (new_mtu < 68)
                return -EINVAL;
+
+       if (new_mtu > max_mtu) {
+               if (strict)
+                       return -EINVAL;
+
+               new_mtu = max_mtu;
+       }
+
        dev->mtu = new_mtu;
        return 0;
 }
+EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu);
+
+int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+{
+       return __ip_tunnel_change_mtu(dev, new_mtu, true);
+}
 EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
 
 static void ip_tunnel_dev_free(struct net_device *dev)
@@ -961,7 +924,7 @@ static void ip_tunnel_dev_free(struct net_device *dev)
        struct ip_tunnel *tunnel = netdev_priv(dev);
 
        gro_cells_destroy(&tunnel->gro_cells);
-       free_percpu(tunnel->dst_cache);
+       dst_cache_destroy(&tunnel->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1155,15 +1118,15 @@ int ip_tunnel_init(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
-       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
-       if (!tunnel->dst_cache) {
+       err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
+       if (err) {
                free_percpu(dev->tstats);
-               return -ENOMEM;
+               return err;
        }
 
        err = gro_cells_init(&tunnel->gro_cells, dev);
        if (err) {
-               free_percpu(tunnel->dst_cache);
+               dst_cache_destroy(&tunnel->dst_cache);
                free_percpu(dev->tstats);
                return err;
        }
@@ -1193,7 +1156,7 @@ void ip_tunnel_uninit(struct net_device *dev)
        if (itn->fb_tunnel_dev != dev)
                ip_tunnel_del(itn, netdev_priv(dev));
 
-       ip_tunnel_dst_reset_all(tunnel);
+       dst_cache_reset(&tunnel->dst_cache);
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
 
index a6e58b6141cdc525435f7292dc97c1e244adb8ad..eaca2449a09acae2374e4cb4a629702f95c5b510 100644 (file)
@@ -86,7 +86,8 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
 }
 EXPORT_SYMBOL_GPL(iptunnel_xmit);
 
-int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
+int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto,
+                        bool xnet)
 {
        if (unlikely(!pskb_may_pull(skb, hdr_len)))
                return -ENOMEM;
@@ -109,13 +110,10 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
                skb->protocol = 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;
+       skb_scrub_packet(skb, xnet);
        return 0;
 }
 EXPORT_SYMBOL_GPL(iptunnel_pull_header);
index 6ec5b42fd1722eefa5968ac0b7a4265eea167289..ec51d02166de66744f27092f1490bb635c9a70bc 100644 (file)
@@ -195,7 +195,7 @@ static int ipip_rcv(struct sk_buff *skb)
        if (tunnel) {
                if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
                        goto drop;
-               if (iptunnel_pull_header(skb, 0, tpi.proto))
+               if (iptunnel_pull_header(skb, 0, tpi.proto, false))
                        goto drop;
                return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
        }
index b488cac9c5ca5496238bcc31a02887362655212b..bf081927e06bed507d2ee798eb5bdd21d4d8d761 100644 (file)
@@ -1780,9 +1780,29 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        return ret;
 }
 
-struct xt_table *arpt_register_table(struct net *net,
-                                    const struct xt_table *table,
-                                    const struct arpt_replace *repl)
+static void __arpt_unregister_table(struct xt_table *table)
+{
+       struct xt_table_info *private;
+       void *loc_cpu_entry;
+       struct module *table_owner = table->me;
+       struct arpt_entry *iter;
+
+       private = xt_unregister_table(table);
+
+       /* Decrease module usage counts and free resources */
+       loc_cpu_entry = private->entries;
+       xt_entry_foreach(iter, loc_cpu_entry, private->size)
+               cleanup_entry(iter);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
+       xt_free_table_info(private);
+}
+
+int arpt_register_table(struct net *net,
+                       const struct xt_table *table,
+                       const struct arpt_replace *repl,
+                       const struct nf_hook_ops *ops,
+                       struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -1791,10 +1811,8 @@ struct xt_table *arpt_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -1809,30 +1827,28 @@ struct xt_table *arpt_register_table(struct net *net,
                ret = PTR_ERR(new_table);
                goto out_free;
        }
-       return new_table;
+
+       /* set res now, will see skbs right after nf_register_net_hooks */
+       WRITE_ONCE(*res, new_table);
+
+       ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
+       if (ret != 0) {
+               __arpt_unregister_table(new_table);
+               *res = NULL;
+       }
+
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void arpt_unregister_table(struct xt_table *table)
+void arpt_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops)
 {
-       struct xt_table_info *private;
-       void *loc_cpu_entry;
-       struct module *table_owner = table->me;
-       struct arpt_entry *iter;
-
-       private = xt_unregister_table(table);
-
-       /* Decrease module usage counts and free resources */
-       loc_cpu_entry = private->entries;
-       xt_entry_foreach(iter, loc_cpu_entry, private->size)
-               cleanup_entry(iter);
-       if (private->number > private->initial_entries)
-               module_put(table_owner);
-       xt_free_table_info(private);
+       nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
+       __arpt_unregister_table(table);
 }
 
 /* The built-in targets: standard (NULL) and error. */
index 1897ee1609202f326a98f96536a00acd96204a13..dd8c80dc32a2216d3705b75cc761bdb156806dc9 100644 (file)
@@ -17,12 +17,15 @@ MODULE_DESCRIPTION("arptables filter table");
 #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
                           (1 << NF_ARP_FORWARD))
 
+static int __net_init arptable_filter_table_init(struct net *net);
+
 static const struct xt_table packet_filter = {
        .name           = "filter",
        .valid_hooks    = FILTER_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_ARP,
        .priority       = NF_IP_PRI_FILTER,
+       .table_init     = arptable_filter_table_init,
 };
 
 /* The work comes in here from netfilter.c */
@@ -35,26 +38,32 @@ arptable_filter_hook(void *priv, struct sk_buff *skb,
 
 static struct nf_hook_ops *arpfilter_ops __read_mostly;
 
-static int __net_init arptable_filter_net_init(struct net *net)
+static int __net_init arptable_filter_table_init(struct net *net)
 {
        struct arpt_replace *repl;
-       
+       int err;
+
+       if (net->ipv4.arptable_filter)
+               return 0;
+
        repl = arpt_alloc_initial_table(&packet_filter);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.arptable_filter =
-               arpt_register_table(net, &packet_filter, repl);
+       err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops,
+                                 &net->ipv4.arptable_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter);
+       return err;
 }
 
 static void __net_exit arptable_filter_net_exit(struct net *net)
 {
-       arpt_unregister_table(net->ipv4.arptable_filter);
+       if (!net->ipv4.arptable_filter)
+               return;
+       arpt_unregister_table(net, net->ipv4.arptable_filter, arpfilter_ops);
+       net->ipv4.arptable_filter = NULL;
 }
 
 static struct pernet_operations arptable_filter_net_ops = {
-       .init = arptable_filter_net_init,
        .exit = arptable_filter_net_exit,
 };
 
@@ -62,26 +71,23 @@ static int __init arptable_filter_init(void)
 {
        int ret;
 
+       arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arptable_filter_hook);
+       if (IS_ERR(arpfilter_ops))
+               return PTR_ERR(arpfilter_ops);
+
        ret = register_pernet_subsys(&arptable_filter_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(arpfilter_ops);
                return ret;
-
-       arpfilter_ops = xt_hook_link(&packet_filter, arptable_filter_hook);
-       if (IS_ERR(arpfilter_ops)) {
-               ret = PTR_ERR(arpfilter_ops);
-               goto cleanup_table;
        }
-       return ret;
 
-cleanup_table:
-       unregister_pernet_subsys(&arptable_filter_net_ops);
        return ret;
 }
 
 static void __exit arptable_filter_fini(void)
 {
-       xt_hook_unlink(&packet_filter, arpfilter_ops);
        unregister_pernet_subsys(&arptable_filter_net_ops);
+       kfree(arpfilter_ops);
 }
 
 module_init(arptable_filter_init);
index b99affad6ba1f4939e10f676a06f92cd27c32add..e53f8d6f326d835eca7a5f9ada7c52f477962679 100644 (file)
@@ -2062,9 +2062,27 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-struct xt_table *ipt_register_table(struct net *net,
-                                   const struct xt_table *table,
-                                   const struct ipt_replace *repl)
+static void __ipt_unregister_table(struct net *net, struct xt_table *table)
+{
+       struct xt_table_info *private;
+       void *loc_cpu_entry;
+       struct module *table_owner = table->me;
+       struct ipt_entry *iter;
+
+       private = xt_unregister_table(table);
+
+       /* Decrease module usage counts and free resources */
+       loc_cpu_entry = private->entries;
+       xt_entry_foreach(iter, loc_cpu_entry, private->size)
+               cleanup_entry(iter, net);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
+       xt_free_table_info(private);
+}
+
+int ipt_register_table(struct net *net, const struct xt_table *table,
+                      const struct ipt_replace *repl,
+                      const struct nf_hook_ops *ops, struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -2073,10 +2091,8 @@ struct xt_table *ipt_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -2091,30 +2107,27 @@ struct xt_table *ipt_register_table(struct net *net,
                goto out_free;
        }
 
-       return new_table;
+       /* set res now, will see skbs right after nf_register_net_hooks */
+       WRITE_ONCE(*res, new_table);
+
+       ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
+       if (ret != 0) {
+               __ipt_unregister_table(net, new_table);
+               *res = NULL;
+       }
+
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void ipt_unregister_table(struct net *net, struct xt_table *table)
+void ipt_unregister_table(struct net *net, struct xt_table *table,
+                         const struct nf_hook_ops *ops)
 {
-       struct xt_table_info *private;
-       void *loc_cpu_entry;
-       struct module *table_owner = table->me;
-       struct ipt_entry *iter;
-
-       private = xt_unregister_table(table);
-
-       /* Decrease module usage counts and free resources */
-       loc_cpu_entry = private->entries;
-       xt_entry_foreach(iter, loc_cpu_entry, private->size)
-               cleanup_entry(iter, net);
-       if (private->number > private->initial_entries)
-               module_put(table_owner);
-       xt_free_table_info(private);
+       nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
+       __ipt_unregister_table(net, table);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
index 5fdc556514bac3335f0c4f78b2c01c54f1c8b68f..7b8fbb35287785ff4cf3168c47a2e251969e8254 100644 (file)
@@ -21,6 +21,7 @@ static struct iphdr *
 synproxy_build_ip(struct sk_buff *skb, __be32 saddr, __be32 daddr)
 {
        struct iphdr *iph;
+       struct net *net = sock_net(skb->sk);
 
        skb_reset_network_header(skb);
        iph = (struct iphdr *)skb_put(skb, sizeof(*iph));
@@ -29,7 +30,7 @@ synproxy_build_ip(struct sk_buff *skb, __be32 saddr, __be32 daddr)
        iph->tos        = 0;
        iph->id         = 0;
        iph->frag_off   = htons(IP_DF);
-       iph->ttl        = sysctl_ip_default_ttl;
+       iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
        iph->protocol   = IPPROTO_TCP;
        iph->check      = 0;
        iph->saddr      = saddr;
index 397ef2dd133ed56f9edb3146e30ee46f99a3f50d..7667f223d7f8c12321537919dbc5260c0813e474 100644 (file)
@@ -23,6 +23,7 @@ MODULE_DESCRIPTION("iptables filter table");
 #define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \
                            (1 << NF_INET_FORWARD) | \
                            (1 << NF_INET_LOCAL_OUT))
+static int __net_init iptable_filter_table_init(struct net *net);
 
 static const struct xt_table packet_filter = {
        .name           = "filter",
@@ -30,6 +31,7 @@ static const struct xt_table packet_filter = {
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_FILTER,
+       .table_init     = iptable_filter_table_init,
 };
 
 static unsigned int
@@ -48,12 +50,16 @@ iptable_filter_hook(void *priv, struct sk_buff *skb,
 static struct nf_hook_ops *filter_ops __read_mostly;
 
 /* Default to forward because I got too much mail already. */
-static bool forward = true;
+static bool forward __read_mostly = true;
 module_param(forward, bool, 0000);
 
-static int __net_init iptable_filter_net_init(struct net *net)
+static int __net_init iptable_filter_table_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int err;
+
+       if (net->ipv4.iptable_filter)
+               return 0;
 
        repl = ipt_alloc_initial_table(&packet_filter);
        if (repl == NULL)
@@ -62,15 +68,26 @@ static int __net_init iptable_filter_net_init(struct net *net)
        ((struct ipt_standard *)repl->entries)[1].target.verdict =
                forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
-       net->ipv4.iptable_filter =
-               ipt_register_table(net, &packet_filter, repl);
+       err = ipt_register_table(net, &packet_filter, repl, filter_ops,
+                                &net->ipv4.iptable_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter);
+       return err;
+}
+
+static int __net_init iptable_filter_net_init(struct net *net)
+{
+       if (net == &init_net || !forward)
+               return iptable_filter_table_init(net);
+
+       return 0;
 }
 
 static void __net_exit iptable_filter_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_filter);
+       if (!net->ipv4.iptable_filter)
+               return;
+       ipt_unregister_table(net, net->ipv4.iptable_filter, filter_ops);
+       net->ipv4.iptable_filter = NULL;
 }
 
 static struct pernet_operations iptable_filter_net_ops = {
@@ -82,24 +99,21 @@ static int __init iptable_filter_init(void)
 {
        int ret;
 
+       filter_ops = xt_hook_ops_alloc(&packet_filter, iptable_filter_hook);
+       if (IS_ERR(filter_ops))
+               return PTR_ERR(filter_ops);
+
        ret = register_pernet_subsys(&iptable_filter_net_ops);
        if (ret < 0)
-               return ret;
-
-       /* Register hooks */
-       filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
-       if (IS_ERR(filter_ops)) {
-               ret = PTR_ERR(filter_ops);
-               unregister_pernet_subsys(&iptable_filter_net_ops);
-       }
+               kfree(filter_ops);
 
        return ret;
 }
 
 static void __exit iptable_filter_fini(void)
 {
-       xt_hook_unlink(&packet_filter, filter_ops);
        unregister_pernet_subsys(&iptable_filter_net_ops);
+       kfree(filter_ops);
 }
 
 module_init(iptable_filter_init);
index ba5d392a13c41c74501cc2b76805d04a06b2675e..57fc97cdac700c1c368da47d40270ba7f0b8679f 100644 (file)
@@ -28,12 +28,15 @@ MODULE_DESCRIPTION("iptables mangle table");
                            (1 << NF_INET_LOCAL_OUT) | \
                            (1 << NF_INET_POST_ROUTING))
 
+static int __net_init iptable_mangle_table_init(struct net *net);
+
 static const struct xt_table packet_mangler = {
        .name           = "mangle",
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_MANGLE,
+       .table_init     = iptable_mangle_table_init,
 };
 
 static unsigned int
@@ -92,27 +95,32 @@ iptable_mangle_hook(void *priv,
 }
 
 static struct nf_hook_ops *mangle_ops __read_mostly;
-
-static int __net_init iptable_mangle_net_init(struct net *net)
+static int __net_init iptable_mangle_table_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
+
+       if (net->ipv4.iptable_mangle)
+               return 0;
 
        repl = ipt_alloc_initial_table(&packet_mangler);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_mangle =
-               ipt_register_table(net, &packet_mangler, repl);
+       ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
+                                &net->ipv4.iptable_mangle);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle);
+       return ret;
 }
 
 static void __net_exit iptable_mangle_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_mangle);
+       if (!net->ipv4.iptable_mangle)
+               return;
+       ipt_unregister_table(net, net->ipv4.iptable_mangle, mangle_ops);
+       net->ipv4.iptable_mangle = NULL;
 }
 
 static struct pernet_operations iptable_mangle_net_ops = {
-       .init = iptable_mangle_net_init,
        .exit = iptable_mangle_net_exit,
 };
 
@@ -120,15 +128,22 @@ static int __init iptable_mangle_init(void)
 {
        int ret;
 
+       mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook);
+       if (IS_ERR(mangle_ops)) {
+               ret = PTR_ERR(mangle_ops);
+               return ret;
+       }
+
        ret = register_pernet_subsys(&iptable_mangle_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(mangle_ops);
                return ret;
+       }
 
-       /* Register hooks */
-       mangle_ops = xt_hook_link(&packet_mangler, iptable_mangle_hook);
-       if (IS_ERR(mangle_ops)) {
-               ret = PTR_ERR(mangle_ops);
+       ret = iptable_mangle_table_init(&init_net);
+       if (ret) {
                unregister_pernet_subsys(&iptable_mangle_net_ops);
+               kfree(mangle_ops);
        }
 
        return ret;
@@ -136,8 +151,8 @@ static int __init iptable_mangle_init(void)
 
 static void __exit iptable_mangle_fini(void)
 {
-       xt_hook_unlink(&packet_mangler, mangle_ops);
        unregister_pernet_subsys(&iptable_mangle_net_ops);
+       kfree(mangle_ops);
 }
 
 module_init(iptable_mangle_init);
index ae2cd275204643ebff64d7537dd617bd3a0eec62..138a24bc76ad9d215e1e9b836405774adaac02e7 100644 (file)
@@ -18,6 +18,8 @@
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_l3proto.h>
 
+static int __net_init iptable_nat_table_init(struct net *net);
+
 static const struct xt_table nf_nat_ipv4_table = {
        .name           = "nat",
        .valid_hooks    = (1 << NF_INET_PRE_ROUTING) |
@@ -26,6 +28,7 @@ static const struct xt_table nf_nat_ipv4_table = {
                          (1 << NF_INET_LOCAL_IN),
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
+       .table_init     = iptable_nat_table_init,
 };
 
 static unsigned int iptable_nat_do_chain(void *priv,
@@ -95,50 +98,50 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
        },
 };
 
-static int __net_init iptable_nat_net_init(struct net *net)
+static int __net_init iptable_nat_table_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
+
+       if (net->ipv4.nat_table)
+               return 0;
 
        repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
+       ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
+                                nf_nat_ipv4_ops, &net->ipv4.nat_table);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.nat_table);
+       return ret;
 }
 
 static void __net_exit iptable_nat_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.nat_table);
+       if (!net->ipv4.nat_table)
+               return;
+       ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops);
+       net->ipv4.nat_table = NULL;
 }
 
 static struct pernet_operations iptable_nat_net_ops = {
-       .init   = iptable_nat_net_init,
        .exit   = iptable_nat_net_exit,
 };
 
 static int __init iptable_nat_init(void)
 {
-       int err;
+       int ret = register_pernet_subsys(&iptable_nat_net_ops);
 
-       err = register_pernet_subsys(&iptable_nat_net_ops);
-       if (err < 0)
-               goto err1;
+       if (ret)
+               return ret;
 
-       err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
-       if (err < 0)
-               goto err2;
-       return 0;
-
-err2:
-       unregister_pernet_subsys(&iptable_nat_net_ops);
-err1:
-       return err;
+       ret = iptable_nat_table_init(&init_net);
+       if (ret)
+               unregister_pernet_subsys(&iptable_nat_net_ops);
+       return ret;
 }
 
 static void __exit iptable_nat_exit(void)
 {
-       nf_unregister_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
        unregister_pernet_subsys(&iptable_nat_net_ops);
 }
 
index 1ba02811acb0c3d380b2779dd61687b92be51ce8..2642ecd2645c4887f9f4013f37ed7ac4fcbcbcd0 100644 (file)
 
 #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
 
+static int __net_init iptable_raw_table_init(struct net *net);
+
 static const struct xt_table packet_raw = {
        .name = "raw",
        .valid_hooks =  RAW_VALID_HOOKS,
        .me = THIS_MODULE,
        .af = NFPROTO_IPV4,
        .priority = NF_IP_PRI_RAW,
+       .table_init = iptable_raw_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
@@ -34,26 +37,32 @@ iptable_raw_hook(void *priv, struct sk_buff *skb,
 
 static struct nf_hook_ops *rawtable_ops __read_mostly;
 
-static int __net_init iptable_raw_net_init(struct net *net)
+static int __net_init iptable_raw_table_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
+
+       if (net->ipv4.iptable_raw)
+               return 0;
 
        repl = ipt_alloc_initial_table(&packet_raw);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_raw =
-               ipt_register_table(net, &packet_raw, repl);
+       ret = ipt_register_table(net, &packet_raw, repl, rawtable_ops,
+                                &net->ipv4.iptable_raw);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw);
+       return ret;
 }
 
 static void __net_exit iptable_raw_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_raw);
+       if (!net->ipv4.iptable_raw)
+               return;
+       ipt_unregister_table(net, net->ipv4.iptable_raw, rawtable_ops);
+       net->ipv4.iptable_raw = NULL;
 }
 
 static struct pernet_operations iptable_raw_net_ops = {
-       .init = iptable_raw_net_init,
        .exit = iptable_raw_net_exit,
 };
 
@@ -61,15 +70,20 @@ static int __init iptable_raw_init(void)
 {
        int ret;
 
+       rawtable_ops = xt_hook_ops_alloc(&packet_raw, iptable_raw_hook);
+       if (IS_ERR(rawtable_ops))
+               return PTR_ERR(rawtable_ops);
+
        ret = register_pernet_subsys(&iptable_raw_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(rawtable_ops);
                return ret;
+       }
 
-       /* Register hooks */
-       rawtable_ops = xt_hook_link(&packet_raw, iptable_raw_hook);
-       if (IS_ERR(rawtable_ops)) {
-               ret = PTR_ERR(rawtable_ops);
+       ret = iptable_raw_table_init(&init_net);
+       if (ret) {
                unregister_pernet_subsys(&iptable_raw_net_ops);
+               kfree(rawtable_ops);
        }
 
        return ret;
@@ -77,8 +91,8 @@ static int __init iptable_raw_init(void)
 
 static void __exit iptable_raw_fini(void)
 {
-       xt_hook_unlink(&packet_raw, rawtable_ops);
        unregister_pernet_subsys(&iptable_raw_net_ops);
+       kfree(rawtable_ops);
 }
 
 module_init(iptable_raw_init);
index c2e23d5e9cd4a8412d38f20eb8ddedf2f32f8aa6..ff226596e4b5e3d504d88700ccb5651c1be0799d 100644 (file)
@@ -28,12 +28,15 @@ MODULE_DESCRIPTION("iptables security table, for MAC rules");
                                (1 << NF_INET_FORWARD) | \
                                (1 << NF_INET_LOCAL_OUT)
 
+static int __net_init iptable_security_table_init(struct net *net);
+
 static const struct xt_table security_table = {
        .name           = "security",
        .valid_hooks    = SECURITY_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV4,
        .priority       = NF_IP_PRI_SECURITY,
+       .table_init     = iptable_security_table_init,
 };
 
 static unsigned int
@@ -51,26 +54,33 @@ iptable_security_hook(void *priv, struct sk_buff *skb,
 
 static struct nf_hook_ops *sectbl_ops __read_mostly;
 
-static int __net_init iptable_security_net_init(struct net *net)
+static int __net_init iptable_security_table_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
+
+       if (net->ipv4.iptable_security)
+               return 0;
 
        repl = ipt_alloc_initial_table(&security_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_security =
-               ipt_register_table(net, &security_table, repl);
+       ret = ipt_register_table(net, &security_table, repl, sectbl_ops,
+                                &net->ipv4.iptable_security);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_security);
+       return ret;
 }
 
 static void __net_exit iptable_security_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_security);
+       if (!net->ipv4.iptable_security)
+               return;
+
+       ipt_unregister_table(net, net->ipv4.iptable_security, sectbl_ops);
+       net->ipv4.iptable_security = NULL;
 }
 
 static struct pernet_operations iptable_security_net_ops = {
-       .init = iptable_security_net_init,
        .exit = iptable_security_net_exit,
 };
 
@@ -78,27 +88,29 @@ static int __init iptable_security_init(void)
 {
        int ret;
 
+       sectbl_ops = xt_hook_ops_alloc(&security_table, iptable_security_hook);
+       if (IS_ERR(sectbl_ops))
+               return PTR_ERR(sectbl_ops);
+
        ret = register_pernet_subsys(&iptable_security_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(sectbl_ops);
                return ret;
-
-       sectbl_ops = xt_hook_link(&security_table, iptable_security_hook);
-       if (IS_ERR(sectbl_ops)) {
-               ret = PTR_ERR(sectbl_ops);
-               goto cleanup_table;
        }
 
-       return ret;
+       ret = iptable_security_table_init(&init_net);
+       if (ret) {
+               unregister_pernet_subsys(&iptable_security_net_ops);
+               kfree(sectbl_ops);
+       }
 
-cleanup_table:
-       unregister_pernet_subsys(&iptable_security_net_ops);
        return ret;
 }
 
 static void __exit iptable_security_fini(void)
 {
-       xt_hook_unlink(&security_table, sectbl_ops);
        unregister_pernet_subsys(&iptable_security_net_ops);
+       kfree(sectbl_ops);
 }
 
 module_init(iptable_security_init);
index a04dee536b8ef8b5f4c1a085563d5d37b6fa118b..d88da36b383ccb4fa5b431b6c5cb83b218cb68ad 100644 (file)
@@ -31,10 +31,8 @@ static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
        err = ip_defrag(net, skb, user);
        local_bh_enable();
 
-       if (!err) {
-               ip_send_check(ip_hdr(skb));
+       if (!err)
                skb->ignore_df = 1;
-       }
 
        return err;
 }
index b72ffc58e2556994eba4b79f69a1630c6177d248..51ced81b616c5aeb3f9d38244f444c8263ec5dca 100644 (file)
@@ -25,7 +25,12 @@ static void nft_masq_ipv4_eval(const struct nft_expr *expr,
 
        memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
-
+       if (priv->sreg_proto_min) {
+               range.min_proto.all =
+                       *(__be16 *)&regs->data[priv->sreg_proto_min];
+               range.max_proto.all =
+                       *(__be16 *)&regs->data[priv->sreg_proto_max];
+       }
        regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook,
                                                    &range, pkt->out);
 }
index f6f93fc2c61f33bcce56d7b4277784c9bb1236a1..cf9700b1a1061404abb62c906afac1cacb43657a 100644 (file)
@@ -748,8 +748,10 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
        if (msg->msg_controllen) {
                err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
-               if (err)
+               if (unlikely(err)) {
+                       kfree(ipc.opt);
                        return err;
+               }
                if (ipc.opt)
                        free = 1;
        }
@@ -1140,13 +1142,6 @@ static int ping_v4_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static const struct seq_operations ping_v4_seq_ops = {
-       .show           = ping_v4_seq_show,
-       .start          = ping_v4_seq_start,
-       .next           = ping_seq_next,
-       .stop           = ping_seq_stop,
-};
-
 static int ping_seq_open(struct inode *inode, struct file *file)
 {
        struct ping_seq_afinfo *afinfo = PDE_DATA(inode);
index 3abd9d7a3adf323bd688b1ab6dabda1248c67be1..9f665b63a927202b9aaf2b6b3d42205058a2ae59 100644 (file)
@@ -390,7 +390,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 
        seq_printf(seq, "\nIp: %d %d",
                   IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2,
-                  sysctl_ip_default_ttl);
+                  net->ipv4.sysctl_ip_default_ttl);
 
        BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0);
        for (i = 0; snmp4_ipstats_list[i].name != NULL; i++)
index d6352515d7384df1f6593ef67d4d9e15337541af..8d22de74080c81f9dd71e1681fb80041b08b8441 100644 (file)
@@ -549,8 +549,10 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
        if (msg->msg_controllen) {
                err = ip_cmsg_send(net, msg, &ipc, false);
-               if (err)
+               if (unlikely(err)) {
+                       kfree(ipc.opt);
                        goto out;
+               }
                if (ipc.opt)
                        free = 1;
        }
index 85f184e429c63c8c426f58c779dc3544cf2e2a54..02c62299d717b9f6c38a5227e3b3ae376e0015b6 100644 (file)
@@ -129,6 +129,7 @@ static int ip_rt_mtu_expires __read_mostly  = 10 * 60 * HZ;
 static int ip_rt_min_pmtu __read_mostly                = 512 + 20 + 20;
 static int ip_rt_min_advmss __read_mostly      = 256;
 
+static int ip_rt_gc_timeout __read_mostly      = RT_GC_TIMEOUT;
 /*
  *     Interface to generic destination cache.
  */
@@ -755,7 +756,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
                                struct fib_nh *nh = &FIB_RES_NH(res);
 
                                update_or_create_fnhe(nh, fl4->daddr, new_gw,
-                                                     0, 0);
+                                               0, jiffies + ip_rt_gc_timeout);
                        }
                        if (kill_route)
                                rt->dst.obsolete = DST_OBSOLETE_KILL;
@@ -1556,6 +1557,36 @@ static void ip_handle_martian_source(struct net_device *dev,
 #endif
 }
 
+static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr)
+{
+       struct fnhe_hash_bucket *hash;
+       struct fib_nh_exception *fnhe, __rcu **fnhe_p;
+       u32 hval = fnhe_hashfun(daddr);
+
+       spin_lock_bh(&fnhe_lock);
+
+       hash = rcu_dereference_protected(nh->nh_exceptions,
+                                        lockdep_is_held(&fnhe_lock));
+       hash += hval;
+
+       fnhe_p = &hash->chain;
+       fnhe = rcu_dereference_protected(*fnhe_p, lockdep_is_held(&fnhe_lock));
+       while (fnhe) {
+               if (fnhe->fnhe_daddr == daddr) {
+                       rcu_assign_pointer(*fnhe_p, rcu_dereference_protected(
+                               fnhe->fnhe_next, lockdep_is_held(&fnhe_lock)));
+                       fnhe_flush_routes(fnhe);
+                       kfree_rcu(fnhe, rcu);
+                       break;
+               }
+               fnhe_p = &fnhe->fnhe_next;
+               fnhe = rcu_dereference_protected(fnhe->fnhe_next,
+                                                lockdep_is_held(&fnhe_lock));
+       }
+
+       spin_unlock_bh(&fnhe_lock);
+}
+
 /* called in rcu_read_lock() section */
 static int __mkroute_input(struct sk_buff *skb,
                           const struct fib_result *res,
@@ -1609,11 +1640,20 @@ static int __mkroute_input(struct sk_buff *skb,
 
        fnhe = find_exception(&FIB_RES_NH(*res), daddr);
        if (do_cache) {
-               if (fnhe)
+               if (fnhe) {
                        rth = rcu_dereference(fnhe->fnhe_rth_input);
-               else
-                       rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
+                       if (rth && rth->dst.expires &&
+                           time_after(jiffies, rth->dst.expires)) {
+                               ip_del_fnhe(&FIB_RES_NH(*res), daddr);
+                               fnhe = NULL;
+                       } else {
+                               goto rt_cache;
+                       }
+               }
+
+               rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input);
 
+rt_cache:
                if (rt_cache_valid(rth)) {
                        skb_dst_set_noref(skb, &rth->dst);
                        goto out;
@@ -2014,19 +2054,29 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
                struct fib_nh *nh = &FIB_RES_NH(*res);
 
                fnhe = find_exception(nh, fl4->daddr);
-               if (fnhe)
+               if (fnhe) {
                        prth = &fnhe->fnhe_rth_output;
-               else {
-                       if (unlikely(fl4->flowi4_flags &
-                                    FLOWI_FLAG_KNOWN_NH &&
-                                    !(nh->nh_gw &&
-                                      nh->nh_scope == RT_SCOPE_LINK))) {
-                               do_cache = false;
-                               goto add;
+                       rth = rcu_dereference(*prth);
+                       if (rth && rth->dst.expires &&
+                           time_after(jiffies, rth->dst.expires)) {
+                               ip_del_fnhe(nh, fl4->daddr);
+                               fnhe = NULL;
+                       } else {
+                               goto rt_cache;
                        }
-                       prth = raw_cpu_ptr(nh->nh_pcpu_rth_output);
                }
+
+               if (unlikely(fl4->flowi4_flags &
+                            FLOWI_FLAG_KNOWN_NH &&
+                            !(nh->nh_gw &&
+                              nh->nh_scope == RT_SCOPE_LINK))) {
+                       do_cache = false;
+                       goto add;
+               }
+               prth = raw_cpu_ptr(nh->nh_pcpu_rth_output);
                rth = rcu_dereference(*prth);
+
+rt_cache:
                if (rt_cache_valid(rth)) {
                        dst_hold(&rth->dst);
                        return rth;
@@ -2569,7 +2619,6 @@ void ip_rt_multicast_event(struct in_device *in_dev)
 }
 
 #ifdef CONFIG_SYSCTL
-static int ip_rt_gc_timeout __read_mostly      = RT_GC_TIMEOUT;
 static int ip_rt_gc_interval __read_mostly  = 60 * HZ;
 static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
 static int ip_rt_gc_elasticity __read_mostly   = 8;
index b537338f5c97d0d09c80fa2f8f19f26f0c270be7..1e1fe6086dd912e5071524053581afa79578061b 100644 (file)
@@ -282,15 +282,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       {
-               .procname       = "ip_default_ttl",
-               .data           = &sysctl_ip_default_ttl,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &ip_ttl_min,
-               .extra2         = &ip_ttl_max,
-       },
        {
                .procname       = "tcp_max_orphans",
                .data           = &sysctl_tcp_max_orphans,
@@ -305,20 +296,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
-       {
-               .procname       = "ip_early_demux",
-               .data           = &sysctl_ip_early_demux,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
-       {
-               .procname       = "ip_dynaddr",
-               .data           = &sysctl_ip_dynaddr,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
        {
                .procname       = "tcp_fastopen",
                .data           = &sysctl_tcp_fastopen,
@@ -752,6 +729,29 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "ip_dynaddr",
+               .data           = &init_net.ipv4.sysctl_ip_dynaddr,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+       {
+               .procname       = "ip_early_demux",
+               .data           = &init_net.ipv4.sysctl_ip_early_demux,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+       {
+               .procname       = "ip_default_ttl",
+               .data           = &init_net.ipv4.sysctl_ip_default_ttl,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &ip_ttl_min,
+               .extra2         = &ip_ttl_max,
+       },
        {
                .procname       = "ip_local_port_range",
                .maxlen         = sizeof(init_net.ipv4.ip_local_ports.range),
@@ -988,6 +988,10 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
        if (!net->ipv4.sysctl_local_reserved_ports)
                goto err_ports;
 
+       net->ipv4.sysctl_ip_default_ttl = IPDEFTTL;
+       net->ipv4.sysctl_ip_dynaddr = 0;
+       net->ipv4.sysctl_ip_early_demux = 1;
+
        return 0;
 
 err_ports:
index 014f18e2f7b368f3ba3a319962ab027d7014ef6f..a265f00b9df948de44f2cfd9730b50924e2226d1 100644 (file)
@@ -556,20 +556,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
                        return -EINVAL;
 
                slow = lock_sock_fast(sk);
-               if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
-                       answ = 0;
-               else if (sock_flag(sk, SOCK_URGINLINE) ||
-                        !tp->urg_data ||
-                        before(tp->urg_seq, tp->copied_seq) ||
-                        !before(tp->urg_seq, tp->rcv_nxt)) {
-
-                       answ = tp->rcv_nxt - tp->copied_seq;
-
-                       /* Subtract 1, if FIN was received */
-                       if (answ && sock_flag(sk, SOCK_DONE))
-                               answ--;
-               } else
-                       answ = tp->urg_seq - tp->copied_seq;
+               answ = tcp_inq(sk);
                unlock_sock_fast(sk, slow);
                break;
        case SIOCATMARK:
@@ -938,7 +925,7 @@ new_segment:
 
                i = skb_shinfo(skb)->nr_frags;
                can_coalesce = skb_can_coalesce(skb, i, page, offset);
-               if (!can_coalesce && i >= MAX_SKB_FRAGS) {
+               if (!can_coalesce && i >= sysctl_max_skb_frags) {
                        tcp_mark_push(tp, skb);
                        goto new_segment;
                }
@@ -1211,7 +1198,7 @@ new_segment:
 
                        if (!skb_can_coalesce(skb, i, pfrag->page,
                                              pfrag->offset)) {
-                               if (i == MAX_SKB_FRAGS || !sg) {
+                               if (i == sysctl_max_skb_frags || !sg) {
                                        tcp_mark_push(tp, skb);
                                        goto new_segment;
                                }
@@ -2642,6 +2629,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 now = tcp_time_stamp;
        unsigned int start;
+       int notsent_bytes;
        u64 rate64;
        u32 rate;
 
@@ -2722,6 +2710,11 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
        } while (u64_stats_fetch_retry_irq(&tp->syncp, start));
        info->tcpi_segs_out = tp->segs_out;
        info->tcpi_segs_in = tp->segs_in;
+
+       notsent_bytes = READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt);
+       info->tcpi_notsent_bytes = max(0, notsent_bytes);
+
+       info->tcpi_min_rtt = tcp_min_rtt(tp);
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
@@ -2954,7 +2947,7 @@ static void __tcp_alloc_md5sig_pool(void)
                        struct crypto_hash *hash;
 
                        hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
-                       if (IS_ERR_OR_NULL(hash))
+                       if (IS_ERR(hash))
                                return;
                        per_cpu(tcp_md5sig_pool, cpu).md5_desc.tfm = hash;
                }
index 5ee6fe0d152dbe8ded87fc7bb1f49d2053124413..e6e65f79ade82132e1a2e5578ba01f43aed15140 100644 (file)
@@ -2907,7 +2907,10 @@ static void tcp_update_rtt_min(struct sock *sk, u32 rtt_us)
 {
        const u32 now = tcp_time_stamp, wlen = sysctl_tcp_min_rtt_wlen * HZ;
        struct rtt_meas *m = tcp_sk(sk)->rtt_min;
-       struct rtt_meas rttm = { .rtt = (rtt_us ? : 1), .ts = now };
+       struct rtt_meas rttm = {
+               .rtt = likely(rtt_us) ? rtt_us : jiffies_to_usecs(1),
+               .ts = now,
+       };
        u32 elapsed;
 
        /* Check if the new measurement updates the 1st, 2nd, or 3rd choices */
index ba5d0146e3f0b52b68ec3abb0eff7e5a46a41bbb..4c8d58dfac9be15e1424d3bdad82ef6c7cd8b79c 100644 (file)
@@ -311,7 +311,7 @@ static void do_redirect(struct sk_buff *skb, struct sock *sk)
 
 
 /* handle ICMP messages on TCP_NEW_SYN_RECV request sockets */
-void tcp_req_err(struct sock *sk, u32 seq)
+void tcp_req_err(struct sock *sk, u32 seq, bool abort)
 {
        struct request_sock *req = inet_reqsk(sk);
        struct net *net = sock_net(sk);
@@ -323,7 +323,7 @@ void tcp_req_err(struct sock *sk, u32 seq)
 
        if (seq != tcp_rsk(req)->snt_isn) {
                NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS);
-       } else {
+       } else if (abort) {
                /*
                 * Still in SYN_RECV, just remove it silently.
                 * There is no good way to pass the error to the newly
@@ -383,7 +383,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
        }
        seq = ntohl(th->seq);
        if (sk->sk_state == TCP_NEW_SYN_RECV)
-               return tcp_req_err(sk, seq);
+               return tcp_req_err(sk, seq,
+                                 type == ICMP_PARAMETERPROB ||
+                                 type == ICMP_TIME_EXCEEDED ||
+                                 (type == ICMP_DEST_UNREACH &&
+                                  (code == ICMP_NET_UNREACH ||
+                                   code == ICMP_HOST_UNREACH)));
 
        bh_lock_sock(sk);
        /* If too many ICMPs get dropped on busy
@@ -1592,28 +1597,30 @@ process:
 
        if (sk->sk_state == TCP_NEW_SYN_RECV) {
                struct request_sock *req = inet_reqsk(sk);
-               struct sock *nsk = NULL;
+               struct sock *nsk;
 
                sk = req->rsk_listener;
-               if (tcp_v4_inbound_md5_hash(sk, skb))
-                       goto discard_and_relse;
-               if (likely(sk->sk_state == TCP_LISTEN)) {
-                       nsk = tcp_check_req(sk, skb, req, false);
-               } else {
+               if (unlikely(tcp_v4_inbound_md5_hash(sk, skb))) {
+                       reqsk_put(req);
+                       goto discard_it;
+               }
+               if (unlikely(sk->sk_state != TCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
                }
+               sock_hold(sk);
+               nsk = tcp_check_req(sk, skb, req, false);
                if (!nsk) {
                        reqsk_put(req);
-                       goto discard_it;
+                       goto discard_and_relse;
                }
                if (nsk == sk) {
-                       sock_hold(sk);
                        reqsk_put(req);
                } else if (tcp_child_process(sk, nsk, skb)) {
                        tcp_v4_send_reset(nsk, skb);
-                       goto discard_it;
+                       goto discard_and_relse;
                } else {
+                       sock_put(sk);
                        return 0;
                }
        }
@@ -2399,12 +2406,6 @@ static int __net_init tcp_sk_init(struct net *net)
        net->ipv4.sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
        net->ipv4.sysctl_tcp_notsent_lowat = UINT_MAX;
 
-       net->ipv4.sysctl_igmp_max_memberships = 20;
-       net->ipv4.sysctl_igmp_max_msf = 10;
-       /* IGMP reports for link-local multicast groups are enabled by default */
-       net->ipv4.sysctl_igmp_llm_reports = 1;
-       net->ipv4.sysctl_igmp_qrv = 2;
-
        return 0;
 fail:
        tcp_sk_exit(net);
index c26241f3057b18d8e1d2aaece7d1e2f7f8399462..7b7eec4399069249ef949ef4b287e8cd0ef4df91 100644 (file)
@@ -551,7 +551,7 @@ reset:
         */
        if (crtt > tp->srtt_us) {
                /* Set RTO like tcp_rtt_estimator(), but from cached RTT. */
-               crtt /= 8 * USEC_PER_MSEC;
+               crtt /= 8 * USEC_PER_SEC / HZ;
                inet_csk(sk)->icsk_rto = crtt + max(2 * crtt, tcp_rto_min(sk));
        } else if (tp->srtt_us == 0) {
                /* RFC6298: 5.7 We've failed to get a valid RTT sample from
index fadd8b978951817f75402af7a12f2b5681b00462..ae90e4b34bd3c656850a79131b22febfb41cb9ad 100644 (file)
@@ -452,7 +452,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
 
                newtp->rcv_wup = newtp->copied_seq =
                newtp->rcv_nxt = treq->rcv_isn + 1;
-               newtp->segs_in = 0;
+               newtp->segs_in = 1;
 
                newtp->snd_sml = newtp->snd_una =
                newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
@@ -812,6 +812,7 @@ int tcp_child_process(struct sock *parent, struct sock *child,
        int ret = 0;
        int state = child->sk_state;
 
+       tcp_sk(child)->segs_in += max_t(u16, 1, skb_shinfo(skb)->gso_segs);
        if (!sock_owned_by_user(child)) {
                ret = tcp_rcv_state_process(child, skb);
                /* Wakeup parent, send SIGIO */
index ebf5ff57526eab65018005c47a907545e61cacf6..f6c50af24a64737672f7ede2ff41158bfed5f1b4 100644 (file)
@@ -187,13 +187,13 @@ static int tcpprobe_sprint(char *tbuf, int n)
 {
        const struct tcp_log *p
                = tcp_probe.log + tcp_probe.tail;
-       struct timespec tv
-               = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start));
+       struct timespec64 ts
+               = ktime_to_timespec64(ktime_sub(p->tstamp, tcp_probe.start));
 
        return scnprintf(tbuf, n,
                        "%lu.%09lu %pISpc %pISpc %d %#x %#x %u %u %u %u %u\n",
-                       (unsigned long)tv.tv_sec,
-                       (unsigned long)tv.tv_nsec,
+                       (unsigned long)ts.tv_sec,
+                       (unsigned long)ts.tv_nsec,
                        &p->src, &p->dst, p->length, p->snd_nxt, p->snd_una,
                        p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt, p->rcv_wnd);
 }
index 9fc4e9c06aaebe69acbb2616dcb4481e593accea..836abe58a9c52c1e0a613d0c1517b0819556c6c8 100644 (file)
@@ -1036,8 +1036,10 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        if (msg->msg_controllen) {
                err = ip_cmsg_send(sock_net(sk), msg, &ipc,
                                   sk->sk_family == AF_INET6);
-               if (err)
+               if (unlikely(err)) {
+                       kfree(ipc.opt);
                        return err;
+               }
                if (ipc.opt)
                        free = 1;
                connected = 0;
index 56c4c8b88b28f2e96220ed68a67d7473aa40c567..f5abb1ae1358f974f8024c0599e6c9bdcca5be60 100644 (file)
@@ -33,8 +33,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        __be16 new_protocol, bool is_ipv6)
 {
        int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+       bool remcsum, need_csum, offload_csum, ufo;
        struct sk_buff *segs = ERR_PTR(-EINVAL);
-       bool remcsum, need_csum, offload_csum;
        struct udphdr *uh = udp_hdr(skb);
        u16 mac_offset = skb->mac_header;
        __be16 protocol = skb->protocol;
@@ -62,6 +62,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM);
        skb->remcsum_offload = remcsum;
 
+       ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
+
        /* Try to offload checksum if possible */
        offload_csum = !!(need_csum &&
                          (skb->dev->features &
@@ -74,9 +76,9 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
         * outer one so strip the existing checksum feature flags and
         * instead set the flag based on our outer checksum offload value.
         */
-       if (remcsum) {
+       if (remcsum || ufo) {
                features &= ~NETIF_F_CSUM_MASK;
-               if (offload_csum)
+               if (!need_csum || offload_csum)
                        features |= NETIF_F_HW_CSUM;
        }
 
@@ -230,6 +232,13 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
 
        skb->ip_summed = CHECKSUM_NONE;
 
+       /* If there is no outer header we can fake a checksum offload
+        * due to the fact that we have already done the checksum in
+        * software prior to segmenting the frame.
+        */
+       if (!skb->encap_hdr_csum)
+               features |= NETIF_F_HW_CSUM;
+
        /* Fragment the skb. IP headers of the fragments are updated in
         * inet_gso_segment()
         */
index 0ec08814f37d9e904b5f85bbd86cd2fa607c4307..96599d1a13184d4ef6d34ae9bff7833420d0ad93 100644 (file)
@@ -89,6 +89,8 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
        uh->source = src_port;
        uh->len = htons(skb->len);
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        udp_set_csum(nocheck, skb, src, dst, skb->len);
 
        iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet);
index 40c897515ddc44d57c434dcd761c2ddc5e7fad50..11e875ffd7ace7360f3f03759cc0b81bc8a11abf 100644 (file)
@@ -207,6 +207,7 @@ config IPV6_NDISC_NODETYPE
 config IPV6_TUNNEL
        tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)"
        select INET6_TUNNEL
+       select DST_CACHE
        ---help---
          Support for IPv6-in-IPv6 and IPv4-in-IPv6 tunnels described in
          RFC 2473.
index ac0ba9e4e06b95769b7471ddfa8805e61a61f9c5..27aed1afcf81c0a516bb6768e20b27a6794fb1cc 100644 (file)
@@ -216,6 +216,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        },
        .use_oif_addrs_only     = 0,
        .ignore_routes_with_linkdown = 0,
+       .keep_addr_on_down      = 0,
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -260,6 +261,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        },
        .use_oif_addrs_only     = 0,
        .ignore_routes_with_linkdown = 0,
+       .keep_addr_on_down      = 0,
 };
 
 /* Check if a valid qdisc is available */
@@ -471,18 +473,21 @@ static int inet6_netconf_msgsize_devconf(int type)
 {
        int size =  NLMSG_ALIGN(sizeof(struct netconfmsg))
                    + nla_total_size(4);        /* NETCONFA_IFINDEX */
+       bool all = false;
 
-       /* type -1 is used for ALL */
-       if (type == -1 || type == NETCONFA_FORWARDING)
+       if (type == NETCONFA_ALL)
+               all = true;
+
+       if (all || type == NETCONFA_FORWARDING)
                size += nla_total_size(4);
 #ifdef CONFIG_IPV6_MROUTE
-       if (type == -1 || type == NETCONFA_MC_FORWARDING)
+       if (all || type == NETCONFA_MC_FORWARDING)
                size += nla_total_size(4);
 #endif
-       if (type == -1 || type == NETCONFA_PROXY_NEIGH)
+       if (all || type == NETCONFA_PROXY_NEIGH)
                size += nla_total_size(4);
 
-       if (type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
+       if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
                size += nla_total_size(4);
 
        return size;
@@ -495,33 +500,36 @@ static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
 {
        struct nlmsghdr  *nlh;
        struct netconfmsg *ncm;
+       bool all = false;
 
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
                        flags);
        if (!nlh)
                return -EMSGSIZE;
 
+       if (type == NETCONFA_ALL)
+               all = true;
+
        ncm = nlmsg_data(nlh);
        ncm->ncm_family = AF_INET6;
 
        if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0)
                goto nla_put_failure;
 
-       /* type -1 is used for ALL */
-       if ((type == -1 || type == NETCONFA_FORWARDING) &&
+       if ((all || type == NETCONFA_FORWARDING) &&
            nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0)
                goto nla_put_failure;
 #ifdef CONFIG_IPV6_MROUTE
-       if ((type == -1 || type == NETCONFA_MC_FORWARDING) &&
+       if ((all || type == NETCONFA_MC_FORWARDING) &&
            nla_put_s32(skb, NETCONFA_MC_FORWARDING,
                        devconf->mc_forwarding) < 0)
                goto nla_put_failure;
 #endif
-       if ((type == -1 || type == NETCONFA_PROXY_NEIGH) &&
+       if ((all || type == NETCONFA_PROXY_NEIGH) &&
            nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0)
                goto nla_put_failure;
 
-       if ((type == -1 || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
+       if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) &&
            nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
                        devconf->ignore_routes_with_linkdown) < 0)
                goto nla_put_failure;
@@ -583,7 +591,7 @@ static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
        if (err < 0)
                goto errout;
 
-       err = EINVAL;
+       err = -EINVAL;
        if (!tb[NETCONFA_IFINDEX])
                goto errout;
 
@@ -607,14 +615,14 @@ static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
        }
 
        err = -ENOBUFS;
-       skb = nlmsg_new(inet6_netconf_msgsize_devconf(-1), GFP_ATOMIC);
+       skb = nlmsg_new(inet6_netconf_msgsize_devconf(NETCONFA_ALL), GFP_ATOMIC);
        if (!skb)
                goto errout;
 
        err = inet6_netconf_fill_devconf(skb, ifindex, devconf,
                                         NETLINK_CB(in_skb).portid,
                                         nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
-                                        -1);
+                                        NETCONFA_ALL);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */
                WARN_ON(err == -EMSGSIZE);
@@ -658,7 +666,7 @@ static int inet6_netconf_dump_devconf(struct sk_buff *skb,
                                                       cb->nlh->nlmsg_seq,
                                                       RTM_NEWNETCONF,
                                                       NLM_F_MULTI,
-                                                      -1) < 0) {
+                                                      NETCONFA_ALL) < 0) {
                                rcu_read_unlock();
                                goto done;
                        }
@@ -674,7 +682,7 @@ cont:
                                               NETLINK_CB(cb->skb).portid,
                                               cb->nlh->nlmsg_seq,
                                               RTM_NEWNETCONF, NLM_F_MULTI,
-                                              -1) < 0)
+                                              NETCONFA_ALL) < 0)
                        goto done;
                else
                        h++;
@@ -685,7 +693,7 @@ cont:
                                               NETLINK_CB(cb->skb).portid,
                                               cb->nlh->nlmsg_seq,
                                               RTM_NEWNETCONF, NLM_F_MULTI,
-                                              -1) < 0)
+                                              NETCONFA_ALL) < 0)
                        goto done;
                else
                        h++;
@@ -3168,6 +3176,81 @@ static void addrconf_gre_config(struct net_device *dev)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
+/* If the host route is cached on the addr struct make sure it is associated
+ * with the proper table. e.g., enslavement can change and if so the cached
+ * host route needs to move to the new table.
+ */
+static void l3mdev_check_host_rt(struct inet6_dev *idev,
+                                 struct inet6_ifaddr *ifp)
+{
+       if (ifp->rt) {
+               u32 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
+
+               if (tb_id != ifp->rt->rt6i_table->tb6_id) {
+                       ip6_del_rt(ifp->rt);
+                       ifp->rt = NULL;
+               }
+       }
+}
+#else
+static void l3mdev_check_host_rt(struct inet6_dev *idev,
+                                 struct inet6_ifaddr *ifp)
+{
+}
+#endif
+
+static int fixup_permanent_addr(struct inet6_dev *idev,
+                               struct inet6_ifaddr *ifp)
+{
+       l3mdev_check_host_rt(idev, ifp);
+
+       if (!ifp->rt) {
+               struct rt6_info *rt;
+
+               rt = addrconf_dst_alloc(idev, &ifp->addr, false);
+               if (unlikely(IS_ERR(rt)))
+                       return PTR_ERR(rt);
+
+               ifp->rt = rt;
+       }
+
+       if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) {
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len,
+                                     idev->dev, 0, 0);
+       }
+
+       addrconf_dad_start(ifp);
+
+       return 0;
+}
+
+static void addrconf_permanent_addr(struct net_device *dev)
+{
+       struct inet6_ifaddr *ifp, *tmp;
+       struct inet6_dev *idev;
+
+       idev = __in6_dev_get(dev);
+       if (!idev)
+               return;
+
+       write_lock_bh(&idev->lock);
+
+       list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) {
+               if ((ifp->flags & IFA_F_PERMANENT) &&
+                   fixup_permanent_addr(idev, ifp) < 0) {
+                       write_unlock_bh(&idev->lock);
+                       ipv6_del_addr(ifp);
+                       write_lock_bh(&idev->lock);
+
+                       net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
+                                            idev->dev->name, &ifp->addr);
+               }
+       }
+
+       write_unlock_bh(&idev->lock);
+}
+
 static int addrconf_notify(struct notifier_block *this, unsigned long event,
                           void *ptr)
 {
@@ -3253,6 +3336,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        run_pending = 1;
                }
 
+               /* restore routes for permanent addresses */
+               addrconf_permanent_addr(dev);
+
                switch (dev->type) {
 #if IS_ENABLED(CONFIG_IPV6_SIT)
                case ARPHRD_SIT:
@@ -3356,7 +3442,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 {
        struct net *net = dev_net(dev);
        struct inet6_dev *idev;
-       struct inet6_ifaddr *ifa;
+       struct inet6_ifaddr *ifa, *tmp;
+       struct list_head del_list;
+       int _keep_addr;
+       bool keep_addr;
        int state, i;
 
        ASSERT_RTNL();
@@ -3383,6 +3472,16 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        }
 
+       /* aggregate the system setting and interface setting */
+       _keep_addr = net->ipv6.devconf_all->keep_addr_on_down;
+       if (!_keep_addr)
+               _keep_addr = idev->cnf.keep_addr_on_down;
+
+       /* combine the user config with event to determine if permanent
+        * addresses are to be removed from address hash table
+        */
+       keep_addr = !(how || _keep_addr <= 0);
+
        /* Step 2: clear hash table */
        for (i = 0; i < IN6_ADDR_HSIZE; i++) {
                struct hlist_head *h = &inet6_addr_lst[i];
@@ -3391,9 +3490,15 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 restart:
                hlist_for_each_entry_rcu(ifa, h, addr_lst) {
                        if (ifa->idev == idev) {
-                               hlist_del_init_rcu(&ifa->addr_lst);
                                addrconf_del_dad_work(ifa);
-                               goto restart;
+                               /* combined flag + permanent flag decide if
+                                * address is retained on a down event
+                                */
+                               if (!keep_addr ||
+                                   !(ifa->flags & IFA_F_PERMANENT)) {
+                                       hlist_del_init_rcu(&ifa->addr_lst);
+                                       goto restart;
+                               }
                        }
                }
                spin_unlock_bh(&addrconf_hash_lock);
@@ -3427,31 +3532,53 @@ restart:
                write_lock_bh(&idev->lock);
        }
 
-       while (!list_empty(&idev->addr_list)) {
-               ifa = list_first_entry(&idev->addr_list,
-                                      struct inet6_ifaddr, if_list);
-               addrconf_del_dad_work(ifa);
+       /* re-combine the user config with event to determine if permanent
+        * addresses are to be removed from the interface list
+        */
+       keep_addr = (!how && _keep_addr > 0);
 
-               list_del(&ifa->if_list);
+       INIT_LIST_HEAD(&del_list);
+       list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) {
+               addrconf_del_dad_work(ifa);
 
                write_unlock_bh(&idev->lock);
-
                spin_lock_bh(&ifa->lock);
-               state = ifa->state;
-               ifa->state = INET6_IFADDR_STATE_DEAD;
+
+               if (keep_addr && (ifa->flags & IFA_F_PERMANENT)) {
+                       /* set state to skip the notifier below */
+                       state = INET6_IFADDR_STATE_DEAD;
+                       ifa->state = 0;
+                       if (!(ifa->flags & IFA_F_NODAD))
+                               ifa->flags |= IFA_F_TENTATIVE;
+               } else {
+                       state = ifa->state;
+                       ifa->state = INET6_IFADDR_STATE_DEAD;
+
+                       list_del(&ifa->if_list);
+                       list_add(&ifa->if_list, &del_list);
+               }
+
                spin_unlock_bh(&ifa->lock);
 
                if (state != INET6_IFADDR_STATE_DEAD) {
                        __ipv6_ifa_notify(RTM_DELADDR, ifa);
                        inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
                }
-               in6_ifa_put(ifa);
 
                write_lock_bh(&idev->lock);
        }
 
        write_unlock_bh(&idev->lock);
 
+       /* now clean up addresses to be removed */
+       while (!list_empty(&del_list)) {
+               ifa = list_first_entry(&del_list,
+                                      struct inet6_ifaddr, if_list);
+               list_del(&ifa->if_list);
+
+               in6_ifa_put(ifa);
+       }
+
        /* Step 5: Discard anycast and multicast list */
        if (how) {
                ipv6_ac_destroy_dev(idev);
@@ -3538,6 +3665,7 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
        struct net_device *dev = idev->dev;
+       bool notify = false;
 
        addrconf_join_solict(dev, &ifp->addr);
 
@@ -3583,7 +3711,7 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
                        /* Because optimistic nodes can use this address,
                         * notify listeners. If DAD fails, RTM_DELADDR is sent.
                         */
-                       ipv6_ifa_notify(RTM_NEWADDR, ifp);
+                       notify = true;
                }
        }
 
@@ -3591,6 +3719,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
 out:
        spin_unlock(&ifp->lock);
        read_unlock_bh(&idev->lock);
+       if (notify)
+               ipv6_ifa_notify(RTM_NEWADDR, ifp);
 }
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp)
@@ -4713,6 +4843,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only;
        array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
        array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
+       array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
 }
 
 static inline size_t inet6_ifla6_size(void)
@@ -5800,6 +5931,14 @@ static struct addrconf_sysctl_table
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
+               {
+                       .procname       = "keep_addr_on_down",
+                       .data           = &ipv6_devconf.keep_addr_on_down,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
+
+               },
                {
                        /* sentinel */
                }
index 5c5d23e59da598995ff962d069d1e7b6886e31d6..9508a20fbf61432f561202edbe40b59e63c3489e 100644 (file)
@@ -257,7 +257,11 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                                                *fragoff = _frag_off;
                                        return hp->nexthdr;
                                }
-                               return -ENOENT;
+                               if (!found)
+                                       return -ENOENT;
+                               if (fragoff)
+                                       *fragoff = _frag_off;
+                               break;
                        }
                        hdrlen = 8;
                } else if (nexthdr == NEXTHDR_AUTH) {
index 32dc9aab7297bfb2e08383a28fd6636f41ccb2f2..30613050e4cab01bf26d090bcc4765e96f2a097a 100644 (file)
@@ -99,5 +99,6 @@ static void __exit ila_fini(void)
 
 module_init(ila_init);
 module_exit(ila_fini);
+MODULE_ALIAS_RTNL_LWT(ILA);
 MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>");
 MODULE_LICENSE("GPL");
index 0c7e276c230e4ab2cd7c7ab0688e84920a41f69b..ea071fad67a03e9d884f99ddb64ea71dc8c31116 100644 (file)
@@ -55,8 +55,6 @@ struct fib6_cleaner {
        void *arg;
 };
 
-static DEFINE_RWLOCK(fib6_walker_lock);
-
 #ifdef CONFIG_IPV6_SUBTREES
 #define FWS_INIT FWS_S
 #else
@@ -66,7 +64,7 @@ static DEFINE_RWLOCK(fib6_walker_lock);
 static void fib6_prune_clones(struct net *net, struct fib6_node *fn);
 static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
 static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
-static int fib6_walk(struct fib6_walker *w);
+static int fib6_walk(struct net *net, struct fib6_walker *w);
 static int fib6_walk_continue(struct fib6_walker *w);
 
 /*
@@ -78,21 +76,21 @@ static int fib6_walk_continue(struct fib6_walker *w);
 
 static void fib6_gc_timer_cb(unsigned long arg);
 
-static LIST_HEAD(fib6_walkers);
-#define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh)
+#define FOR_WALKERS(net, w) \
+       list_for_each_entry(w, &(net)->ipv6.fib6_walkers, lh)
 
-static void fib6_walker_link(struct fib6_walker *w)
+static void fib6_walker_link(struct net *net, struct fib6_walker *w)
 {
-       write_lock_bh(&fib6_walker_lock);
-       list_add(&w->lh, &fib6_walkers);
-       write_unlock_bh(&fib6_walker_lock);
+       write_lock_bh(&net->ipv6.fib6_walker_lock);
+       list_add(&w->lh, &net->ipv6.fib6_walkers);
+       write_unlock_bh(&net->ipv6.fib6_walker_lock);
 }
 
-static void fib6_walker_unlink(struct fib6_walker *w)
+static void fib6_walker_unlink(struct net *net, struct fib6_walker *w)
 {
-       write_lock_bh(&fib6_walker_lock);
+       write_lock_bh(&net->ipv6.fib6_walker_lock);
        list_del(&w->lh);
-       write_unlock_bh(&fib6_walker_lock);
+       write_unlock_bh(&net->ipv6.fib6_walker_lock);
 }
 
 static int fib6_new_sernum(struct net *net)
@@ -325,12 +323,13 @@ static int fib6_dump_node(struct fib6_walker *w)
 
 static void fib6_dump_end(struct netlink_callback *cb)
 {
+       struct net *net = sock_net(cb->skb->sk);
        struct fib6_walker *w = (void *)cb->args[2];
 
        if (w) {
                if (cb->args[4]) {
                        cb->args[4] = 0;
-                       fib6_walker_unlink(w);
+                       fib6_walker_unlink(net, w);
                }
                cb->args[2] = 0;
                kfree(w);
@@ -348,6 +347,7 @@ static int fib6_dump_done(struct netlink_callback *cb)
 static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
                           struct netlink_callback *cb)
 {
+       struct net *net = sock_net(skb->sk);
        struct fib6_walker *w;
        int res;
 
@@ -359,7 +359,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
                w->skip = 0;
 
                read_lock_bh(&table->tb6_lock);
-               res = fib6_walk(w);
+               res = fib6_walk(net, w);
                read_unlock_bh(&table->tb6_lock);
                if (res > 0) {
                        cb->args[4] = 1;
@@ -379,7 +379,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
                res = fib6_walk_continue(w);
                read_unlock_bh(&table->tb6_lock);
                if (res <= 0) {
-                       fib6_walker_unlink(w);
+                       fib6_walker_unlink(net, w);
                        cb->args[4] = 0;
                }
        }
@@ -1340,8 +1340,8 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                }
 #endif
 
-               read_lock(&fib6_walker_lock);
-               FOR_WALKERS(w) {
+               read_lock(&net->ipv6.fib6_walker_lock);
+               FOR_WALKERS(net, w) {
                        if (!child) {
                                if (w->root == fn) {
                                        w->root = w->node = NULL;
@@ -1368,7 +1368,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                                }
                        }
                }
-               read_unlock(&fib6_walker_lock);
+               read_unlock(&net->ipv6.fib6_walker_lock);
 
                node_free(fn);
                if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn))
@@ -1411,8 +1411,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
        }
 
        /* Adjust walkers */
-       read_lock(&fib6_walker_lock);
-       FOR_WALKERS(w) {
+       read_lock(&net->ipv6.fib6_walker_lock);
+       FOR_WALKERS(net, w) {
                if (w->state == FWS_C && w->leaf == rt) {
                        RT6_TRACE("walker %p adjusted by delroute\n", w);
                        w->leaf = rt->dst.rt6_next;
@@ -1420,7 +1420,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
                                w->state = FWS_U;
                }
        }
-       read_unlock(&fib6_walker_lock);
+       read_unlock(&net->ipv6.fib6_walker_lock);
 
        rt->dst.rt6_next = NULL;
 
@@ -1588,17 +1588,17 @@ skip:
        }
 }
 
-static int fib6_walk(struct fib6_walker *w)
+static int fib6_walk(struct net *net, struct fib6_walker *w)
 {
        int res;
 
        w->state = FWS_INIT;
        w->node = w->root;
 
-       fib6_walker_link(w);
+       fib6_walker_link(net, w);
        res = fib6_walk_continue(w);
        if (res <= 0)
-               fib6_walker_unlink(w);
+               fib6_walker_unlink(net, w);
        return res;
 }
 
@@ -1668,7 +1668,7 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root,
        c.arg = arg;
        c.net = net;
 
-       fib6_walk(&c.w);
+       fib6_walk(net, &c.w);
 }
 
 static void __fib6_clean_all(struct net *net,
@@ -1725,14 +1725,15 @@ static void fib6_flush_trees(struct net *net)
  *     Garbage collection
  */
 
-static struct fib6_gc_args
+struct fib6_gc_args
 {
        int                     timeout;
        int                     more;
-} gc_args;
+};
 
 static int fib6_age(struct rt6_info *rt, void *arg)
 {
+       struct fib6_gc_args *gc_args = arg;
        unsigned long now = jiffies;
 
        /*
@@ -1748,10 +1749,10 @@ static int fib6_age(struct rt6_info *rt, void *arg)
                        RT6_TRACE("expiring %p\n", rt);
                        return -1;
                }
-               gc_args.more++;
+               gc_args->more++;
        } else if (rt->rt6i_flags & RTF_CACHE) {
                if (atomic_read(&rt->dst.__refcnt) == 0 &&
-                   time_after_eq(now, rt->dst.lastuse + gc_args.timeout)) {
+                   time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) {
                        RT6_TRACE("aging clone %p\n", rt);
                        return -1;
                } else if (rt->rt6i_flags & RTF_GATEWAY) {
@@ -1769,21 +1770,20 @@ static int fib6_age(struct rt6_info *rt, void *arg)
                                return -1;
                        }
                }
-               gc_args.more++;
+               gc_args->more++;
        }
 
        return 0;
 }
 
-static DEFINE_SPINLOCK(fib6_gc_lock);
-
 void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
+       struct fib6_gc_args gc_args;
        unsigned long now;
 
        if (force) {
-               spin_lock_bh(&fib6_gc_lock);
-       } else if (!spin_trylock_bh(&fib6_gc_lock)) {
+               spin_lock_bh(&net->ipv6.fib6_gc_lock);
+       } else if (!spin_trylock_bh(&net->ipv6.fib6_gc_lock)) {
                mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
                return;
        }
@@ -1792,7 +1792,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 
        gc_args.more = icmp6_dst_gc();
 
-       fib6_clean_all(net, fib6_age, NULL);
+       fib6_clean_all(net, fib6_age, &gc_args);
        now = jiffies;
        net->ipv6.ip6_rt_last_gc = now;
 
@@ -1802,7 +1802,7 @@ void fib6_run_gc(unsigned long expires, struct net *net, bool force)
                                        + net->ipv6.sysctl.ip6_rt_gc_interval));
        else
                del_timer(&net->ipv6.ip6_fib_timer);
-       spin_unlock_bh(&fib6_gc_lock);
+       spin_unlock_bh(&net->ipv6.fib6_gc_lock);
 }
 
 static void fib6_gc_timer_cb(unsigned long arg)
@@ -1814,6 +1814,9 @@ static int __net_init fib6_net_init(struct net *net)
 {
        size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ;
 
+       spin_lock_init(&net->ipv6.fib6_gc_lock);
+       rwlock_init(&net->ipv6.fib6_walker_lock);
+       INIT_LIST_HEAD(&net->ipv6.fib6_walkers);
        setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net);
 
        net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
@@ -1974,7 +1977,8 @@ static int ipv6_route_yield(struct fib6_walker *w)
        return 0;
 }
 
-static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter)
+static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter,
+                                     struct net *net)
 {
        memset(&iter->w, 0, sizeof(iter->w));
        iter->w.func = ipv6_route_yield;
@@ -1984,7 +1988,7 @@ static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter)
        iter->w.args = iter;
        iter->sernum = iter->w.root->fn_sernum;
        INIT_LIST_HEAD(&iter->w.lh);
-       fib6_walker_link(&iter->w);
+       fib6_walker_link(net, &iter->w);
 }
 
 static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl,
@@ -2045,16 +2049,16 @@ iter_table:
                        ++*pos;
                return iter->w.leaf;
        } else if (r < 0) {
-               fib6_walker_unlink(&iter->w);
+               fib6_walker_unlink(net, &iter->w);
                return NULL;
        }
-       fib6_walker_unlink(&iter->w);
+       fib6_walker_unlink(net, &iter->w);
 
        iter->tbl = ipv6_route_seq_next_table(iter->tbl, net);
        if (!iter->tbl)
                return NULL;
 
-       ipv6_route_seq_setup_walk(iter);
+       ipv6_route_seq_setup_walk(iter, net);
        goto iter_table;
 }
 
@@ -2069,7 +2073,7 @@ static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos)
        iter->skip = *pos;
 
        if (iter->tbl) {
-               ipv6_route_seq_setup_walk(iter);
+               ipv6_route_seq_setup_walk(iter, net);
                return ipv6_route_seq_next(seq, NULL, pos);
        } else {
                return NULL;
@@ -2085,10 +2089,11 @@ static bool ipv6_route_iter_active(struct ipv6_route_iter *iter)
 static void ipv6_route_seq_stop(struct seq_file *seq, void *v)
        __releases(RCU_BH)
 {
+       struct net *net = seq_file_net(seq);
        struct ipv6_route_iter *iter = seq->private;
 
        if (ipv6_route_iter_active(iter))
-               fib6_walker_unlink(&iter->w);
+               fib6_walker_unlink(net, &iter->w);
 
        rcu_read_unlock_bh();
 }
index 1f9ebe3cbb4ac042edd0b05754d1fc03cdfe73cd..dc2db4f7b182c4ebc1a8a51487a3d2e893955df9 100644 (file)
@@ -540,12 +540,13 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
                }
                spin_lock_bh(&ip6_sk_fl_lock);
                for (sflp = &np->ipv6_fl_list;
-                    (sfl = rcu_dereference(*sflp)) != NULL;
+                    (sfl = rcu_dereference_protected(*sflp,
+                                                     lockdep_is_held(&ip6_sk_fl_lock))) != NULL;
                     sflp = &sfl->next) {
                        if (sfl->fl->label == freq.flr_label) {
                                if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
                                        np->flow_label &= ~IPV6_FLOWLABEL_MASK;
-                               *sflp = rcu_dereference(sfl->next);
+                               *sflp = sfl->next;
                                spin_unlock_bh(&ip6_sk_fl_lock);
                                fl_release(sfl->fl);
                                kfree_rcu(sfl, rcu);
index f37f18b6b40c9547e24902f4af88bdf6f154f394..4e636e60a360d5c22dc856c2c80d361127ba41b6 100644 (file)
@@ -360,7 +360,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
        struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
 
        ip6gre_tunnel_unlink(ign, t);
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        dev_put(dev);
 }
 
@@ -633,7 +633,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        }
 
        if (!fl6->flowi6_mark)
-               dst = ip6_tnl_dst_get(tunnel);
+               dst = dst_cache_get(&tunnel->dst_cache);
 
        if (!dst) {
                dst = ip6_route_output(net, NULL, fl6);
@@ -702,7 +702,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
        }
 
        if (!fl6->flowi6_mark && ndst)
-               ip6_tnl_dst_set(tunnel, ndst);
+               dst_cache_set_ip6(&tunnel->dst_cache, ndst, &fl6->saddr);
        skb_dst_set(skb, dst);
 
        proto = NEXTHDR_GRE;
@@ -777,6 +777,8 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
        __u32 mtu;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
@@ -1009,7 +1011,7 @@ static int ip6gre_tnl_change(struct ip6_tnl *t,
        t->parms.o_key = p->o_key;
        t->parms.i_flags = p->i_flags;
        t->parms.o_flags = p->o_flags;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        ip6gre_tnl_link_config(t, set_mtu);
        return 0;
 }
@@ -1219,7 +1221,7 @@ static void ip6gre_dev_free(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
 
-       ip6_tnl_dst_destroy(t);
+       dst_cache_destroy(&t->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1257,7 +1259,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
-       ret = ip6_tnl_dst_init(tunnel);
+       ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
        if (ret) {
                free_percpu(dev->tstats);
                dev->tstats = NULL;
@@ -1512,6 +1514,7 @@ static void ip6gre_tap_setup(struct net_device *dev)
        dev->destructor = ip6gre_dev_free;
 
        dev->features |= NETIF_F_NETNS_LOCAL;
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 }
 
 static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
index 31ac3c56da4ba16f806d4ef234de7599f25a265c..c05c425c23890b4b5ce077d5ca835a7e644ab881 100644 (file)
@@ -49,7 +49,7 @@
 
 int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
-       if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
+       if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
                const struct inet6_protocol *ipprot;
 
                ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
index a163102f1803e5f9eb4a60c501bd4adcc27bd62b..9428345d3a078786f6662e9384e75c97b9c3e245 100644 (file)
@@ -332,7 +332,6 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
 static inline int ip6_forward_finish(struct net *net, struct sock *sk,
                                     struct sk_buff *skb)
 {
-       skb_sender_cpu_clear(skb);
        return dst_output(net, sk, skb);
 }
 
index 137fca42aaa6bb809d46e7809b240d8810d89a04..eb2ac4bb09ce0fb0f9afb3fcc142aad80270a6cb 100644 (file)
@@ -122,97 +122,6 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
        return &dev->stats;
 }
 
-/*
- * Locking : hash tables are protected by RCU and RTNL
- */
-
-static void ip6_tnl_per_cpu_dst_set(struct ip6_tnl_dst *idst,
-                                   struct dst_entry *dst)
-{
-       write_seqlock_bh(&idst->lock);
-       dst_release(rcu_dereference_protected(
-                           idst->dst,
-                           lockdep_is_held(&idst->lock.lock)));
-       if (dst) {
-               dst_hold(dst);
-               idst->cookie = rt6_get_cookie((struct rt6_info *)dst);
-       } else {
-               idst->cookie = 0;
-       }
-       rcu_assign_pointer(idst->dst, dst);
-       write_sequnlock_bh(&idst->lock);
-}
-
-struct dst_entry *ip6_tnl_dst_get(struct ip6_tnl *t)
-{
-       struct ip6_tnl_dst *idst;
-       struct dst_entry *dst;
-       unsigned int seq;
-       u32 cookie;
-
-       idst = raw_cpu_ptr(t->dst_cache);
-
-       rcu_read_lock();
-       do {
-               seq = read_seqbegin(&idst->lock);
-               dst = rcu_dereference(idst->dst);
-               cookie = idst->cookie;
-       } while (read_seqretry(&idst->lock, seq));
-
-       if (dst && !atomic_inc_not_zero(&dst->__refcnt))
-               dst = NULL;
-       rcu_read_unlock();
-
-       if (dst && dst->obsolete && !dst->ops->check(dst, cookie)) {
-               ip6_tnl_per_cpu_dst_set(idst, NULL);
-               dst_release(dst);
-               dst = NULL;
-       }
-       return dst;
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_get);
-
-void ip6_tnl_dst_reset(struct ip6_tnl *t)
-{
-       int i;
-
-       for_each_possible_cpu(i)
-               ip6_tnl_per_cpu_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
-
-void ip6_tnl_dst_set(struct ip6_tnl *t, struct dst_entry *dst)
-{
-       ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), dst);
-
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_set);
-
-void ip6_tnl_dst_destroy(struct ip6_tnl *t)
-{
-       if (!t->dst_cache)
-               return;
-
-       ip6_tnl_dst_reset(t);
-       free_percpu(t->dst_cache);
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_destroy);
-
-int ip6_tnl_dst_init(struct ip6_tnl *t)
-{
-       int i;
-
-       t->dst_cache = alloc_percpu(struct ip6_tnl_dst);
-       if (!t->dst_cache)
-               return -ENOMEM;
-
-       for_each_possible_cpu(i)
-               seqlock_init(&per_cpu_ptr(t->dst_cache, i)->lock);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ip6_tnl_dst_init);
-
 /**
  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
  *   @remote: the address of the tunnel exit-point
@@ -329,7 +238,7 @@ static void ip6_dev_free(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
 
-       ip6_tnl_dst_destroy(t);
+       dst_cache_destroy(&t->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -462,7 +371,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
                RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
        else
                ip6_tnl_unlink(ip6n, t);
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        dev_put(dev);
 }
 
@@ -1069,7 +978,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
                neigh_release(neigh);
        } else if (!fl6->flowi6_mark)
-               dst = ip6_tnl_dst_get(t);
+               dst = dst_cache_get(&t->dst_cache);
 
        if (!ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr))
                goto tx_err_link_failure;
@@ -1133,7 +1042,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        }
 
        if (!fl6->flowi6_mark && ndst)
-               ip6_tnl_dst_set(t, ndst);
+               dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr);
        skb_dst_set(skb, dst);
 
        skb->transport_header = skb->network_header;
@@ -1180,6 +1089,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        u8 tproto;
        int err;
 
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
        tproto = ACCESS_ONCE(t->parms.proto);
        if (tproto != IPPROTO_IPIP && tproto != 0)
                return -1;
@@ -1366,7 +1277,7 @@ ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.flowinfo = p->flowinfo;
        t->parms.link = p->link;
        t->parms.proto = p->proto;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        ip6_tnl_link_config(t);
        return 0;
 }
@@ -1637,7 +1548,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        if (!dev->tstats)
                return -ENOMEM;
 
-       ret = ip6_tnl_dst_init(t);
+       ret = dst_cache_init(&t->dst_cache, GFP_KERNEL);
        if (ret) {
                free_percpu(dev->tstats);
                dev->tstats = NULL;
index 14dacf1df529d9602cc497976db0868f68d9fbb7..a7520528ecd27fae3d8ccee03c76345f0776234a 100644 (file)
@@ -73,8 +73,8 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
                         struct sk_buff *skb,
                         struct net_device *dev, struct in6_addr *saddr,
                         struct in6_addr *daddr,
-                        __u8 prio, __u8 ttl, __be16 src_port,
-                        __be16 dst_port, bool nocheck)
+                        __u8 prio, __u8 ttl, __be32 label,
+                        __be16 src_port, __be16 dst_port, bool nocheck)
 {
        struct udphdr *uh;
        struct ipv6hdr *ip6h;
@@ -98,7 +98,7 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
        __skb_push(skb, sizeof(*ip6h));
        skb_reset_network_header(skb);
        ip6h              = ipv6_hdr(skb);
-       ip6_flow_hdr(ip6h, prio, htonl(0));
+       ip6_flow_hdr(ip6h, prio, label);
        ip6h->payload_len = htons(skb->len);
        ip6h->nexthdr     = IPPROTO_UDP;
        ip6h->hop_limit   = ttl;
index 0a8610b33d7980e4b1d5290b4266669ddcdc9e0a..d90a11f14040cf8097d3270710ab7db02be60d84 100644 (file)
@@ -640,7 +640,7 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.i_key = p->i_key;
        t->parms.o_key = p->o_key;
        t->parms.proto = p->proto;
-       ip6_tnl_dst_reset(t);
+       dst_cache_reset(&t->dst_cache);
        vti6_link_config(t);
        return 0;
 }
index 5ee56d0a8699e22434d5ad8b4380f890fa8d2126..d64ee7e8366492a439ab70ea7487bd3669800097 100644 (file)
@@ -1574,9 +1574,8 @@ static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu)
                return NULL;
 
        skb->priority = TC_PRIO_CONTROL;
-       skb->reserved_tailroom = skb_end_offset(skb) -
-                                min(mtu, skb_end_offset(skb));
        skb_reserve(skb, hlen);
+       skb_tailroom_reserve(skb, mtu, tlen);
 
        if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
index 99425cf2819b83ceb33d49af65284cb16fd076ec..84f9baf7aee83c018ac3a50c14417bef10df6030 100644 (file)
@@ -2071,9 +2071,28 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-struct xt_table *ip6t_register_table(struct net *net,
-                                    const struct xt_table *table,
-                                    const struct ip6t_replace *repl)
+static void __ip6t_unregister_table(struct net *net, struct xt_table *table)
+{
+       struct xt_table_info *private;
+       void *loc_cpu_entry;
+       struct module *table_owner = table->me;
+       struct ip6t_entry *iter;
+
+       private = xt_unregister_table(table);
+
+       /* Decrease module usage counts and free resources */
+       loc_cpu_entry = private->entries;
+       xt_entry_foreach(iter, loc_cpu_entry, private->size)
+               cleanup_entry(iter, net);
+       if (private->number > private->initial_entries)
+               module_put(table_owner);
+       xt_free_table_info(private);
+}
+
+int ip6t_register_table(struct net *net, const struct xt_table *table,
+                       const struct ip6t_replace *repl,
+                       const struct nf_hook_ops *ops,
+                       struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -2082,10 +2101,8 @@ struct xt_table *ip6t_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -2099,30 +2116,28 @@ struct xt_table *ip6t_register_table(struct net *net,
                ret = PTR_ERR(new_table);
                goto out_free;
        }
-       return new_table;
+
+       /* set res now, will see skbs right after nf_register_net_hooks */
+       WRITE_ONCE(*res, new_table);
+
+       ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
+       if (ret != 0) {
+               __ip6t_unregister_table(net, new_table);
+               *res = NULL;
+       }
+
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void ip6t_unregister_table(struct net *net, struct xt_table *table)
+void ip6t_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops)
 {
-       struct xt_table_info *private;
-       void *loc_cpu_entry;
-       struct module *table_owner = table->me;
-       struct ip6t_entry *iter;
-
-       private = xt_unregister_table(table);
-
-       /* Decrease module usage counts and free resources */
-       loc_cpu_entry = private->entries;
-       xt_entry_foreach(iter, loc_cpu_entry, private->size)
-               cleanup_entry(iter, net);
-       if (private->number > private->initial_entries)
-               module_put(table_owner);
-       xt_free_table_info(private);
+       nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
+       __ip6t_unregister_table(net, table);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
index 8b277b983ca51886973ab62601d136a0b318f001..1343077dde938f29cb6262937c8587d2ed640b69 100644 (file)
@@ -22,12 +22,15 @@ MODULE_DESCRIPTION("ip6tables filter table");
                            (1 << NF_INET_FORWARD) | \
                            (1 << NF_INET_LOCAL_OUT))
 
+static int __net_init ip6table_filter_table_init(struct net *net);
+
 static const struct xt_table packet_filter = {
        .name           = "filter",
        .valid_hooks    = FILTER_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_FILTER,
+       .table_init     = ip6table_filter_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
@@ -44,9 +47,13 @@ static struct nf_hook_ops *filter_ops __read_mostly;
 static bool forward = true;
 module_param(forward, bool, 0000);
 
-static int __net_init ip6table_filter_net_init(struct net *net)
+static int __net_init ip6table_filter_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int err;
+
+       if (net->ipv6.ip6table_filter)
+               return 0;
 
        repl = ip6t_alloc_initial_table(&packet_filter);
        if (repl == NULL)
@@ -55,15 +62,26 @@ static int __net_init ip6table_filter_net_init(struct net *net)
        ((struct ip6t_standard *)repl->entries)[1].target.verdict =
                forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
-       net->ipv6.ip6table_filter =
-               ip6t_register_table(net, &packet_filter, repl);
+       err = ip6t_register_table(net, &packet_filter, repl, filter_ops,
+                                 &net->ipv6.ip6table_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter);
+       return err;
+}
+
+static int __net_init ip6table_filter_net_init(struct net *net)
+{
+       if (net == &init_net || !forward)
+               return ip6table_filter_table_init(net);
+
+       return 0;
 }
 
 static void __net_exit ip6table_filter_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_filter);
+       if (!net->ipv6.ip6table_filter)
+               return;
+       ip6t_unregister_table(net, net->ipv6.ip6table_filter, filter_ops);
+       net->ipv6.ip6table_filter = NULL;
 }
 
 static struct pernet_operations ip6table_filter_net_ops = {
@@ -75,28 +93,21 @@ static int __init ip6table_filter_init(void)
 {
        int ret;
 
+       filter_ops = xt_hook_ops_alloc(&packet_filter, ip6table_filter_hook);
+       if (IS_ERR(filter_ops))
+               return PTR_ERR(filter_ops);
+
        ret = register_pernet_subsys(&ip6table_filter_net_ops);
        if (ret < 0)
-               return ret;
-
-       /* Register hooks */
-       filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook);
-       if (IS_ERR(filter_ops)) {
-               ret = PTR_ERR(filter_ops);
-               goto cleanup_table;
-       }
+               kfree(filter_ops);
 
        return ret;
-
- cleanup_table:
-       unregister_pernet_subsys(&ip6table_filter_net_ops);
-       return ret;
 }
 
 static void __exit ip6table_filter_fini(void)
 {
-       xt_hook_unlink(&packet_filter, filter_ops);
        unregister_pernet_subsys(&ip6table_filter_net_ops);
+       kfree(filter_ops);
 }
 
 module_init(ip6table_filter_init);
index abe278b079322cb929cc16e260722ec49da414d5..cb2b28883252562ae834f49c811e940fcbb18ee2 100644 (file)
@@ -23,12 +23,15 @@ MODULE_DESCRIPTION("ip6tables mangle table");
                            (1 << NF_INET_LOCAL_OUT) | \
                            (1 << NF_INET_POST_ROUTING))
 
+static int __net_init ip6table_mangle_table_init(struct net *net);
+
 static const struct xt_table packet_mangler = {
        .name           = "mangle",
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_MANGLE,
+       .table_init     = ip6table_mangle_table_init,
 };
 
 static unsigned int
@@ -88,26 +91,33 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
 }
 
 static struct nf_hook_ops *mangle_ops __read_mostly;
-static int __net_init ip6table_mangle_net_init(struct net *net)
+static int __net_init ip6table_mangle_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
+
+       if (net->ipv6.ip6table_mangle)
+               return 0;
 
        repl = ip6t_alloc_initial_table(&packet_mangler);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_mangle =
-               ip6t_register_table(net, &packet_mangler, repl);
+       ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops,
+                                 &net->ipv6.ip6table_mangle);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle);
+       return ret;
 }
 
 static void __net_exit ip6table_mangle_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_mangle);
+       if (!net->ipv6.ip6table_mangle)
+               return;
+
+       ip6t_unregister_table(net, net->ipv6.ip6table_mangle, mangle_ops);
+       net->ipv6.ip6table_mangle = NULL;
 }
 
 static struct pernet_operations ip6table_mangle_net_ops = {
-       .init = ip6table_mangle_net_init,
        .exit = ip6table_mangle_net_exit,
 };
 
@@ -115,28 +125,28 @@ static int __init ip6table_mangle_init(void)
 {
        int ret;
 
+       mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook);
+       if (IS_ERR(mangle_ops))
+               return PTR_ERR(mangle_ops);
+
        ret = register_pernet_subsys(&ip6table_mangle_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(mangle_ops);
                return ret;
-
-       /* Register hooks */
-       mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook);
-       if (IS_ERR(mangle_ops)) {
-               ret = PTR_ERR(mangle_ops);
-               goto cleanup_table;
        }
 
-       return ret;
-
- cleanup_table:
-       unregister_pernet_subsys(&ip6table_mangle_net_ops);
+       ret = ip6table_mangle_table_init(&init_net);
+       if (ret) {
+               unregister_pernet_subsys(&ip6table_mangle_net_ops);
+               kfree(mangle_ops);
+       }
        return ret;
 }
 
 static void __exit ip6table_mangle_fini(void)
 {
-       xt_hook_unlink(&packet_mangler, mangle_ops);
        unregister_pernet_subsys(&ip6table_mangle_net_ops);
+       kfree(mangle_ops);
 }
 
 module_init(ip6table_mangle_init);
index de2a10a565f549bc4ae183d1c5af31d29fb106e4..7d2bd940291fd47a68977ec86b7ac0952744c432 100644 (file)
@@ -20,6 +20,8 @@
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_l3proto.h>
 
+static int __net_init ip6table_nat_table_init(struct net *net);
+
 static const struct xt_table nf_nat_ipv6_table = {
        .name           = "nat",
        .valid_hooks    = (1 << NF_INET_PRE_ROUTING) |
@@ -28,6 +30,7 @@ static const struct xt_table nf_nat_ipv6_table = {
                          (1 << NF_INET_LOCAL_IN),
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
+       .table_init     = ip6table_nat_table_init,
 };
 
 static unsigned int ip6table_nat_do_chain(void *priv,
@@ -97,50 +100,50 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
        },
 };
 
-static int __net_init ip6table_nat_net_init(struct net *net)
+static int __net_init ip6table_nat_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
+
+       if (net->ipv6.ip6table_nat)
+               return 0;
 
        repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
+       ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
+                                 nf_nat_ipv6_ops, &net->ipv6.ip6table_nat);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat);
+       return ret;
 }
 
 static void __net_exit ip6table_nat_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_nat);
+       if (!net->ipv6.ip6table_nat)
+               return;
+       ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops);
+       net->ipv6.ip6table_nat = NULL;
 }
 
 static struct pernet_operations ip6table_nat_net_ops = {
-       .init   = ip6table_nat_net_init,
        .exit   = ip6table_nat_net_exit,
 };
 
 static int __init ip6table_nat_init(void)
 {
-       int err;
+       int ret = register_pernet_subsys(&ip6table_nat_net_ops);
 
-       err = register_pernet_subsys(&ip6table_nat_net_ops);
-       if (err < 0)
-               goto err1;
+       if (ret)
+               return ret;
 
-       err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
-       if (err < 0)
-               goto err2;
-       return 0;
-
-err2:
-       unregister_pernet_subsys(&ip6table_nat_net_ops);
-err1:
-       return err;
+       ret = ip6table_nat_table_init(&init_net);
+       if (ret)
+               unregister_pernet_subsys(&ip6table_nat_net_ops);
+       return ret;
 }
 
 static void __exit ip6table_nat_exit(void)
 {
-       nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
        unregister_pernet_subsys(&ip6table_nat_net_ops);
 }
 
index 9021963565c37703ae478c2a39243a1725c92685..d4bc56443dc17e02a6674b7a90f13b2057ef8558 100644 (file)
@@ -9,12 +9,15 @@
 
 #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
 
+static int __net_init ip6table_raw_table_init(struct net *net);
+
 static const struct xt_table packet_raw = {
        .name = "raw",
        .valid_hooks = RAW_VALID_HOOKS,
        .me = THIS_MODULE,
        .af = NFPROTO_IPV6,
        .priority = NF_IP6_PRI_RAW,
+       .table_init = ip6table_raw_table_init,
 };
 
 /* The work comes in here from netfilter.c. */
@@ -27,26 +30,32 @@ ip6table_raw_hook(void *priv, struct sk_buff *skb,
 
 static struct nf_hook_ops *rawtable_ops __read_mostly;
 
-static int __net_init ip6table_raw_net_init(struct net *net)
+static int __net_init ip6table_raw_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
+
+       if (net->ipv6.ip6table_raw)
+               return 0;
 
        repl = ip6t_alloc_initial_table(&packet_raw);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_raw =
-               ip6t_register_table(net, &packet_raw, repl);
+       ret = ip6t_register_table(net, &packet_raw, repl, rawtable_ops,
+                                 &net->ipv6.ip6table_raw);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw);
+       return ret;
 }
 
 static void __net_exit ip6table_raw_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_raw);
+       if (!net->ipv6.ip6table_raw)
+               return;
+       ip6t_unregister_table(net, net->ipv6.ip6table_raw, rawtable_ops);
+       net->ipv6.ip6table_raw = NULL;
 }
 
 static struct pernet_operations ip6table_raw_net_ops = {
-       .init = ip6table_raw_net_init,
        .exit = ip6table_raw_net_exit,
 };
 
@@ -54,28 +63,29 @@ static int __init ip6table_raw_init(void)
 {
        int ret;
 
+       /* Register hooks */
+       rawtable_ops = xt_hook_ops_alloc(&packet_raw, ip6table_raw_hook);
+       if (IS_ERR(rawtable_ops))
+               return PTR_ERR(rawtable_ops);
+
        ret = register_pernet_subsys(&ip6table_raw_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(rawtable_ops);
                return ret;
-
-       /* Register hooks */
-       rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook);
-       if (IS_ERR(rawtable_ops)) {
-               ret = PTR_ERR(rawtable_ops);
-               goto cleanup_table;
        }
 
-       return ret;
-
- cleanup_table:
-       unregister_pernet_subsys(&ip6table_raw_net_ops);
+       ret = ip6table_raw_table_init(&init_net);
+       if (ret) {
+               unregister_pernet_subsys(&ip6table_raw_net_ops);
+               kfree(rawtable_ops);
+       }
        return ret;
 }
 
 static void __exit ip6table_raw_fini(void)
 {
-       xt_hook_unlink(&packet_raw, rawtable_ops);
        unregister_pernet_subsys(&ip6table_raw_net_ops);
+       kfree(rawtable_ops);
 }
 
 module_init(ip6table_raw_init);
index 0d856fedfeb0c2d1ddc97cb5372fc33eda2f102b..cf26ccb04056e1346f40a1d34ff44e2b8eb9f518 100644 (file)
@@ -27,12 +27,15 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
                                (1 << NF_INET_FORWARD) | \
                                (1 << NF_INET_LOCAL_OUT)
 
+static int __net_init ip6table_security_table_init(struct net *net);
+
 static const struct xt_table security_table = {
        .name           = "security",
        .valid_hooks    = SECURITY_VALID_HOOKS,
        .me             = THIS_MODULE,
        .af             = NFPROTO_IPV6,
        .priority       = NF_IP6_PRI_SECURITY,
+       .table_init     = ip6table_security_table_init,
 };
 
 static unsigned int
@@ -44,26 +47,32 @@ ip6table_security_hook(void *priv, struct sk_buff *skb,
 
 static struct nf_hook_ops *sectbl_ops __read_mostly;
 
-static int __net_init ip6table_security_net_init(struct net *net)
+static int __net_init ip6table_security_table_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
+
+       if (net->ipv6.ip6table_security)
+               return 0;
 
        repl = ip6t_alloc_initial_table(&security_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_security =
-               ip6t_register_table(net, &security_table, repl);
+       ret = ip6t_register_table(net, &security_table, repl, sectbl_ops,
+                                 &net->ipv6.ip6table_security);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security);
+       return ret;
 }
 
 static void __net_exit ip6table_security_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_security);
+       if (!net->ipv6.ip6table_security)
+               return;
+       ip6t_unregister_table(net, net->ipv6.ip6table_security, sectbl_ops);
+       net->ipv6.ip6table_security = NULL;
 }
 
 static struct pernet_operations ip6table_security_net_ops = {
-       .init = ip6table_security_net_init,
        .exit = ip6table_security_net_exit,
 };
 
@@ -71,27 +80,28 @@ static int __init ip6table_security_init(void)
 {
        int ret;
 
+       sectbl_ops = xt_hook_ops_alloc(&security_table, ip6table_security_hook);
+       if (IS_ERR(sectbl_ops))
+               return PTR_ERR(sectbl_ops);
+
        ret = register_pernet_subsys(&ip6table_security_net_ops);
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(sectbl_ops);
                return ret;
-
-       sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook);
-       if (IS_ERR(sectbl_ops)) {
-               ret = PTR_ERR(sectbl_ops);
-               goto cleanup_table;
        }
 
-       return ret;
-
-cleanup_table:
-       unregister_pernet_subsys(&ip6table_security_net_ops);
+       ret = ip6table_security_table_init(&init_net);
+       if (ret) {
+               unregister_pernet_subsys(&ip6table_security_net_ops);
+               kfree(sectbl_ops);
+       }
        return ret;
 }
 
 static void __exit ip6table_security_fini(void)
 {
-       xt_hook_unlink(&security_table, sectbl_ops);
        unregister_pernet_subsys(&ip6table_security_net_ops);
+       kfree(sectbl_ops);
 }
 
 module_init(ip6table_security_init);
index 31ba7ca19757083a1a83f8388b87be5695b1ba98..051b6a6bfff6ca7c0dd42ceb43a417260a11bd23 100644 (file)
 #include <net/ipv6.h>
 #include <net/netfilter/ipv6/nf_nat_masquerade.h>
 
+#define MAX_WORK_COUNT 16
+
+static atomic_t v6_worker_count;
+
 unsigned int
 nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
                       const struct net_device *out)
@@ -78,14 +82,78 @@ static struct notifier_block masq_dev_notifier = {
        .notifier_call  = masq_device_event,
 };
 
+struct masq_dev_work {
+       struct work_struct work;
+       struct net *net;
+       int ifindex;
+};
+
+static void iterate_cleanup_work(struct work_struct *work)
+{
+       struct masq_dev_work *w;
+       long index;
+
+       w = container_of(work, struct masq_dev_work, work);
+
+       index = w->ifindex;
+       nf_ct_iterate_cleanup(w->net, device_cmp, (void *)index, 0, 0);
+
+       put_net(w->net);
+       kfree(w);
+       atomic_dec(&v6_worker_count);
+       module_put(THIS_MODULE);
+}
+
+/* ipv6 inet notifier is an atomic notifier, i.e. we cannot
+ * schedule.
+ *
+ * Unfortunately, nf_ct_iterate_cleanup can run for a long
+ * time if there are lots of conntracks and the system
+ * handles high softirq load, so it frequently calls cond_resched
+ * while iterating the conntrack table.
+ *
+ * So we defer nf_ct_iterate_cleanup walk to the system workqueue.
+ *
+ * As we can have 'a lot' of inet_events (depending on amount
+ * of ipv6 addresses being deleted), we also need to add an upper
+ * limit to the number of queued work items.
+ */
 static int masq_inet_event(struct notifier_block *this,
                           unsigned long event, void *ptr)
 {
        struct inet6_ifaddr *ifa = ptr;
-       struct netdev_notifier_info info;
+       const struct net_device *dev;
+       struct masq_dev_work *w;
+       struct net *net;
+
+       if (event != NETDEV_DOWN ||
+           atomic_read(&v6_worker_count) >= MAX_WORK_COUNT)
+               return NOTIFY_DONE;
+
+       dev = ifa->idev->dev;
+       net = maybe_get_net(dev_net(dev));
+       if (!net)
+               return NOTIFY_DONE;
 
-       netdev_notifier_info_init(&info, ifa->idev->dev);
-       return masq_device_event(this, event, &info);
+       if (!try_module_get(THIS_MODULE))
+               goto err_module;
+
+       w = kmalloc(sizeof(*w), GFP_ATOMIC);
+       if (w) {
+               atomic_inc(&v6_worker_count);
+
+               INIT_WORK(&w->work, iterate_cleanup_work);
+               w->ifindex = dev->ifindex;
+               w->net = net;
+               schedule_work(&w->work);
+
+               return NOTIFY_DONE;
+       }
+
+       module_put(THIS_MODULE);
+ err_module:
+       put_net(net);
+       return NOTIFY_DONE;
 }
 
 static struct notifier_block masq_inet_notifier = {
index cd1ac1637a0512d19fd4d3345011bcc3c9daab9d..9597ffb740773f37463706d26f29660a05f61abb 100644 (file)
@@ -26,7 +26,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,
 
        memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
-
+       if (priv->sreg_proto_min) {
+               range.min_proto.all =
+                       *(__be16 *)&regs->data[priv->sreg_proto_min];
+               range.max_proto.all =
+                       *(__be16 *)&regs->data[priv->sreg_proto_max];
+       }
        regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
 }
 
index 18f3498a6c80564d897a2f659a7747827d19a667..e2ea31175ef938af102a3dae8199fb0583399baf 100644 (file)
@@ -496,10 +496,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
        IP6CB(head)->flags |= IP6SKB_FRAGMENTED;
 
        /* Yes, and fold redundant checksum back. 8) */
-       if (head->ip_summed == CHECKSUM_COMPLETE)
-               head->csum = csum_partial(skb_network_header(head),
-                                         skb_network_header_len(head),
-                                         head->csum);
+       skb_postpush_rcsum(head, skb_network_header(head),
+                          skb_network_header_len(head));
 
        rcu_read_lock();
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
index 9a6b407f5840bf7b50344ca37fd8689693bdc198..f45b8ffc2840bbca9070b96ad85811ea8157f829 100644 (file)
@@ -475,7 +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);
+       dst_cache_reset(&tunnel->dst_cache);
        dev_put(dev);
 }
 
@@ -740,7 +740,7 @@ static int ipip_rcv(struct sk_buff *skb)
 
                if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
                        goto drop;
-               if (iptunnel_pull_header(skb, 0, tpi.proto))
+               if (iptunnel_pull_header(skb, 0, tpi.proto, false))
                        goto drop;
                return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
        }
@@ -1093,7 +1093,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);
+       dst_cache_reset(&t->dst_cache);
        netdev_state_change(t->dev);
 }
 
@@ -1124,7 +1124,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);
+       dst_cache_reset(&t->dst_cache);
        netdev_state_change(t->dev);
        return 0;
 }
@@ -1278,7 +1278,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);
+               dst_cache_reset(&t->dst_cache);
                netdev_state_change(dev);
                break;
 
@@ -1339,7 +1339,7 @@ static void ipip6_dev_free(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
 
-       free_percpu(tunnel->dst_cache);
+       dst_cache_destroy(&tunnel->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1372,6 +1372,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
 static int ipip6_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
+       int err;
 
        tunnel->dev = dev;
        tunnel->net = dev_net(dev);
@@ -1382,10 +1383,10 @@ 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) {
+       err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL);
+       if (err) {
                free_percpu(dev->tstats);
-               return -ENOMEM;
+               return err;
        }
 
        return 0;
index 9977b6f19f2af3c8a612afb853c3dd5b2cb72ac5..33f2820181f9512fc465a6af7559c3d33f539a57 100644 (file)
@@ -327,6 +327,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct tcp_sock *tp;
        __u32 seq, snd_una;
        struct sock *sk;
+       bool fatal;
        int err;
 
        sk = __inet6_lookup_established(net, &tcp_hashinfo,
@@ -345,8 +346,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                return;
        }
        seq = ntohl(th->seq);
+       fatal = icmpv6_err_convert(type, code, &err);
        if (sk->sk_state == TCP_NEW_SYN_RECV)
-               return tcp_req_err(sk, seq);
+               return tcp_req_err(sk, seq, fatal);
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG)
@@ -400,7 +402,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                goto out;
        }
 
-       icmpv6_err_convert(type, code, &err);
 
        /* Might be for an request_sock */
        switch (sk->sk_state) {
@@ -1387,7 +1388,7 @@ process:
 
        if (sk->sk_state == TCP_NEW_SYN_RECV) {
                struct request_sock *req = inet_reqsk(sk);
-               struct sock *nsk = NULL;
+               struct sock *nsk;
 
                sk = req->rsk_listener;
                tcp_v6_fill_cb(skb, hdr, th);
@@ -1395,24 +1396,24 @@ process:
                        reqsk_put(req);
                        goto discard_it;
                }
-               if (likely(sk->sk_state == TCP_LISTEN)) {
-                       nsk = tcp_check_req(sk, skb, req, false);
-               } else {
+               if (unlikely(sk->sk_state != TCP_LISTEN)) {
                        inet_csk_reqsk_queue_drop_and_put(sk, req);
                        goto lookup;
                }
+               sock_hold(sk);
+               nsk = tcp_check_req(sk, skb, req, false);
                if (!nsk) {
                        reqsk_put(req);
-                       goto discard_it;
+                       goto discard_and_relse;
                }
                if (nsk == sk) {
-                       sock_hold(sk);
                        reqsk_put(req);
                        tcp_v6_restore_cb(skb);
                } else if (tcp_child_process(sk, nsk, skb)) {
                        tcp_v6_send_reset(nsk, skb);
-                       goto discard_it;
+                       goto discard_and_relse;
                } else {
+                       sock_put(sk);
                        return 0;
                }
        }
index ac4e7e03dded9d637f2835c6782c0b406c21b1cf..fd25e447a5fa3fb5590f5979a43414ea9c85f079 100644 (file)
@@ -548,6 +548,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        const struct in6_addr *daddr = &hdr->daddr;
        struct udphdr *uh = (struct udphdr *)(skb->data+offset);
        struct sock *sk;
+       int harderr;
        int err;
        struct net *net = dev_net(skb->dev);
 
@@ -559,26 +560,27 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                return;
        }
 
+       harderr = icmpv6_err_convert(type, code, &err);
+       np = inet6_sk(sk);
+
        if (type == ICMPV6_PKT_TOOBIG) {
                if (!ip6_sk_accept_pmtu(sk))
                        goto out;
                ip6_sk_update_pmtu(skb, sk, info);
+               if (np->pmtudisc != IPV6_PMTUDISC_DONT)
+                       harderr = 1;
        }
        if (type == NDISC_REDIRECT) {
                ip6_sk_redirect(skb, sk);
                goto out;
        }
 
-       np = inet6_sk(sk);
-
-       if (!icmpv6_err_convert(type, code, &err) && !np->recverr)
-               goto out;
-
-       if (sk->sk_state != TCP_ESTABLISHED && !np->recverr)
-               goto out;
-
-       if (np->recverr)
+       if (!np->recverr) {
+               if (!harderr || sk->sk_state != TCP_ESTABLISHED)
+                       goto out;
+       } else {
                ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
+       }
 
        sk->sk_err = err;
        sk->sk_error_report(sk);
@@ -920,11 +922,9 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
-               /* a return value > 0 means to resubmit the input, but
-                * it wants the return to be -protocol, or 0
-                */
+               /* a return value > 0 means to resubmit the input */
                if (ret > 0)
-                       return -ret;
+                       return ret;
 
                return 0;
        }
index 7441e1e6389381a9ae65df5c433433d5cf63a3f2..2b0fbe6929e84e1bcd9cda057c98a0207a573cab 100644 (file)
@@ -81,12 +81,18 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                csum = skb_checksum(skb, 0, skb->len, 0);
                uh->check = udp_v6_check(skb->len, &ipv6h->saddr,
                                          &ipv6h->daddr, csum);
-
                if (uh->check == 0)
                        uh->check = CSUM_MANGLED_0;
 
                skb->ip_summed = CHECKSUM_NONE;
 
+               /* If there is no outer header we can fake a checksum offload
+                * due to the fact that we have already done the checksum in
+                * software prior to segmenting the frame.
+                */
+               if (!skb->encap_hdr_csum)
+                       features |= NETIF_F_HW_CSUM;
+
                /* Check if there is enough headroom to insert fragment header. */
                tnl_hlen = skb_tnl_header_len(skb);
                if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) {
diff --git a/net/kcm/Kconfig b/net/kcm/Kconfig
new file mode 100644 (file)
index 0000000..5db94d9
--- /dev/null
@@ -0,0 +1,10 @@
+
+config AF_KCM
+       tristate "KCM sockets"
+       depends on INET
+       select BPF_SYSCALL
+       ---help---
+         KCM (Kernel Connection Multiplexor) sockets provide a method
+         for multiplexing messages of a message based application
+         protocol over kernel connectons (e.g. TCP connections).
+
diff --git a/net/kcm/Makefile b/net/kcm/Makefile
new file mode 100644 (file)
index 0000000..7125613
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_AF_KCM) += kcm.o
+
+kcm-y := kcmsock.o kcmproc.o
diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c
new file mode 100644 (file)
index 0000000..7380087
--- /dev/null
@@ -0,0 +1,426 @@
+#include <linux/in.h>
+#include <linux/inet.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <linux/rculist.h>
+#include <linux/seq_file.h>
+#include <linux/socket.h>
+#include <net/inet_sock.h>
+#include <net/kcm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/tcp.h>
+
+#ifdef CONFIG_PROC_FS
+struct kcm_seq_muxinfo {
+       char                            *name;
+       const struct file_operations    *seq_fops;
+       const struct seq_operations     seq_ops;
+};
+
+static struct kcm_mux *kcm_get_first(struct seq_file *seq)
+{
+       struct net *net = seq_file_net(seq);
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       return list_first_or_null_rcu(&knet->mux_list,
+                                     struct kcm_mux, kcm_mux_list);
+}
+
+static struct kcm_mux *kcm_get_next(struct kcm_mux *mux)
+{
+       struct kcm_net *knet = mux->knet;
+
+       return list_next_or_null_rcu(&knet->mux_list, &mux->kcm_mux_list,
+                                    struct kcm_mux, kcm_mux_list);
+}
+
+static struct kcm_mux *kcm_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct net *net = seq_file_net(seq);
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+       struct kcm_mux *m;
+
+       list_for_each_entry_rcu(m, &knet->mux_list, kcm_mux_list) {
+               if (!pos)
+                       return m;
+               --pos;
+       }
+       return NULL;
+}
+
+static void *kcm_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       void *p;
+
+       if (v == SEQ_START_TOKEN)
+               p = kcm_get_first(seq);
+       else
+               p = kcm_get_next(v);
+       ++*pos;
+       return p;
+}
+
+static void *kcm_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(rcu)
+{
+       rcu_read_lock();
+
+       if (!*pos)
+               return SEQ_START_TOKEN;
+       else
+               return kcm_get_idx(seq, *pos - 1);
+}
+
+static void kcm_seq_stop(struct seq_file *seq, void *v)
+       __releases(rcu)
+{
+       rcu_read_unlock();
+}
+
+struct kcm_proc_mux_state {
+       struct seq_net_private p;
+       int idx;
+};
+
+static int kcm_seq_open(struct inode *inode, struct file *file)
+{
+       struct kcm_seq_muxinfo *muxinfo = PDE_DATA(inode);
+       int err;
+
+       err = seq_open_net(inode, file, &muxinfo->seq_ops,
+                          sizeof(struct kcm_proc_mux_state));
+       if (err < 0)
+               return err;
+       return err;
+}
+
+static void kcm_format_mux_header(struct seq_file *seq)
+{
+       struct net *net = seq_file_net(seq);
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       seq_printf(seq,
+                  "*** KCM statistics (%d MUX) ****\n",
+                  knet->count);
+
+       seq_printf(seq,
+                  "%-14s %-10s %-16s %-10s %-16s %-8s %-8s %-8s %-8s %s",
+                  "Object",
+                  "RX-Msgs",
+                  "RX-Bytes",
+                  "TX-Msgs",
+                  "TX-Bytes",
+                  "Recv-Q",
+                  "Rmem",
+                  "Send-Q",
+                  "Smem",
+                  "Status");
+
+       /* XXX: pdsts header stuff here */
+       seq_puts(seq, "\n");
+}
+
+static void kcm_format_sock(struct kcm_sock *kcm, struct seq_file *seq,
+                           int i, int *len)
+{
+       seq_printf(seq,
+                  "   kcm-%-7u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8s ",
+                  kcm->index,
+                  kcm->stats.rx_msgs,
+                  kcm->stats.rx_bytes,
+                  kcm->stats.tx_msgs,
+                  kcm->stats.tx_bytes,
+                  kcm->sk.sk_receive_queue.qlen,
+                  sk_rmem_alloc_get(&kcm->sk),
+                  kcm->sk.sk_write_queue.qlen,
+                  "-");
+
+       if (kcm->tx_psock)
+               seq_printf(seq, "Psck-%u ", kcm->tx_psock->index);
+
+       if (kcm->tx_wait)
+               seq_puts(seq, "TxWait ");
+
+       if (kcm->tx_wait_more)
+               seq_puts(seq, "WMore ");
+
+       if (kcm->rx_wait)
+               seq_puts(seq, "RxWait ");
+
+       seq_puts(seq, "\n");
+}
+
+static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
+                            int i, int *len)
+{
+       seq_printf(seq,
+                  "   psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
+                  psock->index,
+                  psock->stats.rx_msgs,
+                  psock->stats.rx_bytes,
+                  psock->stats.tx_msgs,
+                  psock->stats.tx_bytes,
+                  psock->sk->sk_receive_queue.qlen,
+                  atomic_read(&psock->sk->sk_rmem_alloc),
+                  psock->sk->sk_write_queue.qlen,
+                  atomic_read(&psock->sk->sk_wmem_alloc));
+
+       if (psock->done)
+               seq_puts(seq, "Done ");
+
+       if (psock->tx_stopped)
+               seq_puts(seq, "TxStop ");
+
+       if (psock->rx_stopped)
+               seq_puts(seq, "RxStop ");
+
+       if (psock->tx_kcm)
+               seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
+
+       if (psock->ready_rx_msg)
+               seq_puts(seq, "RdyRx ");
+
+       seq_puts(seq, "\n");
+}
+
+static void
+kcm_format_mux(struct kcm_mux *mux, loff_t idx, struct seq_file *seq)
+{
+       int i, len;
+       struct kcm_sock *kcm;
+       struct kcm_psock *psock;
+
+       /* mux information */
+       seq_printf(seq,
+                  "%-6s%-8s %-10llu %-16llu %-10llu %-16llu %-8s %-8s %-8s %-8s ",
+                  "mux", "",
+                  mux->stats.rx_msgs,
+                  mux->stats.rx_bytes,
+                  mux->stats.tx_msgs,
+                  mux->stats.tx_bytes,
+                  "-", "-", "-", "-");
+
+       seq_printf(seq, "KCMs: %d, Psocks %d\n",
+                  mux->kcm_socks_cnt, mux->psocks_cnt);
+
+       /* kcm sock information */
+       i = 0;
+       spin_lock_bh(&mux->lock);
+       list_for_each_entry(kcm, &mux->kcm_socks, kcm_sock_list) {
+               kcm_format_sock(kcm, seq, i, &len);
+               i++;
+       }
+       i = 0;
+       list_for_each_entry(psock, &mux->psocks, psock_list) {
+               kcm_format_psock(psock, seq, i, &len);
+               i++;
+       }
+       spin_unlock_bh(&mux->lock);
+}
+
+static int kcm_seq_show(struct seq_file *seq, void *v)
+{
+       struct kcm_proc_mux_state *mux_state;
+
+       mux_state = seq->private;
+       if (v == SEQ_START_TOKEN) {
+               mux_state->idx = 0;
+               kcm_format_mux_header(seq);
+       } else {
+               kcm_format_mux(v, mux_state->idx, seq);
+               mux_state->idx++;
+       }
+       return 0;
+}
+
+static const struct file_operations kcm_seq_fops = {
+       .owner          = THIS_MODULE,
+       .open           = kcm_seq_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+static struct kcm_seq_muxinfo kcm_seq_muxinfo = {
+       .name           = "kcm",
+       .seq_fops       = &kcm_seq_fops,
+       .seq_ops        = {
+               .show   = kcm_seq_show,
+               .start  = kcm_seq_start,
+               .next   = kcm_seq_next,
+               .stop   = kcm_seq_stop,
+       }
+};
+
+static int kcm_proc_register(struct net *net, struct kcm_seq_muxinfo *muxinfo)
+{
+       struct proc_dir_entry *p;
+       int rc = 0;
+
+       p = proc_create_data(muxinfo->name, S_IRUGO, net->proc_net,
+                            muxinfo->seq_fops, muxinfo);
+       if (!p)
+               rc = -ENOMEM;
+       return rc;
+}
+EXPORT_SYMBOL(kcm_proc_register);
+
+static void kcm_proc_unregister(struct net *net,
+                               struct kcm_seq_muxinfo *muxinfo)
+{
+       remove_proc_entry(muxinfo->name, net->proc_net);
+}
+EXPORT_SYMBOL(kcm_proc_unregister);
+
+static int kcm_stats_seq_show(struct seq_file *seq, void *v)
+{
+       struct kcm_psock_stats psock_stats;
+       struct kcm_mux_stats mux_stats;
+       struct kcm_mux *mux;
+       struct kcm_psock *psock;
+       struct net *net = seq->private;
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       memset(&mux_stats, 0, sizeof(mux_stats));
+       memset(&psock_stats, 0, sizeof(psock_stats));
+
+       mutex_lock(&knet->mutex);
+
+       aggregate_mux_stats(&knet->aggregate_mux_stats, &mux_stats);
+       aggregate_psock_stats(&knet->aggregate_psock_stats,
+                             &psock_stats);
+
+       list_for_each_entry_rcu(mux, &knet->mux_list, kcm_mux_list) {
+               spin_lock_bh(&mux->lock);
+               aggregate_mux_stats(&mux->stats, &mux_stats);
+               aggregate_psock_stats(&mux->aggregate_psock_stats,
+                                     &psock_stats);
+               list_for_each_entry(psock, &mux->psocks, psock_list)
+                       aggregate_psock_stats(&psock->stats, &psock_stats);
+               spin_unlock_bh(&mux->lock);
+       }
+
+       mutex_unlock(&knet->mutex);
+
+       seq_printf(seq,
+                  "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s\n",
+                  "MUX",
+                  "RX-Msgs",
+                  "RX-Bytes",
+                  "TX-Msgs",
+                  "TX-Bytes",
+                  "TX-Retries",
+                  "Attach",
+                  "Unattach",
+                  "UnattchRsvd",
+                  "RX-RdyDrops");
+
+       seq_printf(seq,
+                  "%-8s %-10llu %-16llu %-10llu %-16llu %-10u %-10u %-10u %-10u %-10u\n",
+                  "",
+                  mux_stats.rx_msgs,
+                  mux_stats.rx_bytes,
+                  mux_stats.tx_msgs,
+                  mux_stats.tx_bytes,
+                  mux_stats.tx_retries,
+                  mux_stats.psock_attach,
+                  mux_stats.psock_unattach_rsvd,
+                  mux_stats.psock_unattach,
+                  mux_stats.rx_ready_drops);
+
+       seq_printf(seq,
+                  "%-8s %-10s %-16s %-10s %-16s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s\n",
+                  "Psock",
+                  "RX-Msgs",
+                  "RX-Bytes",
+                  "TX-Msgs",
+                  "TX-Bytes",
+                  "Reserved",
+                  "Unreserved",
+                  "RX-Aborts",
+                  "RX-MemFail",
+                  "RX-NeedMor",
+                  "RX-BadLen",
+                  "RX-TooBig",
+                  "RX-Timeout",
+                  "TX-Aborts");
+
+       seq_printf(seq,
+                  "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
+                  "",
+                  psock_stats.rx_msgs,
+                  psock_stats.rx_bytes,
+                  psock_stats.tx_msgs,
+                  psock_stats.tx_bytes,
+                  psock_stats.reserved,
+                  psock_stats.unreserved,
+                  psock_stats.rx_aborts,
+                  psock_stats.rx_mem_fail,
+                  psock_stats.rx_need_more_hdr,
+                  psock_stats.rx_bad_hdr_len,
+                  psock_stats.rx_msg_too_big,
+                  psock_stats.rx_msg_timeouts,
+                  psock_stats.tx_aborts);
+
+       return 0;
+}
+
+static int kcm_stats_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open_net(inode, file, kcm_stats_seq_show);
+}
+
+static const struct file_operations kcm_stats_seq_fops = {
+       .owner   = THIS_MODULE,
+       .open    = kcm_stats_seq_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release_net,
+};
+
+static int kcm_proc_init_net(struct net *net)
+{
+       int err;
+
+       if (!proc_create("kcm_stats", S_IRUGO, net->proc_net,
+                        &kcm_stats_seq_fops)) {
+               err = -ENOMEM;
+               goto out_kcm_stats;
+       }
+
+       err = kcm_proc_register(net, &kcm_seq_muxinfo);
+       if (err)
+               goto out_kcm;
+
+       return 0;
+
+out_kcm:
+       remove_proc_entry("kcm_stats", net->proc_net);
+out_kcm_stats:
+       return err;
+}
+
+static void kcm_proc_exit_net(struct net *net)
+{
+       kcm_proc_unregister(net, &kcm_seq_muxinfo);
+       remove_proc_entry("kcm_stats", net->proc_net);
+}
+
+static struct pernet_operations kcm_net_ops = {
+       .init = kcm_proc_init_net,
+       .exit = kcm_proc_exit_net,
+};
+
+int __init kcm_proc_init(void)
+{
+       return register_pernet_subsys(&kcm_net_ops);
+}
+
+void __exit kcm_proc_exit(void)
+{
+       unregister_pernet_subsys(&kcm_net_ops);
+}
+
+#endif /* CONFIG_PROC_FS */
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
new file mode 100644 (file)
index 0000000..40662d7
--- /dev/null
@@ -0,0 +1,2409 @@
+#include <linux/bpf.h>
+#include <linux/errno.h>
+#include <linux/errqueue.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/rculist.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <net/kcm.h>
+#include <net/netns/generic.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <uapi/linux/kcm.h>
+
+unsigned int kcm_net_id;
+
+static struct kmem_cache *kcm_psockp __read_mostly;
+static struct kmem_cache *kcm_muxp __read_mostly;
+static struct workqueue_struct *kcm_wq;
+
+static inline struct kcm_sock *kcm_sk(const struct sock *sk)
+{
+       return (struct kcm_sock *)sk;
+}
+
+static inline struct kcm_tx_msg *kcm_tx_msg(struct sk_buff *skb)
+{
+       return (struct kcm_tx_msg *)skb->cb;
+}
+
+static inline struct kcm_rx_msg *kcm_rx_msg(struct sk_buff *skb)
+{
+       return (struct kcm_rx_msg *)((void *)skb->cb +
+                                    offsetof(struct qdisc_skb_cb, data));
+}
+
+static void report_csk_error(struct sock *csk, int err)
+{
+       csk->sk_err = EPIPE;
+       csk->sk_error_report(csk);
+}
+
+/* Callback lock held */
+static void kcm_abort_rx_psock(struct kcm_psock *psock, int err,
+                              struct sk_buff *skb)
+{
+       struct sock *csk = psock->sk;
+
+       /* Unrecoverable error in receive */
+
+       del_timer(&psock->rx_msg_timer);
+
+       if (psock->rx_stopped)
+               return;
+
+       psock->rx_stopped = 1;
+       KCM_STATS_INCR(psock->stats.rx_aborts);
+
+       /* Report an error on the lower socket */
+       report_csk_error(csk, err);
+}
+
+static void kcm_abort_tx_psock(struct kcm_psock *psock, int err,
+                              bool wakeup_kcm)
+{
+       struct sock *csk = psock->sk;
+       struct kcm_mux *mux = psock->mux;
+
+       /* Unrecoverable error in transmit */
+
+       spin_lock_bh(&mux->lock);
+
+       if (psock->tx_stopped) {
+               spin_unlock_bh(&mux->lock);
+               return;
+       }
+
+       psock->tx_stopped = 1;
+       KCM_STATS_INCR(psock->stats.tx_aborts);
+
+       if (!psock->tx_kcm) {
+               /* Take off psocks_avail list */
+               list_del(&psock->psock_avail_list);
+       } else if (wakeup_kcm) {
+               /* In this case psock is being aborted while outside of
+                * write_msgs and psock is reserved. Schedule tx_work
+                * to handle the failure there. Need to commit tx_stopped
+                * before queuing work.
+                */
+               smp_mb();
+
+               queue_work(kcm_wq, &psock->tx_kcm->tx_work);
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+       /* Report error on lower socket */
+       report_csk_error(csk, err);
+}
+
+/* RX mux lock held. */
+static void kcm_update_rx_mux_stats(struct kcm_mux *mux,
+                                   struct kcm_psock *psock)
+{
+       KCM_STATS_ADD(mux->stats.rx_bytes,
+                     psock->stats.rx_bytes - psock->saved_rx_bytes);
+       mux->stats.rx_msgs +=
+               psock->stats.rx_msgs - psock->saved_rx_msgs;
+       psock->saved_rx_msgs = psock->stats.rx_msgs;
+       psock->saved_rx_bytes = psock->stats.rx_bytes;
+}
+
+static void kcm_update_tx_mux_stats(struct kcm_mux *mux,
+                                   struct kcm_psock *psock)
+{
+       KCM_STATS_ADD(mux->stats.tx_bytes,
+                     psock->stats.tx_bytes - psock->saved_tx_bytes);
+       mux->stats.tx_msgs +=
+               psock->stats.tx_msgs - psock->saved_tx_msgs;
+       psock->saved_tx_msgs = psock->stats.tx_msgs;
+       psock->saved_tx_bytes = psock->stats.tx_bytes;
+}
+
+static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+
+/* KCM is ready to receive messages on its queue-- either the KCM is new or
+ * has become unblocked after being blocked on full socket buffer. Queue any
+ * pending ready messages on a psock. RX mux lock held.
+ */
+static void kcm_rcv_ready(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+       struct sk_buff *skb;
+
+       if (unlikely(kcm->rx_wait || kcm->rx_psock || kcm->rx_disabled))
+               return;
+
+       while (unlikely((skb = __skb_dequeue(&mux->rx_hold_queue)))) {
+               if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
+                       /* Assuming buffer limit has been reached */
+                       skb_queue_head(&mux->rx_hold_queue, skb);
+                       WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
+                       return;
+               }
+       }
+
+       while (!list_empty(&mux->psocks_ready)) {
+               psock = list_first_entry(&mux->psocks_ready, struct kcm_psock,
+                                        psock_ready_list);
+
+               if (kcm_queue_rcv_skb(&kcm->sk, psock->ready_rx_msg)) {
+                       /* Assuming buffer limit has been reached */
+                       WARN_ON(!sk_rmem_alloc_get(&kcm->sk));
+                       return;
+               }
+
+               /* Consumed the ready message on the psock. Schedule rx_work to
+                * get more messages.
+                */
+               list_del(&psock->psock_ready_list);
+               psock->ready_rx_msg = NULL;
+
+               /* Commit clearing of ready_rx_msg for queuing work */
+               smp_mb();
+
+               queue_work(kcm_wq, &psock->rx_work);
+       }
+
+       /* Buffer limit is okay now, add to ready list */
+       list_add_tail(&kcm->wait_rx_list,
+                     &kcm->mux->kcm_rx_waiters);
+       kcm->rx_wait = true;
+}
+
+static void kcm_rfree(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       struct kcm_mux *mux = kcm->mux;
+       unsigned int len = skb->truesize;
+
+       sk_mem_uncharge(sk, len);
+       atomic_sub(len, &sk->sk_rmem_alloc);
+
+       /* For reading rx_wait and rx_psock without holding lock */
+       smp_mb__after_atomic();
+
+       if (!kcm->rx_wait && !kcm->rx_psock &&
+           sk_rmem_alloc_get(sk) < sk->sk_rcvlowat) {
+               spin_lock_bh(&mux->rx_lock);
+               kcm_rcv_ready(kcm);
+               spin_unlock_bh(&mux->rx_lock);
+       }
+}
+
+static int kcm_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       struct sk_buff_head *list = &sk->sk_receive_queue;
+
+       if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
+               return -ENOMEM;
+
+       if (!sk_rmem_schedule(sk, skb, skb->truesize))
+               return -ENOBUFS;
+
+       skb->dev = NULL;
+
+       skb_orphan(skb);
+       skb->sk = sk;
+       skb->destructor = kcm_rfree;
+       atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+       sk_mem_charge(sk, skb->truesize);
+
+       skb_queue_tail(list, skb);
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_data_ready(sk);
+
+       return 0;
+}
+
+/* Requeue received messages for a kcm socket to other kcm sockets. This is
+ * called with a kcm socket is receive disabled.
+ * RX mux lock held.
+ */
+static void requeue_rx_msgs(struct kcm_mux *mux, struct sk_buff_head *head)
+{
+       struct sk_buff *skb;
+       struct kcm_sock *kcm;
+
+       while ((skb = __skb_dequeue(head))) {
+               /* Reset destructor to avoid calling kcm_rcv_ready */
+               skb->destructor = sock_rfree;
+               skb_orphan(skb);
+try_again:
+               if (list_empty(&mux->kcm_rx_waiters)) {
+                       skb_queue_tail(&mux->rx_hold_queue, skb);
+                       continue;
+               }
+
+               kcm = list_first_entry(&mux->kcm_rx_waiters,
+                                      struct kcm_sock, wait_rx_list);
+
+               if (kcm_queue_rcv_skb(&kcm->sk, skb)) {
+                       /* Should mean socket buffer full */
+                       list_del(&kcm->wait_rx_list);
+                       kcm->rx_wait = false;
+
+                       /* Commit rx_wait to read in kcm_free */
+                       smp_wmb();
+
+                       goto try_again;
+               }
+       }
+}
+
+/* Lower sock lock held */
+static struct kcm_sock *reserve_rx_kcm(struct kcm_psock *psock,
+                                      struct sk_buff *head)
+{
+       struct kcm_mux *mux = psock->mux;
+       struct kcm_sock *kcm;
+
+       WARN_ON(psock->ready_rx_msg);
+
+       if (psock->rx_kcm)
+               return psock->rx_kcm;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       if (psock->rx_kcm) {
+               spin_unlock_bh(&mux->rx_lock);
+               return psock->rx_kcm;
+       }
+
+       kcm_update_rx_mux_stats(mux, psock);
+
+       if (list_empty(&mux->kcm_rx_waiters)) {
+               psock->ready_rx_msg = head;
+               list_add_tail(&psock->psock_ready_list,
+                             &mux->psocks_ready);
+               spin_unlock_bh(&mux->rx_lock);
+               return NULL;
+       }
+
+       kcm = list_first_entry(&mux->kcm_rx_waiters,
+                              struct kcm_sock, wait_rx_list);
+       list_del(&kcm->wait_rx_list);
+       kcm->rx_wait = false;
+
+       psock->rx_kcm = kcm;
+       kcm->rx_psock = psock;
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       return kcm;
+}
+
+static void kcm_done(struct kcm_sock *kcm);
+
+static void kcm_done_work(struct work_struct *w)
+{
+       kcm_done(container_of(w, struct kcm_sock, done_work));
+}
+
+/* Lower sock held */
+static void unreserve_rx_kcm(struct kcm_psock *psock,
+                            bool rcv_ready)
+{
+       struct kcm_sock *kcm = psock->rx_kcm;
+       struct kcm_mux *mux = psock->mux;
+
+       if (!kcm)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       psock->rx_kcm = NULL;
+       kcm->rx_psock = NULL;
+
+       /* Commit kcm->rx_psock before sk_rmem_alloc_get to sync with
+        * kcm_rfree
+        */
+       smp_mb();
+
+       if (unlikely(kcm->done)) {
+               spin_unlock_bh(&mux->rx_lock);
+
+               /* Need to run kcm_done in a task since we need to qcquire
+                * callback locks which may already be held here.
+                */
+               INIT_WORK(&kcm->done_work, kcm_done_work);
+               schedule_work(&kcm->done_work);
+               return;
+       }
+
+       if (unlikely(kcm->rx_disabled)) {
+               requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
+       } else if (rcv_ready || unlikely(!sk_rmem_alloc_get(&kcm->sk))) {
+               /* Check for degenerative race with rx_wait that all
+                * data was dequeued (accounted for in kcm_rfree).
+                */
+               kcm_rcv_ready(kcm);
+       }
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+static void kcm_start_rx_timer(struct kcm_psock *psock)
+{
+       if (psock->sk->sk_rcvtimeo)
+               mod_timer(&psock->rx_msg_timer, psock->sk->sk_rcvtimeo);
+}
+
+/* Macro to invoke filter function. */
+#define KCM_RUN_FILTER(prog, ctx) \
+       (*prog->bpf_func)(ctx, prog->insnsi)
+
+/* Lower socket lock held */
+static int kcm_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
+                       unsigned int orig_offset, size_t orig_len)
+{
+       struct kcm_psock *psock = (struct kcm_psock *)desc->arg.data;
+       struct kcm_rx_msg *rxm;
+       struct kcm_sock *kcm;
+       struct sk_buff *head, *skb;
+       size_t eaten = 0, cand_len;
+       ssize_t extra;
+       int err;
+       bool cloned_orig = false;
+
+       if (psock->ready_rx_msg)
+               return 0;
+
+       head = psock->rx_skb_head;
+       if (head) {
+               /* Message already in progress */
+
+               rxm = kcm_rx_msg(head);
+               if (unlikely(rxm->early_eaten)) {
+                       /* Already some number of bytes on the receive sock
+                        * data saved in rx_skb_head, just indicate they
+                        * are consumed.
+                        */
+                       eaten = orig_len <= rxm->early_eaten ?
+                               orig_len : rxm->early_eaten;
+                       rxm->early_eaten -= eaten;
+
+                       return eaten;
+               }
+
+               if (unlikely(orig_offset)) {
+                       /* Getting data with a non-zero offset when a message is
+                        * in progress is not expected. If it does happen, we
+                        * need to clone and pull since we can't deal with
+                        * offsets in the skbs for a message expect in the head.
+                        */
+                       orig_skb = skb_clone(orig_skb, GFP_ATOMIC);
+                       if (!orig_skb) {
+                               KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                               desc->error = -ENOMEM;
+                               return 0;
+                       }
+                       if (!pskb_pull(orig_skb, orig_offset)) {
+                               KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                               kfree_skb(orig_skb);
+                               desc->error = -ENOMEM;
+                               return 0;
+                       }
+                       cloned_orig = true;
+                       orig_offset = 0;
+               }
+
+               if (!psock->rx_skb_nextp) {
+                       /* We are going to append to the frags_list of head.
+                        * Need to unshare the frag_list.
+                        */
+                       err = skb_unclone(head, GFP_ATOMIC);
+                       if (err) {
+                               KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                               desc->error = err;
+                               return 0;
+                       }
+
+                       if (unlikely(skb_shinfo(head)->frag_list)) {
+                               /* We can't append to an sk_buff that already
+                                * has a frag_list. We create a new head, point
+                                * the frag_list of that to the old head, and
+                                * then are able to use the old head->next for
+                                * appending to the message.
+                                */
+                               if (WARN_ON(head->next)) {
+                                       desc->error = -EINVAL;
+                                       return 0;
+                               }
+
+                               skb = alloc_skb(0, GFP_ATOMIC);
+                               if (!skb) {
+                                       KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                                       desc->error = -ENOMEM;
+                                       return 0;
+                               }
+                               skb->len = head->len;
+                               skb->data_len = head->len;
+                               skb->truesize = head->truesize;
+                               *kcm_rx_msg(skb) = *kcm_rx_msg(head);
+                               psock->rx_skb_nextp = &head->next;
+                               skb_shinfo(skb)->frag_list = head;
+                               psock->rx_skb_head = skb;
+                               head = skb;
+                       } else {
+                               psock->rx_skb_nextp =
+                                   &skb_shinfo(head)->frag_list;
+                       }
+               }
+       }
+
+       while (eaten < orig_len) {
+               /* Always clone since we will consume something */
+               skb = skb_clone(orig_skb, GFP_ATOMIC);
+               if (!skb) {
+                       KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                       desc->error = -ENOMEM;
+                       break;
+               }
+
+               cand_len = orig_len - eaten;
+
+               head = psock->rx_skb_head;
+               if (!head) {
+                       head = skb;
+                       psock->rx_skb_head = head;
+                       /* Will set rx_skb_nextp on next packet if needed */
+                       psock->rx_skb_nextp = NULL;
+                       rxm = kcm_rx_msg(head);
+                       memset(rxm, 0, sizeof(*rxm));
+                       rxm->offset = orig_offset + eaten;
+               } else {
+                       /* Unclone since we may be appending to an skb that we
+                        * already share a frag_list with.
+                        */
+                       err = skb_unclone(skb, GFP_ATOMIC);
+                       if (err) {
+                               KCM_STATS_INCR(psock->stats.rx_mem_fail);
+                               desc->error = err;
+                               break;
+                       }
+
+                       rxm = kcm_rx_msg(head);
+                       *psock->rx_skb_nextp = skb;
+                       psock->rx_skb_nextp = &skb->next;
+                       head->data_len += skb->len;
+                       head->len += skb->len;
+                       head->truesize += skb->truesize;
+               }
+
+               if (!rxm->full_len) {
+                       ssize_t len;
+
+                       len = KCM_RUN_FILTER(psock->bpf_prog, head);
+
+                       if (!len) {
+                               /* Need more header to determine length */
+                               if (!rxm->accum_len) {
+                                       /* Start RX timer for new message */
+                                       kcm_start_rx_timer(psock);
+                               }
+                               rxm->accum_len += cand_len;
+                               eaten += cand_len;
+                               KCM_STATS_INCR(psock->stats.rx_need_more_hdr);
+                               WARN_ON(eaten != orig_len);
+                               break;
+                       } else if (len > psock->sk->sk_rcvbuf) {
+                               /* Message length exceeds maximum allowed */
+                               KCM_STATS_INCR(psock->stats.rx_msg_too_big);
+                               desc->error = -EMSGSIZE;
+                               psock->rx_skb_head = NULL;
+                               kcm_abort_rx_psock(psock, EMSGSIZE, head);
+                               break;
+                       } else if (len <= (ssize_t)head->len -
+                                         skb->len - rxm->offset) {
+                               /* Length must be into new skb (and also
+                                * greater than zero)
+                                */
+                               KCM_STATS_INCR(psock->stats.rx_bad_hdr_len);
+                               desc->error = -EPROTO;
+                               psock->rx_skb_head = NULL;
+                               kcm_abort_rx_psock(psock, EPROTO, head);
+                               break;
+                       }
+
+                       rxm->full_len = len;
+               }
+
+               extra = (ssize_t)(rxm->accum_len + cand_len) - rxm->full_len;
+
+               if (extra < 0) {
+                       /* Message not complete yet. */
+                       if (rxm->full_len - rxm->accum_len >
+                           tcp_inq(psock->sk)) {
+                               /* Don't have the whole messages in the socket
+                                * buffer. Set psock->rx_need_bytes to wait for
+                                * the rest of the message. Also, set "early
+                                * eaten" since we've already buffered the skb
+                                * but don't consume yet per tcp_read_sock.
+                                */
+
+                               if (!rxm->accum_len) {
+                                       /* Start RX timer for new message */
+                                       kcm_start_rx_timer(psock);
+                               }
+
+                               psock->rx_need_bytes = rxm->full_len -
+                                                      rxm->accum_len;
+                               rxm->accum_len += cand_len;
+                               rxm->early_eaten = cand_len;
+                               KCM_STATS_ADD(psock->stats.rx_bytes, cand_len);
+                               desc->count = 0; /* Stop reading socket */
+                               break;
+                       }
+                       rxm->accum_len += cand_len;
+                       eaten += cand_len;
+                       WARN_ON(eaten != orig_len);
+                       break;
+               }
+
+               /* Positive extra indicates ore bytes than needed for the
+                * message
+                */
+
+               WARN_ON(extra > cand_len);
+
+               eaten += (cand_len - extra);
+
+               /* Hurray, we have a new message! */
+               del_timer(&psock->rx_msg_timer);
+               psock->rx_skb_head = NULL;
+               KCM_STATS_INCR(psock->stats.rx_msgs);
+
+try_queue:
+               kcm = reserve_rx_kcm(psock, head);
+               if (!kcm) {
+                       /* Unable to reserve a KCM, message is held in psock. */
+                       break;
+               }
+
+               if (kcm_queue_rcv_skb(&kcm->sk, head)) {
+                       /* Should mean socket buffer full */
+                       unreserve_rx_kcm(psock, false);
+                       goto try_queue;
+               }
+       }
+
+       if (cloned_orig)
+               kfree_skb(orig_skb);
+
+       KCM_STATS_ADD(psock->stats.rx_bytes, eaten);
+
+       return eaten;
+}
+
+/* Called with lock held on lower socket */
+static int psock_tcp_read_sock(struct kcm_psock *psock)
+{
+       read_descriptor_t desc;
+
+       desc.arg.data = psock;
+       desc.error = 0;
+       desc.count = 1; /* give more than one skb per call */
+
+       /* sk should be locked here, so okay to do tcp_read_sock */
+       tcp_read_sock(psock->sk, &desc, kcm_tcp_recv);
+
+       unreserve_rx_kcm(psock, true);
+
+       return desc.error;
+}
+
+/* Lower sock lock held */
+static void psock_tcp_data_ready(struct sock *sk)
+{
+       struct kcm_psock *psock;
+
+       read_lock_bh(&sk->sk_callback_lock);
+
+       psock = (struct kcm_psock *)sk->sk_user_data;
+       if (unlikely(!psock || psock->rx_stopped))
+               goto out;
+
+       if (psock->ready_rx_msg)
+               goto out;
+
+       if (psock->rx_need_bytes) {
+               if (tcp_inq(sk) >= psock->rx_need_bytes)
+                       psock->rx_need_bytes = 0;
+               else
+                       goto out;
+       }
+
+       if (psock_tcp_read_sock(psock) == -ENOMEM)
+               queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0);
+
+out:
+       read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void do_psock_rx_work(struct kcm_psock *psock)
+{
+       read_descriptor_t rd_desc;
+       struct sock *csk = psock->sk;
+
+       /* We need the read lock to synchronize with psock_tcp_data_ready. We
+        * need the socket lock for calling tcp_read_sock.
+        */
+       lock_sock(csk);
+       read_lock_bh(&csk->sk_callback_lock);
+
+       if (unlikely(csk->sk_user_data != psock))
+               goto out;
+
+       if (unlikely(psock->rx_stopped))
+               goto out;
+
+       if (psock->ready_rx_msg)
+               goto out;
+
+       rd_desc.arg.data = psock;
+
+       if (psock_tcp_read_sock(psock) == -ENOMEM)
+               queue_delayed_work(kcm_wq, &psock->rx_delayed_work, 0);
+
+out:
+       read_unlock_bh(&csk->sk_callback_lock);
+       release_sock(csk);
+}
+
+static void psock_rx_work(struct work_struct *w)
+{
+       do_psock_rx_work(container_of(w, struct kcm_psock, rx_work));
+}
+
+static void psock_rx_delayed_work(struct work_struct *w)
+{
+       do_psock_rx_work(container_of(w, struct kcm_psock,
+                                     rx_delayed_work.work));
+}
+
+static void psock_tcp_state_change(struct sock *sk)
+{
+       /* TCP only does a POLLIN for a half close. Do a POLLHUP here
+        * since application will normally not poll with POLLIN
+        * on the TCP sockets.
+        */
+
+       report_csk_error(sk, EPIPE);
+}
+
+static void psock_tcp_write_space(struct sock *sk)
+{
+       struct kcm_psock *psock;
+       struct kcm_mux *mux;
+       struct kcm_sock *kcm;
+
+       read_lock_bh(&sk->sk_callback_lock);
+
+       psock = (struct kcm_psock *)sk->sk_user_data;
+       if (unlikely(!psock))
+               goto out;
+
+       mux = psock->mux;
+
+       spin_lock_bh(&mux->lock);
+
+       /* Check if the socket is reserved so someone is waiting for sending. */
+       kcm = psock->tx_kcm;
+       if (kcm)
+               queue_work(kcm_wq, &kcm->tx_work);
+
+       spin_unlock_bh(&mux->lock);
+out:
+       read_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void unreserve_psock(struct kcm_sock *kcm);
+
+/* kcm sock is locked. */
+static struct kcm_psock *reserve_psock(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+
+       psock = kcm->tx_psock;
+
+       smp_rmb(); /* Must read tx_psock before tx_wait */
+
+       if (psock) {
+               WARN_ON(kcm->tx_wait);
+               if (unlikely(psock->tx_stopped))
+                       unreserve_psock(kcm);
+               else
+                       return kcm->tx_psock;
+       }
+
+       spin_lock_bh(&mux->lock);
+
+       /* Check again under lock to see if psock was reserved for this
+        * psock via psock_unreserve.
+        */
+       psock = kcm->tx_psock;
+       if (unlikely(psock)) {
+               WARN_ON(kcm->tx_wait);
+               spin_unlock_bh(&mux->lock);
+               return kcm->tx_psock;
+       }
+
+       if (!list_empty(&mux->psocks_avail)) {
+               psock = list_first_entry(&mux->psocks_avail,
+                                        struct kcm_psock,
+                                        psock_avail_list);
+               list_del(&psock->psock_avail_list);
+               if (kcm->tx_wait) {
+                       list_del(&kcm->wait_psock_list);
+                       kcm->tx_wait = false;
+               }
+               kcm->tx_psock = psock;
+               psock->tx_kcm = kcm;
+               KCM_STATS_INCR(psock->stats.reserved);
+       } else if (!kcm->tx_wait) {
+               list_add_tail(&kcm->wait_psock_list,
+                             &mux->kcm_tx_waiters);
+               kcm->tx_wait = true;
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+       return psock;
+}
+
+/* mux lock held */
+static void psock_now_avail(struct kcm_psock *psock)
+{
+       struct kcm_mux *mux = psock->mux;
+       struct kcm_sock *kcm;
+
+       if (list_empty(&mux->kcm_tx_waiters)) {
+               list_add_tail(&psock->psock_avail_list,
+                             &mux->psocks_avail);
+       } else {
+               kcm = list_first_entry(&mux->kcm_tx_waiters,
+                                      struct kcm_sock,
+                                      wait_psock_list);
+               list_del(&kcm->wait_psock_list);
+               kcm->tx_wait = false;
+               psock->tx_kcm = kcm;
+
+               /* Commit before changing tx_psock since that is read in
+                * reserve_psock before queuing work.
+                */
+               smp_mb();
+
+               kcm->tx_psock = psock;
+               KCM_STATS_INCR(psock->stats.reserved);
+               queue_work(kcm_wq, &kcm->tx_work);
+       }
+}
+
+/* kcm sock is locked. */
+static void unreserve_psock(struct kcm_sock *kcm)
+{
+       struct kcm_psock *psock;
+       struct kcm_mux *mux = kcm->mux;
+
+       spin_lock_bh(&mux->lock);
+
+       psock = kcm->tx_psock;
+
+       if (WARN_ON(!psock)) {
+               spin_unlock_bh(&mux->lock);
+               return;
+       }
+
+       smp_rmb(); /* Read tx_psock before tx_wait */
+
+       kcm_update_tx_mux_stats(mux, psock);
+
+       WARN_ON(kcm->tx_wait);
+
+       kcm->tx_psock = NULL;
+       psock->tx_kcm = NULL;
+       KCM_STATS_INCR(psock->stats.unreserved);
+
+       if (unlikely(psock->tx_stopped)) {
+               if (psock->done) {
+                       /* Deferred free */
+                       list_del(&psock->psock_list);
+                       mux->psocks_cnt--;
+                       sock_put(psock->sk);
+                       fput(psock->sk->sk_socket->file);
+                       kmem_cache_free(kcm_psockp, psock);
+               }
+
+               /* Don't put back on available list */
+
+               spin_unlock_bh(&mux->lock);
+
+               return;
+       }
+
+       psock_now_avail(psock);
+
+       spin_unlock_bh(&mux->lock);
+}
+
+static void kcm_report_tx_retry(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+
+       spin_lock_bh(&mux->lock);
+       KCM_STATS_INCR(mux->stats.tx_retries);
+       spin_unlock_bh(&mux->lock);
+}
+
+/* Write any messages ready on the kcm socket.  Called with kcm sock lock
+ * held.  Return bytes actually sent or error.
+ */
+static int kcm_write_msgs(struct kcm_sock *kcm)
+{
+       struct sock *sk = &kcm->sk;
+       struct kcm_psock *psock;
+       struct sk_buff *skb, *head;
+       struct kcm_tx_msg *txm;
+       unsigned short fragidx, frag_offset;
+       unsigned int sent, total_sent = 0;
+       int ret = 0;
+
+       kcm->tx_wait_more = false;
+       psock = kcm->tx_psock;
+       if (unlikely(psock && psock->tx_stopped)) {
+               /* A reserved psock was aborted asynchronously. Unreserve
+                * it and we'll retry the message.
+                */
+               unreserve_psock(kcm);
+               kcm_report_tx_retry(kcm);
+               if (skb_queue_empty(&sk->sk_write_queue))
+                       return 0;
+
+               kcm_tx_msg(skb_peek(&sk->sk_write_queue))->sent = 0;
+
+       } else if (skb_queue_empty(&sk->sk_write_queue)) {
+               return 0;
+       }
+
+       head = skb_peek(&sk->sk_write_queue);
+       txm = kcm_tx_msg(head);
+
+       if (txm->sent) {
+               /* Send of first skbuff in queue already in progress */
+               if (WARN_ON(!psock)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               sent = txm->sent;
+               frag_offset = txm->frag_offset;
+               fragidx = txm->fragidx;
+               skb = txm->frag_skb;
+
+               goto do_frag;
+       }
+
+try_again:
+       psock = reserve_psock(kcm);
+       if (!psock)
+               goto out;
+
+       do {
+               skb = head;
+               txm = kcm_tx_msg(head);
+               sent = 0;
+
+do_frag_list:
+               if (WARN_ON(!skb_shinfo(skb)->nr_frags)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags;
+                    fragidx++) {
+                       skb_frag_t *frag;
+
+                       frag_offset = 0;
+do_frag:
+                       frag = &skb_shinfo(skb)->frags[fragidx];
+                       if (WARN_ON(!frag->size)) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = kernel_sendpage(psock->sk->sk_socket,
+                                             frag->page.p,
+                                             frag->page_offset + frag_offset,
+                                             frag->size - frag_offset,
+                                             MSG_DONTWAIT);
+                       if (ret <= 0) {
+                               if (ret == -EAGAIN) {
+                                       /* Save state to try again when there's
+                                        * write space on the socket
+                                        */
+                                       txm->sent = sent;
+                                       txm->frag_offset = frag_offset;
+                                       txm->fragidx = fragidx;
+                                       txm->frag_skb = skb;
+
+                                       ret = 0;
+                                       goto out;
+                               }
+
+                               /* Hard failure in sending message, abort this
+                                * psock since it has lost framing
+                                * synchonization and retry sending the
+                                * message from the beginning.
+                                */
+                               kcm_abort_tx_psock(psock, ret ? -ret : EPIPE,
+                                                  true);
+                               unreserve_psock(kcm);
+
+                               txm->sent = 0;
+                               kcm_report_tx_retry(kcm);
+                               ret = 0;
+
+                               goto try_again;
+                       }
+
+                       sent += ret;
+                       frag_offset += ret;
+                       KCM_STATS_ADD(psock->stats.tx_bytes, ret);
+                       if (frag_offset < frag->size) {
+                               /* Not finished with this frag */
+                               goto do_frag;
+                       }
+               }
+
+               if (skb == head) {
+                       if (skb_has_frag_list(skb)) {
+                               skb = skb_shinfo(skb)->frag_list;
+                               goto do_frag_list;
+                       }
+               } else if (skb->next) {
+                       skb = skb->next;
+                       goto do_frag_list;
+               }
+
+               /* Successfully sent the whole packet, account for it. */
+               skb_dequeue(&sk->sk_write_queue);
+               kfree_skb(head);
+               sk->sk_wmem_queued -= sent;
+               total_sent += sent;
+               KCM_STATS_INCR(psock->stats.tx_msgs);
+       } while ((head = skb_peek(&sk->sk_write_queue)));
+out:
+       if (!head) {
+               /* Done with all queued messages. */
+               WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
+               unreserve_psock(kcm);
+       }
+
+       /* Check if write space is available */
+       sk->sk_write_space(sk);
+
+       return total_sent ? : ret;
+}
+
+static void kcm_tx_work(struct work_struct *w)
+{
+       struct kcm_sock *kcm = container_of(w, struct kcm_sock, tx_work);
+       struct sock *sk = &kcm->sk;
+       int err;
+
+       lock_sock(sk);
+
+       /* Primarily for SOCK_DGRAM sockets, also handle asynchronous tx
+        * aborts
+        */
+       err = kcm_write_msgs(kcm);
+       if (err < 0) {
+               /* Hard failure in write, report error on KCM socket */
+               pr_warn("KCM: Hard failure on kcm_write_msgs %d\n", err);
+               report_csk_error(&kcm->sk, -err);
+               goto out;
+       }
+
+       /* Primarily for SOCK_SEQPACKET sockets */
+       if (likely(sk->sk_socket) &&
+           test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
+               clear_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+               sk->sk_write_space(sk);
+       }
+
+out:
+       release_sock(sk);
+}
+
+static void kcm_push(struct kcm_sock *kcm)
+{
+       if (kcm->tx_wait_more)
+               kcm_write_msgs(kcm);
+}
+
+static ssize_t kcm_sendpage(struct socket *sock, struct page *page,
+                           int offset, size_t size, int flags)
+
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       struct sk_buff *skb = NULL, *head = NULL;
+       long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+       bool eor;
+       int err = 0;
+       int i;
+
+       if (flags & MSG_SENDPAGE_NOTLAST)
+               flags |= MSG_MORE;
+
+       /* No MSG_EOR from splice, only look at MSG_MORE */
+       eor = !(flags & MSG_MORE);
+
+       lock_sock(sk);
+
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
+
+       err = -EPIPE;
+       if (sk->sk_err)
+               goto out_error;
+
+       if (kcm->seq_skb) {
+               /* Previously opened message */
+               head = kcm->seq_skb;
+               skb = kcm_tx_msg(head)->last_skb;
+               i = skb_shinfo(skb)->nr_frags;
+
+               if (skb_can_coalesce(skb, i, page, offset)) {
+                       skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size);
+                       skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
+                       goto coalesced;
+               }
+
+               if (i >= MAX_SKB_FRAGS) {
+                       struct sk_buff *tskb;
+
+                       tskb = alloc_skb(0, sk->sk_allocation);
+                       while (!tskb) {
+                               kcm_push(kcm);
+                               err = sk_stream_wait_memory(sk, &timeo);
+                               if (err)
+                                       goto out_error;
+                       }
+
+                       if (head == skb)
+                               skb_shinfo(head)->frag_list = tskb;
+                       else
+                               skb->next = tskb;
+
+                       skb = tskb;
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       i = 0;
+               }
+       } else {
+               /* Call the sk_stream functions to manage the sndbuf mem. */
+               if (!sk_stream_memory_free(sk)) {
+                       kcm_push(kcm);
+                       set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+                       err = sk_stream_wait_memory(sk, &timeo);
+                       if (err)
+                               goto out_error;
+               }
+
+               head = alloc_skb(0, sk->sk_allocation);
+               while (!head) {
+                       kcm_push(kcm);
+                       err = sk_stream_wait_memory(sk, &timeo);
+                       if (err)
+                               goto out_error;
+               }
+
+               skb = head;
+               i = 0;
+       }
+
+       get_page(page);
+       skb_fill_page_desc(skb, i, page, offset, size);
+       skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
+
+coalesced:
+       skb->len += size;
+       skb->data_len += size;
+       skb->truesize += size;
+       sk->sk_wmem_queued += size;
+       sk_mem_charge(sk, size);
+
+       if (head != skb) {
+               head->len += size;
+               head->data_len += size;
+               head->truesize += size;
+       }
+
+       if (eor) {
+               bool not_busy = skb_queue_empty(&sk->sk_write_queue);
+
+               /* Message complete, queue it on send buffer */
+               __skb_queue_tail(&sk->sk_write_queue, head);
+               kcm->seq_skb = NULL;
+               KCM_STATS_INCR(kcm->stats.tx_msgs);
+
+               if (flags & MSG_BATCH) {
+                       kcm->tx_wait_more = true;
+               } else if (kcm->tx_wait_more || not_busy) {
+                       err = kcm_write_msgs(kcm);
+                       if (err < 0) {
+                               /* We got a hard error in write_msgs but have
+                                * already queued this message. Report an error
+                                * in the socket, but don't affect return value
+                                * from sendmsg
+                                */
+                               pr_warn("KCM: Hard failure on kcm_write_msgs\n");
+                               report_csk_error(&kcm->sk, -err);
+                       }
+               }
+       } else {
+               /* Message not complete, save state */
+               kcm->seq_skb = head;
+               kcm_tx_msg(head)->last_skb = skb;
+       }
+
+       KCM_STATS_ADD(kcm->stats.tx_bytes, size);
+
+       release_sock(sk);
+       return size;
+
+out_error:
+       kcm_push(kcm);
+
+       err = sk_stream_error(sk, flags, err);
+
+       /* make sure we wake any epoll edge trigger waiter */
+       if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
+               sk->sk_write_space(sk);
+
+       release_sock(sk);
+       return err;
+}
+
+static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       struct sk_buff *skb = NULL, *head = NULL;
+       size_t copy, copied = 0;
+       long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+       int eor = (sock->type == SOCK_DGRAM) ?
+                 !(msg->msg_flags & MSG_MORE) : !!(msg->msg_flags & MSG_EOR);
+       int err = -EPIPE;
+
+       lock_sock(sk);
+
+       /* Per tcp_sendmsg this should be in poll */
+       sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
+
+       if (sk->sk_err)
+               goto out_error;
+
+       if (kcm->seq_skb) {
+               /* Previously opened message */
+               head = kcm->seq_skb;
+               skb = kcm_tx_msg(head)->last_skb;
+               goto start;
+       }
+
+       /* Call the sk_stream functions to manage the sndbuf mem. */
+       if (!sk_stream_memory_free(sk)) {
+               kcm_push(kcm);
+               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+       }
+
+       /* New message, alloc head skb */
+       head = alloc_skb(0, sk->sk_allocation);
+       while (!head) {
+               kcm_push(kcm);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+
+               head = alloc_skb(0, sk->sk_allocation);
+       }
+
+       skb = head;
+
+       /* Set ip_summed to CHECKSUM_UNNECESSARY to avoid calling
+        * csum_and_copy_from_iter from skb_do_copy_data_nocache.
+        */
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+start:
+       while (msg_data_left(msg)) {
+               bool merge = true;
+               int i = skb_shinfo(skb)->nr_frags;
+               struct page_frag *pfrag = sk_page_frag(sk);
+
+               if (!sk_page_frag_refill(sk, pfrag))
+                       goto wait_for_memory;
+
+               if (!skb_can_coalesce(skb, i, pfrag->page,
+                                     pfrag->offset)) {
+                       if (i == MAX_SKB_FRAGS) {
+                               struct sk_buff *tskb;
+
+                               tskb = alloc_skb(0, sk->sk_allocation);
+                               if (!tskb)
+                                       goto wait_for_memory;
+
+                               if (head == skb)
+                                       skb_shinfo(head)->frag_list = tskb;
+                               else
+                                       skb->next = tskb;
+
+                               skb = tskb;
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               continue;
+                       }
+                       merge = false;
+               }
+
+               copy = min_t(int, msg_data_left(msg),
+                            pfrag->size - pfrag->offset);
+
+               if (!sk_wmem_schedule(sk, copy))
+                       goto wait_for_memory;
+
+               err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
+                                              pfrag->page,
+                                              pfrag->offset,
+                                              copy);
+               if (err)
+                       goto out_error;
+
+               /* Update the skb. */
+               if (merge) {
+                       skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
+               } else {
+                       skb_fill_page_desc(skb, i, pfrag->page,
+                                          pfrag->offset, copy);
+                       get_page(pfrag->page);
+               }
+
+               pfrag->offset += copy;
+               copied += copy;
+               if (head != skb) {
+                       head->len += copy;
+                       head->data_len += copy;
+               }
+
+               continue;
+
+wait_for_memory:
+               kcm_push(kcm);
+               err = sk_stream_wait_memory(sk, &timeo);
+               if (err)
+                       goto out_error;
+       }
+
+       if (eor) {
+               bool not_busy = skb_queue_empty(&sk->sk_write_queue);
+
+               /* Message complete, queue it on send buffer */
+               __skb_queue_tail(&sk->sk_write_queue, head);
+               kcm->seq_skb = NULL;
+               KCM_STATS_INCR(kcm->stats.tx_msgs);
+
+               if (msg->msg_flags & MSG_BATCH) {
+                       kcm->tx_wait_more = true;
+               } else if (kcm->tx_wait_more || not_busy) {
+                       err = kcm_write_msgs(kcm);
+                       if (err < 0) {
+                               /* We got a hard error in write_msgs but have
+                                * already queued this message. Report an error
+                                * in the socket, but don't affect return value
+                                * from sendmsg
+                                */
+                               pr_warn("KCM: Hard failure on kcm_write_msgs\n");
+                               report_csk_error(&kcm->sk, -err);
+                       }
+               }
+       } else {
+               /* Message not complete, save state */
+partial_message:
+               kcm->seq_skb = head;
+               kcm_tx_msg(head)->last_skb = skb;
+       }
+
+       KCM_STATS_ADD(kcm->stats.tx_bytes, copied);
+
+       release_sock(sk);
+       return copied;
+
+out_error:
+       kcm_push(kcm);
+
+       if (copied && sock->type == SOCK_SEQPACKET) {
+               /* Wrote some bytes before encountering an
+                * error, return partial success.
+                */
+               goto partial_message;
+       }
+
+       if (head != kcm->seq_skb)
+               kfree_skb(head);
+
+       err = sk_stream_error(sk, msg->msg_flags, err);
+
+       /* make sure we wake any epoll edge trigger waiter */
+       if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN))
+               sk->sk_write_space(sk);
+
+       release_sock(sk);
+       return err;
+}
+
+static struct sk_buff *kcm_wait_data(struct sock *sk, int flags,
+                                    long timeo, int *err)
+{
+       struct sk_buff *skb;
+
+       while (!(skb = skb_peek(&sk->sk_receive_queue))) {
+               if (sk->sk_err) {
+                       *err = sock_error(sk);
+                       return NULL;
+               }
+
+               if (sock_flag(sk, SOCK_DONE))
+                       return NULL;
+
+               if ((flags & MSG_DONTWAIT) || !timeo) {
+                       *err = -EAGAIN;
+                       return NULL;
+               }
+
+               sk_wait_data(sk, &timeo, NULL);
+
+               /* Handle signals */
+               if (signal_pending(current)) {
+                       *err = sock_intr_errno(timeo);
+                       return NULL;
+               }
+       }
+
+       return skb;
+}
+
+static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
+                      size_t len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       int err = 0;
+       long timeo;
+       struct kcm_rx_msg *rxm;
+       int copied = 0;
+       struct sk_buff *skb;
+
+       timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+       lock_sock(sk);
+
+       skb = kcm_wait_data(sk, flags, timeo, &err);
+       if (!skb)
+               goto out;
+
+       /* Okay, have a message on the receive queue */
+
+       rxm = kcm_rx_msg(skb);
+
+       if (len > rxm->full_len)
+               len = rxm->full_len;
+
+       err = skb_copy_datagram_msg(skb, rxm->offset, msg, len);
+       if (err < 0)
+               goto out;
+
+       copied = len;
+       if (likely(!(flags & MSG_PEEK))) {
+               KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
+               if (copied < rxm->full_len) {
+                       if (sock->type == SOCK_DGRAM) {
+                               /* Truncated message */
+                               msg->msg_flags |= MSG_TRUNC;
+                               goto msg_finished;
+                       }
+                       rxm->offset += copied;
+                       rxm->full_len -= copied;
+               } else {
+msg_finished:
+                       /* Finished with message */
+                       msg->msg_flags |= MSG_EOR;
+                       KCM_STATS_INCR(kcm->stats.rx_msgs);
+                       skb_unlink(skb, &sk->sk_receive_queue);
+                       kfree_skb(skb);
+               }
+       }
+
+out:
+       release_sock(sk);
+
+       return copied ? : err;
+}
+
+static ssize_t kcm_sock_splice(struct sock *sk,
+                              struct pipe_inode_info *pipe,
+                              struct splice_pipe_desc *spd)
+{
+       int ret;
+
+       release_sock(sk);
+       ret = splice_to_pipe(pipe, spd);
+       lock_sock(sk);
+
+       return ret;
+}
+
+static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
+                              struct pipe_inode_info *pipe, size_t len,
+                              unsigned int flags)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm = kcm_sk(sk);
+       long timeo;
+       struct kcm_rx_msg *rxm;
+       int err = 0;
+       size_t copied;
+       struct sk_buff *skb;
+
+       /* Only support splice for SOCKSEQPACKET */
+
+       timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
+
+       lock_sock(sk);
+
+       skb = kcm_wait_data(sk, flags, timeo, &err);
+       if (!skb)
+               goto err_out;
+
+       /* Okay, have a message on the receive queue */
+
+       rxm = kcm_rx_msg(skb);
+
+       if (len > rxm->full_len)
+               len = rxm->full_len;
+
+       copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags,
+                                kcm_sock_splice);
+       if (copied < 0) {
+               err = copied;
+               goto err_out;
+       }
+
+       KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
+
+       rxm->offset += copied;
+       rxm->full_len -= copied;
+
+       /* We have no way to return MSG_EOR. If all the bytes have been
+        * read we still leave the message in the receive socket buffer.
+        * A subsequent recvmsg needs to be done to return MSG_EOR and
+        * finish reading the message.
+        */
+
+       release_sock(sk);
+
+       return copied;
+
+err_out:
+       release_sock(sk);
+
+       return err;
+}
+
+/* kcm sock lock held */
+static void kcm_recv_disable(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+
+       if (kcm->rx_disabled)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       kcm->rx_disabled = 1;
+
+       /* If a psock is reserved we'll do cleanup in unreserve */
+       if (!kcm->rx_psock) {
+               if (kcm->rx_wait) {
+                       list_del(&kcm->wait_rx_list);
+                       kcm->rx_wait = false;
+               }
+
+               requeue_rx_msgs(mux, &kcm->sk.sk_receive_queue);
+       }
+
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+/* kcm sock lock held */
+static void kcm_recv_enable(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+
+       if (!kcm->rx_disabled)
+               return;
+
+       spin_lock_bh(&mux->rx_lock);
+
+       kcm->rx_disabled = 0;
+       kcm_rcv_ready(kcm);
+
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+static int kcm_setsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, unsigned int optlen)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       int val, valbool;
+       int err = 0;
+
+       if (level != SOL_KCM)
+               return -ENOPROTOOPT;
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+
+       if (get_user(val, (int __user *)optval))
+               return -EINVAL;
+
+       valbool = val ? 1 : 0;
+
+       switch (optname) {
+       case KCM_RECV_DISABLE:
+               lock_sock(&kcm->sk);
+               if (valbool)
+                       kcm_recv_disable(kcm);
+               else
+                       kcm_recv_enable(kcm);
+               release_sock(&kcm->sk);
+               break;
+       default:
+               err = -ENOPROTOOPT;
+       }
+
+       return err;
+}
+
+static int kcm_getsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       int val, len;
+
+       if (level != SOL_KCM)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(int));
+       if (len < 0)
+               return -EINVAL;
+
+       switch (optname) {
+       case KCM_RECV_DISABLE:
+               val = kcm->rx_disabled;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &val, len))
+               return -EFAULT;
+       return 0;
+}
+
+static void init_kcm_sock(struct kcm_sock *kcm, struct kcm_mux *mux)
+{
+       struct kcm_sock *tkcm;
+       struct list_head *head;
+       int index = 0;
+
+       /* For SOCK_SEQPACKET sock type, datagram_poll checks the sk_state, so
+        * we set sk_state, otherwise epoll_wait always returns right away with
+        * POLLHUP
+        */
+       kcm->sk.sk_state = TCP_ESTABLISHED;
+
+       /* Add to mux's kcm sockets list */
+       kcm->mux = mux;
+       spin_lock_bh(&mux->lock);
+
+       head = &mux->kcm_socks;
+       list_for_each_entry(tkcm, &mux->kcm_socks, kcm_sock_list) {
+               if (tkcm->index != index)
+                       break;
+               head = &tkcm->kcm_sock_list;
+               index++;
+       }
+
+       list_add(&kcm->kcm_sock_list, head);
+       kcm->index = index;
+
+       mux->kcm_socks_cnt++;
+       spin_unlock_bh(&mux->lock);
+
+       INIT_WORK(&kcm->tx_work, kcm_tx_work);
+
+       spin_lock_bh(&mux->rx_lock);
+       kcm_rcv_ready(kcm);
+       spin_unlock_bh(&mux->rx_lock);
+}
+
+static void kcm_rx_msg_timeout(unsigned long arg)
+{
+       struct kcm_psock *psock = (struct kcm_psock *)arg;
+
+       /* Message assembly timed out */
+       KCM_STATS_INCR(psock->stats.rx_msg_timeouts);
+       kcm_abort_rx_psock(psock, ETIMEDOUT, NULL);
+}
+
+static int kcm_attach(struct socket *sock, struct socket *csock,
+                     struct bpf_prog *prog)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       struct kcm_mux *mux = kcm->mux;
+       struct sock *csk;
+       struct kcm_psock *psock = NULL, *tpsock;
+       struct list_head *head;
+       int index = 0;
+
+       if (csock->ops->family != PF_INET &&
+           csock->ops->family != PF_INET6)
+               return -EINVAL;
+
+       csk = csock->sk;
+       if (!csk)
+               return -EINVAL;
+
+       /* Only support TCP for now */
+       if (csk->sk_protocol != IPPROTO_TCP)
+               return -EINVAL;
+
+       psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
+       if (!psock)
+               return -ENOMEM;
+
+       psock->mux = mux;
+       psock->sk = csk;
+       psock->bpf_prog = prog;
+
+       setup_timer(&psock->rx_msg_timer, kcm_rx_msg_timeout,
+                   (unsigned long)psock);
+
+       INIT_WORK(&psock->rx_work, psock_rx_work);
+       INIT_DELAYED_WORK(&psock->rx_delayed_work, psock_rx_delayed_work);
+
+       sock_hold(csk);
+
+       write_lock_bh(&csk->sk_callback_lock);
+       psock->save_data_ready = csk->sk_data_ready;
+       psock->save_write_space = csk->sk_write_space;
+       psock->save_state_change = csk->sk_state_change;
+       csk->sk_user_data = psock;
+       csk->sk_data_ready = psock_tcp_data_ready;
+       csk->sk_write_space = psock_tcp_write_space;
+       csk->sk_state_change = psock_tcp_state_change;
+       write_unlock_bh(&csk->sk_callback_lock);
+
+       /* Finished initialization, now add the psock to the MUX. */
+       spin_lock_bh(&mux->lock);
+       head = &mux->psocks;
+       list_for_each_entry(tpsock, &mux->psocks, psock_list) {
+               if (tpsock->index != index)
+                       break;
+               head = &tpsock->psock_list;
+               index++;
+       }
+
+       list_add(&psock->psock_list, head);
+       psock->index = index;
+
+       KCM_STATS_INCR(mux->stats.psock_attach);
+       mux->psocks_cnt++;
+       psock_now_avail(psock);
+       spin_unlock_bh(&mux->lock);
+
+       /* Schedule RX work in case there are already bytes queued */
+       queue_work(kcm_wq, &psock->rx_work);
+
+       return 0;
+}
+
+static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info)
+{
+       struct socket *csock;
+       struct bpf_prog *prog;
+       int err;
+
+       csock = sockfd_lookup(info->fd, &err);
+       if (!csock)
+               return -ENOENT;
+
+       prog = bpf_prog_get(info->bpf_fd);
+       if (IS_ERR(prog)) {
+               err = PTR_ERR(prog);
+               goto out;
+       }
+
+       if (prog->type != BPF_PROG_TYPE_SOCKET_FILTER) {
+               bpf_prog_put(prog);
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = kcm_attach(sock, csock, prog);
+       if (err) {
+               bpf_prog_put(prog);
+               goto out;
+       }
+
+       /* Keep reference on file also */
+
+       return 0;
+out:
+       fput(csock->file);
+       return err;
+}
+
+static void kcm_unattach(struct kcm_psock *psock)
+{
+       struct sock *csk = psock->sk;
+       struct kcm_mux *mux = psock->mux;
+
+       /* Stop getting callbacks from TCP socket. After this there should
+        * be no way to reserve a kcm for this psock.
+        */
+       write_lock_bh(&csk->sk_callback_lock);
+       csk->sk_user_data = NULL;
+       csk->sk_data_ready = psock->save_data_ready;
+       csk->sk_write_space = psock->save_write_space;
+       csk->sk_state_change = psock->save_state_change;
+       psock->rx_stopped = 1;
+
+       if (WARN_ON(psock->rx_kcm)) {
+               write_unlock_bh(&csk->sk_callback_lock);
+               return;
+       }
+
+       spin_lock_bh(&mux->rx_lock);
+
+       /* Stop receiver activities. After this point psock should not be
+        * able to get onto ready list either through callbacks or work.
+        */
+       if (psock->ready_rx_msg) {
+               list_del(&psock->psock_ready_list);
+               kfree_skb(psock->ready_rx_msg);
+               psock->ready_rx_msg = NULL;
+               KCM_STATS_INCR(mux->stats.rx_ready_drops);
+       }
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       write_unlock_bh(&csk->sk_callback_lock);
+
+       del_timer_sync(&psock->rx_msg_timer);
+       cancel_work_sync(&psock->rx_work);
+       cancel_delayed_work_sync(&psock->rx_delayed_work);
+
+       bpf_prog_put(psock->bpf_prog);
+
+       kfree_skb(psock->rx_skb_head);
+       psock->rx_skb_head = NULL;
+
+       spin_lock_bh(&mux->lock);
+
+       aggregate_psock_stats(&psock->stats, &mux->aggregate_psock_stats);
+
+       KCM_STATS_INCR(mux->stats.psock_unattach);
+
+       if (psock->tx_kcm) {
+               /* psock was reserved.  Just mark it finished and we will clean
+                * up in the kcm paths, we need kcm lock which can not be
+                * acquired here.
+                */
+               KCM_STATS_INCR(mux->stats.psock_unattach_rsvd);
+               spin_unlock_bh(&mux->lock);
+
+               /* We are unattaching a socket that is reserved. Abort the
+                * socket since we may be out of sync in sending on it. We need
+                * to do this without the mux lock.
+                */
+               kcm_abort_tx_psock(psock, EPIPE, false);
+
+               spin_lock_bh(&mux->lock);
+               if (!psock->tx_kcm) {
+                       /* psock now unreserved in window mux was unlocked */
+                       goto no_reserved;
+               }
+               psock->done = 1;
+
+               /* Commit done before queuing work to process it */
+               smp_mb();
+
+               /* Queue tx work to make sure psock->done is handled */
+               queue_work(kcm_wq, &psock->tx_kcm->tx_work);
+               spin_unlock_bh(&mux->lock);
+       } else {
+no_reserved:
+               if (!psock->tx_stopped)
+                       list_del(&psock->psock_avail_list);
+               list_del(&psock->psock_list);
+               mux->psocks_cnt--;
+               spin_unlock_bh(&mux->lock);
+
+               sock_put(csk);
+               fput(csk->sk_socket->file);
+               kmem_cache_free(kcm_psockp, psock);
+       }
+}
+
+static int kcm_unattach_ioctl(struct socket *sock, struct kcm_unattach *info)
+{
+       struct kcm_sock *kcm = kcm_sk(sock->sk);
+       struct kcm_mux *mux = kcm->mux;
+       struct kcm_psock *psock;
+       struct socket *csock;
+       struct sock *csk;
+       int err;
+
+       csock = sockfd_lookup(info->fd, &err);
+       if (!csock)
+               return -ENOENT;
+
+       csk = csock->sk;
+       if (!csk) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = -ENOENT;
+
+       spin_lock_bh(&mux->lock);
+
+       list_for_each_entry(psock, &mux->psocks, psock_list) {
+               if (psock->sk != csk)
+                       continue;
+
+               /* Found the matching psock */
+
+               if (psock->unattaching || WARN_ON(psock->done)) {
+                       err = -EALREADY;
+                       break;
+               }
+
+               psock->unattaching = 1;
+
+               spin_unlock_bh(&mux->lock);
+
+               kcm_unattach(psock);
+
+               err = 0;
+               goto out;
+       }
+
+       spin_unlock_bh(&mux->lock);
+
+out:
+       fput(csock->file);
+       return err;
+}
+
+static struct proto kcm_proto = {
+       .name   = "KCM",
+       .owner  = THIS_MODULE,
+       .obj_size = sizeof(struct kcm_sock),
+};
+
+/* Clone a kcm socket. */
+static int kcm_clone(struct socket *osock, struct kcm_clone *info,
+                    struct socket **newsockp)
+{
+       struct socket *newsock;
+       struct sock *newsk;
+       struct file *newfile;
+       int err, newfd;
+
+       err = -ENFILE;
+       newsock = sock_alloc();
+       if (!newsock)
+               goto out;
+
+       newsock->type = osock->type;
+       newsock->ops = osock->ops;
+
+       __module_get(newsock->ops->owner);
+
+       newfd = get_unused_fd_flags(0);
+       if (unlikely(newfd < 0)) {
+               err = newfd;
+               goto out_fd_fail;
+       }
+
+       newfile = sock_alloc_file(newsock, 0, osock->sk->sk_prot_creator->name);
+       if (unlikely(IS_ERR(newfile))) {
+               err = PTR_ERR(newfile);
+               goto out_sock_alloc_fail;
+       }
+
+       newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL,
+                        &kcm_proto, true);
+       if (!newsk) {
+               err = -ENOMEM;
+               goto out_sk_alloc_fail;
+       }
+
+       sock_init_data(newsock, newsk);
+       init_kcm_sock(kcm_sk(newsk), kcm_sk(osock->sk)->mux);
+
+       fd_install(newfd, newfile);
+       *newsockp = newsock;
+       info->fd = newfd;
+
+       return 0;
+
+out_sk_alloc_fail:
+       fput(newfile);
+out_sock_alloc_fail:
+       put_unused_fd(newfd);
+out_fd_fail:
+       sock_release(newsock);
+out:
+       return err;
+}
+
+static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       int err;
+
+       switch (cmd) {
+       case SIOCKCMATTACH: {
+               struct kcm_attach info;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_attach_ioctl(sock, &info);
+
+               break;
+       }
+       case SIOCKCMUNATTACH: {
+               struct kcm_unattach info;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_unattach_ioctl(sock, &info);
+
+               break;
+       }
+       case SIOCKCMCLONE: {
+               struct kcm_clone info;
+               struct socket *newsock = NULL;
+
+               if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+                       err = -EFAULT;
+
+               err = kcm_clone(sock, &info, &newsock);
+
+               if (!err) {
+                       if (copy_to_user((void __user *)arg, &info,
+                                        sizeof(info))) {
+                               err = -EFAULT;
+                               sock_release(newsock);
+                       }
+               }
+
+               break;
+       }
+       default:
+               err = -ENOIOCTLCMD;
+               break;
+       }
+
+       return err;
+}
+
+static void free_mux(struct rcu_head *rcu)
+{
+       struct kcm_mux *mux = container_of(rcu,
+           struct kcm_mux, rcu);
+
+       kmem_cache_free(kcm_muxp, mux);
+}
+
+static void release_mux(struct kcm_mux *mux)
+{
+       struct kcm_net *knet = mux->knet;
+       struct kcm_psock *psock, *tmp_psock;
+
+       /* Release psocks */
+       list_for_each_entry_safe(psock, tmp_psock,
+                                &mux->psocks, psock_list) {
+               if (!WARN_ON(psock->unattaching))
+                       kcm_unattach(psock);
+       }
+
+       if (WARN_ON(mux->psocks_cnt))
+               return;
+
+       __skb_queue_purge(&mux->rx_hold_queue);
+
+       mutex_lock(&knet->mutex);
+       aggregate_mux_stats(&mux->stats, &knet->aggregate_mux_stats);
+       aggregate_psock_stats(&mux->aggregate_psock_stats,
+                             &knet->aggregate_psock_stats);
+       list_del_rcu(&mux->kcm_mux_list);
+       knet->count--;
+       mutex_unlock(&knet->mutex);
+
+       call_rcu(&mux->rcu, free_mux);
+}
+
+static void kcm_done(struct kcm_sock *kcm)
+{
+       struct kcm_mux *mux = kcm->mux;
+       struct sock *sk = &kcm->sk;
+       int socks_cnt;
+
+       spin_lock_bh(&mux->rx_lock);
+       if (kcm->rx_psock) {
+               /* Cleanup in unreserve_rx_kcm */
+               WARN_ON(kcm->done);
+               kcm->rx_disabled = 1;
+               kcm->done = 1;
+               spin_unlock_bh(&mux->rx_lock);
+               return;
+       }
+
+       if (kcm->rx_wait) {
+               list_del(&kcm->wait_rx_list);
+               kcm->rx_wait = false;
+       }
+       /* Move any pending receive messages to other kcm sockets */
+       requeue_rx_msgs(mux, &sk->sk_receive_queue);
+
+       spin_unlock_bh(&mux->rx_lock);
+
+       if (WARN_ON(sk_rmem_alloc_get(sk)))
+               return;
+
+       /* Detach from MUX */
+       spin_lock_bh(&mux->lock);
+
+       list_del(&kcm->kcm_sock_list);
+       mux->kcm_socks_cnt--;
+       socks_cnt = mux->kcm_socks_cnt;
+
+       spin_unlock_bh(&mux->lock);
+
+       if (!socks_cnt) {
+               /* We are done with the mux now. */
+               release_mux(mux);
+       }
+
+       WARN_ON(kcm->rx_wait);
+
+       sock_put(&kcm->sk);
+}
+
+/* Called by kcm_release to close a KCM socket.
+ * If this is the last KCM socket on the MUX, destroy the MUX.
+ */
+static int kcm_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct kcm_sock *kcm;
+       struct kcm_mux *mux;
+       struct kcm_psock *psock;
+
+       if (!sk)
+               return 0;
+
+       kcm = kcm_sk(sk);
+       mux = kcm->mux;
+
+       sock_orphan(sk);
+       kfree_skb(kcm->seq_skb);
+
+       lock_sock(sk);
+       /* Purge queue under lock to avoid race condition with tx_work trying
+        * to act when queue is nonempty. If tx_work runs after this point
+        * it will just return.
+        */
+       __skb_queue_purge(&sk->sk_write_queue);
+       release_sock(sk);
+
+       spin_lock_bh(&mux->lock);
+       if (kcm->tx_wait) {
+               /* Take of tx_wait list, after this point there should be no way
+                * that a psock will be assigned to this kcm.
+                */
+               list_del(&kcm->wait_psock_list);
+               kcm->tx_wait = false;
+       }
+       spin_unlock_bh(&mux->lock);
+
+       /* Cancel work. After this point there should be no outside references
+        * to the kcm socket.
+        */
+       cancel_work_sync(&kcm->tx_work);
+
+       lock_sock(sk);
+       psock = kcm->tx_psock;
+       if (psock) {
+               /* A psock was reserved, so we need to kill it since it
+                * may already have some bytes queued from a message. We
+                * need to do this after removing kcm from tx_wait list.
+                */
+               kcm_abort_tx_psock(psock, EPIPE, false);
+               unreserve_psock(kcm);
+       }
+       release_sock(sk);
+
+       WARN_ON(kcm->tx_wait);
+       WARN_ON(kcm->tx_psock);
+
+       sock->sk = NULL;
+
+       kcm_done(kcm);
+
+       return 0;
+}
+
+static const struct proto_ops kcm_dgram_ops = {
+       .family =       PF_KCM,
+       .owner =        THIS_MODULE,
+       .release =      kcm_release,
+       .bind =         sock_no_bind,
+       .connect =      sock_no_connect,
+       .socketpair =   sock_no_socketpair,
+       .accept =       sock_no_accept,
+       .getname =      sock_no_getname,
+       .poll =         datagram_poll,
+       .ioctl =        kcm_ioctl,
+       .listen =       sock_no_listen,
+       .shutdown =     sock_no_shutdown,
+       .setsockopt =   kcm_setsockopt,
+       .getsockopt =   kcm_getsockopt,
+       .sendmsg =      kcm_sendmsg,
+       .recvmsg =      kcm_recvmsg,
+       .mmap =         sock_no_mmap,
+       .sendpage =     kcm_sendpage,
+};
+
+static const struct proto_ops kcm_seqpacket_ops = {
+       .family =       PF_KCM,
+       .owner =        THIS_MODULE,
+       .release =      kcm_release,
+       .bind =         sock_no_bind,
+       .connect =      sock_no_connect,
+       .socketpair =   sock_no_socketpair,
+       .accept =       sock_no_accept,
+       .getname =      sock_no_getname,
+       .poll =         datagram_poll,
+       .ioctl =        kcm_ioctl,
+       .listen =       sock_no_listen,
+       .shutdown =     sock_no_shutdown,
+       .setsockopt =   kcm_setsockopt,
+       .getsockopt =   kcm_getsockopt,
+       .sendmsg =      kcm_sendmsg,
+       .recvmsg =      kcm_recvmsg,
+       .mmap =         sock_no_mmap,
+       .sendpage =     kcm_sendpage,
+       .splice_read =  kcm_splice_read,
+};
+
+/* Create proto operation for kcm sockets */
+static int kcm_create(struct net *net, struct socket *sock,
+                     int protocol, int kern)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+       struct sock *sk;
+       struct kcm_mux *mux;
+
+       switch (sock->type) {
+       case SOCK_DGRAM:
+               sock->ops = &kcm_dgram_ops;
+               break;
+       case SOCK_SEQPACKET:
+               sock->ops = &kcm_seqpacket_ops;
+               break;
+       default:
+               return -ESOCKTNOSUPPORT;
+       }
+
+       if (protocol != KCMPROTO_CONNECTED)
+               return -EPROTONOSUPPORT;
+
+       sk = sk_alloc(net, PF_KCM, GFP_KERNEL, &kcm_proto, kern);
+       if (!sk)
+               return -ENOMEM;
+
+       /* Allocate a kcm mux, shared between KCM sockets */
+       mux = kmem_cache_zalloc(kcm_muxp, GFP_KERNEL);
+       if (!mux) {
+               sk_free(sk);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&mux->lock);
+       spin_lock_init(&mux->rx_lock);
+       INIT_LIST_HEAD(&mux->kcm_socks);
+       INIT_LIST_HEAD(&mux->kcm_rx_waiters);
+       INIT_LIST_HEAD(&mux->kcm_tx_waiters);
+
+       INIT_LIST_HEAD(&mux->psocks);
+       INIT_LIST_HEAD(&mux->psocks_ready);
+       INIT_LIST_HEAD(&mux->psocks_avail);
+
+       mux->knet = knet;
+
+       /* Add new MUX to list */
+       mutex_lock(&knet->mutex);
+       list_add_rcu(&mux->kcm_mux_list, &knet->mux_list);
+       knet->count++;
+       mutex_unlock(&knet->mutex);
+
+       skb_queue_head_init(&mux->rx_hold_queue);
+
+       /* Init KCM socket */
+       sock_init_data(sock, sk);
+       init_kcm_sock(kcm_sk(sk), mux);
+
+       return 0;
+}
+
+static struct net_proto_family kcm_family_ops = {
+       .family = PF_KCM,
+       .create = kcm_create,
+       .owner  = THIS_MODULE,
+};
+
+static __net_init int kcm_init_net(struct net *net)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       INIT_LIST_HEAD_RCU(&knet->mux_list);
+       mutex_init(&knet->mutex);
+
+       return 0;
+}
+
+static __net_exit void kcm_exit_net(struct net *net)
+{
+       struct kcm_net *knet = net_generic(net, kcm_net_id);
+
+       /* All KCM sockets should be closed at this point, which should mean
+        * that all multiplexors and psocks have been destroyed.
+        */
+       WARN_ON(!list_empty(&knet->mux_list));
+}
+
+static struct pernet_operations kcm_net_ops = {
+       .init = kcm_init_net,
+       .exit = kcm_exit_net,
+       .id   = &kcm_net_id,
+       .size = sizeof(struct kcm_net),
+};
+
+static int __init kcm_init(void)
+{
+       int err = -ENOMEM;
+
+       kcm_muxp = kmem_cache_create("kcm_mux_cache",
+                                    sizeof(struct kcm_mux), 0,
+                                    SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       if (!kcm_muxp)
+               goto fail;
+
+       kcm_psockp = kmem_cache_create("kcm_psock_cache",
+                                      sizeof(struct kcm_psock), 0,
+                                       SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
+       if (!kcm_psockp)
+               goto fail;
+
+       kcm_wq = create_singlethread_workqueue("kkcmd");
+       if (!kcm_wq)
+               goto fail;
+
+       err = proto_register(&kcm_proto, 1);
+       if (err)
+               goto fail;
+
+       err = sock_register(&kcm_family_ops);
+       if (err)
+               goto sock_register_fail;
+
+       err = register_pernet_device(&kcm_net_ops);
+       if (err)
+               goto net_ops_fail;
+
+       err = kcm_proc_init();
+       if (err)
+               goto proc_init_fail;
+
+       return 0;
+
+proc_init_fail:
+       unregister_pernet_device(&kcm_net_ops);
+
+net_ops_fail:
+       sock_unregister(PF_KCM);
+
+sock_register_fail:
+       proto_unregister(&kcm_proto);
+
+fail:
+       kmem_cache_destroy(kcm_muxp);
+       kmem_cache_destroy(kcm_psockp);
+
+       if (kcm_wq)
+               destroy_workqueue(kcm_wq);
+
+       return err;
+}
+
+static void __exit kcm_exit(void)
+{
+       kcm_proc_exit();
+       unregister_pernet_device(&kcm_net_ops);
+       sock_unregister(PF_KCM);
+       proto_unregister(&kcm_proto);
+       destroy_workqueue(kcm_wq);
+
+       kmem_cache_destroy(kcm_muxp);
+       kmem_cache_destroy(kcm_psockp);
+}
+
+module_init(kcm_init);
+module_exit(kcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_KCM);
+
index f93c5be612a7cb43611708ebb66c25b4db0d27cf..2caaa84ce92dac811c7813ebbb233c9596d03ca0 100644 (file)
@@ -124,8 +124,13 @@ static int l2tp_tunnel_notify(struct genl_family *family,
        ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq,
                                  NLM_F_ACK, tunnel, cmd);
 
-       if (ret >= 0)
-               return genlmsg_multicast_allns(family, msg, 0,  0, GFP_ATOMIC);
+       if (ret >= 0) {
+               ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC);
+               /* We don't care if no one is listening */
+               if (ret == -ESRCH)
+                       ret = 0;
+               return ret;
+       }
 
        nlmsg_free(msg);
 
@@ -147,8 +152,13 @@ static int l2tp_session_notify(struct genl_family *family,
        ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq,
                                   NLM_F_ACK, session, cmd);
 
-       if (ret >= 0)
-               return genlmsg_multicast_allns(family, msg, 0,  0, GFP_ATOMIC);
+       if (ret >= 0) {
+               ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC);
+               /* We don't care if no one is listening */
+               if (ret == -ESRCH)
+                       ret = 0;
+               return ret;
+       }
 
        nlmsg_free(msg);
 
index 8e5ead366e7f93988a50589365eee758db12a694..e925037fa0df06b51b4ea8163707c039bfcdc03e 100644 (file)
@@ -17,7 +17,7 @@
  *     @dev: targeted interface
  */
 
-int l3mdev_master_ifindex_rcu(struct net_device *dev)
+int l3mdev_master_ifindex_rcu(const struct net_device *dev)
 {
        int ifindex = 0;
 
@@ -28,8 +28,15 @@ int l3mdev_master_ifindex_rcu(struct net_device *dev)
                ifindex = dev->ifindex;
        } else if (netif_is_l3_slave(dev)) {
                struct net_device *master;
+               struct net_device *_dev = (struct net_device *)dev;
 
-               master = netdev_master_upper_dev_get_rcu(dev);
+               /* netdev_master_upper_dev_get_rcu calls
+                * list_first_or_null_rcu to walk the upper dev list.
+                * list_first_or_null_rcu does not handle a const arg. We aren't
+                * making changes, just want the master device from that list so
+                * typecast to remove the const
+                */
+               master = netdev_master_upper_dev_get_rcu(_dev);
                if (master)
                        ifindex = master->ifindex;
        }
index 8dab4e569571dd34096104f87e8ed27faa7d5522..b3c52e3f689ad16468eb603f1a5d11c55f3d7ae5 100644 (file)
@@ -38,7 +38,7 @@ static u16 llc_ui_sap_link_no_max[256];
 static struct sockaddr_llc llc_ui_addrnull;
 static const struct proto_ops llc_ui_ops;
 
-static int llc_ui_wait_for_conn(struct sock *sk, long timeout);
+static long llc_ui_wait_for_conn(struct sock *sk, long timeout);
 static int llc_ui_wait_for_disc(struct sock *sk, long timeout);
 static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
 
@@ -551,7 +551,7 @@ static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
        return rc;
 }
 
-static int llc_ui_wait_for_conn(struct sock *sk, long timeout)
+static long llc_ui_wait_for_conn(struct sock *sk, long timeout)
 {
        DEFINE_WAIT(wait);
 
index 10ad4ac1fa0ba8ebd04e793595fab47d326194ce..3a8f881b22f10c983ab354a4393157e090fd6d3a 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * 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
@@ -61,16 +62,25 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_rx *tid_rx;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_RX_STOP,
+               .tid = tid,
+               .amsdu = false,
+               .timeout = 0,
+               .ssn = 0,
+       };
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
        tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
                                        lockdep_is_held(&sta->ampdu_mlme.mtx));
 
-       if (!tid_rx)
+       if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
                return;
 
        RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
+       __clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
 
        ht_dbg(sta->sdata,
               "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
@@ -78,8 +88,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
               initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
               (int)reason);
 
-       if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
-                            &sta->sta, tid, NULL, 0, false))
+       if (drv_ampdu_action(local, sta->sdata, &params))
                sdata_info(sta->sdata,
                           "HW problem - can not stop rx aggregation for %pM tid %d\n",
                           sta->sta.addr, tid);
@@ -89,6 +98,13 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, WLAN_BACK_RECIPIENT, reason);
 
+       /*
+        * return here in case tid_rx is not assigned - which will happen if
+        * IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
+        */
+       if (!tid_rx)
+               return;
+
        del_timer_sync(&tid_rx->session_timer);
 
        /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
@@ -237,6 +253,15 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 {
        struct ieee80211_local *local = sta->sdata->local;
        struct tid_ampdu_rx *tid_agg_rx;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_RX_START,
+               .tid = tid,
+               .amsdu = false,
+               .timeout = timeout,
+               .ssn = start_seq_num,
+       };
+
        int i, ret = -EOPNOTSUPP;
        u16 status = WLAN_STATUS_REQUEST_DECLINED;
 
@@ -275,11 +300,12 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        /* make sure the size doesn't exceed the maximum supported by the hw */
        if (buf_size > local->hw.max_rx_aggregation_subframes)
                buf_size = local->hw.max_rx_aggregation_subframes;
+       params.buf_size = buf_size;
 
        /* examine state machine */
        mutex_lock(&sta->ampdu_mlme.mtx);
 
-       if (sta->ampdu_mlme.tid_rx[tid]) {
+       if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
                ht_dbg_ratelimited(sta->sdata,
                                   "unexpected AddBA Req from %pM on tid %u\n",
                                   sta->sta.addr, tid);
@@ -290,8 +316,18 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
                                                false);
        }
 
+       if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
+               ret = drv_ampdu_action(local, sta->sdata, &params);
+               ht_dbg(sta->sdata,
+                      "Rx A-MPDU request on %pM tid %d result %d\n",
+                      sta->sta.addr, tid, ret);
+               if (!ret)
+                       status = WLAN_STATUS_SUCCESS;
+               goto end;
+       }
+
        /* prepare A-MPDU MLME for Rx aggregation */
-       tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
+       tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
        if (!tid_agg_rx)
                goto end;
 
@@ -322,8 +358,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        for (i = 0; i < buf_size; i++)
                __skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
 
-       ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
-                              &sta->sta, tid, &start_seq_num, 0, false);
+       ret = drv_ampdu_action(local, sta->sdata, &params);
        ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
               sta->sta.addr, tid, ret);
        if (ret) {
@@ -341,6 +376,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        tid_agg_rx->timeout = timeout;
        tid_agg_rx->stored_mpdu_num = 0;
        tid_agg_rx->auto_seq = auto_seq;
+       tid_agg_rx->reorder_buf_filtered = 0;
        status = WLAN_STATUS_SUCCESS;
 
        /* activate it for RX */
@@ -352,6 +388,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
        }
 
 end:
+       if (status == WLAN_STATUS_SUCCESS)
+               __set_bit(tid, sta->ampdu_mlme.agg_session_valid);
        mutex_unlock(&sta->ampdu_mlme.mtx);
 
 end_no_lock:
index ff757181b0a85c820e1acc53a088e95c78b87bff..4932e9f243a2cb9e156e7e24ac1c098fc9a4b19c 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * 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
@@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 {
        struct ieee80211_local *local = sta->local;
        struct tid_ampdu_tx *tid_tx;
-       enum ieee80211_ampdu_mlme_action action;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .tid = tid,
+               .buf_size = 0,
+               .amsdu = false,
+               .timeout = 0,
+               .ssn = 0,
+       };
        int ret;
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
@@ -304,10 +312,10 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        case AGG_STOP_DECLINED:
        case AGG_STOP_LOCAL_REQUEST:
        case AGG_STOP_PEER_REQUEST:
-               action = IEEE80211_AMPDU_TX_STOP_CONT;
+               params.action = IEEE80211_AMPDU_TX_STOP_CONT;
                break;
        case AGG_STOP_DESTROY_STA:
-               action = IEEE80211_AMPDU_TX_STOP_FLUSH;
+               params.action = IEEE80211_AMPDU_TX_STOP_FLUSH;
                break;
        default:
                WARN_ON_ONCE(1);
@@ -330,9 +338,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                spin_unlock_bh(&sta->lock);
                if (reason != AGG_STOP_DESTROY_STA)
                        return -EALREADY;
-               ret = drv_ampdu_action(local, sta->sdata,
-                                      IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
-                                      &sta->sta, tid, NULL, 0, false);
+               params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT;
+               ret = drv_ampdu_action(local, sta->sdata, &params);
                WARN_ON_ONCE(ret);
                return 0;
        }
@@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
                                        WLAN_BACK_INITIATOR;
        tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
 
-       ret = drv_ampdu_action(local, sta->sdata, action,
-                              &sta->sta, tid, NULL, 0, false);
+       ret = drv_ampdu_action(local, sta->sdata, &params);
 
        /* HW shall not deny going back to legacy */
        if (WARN_ON(ret)) {
@@ -445,7 +451,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
        struct tid_ampdu_tx *tid_tx;
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       u16 start_seq_num;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_TX_START,
+               .tid = tid,
+               .buf_size = 0,
+               .amsdu = false,
+               .timeout = 0,
+       };
        int ret;
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
@@ -467,10 +480,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
         */
        synchronize_net();
 
-       start_seq_num = sta->tid_seq[tid] >> 4;
-
-       ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
-                              &sta->sta, tid, &start_seq_num, 0, false);
+       params.ssn = sta->tid_seq[tid] >> 4;
+       ret = drv_ampdu_action(local, sdata, &params);
        if (ret) {
                ht_dbg(sdata,
                       "BA request denied - HW unavailable for %pM tid %d\n",
@@ -499,7 +510,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
 
        /* send AddBA request */
        ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
-                                    tid_tx->dialog_token, start_seq_num,
+                                    tid_tx->dialog_token, params.ssn,
                                     IEEE80211_MAX_AMPDU_BUF,
                                     tid_tx->timeout);
 }
@@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
                                         struct sta_info *sta, u16 tid)
 {
        struct tid_ampdu_tx *tid_tx;
+       struct ieee80211_ampdu_params params = {
+               .sta = &sta->sta,
+               .action = IEEE80211_AMPDU_TX_OPERATIONAL,
+               .tid = tid,
+               .timeout = 0,
+               .ssn = 0,
+       };
 
        lockdep_assert_held(&sta->ampdu_mlme.mtx);
 
        tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+       params.buf_size = tid_tx->buf_size;
+       params.amsdu = tid_tx->amsdu;
 
        ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
               sta->sta.addr, tid);
 
-       drv_ampdu_action(local, sta->sdata,
-                        IEEE80211_AMPDU_TX_OPERATIONAL,
-                        &sta->sta, tid, NULL, tid_tx->buf_size,
-                        tid_tx->amsdu);
+       drv_ampdu_action(local, sta->sdata, &params);
 
        /*
         * synchronize with TX path, while splicing the TX path
index 166a29fe6c35f63a5357a01ceeb140f19346f9bd..fe1704c4e8fb825a455afeb53f34fd50b62dd33e 100644 (file)
@@ -339,8 +339,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               iv32 = key->u.tkip.tx.iv32;
-               iv16 = key->u.tkip.tx.iv16;
+               pn64 = atomic64_read(&key->conf.tx_pn);
+               iv32 = TKIP_PN_TO_IV32(pn64);
+               iv16 = TKIP_PN_TO_IV16(pn64);
 
                if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
                    !(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
@@ -1131,6 +1132,34 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                sta->sta.max_sp = params->max_sp;
        }
 
+       /* The sender might not have sent the last bit, consider it to be 0 */
+       if (params->ext_capab_len >= 8) {
+               u8 val = (params->ext_capab[7] &
+                         WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7;
+
+               /* we did get all the bits, take the MSB as well */
+               if (params->ext_capab_len >= 9) {
+                       u8 val_msb = params->ext_capab[8] &
+                               WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB;
+                       val_msb <<= 1;
+                       val |= val_msb;
+               }
+
+               switch (val) {
+               case 1:
+                       sta->sta.max_amsdu_subframes = 32;
+                       break;
+               case 2:
+                       sta->sta.max_amsdu_subframes = 16;
+                       break;
+               case 3:
+                       sta->sta.max_amsdu_subframes = 8;
+                       break;
+               default:
+                       sta->sta.max_amsdu_subframes = 0;
+               }
+       }
+
        /*
         * cfg80211 validates this (1-2007) and allows setting the AID
         * only when creating a new station entry
@@ -1160,6 +1189,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                  params->ht_capa, sta);
 
+       /* VHT can override some HT caps such as the A-MSDU max length */
        if (params->vht_capa)
                ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                    params->vht_capa, sta);
index 1d1b9b7bdefe74ac851ca6d01554d663fae39541..283981108ca80cb5bb7182b28e626a1a14c09fb1 100644 (file)
@@ -231,7 +231,7 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
                    !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
                        continue;
 
-               if (!sta->uploaded)
+               if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC))
                        continue;
 
                max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
index 3e24d0ddb51bfaca18d39669e41dba2bb6a91bb5..4ab5c522ceeeee5def93f869fd96618999a2daf5 100644 (file)
@@ -126,6 +126,7 @@ static const char *hw_flag_names[] = {
        FLAG(SUPPORTS_AMSDU_IN_AMPDU),
        FLAG(BEACON_TX_STATUS),
        FLAG(NEEDS_UNIQUE_STA_ADDR),
+       FLAG(SUPPORTS_REORDERING_BUFFER),
 #undef FLAG
 };
 
index 7961e7d0b61e1ee48700e9a7ef2db8feec84814f..a2ef95f16f116ae905049c595742bcee3e78c6c7 100644 (file)
@@ -132,9 +132,10 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
                len = scnprintf(buf, sizeof(buf), "\n");
                break;
        case WLAN_CIPHER_SUITE_TKIP:
+               pn = atomic64_read(&key->conf.tx_pn);
                len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
-                               key->u.tkip.tx.iv32,
-                               key->u.tkip.tx.iv16);
+                               TKIP_PN_TO_IV32(pn),
+                               TKIP_PN_TO_IV16(pn));
                break;
        case WLAN_CIPHER_SUITE_CCMP:
        case WLAN_CIPHER_SUITE_CCMP_256:
index ca1fe5576103767c3a98b52e037c0034b949887f..c258f1041d330885d08869e302a5ec255b470b4b 100644 (file)
@@ -284,9 +284,7 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local,
 
 int drv_ampdu_action(struct ieee80211_local *local,
                     struct ieee80211_sub_if_data *sdata,
-                    enum ieee80211_ampdu_mlme_action action,
-                    struct ieee80211_sta *sta, u16 tid,
-                    u16 *ssn, u8 buf_size, bool amsdu)
+                    struct ieee80211_ampdu_params *params)
 {
        int ret = -EOPNOTSUPP;
 
@@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local,
        if (!check_sdata_in_driver(sdata))
                return -EIO;
 
-       trace_drv_ampdu_action(local, sdata, action, sta, tid,
-                              ssn, buf_size, amsdu);
+       trace_drv_ampdu_action(local, sdata, params);
 
        if (local->ops->ampdu_action)
-               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
-                                              sta, tid, ssn, buf_size, amsdu);
+               ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
 
        trace_drv_return_int(local, ret);
 
index 154ce4b13406d5a31bac8797f8069184ca9cd6f5..18b0d65baff000156c8015f76b9ce527a938e95a 100644 (file)
@@ -585,9 +585,7 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 
 int drv_ampdu_action(struct ieee80211_local *local,
                     struct ieee80211_sub_if_data *sdata,
-                    enum ieee80211_ampdu_mlme_action action,
-                    struct ieee80211_sta *sta, u16 tid,
-                    u16 *ssn, u8 buf_size, bool amsdu);
+                    struct ieee80211_ampdu_params *params);
 
 static inline int drv_get_survey(struct ieee80211_local *local, int idx,
                                struct survey_info *survey)
index 7a76ce639d58d6071681551e916f0125cf376212..f4a52877356349abed96d0a77d6ae75f301181e4 100644 (file)
@@ -230,6 +230,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
        /* set Rx highest rate */
        ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
 
+       if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
+               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;
+       else
+               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
+
  apply:
        changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
 
index 978d3bc31df727468602a7b234d10b5b1e9ba35c..fc3238376b39546d025f81ad92240356a77aa48b 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * 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
@@ -1050,9 +1051,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
                struct cfg80211_chan_def chandef;
                enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
 
-               ieee80211_ht_oper_to_chandef(channel,
-                                            elems->ht_operation,
-                                            &chandef);
+               cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
+               ieee80211_chandef_ht_oper(elems->ht_operation, &chandef);
 
                memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
                rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
@@ -1066,9 +1066,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
                        struct ieee80211_vht_cap cap_ie;
                        struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
 
-                       ieee80211_vht_oper_to_chandef(channel,
-                                                     elems->vht_operation,
-                                                     &chandef);
+                       ieee80211_chandef_vht_oper(elems->vht_operation,
+                                                  &chandef);
                        memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
                        ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
                                                            &cap_ie, sta);
@@ -1485,14 +1484,21 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
 
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
-               num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
-                                                        &ifibss->chandef,
-                                                        channels,
-                                                        ARRAY_SIZE(channels));
                scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
-               ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-                                           ifibss->ssid_len, channels, num,
-                                           scan_width);
+
+               if (ifibss->fixed_channel) {
+                       num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+                                                                &ifibss->chandef,
+                                                                channels,
+                                                                ARRAY_SIZE(channels));
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, channels,
+                                                   num, scan_width);
+               } else {
+                       ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                                   ifibss->ssid_len, NULL,
+                                                   0, scan_width);
+               }
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
index b84f6aa32c0831ce200f286af2ecd947ef0fefde..804575ff7af506e73ef50d6ebc32326219b99082 100644 (file)
@@ -92,7 +92,7 @@ struct ieee80211_fragment_entry {
        u16 extra_len;
        u16 last_frag;
        u8 rx_queue;
-       bool ccmp; /* Whether fragments were encrypted with CCMP */
+       bool check_sequential_pn; /* needed for CCMP/GCMP */
        u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
 };
 
@@ -716,7 +716,6 @@ struct ieee80211_if_mesh {
  *     back to wireless media and to the local net stack.
  * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
  * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
- * @IEEE80211_SDATA_MU_MIMO_OWNER: indicates interface owns MU-MIMO capability
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
@@ -724,7 +723,6 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
        IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
        IEEE80211_SDATA_IN_DRIVER               = BIT(5),
-       IEEE80211_SDATA_MU_MIMO_OWNER           = BIT(6),
 };
 
 /**
@@ -804,6 +802,7 @@ enum txq_info_flags {
 struct txq_info {
        struct sk_buff_head queue;
        unsigned long flags;
+       unsigned long byte_cnt;
 
        /* keep last! */
        struct ieee80211_txq txq;
@@ -1466,7 +1465,13 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
 {
        WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
                     status->flag & RX_FLAG_MACTIME_END);
-       return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END);
+       if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END))
+               return true;
+       /* can't handle HT/VHT preamble yet */
+       if (status->flag & RX_FLAG_MACTIME_PLCP_START &&
+           !(status->flag & (RX_FLAG_HT | RX_FLAG_VHT)))
+               return true;
+       return false;
 }
 
 u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
@@ -1714,6 +1719,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
 enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta);
 enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
 void ieee80211_sta_set_rx_nss(struct sta_info *sta);
+void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
+                                struct ieee80211_mgmt *mgmt);
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                   struct sta_info *sta, u8 opmode,
                                  enum ieee80211_band band);
@@ -1829,20 +1836,6 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
        ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
 }
 
-static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames)
-{
-       struct sk_buff *tail = skb_peek_tail(frames);
-       struct ieee80211_rx_status *status;
-
-       if (!tail)
-               return false;
-
-       status = IEEE80211_SKB_RXCB(tail);
-       if (status->flag & RX_FLAG_AMSDU_MORE)
-               return false;
-
-       return true;
-}
 
 extern const int ieee802_1d_to_ac[8];
 
@@ -1986,12 +1979,10 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
 
 /* channel management */
-void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                 const struct ieee80211_ht_operation *ht_oper,
-                                 struct cfg80211_chan_def *chandef);
-void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                  const struct ieee80211_vht_operation *oper,
-                                  struct cfg80211_chan_def *chandef);
+bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
+                              struct cfg80211_chan_def *chandef);
+bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+                               struct cfg80211_chan_def *chandef);
 u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
 
 int __must_check
index c9e325d2e120c0f9c230dbace71c3c405b9216a3..453b4e7417804105cb136e2ec7f4c57a39392db3 100644 (file)
@@ -977,7 +977,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.txq) {
                struct txq_info *txqi = to_txq_info(sdata->vif.txq);
 
+               spin_lock_bh(&txqi->queue.lock);
                ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
+               txqi->byte_cnt = 0;
+               spin_unlock_bh(&txqi->queue.lock);
+
                atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
        }
 
@@ -1271,6 +1275,16 @@ static void ieee80211_iface_work(struct work_struct *work)
                                }
                        }
                        mutex_unlock(&local->sta_mtx);
+               } else if (ieee80211_is_action(mgmt->frame_control) &&
+                          mgmt->u.action.category == WLAN_CATEGORY_VHT) {
+                       switch (mgmt->u.action.u.vht_group_notif.action_code) {
+                       case WLAN_VHT_ACTION_GROUPID_MGMT:
+                               ieee80211_process_mu_groups(sdata, mgmt);
+                               break;
+                       default:
+                               WARN_ON(1);
+                               break;
+                       }
                } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
                        struct ieee80211_hdr *hdr = (void *)mgmt;
                        /*
index 5e5bc599da4c8cc42639f6cbec7de47ea24925bc..3df7b0392d30c70fcfa988a7f1233e17111868a1 100644 (file)
@@ -932,50 +932,6 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
 }
 EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
 
-void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
-                             struct ieee80211_key_seq *seq)
-{
-       struct ieee80211_key *key;
-       u64 pn64;
-
-       if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
-               return;
-
-       key = container_of(keyconf, struct ieee80211_key, conf);
-
-       switch (key->conf.cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               seq->tkip.iv32 = key->u.tkip.tx.iv32;
-               seq->tkip.iv16 = key->u.tkip.tx.iv16;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-       case WLAN_CIPHER_SUITE_CCMP_256:
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-       case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), aes_cmac));
-       case WLAN_CIPHER_SUITE_BIP_GMAC_128:
-       case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), aes_gmac));
-       case WLAN_CIPHER_SUITE_GCMP:
-       case WLAN_CIPHER_SUITE_GCMP_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), gcmp));
-               pn64 = atomic64_read(&key->conf.tx_pn);
-               seq->ccmp.pn[5] = pn64;
-               seq->ccmp.pn[4] = pn64 >> 8;
-               seq->ccmp.pn[3] = pn64 >> 16;
-               seq->ccmp.pn[2] = pn64 >> 24;
-               seq->ccmp.pn[1] = pn64 >> 32;
-               seq->ccmp.pn[0] = pn64 >> 40;
-               break;
-       default:
-               WARN_ON(1);
-       }
-}
-EXPORT_SYMBOL(ieee80211_get_key_tx_seq);
-
 void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
                              int tid, struct ieee80211_key_seq *seq)
 {
@@ -1029,48 +985,6 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
 }
 EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
 
-void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
-                             struct ieee80211_key_seq *seq)
-{
-       struct ieee80211_key *key;
-       u64 pn64;
-
-       key = container_of(keyconf, struct ieee80211_key, conf);
-
-       switch (key->conf.cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               key->u.tkip.tx.iv32 = seq->tkip.iv32;
-               key->u.tkip.tx.iv16 = seq->tkip.iv16;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-       case WLAN_CIPHER_SUITE_CCMP_256:
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-       case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), aes_cmac));
-       case WLAN_CIPHER_SUITE_BIP_GMAC_128:
-       case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), aes_gmac));
-       case WLAN_CIPHER_SUITE_GCMP:
-       case WLAN_CIPHER_SUITE_GCMP_256:
-               BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
-                            offsetof(typeof(*seq), gcmp));
-               pn64 = (u64)seq->ccmp.pn[5] |
-                      ((u64)seq->ccmp.pn[4] << 8) |
-                      ((u64)seq->ccmp.pn[3] << 16) |
-                      ((u64)seq->ccmp.pn[2] << 24) |
-                      ((u64)seq->ccmp.pn[1] << 32) |
-                      ((u64)seq->ccmp.pn[0] << 40);
-               atomic64_set(&key->conf.tx_pn, pn64);
-               break;
-       default:
-               WARN_ON(1);
-               break;
-       }
-}
-EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq);
-
 void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
                              int tid, struct ieee80211_key_seq *seq)
 {
index 9951ef06323e743d2c33156d15e5a21478584cd9..4aa20cef08595955702cd0aa5746d2dde1e56647 100644 (file)
@@ -44,13 +44,17 @@ enum ieee80211_internal_tkip_state {
 };
 
 struct tkip_ctx {
-       u32 iv32;       /* current iv32 */
-       u16 iv16;       /* current iv16 */
        u16 p1k[5];     /* p1k cache */
        u32 p1k_iv32;   /* iv32 for which p1k computed */
        enum ieee80211_internal_tkip_state state;
 };
 
+struct tkip_ctx_rx {
+       struct tkip_ctx ctx;
+       u32 iv32;       /* current iv32 */
+       u16 iv16;       /* current iv16 */
+};
+
 struct ieee80211_key {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
@@ -71,7 +75,7 @@ struct ieee80211_key {
                        struct tkip_ctx tx;
 
                        /* last received RSC */
-                       struct tkip_ctx rx[IEEE80211_NUM_TIDS];
+                       struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS];
 
                        /* number of mic failures */
                        u32 mic_failures;
index 6f85b6ab8e51015ab9a0520822fc4daff6af92b0..d32cefcb63b02ecd4f1af220c559a2a82c75430d 100644 (file)
@@ -91,11 +91,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.bss_conf.basic_rates != basic_rates)
                return false;
 
-       ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
-                                    ie->ht_operation, &sta_chan_def);
-
-       ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
-                                     ie->vht_operation, &sta_chan_def);
+       cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
+                               NL80211_CHAN_NO_HT);
+       ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
+       ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
 
        if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
                                         &sta_chan_def))
index 4a8019f79fb2cba035a316b0a8d56a7e8f25d614..87c017a3b1ce8db928a999bec05fb1cf32169b73 100644 (file)
@@ -137,8 +137,6 @@ struct mesh_path {
  * @copy_node: function to copy nodes of the table
  * @size_order: determines size of the table, there will be 2^size_order hash
  *     buckets
- * @mean_chain_len: maximum average length for the hash buckets' list, if it is
- *     reached, the table will grow
  * @known_gates: list of known mesh gates and their mpaths by the station. The
  * gate's mpath may or may not be resolved and active.
  *
@@ -154,7 +152,6 @@ struct mesh_table {
        void (*free_node) (struct hlist_node *p, bool free_leafs);
        int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
        int size_order;
-       int mean_chain_len;
        struct hlist_head *known_gates;
        spinlock_t gates_lock;
 
index c6be0b4f405888489b21cee009b267d95f626c34..5b6aec1a06302c7b5efac015a5e50d5239242406 100644 (file)
@@ -205,9 +205,9 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
-       skb_set_transport_header(skb, 0);
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
 
        /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
        skb_set_queue_mapping(skb, IEEE80211_AC_VO);
index dadf8dc6f1cfdceb762cabcf057e2e485ad853e8..2ba7aa56b11c0ec121d7851665c989e1a2b3b2d1 100644 (file)
@@ -55,16 +55,21 @@ int mpp_paths_generation;
 static DEFINE_RWLOCK(pathtbl_resize_lock);
 
 
+static inline struct mesh_table *resize_dereference_paths(
+       struct mesh_table __rcu *table)
+{
+       return rcu_dereference_protected(table,
+                                       lockdep_is_held(&pathtbl_resize_lock));
+}
+
 static inline struct mesh_table *resize_dereference_mesh_paths(void)
 {
-       return rcu_dereference_protected(mesh_paths,
-               lockdep_is_held(&pathtbl_resize_lock));
+       return resize_dereference_paths(mesh_paths);
 }
 
 static inline struct mesh_table *resize_dereference_mpp_paths(void)
 {
-       return rcu_dereference_protected(mpp_paths,
-               lockdep_is_held(&pathtbl_resize_lock));
+       return resize_dereference_paths(mpp_paths);
 }
 
 /*
@@ -160,11 +165,10 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
        int i;
 
        if (atomic_read(&oldtbl->entries)
-                       < oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
+                       < MEAN_CHAIN_LEN * (oldtbl->hash_mask + 1))
                return -EAGAIN;
 
        newtbl->free_node = oldtbl->free_node;
-       newtbl->mean_chain_len = oldtbl->mean_chain_len;
        newtbl->copy_node = oldtbl->copy_node;
        newtbl->known_gates = oldtbl->known_gates;
        atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
@@ -585,7 +589,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
 
        hlist_add_head_rcu(&new_node->list, bucket);
        if (atomic_inc_return(&tbl->entries) >=
-           tbl->mean_chain_len * (tbl->hash_mask + 1))
+           MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
                grow = 1;
 
        mesh_paths_generation++;
@@ -714,7 +718,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
 
        hlist_add_head_rcu(&new_node->list, bucket);
        if (atomic_inc_return(&tbl->entries) >=
-           tbl->mean_chain_len * (tbl->hash_mask + 1))
+           MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
                grow = 1;
 
        spin_unlock(&tbl->hashwlock[hash_idx]);
@@ -835,6 +839,29 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
        rcu_read_unlock();
 }
 
+static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
+                              const u8 *proxy)
+{
+       struct mesh_table *tbl;
+       struct mesh_path *mpp;
+       struct mpath_node *node;
+       int i;
+
+       rcu_read_lock();
+       read_lock_bh(&pathtbl_resize_lock);
+       tbl = resize_dereference_mpp_paths();
+       for_each_mesh_entry(tbl, node, i) {
+               mpp = node->mpath;
+               if (ether_addr_equal(mpp->mpp, proxy)) {
+                       spin_lock(&tbl->hashwlock[i]);
+                       __mesh_path_del(tbl, node);
+                       spin_unlock(&tbl->hashwlock[i]);
+               }
+       }
+       read_unlock_bh(&pathtbl_resize_lock);
+       rcu_read_unlock();
+}
+
 static void table_flush_by_iface(struct mesh_table *tbl,
                                 struct ieee80211_sub_if_data *sdata)
 {
@@ -876,14 +903,17 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
 }
 
 /**
- * mesh_path_del - delete a mesh path from the table
+ * table_path_del - delete a path from the mesh or mpp table
  *
- * @addr: dst address (ETH_ALEN length)
+ * @tbl: mesh or mpp path table
  * @sdata: local subif
+ * @addr: dst address (ETH_ALEN length)
  *
  * Returns: 0 if successful
  */
-int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+static int table_path_del(struct mesh_table __rcu *rcu_tbl,
+                         struct ieee80211_sub_if_data *sdata,
+                         const u8 *addr)
 {
        struct mesh_table *tbl;
        struct mesh_path *mpath;
@@ -892,8 +922,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
        int hash_idx;
        int err = 0;
 
-       read_lock_bh(&pathtbl_resize_lock);
-       tbl = resize_dereference_mesh_paths();
+       tbl = resize_dereference_paths(rcu_tbl);
        hash_idx = mesh_table_hash(addr, sdata, tbl);
        bucket = &tbl->hash_buckets[hash_idx];
 
@@ -909,9 +938,50 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
 
        err = -ENXIO;
 enddel:
-       mesh_paths_generation++;
        spin_unlock(&tbl->hashwlock[hash_idx]);
+       return err;
+}
+
+/**
+ * mesh_path_del - delete a mesh path from the table
+ *
+ * @addr: dst address (ETH_ALEN length)
+ * @sdata: local subif
+ *
+ * Returns: 0 if successful
+ */
+int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+{
+       int err = 0;
+
+       /* flush relevant mpp entries first */
+       mpp_flush_by_proxy(sdata, addr);
+
+       read_lock_bh(&pathtbl_resize_lock);
+       err = table_path_del(mesh_paths, sdata, addr);
+       mesh_paths_generation++;
        read_unlock_bh(&pathtbl_resize_lock);
+
+       return err;
+}
+
+/**
+ * mpp_path_del - delete a mesh proxy path from the table
+ *
+ * @addr: addr address (ETH_ALEN length)
+ * @sdata: local subif
+ *
+ * Returns: 0 if successful
+ */
+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
+{
+       int err = 0;
+
+       read_lock_bh(&pathtbl_resize_lock);
+       err = table_path_del(mpp_paths, sdata, addr);
+       mpp_paths_generation++;
+       read_unlock_bh(&pathtbl_resize_lock);
+
        return err;
 }
 
@@ -1076,7 +1146,6 @@ int mesh_pathtbl_init(void)
                return -ENOMEM;
        tbl_path->free_node = &mesh_path_node_free;
        tbl_path->copy_node = &mesh_path_node_copy;
-       tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
        tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
        if (!tbl_path->known_gates) {
                ret = -ENOMEM;
@@ -1092,7 +1161,6 @@ int mesh_pathtbl_init(void)
        }
        tbl_mpp->free_node = &mesh_path_node_free;
        tbl_mpp->copy_node = &mesh_path_node_copy;
-       tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
        tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
        if (!tbl_mpp->known_gates) {
                ret = -ENOMEM;
@@ -1131,6 +1199,17 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
                     time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
                        mesh_path_del(mpath->sdata, mpath->dst);
        }
+
+       tbl = rcu_dereference(mpp_paths);
+       for_each_mesh_entry(tbl, node, i) {
+               if (node->mpath->sdata != sdata)
+                       continue;
+               mpath = node->mpath;
+               if ((!(mpath->flags & MESH_PATH_FIXED)) &&
+                   time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
+                       mpp_path_del(mpath->sdata, mpath->dst);
+       }
+
        rcu_read_unlock();
 }
 
index bd3d55eb21d4f8fb5d4cf7a0da75a506ecdf00eb..a07e93c21c9ede90bd94328f1e4aaa51476d58bd 100644 (file)
@@ -976,6 +976,10 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
                        mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
                        goto out;
                }
+
+               /* new matching peer */
+               event = OPN_ACPT;
+               goto out;
        } else {
                if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
                        mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
@@ -985,12 +989,6 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
                        goto out;
        }
 
-       /* new matching peer */
-       if (!sta) {
-               event = OPN_ACPT;
-               goto out;
-       }
-
        switch (ftype) {
        case WLAN_SP_MESH_PEERING_OPEN:
                if (!matches_local)
index bfbb1acafdd1f004ff4960b2238fbc5343302f38..281b8d6e51097e8160b7243ee32f630faf742ef1 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2015 Intel Deutschland GmbH
+ * Copyright (C) 2015 - 2016 Intel Deutschland GmbH
  *
  * 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
@@ -196,16 +196,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
 
        /* check 40 MHz support, if we have it */
        if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
-               switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-               case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-                       chandef->width = NL80211_CHAN_WIDTH_40;
-                       chandef->center_freq1 += 10;
-                       break;
-               case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                       chandef->width = NL80211_CHAN_WIDTH_40;
-                       chandef->center_freq1 -= 10;
-                       break;
-               }
+               ieee80211_chandef_ht_oper(ht_oper, chandef);
        } else {
                /* 40 MHz (and 80 MHz) must be supported for VHT */
                ret = IEEE80211_STA_DISABLE_VHT;
@@ -219,35 +210,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
-       vht_chandef.chan = channel;
-       vht_chandef.center_freq1 =
-               ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx,
-                                              channel->band);
-       vht_chandef.center_freq2 = 0;
-
-       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;
-               break;
-       case IEEE80211_VHT_CHANWIDTH_160MHZ:
-               vht_chandef.width = NL80211_CHAN_WIDTH_160;
-               break;
-       case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
-               vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
-               vht_chandef.center_freq2 =
-                       ieee80211_channel_to_frequency(
-                               vht_oper->center_freq_seg2_idx,
-                               channel->band);
-               break;
-       default:
+       vht_chandef = *chandef;
+       if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
                if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
-                                  "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
-                                  vht_oper->chan_width);
+                                  "AP VHT information is invalid, disable VHT\n");
                ret = IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
@@ -592,7 +559,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_sub_if_data *other;
 
                list_for_each_entry_rcu(other, &local->interfaces, list) {
-                       if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) {
+                       if (other->vif.mu_mimo_owner) {
                                disable_mu_mimo = true;
                                break;
                        }
@@ -600,7 +567,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
                if (disable_mu_mimo)
                        cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
                else
-                       sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER;
+                       sdata->vif.mu_mimo_owner = true;
        }
 
        mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
@@ -1638,8 +1605,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
 
 void ieee80211_dfs_cac_timer_work(struct work_struct *work)
 {
-       struct delayed_work *delayed_work =
-               container_of(work, struct delayed_work, work);
+       struct delayed_work *delayed_work = to_delayed_work(work);
        struct ieee80211_sub_if_data *sdata =
                container_of(delayed_work, struct ieee80211_sub_if_data,
                             dfs_cac_timer_work);
@@ -2079,7 +2045,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
        memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
        memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
-       sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
+
+       /* reset MU-MIMO ownership and group data */
+       memset(sdata->vif.bss_conf.mu_group.membership, 0,
+              sizeof(sdata->vif.bss_conf.mu_group.membership));
+       memset(sdata->vif.bss_conf.mu_group.position, 0,
+              sizeof(sdata->vif.bss_conf.mu_group.position));
+       changed |= BSS_CHANGED_MU_GROUPS;
+       sdata->vif.mu_mimo_owner = false;
 
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
 
@@ -2536,7 +2509,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                eth_zero_addr(sdata->u.mgd.bssid);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
-               sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
+               sdata->vif.mu_mimo_owner = false;
+
                mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
                mutex_unlock(&sdata->local->mtx);
@@ -3571,6 +3545,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                elems.ht_cap_elem, elems.ht_operation,
                                elems.vht_operation, bssid, &changed)) {
                mutex_unlock(&local->sta_mtx);
+               sdata_info(sdata,
+                          "failed to follow AP %pM bandwidth change, disconnect\n",
+                          bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DEAUTH_LEAVING,
                                       true, deauth_buf);
@@ -3946,11 +3923,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
                         * We actually lost the connection ... or did we?
                         * Let's make sure!
                         */
-                       wiphy_debug(local->hw.wiphy,
-                                   "%s: No probe response from AP %pM"
-                                   " after %dms, disconnecting.\n",
-                                   sdata->name,
-                                   bssid, probe_wait_ms);
+                       mlme_dbg(sdata,
+                                "No probe response from AP %pM after %dms, disconnecting.\n",
+                                bssid, probe_wait_ms);
 
                        ieee80211_sta_connection_lost(sdata, bssid,
                                WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
@@ -4536,6 +4511,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
+               sdata_info(sdata,
+                          "disconnect from AP %pM for new auth to %pM\n",
+                          ifmgd->associated->bssid, req->bss->bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
@@ -4604,6 +4582,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->associated) {
                u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
 
+               sdata_info(sdata,
+                          "disconnect from AP %pM for new assoc to %pM\n",
+                          ifmgd->associated->bssid, req->bss->bssid);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
index 3ece7d1034c81ae8749cada074fbebecbe06d57f..b54f398cda5d0e2d561f2383f1d049a5410fcf68 100644 (file)
@@ -711,7 +711,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta)
         * computing cur_tp
         */
        tmp_mrs = &mi->r[idx].stats;
-       tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma);
+       tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
        tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
 
        return tmp_cur_tp;
index 3928dbd24e257e68627aa977cc54a19aaa996339..370d677b547b2aa2591bea4302e4994bddfe2649 100644 (file)
@@ -414,15 +414,16 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
            (max_tp_group != MINSTREL_CCK_GROUP))
                return;
 
+       max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
+       max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
+       max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
+
        if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
                cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
                                                    mrs->prob_ewma);
                if (cur_tp_avg > tmp_tp_avg)
                        mi->max_prob_rate = index;
 
-               max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
-               max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
-               max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
                max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
                                                        max_gpr_idx,
                                                        max_gpr_prob);
@@ -431,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
        } else {
                if (mrs->prob_ewma > tmp_prob)
                        mi->max_prob_rate = index;
-               if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma)
+               if (mrs->prob_ewma > max_gpr_prob)
                        mg->max_group_prob_rate = index;
        }
 }
@@ -691,7 +692,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
        if (likely(sta->ampdu_mlme.tid_tx[tid]))
                return;
 
-       ieee80211_start_tx_ba_session(pubsta, tid, 5000);
+       ieee80211_start_tx_ba_session(pubsta, tid, 0);
 }
 
 static void
@@ -871,7 +872,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
         *  - if station is in dynamic SMPS (and streams > 1)
         *  - for fallback rates, to increase chances of getting through
         */
-       if (offset > 0 &&
+       if (offset > 0 ||
            (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC &&
             group->streams > 1)) {
                ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
@@ -1334,7 +1335,8 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta)
        prob = mi->groups[i].rates[j].prob_ewma;
 
        /* convert tp_avg from pkt per second in kbps */
-       tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024;
+       tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
+       tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024;
 
        return tp_avg;
 }
index bc081850ac0e5538241bd1cab37b65aeefd2c244..dc27becb9b71ec6ab3c2f0b94b57c278296f8157 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * 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
@@ -18,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/rcupdate.h>
 #include <linux/export.h>
+#include <linux/bitops.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <asm/unaligned.h>
@@ -122,7 +124,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
        hdr = (void *)(skb->data + rtap_vendor_space);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
-                           RX_FLAG_FAILED_PLCP_CRC))
+                           RX_FLAG_FAILED_PLCP_CRC |
+                           RX_FLAG_ONLY_MONITOR))
                return true;
 
        if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
@@ -507,7 +510,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
                return NULL;
        }
 
-       if (!local->monitors) {
+       if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
                if (should_drop_frame(origskb, present_fcs_len,
                                      rtap_vendor_space)) {
                        dev_kfree_skb(origskb);
@@ -797,6 +800,26 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
+static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
+                                             int index)
+{
+       struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
+       struct sk_buff *tail = skb_peek_tail(frames);
+       struct ieee80211_rx_status *status;
+
+       if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
+               return true;
+
+       if (!tail)
+               return false;
+
+       status = IEEE80211_SKB_RXCB(tail);
+       if (status->flag & RX_FLAG_AMSDU_MORE)
+               return false;
+
+       return true;
+}
+
 static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
                                            struct tid_ampdu_rx *tid_agg_rx,
                                            int index,
@@ -811,7 +834,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
        if (skb_queue_empty(skb_list))
                goto no_frame;
 
-       if (!ieee80211_rx_reorder_ready(skb_list)) {
+       if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                __skb_queue_purge(skb_list);
                goto no_frame;
        }
@@ -825,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
        }
 
 no_frame:
+       tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
        tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
 }
 
@@ -865,7 +889,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
        /* release the buffer until next missing frame */
        index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
-       if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) &&
+       if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
            tid_agg_rx->stored_mpdu_num) {
                /*
                 * No buffers ready to be released, but check whether any
@@ -874,8 +898,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                int skipped = 1;
                for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
                     j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (!ieee80211_rx_reorder_ready(
-                                       &tid_agg_rx->reorder_buf[j])) {
+                       if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
                                skipped++;
                                continue;
                        }
@@ -902,8 +925,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
                                 skipped) & IEEE80211_SN_MASK;
                        skipped = 0;
                }
-       } else while (ieee80211_rx_reorder_ready(
-                               &tid_agg_rx->reorder_buf[index])) {
+       } else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
                                                frames);
                index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
@@ -914,8 +936,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
 
                for (; j != (index - 1) % tid_agg_rx->buf_size;
                     j = (j + 1) % tid_agg_rx->buf_size) {
-                       if (ieee80211_rx_reorder_ready(
-                                       &tid_agg_rx->reorder_buf[j]))
+                       if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
                                break;
                }
 
@@ -986,7 +1007,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
        index = mpdu_seq_num % tid_agg_rx->buf_size;
 
        /* check if we already stored this frame */
-       if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) {
+       if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
                dev_kfree_skb(skb);
                goto out;
        }
@@ -1099,6 +1120,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
+       if (status->flag & RX_FLAG_DUP_VALIDATED)
+               return RX_CONTINUE;
+
        /*
         * Drop duplicate 802.11 retransmissions
         * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
@@ -1753,7 +1777,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
        entry->seq = seq;
        entry->rx_queue = rx_queue;
        entry->last_frag = frag;
-       entry->ccmp = 0;
+       entry->check_sequential_pn = false;
        entry->extra_len = 0;
 
        return entry;
@@ -1849,15 +1873,27 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                                                 rx->seqno_idx, &(rx->skb));
                if (rx->key &&
                    (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP ||
-                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256) &&
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 ||
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP ||
+                    rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) &&
                    ieee80211_has_protected(fc)) {
                        int queue = rx->security_idx;
-                       /* Store CCMP PN so that we can verify that the next
-                        * fragment has a sequential PN value. */
-                       entry->ccmp = 1;
+
+                       /* Store CCMP/GCMP PN so that we can verify that the
+                        * next fragment has a sequential PN value.
+                        */
+                       entry->check_sequential_pn = true;
                        memcpy(entry->last_pn,
                               rx->key->u.ccmp.rx_pn[queue],
                               IEEE80211_CCMP_PN_LEN);
+                       BUILD_BUG_ON(offsetof(struct ieee80211_key,
+                                             u.ccmp.rx_pn) !=
+                                    offsetof(struct ieee80211_key,
+                                             u.gcmp.rx_pn));
+                       BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) !=
+                                    sizeof(rx->key->u.gcmp.rx_pn[queue]));
+                       BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN !=
+                                    IEEE80211_GCMP_PN_LEN);
                }
                return RX_QUEUED;
        }
@@ -1872,15 +1908,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
        }
 
-       /* Verify that MPDUs within one MSDU have sequential PN values.
-        * (IEEE 802.11i, 8.3.3.4.5) */
-       if (entry->ccmp) {
+       /* "The receiver shall discard MSDUs and MMPDUs whose constituent
+        *  MPDU PN values are not incrementing in steps of 1."
+        * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP)
+        * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP)
+        */
+       if (entry->check_sequential_pn) {
                int i;
                u8 pn[IEEE80211_CCMP_PN_LEN], *rpn;
                int queue;
+
                if (!rx->key ||
                    (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP &&
-                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256))
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP &&
+                    rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256))
                        return RX_DROP_UNUSABLE;
                memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN);
                for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -2199,9 +2241,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
-       if (skb_linearize(skb))
-               return RX_DROP_UNUSABLE;
-
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
                                 rx->local->hw.extra_tx_headroom, true);
@@ -2231,7 +2270,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = rx->sdata;
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-       u16 q, hdrlen;
+       u16 ac, q, hdrlen;
 
        hdr = (struct ieee80211_hdr *) skb->data;
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -2290,6 +2329,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        spin_lock_bh(&mppath->state_lock);
                        if (!ether_addr_equal(mppath->mpp, mpp_addr))
                                memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
+                       mppath->exp_time = jiffies;
                        spin_unlock_bh(&mppath->state_lock);
                }
                rcu_read_unlock();
@@ -2300,7 +2340,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            ether_addr_equal(sdata->vif.addr, hdr->addr3))
                return RX_CONTINUE;
 
-       q = ieee80211_select_queue_80211(sdata, skb, hdr);
+       ac = ieee80211_select_queue_80211(sdata, skb, hdr);
+       q = sdata->vif.hw_queue[ac];
        if (ieee80211_queue_stopped(&local->hw, q)) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
                return RX_DROP_MONITOR;
@@ -2738,6 +2779,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                                    opmode, status->band);
                        goto handled;
                }
+               case WLAN_VHT_ACTION_GROUPID_MGMT: {
+                       if (len < IEEE80211_MIN_ACTION_SIZE + 25)
+                               goto invalid;
+                       goto queue;
+               }
                default:
                        break;
                }
@@ -3073,7 +3119,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
        ieee80211_add_rx_radiotap_header(local, skb, rate, needed_headroom,
                                         false);
 
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
@@ -3275,6 +3321,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
        ieee80211_rx_handlers(&rx, &frames);
 }
 
+void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
+                                         u16 ssn, u64 filtered,
+                                         u16 received_mpdus)
+{
+       struct sta_info *sta;
+       struct tid_ampdu_rx *tid_agg_rx;
+       struct sk_buff_head frames;
+       struct ieee80211_rx_data rx = {
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
+       };
+       int i, diff;
+
+       if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
+               return;
+
+       __skb_queue_head_init(&frames);
+
+       sta = container_of(pubsta, struct sta_info, sta);
+
+       rx.sta = sta;
+       rx.sdata = sta->sdata;
+       rx.local = sta->local;
+
+       rcu_read_lock();
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+               goto out;
+
+       spin_lock_bh(&tid_agg_rx->reorder_lock);
+
+       if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
+               int release;
+
+               /* release all frames in the reorder buffer */
+               release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
+                          IEEE80211_SN_MODULO;
+               ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
+                                                release, &frames);
+               /* update ssn to match received ssn */
+               tid_agg_rx->head_seq_num = ssn;
+       } else {
+               ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
+                                                &frames);
+       }
+
+       /* handle the case that received ssn is behind the mac ssn.
+        * it can be tid_agg_rx->buf_size behind and still be valid */
+       diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
+       if (diff >= tid_agg_rx->buf_size) {
+               tid_agg_rx->reorder_buf_filtered = 0;
+               goto release;
+       }
+       filtered = filtered >> diff;
+       ssn += diff;
+
+       /* update bitmap */
+       for (i = 0; i < tid_agg_rx->buf_size; i++) {
+               int index = (ssn + i) % tid_agg_rx->buf_size;
+
+               tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
+               if (filtered & BIT_ULL(i))
+                       tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
+       }
+
+       /* now process also frames that the filter marking released */
+       ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
+
+release:
+       spin_unlock_bh(&tid_agg_rx->reorder_lock);
+
+       ieee80211_rx_handlers(&rx, &frames);
+
+ out:
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
+
 /* main receive path */
 
 static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
@@ -3366,6 +3491,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
                                return false;
                        /* ignore action frames to TDLS-peers */
                        if (ieee80211_is_action(hdr->frame_control) &&
+                           !is_broadcast_ether_addr(bssid) &&
                            !ether_addr_equal(bssid, hdr->addr1))
                                return false;
                }
index a4a4f89d3ba01138c033a13a7d023a04a99e3e6d..d20bab5c146c9d435ee67d6a11eec746db1b1bfa 100644 (file)
@@ -116,6 +116,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
 
                        ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
                        atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
+                       txqi->byte_cnt = 0;
                }
        }
 
@@ -498,11 +499,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo;
+       struct station_info *sinfo;
        int err = 0;
 
        lockdep_assert_held(&local->sta_mtx);
 
+       sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
+       if (!sinfo) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+
        /* check if STA exists already */
        if (sta_info_get_bss(sdata, sta->sta.addr)) {
                err = -EEXIST;
@@ -530,14 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        /* accept BA sessions now */
        clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
-       ieee80211_recalc_min_chandef(sdata);
        ieee80211_sta_debugfs_add(sta);
        rate_control_add_sta_debugfs(sta);
 
-       memset(&sinfo, 0, sizeof(sinfo));
-       sinfo.filled = 0;
-       sinfo.generation = local->sta_generation;
-       cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo->generation = local->sta_generation;
+       cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
 
        sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
 
@@ -557,6 +562,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        __cleanup_single_sta(sta);
  out_err:
        mutex_unlock(&local->sta_mtx);
+       kfree(sinfo);
        rcu_read_lock();
        return err;
 }
@@ -898,7 +904,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       struct station_info sinfo = {};
+       struct station_info *sinfo;
        int ret;
 
        /*
@@ -936,12 +942,14 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 
        sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
 
-       sta_set_sinfo(sta, &sinfo);
-       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
+       sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
+       if (sinfo)
+               sta_set_sinfo(sta, sinfo);
+       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
+       kfree(sinfo);
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
-       ieee80211_recalc_min_chandef(sdata);
 
        cleanup_single_sta(sta);
 }
@@ -1808,14 +1816,17 @@ int sta_info_move_state(struct sta_info *sta,
                        clear_bit(WLAN_STA_AUTH, &sta->_flags);
                break;
        case IEEE80211_STA_AUTH:
-               if (sta->sta_state == IEEE80211_STA_NONE)
+               if (sta->sta_state == IEEE80211_STA_NONE) {
                        set_bit(WLAN_STA_AUTH, &sta->_flags);
-               else if (sta->sta_state == IEEE80211_STA_ASSOC)
+               } else if (sta->sta_state == IEEE80211_STA_ASSOC) {
                        clear_bit(WLAN_STA_ASSOC, &sta->_flags);
+                       ieee80211_recalc_min_chandef(sta->sdata);
+               }
                break;
        case IEEE80211_STA_ASSOC:
                if (sta->sta_state == IEEE80211_STA_AUTH) {
                        set_bit(WLAN_STA_ASSOC, &sta->_flags);
+                       ieee80211_recalc_min_chandef(sta->sdata);
                } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
                        if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                            (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
index d6051629ed155859819a591960183c0062c230d9..053f5c4fa495ba02cd99c5ddb201ce0ad0f7aeff 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002-2005, Devicescape Software, Inc.
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * 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
@@ -167,6 +168,8 @@ struct tid_ampdu_tx {
  *
  * @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an
  *     A-MSDU with individually reported subframes.
+ * @reorder_buf_filtered: bitmap indicating where there are filtered frames in
+ *     the reorder buffer that should be ignored when releasing frames
  * @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.
@@ -194,6 +197,7 @@ struct tid_ampdu_tx {
 struct tid_ampdu_rx {
        struct rcu_head rcu_head;
        spinlock_t reorder_lock;
+       u64 reorder_buf_filtered;
        struct sk_buff_head *reorder_buf;
        unsigned long *reorder_time;
        struct timer_list session_timer;
@@ -212,20 +216,21 @@ struct tid_ampdu_rx {
 /**
  * struct sta_ampdu_mlme - STA aggregation information.
  *
+ * @mtx: mutex to protect all TX data (except non-NULL assignments
+ *     to tid_tx[idx], which are protected by the sta spinlock)
+ *     tid_start_tx is also protected by sta->lock.
  * @tid_rx: aggregation info for Rx per TID -- RCU protected
- * @tid_tx: aggregation info for Tx per TID
- * @tid_start_tx: sessions where start was requested
- * @addba_req_num: number of times addBA request has been sent.
- * @last_addba_req_time: timestamp of the last addBA request.
- * @dialog_token_allocator: dialog token enumerator for each new session;
- * @work: work struct for starting/stopping aggregation
  * @tid_rx_timer_expired: bitmap indicating on which TIDs the
  *     RX timer expired until the work for it runs
  * @tid_rx_stop_requested:  bitmap indicating which BA sessions per TID the
  *     driver requested to close until the work for it runs
- * @mtx: mutex to protect all TX data (except non-NULL assignments
- *     to tid_tx[idx], which are protected by the sta spinlock)
- *     tid_start_tx is also protected by sta->lock.
+ * @agg_session_valid: bitmap indicating which TID has a rx BA session open on
+ * @work: work struct for starting/stopping aggregation
+ * @tid_tx: aggregation info for Tx per TID
+ * @tid_start_tx: sessions where start was requested
+ * @last_addba_req_time: timestamp of the last addBA request.
+ * @addba_req_num: number of times addBA request has been sent.
+ * @dialog_token_allocator: dialog token enumerator for each new session;
  */
 struct sta_ampdu_mlme {
        struct mutex mtx;
@@ -233,6 +238,7 @@ struct sta_ampdu_mlme {
        struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
+       unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        /* tx */
        struct work_struct work;
        struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
index 6101deb805a830a80acccbe05499ca4f4fc33988..8b1b2ea03eb5a13cc291c8d5e389b045e983ee47 100644 (file)
@@ -697,7 +697,7 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
                                         rtap_len, shift);
 
        /* XXX: is this sufficient for BPF? */
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = htons(ETH_P_802_2);
index 0ae207771a5837ff73d359fe4032be26ac4ca358..b3622823bad23b9a34a58b09fea1dd3e067bbcf2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (C) 2016 Intel Deutschland GmbH
  *
  * 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
@@ -142,15 +143,14 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
 /* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
  * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
  * the packet payload). */
-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key)
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn)
 {
-       lockdep_assert_held(&key->u.tkip.txlock);
-
-       pos = write_tkip_iv(pos, key->u.tkip.tx.iv16);
-       *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
-       put_unaligned_le32(key->u.tkip.tx.iv32, pos);
+       pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn));
+       *pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */;
+       put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos);
        return pos + 4;
 }
+EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv);
 
 static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
 {
@@ -250,6 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
        u8 rc4key[16], keyid, *pos = payload;
        int res;
        const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
+       struct tkip_ctx_rx *rx_ctx = &key->u.tkip.rx[queue];
 
        if (payload_len < 12)
                return -1;
@@ -265,37 +266,36 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
        if ((keyid >> 6) != key->conf.keyidx)
                return TKIP_DECRYPT_INVALID_KEYIDX;
 
-       if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
-           (iv32 < key->u.tkip.rx[queue].iv32 ||
-            (iv32 == key->u.tkip.rx[queue].iv32 &&
-             iv16 <= key->u.tkip.rx[queue].iv16)))
+       if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT &&
+           (iv32 < rx_ctx->iv32 ||
+            (iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16)))
                return TKIP_DECRYPT_REPLAY;
 
        if (only_iv) {
                res = TKIP_DECRYPT_OK;
-               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
+               rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
                goto done;
        }
 
-       if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
-           key->u.tkip.rx[queue].iv32 != iv32) {
+       if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT ||
+           rx_ctx->iv32 != iv32) {
                /* IV16 wrapped around - perform TKIP phase 1 */
-               tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
+               tkip_mixing_phase1(tk, &rx_ctx->ctx, ta, iv32);
        }
        if (key->local->ops->update_tkip_key &&
            key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
-           key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
+           rx_ctx->ctx.state != TKIP_STATE_PHASE1_HW_UPLOADED) {
                struct ieee80211_sub_if_data *sdata = key->sdata;
 
                if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        sdata = container_of(key->sdata->bss,
                                        struct ieee80211_sub_if_data, u.ap);
                drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
-                               iv32, key->u.tkip.rx[queue].p1k);
-               key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
+                               iv32, rx_ctx->ctx.p1k);
+               rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
        }
 
-       tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
+       tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key);
 
        res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
  done:
index e3ecb659b90af6002966d74acdb05b05e3a0be4d..a1bcbfbefe7c32ca5e0fe6d080818acebb624b9b 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/crypto.h>
 #include "key.h"
 
-u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
-
 int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
                                struct ieee80211_key *key,
                                struct sk_buff *skb,
index a6b4442776a0519251b1a7650007343a3541181e..2b0a17ee907abff27d2fef4c93e8d2a03eda4c17 100644 (file)
 #define KEY_PR_FMT     " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d"
 #define KEY_PR_ARG     __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx
 
-
+#define AMPDU_ACTION_ENTRY     __field(enum ieee80211_ampdu_mlme_action,               \
+                                       ieee80211_ampdu_mlme_action)                    \
+                               STA_ENTRY                                               \
+                               __field(u16, tid)                                       \
+                               __field(u16, ssn)                                       \
+                               __field(u8, buf_size)                                   \
+                               __field(bool, amsdu)                                    \
+                               __field(u16, timeout)
+#define AMPDU_ACTION_ASSIGN    STA_NAMED_ASSIGN(params->sta);                          \
+                               __entry->tid = params->tid;                             \
+                               __entry->ssn = params->ssn;                             \
+                               __entry->buf_size = params->buf_size;                   \
+                               __entry->amsdu = params->amsdu;                         \
+                               __entry->timeout = params->timeout;
+#define AMPDU_ACTION_PR_FMT    STA_PR_FMT " tid %d, ssn %d, buf_size %u, amsdu %d, timeout %d"
+#define AMPDU_ACTION_PR_ARG    STA_PR_ARG, __entry->tid, __entry->ssn,                 \
+                               __entry->buf_size, __entry->amsdu, __entry->timeout
 
 /*
  * Tracing for driver callbacks.
@@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
 TRACE_EVENT(drv_ampdu_action,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
-                enum ieee80211_ampdu_mlme_action action,
-                struct ieee80211_sta *sta, u16 tid,
-                u16 *ssn, u8 buf_size, bool amsdu),
+                struct ieee80211_ampdu_params *params),
 
-       TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu),
+       TP_ARGS(local, sdata, params),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
-               STA_ENTRY
-               __field(u32, action)
-               __field(u16, tid)
-               __field(u16, ssn)
-               __field(u8, buf_size)
-               __field(bool, amsdu)
                VIF_ENTRY
+               AMPDU_ACTION_ENTRY
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
                VIF_ASSIGN;
-               STA_ASSIGN;
-               __entry->action = action;
-               __entry->tid = tid;
-               __entry->ssn = ssn ? *ssn : 0;
-               __entry->buf_size = buf_size;
-               __entry->amsdu = amsdu;
+               AMPDU_ACTION_ASSIGN;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d",
-               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
-               __entry->tid, __entry->buf_size, __entry->amsdu
+               LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG
        )
 );
 
index 3311ce0f3d6c2f9c93c075458159935c631d144d..62ad5321257d0679918c0f1e21ed716b221a3bf4 100644 (file)
@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 
        info->control.short_preamble = txrc.short_preamble;
 
+       /* don't ask rate control when rate already injected via radiotap */
+       if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
+               return TX_CONTINUE;
+
        if (tx->sta)
                assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
 
@@ -1266,7 +1270,11 @@ static void ieee80211_drv_tx(struct ieee80211_local *local,
        if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
                netif_stop_subqueue(sdata->dev, ac);
 
-       skb_queue_tail(&txqi->queue, skb);
+       spin_lock_bh(&txqi->queue.lock);
+       txqi->byte_cnt += skb->len;
+       __skb_queue_tail(&txqi->queue, skb);
+       spin_unlock_bh(&txqi->queue.lock);
+
        drv_wake_tx_queue(local, txqi);
 
        return;
@@ -1294,6 +1302,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
        if (!skb)
                goto out;
 
+       txqi->byte_cnt -= skb->len;
+
        atomic_dec(&sdata->txqs_len[ac]);
        if (__netif_subqueue_stopped(sdata->dev, ac))
                ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
@@ -1665,15 +1675,24 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
        ieee80211_tx(sdata, sta, skb, false);
 }
 
-static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
+static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
+                                       struct sk_buff *skb)
 {
        struct ieee80211_radiotap_iterator iterator;
        struct ieee80211_radiotap_header *rthdr =
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_supported_band *sband =
+               local->hw.wiphy->bands[info->band];
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
                                                   NULL);
        u16 txflags;
+       u16 rate = 0;
+       bool rate_found = false;
+       u8 rate_retries = 0;
+       u16 rate_flags = 0;
+       u8 mcs_known, mcs_flags;
+       int i;
 
        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
                       IEEE80211_TX_CTL_DONTFRAG;
@@ -1724,6 +1743,35 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
                                info->flags |= IEEE80211_TX_CTL_NO_ACK;
                        break;
 
+               case IEEE80211_RADIOTAP_RATE:
+                       rate = *iterator.this_arg;
+                       rate_flags = 0;
+                       rate_found = true;
+                       break;
+
+               case IEEE80211_RADIOTAP_DATA_RETRIES:
+                       rate_retries = *iterator.this_arg;
+                       break;
+
+               case IEEE80211_RADIOTAP_MCS:
+                       mcs_known = iterator.this_arg[0];
+                       mcs_flags = iterator.this_arg[1];
+                       if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
+                               break;
+
+                       rate_found = true;
+                       rate = iterator.this_arg[2];
+                       rate_flags = IEEE80211_TX_RC_MCS;
+
+                       if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
+                           mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
+                               rate_flags |= IEEE80211_TX_RC_SHORT_GI;
+
+                       if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
+                           mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
+                               rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+                       break;
+
                /*
                 * Please update the file
                 * Documentation/networking/mac80211-injection.txt
@@ -1738,6 +1786,32 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
        if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
                return false;
 
+       if (rate_found) {
+               info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
+
+               for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+                       info->control.rates[i].idx = -1;
+                       info->control.rates[i].flags = 0;
+                       info->control.rates[i].count = 0;
+               }
+
+               if (rate_flags & IEEE80211_TX_RC_MCS) {
+                       info->control.rates[0].idx = rate;
+               } else {
+                       for (i = 0; i < sband->n_bitrates; i++) {
+                               if (rate * 5 != sband->bitrates[i].bitrate)
+                                       continue;
+
+                               info->control.rates[0].idx = i;
+                               break;
+                       }
+               }
+
+               info->control.rates[0].flags = rate_flags;
+               info->control.rates[0].count = min_t(u8, rate_retries + 1,
+                                                    local->hw.max_rate_tries);
+       }
+
        /*
         * remove the radiotap header
         * iterator->_max_length was sanity-checked against
@@ -1818,10 +1892,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
                      IEEE80211_TX_CTL_INJECTED;
 
-       /* process and remove the injection radiotap header */
-       if (!ieee80211_parse_tx_radiotap(skb))
-               goto fail;
-
        rcu_read_lock();
 
        /*
@@ -1883,6 +1953,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
                goto fail_rcu;
 
        info->band = chandef->chan->band;
+
+       /* process and remove the injection radiotap header */
+       if (!ieee80211_parse_tx_radiotap(local, skb))
+               goto fail_rcu;
+
        ieee80211_xmit(sdata, NULL, skb);
        rcu_read_unlock();
 
@@ -2099,8 +2174,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
                                        mpp_lookup = true;
                        }
 
-                       if (mpp_lookup)
+                       if (mpp_lookup) {
                                mppath = mpp_path_lookup(sdata, skb->data);
+                               if (mppath)
+                                       mppath->exp_time = jiffies;
+                       }
 
                        if (mppath && mpath)
                                mesh_path_del(mpath->sdata, mpath->dst);
@@ -2380,7 +2458,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
        /* Update skb pointers to various headers since this modified frame
         * is going to go through Linux networking code that may potentially
         * need things like pointer to IP header. */
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb_set_network_header(skb, nh_pos);
        skb_set_transport_header(skb, h_pos);
 
@@ -3895,9 +3973,9 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
 {
        int ac = ieee802_1d_to_ac[tid & 7];
 
-       skb_set_mac_header(skb, 0);
-       skb_set_network_header(skb, 0);
-       skb_set_transport_header(skb, 0);
+       skb_reset_mac_header(skb);
+       skb_reset_network_header(skb);
+       skb_reset_transport_header(skb);
 
        skb_set_queue_mapping(skb, ac);
        skb->priority = tid;
index 58f58bd5202ff5ad99630bc7584a8afeb8c2cf26..7390de4946a9d8572567a4fb451887530b042a16 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2015  Intel Deutschland GmbH
+ * Copyright (C) 2015-2016     Intel Deutschland GmbH
  *
  * 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
@@ -1928,6 +1928,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_IDLE |
                          BSS_CHANGED_TXPOWER;
 
+               if (sdata->vif.mu_mimo_owner)
+                       changed |= BSS_CHANGED_MU_GROUPS;
+
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
                        changed |= BSS_CHANGED_ASSOC |
@@ -2371,10 +2374,23 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 
        switch (chandef->width) {
        case NL80211_CHAN_WIDTH_160:
-               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+               /*
+                * Convert 160 MHz channel width to new style as interop
+                * workaround.
+                */
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+               vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
+               if (chandef->chan->center_freq < chandef->center_freq1)
+                       vht_oper->center_freq_seg1_idx -= 8;
+               else
+                       vht_oper->center_freq_seg1_idx += 8;
                break;
        case NL80211_CHAN_WIDTH_80P80:
-               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+               /*
+                * Convert 80+80 MHz channel width to new style as interop
+                * workaround.
+                */
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
                break;
        case NL80211_CHAN_WIDTH_80:
                vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
@@ -2390,17 +2406,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
        return pos + sizeof(struct ieee80211_vht_operation);
 }
 
-void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                 const struct ieee80211_ht_operation *ht_oper,
-                                 struct cfg80211_chan_def *chandef)
+bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
+                              struct cfg80211_chan_def *chandef)
 {
        enum nl80211_channel_type channel_type;
 
-       if (!ht_oper) {
-               cfg80211_chandef_create(chandef, control_chan,
-                                       NL80211_CHAN_NO_HT);
-               return;
-       }
+       if (!ht_oper)
+               return false;
 
        switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_NONE:
@@ -2414,42 +2426,66 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                break;
        default:
                channel_type = NL80211_CHAN_NO_HT;
+               return false;
        }
 
-       cfg80211_chandef_create(chandef, control_chan, channel_type);
+       cfg80211_chandef_create(chandef, chandef->chan, channel_type);
+       return true;
 }
 
-void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
-                                  const struct ieee80211_vht_operation *oper,
-                                  struct cfg80211_chan_def *chandef)
+bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
+                               struct cfg80211_chan_def *chandef)
 {
+       struct cfg80211_chan_def new = *chandef;
+       int cf1, cf2;
+
        if (!oper)
-               return;
+               return false;
 
-       chandef->chan = control_chan;
+       cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+                                            chandef->chan->band);
+       cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+                                            chandef->chan->band);
 
        switch (oper->chan_width) {
        case IEEE80211_VHT_CHANWIDTH_USE_HT:
                break;
        case IEEE80211_VHT_CHANWIDTH_80MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_80;
+               new.width = NL80211_CHAN_WIDTH_80;
+               new.center_freq1 = cf1;
+               /* If needed, adjust based on the newer interop workaround. */
+               if (oper->center_freq_seg2_idx) {
+                       unsigned int diff;
+
+                       diff = abs(oper->center_freq_seg2_idx -
+                                  oper->center_freq_seg1_idx);
+                       if (diff == 8) {
+                               new.width = NL80211_CHAN_WIDTH_160;
+                               new.center_freq1 = cf2;
+                       } else if (diff > 8) {
+                               new.width = NL80211_CHAN_WIDTH_80P80;
+                               new.center_freq2 = cf2;
+                       }
+               }
                break;
        case IEEE80211_VHT_CHANWIDTH_160MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_160;
+               new.width = NL80211_CHAN_WIDTH_160;
+               new.center_freq1 = cf1;
                break;
        case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
-               chandef->width = NL80211_CHAN_WIDTH_80P80;
+               new.width = NL80211_CHAN_WIDTH_80P80;
+               new.center_freq1 = cf1;
+               new.center_freq2 = cf2;
                break;
        default:
-               break;
+               return false;
        }
 
-       chandef->center_freq1 =
-               ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
-                                              control_chan->band);
-       chandef->center_freq2 =
-               ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
-                                              control_chan->band);
+       if (!cfg80211_chandef_valid(&new))
+               return false;
+
+       *chandef = new;
+       return true;
 }
 
 int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
@@ -2672,6 +2708,18 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
                sband = local->hw.wiphy->bands[status->band];
                bitrate = sband->bitrates[status->rate_idx].bitrate;
                ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
+
+               if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+                       /* TODO: handle HT/VHT preambles */
+                       if (status->band == IEEE80211_BAND_5GHZ) {
+                               ts += 20 << shift;
+                               mpdu_offset += 2;
+                       } else if (status->flag & RX_FLAG_SHORTPRE) {
+                               ts += 96;
+                       } else {
+                               ts += 192;
+                       }
+               }
        }
 
        rate = cfg80211_calculate_bitrate(&ri);
@@ -3357,3 +3405,17 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
                txqi->txq.ac = IEEE80211_AC_BE;
        }
 }
+
+void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
+                            unsigned long *frame_cnt,
+                            unsigned long *byte_cnt)
+{
+       struct txq_info *txqi = to_txq_info(txq);
+
+       if (frame_cnt)
+               *frame_cnt = txqi->queue.qlen;
+
+       if (byte_cnt)
+               *byte_cnt = txqi->byte_cnt;
+}
+EXPORT_SYMBOL(ieee80211_txq_get_depth);
index c38b2f07a919e20dc22363fe80911f5f5a0b004f..89e04d55aa1832e522f8e8f9619bfabc8c81ee93 100644 (file)
@@ -1,6 +1,9 @@
 /*
  * VHT handling
  *
+ * Portions of this file
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
+ *
  * 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.
@@ -278,6 +281,23 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        }
 
        sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
+
+       /* If HT IE reported 3839 bytes only, stay with that size. */
+       if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839)
+               return;
+
+       switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
+               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
+               break;
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
+               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
+               break;
+       case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
+       default:
+               sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
+               break;
+       }
 }
 
 enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
@@ -425,6 +445,43 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
        return changed;
 }
 
+void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
+                                struct ieee80211_mgmt *mgmt)
+{
+       struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
+
+       if (!sdata->vif.mu_mimo_owner)
+               return;
+
+       if (!memcmp(mgmt->u.action.u.vht_group_notif.position,
+                   bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) &&
+           !memcmp(mgmt->u.action.u.vht_group_notif.membership,
+                   bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN))
+               return;
+
+       memcpy(bss_conf->mu_group.membership,
+              mgmt->u.action.u.vht_group_notif.membership,
+              WLAN_MEMBERSHIP_LEN);
+       memcpy(bss_conf->mu_group.position,
+              mgmt->u.action.u.vht_group_notif.position,
+              WLAN_USER_POSITION_LEN);
+
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
+}
+
+void ieee80211_update_mu_groups(struct ieee80211_vif *vif,
+                               const u8 *membership, const u8 *position)
+{
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       if (WARN_ON_ONCE(!vif->mu_mimo_owner))
+               return;
+
+       memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN);
+       memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN);
+}
+EXPORT_SYMBOL_GPL(ieee80211_update_mu_groups);
+
 void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
                                 struct sta_info *sta, u8 opmode,
                                 enum ieee80211_band band)
index d824c38971ed53ff702669c9bce0f4a86495bdd0..18848258adde8bdf855829cbce15d388d84a3eef 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (C) 2016 Intel Deutschland GmbH
  *
  * 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
@@ -183,7 +184,6 @@ mic_fail_no_key:
        return RX_DROP_UNUSABLE;
 }
 
-
 static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -191,6 +191,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        unsigned int hdrlen;
        int len, tail;
+       u64 pn;
        u8 *pos;
 
        if (info->control.hw_key &&
@@ -222,12 +223,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
                return 0;
 
        /* Increase IV for the frame */
-       spin_lock(&key->u.tkip.txlock);
-       key->u.tkip.tx.iv16++;
-       if (key->u.tkip.tx.iv16 == 0)
-               key->u.tkip.tx.iv32++;
-       pos = ieee80211_tkip_add_iv(pos, key);
-       spin_unlock(&key->u.tkip.txlock);
+       pn = atomic64_inc_return(&key->conf.tx_pn);
+       pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
 
        /* hwaccel - with software IV */
        if (info->control.hw_key)
index e8cab5bb80c664669f9c34b36e5e9178db83ae13..87da85ae5a6b1ace5f6cdda2c0a9b8e01c8c5ba6 100644 (file)
@@ -218,7 +218,6 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw)
 
        tasklet_kill(&local->tasklet);
        flush_workqueue(local->workqueue);
-       destroy_workqueue(local->workqueue);
 
        rtnl_lock();
 
@@ -226,6 +225,7 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw)
 
        rtnl_unlock();
 
+       destroy_workqueue(local->workqueue);
        wpan_phy_unregister(local->phy);
 }
 EXPORT_SYMBOL(ieee802154_unregister_hw);
index fb31aa87de817f9de8f30f6adae052c7eb53247b..644a8da6d4bd9fc2583880bca2e22618ec970b4b 100644 (file)
@@ -227,5 +227,6 @@ static void __exit mpls_iptunnel_exit(void)
 }
 module_exit(mpls_iptunnel_exit);
 
+MODULE_ALIAS_RTNL_LWT(MPLS);
 MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels");
 MODULE_LICENSE("GPL v2");
index 8c067e6663a14adf43212eda165c33240bb87985..95e757c377f9598429f136ebd3c951f1bb9da11b 100644 (file)
@@ -891,7 +891,7 @@ config NETFILTER_XT_TARGET_TEE
        depends on IPV6 || IPV6=n
        depends on !NF_CONNTRACK || NF_CONNTRACK
        select NF_DUP_IPV4
-       select NF_DUP_IPV6 if IP6_NF_IPTABLES != n
+       select NF_DUP_IPV6 if IPV6
        ---help---
        This option adds a "TEE" target with which a packet can be cloned and
        this clone be rerouted to another nexthop.
index 0328f725069332d0c84bbb3108192a2a28beeb2a..299edc6add5a6ac2c729e4caa6f9550b1cebe3df 100644 (file)
@@ -605,17 +605,13 @@ static const struct file_operations ip_vs_app_fops = {
 
 int __net_init ip_vs_app_net_init(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        INIT_LIST_HEAD(&ipvs->app_list);
-       proc_create("ip_vs_app", 0, net->proc_net, &ip_vs_app_fops);
+       proc_create("ip_vs_app", 0, ipvs->net->proc_net, &ip_vs_app_fops);
        return 0;
 }
 
 void __net_exit ip_vs_app_net_cleanup(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        unregister_ip_vs_app(ipvs, NULL /* all */);
-       remove_proc_entry("ip_vs_app", net->proc_net);
+       remove_proc_entry("ip_vs_app", ipvs->net->proc_net);
 }
index e7c1b052c2a3ac9cccd54ed1e4558d36bde080c4..404b2a4f4b5be90f630a20ff592e030f1ed4d671 100644 (file)
@@ -1376,8 +1376,6 @@ static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
        struct ip_vs_pe *old_pe;
        struct netns_ipvs *ipvs = svc->ipvs;
 
-       pr_info("%s: enter\n", __func__);
-
        /* Count only IPv4 services for old get/setsockopt interface */
        if (svc->af == AF_INET)
                ipvs->num_services--;
@@ -3947,7 +3945,6 @@ static struct notifier_block ip_vs_dst_notifier = {
 
 int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
        int i, idx;
 
        /* Initialize rs_table */
@@ -3974,9 +3971,9 @@ int __net_init ip_vs_control_net_init(struct netns_ipvs *ipvs)
 
        spin_lock_init(&ipvs->tot_stats.lock);
 
-       proc_create("ip_vs", 0, net->proc_net, &ip_vs_info_fops);
-       proc_create("ip_vs_stats", 0, net->proc_net, &ip_vs_stats_fops);
-       proc_create("ip_vs_stats_percpu", 0, net->proc_net,
+       proc_create("ip_vs", 0, ipvs->net->proc_net, &ip_vs_info_fops);
+       proc_create("ip_vs_stats", 0, ipvs->net->proc_net, &ip_vs_stats_fops);
+       proc_create("ip_vs_stats_percpu", 0, ipvs->net->proc_net,
                    &ip_vs_stats_percpu_fops);
 
        if (ip_vs_control_net_init_sysctl(ipvs))
@@ -3991,13 +3988,11 @@ err:
 
 void __net_exit ip_vs_control_net_cleanup(struct netns_ipvs *ipvs)
 {
-       struct net *net = ipvs->net;
-
        ip_vs_trash_cleanup(ipvs);
        ip_vs_control_net_cleanup_sysctl(ipvs);
-       remove_proc_entry("ip_vs_stats_percpu", net->proc_net);
-       remove_proc_entry("ip_vs_stats", net->proc_net);
-       remove_proc_entry("ip_vs", net->proc_net);
+       remove_proc_entry("ip_vs_stats_percpu", ipvs->net->proc_net);
+       remove_proc_entry("ip_vs_stats", ipvs->net->proc_net);
+       remove_proc_entry("ip_vs", ipvs->net->proc_net);
        free_percpu(ipvs->tot_stats.cpustats);
 }
 
index a3f5cd9b3c4c3a295466b3492884ce2d47868162..dc196a0f501def30c16ee0d965b1b1938028f94a 100644 (file)
@@ -531,8 +531,6 @@ static inline int ip_vs_tunnel_xmit_prepare(struct sk_buff *skb,
        if (ret == NF_ACCEPT) {
                nf_reset(skb);
                skb_forward_csum(skb);
-               if (!skb->sk)
-                       skb_sender_cpu_clear(skb);
        }
        return ret;
 }
@@ -573,8 +571,6 @@ static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
 
        if (!local) {
                skb_forward_csum(skb);
-               if (!skb->sk)
-                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, cp->ipvs->net, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output);
        } else
@@ -595,8 +591,6 @@ static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb,
        if (!local) {
                ip_vs_drop_early_demux_sk(skb);
                skb_forward_csum(skb);
-               if (!skb->sk)
-                       skb_sender_cpu_clear(skb);
                NF_HOOK(pf, NF_INET_LOCAL_OUT, cp->ipvs->net, NULL, skb,
                        NULL, skb_dst(skb)->dev, dst_output);
        } else
index 58882de06bd74f254033e0f06521f264c18c8d44..f60b4fdeeb8cc4fc600506ecc58e2bdc4cad1654 100644 (file)
@@ -1412,6 +1412,7 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
                }
                spin_unlock(lockp);
                local_bh_enable();
+               cond_resched();
        }
 
        for_each_possible_cpu(cpu) {
@@ -1424,6 +1425,7 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
                                set_bit(IPS_DYING_BIT, &ct->status);
                }
                spin_unlock_bh(&pcpu->lock);
+               cond_resched();
        }
        return NULL;
 found:
@@ -1440,6 +1442,8 @@ void nf_ct_iterate_cleanup(struct net *net,
        struct nf_conn *ct;
        unsigned int bucket = 0;
 
+       might_sleep();
+
        while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) {
                /* Time to push up daises... */
                if (del_timer(&ct->timeout))
@@ -1448,6 +1452,7 @@ void nf_ct_iterate_cleanup(struct net *net,
                /* ... else the timer will get him soon. */
 
                nf_ct_put(ct);
+               cond_resched();
        }
 }
 EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
index 8414ee1a0319844bbf2c9dcec7492080fa286d09..7ec69723940f120fb783160ebaa6889cf24fcb3b 100644 (file)
@@ -31,7 +31,6 @@ void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif)
                skb_push(skb, skb->mac_len);
 
        skb->dev = dev;
-       skb_sender_cpu_clear(skb);
        dev_queue_xmit(skb);
 }
 EXPORT_SYMBOL_GPL(nf_dup_netdev_egress);
index a7ba23353dab938b4048095e50da9eb463dfc477..2278d9ab723bf1c3a2b199db6fc9519e9c59e1be 100644 (file)
@@ -127,13 +127,6 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group)
 }
 EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
 
-struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
-                                   u32 dst_portid, gfp_t gfp_mask)
-{
-       return netlink_alloc_skb(net->nfnl, size, dst_portid, gfp_mask);
-}
-EXPORT_SYMBOL_GPL(nfnetlink_alloc_skb);
-
 int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
                   unsigned int group, int echo, gfp_t flags)
 {
@@ -311,14 +304,14 @@ replay:
 #endif
                {
                        nfnl_unlock(subsys_id);
-                       netlink_ack(skb, nlh, -EOPNOTSUPP);
+                       netlink_ack(oskb, nlh, -EOPNOTSUPP);
                        return kfree_skb(skb);
                }
        }
 
        if (!ss->commit || !ss->abort) {
                nfnl_unlock(subsys_id);
-               netlink_ack(skb, nlh, -EOPNOTSUPP);
+               netlink_ack(oskb, nlh, -EOPNOTSUPP);
                return kfree_skb(skb);
        }
 
@@ -328,10 +321,12 @@ replay:
                nlh = nlmsg_hdr(skb);
                err = 0;
 
-               if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
-                   skb->len < nlh->nlmsg_len) {
-                       err = -EINVAL;
-                       goto ack;
+               if (nlh->nlmsg_len < NLMSG_HDRLEN ||
+                   skb->len < nlh->nlmsg_len ||
+                   nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
+                       nfnl_err_reset(&err_list);
+                       status |= NFNL_BATCH_FAILURE;
+                       goto done;
                }
 
                /* Only requests are handled by the kernel */
@@ -406,7 +401,7 @@ ack:
                                 * pointing to the batch header.
                                 */
                                nfnl_err_reset(&err_list);
-                               netlink_ack(skb, nlmsg_hdr(oskb), -ENOMEM);
+                               netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM);
                                status |= NFNL_BATCH_FAILURE;
                                goto done;
                        }
index 94837d236ab0e9a2fc3baa5d8fe7688a1b399afc..2671b9deb103735ff203999286a8cfbdde434f12 100644 (file)
@@ -312,7 +312,7 @@ static void ctnl_untimeout(struct net *net, struct ctnl_timeout *timeout)
                        hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode)
                                untimeout(h, timeout);
                }
-               nf_conntrack_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
+               spin_unlock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
        }
        local_bh_enable();
 }
index 8ca932057c13b32e39161de128edc81d21219ff6..11f81c8385fcf80daac88b5899bc4e2964f5b796 100644 (file)
@@ -330,14 +330,13 @@ nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size,
         * message.  WARNING: has to be <= 128k due to slab restrictions */
 
        n = max(inst_size, pkt_size);
-       skb = nfnetlink_alloc_skb(net, n, peer_portid, GFP_ATOMIC);
+       skb = alloc_skb(n, GFP_ATOMIC);
        if (!skb) {
                if (n > pkt_size) {
                        /* try to allocate only as much as we need for current
                         * packet */
 
-                       skb = nfnetlink_alloc_skb(net, pkt_size,
-                                                 peer_portid, GFP_ATOMIC);
+                       skb = alloc_skb(pkt_size, GFP_ATOMIC);
                }
        }
 
index 1d3936587ace28c0f8725a4022b5c93255b6e0fc..75429997ed41be3af40fafc0e8dea04c2f374d8d 100644 (file)
@@ -301,7 +301,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                           __be32 **packet_id_ptr)
 {
        size_t size;
-       size_t data_len = 0, cap_len = 0, rem_len = 0;
+       size_t data_len = 0, cap_len = 0;
        unsigned int hlen = 0;
        struct sk_buff *skb;
        struct nlattr *nla;
@@ -361,7 +361,6 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                hlen = min_t(unsigned int, hlen, data_len);
                size += sizeof(struct nlattr) + hlen;
                cap_len = entskb->len;
-               rem_len = data_len - hlen;
                break;
        }
 
@@ -386,8 +385,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                        size += nla_total_size(seclen);
        }
 
-       skb = __netlink_alloc_skb(net->nfnl, size, rem_len, queue->peer_portid,
-                                 GFP_ATOMIC);
+       skb = alloc_skb(size, GFP_ATOMIC);
        if (!skb) {
                skb_tx_error(entskb);
                return NULL;
index c7808fc19719c4687457d039586f9708179b804e..c9743f78f21999ae01ed735a63c4e856e79cdc37 100644 (file)
@@ -100,7 +100,7 @@ static int nft_counter_init(const struct nft_ctx *ctx,
 
        cpu_stats = netdev_alloc_pcpu_stats(struct nft_counter_percpu);
        if (cpu_stats == NULL)
-               return ENOMEM;
+               return -ENOMEM;
 
        preempt_disable();
        this_cpu = this_cpu_ptr(cpu_stats);
@@ -138,7 +138,7 @@ static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
        cpu_stats = __netdev_alloc_pcpu_stats(struct nft_counter_percpu,
                                              GFP_ATOMIC);
        if (cpu_stats == NULL)
-               return ENOMEM;
+               return -ENOMEM;
 
        preempt_disable();
        this_cpu = this_cpu_ptr(cpu_stats);
index 9aea747b43eab7b91b3b458cd0a5b89f2d9e6927..81b5ad6165ac7e4c51101fc696ee0e5447996fef 100644 (file)
@@ -17,7 +17,9 @@
 #include <net/netfilter/nft_masq.h>
 
 const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
-       [NFTA_MASQ_FLAGS]       = { .type = NLA_U32 },
+       [NFTA_MASQ_FLAGS]               = { .type = NLA_U32 },
+       [NFTA_MASQ_REG_PROTO_MIN]       = { .type = NLA_U32 },
+       [NFTA_MASQ_REG_PROTO_MAX]       = { .type = NLA_U32 },
 };
 EXPORT_SYMBOL_GPL(nft_masq_policy);
 
@@ -40,6 +42,7 @@ int nft_masq_init(const struct nft_ctx *ctx,
                  const struct nft_expr *expr,
                  const struct nlattr * const tb[])
 {
+       u32 plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
        struct nft_masq *priv = nft_expr_priv(expr);
        int err;
 
@@ -47,12 +50,32 @@ int nft_masq_init(const struct nft_ctx *ctx,
        if (err)
                return err;
 
-       if (tb[NFTA_MASQ_FLAGS] == NULL)
-               return 0;
-
-       priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
-       if (priv->flags & ~NF_NAT_RANGE_MASK)
-               return -EINVAL;
+       if (tb[NFTA_MASQ_FLAGS]) {
+               priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
+               if (priv->flags & ~NF_NAT_RANGE_MASK)
+                       return -EINVAL;
+       }
+
+       if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
+               priv->sreg_proto_min =
+                       nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]);
+
+               err = nft_validate_register_load(priv->sreg_proto_min, plen);
+               if (err < 0)
+                       return err;
+
+               if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
+                       priv->sreg_proto_max =
+                               nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]);
+
+                       err = nft_validate_register_load(priv->sreg_proto_max,
+                                                        plen);
+                       if (err < 0)
+                               return err;
+               } else {
+                       priv->sreg_proto_max = priv->sreg_proto_min;
+               }
+       }
 
        return 0;
 }
@@ -62,12 +85,18 @@ int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_masq *priv = nft_expr_priv(expr);
 
-       if (priv->flags == 0)
-               return 0;
-
-       if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
+       if (priv->flags != 0 &&
+           nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
                goto nla_put_failure;
 
+       if (priv->sreg_proto_min) {
+               if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
+                                     priv->sreg_proto_min) ||
+                   nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
+                                     priv->sreg_proto_max))
+                       goto nla_put_failure;
+       }
+
        return 0;
 
 nla_put_failure:
index fe885bf271c5d7f0a1cb20f3ea827d7103cfcb55..16c50b0dd426840f79bda0bb3ebbd28ecb2845e5 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
 
+static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
+
 void nft_meta_get_eval(const struct nft_expr *expr,
                       struct nft_regs *regs,
                       const struct nft_pktinfo *pkt)
@@ -181,6 +183,11 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
                break;
 #endif
+       case NFT_META_PRANDOM: {
+               struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
+               *dest = prandom_u32_state(state);
+               break;
+       }
        default:
                WARN_ON(1);
                goto err;
@@ -277,6 +284,10 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
        case NFT_META_OIFNAME:
                len = IFNAMSIZ;
                break;
+       case NFT_META_PRANDOM:
+               prandom_init_once(&nft_prandom_state);
+               len = sizeof(u32);
+               break;
        default:
                return -EOPNOTSUPP;
        }
index c8a0b7da5ff4607ee6d8f163e9677cae1505a976..d0cd2b9bf84463af1028d00ce87d2f5aab1dc736 100644 (file)
@@ -694,12 +694,45 @@ EXPORT_SYMBOL(xt_free_table_info);
 struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
                                    const char *name)
 {
-       struct xt_table *t;
+       struct xt_table *t, *found = NULL;
 
        mutex_lock(&xt[af].mutex);
        list_for_each_entry(t, &net->xt.tables[af], list)
                if (strcmp(t->name, name) == 0 && try_module_get(t->me))
                        return t;
+
+       if (net == &init_net)
+               goto out;
+
+       /* Table doesn't exist in this netns, re-try init */
+       list_for_each_entry(t, &init_net.xt.tables[af], list) {
+               if (strcmp(t->name, name))
+                       continue;
+               if (!try_module_get(t->me))
+                       return NULL;
+
+               mutex_unlock(&xt[af].mutex);
+               if (t->table_init(net) != 0) {
+                       module_put(t->me);
+                       return NULL;
+               }
+
+               found = t;
+
+               mutex_lock(&xt[af].mutex);
+               break;
+       }
+
+       if (!found)
+               goto out;
+
+       /* and once again: */
+       list_for_each_entry(t, &net->xt.tables[af], list)
+               if (strcmp(t->name, name) == 0)
+                       return t;
+
+       module_put(found->me);
+ out:
        mutex_unlock(&xt[af].mutex);
        return NULL;
 }
@@ -1170,20 +1203,20 @@ static const struct file_operations xt_target_ops = {
 #endif /* CONFIG_PROC_FS */
 
 /**
- * xt_hook_link - set up hooks for a new table
+ * xt_hook_ops_alloc - set up hooks for a new table
  * @table:     table with metadata needed to set up hooks
  * @fn:                Hook function
  *
- * This function will take care of creating and registering the necessary
- * Netfilter hooks for XT tables.
+ * This function will create the nf_hook_ops that the x_table needs
+ * to hand to xt_hook_link_net().
  */
-struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
+struct nf_hook_ops *
+xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
 {
        unsigned int hook_mask = table->valid_hooks;
        uint8_t i, num_hooks = hweight32(hook_mask);
        uint8_t hooknum;
        struct nf_hook_ops *ops;
-       int ret;
 
        ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
        if (ops == NULL)
@@ -1200,27 +1233,9 @@ struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
                ++i;
        }
 
-       ret = nf_register_hooks(ops, num_hooks);
-       if (ret < 0) {
-               kfree(ops);
-               return ERR_PTR(ret);
-       }
-
        return ops;
 }
-EXPORT_SYMBOL_GPL(xt_hook_link);
-
-/**
- * xt_hook_unlink - remove hooks for a table
- * @ops:       nf_hook_ops array as returned by nf_hook_link
- * @hook_mask: the very same mask that was passed to nf_hook_link
- */
-void xt_hook_unlink(const struct xt_table *table, struct nf_hook_ops *ops)
-{
-       nf_unregister_hooks(ops, hweight32(table->valid_hooks));
-       kfree(ops);
-}
-EXPORT_SYMBOL_GPL(xt_hook_unlink);
+EXPORT_SYMBOL_GPL(xt_hook_ops_alloc);
 
 int xt_proto_init(struct net *net, u_int8_t af)
 {
index 3eff7b67cdf2f5277c2004cf48c2f4e37c218068..6e57a3966dc5748a8cbb99cdf28c62ba1d5b90f1 100644 (file)
@@ -38,7 +38,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
        return XT_CONTINUE;
 }
 
-#if IS_ENABLED(CONFIG_NF_DUP_IPV6)
+#if IS_ENABLED(CONFIG_IPV6)
 static unsigned int
 tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
@@ -131,7 +131,7 @@ static struct xt_target tee_tg_reg[] __read_mostly = {
                .destroy    = tee_tg_destroy,
                .me         = THIS_MODULE,
        },
-#if IS_ENABLED(CONFIG_NF_DUP_IPV6)
+#if IS_ENABLED(CONFIG_IPV6)
        {
                .name       = "TEE",
                .revision   = 1,
index 4e3c3affd2859060520e3717acf4d691fb16542f..2455b69b58104366e4670967f7a169994af3ea97 100644 (file)
@@ -262,7 +262,6 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
                        if (f->opt[optnum].kind == (*optp)) {
                                __u32 len = f->opt[optnum].length;
                                const __u8 *optend = optp + len;
-                               int loop_cont = 0;
 
                                fmatch = FMATCH_OK;
 
@@ -275,7 +274,6 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
                                        mss = ntohs((__force __be16)mss);
                                        break;
                                case OSFOPT_TS:
-                                       loop_cont = 1;
                                        break;
                                }
 
index f0cb92f3ddafa47063f82d54232e27308ea539fa..ada67422234bc41ba73f23696607903d800d87e3 100644 (file)
@@ -55,8 +55,8 @@ struct netlbl_domhsh_tbl {
 static DEFINE_SPINLOCK(netlbl_domhsh_lock);
 #define netlbl_domhsh_rcu_deref(p) \
        rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
-static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
-static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
+static struct netlbl_domhsh_tbl *netlbl_domhsh;
+static struct netlbl_dom_map *netlbl_domhsh_def;
 
 /*
  * Domain Hash Table Helper Functions
index b0380927f05f973a59228860e6cfae86187ab639..9eaa9a1e862960e7d37c812d17f16e6680772429 100644 (file)
@@ -116,11 +116,11 @@ struct netlbl_unlhsh_walk_arg {
 static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
 #define netlbl_unlhsh_rcu_deref(p) \
        rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
-static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;
-static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;
+static struct netlbl_unlhsh_tbl *netlbl_unlhsh;
+static struct netlbl_unlhsh_iface *netlbl_unlhsh_def;
 
 /* Accept unlabeled packets flag */
-static u8 netlabel_unlabel_acceptflg = 0;
+static u8 netlabel_unlabel_acceptflg;
 
 /* NetLabel Generic NETLINK unlabeled family */
 static struct genl_family netlbl_unlabel_gnl_family = {
index 2c5e95e9bfbd386693e183f09dfe0be0acffedca..5d6e8c05b3d48adb1201fad2b69c8cda2efcc03e 100644 (file)
@@ -2,15 +2,6 @@
 # Netlink Sockets
 #
 
-config NETLINK_MMAP
-       bool "NETLINK: mmaped IO"
-       ---help---
-         This option enables support for memory mapped netlink IO. This
-         reduces overhead by avoiding copying data between kernel- and
-         userspace.
-
-         If unsure, say N.
-
 config NETLINK_DIAG
        tristate "NETLINK: socket monitoring interface"
        default n
index f1ffb34e253f4906275d4da99ce26306b94241eb..c8416792cce0bed9bedcd18f15aa7c2278afa3de 100644 (file)
@@ -225,7 +225,7 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
 
        dev_hold(dev);
 
-       if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head))
+       if (is_vmalloc_addr(skb->head))
                nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
        else
                nskb = skb_clone(skb, GFP_ATOMIC);
@@ -300,610 +300,8 @@ static void netlink_rcv_wake(struct sock *sk)
                wake_up_interruptible(&nlk->wait);
 }
 
-#ifdef CONFIG_NETLINK_MMAP
-static bool netlink_rx_is_mmaped(struct sock *sk)
-{
-       return nlk_sk(sk)->rx_ring.pg_vec != NULL;
-}
-
-static bool netlink_tx_is_mmaped(struct sock *sk)
-{
-       return nlk_sk(sk)->tx_ring.pg_vec != NULL;
-}
-
-static __pure struct page *pgvec_to_page(const void *addr)
-{
-       if (is_vmalloc_addr(addr))
-               return vmalloc_to_page(addr);
-       else
-               return virt_to_page(addr);
-}
-
-static void free_pg_vec(void **pg_vec, unsigned int order, unsigned int len)
-{
-       unsigned int i;
-
-       for (i = 0; i < len; i++) {
-               if (pg_vec[i] != NULL) {
-                       if (is_vmalloc_addr(pg_vec[i]))
-                               vfree(pg_vec[i]);
-                       else
-                               free_pages((unsigned long)pg_vec[i], order);
-               }
-       }
-       kfree(pg_vec);
-}
-
-static void *alloc_one_pg_vec_page(unsigned long order)
-{
-       void *buffer;
-       gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO |
-                         __GFP_NOWARN | __GFP_NORETRY;
-
-       buffer = (void *)__get_free_pages(gfp_flags, order);
-       if (buffer != NULL)
-               return buffer;
-
-       buffer = vzalloc((1 << order) * PAGE_SIZE);
-       if (buffer != NULL)
-               return buffer;
-
-       gfp_flags &= ~__GFP_NORETRY;
-       return (void *)__get_free_pages(gfp_flags, order);
-}
-
-static void **alloc_pg_vec(struct netlink_sock *nlk,
-                          struct nl_mmap_req *req, unsigned int order)
-{
-       unsigned int block_nr = req->nm_block_nr;
-       unsigned int i;
-       void **pg_vec;
-
-       pg_vec = kcalloc(block_nr, sizeof(void *), GFP_KERNEL);
-       if (pg_vec == NULL)
-               return NULL;
-
-       for (i = 0; i < block_nr; i++) {
-               pg_vec[i] = alloc_one_pg_vec_page(order);
-               if (pg_vec[i] == NULL)
-                       goto err1;
-       }
-
-       return pg_vec;
-err1:
-       free_pg_vec(pg_vec, order, block_nr);
-       return NULL;
-}
-
-
-static void
-__netlink_set_ring(struct sock *sk, struct nl_mmap_req *req, bool tx_ring, void **pg_vec,
-                  unsigned int order)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-       struct sk_buff_head *queue;
-       struct netlink_ring *ring;
-
-       queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
-       ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
-
-       spin_lock_bh(&queue->lock);
-
-       ring->frame_max         = req->nm_frame_nr - 1;
-       ring->head              = 0;
-       ring->frame_size        = req->nm_frame_size;
-       ring->pg_vec_pages      = req->nm_block_size / PAGE_SIZE;
-
-       swap(ring->pg_vec_len, req->nm_block_nr);
-       swap(ring->pg_vec_order, order);
-       swap(ring->pg_vec, pg_vec);
-
-       __skb_queue_purge(queue);
-       spin_unlock_bh(&queue->lock);
-
-       WARN_ON(atomic_read(&nlk->mapped));
-
-       if (pg_vec)
-               free_pg_vec(pg_vec, order, req->nm_block_nr);
-}
-
-static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
-                           bool tx_ring)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-       struct netlink_ring *ring;
-       void **pg_vec = NULL;
-       unsigned int order = 0;
-
-       ring  = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
-
-       if (atomic_read(&nlk->mapped))
-               return -EBUSY;
-       if (atomic_read(&ring->pending))
-               return -EBUSY;
-
-       if (req->nm_block_nr) {
-               if (ring->pg_vec != NULL)
-                       return -EBUSY;
-
-               if ((int)req->nm_block_size <= 0)
-                       return -EINVAL;
-               if (!PAGE_ALIGNED(req->nm_block_size))
-                       return -EINVAL;
-               if (req->nm_frame_size < NL_MMAP_HDRLEN)
-                       return -EINVAL;
-               if (!IS_ALIGNED(req->nm_frame_size, NL_MMAP_MSG_ALIGNMENT))
-                       return -EINVAL;
-
-               ring->frames_per_block = req->nm_block_size /
-                                        req->nm_frame_size;
-               if (ring->frames_per_block == 0)
-                       return -EINVAL;
-               if (ring->frames_per_block * req->nm_block_nr !=
-                   req->nm_frame_nr)
-                       return -EINVAL;
-
-               order = get_order(req->nm_block_size);
-               pg_vec = alloc_pg_vec(nlk, req, order);
-               if (pg_vec == NULL)
-                       return -ENOMEM;
-       } else {
-               if (req->nm_frame_nr)
-                       return -EINVAL;
-       }
-
-       mutex_lock(&nlk->pg_vec_lock);
-       if (atomic_read(&nlk->mapped) == 0) {
-               __netlink_set_ring(sk, req, tx_ring, pg_vec, order);
-               mutex_unlock(&nlk->pg_vec_lock);
-               return 0;
-       }
-
-       mutex_unlock(&nlk->pg_vec_lock);
-
-       if (pg_vec)
-               free_pg_vec(pg_vec, order, req->nm_block_nr);
-
-       return -EBUSY;
-}
-
-static void netlink_mm_open(struct vm_area_struct *vma)
-{
-       struct file *file = vma->vm_file;
-       struct socket *sock = file->private_data;
-       struct sock *sk = sock->sk;
-
-       if (sk)
-               atomic_inc(&nlk_sk(sk)->mapped);
-}
-
-static void netlink_mm_close(struct vm_area_struct *vma)
-{
-       struct file *file = vma->vm_file;
-       struct socket *sock = file->private_data;
-       struct sock *sk = sock->sk;
-
-       if (sk)
-               atomic_dec(&nlk_sk(sk)->mapped);
-}
-
-static const struct vm_operations_struct netlink_mmap_ops = {
-       .open   = netlink_mm_open,
-       .close  = netlink_mm_close,
-};
-
-static int netlink_mmap(struct file *file, struct socket *sock,
-                       struct vm_area_struct *vma)
-{
-       struct sock *sk = sock->sk;
-       struct netlink_sock *nlk = nlk_sk(sk);
-       struct netlink_ring *ring;
-       unsigned long start, size, expected;
-       unsigned int i;
-       int err = -EINVAL;
-
-       if (vma->vm_pgoff)
-               return -EINVAL;
-
-       mutex_lock(&nlk->pg_vec_lock);
-
-       expected = 0;
-       for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
-               if (ring->pg_vec == NULL)
-                       continue;
-               expected += ring->pg_vec_len * ring->pg_vec_pages * PAGE_SIZE;
-       }
-
-       if (expected == 0)
-               goto out;
-
-       size = vma->vm_end - vma->vm_start;
-       if (size != expected)
-               goto out;
-
-       start = vma->vm_start;
-       for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
-               if (ring->pg_vec == NULL)
-                       continue;
-
-               for (i = 0; i < ring->pg_vec_len; i++) {
-                       struct page *page;
-                       void *kaddr = ring->pg_vec[i];
-                       unsigned int pg_num;
-
-                       for (pg_num = 0; pg_num < ring->pg_vec_pages; pg_num++) {
-                               page = pgvec_to_page(kaddr);
-                               err = vm_insert_page(vma, start, page);
-                               if (err < 0)
-                                       goto out;
-                               start += PAGE_SIZE;
-                               kaddr += PAGE_SIZE;
-                       }
-               }
-       }
-
-       atomic_inc(&nlk->mapped);
-       vma->vm_ops = &netlink_mmap_ops;
-       err = 0;
-out:
-       mutex_unlock(&nlk->pg_vec_lock);
-       return err;
-}
-
-static void netlink_frame_flush_dcache(const struct nl_mmap_hdr *hdr, unsigned int nm_len)
-{
-#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
-       struct page *p_start, *p_end;
-
-       /* First page is flushed through netlink_{get,set}_status */
-       p_start = pgvec_to_page(hdr + PAGE_SIZE);
-       p_end   = pgvec_to_page((void *)hdr + NL_MMAP_HDRLEN + nm_len - 1);
-       while (p_start <= p_end) {
-               flush_dcache_page(p_start);
-               p_start++;
-       }
-#endif
-}
-
-static enum nl_mmap_status netlink_get_status(const struct nl_mmap_hdr *hdr)
-{
-       smp_rmb();
-       flush_dcache_page(pgvec_to_page(hdr));
-       return hdr->nm_status;
-}
-
-static void netlink_set_status(struct nl_mmap_hdr *hdr,
-                              enum nl_mmap_status status)
-{
-       smp_mb();
-       hdr->nm_status = status;
-       flush_dcache_page(pgvec_to_page(hdr));
-}
-
-static struct nl_mmap_hdr *
-__netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos)
-{
-       unsigned int pg_vec_pos, frame_off;
-
-       pg_vec_pos = pos / ring->frames_per_block;
-       frame_off  = pos % ring->frames_per_block;
-
-       return ring->pg_vec[pg_vec_pos] + (frame_off * ring->frame_size);
-}
-
-static struct nl_mmap_hdr *
-netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos,
-                    enum nl_mmap_status status)
-{
-       struct nl_mmap_hdr *hdr;
-
-       hdr = __netlink_lookup_frame(ring, pos);
-       if (netlink_get_status(hdr) != status)
-               return NULL;
-
-       return hdr;
-}
-
-static struct nl_mmap_hdr *
-netlink_current_frame(const struct netlink_ring *ring,
-                     enum nl_mmap_status status)
-{
-       return netlink_lookup_frame(ring, ring->head, status);
-}
-
-static void netlink_increment_head(struct netlink_ring *ring)
-{
-       ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0;
-}
-
-static void netlink_forward_ring(struct netlink_ring *ring)
-{
-       unsigned int head = ring->head;
-       const struct nl_mmap_hdr *hdr;
-
-       do {
-               hdr = __netlink_lookup_frame(ring, ring->head);
-               if (hdr->nm_status == NL_MMAP_STATUS_UNUSED)
-                       break;
-               if (hdr->nm_status != NL_MMAP_STATUS_SKIP)
-                       break;
-               netlink_increment_head(ring);
-       } while (ring->head != head);
-}
-
-static bool netlink_has_valid_frame(struct netlink_ring *ring)
-{
-       unsigned int head = ring->head, pos = head;
-       const struct nl_mmap_hdr *hdr;
-
-       do {
-               hdr = __netlink_lookup_frame(ring, pos);
-               if (hdr->nm_status == NL_MMAP_STATUS_VALID)
-                       return true;
-               pos = pos != 0 ? pos - 1 : ring->frame_max;
-       } while (pos != head);
-
-       return false;
-}
-
-static bool netlink_dump_space(struct netlink_sock *nlk)
-{
-       struct netlink_ring *ring = &nlk->rx_ring;
-       struct nl_mmap_hdr *hdr;
-       unsigned int n;
-
-       hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
-       if (hdr == NULL)
-               return false;
-
-       n = ring->head + ring->frame_max / 2;
-       if (n > ring->frame_max)
-               n -= ring->frame_max;
-
-       hdr = __netlink_lookup_frame(ring, n);
-
-       return hdr->nm_status == NL_MMAP_STATUS_UNUSED;
-}
-
-static unsigned int netlink_poll(struct file *file, struct socket *sock,
-                                poll_table *wait)
-{
-       struct sock *sk = sock->sk;
-       struct netlink_sock *nlk = nlk_sk(sk);
-       unsigned int mask;
-       int err;
-
-       if (nlk->rx_ring.pg_vec != NULL) {
-               /* Memory mapped sockets don't call recvmsg(), so flow control
-                * for dumps is performed here. A dump is allowed to continue
-                * if at least half the ring is unused.
-                */
-               while (nlk->cb_running && netlink_dump_space(nlk)) {
-                       err = netlink_dump(sk);
-                       if (err < 0) {
-                               sk->sk_err = -err;
-                               sk->sk_error_report(sk);
-                               break;
-                       }
-               }
-               netlink_rcv_wake(sk);
-       }
-
-       mask = datagram_poll(file, sock, wait);
-
-       /* We could already have received frames in the normal receive
-        * queue, that will show up as NL_MMAP_STATUS_COPY in the ring,
-        * so if mask contains pollin/etc already, there's no point
-        * walking the ring.
-        */
-       if ((mask & (POLLIN | POLLRDNORM)) != (POLLIN | POLLRDNORM)) {
-               spin_lock_bh(&sk->sk_receive_queue.lock);
-               if (nlk->rx_ring.pg_vec) {
-                       if (netlink_has_valid_frame(&nlk->rx_ring))
-                               mask |= POLLIN | POLLRDNORM;
-               }
-               spin_unlock_bh(&sk->sk_receive_queue.lock);
-       }
-
-       spin_lock_bh(&sk->sk_write_queue.lock);
-       if (nlk->tx_ring.pg_vec) {
-               if (netlink_current_frame(&nlk->tx_ring, NL_MMAP_STATUS_UNUSED))
-                       mask |= POLLOUT | POLLWRNORM;
-       }
-       spin_unlock_bh(&sk->sk_write_queue.lock);
-
-       return mask;
-}
-
-static struct nl_mmap_hdr *netlink_mmap_hdr(struct sk_buff *skb)
-{
-       return (struct nl_mmap_hdr *)(skb->head - NL_MMAP_HDRLEN);
-}
-
-static void netlink_ring_setup_skb(struct sk_buff *skb, struct sock *sk,
-                                  struct netlink_ring *ring,
-                                  struct nl_mmap_hdr *hdr)
-{
-       unsigned int size;
-       void *data;
-
-       size = ring->frame_size - NL_MMAP_HDRLEN;
-       data = (void *)hdr + NL_MMAP_HDRLEN;
-
-       skb->head       = data;
-       skb->data       = data;
-       skb_reset_tail_pointer(skb);
-       skb->end        = skb->tail + size;
-       skb->len        = 0;
-
-       skb->destructor = netlink_skb_destructor;
-       NETLINK_CB(skb).flags |= NETLINK_SKB_MMAPED;
-       NETLINK_CB(skb).sk = sk;
-}
-
-static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg,
-                               u32 dst_portid, u32 dst_group,
-                               struct scm_cookie *scm)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-       struct netlink_ring *ring;
-       struct nl_mmap_hdr *hdr;
-       struct sk_buff *skb;
-       unsigned int maxlen;
-       int err = 0, len = 0;
-
-       mutex_lock(&nlk->pg_vec_lock);
-
-       ring   = &nlk->tx_ring;
-       maxlen = ring->frame_size - NL_MMAP_HDRLEN;
-
-       do {
-               unsigned int nm_len;
-
-               hdr = netlink_current_frame(ring, NL_MMAP_STATUS_VALID);
-               if (hdr == NULL) {
-                       if (!(msg->msg_flags & MSG_DONTWAIT) &&
-                           atomic_read(&nlk->tx_ring.pending))
-                               schedule();
-                       continue;
-               }
-
-               nm_len = ACCESS_ONCE(hdr->nm_len);
-               if (nm_len > maxlen) {
-                       err = -EINVAL;
-                       goto out;
-               }
-
-               netlink_frame_flush_dcache(hdr, nm_len);
-
-               skb = alloc_skb(nm_len, GFP_KERNEL);
-               if (skb == NULL) {
-                       err = -ENOBUFS;
-                       goto out;
-               }
-               __skb_put(skb, nm_len);
-               memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, nm_len);
-               netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED);
-
-               netlink_increment_head(ring);
-
-               NETLINK_CB(skb).portid    = nlk->portid;
-               NETLINK_CB(skb).dst_group = dst_group;
-               NETLINK_CB(skb).creds     = scm->creds;
-
-               err = security_netlink_send(sk, skb);
-               if (err) {
-                       kfree_skb(skb);
-                       goto out;
-               }
-
-               if (unlikely(dst_group)) {
-                       atomic_inc(&skb->users);
-                       netlink_broadcast(sk, skb, dst_portid, dst_group,
-                                         GFP_KERNEL);
-               }
-               err = netlink_unicast(sk, skb, dst_portid,
-                                     msg->msg_flags & MSG_DONTWAIT);
-               if (err < 0)
-                       goto out;
-               len += err;
-
-       } while (hdr != NULL ||
-                (!(msg->msg_flags & MSG_DONTWAIT) &&
-                 atomic_read(&nlk->tx_ring.pending)));
-
-       if (len > 0)
-               err = len;
-out:
-       mutex_unlock(&nlk->pg_vec_lock);
-       return err;
-}
-
-static void netlink_queue_mmaped_skb(struct sock *sk, struct sk_buff *skb)
-{
-       struct nl_mmap_hdr *hdr;
-
-       hdr = netlink_mmap_hdr(skb);
-       hdr->nm_len     = skb->len;
-       hdr->nm_group   = NETLINK_CB(skb).dst_group;
-       hdr->nm_pid     = NETLINK_CB(skb).creds.pid;
-       hdr->nm_uid     = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid);
-       hdr->nm_gid     = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid);
-       netlink_frame_flush_dcache(hdr, hdr->nm_len);
-       netlink_set_status(hdr, NL_MMAP_STATUS_VALID);
-
-       NETLINK_CB(skb).flags |= NETLINK_SKB_DELIVERED;
-       kfree_skb(skb);
-}
-
-static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-       struct netlink_ring *ring = &nlk->rx_ring;
-       struct nl_mmap_hdr *hdr;
-
-       spin_lock_bh(&sk->sk_receive_queue.lock);
-       hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
-       if (hdr == NULL) {
-               spin_unlock_bh(&sk->sk_receive_queue.lock);
-               kfree_skb(skb);
-               netlink_overrun(sk);
-               return;
-       }
-       netlink_increment_head(ring);
-       __skb_queue_tail(&sk->sk_receive_queue, skb);
-       spin_unlock_bh(&sk->sk_receive_queue.lock);
-
-       hdr->nm_len     = skb->len;
-       hdr->nm_group   = NETLINK_CB(skb).dst_group;
-       hdr->nm_pid     = NETLINK_CB(skb).creds.pid;
-       hdr->nm_uid     = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid);
-       hdr->nm_gid     = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid);
-       netlink_set_status(hdr, NL_MMAP_STATUS_COPY);
-}
-
-#else /* CONFIG_NETLINK_MMAP */
-#define netlink_rx_is_mmaped(sk)       false
-#define netlink_tx_is_mmaped(sk)       false
-#define netlink_mmap                   sock_no_mmap
-#define netlink_poll                   datagram_poll
-#define netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group, scm)      0
-#endif /* CONFIG_NETLINK_MMAP */
-
 static void netlink_skb_destructor(struct sk_buff *skb)
 {
-#ifdef CONFIG_NETLINK_MMAP
-       struct nl_mmap_hdr *hdr;
-       struct netlink_ring *ring;
-       struct sock *sk;
-
-       /* If a packet from the kernel to userspace was freed because of an
-        * error without being delivered to userspace, the kernel must reset
-        * the status. In the direction userspace to kernel, the status is
-        * always reset here after the packet was processed and freed.
-        */
-       if (netlink_skb_is_mmaped(skb)) {
-               hdr = netlink_mmap_hdr(skb);
-               sk = NETLINK_CB(skb).sk;
-
-               if (NETLINK_CB(skb).flags & NETLINK_SKB_TX) {
-                       netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED);
-                       ring = &nlk_sk(sk)->tx_ring;
-               } else {
-                       if (!(NETLINK_CB(skb).flags & NETLINK_SKB_DELIVERED)) {
-                               hdr->nm_len = 0;
-                               netlink_set_status(hdr, NL_MMAP_STATUS_VALID);
-                       }
-                       ring = &nlk_sk(sk)->rx_ring;
-               }
-
-               WARN_ON(atomic_read(&ring->pending) == 0);
-               atomic_dec(&ring->pending);
-               sock_put(sk);
-
-               skb->head = NULL;
-       }
-#endif
        if (is_vmalloc_addr(skb->head)) {
                if (!skb->cloned ||
                    !atomic_dec_return(&(skb_shinfo(skb)->dataref)))
@@ -937,18 +335,6 @@ static void netlink_sock_destruct(struct sock *sk)
        }
 
        skb_queue_purge(&sk->sk_receive_queue);
-#ifdef CONFIG_NETLINK_MMAP
-       if (1) {
-               struct nl_mmap_req req;
-
-               memset(&req, 0, sizeof(req));
-               if (nlk->rx_ring.pg_vec)
-                       __netlink_set_ring(sk, &req, false, NULL, 0);
-               memset(&req, 0, sizeof(req));
-               if (nlk->tx_ring.pg_vec)
-                       __netlink_set_ring(sk, &req, true, NULL, 0);
-       }
-#endif /* CONFIG_NETLINK_MMAP */
 
        if (!sock_flag(sk, SOCK_DEAD)) {
                printk(KERN_ERR "Freeing alive netlink socket %p\n", sk);
@@ -1194,9 +580,6 @@ static int __netlink_create(struct net *net, struct socket *sock,
                mutex_init(nlk->cb_mutex);
        }
        init_waitqueue_head(&nlk->wait);
-#ifdef CONFIG_NETLINK_MMAP
-       mutex_init(&nlk->pg_vec_lock);
-#endif
 
        sk->sk_destruct = netlink_sock_destruct;
        sk->sk_protocol = protocol;
@@ -1728,8 +1111,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
        nlk = nlk_sk(sk);
 
        if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
-            test_bit(NETLINK_S_CONGESTED, &nlk->state)) &&
-           !netlink_skb_is_mmaped(skb)) {
+            test_bit(NETLINK_S_CONGESTED, &nlk->state))) {
                DECLARE_WAITQUEUE(wait, current);
                if (!*timeo) {
                        if (!ssk || netlink_is_kernel(ssk))
@@ -1767,14 +1149,7 @@ static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
 
        netlink_deliver_tap(skb);
 
-#ifdef CONFIG_NETLINK_MMAP
-       if (netlink_skb_is_mmaped(skb))
-               netlink_queue_mmaped_skb(sk, skb);
-       else if (netlink_rx_is_mmaped(sk))
-               netlink_ring_set_copied(sk, skb);
-       else
-#endif /* CONFIG_NETLINK_MMAP */
-               skb_queue_tail(&sk->sk_receive_queue, skb);
+       skb_queue_tail(&sk->sk_receive_queue, skb);
        sk->sk_data_ready(sk);
        return len;
 }
@@ -1798,9 +1173,6 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
        int delta;
 
        WARN_ON(skb->sk != NULL);
-       if (netlink_skb_is_mmaped(skb))
-               return skb;
-
        delta = skb->end - skb->tail;
        if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
                return skb;
@@ -1876,79 +1248,6 @@ retry:
 }
 EXPORT_SYMBOL(netlink_unicast);
 
-struct sk_buff *__netlink_alloc_skb(struct sock *ssk, unsigned int size,
-                                   unsigned int ldiff, u32 dst_portid,
-                                   gfp_t gfp_mask)
-{
-#ifdef CONFIG_NETLINK_MMAP
-       unsigned int maxlen, linear_size;
-       struct sock *sk = NULL;
-       struct sk_buff *skb;
-       struct netlink_ring *ring;
-       struct nl_mmap_hdr *hdr;
-
-       sk = netlink_getsockbyportid(ssk, dst_portid);
-       if (IS_ERR(sk))
-               goto out;
-
-       ring = &nlk_sk(sk)->rx_ring;
-       /* fast-path without atomic ops for common case: non-mmaped receiver */
-       if (ring->pg_vec == NULL)
-               goto out_put;
-
-       /* We need to account the full linear size needed as a ring
-        * slot cannot have non-linear parts.
-        */
-       linear_size = size + ldiff;
-       if (ring->frame_size - NL_MMAP_HDRLEN < linear_size)
-               goto out_put;
-
-       skb = alloc_skb_head(gfp_mask);
-       if (skb == NULL)
-               goto err1;
-
-       spin_lock_bh(&sk->sk_receive_queue.lock);
-       /* check again under lock */
-       if (ring->pg_vec == NULL)
-               goto out_free;
-
-       /* check again under lock */
-       maxlen = ring->frame_size - NL_MMAP_HDRLEN;
-       if (maxlen < linear_size)
-               goto out_free;
-
-       netlink_forward_ring(ring);
-       hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
-       if (hdr == NULL)
-               goto err2;
-
-       netlink_ring_setup_skb(skb, sk, ring, hdr);
-       netlink_set_status(hdr, NL_MMAP_STATUS_RESERVED);
-       atomic_inc(&ring->pending);
-       netlink_increment_head(ring);
-
-       spin_unlock_bh(&sk->sk_receive_queue.lock);
-       return skb;
-
-err2:
-       kfree_skb(skb);
-       spin_unlock_bh(&sk->sk_receive_queue.lock);
-       netlink_overrun(sk);
-err1:
-       sock_put(sk);
-       return NULL;
-
-out_free:
-       kfree_skb(skb);
-       spin_unlock_bh(&sk->sk_receive_queue.lock);
-out_put:
-       sock_put(sk);
-out:
-#endif
-       return alloc_skb(size, gfp_mask);
-}
-EXPORT_SYMBOL_GPL(__netlink_alloc_skb);
-
 int netlink_has_listeners(struct sock *sk, unsigned int group)
 {
        int res = 0;
@@ -2225,8 +1524,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
        if (level != SOL_NETLINK)
                return -ENOPROTOOPT;
 
-       if (optname != NETLINK_RX_RING && optname != NETLINK_TX_RING &&
-           optlen >= sizeof(int) &&
+       if (optlen >= sizeof(int) &&
            get_user(val, (unsigned int __user *)optval))
                return -EFAULT;
 
@@ -2279,25 +1577,6 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                }
                err = 0;
                break;
-#ifdef CONFIG_NETLINK_MMAP
-       case NETLINK_RX_RING:
-       case NETLINK_TX_RING: {
-               struct nl_mmap_req req;
-
-               /* Rings might consume more memory than queue limits, require
-                * CAP_NET_ADMIN.
-                */
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-               if (optlen < sizeof(req))
-                       return -EINVAL;
-               if (copy_from_user(&req, optval, sizeof(req)))
-                       return -EFAULT;
-               err = netlink_set_ring(sk, &req,
-                                      optname == NETLINK_TX_RING);
-               break;
-       }
-#endif /* CONFIG_NETLINK_MMAP */
        case NETLINK_LISTEN_ALL_NSID:
                if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST))
                        return -EPERM;
@@ -2467,18 +1746,6 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
                smp_rmb();
        }
 
-       /* It's a really convoluted way for userland to ask for mmaped
-        * sendmsg(), but that's what we've got...
-        */
-       if (netlink_tx_is_mmaped(sk) &&
-           iter_is_iovec(&msg->msg_iter) &&
-           msg->msg_iter.nr_segs == 1 &&
-           msg->msg_iter.iov->iov_base == NULL) {
-               err = netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group,
-                                          &scm);
-               goto out;
-       }
-
        err = -EMSGSIZE;
        if (len > sk->sk_sndbuf - 32)
                goto out;
@@ -2794,8 +2061,7 @@ static int netlink_dump(struct sock *sk)
                goto errout_skb;
        }
 
-       if (!netlink_rx_is_mmaped(sk) &&
-           atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
+       if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
                goto errout_skb;
 
        /* NLMSG_GOODSIZE is small to avoid high order allocations being
@@ -2808,15 +2074,12 @@ static int netlink_dump(struct sock *sk)
 
        if (alloc_min_size < nlk->max_recvmsg_len) {
                alloc_size = nlk->max_recvmsg_len;
-               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
-                                       GFP_KERNEL |
-                                       __GFP_NOWARN |
-                                       __GFP_NORETRY);
+               skb = alloc_skb(alloc_size, GFP_KERNEL |
+                                           __GFP_NOWARN | __GFP_NORETRY);
        }
        if (!skb) {
                alloc_size = alloc_min_size;
-               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
-                                       GFP_KERNEL);
+               skb = alloc_skb(alloc_size, GFP_KERNEL);
        }
        if (!skb)
                goto errout_skb;
@@ -2831,8 +2094,7 @@ static int netlink_dump(struct sock *sk)
         * reasonable static buffer based on the expected largest dump of a
         * single netdev. The outcome is MSG_TRUNC error.
         */
-       if (!netlink_rx_is_mmaped(sk))
-               skb_reserve(skb, skb_tailroom(skb) - alloc_size);
+       skb_reserve(skb, skb_tailroom(skb) - alloc_size);
        netlink_skb_set_owner_r(skb, sk);
 
        len = cb->dump(skb, cb);
@@ -2884,16 +2146,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        struct netlink_sock *nlk;
        int ret;
 
-       /* Memory mapped dump requests need to be copied to avoid looping
-        * on the pending state in netlink_mmap_sendmsg() while the CB hold
-        * a reference to the skb.
-        */
-       if (netlink_skb_is_mmaped(skb)) {
-               skb = skb_copy(skb, GFP_KERNEL);
-               if (skb == NULL)
-                       return -ENOBUFS;
-       } else
-               atomic_inc(&skb->users);
+       atomic_inc(&skb->users);
 
        sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid);
        if (sk == NULL) {
@@ -2966,8 +2219,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
        if (!(nlk->flags & NETLINK_F_CAP_ACK) && err)
                payload += nlmsg_len(nlh);
 
-       skb = netlink_alloc_skb(in_skb->sk, nlmsg_total_size(payload),
-                               NETLINK_CB(in_skb).portid, GFP_KERNEL);
+       skb = nlmsg_new(payload, GFP_KERNEL);
        if (!skb) {
                struct sock *sk;
 
@@ -3241,7 +2493,7 @@ static const struct proto_ops netlink_ops = {
        .socketpair =   sock_no_socketpair,
        .accept =       sock_no_accept,
        .getname =      netlink_getname,
-       .poll =         netlink_poll,
+       .poll =         datagram_poll,
        .ioctl =        sock_no_ioctl,
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
@@ -3249,7 +2501,7 @@ static const struct proto_ops netlink_ops = {
        .getsockopt =   netlink_getsockopt,
        .sendmsg =      netlink_sendmsg,
        .recvmsg =      netlink_recvmsg,
-       .mmap =         netlink_mmap,
+       .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
 };
 
index 14437d9b1965dcf3d3f085e4aba1f804bdc6f652..e68ef9ccd7039df76db504060912c0491ce98589 100644 (file)
@@ -44,12 +44,6 @@ struct netlink_sock {
        int                     (*netlink_bind)(struct net *net, int group);
        void                    (*netlink_unbind)(struct net *net, int group);
        struct module           *module;
-#ifdef CONFIG_NETLINK_MMAP
-       struct mutex            pg_vec_lock;
-       struct netlink_ring     rx_ring;
-       struct netlink_ring     tx_ring;
-       atomic_t                mapped;
-#endif /* CONFIG_NETLINK_MMAP */
 
        struct rhash_head       node;
        struct rcu_head         rcu;
@@ -60,15 +54,6 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk)
        return container_of(sk, struct netlink_sock, sk);
 }
 
-static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb)
-{
-#ifdef CONFIG_NETLINK_MMAP
-       return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
-#else
-       return false;
-#endif /* CONFIG_NETLINK_MMAP */
-}
-
 struct netlink_table {
        struct rhashtable       hash;
        struct hlist_head       mc_list;
index 3ee63a3cff3049cba8f837713394a5123bf54708..8dd836a8dd60ce67c3b2b910f18f80f28cc05b7c 100644 (file)
@@ -8,41 +8,6 @@
 
 #include "af_netlink.h"
 
-#ifdef CONFIG_NETLINK_MMAP
-static int sk_diag_put_ring(struct netlink_ring *ring, int nl_type,
-                           struct sk_buff *nlskb)
-{
-       struct netlink_diag_ring ndr;
-
-       ndr.ndr_block_size = ring->pg_vec_pages << PAGE_SHIFT;
-       ndr.ndr_block_nr   = ring->pg_vec_len;
-       ndr.ndr_frame_size = ring->frame_size;
-       ndr.ndr_frame_nr   = ring->frame_max + 1;
-
-       return nla_put(nlskb, nl_type, sizeof(ndr), &ndr);
-}
-
-static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
-{
-       struct netlink_sock *nlk = nlk_sk(sk);
-       int ret;
-
-       mutex_lock(&nlk->pg_vec_lock);
-       ret = sk_diag_put_ring(&nlk->rx_ring, NETLINK_DIAG_RX_RING, nlskb);
-       if (!ret)
-               ret = sk_diag_put_ring(&nlk->tx_ring, NETLINK_DIAG_TX_RING,
-                                      nlskb);
-       mutex_unlock(&nlk->pg_vec_lock);
-
-       return ret;
-}
-#else
-static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
-{
-       return 0;
-}
-#endif
-
 static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
@@ -87,10 +52,6 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
            sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
                goto out_nlmsg_trim;
 
-       if ((req->ndiag_show & NDIAG_SHOW_RING_CFG) &&
-           sk_diag_put_rings_cfg(sk, skb))
-               goto out_nlmsg_trim;
-
        nlmsg_end(skb, nlh);
        return 0;
 
index 0ffd721126e7fbb7d1b443e1346f305c08ae3a58..a09132a69869245a20aacc87953213f16a5111e8 100644 (file)
@@ -462,26 +462,6 @@ int genl_unregister_family(struct genl_family *family)
 }
 EXPORT_SYMBOL(genl_unregister_family);
 
-/**
- * genlmsg_new_unicast - Allocate generic netlink message for unicast
- * @payload: size of the message payload
- * @info: information on destination
- * @flags: the type of memory to allocate
- *
- * Allocates a new sk_buff large enough to cover the specified payload
- * plus required Netlink headers. Will check receiving socket for
- * memory mapped i/o capability and use it if enabled. Will fall back
- * to non-mapped skb if message size exceeds the frame size of the ring.
- */
-struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info,
-                                   gfp_t flags)
-{
-       size_t len = nlmsg_total_size(genlmsg_total_size(payload));
-
-       return netlink_alloc_skb(info->dst_sk, len, info->snd_portid, flags);
-}
-EXPORT_SYMBOL_GPL(genlmsg_new_unicast);
-
 /**
  * genlmsg_put - Add generic netlink header to netlink message
  * @skb: socket buffer holding the message
@@ -642,7 +622,6 @@ static int genl_family_rcv_msg(struct genl_family *family,
        info.genlhdr = nlmsg_data(nlh);
        info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
        info.attrs = attrbuf;
-       info.dst_sk = skb->sk;
        genl_info_net_set(&info, net);
        memset(&info.user_ptr, 0, sizeof(info.user_ptr));
 
index d143aa9f66541898d558888b409414f618fc769d..cd5fd9d728a7cd00e676dda2a90a2d5403b0dfeb 100644 (file)
@@ -10,6 +10,7 @@ config OPENVSWITCH
        select LIBCRC32C
        select MPLS
        select NET_MPLS_GSO
+       select DST_CACHE
        ---help---
          Open vSwitch is a multilayer Ethernet switch targeted at virtualized
          environments.  In addition to supporting a variety of features
index 2d59df521915747db6d46aa12e85e9154e4a9291..e9dd47b2a85b9e7b65795335b5722e89ac5c3ed8 100644 (file)
@@ -158,9 +158,7 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
        new_mpls_lse = (__be32 *)skb_mpls_header(skb);
        *new_mpls_lse = mpls->mpls_lse;
 
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
-               skb->csum = csum_add(skb->csum, csum_partial(new_mpls_lse,
-                                                            MPLS_HLEN, 0));
+       skb_postpush_rcsum(skb, new_mpls_lse, MPLS_HLEN);
 
        hdr = eth_hdr(skb);
        hdr->h_proto = mpls->mpls_ethertype;
@@ -280,7 +278,7 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key,
        ether_addr_copy_masked(eth_hdr(skb)->h_dest, key->eth_dst,
                               mask->eth_dst);
 
-       ovs_skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
+       skb_postpush_rcsum(skb, eth_hdr(skb), ETH_ALEN * 2);
 
        ether_addr_copy(flow_key->eth.src, eth_hdr(skb)->h_source);
        ether_addr_copy(flow_key->eth.dst, eth_hdr(skb)->h_dest);
@@ -639,7 +637,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk, struct sk_buff *sk
        /* Reconstruct the MAC header.  */
        skb_push(skb, data->l2_len);
        memcpy(skb->data, &data->l2_data, data->l2_len);
-       ovs_skb_postpush_rcsum(skb, skb->data, data->l2_len);
+       skb_postpush_rcsum(skb, skb->data, data->l2_len);
        skb_reset_mac_header(skb);
 
        ovs_vport_send(vport, skb);
index d6f7fe92744a4baebed536f72aee9d4c3a66f30c..0cc66a4e492deb8484781434d211fef5fa84b25c 100644 (file)
@@ -422,10 +422,6 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        struct sk_buff *nskb = NULL;
        struct sk_buff *user_skb = NULL; /* to be queued to userspace */
        struct nlattr *nla;
-       struct genl_info info = {
-               .dst_sk = ovs_dp_get_net(dp)->genl_sock,
-               .snd_portid = upcall_info->portid,
-       };
        size_t len;
        unsigned int hlen;
        int err, dp_ifindex;
@@ -466,7 +462,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                hlen = skb->len;
 
        len = upcall_msg_size(upcall_info, hlen);
-       user_skb = genlmsg_new_unicast(len, &info, GFP_ATOMIC);
+       user_skb = genlmsg_new(len, GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -876,7 +872,7 @@ static struct sk_buff *ovs_flow_cmd_alloc_info(const struct sw_flow_actions *act
                return NULL;
 
        len = ovs_flow_cmd_msg_size(acts, sfid, ufid_flags);
-       skb = genlmsg_new_unicast(len, info, GFP_KERNEL);
+       skb = genlmsg_new(len, GFP_KERNEL);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
@@ -1100,26 +1096,32 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_match match;
        struct sw_flow_id sfid;
        u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
-       int error;
+       int error = 0;
        bool log = !a[OVS_FLOW_ATTR_PROBE];
        bool ufid_present;
 
-       /* Extract key. */
-       error = -EINVAL;
-       if (!a[OVS_FLOW_ATTR_KEY]) {
-               OVS_NLERR(log, "Flow key attribute not present in set flow.");
-               goto error;
-       }
-
        ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
-       ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
-                                 a[OVS_FLOW_ATTR_MASK], log);
+       if (a[OVS_FLOW_ATTR_KEY]) {
+               ovs_match_init(&match, &key, &mask);
+               error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
+                                         a[OVS_FLOW_ATTR_MASK], log);
+       } else if (!ufid_present) {
+               OVS_NLERR(log,
+                         "Flow set message rejected, Key attribute missing.");
+               error = -EINVAL;
+       }
        if (error)
                goto error;
 
        /* Validate actions. */
        if (a[OVS_FLOW_ATTR_ACTIONS]) {
+               if (!a[OVS_FLOW_ATTR_KEY]) {
+                       OVS_NLERR(log,
+                                 "Flow key attribute not present in set flow.");
+                       error = -EINVAL;
+                       goto error;
+               }
+
                acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
                                        &mask, log);
                if (IS_ERR(acts)) {
@@ -1481,9 +1483,9 @@ error:
        return -EMSGSIZE;
 }
 
-static struct sk_buff *ovs_dp_cmd_alloc_info(struct genl_info *info)
+static struct sk_buff *ovs_dp_cmd_alloc_info(void)
 {
-       return genlmsg_new_unicast(ovs_dp_cmd_msg_size(), info, GFP_KERNEL);
+       return genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
 }
 
 /* Called with rcu_read_lock or ovs_mutex. */
@@ -1536,7 +1538,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
                goto err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1657,7 +1659,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1690,7 +1692,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1723,7 +1725,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        int err;
 
-       reply = ovs_dp_cmd_alloc_info(info);
+       reply = ovs_dp_cmd_alloc_info();
        if (!reply)
                return -ENOMEM;
 
@@ -1912,6 +1914,29 @@ static struct vport *lookup_vport(struct net *net,
                return ERR_PTR(-EINVAL);
 }
 
+/* Called with ovs_mutex */
+static void update_headroom(struct datapath *dp)
+{
+       unsigned dev_headroom, max_headroom = 0;
+       struct net_device *dev;
+       struct vport *vport;
+       int i;
+
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
+                       dev = vport->dev;
+                       dev_headroom = netdev_get_fwd_headroom(dev);
+                       if (dev_headroom > max_headroom)
+                               max_headroom = dev_headroom;
+               }
+       }
+
+       dp->max_headroom = max_headroom;
+       for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++)
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node)
+                       netdev_set_rx_headroom(vport->dev, max_headroom);
+}
+
 static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
@@ -1977,6 +2002,12 @@ restart:
 
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+
+       if (netdev_get_fwd_headroom(vport->dev) > dp->max_headroom)
+               update_headroom(dp);
+       else
+               netdev_set_rx_headroom(vport->dev, dp->max_headroom);
+
        BUG_ON(err < 0);
        ovs_unlock();
 
@@ -2043,8 +2074,10 @@ exit_unlock_free:
 
 static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
+       bool must_update_headroom = false;
        struct nlattr **a = info->attrs;
        struct sk_buff *reply;
+       struct datapath *dp;
        struct vport *vport;
        int err;
 
@@ -2066,7 +2099,16 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
                                      info->snd_seq, 0, OVS_VPORT_CMD_DEL);
        BUG_ON(err < 0);
+
+       /* the vport deletion may trigger dp headroom update */
+       dp = vport->dp;
+       if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
+               must_update_headroom = true;
+       netdev_reset_rx_headroom(vport->dev);
        ovs_dp_detach_port(vport);
+
+       if (must_update_headroom)
+               update_headroom(dp);
        ovs_unlock();
 
        ovs_notify(&dp_vport_genl_family, reply, info);
index 67bdecd9fdc1f2b0544c2081aa1a557b16e0063a..427e39a045cf2d98aff3add0b4a9f47c50c467f4 100644 (file)
@@ -68,6 +68,8 @@ struct dp_stats_percpu {
  * ovs_mutex and RCU.
  * @stats_percpu: Per-CPU datapath statistics.
  * @net: Reference to net namespace.
+ * @max_headroom: the maximum headroom of all vports in this datapath; it will
+ * be used by all the internal vports in this dp.
  *
  * Context: See the comment on locking at the top of datapath.c for additional
  * locking information.
@@ -89,6 +91,8 @@ struct datapath {
        possible_net_t net;
 
        u32 user_features;
+
+       u32 max_headroom;
 };
 
 /**
index d1bd4a45ca2d64eca6439335d967aa21feff2b8b..58b8efc236683e6744a6f07784a6b3f85284b9a2 100644 (file)
@@ -1959,6 +1959,12 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
        if (!tun_dst)
                return -ENOMEM;
 
+       err = dst_cache_init(&tun_dst->u.tun_info.dst_cache, GFP_KERNEL);
+       if (err) {
+               dst_release((struct dst_entry *)tun_dst);
+               return err;
+       }
+
        a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL,
                         sizeof(*ovs_tun), log);
        if (IS_ERR(a)) {
index ec76398a792fbb7451c53b958304a2e001704604..83a5534abd312b34d8e0171981645f32691cdf39 100644 (file)
@@ -138,6 +138,11 @@ internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
        return stats;
 }
 
+void internal_set_rx_headroom(struct net_device *dev, int new_hr)
+{
+       dev->needed_headroom = new_hr;
+}
+
 static const struct net_device_ops internal_dev_netdev_ops = {
        .ndo_open = internal_dev_open,
        .ndo_stop = internal_dev_stop,
@@ -145,6 +150,7 @@ static const struct net_device_ops internal_dev_netdev_ops = {
        .ndo_set_mac_address = eth_mac_addr,
        .ndo_change_mtu = internal_dev_change_mtu,
        .ndo_get_stats64 = internal_get_stats,
+       .ndo_set_rx_headroom = internal_set_rx_headroom,
 };
 
 static struct rtnl_link_ops internal_dev_link_ops __read_mostly = {
@@ -158,7 +164,8 @@ static void do_setup(struct net_device *netdev)
        netdev->netdev_ops = &internal_dev_netdev_ops;
 
        netdev->priv_flags &= ~IFF_TX_SKB_SHARING;
-       netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH;
+       netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH |
+                             IFF_PHONY_HEADROOM;
        netdev->destructor = internal_dev_destructor;
        netdev->ethtool_ops = &internal_dev_ethtool_ops;
        netdev->rtnl_link_ops = &internal_dev_link_ops;
@@ -199,6 +206,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
                err = -ENOMEM;
                goto error_free_netdev;
        }
+       vport->dev->needed_headroom = vport->dp->max_headroom;
 
        dev_net_set(vport->dev, ovs_dp_get_net(vport->dp));
        internal_dev = internal_dev_priv(vport->dev);
index 6a6adf3143638f4cf6f5a027fa81de56cc041588..4e3972344aa6442986f457c12ed6e23fc92f844d 100644 (file)
@@ -58,7 +58,7 @@ static void netdev_port_receive(struct sk_buff *skb)
                return;
 
        skb_push(skb, ETH_HLEN);
-       ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
+       skb_postpush_rcsum(skb, skb->data, ETH_HLEN);
        ovs_vport_receive(vport, skb, skb_tunnel_info(skb));
        return;
 error:
index 1605691d94144aee0fc50ffb17be05eca2b59675..5eb7694348b5b82a3e80dc6262912eef441ec88e 100644 (file)
@@ -90,7 +90,9 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
        int err;
        struct vxlan_config conf = {
                .no_share = true,
-               .flags = VXLAN_F_COLLECT_METADATA,
+               .flags = VXLAN_F_COLLECT_METADATA | VXLAN_F_UDP_ZERO_CSUM6_RX,
+               /* Don't restrict the packets that can be sent by MTU */
+               .mtu = IP_MAX_MTU,
        };
 
        if (!options) {
index c10899cb90408c2611dd62f9af479a4eeb162c93..f01f28a567adb50db4c0a270a50980be39185a43 100644 (file)
@@ -185,13 +185,6 @@ static inline struct vport *vport_from_priv(void *priv)
 int ovs_vport_receive(struct vport *, struct sk_buff *,
                      const struct ip_tunnel_info *);
 
-static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
-                                     const void *start, unsigned int len)
-{
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
-               skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
-}
-
 static inline const char *ovs_vport_name(struct vport *vport)
 {
        return vport->dev->name;
index b7e7851ddc5d079f246e96ffe2372d659376258e..1ecfa710ca9803e6cbb49e3d419633085f3544dd 100644 (file)
@@ -557,9 +557,8 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
 {
        struct net_device *dev;
        unsigned int mbits = 0, msec = 0, div = 0, tmo = 0;
-       struct ethtool_cmd ecmd;
+       struct ethtool_link_ksettings ecmd;
        int err;
-       u32 speed;
 
        rtnl_lock();
        dev = __dev_get_by_index(sock_net(&po->sk), po->ifindex);
@@ -567,19 +566,19 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
                rtnl_unlock();
                return DEFAULT_PRB_RETIRE_TOV;
        }
-       err = __ethtool_get_settings(dev, &ecmd);
-       speed = ethtool_cmd_speed(&ecmd);
+       err = __ethtool_get_link_ksettings(dev, &ecmd);
        rtnl_unlock();
        if (!err) {
                /*
                 * If the link speed is so slow you don't really
                 * need to worry about perf anyways
                 */
-               if (speed < SPEED_1000 || speed == SPEED_UNKNOWN) {
+               if (ecmd.base.speed < SPEED_1000 ||
+                   ecmd.base.speed == SPEED_UNKNOWN) {
                        return DEFAULT_PRB_RETIRE_TOV;
                } else {
                        msec = 1;
-                       div = speed / 1000;
+                       div = ecmd.base.speed / 1000;
                }
        }
 
@@ -1916,6 +1915,10 @@ retry:
                goto retry;
        }
 
+       if (!dev_validate_header(dev, skb->data, len)) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
        if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
            !packet_extra_vlan_len_allowed(dev, skb)) {
                err = -EMSGSIZE;
@@ -2394,18 +2397,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
        sock_wfree(skb);
 }
 
-static bool ll_header_truncated(const struct net_device *dev, int len)
-{
-       /* net device doesn't like empty head */
-       if (unlikely(len < dev->hard_header_len)) {
-               net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
-                                    current->comm, len, dev->hard_header_len);
-               return true;
-       }
-
-       return false;
-}
-
 static void tpacket_set_protocol(const struct net_device *dev,
                                 struct sk_buff *skb)
 {
@@ -2523,16 +2514,20 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                if (unlikely(err < 0))
                        return -EINVAL;
        } else if (copylen) {
+               int hdrlen = min_t(int, copylen, tp_len);
+
                skb_push(skb, dev->hard_header_len);
                skb_put(skb, copylen - dev->hard_header_len);
-               err = skb_store_bits(skb, 0, data, copylen);
+               err = skb_store_bits(skb, 0, data, hdrlen);
                if (unlikely(err))
                        return err;
+               if (!dev_validate_header(dev, skb->data, hdrlen))
+                       return -EINVAL;
                if (!skb->protocol)
                        tpacket_set_protocol(dev, skb);
 
-               data += copylen;
-               to_write -= copylen;
+               data += hdrlen;
+               to_write -= hdrlen;
        }
 
        offset = offset_in_page(data);
@@ -2704,13 +2699,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                        copylen = __virtio16_to_cpu(vio_le(),
                                                    vnet_hdr->hdr_len);
                }
-               if (dev->hard_header_len) {
-                       if (ll_header_truncated(dev, tp_len)) {
-                               tp_len = -EINVAL;
-                               goto tpacket_error;
-                       }
-                       copylen = max_t(int, copylen, dev->hard_header_len);
-               }
+               copylen = max_t(int, copylen, dev->hard_header_len);
                skb = sock_alloc_send_skb(&po->sk,
                                hlen + tlen + sizeof(struct sockaddr_ll) +
                                (copylen - dev->hard_header_len),
@@ -2906,9 +2895,6 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
                offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
                if (unlikely(offset < 0))
                        goto out_free;
-       } else {
-               if (ll_header_truncated(dev, len))
-                       goto out_free;
        }
 
        /* Returns -EFAULT on error */
@@ -2916,6 +2902,12 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        if (err)
                goto out_free;
 
+       if (sock->type == SOCK_RAW &&
+           !dev_validate_header(dev, skb->data, len)) {
+               err = -EINVAL;
+               goto out_free;
+       }
+
        sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
 
        if (!vnet_hdr.gso_type && (len > dev->mtu + reserve + extra_len) &&
index f2c670ba7b9b2b26592e1b07bbedf0c5b8b3b842..bffde4b46c5d2058027da6158c6d780edde78950 100644 (file)
@@ -4,14 +4,13 @@ config RDS
        depends on INET
        ---help---
          The RDS (Reliable Datagram Sockets) protocol provides reliable,
-         sequenced delivery of datagrams over Infiniband, iWARP,
-         or TCP.
+         sequenced delivery of datagrams over Infiniband or TCP.
 
 config RDS_RDMA
-       tristate "RDS over Infiniband and iWARP"
+       tristate "RDS over Infiniband"
        depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS
        ---help---
-         Allow RDS to use Infiniband and iWARP as a transport.
+         Allow RDS to use Infiniband as a transport.
          This transport supports RDMA operations.
 
 config RDS_TCP
index 56d3f6023ced41adb81510ec0dc8525c9230dea9..0e72bec1529f52116a1aa8a2a4512d903ce03a4b 100644 (file)
@@ -6,9 +6,7 @@ rds-y :=        af_rds.o bind.o cong.o connection.o info.o message.o   \
 obj-$(CONFIG_RDS_RDMA) += rds_rdma.o
 rds_rdma-y :=  rdma_transport.o \
                        ib.o ib_cm.o ib_recv.o ib_ring.o ib_send.o ib_stats.o \
-                       ib_sysctl.o ib_rdma.o \
-                       iw.o iw_cm.o iw_recv.o iw_ring.o iw_send.o iw_stats.o \
-                       iw_sysctl.o iw_rdma.o
+                       ib_sysctl.o ib_rdma.o ib_fmr.o ib_frmr.o
 
 
 obj-$(CONFIG_RDS_TCP) += rds_tcp.o
index b5476aebd68d842e7e1b7ced45809a4c964e648e..6beaeb1138f34a82f0d0a70f86dc5caba4d0ac5d 100644 (file)
@@ -277,6 +277,27 @@ static int rds_set_transport(struct rds_sock *rs, char __user *optval,
        return rs->rs_transport ? 0 : -ENOPROTOOPT;
 }
 
+static int rds_enable_recvtstamp(struct sock *sk, char __user *optval,
+                                int optlen)
+{
+       int val, valbool;
+
+       if (optlen != sizeof(int))
+               return -EFAULT;
+
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       valbool = val ? 1 : 0;
+
+       if (valbool)
+               sock_set_flag(sk, SOCK_RCVTSTAMP);
+       else
+               sock_reset_flag(sk, SOCK_RCVTSTAMP);
+
+       return 0;
+}
+
 static int rds_setsockopt(struct socket *sock, int level, int optname,
                          char __user *optval, unsigned int optlen)
 {
@@ -312,6 +333,11 @@ static int rds_setsockopt(struct socket *sock, int level, int optname,
                ret = rds_set_transport(rs, optval, optlen);
                release_sock(sock->sk);
                break;
+       case SO_TIMESTAMP:
+               lock_sock(sock->sk);
+               ret = rds_enable_recvtstamp(sock->sk, optval, optlen);
+               release_sock(sock->sk);
+               break;
        default:
                ret = -ENOPROTOOPT;
        }
index 9481d55ff6cb2dd7a228964fa3d9dea154a5a9af..b5342fddaf984e73fa1c566833685e9cbb940b05 100644 (file)
 
 #include "rds.h"
 #include "ib.h"
+#include "ib_mr.h"
 
-unsigned int rds_ib_fmr_1m_pool_size = RDS_FMR_1M_POOL_SIZE;
-unsigned int rds_ib_fmr_8k_pool_size = RDS_FMR_8K_POOL_SIZE;
+unsigned int rds_ib_mr_1m_pool_size = RDS_MR_1M_POOL_SIZE;
+unsigned int rds_ib_mr_8k_pool_size = RDS_MR_8K_POOL_SIZE;
 unsigned int rds_ib_retry_count = RDS_IB_DEFAULT_RETRY_COUNT;
 
-module_param(rds_ib_fmr_1m_pool_size, int, 0444);
-MODULE_PARM_DESC(rds_ib_fmr_1m_pool_size, " Max number of 1M fmr per HCA");
-module_param(rds_ib_fmr_8k_pool_size, int, 0444);
-MODULE_PARM_DESC(rds_ib_fmr_8k_pool_size, " Max number of 8K fmr per HCA");
+module_param(rds_ib_mr_1m_pool_size, int, 0444);
+MODULE_PARM_DESC(rds_ib_mr_1m_pool_size, " Max number of 1M mr per HCA");
+module_param(rds_ib_mr_8k_pool_size, int, 0444);
+MODULE_PARM_DESC(rds_ib_mr_8k_pool_size, " Max number of 8K mr per HCA");
 module_param(rds_ib_retry_count, int, 0444);
 MODULE_PARM_DESC(rds_ib_retry_count, " Number of hw retries before reporting an error");
 
@@ -139,14 +140,20 @@ static void rds_ib_add_one(struct ib_device *device)
        rds_ibdev->max_wrs = device->attrs.max_qp_wr;
        rds_ibdev->max_sge = min(device->attrs.max_sge, RDS_IB_MAX_SGE);
 
+       rds_ibdev->has_fr = (device->attrs.device_cap_flags &
+                                 IB_DEVICE_MEM_MGT_EXTENSIONS);
+       rds_ibdev->has_fmr = (device->alloc_fmr && device->dealloc_fmr &&
+                           device->map_phys_fmr && device->unmap_fmr);
+       rds_ibdev->use_fastreg = (rds_ibdev->has_fr && !rds_ibdev->has_fmr);
+
        rds_ibdev->fmr_max_remaps = device->attrs.max_map_per_fmr?: 32;
-       rds_ibdev->max_1m_fmrs = device->attrs.max_mr ?
+       rds_ibdev->max_1m_mrs = device->attrs.max_mr ?
                min_t(unsigned int, (device->attrs.max_mr / 2),
-                     rds_ib_fmr_1m_pool_size) : rds_ib_fmr_1m_pool_size;
+                     rds_ib_mr_1m_pool_size) : rds_ib_mr_1m_pool_size;
 
-       rds_ibdev->max_8k_fmrs = device->attrs.max_mr ?
+       rds_ibdev->max_8k_mrs = device->attrs.max_mr ?
                min_t(unsigned int, ((device->attrs.max_mr / 2) * RDS_MR_8K_SCALE),
-                     rds_ib_fmr_8k_pool_size) : rds_ib_fmr_8k_pool_size;
+                     rds_ib_mr_8k_pool_size) : rds_ib_mr_8k_pool_size;
 
        rds_ibdev->max_initiator_depth = device->attrs.max_qp_init_rd_atom;
        rds_ibdev->max_responder_resources = device->attrs.max_qp_rd_atom;
@@ -172,10 +179,14 @@ static void rds_ib_add_one(struct ib_device *device)
                goto put_dev;
        }
 
-       rdsdebug("RDS/IB: max_mr = %d, max_wrs = %d, max_sge = %d, fmr_max_remaps = %d, max_1m_fmrs = %d, max_8k_fmrs = %d\n",
+       rdsdebug("RDS/IB: max_mr = %d, max_wrs = %d, max_sge = %d, fmr_max_remaps = %d, max_1m_mrs = %d, max_8k_mrs = %d\n",
                 device->attrs.max_fmr, rds_ibdev->max_wrs, rds_ibdev->max_sge,
-                rds_ibdev->fmr_max_remaps, rds_ibdev->max_1m_fmrs,
-                rds_ibdev->max_8k_fmrs);
+                rds_ibdev->fmr_max_remaps, rds_ibdev->max_1m_mrs,
+                rds_ibdev->max_8k_mrs);
+
+       pr_info("RDS/IB: %s: %s supported and preferred\n",
+               device->name,
+               rds_ibdev->use_fastreg ? "FRMR" : "FMR");
 
        INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
        INIT_LIST_HEAD(&rds_ibdev->conn_list);
@@ -364,7 +375,7 @@ void rds_ib_exit(void)
        rds_ib_sysctl_exit();
        rds_ib_recv_exit();
        rds_trans_unregister(&rds_ib_transport);
-       rds_ib_fmr_exit();
+       rds_ib_mr_exit();
 }
 
 struct rds_transport rds_ib_transport = {
@@ -400,13 +411,13 @@ int rds_ib_init(void)
 
        INIT_LIST_HEAD(&rds_ib_devices);
 
-       ret = rds_ib_fmr_init();
+       ret = rds_ib_mr_init();
        if (ret)
                goto out;
 
        ret = ib_register_client(&rds_ib_client);
        if (ret)
-               goto out_fmr_exit;
+               goto out_mr_exit;
 
        ret = rds_ib_sysctl_init();
        if (ret)
@@ -430,8 +441,8 @@ out_sysctl:
        rds_ib_sysctl_exit();
 out_ibreg:
        rds_ib_unregister_client();
-out_fmr_exit:
-       rds_ib_fmr_exit();
+out_mr_exit:
+       rds_ib_mr_exit();
 out:
        return ret;
 }
index b3fdebb57460392ae9a751bfaae2e218ff9b6e17..627fb79aee65b24baa7820d93b63cc3a02f2c6f5 100644 (file)
@@ -9,17 +9,12 @@
 #include "rds.h"
 #include "rdma_transport.h"
 
-#define RDS_FMR_1M_POOL_SIZE           (8192 / 2)
-#define RDS_FMR_1M_MSG_SIZE            256
-#define RDS_FMR_8K_MSG_SIZE            2
-#define RDS_MR_8K_SCALE                        (256 / (RDS_FMR_8K_MSG_SIZE + 1))
-#define RDS_FMR_8K_POOL_SIZE           (RDS_MR_8K_SCALE * (8192 / 2))
-
 #define RDS_IB_MAX_SGE                 8
 #define RDS_IB_RECV_SGE                2
 
 #define RDS_IB_DEFAULT_RECV_WR         1024
 #define RDS_IB_DEFAULT_SEND_WR         256
+#define RDS_IB_DEFAULT_FR_WR           512
 
 #define RDS_IB_DEFAULT_RETRY_COUNT     2
 
@@ -28,7 +23,6 @@
 #define RDS_IB_RECYCLE_BATCH_COUNT     32
 
 #define RDS_IB_WC_MAX                  32
-#define RDS_IB_SEND_OP                 BIT_ULL(63)
 
 extern struct rw_semaphore rds_ib_devices_lock;
 extern struct list_head rds_ib_devices;
@@ -129,6 +123,9 @@ struct rds_ib_connection {
        struct ib_wc            i_send_wc[RDS_IB_WC_MAX];
        struct ib_wc            i_recv_wc[RDS_IB_WC_MAX];
 
+       /* To control the number of wrs from fastreg */
+       atomic_t                i_fastreg_wrs;
+
        /* interrupt handling */
        struct tasklet_struct   i_send_tasklet;
        struct tasklet_struct   i_recv_tasklet;
@@ -207,12 +204,16 @@ struct rds_ib_device {
        struct list_head        conn_list;
        struct ib_device        *dev;
        struct ib_pd            *pd;
-       unsigned int            max_fmrs;
+       bool                    has_fmr;
+       bool                    has_fr;
+       bool                    use_fastreg;
+
+       unsigned int            max_mrs;
        struct rds_ib_mr_pool   *mr_1m_pool;
        struct rds_ib_mr_pool   *mr_8k_pool;
        unsigned int            fmr_max_remaps;
-       unsigned int            max_8k_fmrs;
-       unsigned int            max_1m_fmrs;
+       unsigned int            max_8k_mrs;
+       unsigned int            max_1m_mrs;
        int                     max_sge;
        unsigned int            max_wrs;
        unsigned int            max_initiator_depth;
@@ -266,6 +267,8 @@ struct rds_ib_statistics {
        uint64_t        s_ib_rdma_mr_1m_pool_flush;
        uint64_t        s_ib_rdma_mr_1m_pool_wait;
        uint64_t        s_ib_rdma_mr_1m_pool_depleted;
+       uint64_t        s_ib_rdma_mr_8k_reused;
+       uint64_t        s_ib_rdma_mr_1m_reused;
        uint64_t        s_ib_atomic_cswp;
        uint64_t        s_ib_atomic_fadd;
 };
@@ -317,8 +320,6 @@ struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device);
 void rds_ib_dev_put(struct rds_ib_device *rds_ibdev);
 extern struct ib_client rds_ib_client;
 
-extern unsigned int rds_ib_fmr_1m_pool_size;
-extern unsigned int rds_ib_fmr_8k_pool_size;
 extern unsigned int rds_ib_retry_count;
 
 extern spinlock_t ib_nodev_conns_lock;
@@ -348,17 +349,7 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr);
 void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
 void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
 void rds_ib_destroy_nodev_conns(void);
-struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_dev,
-                                            int npages);
-void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
-void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
-void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
-                   struct rds_sock *rs, u32 *key_ret);
-void rds_ib_sync_mr(void *trans_private, int dir);
-void rds_ib_free_mr(void *trans_private, int invalidate);
-void rds_ib_flush_mrs(void);
-int rds_ib_fmr_init(void);
-void rds_ib_fmr_exit(void);
+void rds_ib_mr_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc);
 
 /* ib_recv.c */
 int rds_ib_recv_init(void);
index da5a7fb98c77abf0c43f0c4825657874eda89ba3..8764970f0c24179b8470a27c1ab0d45567a0d90f 100644 (file)
@@ -236,12 +236,10 @@ static void rds_ib_cq_comp_handler_recv(struct ib_cq *cq, void *context)
        tasklet_schedule(&ic->i_recv_tasklet);
 }
 
-static void poll_cq(struct rds_ib_connection *ic, struct ib_cq *cq,
-                   struct ib_wc *wcs,
-                   struct rds_ib_ack_state *ack_state)
+static void poll_scq(struct rds_ib_connection *ic, struct ib_cq *cq,
+                    struct ib_wc *wcs)
 {
-       int nr;
-       int i;
+       int nr, i;
        struct ib_wc *wc;
 
        while ((nr = ib_poll_cq(cq, RDS_IB_WC_MAX, wcs)) > 0) {
@@ -251,10 +249,12 @@ static void poll_cq(struct rds_ib_connection *ic, struct ib_cq *cq,
                                 (unsigned long long)wc->wr_id, wc->status,
                                 wc->byte_len, be32_to_cpu(wc->ex.imm_data));
 
-                       if (wc->wr_id & RDS_IB_SEND_OP)
+                       if (wc->wr_id <= ic->i_send_ring.w_nr ||
+                           wc->wr_id == RDS_IB_ACK_WR_ID)
                                rds_ib_send_cqe_handler(ic, wc);
                        else
-                               rds_ib_recv_cqe_handler(ic, wc, ack_state);
+                               rds_ib_mr_cqe_handler(ic, wc);
+
                }
        }
 }
@@ -263,14 +263,12 @@ static void rds_ib_tasklet_fn_send(unsigned long data)
 {
        struct rds_ib_connection *ic = (struct rds_ib_connection *)data;
        struct rds_connection *conn = ic->conn;
-       struct rds_ib_ack_state state;
 
        rds_ib_stats_inc(s_ib_tasklet_call);
 
-       memset(&state, 0, sizeof(state));
-       poll_cq(ic, ic->i_send_cq, ic->i_send_wc, &state);
+       poll_scq(ic, ic->i_send_cq, ic->i_send_wc);
        ib_req_notify_cq(ic->i_send_cq, IB_CQ_NEXT_COMP);
-       poll_cq(ic, ic->i_send_cq, ic->i_send_wc, &state);
+       poll_scq(ic, ic->i_send_cq, ic->i_send_wc);
 
        if (rds_conn_up(conn) &&
            (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
@@ -278,6 +276,25 @@ static void rds_ib_tasklet_fn_send(unsigned long data)
                rds_send_xmit(ic->conn);
 }
 
+static void poll_rcq(struct rds_ib_connection *ic, struct ib_cq *cq,
+                    struct ib_wc *wcs,
+                    struct rds_ib_ack_state *ack_state)
+{
+       int nr, i;
+       struct ib_wc *wc;
+
+       while ((nr = ib_poll_cq(cq, RDS_IB_WC_MAX, wcs)) > 0) {
+               for (i = 0; i < nr; i++) {
+                       wc = wcs + i;
+                       rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
+                                (unsigned long long)wc->wr_id, wc->status,
+                                wc->byte_len, be32_to_cpu(wc->ex.imm_data));
+
+                       rds_ib_recv_cqe_handler(ic, wc, ack_state);
+               }
+       }
+}
+
 static void rds_ib_tasklet_fn_recv(unsigned long data)
 {
        struct rds_ib_connection *ic = (struct rds_ib_connection *)data;
@@ -291,9 +308,9 @@ static void rds_ib_tasklet_fn_recv(unsigned long data)
        rds_ib_stats_inc(s_ib_tasklet_call);
 
        memset(&state, 0, sizeof(state));
-       poll_cq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
+       poll_rcq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
        ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED);
-       poll_cq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
+       poll_rcq(ic, ic->i_recv_cq, ic->i_recv_wc, &state);
 
        if (state.ack_next_valid)
                rds_ib_set_ack(ic, state.ack_next, state.ack_required);
@@ -351,7 +368,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        struct ib_qp_init_attr attr;
        struct ib_cq_init_attr cq_attr = {};
        struct rds_ib_device *rds_ibdev;
-       int ret;
+       int ret, fr_queue_space;
 
        /*
         * It's normal to see a null device if an incoming connection races
@@ -361,6 +378,12 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        if (!rds_ibdev)
                return -EOPNOTSUPP;
 
+       /* The fr_queue_space is currently set to 512, to add extra space on
+        * completion queue and send queue. This extra space is used for FRMR
+        * registration and invalidation work requests
+        */
+       fr_queue_space = (rds_ibdev->use_fastreg ? RDS_IB_DEFAULT_FR_WR : 0);
+
        /* add the conn now so that connection establishment has the dev */
        rds_ib_add_conn(rds_ibdev, conn);
 
@@ -372,7 +395,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        /* Protection domain and memory range */
        ic->i_pd = rds_ibdev->pd;
 
-       cq_attr.cqe = ic->i_send_ring.w_nr + 1;
+       cq_attr.cqe = ic->i_send_ring.w_nr + fr_queue_space + 1;
 
        ic->i_send_cq = ib_create_cq(dev, rds_ib_cq_comp_handler_send,
                                     rds_ib_cq_event_handler, conn,
@@ -412,7 +435,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        attr.event_handler = rds_ib_qp_event_handler;
        attr.qp_context = conn;
        /* + 1 to allow for the single ack message */
-       attr.cap.max_send_wr = ic->i_send_ring.w_nr + 1;
+       attr.cap.max_send_wr = ic->i_send_ring.w_nr + fr_queue_space + 1;
        attr.cap.max_recv_wr = ic->i_recv_ring.w_nr + 1;
        attr.cap.max_send_sge = rds_ibdev->max_sge;
        attr.cap.max_recv_sge = RDS_IB_RECV_SGE;
@@ -420,6 +443,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn)
        attr.qp_type = IB_QPT_RC;
        attr.send_cq = ic->i_send_cq;
        attr.recv_cq = ic->i_recv_cq;
+       atomic_set(&ic->i_fastreg_wrs, RDS_IB_DEFAULT_FR_WR);
 
        /*
         * XXX this can fail if max_*_wr is too large?  Are we supposed
@@ -739,7 +763,8 @@ void rds_ib_conn_shutdown(struct rds_connection *conn)
                 */
                wait_event(rds_ib_ring_empty_wait,
                           rds_ib_ring_empty(&ic->i_recv_ring) &&
-                          (atomic_read(&ic->i_signaled_sends) == 0));
+                          (atomic_read(&ic->i_signaled_sends) == 0) &&
+                          (atomic_read(&ic->i_fastreg_wrs) == RDS_IB_DEFAULT_FR_WR));
                tasklet_kill(&ic->i_send_tasklet);
                tasklet_kill(&ic->i_recv_tasklet);
 
diff --git a/net/rds/ib_fmr.c b/net/rds/ib_fmr.c
new file mode 100644 (file)
index 0000000..4fe8f4f
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2016 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "ib_mr.h"
+
+struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev, int npages)
+{
+       struct rds_ib_mr_pool *pool;
+       struct rds_ib_mr *ibmr = NULL;
+       struct rds_ib_fmr *fmr;
+       int err = 0;
+
+       if (npages <= RDS_MR_8K_MSG_SIZE)
+               pool = rds_ibdev->mr_8k_pool;
+       else
+               pool = rds_ibdev->mr_1m_pool;
+
+       ibmr = rds_ib_try_reuse_ibmr(pool);
+       if (ibmr)
+               return ibmr;
+
+       ibmr = kzalloc_node(sizeof(*ibmr), GFP_KERNEL,
+                           rdsibdev_to_node(rds_ibdev));
+       if (!ibmr) {
+               err = -ENOMEM;
+               goto out_no_cigar;
+       }
+
+       fmr = &ibmr->u.fmr;
+       fmr->fmr = ib_alloc_fmr(rds_ibdev->pd,
+                       (IB_ACCESS_LOCAL_WRITE |
+                        IB_ACCESS_REMOTE_READ |
+                        IB_ACCESS_REMOTE_WRITE |
+                        IB_ACCESS_REMOTE_ATOMIC),
+                       &pool->fmr_attr);
+       if (IS_ERR(fmr->fmr)) {
+               err = PTR_ERR(fmr->fmr);
+               fmr->fmr = NULL;
+               pr_warn("RDS/IB: %s failed (err=%d)\n", __func__, err);
+               goto out_no_cigar;
+       }
+
+       ibmr->pool = pool;
+       if (pool->pool_type == RDS_IB_MR_8K_POOL)
+               rds_ib_stats_inc(s_ib_rdma_mr_8k_alloc);
+       else
+               rds_ib_stats_inc(s_ib_rdma_mr_1m_alloc);
+
+       return ibmr;
+
+out_no_cigar:
+       if (ibmr) {
+               if (fmr->fmr)
+                       ib_dealloc_fmr(fmr->fmr);
+               kfree(ibmr);
+       }
+       atomic_dec(&pool->item_count);
+       return ERR_PTR(err);
+}
+
+int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibmr,
+                  struct scatterlist *sg, unsigned int nents)
+{
+       struct ib_device *dev = rds_ibdev->dev;
+       struct rds_ib_fmr *fmr = &ibmr->u.fmr;
+       struct scatterlist *scat = sg;
+       u64 io_addr = 0;
+       u64 *dma_pages;
+       u32 len;
+       int page_cnt, sg_dma_len;
+       int i, j;
+       int ret;
+
+       sg_dma_len = ib_dma_map_sg(dev, sg, nents, DMA_BIDIRECTIONAL);
+       if (unlikely(!sg_dma_len)) {
+               pr_warn("RDS/IB: %s failed!\n", __func__);
+               return -EBUSY;
+       }
+
+       len = 0;
+       page_cnt = 0;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
+
+               if (dma_addr & ~PAGE_MASK) {
+                       if (i > 0)
+                               return -EINVAL;
+                       else
+                               ++page_cnt;
+               }
+               if ((dma_addr + dma_len) & ~PAGE_MASK) {
+                       if (i < sg_dma_len - 1)
+                               return -EINVAL;
+                       else
+                               ++page_cnt;
+               }
+
+               len += dma_len;
+       }
+
+       page_cnt += len >> PAGE_SHIFT;
+       if (page_cnt > ibmr->pool->fmr_attr.max_pages)
+               return -EINVAL;
+
+       dma_pages = kmalloc_node(sizeof(u64) * page_cnt, GFP_ATOMIC,
+                                rdsibdev_to_node(rds_ibdev));
+       if (!dma_pages)
+               return -ENOMEM;
+
+       page_cnt = 0;
+       for (i = 0; i < sg_dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
+
+               for (j = 0; j < dma_len; j += PAGE_SIZE)
+                       dma_pages[page_cnt++] =
+                               (dma_addr & PAGE_MASK) + j;
+       }
+
+       ret = ib_map_phys_fmr(fmr->fmr, dma_pages, page_cnt, io_addr);
+       if (ret)
+               goto out;
+
+       /* Success - we successfully remapped the MR, so we can
+        * safely tear down the old mapping.
+        */
+       rds_ib_teardown_mr(ibmr);
+
+       ibmr->sg = scat;
+       ibmr->sg_len = nents;
+       ibmr->sg_dma_len = sg_dma_len;
+       ibmr->remap_count++;
+
+       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
+               rds_ib_stats_inc(s_ib_rdma_mr_8k_used);
+       else
+               rds_ib_stats_inc(s_ib_rdma_mr_1m_used);
+       ret = 0;
+
+out:
+       kfree(dma_pages);
+
+       return ret;
+}
+
+struct rds_ib_mr *rds_ib_reg_fmr(struct rds_ib_device *rds_ibdev,
+                                struct scatterlist *sg,
+                                unsigned long nents,
+                                u32 *key)
+{
+       struct rds_ib_mr *ibmr = NULL;
+       struct rds_ib_fmr *fmr;
+       int ret;
+
+       ibmr = rds_ib_alloc_fmr(rds_ibdev, nents);
+       if (IS_ERR(ibmr))
+               return ibmr;
+
+       ibmr->device = rds_ibdev;
+       fmr = &ibmr->u.fmr;
+       ret = rds_ib_map_fmr(rds_ibdev, ibmr, sg, nents);
+       if (ret == 0)
+               *key = fmr->fmr->rkey;
+       else
+               rds_ib_free_mr(ibmr, 0);
+
+       return ibmr;
+}
+
+void rds_ib_unreg_fmr(struct list_head *list, unsigned int *nfreed,
+                     unsigned long *unpinned, unsigned int goal)
+{
+       struct rds_ib_mr *ibmr, *next;
+       struct rds_ib_fmr *fmr;
+       LIST_HEAD(fmr_list);
+       int ret = 0;
+       unsigned int freed = *nfreed;
+
+       /* String all ib_mr's onto one list and hand them to  ib_unmap_fmr */
+       list_for_each_entry(ibmr, list, unmap_list) {
+               fmr = &ibmr->u.fmr;
+               list_add(&fmr->fmr->list, &fmr_list);
+       }
+
+       ret = ib_unmap_fmr(&fmr_list);
+       if (ret)
+               pr_warn("RDS/IB: FMR invalidation failed (err=%d)\n", ret);
+
+       /* Now we can destroy the DMA mapping and unpin any pages */
+       list_for_each_entry_safe(ibmr, next, list, unmap_list) {
+               fmr = &ibmr->u.fmr;
+               *unpinned += ibmr->sg_len;
+               __rds_ib_teardown_mr(ibmr);
+               if (freed < goal ||
+                   ibmr->remap_count >= ibmr->pool->fmr_attr.max_maps) {
+                       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
+                               rds_ib_stats_inc(s_ib_rdma_mr_8k_free);
+                       else
+                               rds_ib_stats_inc(s_ib_rdma_mr_1m_free);
+                       list_del(&ibmr->unmap_list);
+                       ib_dealloc_fmr(fmr->fmr);
+                       kfree(ibmr);
+                       freed++;
+               }
+       }
+       *nfreed = freed;
+}
+
+void rds_ib_free_fmr_list(struct rds_ib_mr *ibmr)
+{
+       struct rds_ib_mr_pool *pool = ibmr->pool;
+
+       if (ibmr->remap_count >= pool->fmr_attr.max_maps)
+               llist_add(&ibmr->llnode, &pool->drop_list);
+       else
+               llist_add(&ibmr->llnode, &pool->free_list);
+}
diff --git a/net/rds/ib_frmr.c b/net/rds/ib_frmr.c
new file mode 100644 (file)
index 0000000..93ff038
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2016 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "ib_mr.h"
+
+static struct rds_ib_mr *rds_ib_alloc_frmr(struct rds_ib_device *rds_ibdev,
+                                          int npages)
+{
+       struct rds_ib_mr_pool *pool;
+       struct rds_ib_mr *ibmr = NULL;
+       struct rds_ib_frmr *frmr;
+       int err = 0;
+
+       if (npages <= RDS_MR_8K_MSG_SIZE)
+               pool = rds_ibdev->mr_8k_pool;
+       else
+               pool = rds_ibdev->mr_1m_pool;
+
+       ibmr = rds_ib_try_reuse_ibmr(pool);
+       if (ibmr)
+               return ibmr;
+
+       ibmr = kzalloc_node(sizeof(*ibmr), GFP_KERNEL,
+                           rdsibdev_to_node(rds_ibdev));
+       if (!ibmr) {
+               err = -ENOMEM;
+               goto out_no_cigar;
+       }
+
+       frmr = &ibmr->u.frmr;
+       frmr->mr = ib_alloc_mr(rds_ibdev->pd, IB_MR_TYPE_MEM_REG,
+                        pool->fmr_attr.max_pages);
+       if (IS_ERR(frmr->mr)) {
+               pr_warn("RDS/IB: %s failed to allocate MR", __func__);
+               goto out_no_cigar;
+       }
+
+       ibmr->pool = pool;
+       if (pool->pool_type == RDS_IB_MR_8K_POOL)
+               rds_ib_stats_inc(s_ib_rdma_mr_8k_alloc);
+       else
+               rds_ib_stats_inc(s_ib_rdma_mr_1m_alloc);
+
+       if (atomic_read(&pool->item_count) > pool->max_items_soft)
+               pool->max_items_soft = pool->max_items;
+
+       frmr->fr_state = FRMR_IS_FREE;
+       return ibmr;
+
+out_no_cigar:
+       kfree(ibmr);
+       atomic_dec(&pool->item_count);
+       return ERR_PTR(err);
+}
+
+static void rds_ib_free_frmr(struct rds_ib_mr *ibmr, bool drop)
+{
+       struct rds_ib_mr_pool *pool = ibmr->pool;
+
+       if (drop)
+               llist_add(&ibmr->llnode, &pool->drop_list);
+       else
+               llist_add(&ibmr->llnode, &pool->free_list);
+       atomic_add(ibmr->sg_len, &pool->free_pinned);
+       atomic_inc(&pool->dirty_count);
+
+       /* If we've pinned too many pages, request a flush */
+       if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
+           atomic_read(&pool->dirty_count) >= pool->max_items / 5)
+               queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
+}
+
+static int rds_ib_post_reg_frmr(struct rds_ib_mr *ibmr)
+{
+       struct rds_ib_frmr *frmr = &ibmr->u.frmr;
+       struct ib_send_wr *failed_wr;
+       struct ib_reg_wr reg_wr;
+       int ret;
+
+       while (atomic_dec_return(&ibmr->ic->i_fastreg_wrs) <= 0) {
+               atomic_inc(&ibmr->ic->i_fastreg_wrs);
+               cpu_relax();
+       }
+
+       ret = ib_map_mr_sg_zbva(frmr->mr, ibmr->sg, ibmr->sg_len, PAGE_SIZE);
+       if (unlikely(ret != ibmr->sg_len))
+               return ret < 0 ? ret : -EINVAL;
+
+       /* Perform a WR for the fast_reg_mr. Each individual page
+        * in the sg list is added to the fast reg page list and placed
+        * inside the fast_reg_mr WR.  The key used is a rolling 8bit
+        * counter, which should guarantee uniqueness.
+        */
+       ib_update_fast_reg_key(frmr->mr, ibmr->remap_count++);
+       frmr->fr_state = FRMR_IS_INUSE;
+
+       memset(&reg_wr, 0, sizeof(reg_wr));
+       reg_wr.wr.wr_id = (unsigned long)(void *)ibmr;
+       reg_wr.wr.opcode = IB_WR_REG_MR;
+       reg_wr.wr.num_sge = 0;
+       reg_wr.mr = frmr->mr;
+       reg_wr.key = frmr->mr->rkey;
+       reg_wr.access = IB_ACCESS_LOCAL_WRITE |
+                       IB_ACCESS_REMOTE_READ |
+                       IB_ACCESS_REMOTE_WRITE;
+       reg_wr.wr.send_flags = IB_SEND_SIGNALED;
+
+       failed_wr = &reg_wr.wr;
+       ret = ib_post_send(ibmr->ic->i_cm_id->qp, &reg_wr.wr, &failed_wr);
+       WARN_ON(failed_wr != &reg_wr.wr);
+       if (unlikely(ret)) {
+               /* Failure here can be because of -ENOMEM as well */
+               frmr->fr_state = FRMR_IS_STALE;
+               atomic_inc(&ibmr->ic->i_fastreg_wrs);
+               if (printk_ratelimit())
+                       pr_warn("RDS/IB: %s returned error(%d)\n",
+                               __func__, ret);
+       }
+       return ret;
+}
+
+static int rds_ib_map_frmr(struct rds_ib_device *rds_ibdev,
+                          struct rds_ib_mr_pool *pool,
+                          struct rds_ib_mr *ibmr,
+                          struct scatterlist *sg, unsigned int sg_len)
+{
+       struct ib_device *dev = rds_ibdev->dev;
+       struct rds_ib_frmr *frmr = &ibmr->u.frmr;
+       int i;
+       u32 len;
+       int ret = 0;
+
+       /* We want to teardown old ibmr values here and fill it up with
+        * new sg values
+        */
+       rds_ib_teardown_mr(ibmr);
+
+       ibmr->sg = sg;
+       ibmr->sg_len = sg_len;
+       ibmr->sg_dma_len = 0;
+       frmr->sg_byte_len = 0;
+       WARN_ON(ibmr->sg_dma_len);
+       ibmr->sg_dma_len = ib_dma_map_sg(dev, ibmr->sg, ibmr->sg_len,
+                                        DMA_BIDIRECTIONAL);
+       if (unlikely(!ibmr->sg_dma_len)) {
+               pr_warn("RDS/IB: %s failed!\n", __func__);
+               return -EBUSY;
+       }
+
+       frmr->sg_byte_len = 0;
+       frmr->dma_npages = 0;
+       len = 0;
+
+       ret = -EINVAL;
+       for (i = 0; i < ibmr->sg_dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &ibmr->sg[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &ibmr->sg[i]);
+
+               frmr->sg_byte_len += dma_len;
+               if (dma_addr & ~PAGE_MASK) {
+                       if (i > 0)
+                               goto out_unmap;
+                       else
+                               ++frmr->dma_npages;
+               }
+
+               if ((dma_addr + dma_len) & ~PAGE_MASK) {
+                       if (i < ibmr->sg_dma_len - 1)
+                               goto out_unmap;
+                       else
+                               ++frmr->dma_npages;
+               }
+
+               len += dma_len;
+       }
+       frmr->dma_npages += len >> PAGE_SHIFT;
+
+       if (frmr->dma_npages > ibmr->pool->fmr_attr.max_pages) {
+               ret = -EMSGSIZE;
+               goto out_unmap;
+       }
+
+       ret = rds_ib_post_reg_frmr(ibmr);
+       if (ret)
+               goto out_unmap;
+
+       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
+               rds_ib_stats_inc(s_ib_rdma_mr_8k_used);
+       else
+               rds_ib_stats_inc(s_ib_rdma_mr_1m_used);
+
+       return ret;
+
+out_unmap:
+       ib_dma_unmap_sg(rds_ibdev->dev, ibmr->sg, ibmr->sg_len,
+                       DMA_BIDIRECTIONAL);
+       ibmr->sg_dma_len = 0;
+       return ret;
+}
+
+static int rds_ib_post_inv(struct rds_ib_mr *ibmr)
+{
+       struct ib_send_wr *s_wr, *failed_wr;
+       struct rds_ib_frmr *frmr = &ibmr->u.frmr;
+       struct rdma_cm_id *i_cm_id = ibmr->ic->i_cm_id;
+       int ret = -EINVAL;
+
+       if (!i_cm_id || !i_cm_id->qp || !frmr->mr)
+               goto out;
+
+       if (frmr->fr_state != FRMR_IS_INUSE)
+               goto out;
+
+       while (atomic_dec_return(&ibmr->ic->i_fastreg_wrs) <= 0) {
+               atomic_inc(&ibmr->ic->i_fastreg_wrs);
+               cpu_relax();
+       }
+
+       frmr->fr_inv = true;
+       s_wr = &frmr->fr_wr;
+
+       memset(s_wr, 0, sizeof(*s_wr));
+       s_wr->wr_id = (unsigned long)(void *)ibmr;
+       s_wr->opcode = IB_WR_LOCAL_INV;
+       s_wr->ex.invalidate_rkey = frmr->mr->rkey;
+       s_wr->send_flags = IB_SEND_SIGNALED;
+
+       failed_wr = s_wr;
+       ret = ib_post_send(i_cm_id->qp, s_wr, &failed_wr);
+       WARN_ON(failed_wr != s_wr);
+       if (unlikely(ret)) {
+               frmr->fr_state = FRMR_IS_STALE;
+               frmr->fr_inv = false;
+               atomic_inc(&ibmr->ic->i_fastreg_wrs);
+               pr_err("RDS/IB: %s returned error(%d)\n", __func__, ret);
+               goto out;
+       }
+out:
+       return ret;
+}
+
+void rds_ib_mr_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
+{
+       struct rds_ib_mr *ibmr = (void *)(unsigned long)wc->wr_id;
+       struct rds_ib_frmr *frmr = &ibmr->u.frmr;
+
+       if (wc->status != IB_WC_SUCCESS) {
+               frmr->fr_state = FRMR_IS_STALE;
+               if (rds_conn_up(ic->conn))
+                       rds_ib_conn_error(ic->conn,
+                                         "frmr completion <%pI4,%pI4> status %u(%s), vendor_err 0x%x, disconnecting and reconnecting\n",
+                                         &ic->conn->c_laddr,
+                                         &ic->conn->c_faddr,
+                                         wc->status,
+                                         ib_wc_status_msg(wc->status),
+                                         wc->vendor_err);
+       }
+
+       if (frmr->fr_inv) {
+               frmr->fr_state = FRMR_IS_FREE;
+               frmr->fr_inv = false;
+       }
+
+       atomic_inc(&ic->i_fastreg_wrs);
+}
+
+void rds_ib_unreg_frmr(struct list_head *list, unsigned int *nfreed,
+                      unsigned long *unpinned, unsigned int goal)
+{
+       struct rds_ib_mr *ibmr, *next;
+       struct rds_ib_frmr *frmr;
+       int ret = 0;
+       unsigned int freed = *nfreed;
+
+       /* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
+       list_for_each_entry(ibmr, list, unmap_list) {
+               if (ibmr->sg_dma_len)
+                       ret |= rds_ib_post_inv(ibmr);
+       }
+       if (ret)
+               pr_warn("RDS/IB: %s failed (err=%d)\n", __func__, ret);
+
+       /* Now we can destroy the DMA mapping and unpin any pages */
+       list_for_each_entry_safe(ibmr, next, list, unmap_list) {
+               *unpinned += ibmr->sg_len;
+               frmr = &ibmr->u.frmr;
+               __rds_ib_teardown_mr(ibmr);
+               if (freed < goal || frmr->fr_state == FRMR_IS_STALE) {
+                       /* Don't de-allocate if the MR is not free yet */
+                       if (frmr->fr_state == FRMR_IS_INUSE)
+                               continue;
+
+                       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
+                               rds_ib_stats_inc(s_ib_rdma_mr_8k_free);
+                       else
+                               rds_ib_stats_inc(s_ib_rdma_mr_1m_free);
+                       list_del(&ibmr->unmap_list);
+                       if (frmr->mr)
+                               ib_dereg_mr(frmr->mr);
+                       kfree(ibmr);
+                       freed++;
+               }
+       }
+       *nfreed = freed;
+}
+
+struct rds_ib_mr *rds_ib_reg_frmr(struct rds_ib_device *rds_ibdev,
+                                 struct rds_ib_connection *ic,
+                                 struct scatterlist *sg,
+                                 unsigned long nents, u32 *key)
+{
+       struct rds_ib_mr *ibmr = NULL;
+       struct rds_ib_frmr *frmr;
+       int ret;
+
+       do {
+               if (ibmr)
+                       rds_ib_free_frmr(ibmr, true);
+               ibmr = rds_ib_alloc_frmr(rds_ibdev, nents);
+               if (IS_ERR(ibmr))
+                       return ibmr;
+               frmr = &ibmr->u.frmr;
+       } while (frmr->fr_state != FRMR_IS_FREE);
+
+       ibmr->ic = ic;
+       ibmr->device = rds_ibdev;
+       ret = rds_ib_map_frmr(rds_ibdev, ibmr->pool, ibmr, sg, nents);
+       if (ret == 0) {
+               *key = frmr->mr->rkey;
+       } else {
+               rds_ib_free_frmr(ibmr, false);
+               ibmr = ERR_PTR(ret);
+       }
+
+       return ibmr;
+}
+
+void rds_ib_free_frmr_list(struct rds_ib_mr *ibmr)
+{
+       struct rds_ib_mr_pool *pool = ibmr->pool;
+       struct rds_ib_frmr *frmr = &ibmr->u.frmr;
+
+       if (frmr->fr_state == FRMR_IS_STALE)
+               llist_add(&ibmr->llnode, &pool->drop_list);
+       else
+               llist_add(&ibmr->llnode, &pool->free_list);
+}
diff --git a/net/rds/ib_mr.h b/net/rds/ib_mr.h
new file mode 100644 (file)
index 0000000..1c754f4
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _RDS_IB_MR_H
+#define _RDS_IB_MR_H
+
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "ib.h"
+
+#define RDS_MR_1M_POOL_SIZE            (8192 / 2)
+#define RDS_MR_1M_MSG_SIZE             256
+#define RDS_MR_8K_MSG_SIZE             2
+#define RDS_MR_8K_SCALE                        (256 / (RDS_MR_8K_MSG_SIZE + 1))
+#define RDS_MR_8K_POOL_SIZE            (RDS_MR_8K_SCALE * (8192 / 2))
+
+struct rds_ib_fmr {
+       struct ib_fmr           *fmr;
+       u64                     *dma;
+};
+
+enum rds_ib_fr_state {
+       FRMR_IS_FREE,   /* mr invalidated & ready for use */
+       FRMR_IS_INUSE,  /* mr is in use or used & can be invalidated */
+       FRMR_IS_STALE,  /* Stale MR and needs to be dropped  */
+};
+
+struct rds_ib_frmr {
+       struct ib_mr            *mr;
+       enum rds_ib_fr_state    fr_state;
+       bool                    fr_inv;
+       struct ib_send_wr       fr_wr;
+       unsigned int            dma_npages;
+       unsigned int            sg_byte_len;
+};
+
+/* This is stored as mr->r_trans_private. */
+struct rds_ib_mr {
+       struct rds_ib_device            *device;
+       struct rds_ib_mr_pool           *pool;
+       struct rds_ib_connection        *ic;
+
+       struct llist_node               llnode;
+
+       /* unmap_list is for freeing */
+       struct list_head                unmap_list;
+       unsigned int                    remap_count;
+
+       struct scatterlist              *sg;
+       unsigned int                    sg_len;
+       int                             sg_dma_len;
+
+       union {
+               struct rds_ib_fmr       fmr;
+               struct rds_ib_frmr      frmr;
+       } u;
+};
+
+/* Our own little MR pool */
+struct rds_ib_mr_pool {
+       unsigned int            pool_type;
+       struct mutex            flush_lock;     /* serialize fmr invalidate */
+       struct delayed_work     flush_worker;   /* flush worker */
+
+       atomic_t                item_count;     /* total # of MRs */
+       atomic_t                dirty_count;    /* # dirty of MRs */
+
+       struct llist_head       drop_list;      /* MRs not reached max_maps */
+       struct llist_head       free_list;      /* unused MRs */
+       struct llist_head       clean_list;     /* unused & unmapped MRs */
+       wait_queue_head_t       flush_wait;
+
+       atomic_t                free_pinned;    /* memory pinned by free MRs */
+       unsigned long           max_items;
+       unsigned long           max_items_soft;
+       unsigned long           max_free_pinned;
+       struct ib_fmr_attr      fmr_attr;
+       bool                    use_fastreg;
+};
+
+extern struct workqueue_struct *rds_ib_mr_wq;
+extern unsigned int rds_ib_mr_1m_pool_size;
+extern unsigned int rds_ib_mr_8k_pool_size;
+extern bool prefer_frmr;
+
+struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_dev,
+                                            int npages);
+void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev,
+                       struct rds_info_rdma_connection *iinfo);
+void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
+void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+                   struct rds_sock *rs, u32 *key_ret);
+void rds_ib_sync_mr(void *trans_private, int dir);
+void rds_ib_free_mr(void *trans_private, int invalidate);
+void rds_ib_flush_mrs(void);
+int rds_ib_mr_init(void);
+void rds_ib_mr_exit(void);
+
+void __rds_ib_teardown_mr(struct rds_ib_mr *);
+void rds_ib_teardown_mr(struct rds_ib_mr *);
+struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *, int);
+int rds_ib_map_fmr(struct rds_ib_device *, struct rds_ib_mr *,
+                  struct scatterlist *, unsigned int);
+struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *);
+int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *, int, struct rds_ib_mr **);
+struct rds_ib_mr *rds_ib_reg_fmr(struct rds_ib_device *, struct scatterlist *,
+                                unsigned long, u32 *);
+struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *);
+void rds_ib_unreg_fmr(struct list_head *, unsigned int *,
+                     unsigned long *, unsigned int);
+void rds_ib_free_fmr_list(struct rds_ib_mr *);
+struct rds_ib_mr *rds_ib_reg_frmr(struct rds_ib_device *rds_ibdev,
+                                 struct rds_ib_connection *ic,
+                                 struct scatterlist *sg,
+                                 unsigned long nents, u32 *key);
+void rds_ib_unreg_frmr(struct list_head *list, unsigned int *nfreed,
+                      unsigned long *unpinned, unsigned int goal);
+void rds_ib_free_frmr_list(struct rds_ib_mr *);
+#endif
index a2340748ec8673d478df5961329734a07d0b9ca6..f7164ac1ffc1e2940b88de0455e02c3ab59ed8d1 100644 (file)
 #include <linux/rculist.h>
 #include <linux/llist.h>
 
-#include "rds.h"
-#include "ib.h"
+#include "ib_mr.h"
+
+struct workqueue_struct *rds_ib_mr_wq;
 
 static DEFINE_PER_CPU(unsigned long, clean_list_grace);
 #define CLEAN_LIST_BUSY_BIT 0
 
-/*
- * This is stored as mr->r_trans_private.
- */
-struct rds_ib_mr {
-       struct rds_ib_device    *device;
-       struct rds_ib_mr_pool   *pool;
-       struct ib_fmr           *fmr;
-
-       struct llist_node       llnode;
-
-       /* unmap_list is for freeing */
-       struct list_head        unmap_list;
-       unsigned int            remap_count;
-
-       struct scatterlist      *sg;
-       unsigned int            sg_len;
-       u64                     *dma;
-       int                     sg_dma_len;
-};
-
-/*
- * Our own little FMR pool
- */
-struct rds_ib_mr_pool {
-       unsigned int            pool_type;
-       struct mutex            flush_lock;             /* serialize fmr invalidate */
-       struct delayed_work     flush_worker;           /* flush worker */
-
-       atomic_t                item_count;             /* total # of MRs */
-       atomic_t                dirty_count;            /* # dirty of MRs */
-
-       struct llist_head       drop_list;              /* MRs that have reached their max_maps limit */
-       struct llist_head       free_list;              /* unused MRs */
-       struct llist_head       clean_list;             /* global unused & unamapped MRs */
-       wait_queue_head_t       flush_wait;
-
-       atomic_t                free_pinned;            /* memory pinned by free MRs */
-       unsigned long           max_items;
-       unsigned long           max_items_soft;
-       unsigned long           max_free_pinned;
-       struct ib_fmr_attr      fmr_attr;
-};
-
-static struct workqueue_struct *rds_ib_fmr_wq;
-
-int rds_ib_fmr_init(void)
-{
-       rds_ib_fmr_wq = create_workqueue("rds_fmr_flushd");
-       if (!rds_ib_fmr_wq)
-               return -ENOMEM;
-       return 0;
-}
-
-/* By the time this is called all the IB devices should have been torn down and
- * had their pools freed.  As each pool is freed its work struct is waited on,
- * so the pool flushing work queue should be idle by the time we get here.
- */
-void rds_ib_fmr_exit(void)
-{
-       destroy_workqueue(rds_ib_fmr_wq);
-}
-
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all, struct rds_ib_mr **);
-static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr);
-static void rds_ib_mr_pool_flush_worker(struct work_struct *work);
-
 static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
 {
        struct rds_ib_device *rds_ibdev;
@@ -235,41 +170,6 @@ void rds_ib_destroy_nodev_conns(void)
                rds_conn_destroy(ic->conn);
 }
 
-struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev,
-                                            int pool_type)
-{
-       struct rds_ib_mr_pool *pool;
-
-       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-       if (!pool)
-               return ERR_PTR(-ENOMEM);
-
-       pool->pool_type = pool_type;
-       init_llist_head(&pool->free_list);
-       init_llist_head(&pool->drop_list);
-       init_llist_head(&pool->clean_list);
-       mutex_init(&pool->flush_lock);
-       init_waitqueue_head(&pool->flush_wait);
-       INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
-
-       if (pool_type == RDS_IB_MR_1M_POOL) {
-               /* +1 allows for unaligned MRs */
-               pool->fmr_attr.max_pages = RDS_FMR_1M_MSG_SIZE + 1;
-               pool->max_items = RDS_FMR_1M_POOL_SIZE;
-       } else {
-               /* pool_type == RDS_IB_MR_8K_POOL */
-               pool->fmr_attr.max_pages = RDS_FMR_8K_MSG_SIZE + 1;
-               pool->max_items = RDS_FMR_8K_POOL_SIZE;
-       }
-
-       pool->max_free_pinned = pool->max_items * pool->fmr_attr.max_pages / 4;
-       pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
-       pool->fmr_attr.page_shift = PAGE_SHIFT;
-       pool->max_items_soft = rds_ibdev->max_fmrs * 3 / 4;
-
-       return pool;
-}
-
 void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo)
 {
        struct rds_ib_mr_pool *pool_1m = rds_ibdev->mr_1m_pool;
@@ -278,16 +178,7 @@ void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_co
        iinfo->rdma_mr_size = pool_1m->fmr_attr.max_pages;
 }
 
-void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
-{
-       cancel_delayed_work_sync(&pool->flush_worker);
-       rds_ib_flush_mr_pool(pool, 1, NULL);
-       WARN_ON(atomic_read(&pool->item_count));
-       WARN_ON(atomic_read(&pool->free_pinned));
-       kfree(pool);
-}
-
-static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
+struct rds_ib_mr *rds_ib_reuse_mr(struct rds_ib_mr_pool *pool)
 {
        struct rds_ib_mr *ibmr = NULL;
        struct llist_node *ret;
@@ -297,8 +188,13 @@ static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
        flag = this_cpu_ptr(&clean_list_grace);
        set_bit(CLEAN_LIST_BUSY_BIT, flag);
        ret = llist_del_first(&pool->clean_list);
-       if (ret)
+       if (ret) {
                ibmr = llist_entry(ret, struct rds_ib_mr, llnode);
+               if (pool->pool_type == RDS_IB_MR_8K_POOL)
+                       rds_ib_stats_inc(s_ib_rdma_mr_8k_reused);
+               else
+                       rds_ib_stats_inc(s_ib_rdma_mr_1m_reused);
+       }
 
        clear_bit(CLEAN_LIST_BUSY_BIT, flag);
        preempt_enable();
@@ -317,190 +213,6 @@ static inline void wait_clean_list_grace(void)
        }
 }
 
-static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev,
-                                         int npages)
-{
-       struct rds_ib_mr_pool *pool;
-       struct rds_ib_mr *ibmr = NULL;
-       int err = 0, iter = 0;
-
-       if (npages <= RDS_FMR_8K_MSG_SIZE)
-               pool = rds_ibdev->mr_8k_pool;
-       else
-               pool = rds_ibdev->mr_1m_pool;
-
-       if (atomic_read(&pool->dirty_count) >= pool->max_items / 10)
-               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
-
-       /* Switch pools if one of the pool is reaching upper limit */
-       if (atomic_read(&pool->dirty_count) >=  pool->max_items * 9 / 10) {
-               if (pool->pool_type == RDS_IB_MR_8K_POOL)
-                       pool = rds_ibdev->mr_1m_pool;
-               else
-                       pool = rds_ibdev->mr_8k_pool;
-       }
-
-       while (1) {
-               ibmr = rds_ib_reuse_fmr(pool);
-               if (ibmr)
-                       return ibmr;
-
-               /* No clean MRs - now we have the choice of either
-                * allocating a fresh MR up to the limit imposed by the
-                * driver, or flush any dirty unused MRs.
-                * We try to avoid stalling in the send path if possible,
-                * so we allocate as long as we're allowed to.
-                *
-                * We're fussy with enforcing the FMR limit, though. If the driver
-                * tells us we can't use more than N fmrs, we shouldn't start
-                * arguing with it */
-               if (atomic_inc_return(&pool->item_count) <= pool->max_items)
-                       break;
-
-               atomic_dec(&pool->item_count);
-
-               if (++iter > 2) {
-                       if (pool->pool_type == RDS_IB_MR_8K_POOL)
-                               rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_depleted);
-                       else
-                               rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_depleted);
-                       return ERR_PTR(-EAGAIN);
-               }
-
-               /* We do have some empty MRs. Flush them out. */
-               if (pool->pool_type == RDS_IB_MR_8K_POOL)
-                       rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_wait);
-               else
-                       rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_wait);
-               rds_ib_flush_mr_pool(pool, 0, &ibmr);
-               if (ibmr)
-                       return ibmr;
-       }
-
-       ibmr = kzalloc_node(sizeof(*ibmr), GFP_KERNEL, rdsibdev_to_node(rds_ibdev));
-       if (!ibmr) {
-               err = -ENOMEM;
-               goto out_no_cigar;
-       }
-
-       ibmr->fmr = ib_alloc_fmr(rds_ibdev->pd,
-                       (IB_ACCESS_LOCAL_WRITE |
-                        IB_ACCESS_REMOTE_READ |
-                        IB_ACCESS_REMOTE_WRITE|
-                        IB_ACCESS_REMOTE_ATOMIC),
-                       &pool->fmr_attr);
-       if (IS_ERR(ibmr->fmr)) {
-               err = PTR_ERR(ibmr->fmr);
-               ibmr->fmr = NULL;
-               printk(KERN_WARNING "RDS/IB: ib_alloc_fmr failed (err=%d)\n", err);
-               goto out_no_cigar;
-       }
-
-       ibmr->pool = pool;
-       if (pool->pool_type == RDS_IB_MR_8K_POOL)
-               rds_ib_stats_inc(s_ib_rdma_mr_8k_alloc);
-       else
-               rds_ib_stats_inc(s_ib_rdma_mr_1m_alloc);
-
-       return ibmr;
-
-out_no_cigar:
-       if (ibmr) {
-               if (ibmr->fmr)
-                       ib_dealloc_fmr(ibmr->fmr);
-               kfree(ibmr);
-       }
-       atomic_dec(&pool->item_count);
-       return ERR_PTR(err);
-}
-
-static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibmr,
-              struct scatterlist *sg, unsigned int nents)
-{
-       struct ib_device *dev = rds_ibdev->dev;
-       struct scatterlist *scat = sg;
-       u64 io_addr = 0;
-       u64 *dma_pages;
-       u32 len;
-       int page_cnt, sg_dma_len;
-       int i, j;
-       int ret;
-
-       sg_dma_len = ib_dma_map_sg(dev, sg, nents,
-                                DMA_BIDIRECTIONAL);
-       if (unlikely(!sg_dma_len)) {
-               printk(KERN_WARNING "RDS/IB: dma_map_sg failed!\n");
-               return -EBUSY;
-       }
-
-       len = 0;
-       page_cnt = 0;
-
-       for (i = 0; i < sg_dma_len; ++i) {
-               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
-               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
-
-               if (dma_addr & ~PAGE_MASK) {
-                       if (i > 0)
-                               return -EINVAL;
-                       else
-                               ++page_cnt;
-               }
-               if ((dma_addr + dma_len) & ~PAGE_MASK) {
-                       if (i < sg_dma_len - 1)
-                               return -EINVAL;
-                       else
-                               ++page_cnt;
-               }
-
-               len += dma_len;
-       }
-
-       page_cnt += len >> PAGE_SHIFT;
-       if (page_cnt > ibmr->pool->fmr_attr.max_pages)
-               return -EINVAL;
-
-       dma_pages = kmalloc_node(sizeof(u64) * page_cnt, GFP_ATOMIC,
-                                rdsibdev_to_node(rds_ibdev));
-       if (!dma_pages)
-               return -ENOMEM;
-
-       page_cnt = 0;
-       for (i = 0; i < sg_dma_len; ++i) {
-               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
-               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
-
-               for (j = 0; j < dma_len; j += PAGE_SIZE)
-                       dma_pages[page_cnt++] =
-                               (dma_addr & PAGE_MASK) + j;
-       }
-
-       ret = ib_map_phys_fmr(ibmr->fmr,
-                                  dma_pages, page_cnt, io_addr);
-       if (ret)
-               goto out;
-
-       /* Success - we successfully remapped the MR, so we can
-        * safely tear down the old mapping. */
-       rds_ib_teardown_mr(ibmr);
-
-       ibmr->sg = scat;
-       ibmr->sg_len = nents;
-       ibmr->sg_dma_len = sg_dma_len;
-       ibmr->remap_count++;
-
-       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
-               rds_ib_stats_inc(s_ib_rdma_mr_8k_used);
-       else
-               rds_ib_stats_inc(s_ib_rdma_mr_1m_used);
-       ret = 0;
-
-out:
-       kfree(dma_pages);
-
-       return ret;
-}
-
 void rds_ib_sync_mr(void *trans_private, int direction)
 {
        struct rds_ib_mr *ibmr = trans_private;
@@ -518,7 +230,7 @@ void rds_ib_sync_mr(void *trans_private, int direction)
        }
 }
 
-static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
+void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
 {
        struct rds_ib_device *rds_ibdev = ibmr->device;
 
@@ -549,7 +261,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
        }
 }
 
-static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
+void rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
 {
        unsigned int pinned = ibmr->sg_len;
 
@@ -623,17 +335,15 @@ static void list_to_llist_nodes(struct rds_ib_mr_pool *pool,
  * If the number of MRs allocated exceeds the limit, we also try
  * to free as many MRs as needed to get back to this limit.
  */
-static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
-                               int free_all, struct rds_ib_mr **ibmr_ret)
+int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
+                        int free_all, struct rds_ib_mr **ibmr_ret)
 {
-       struct rds_ib_mr *ibmr, *next;
+       struct rds_ib_mr *ibmr;
        struct llist_node *clean_nodes;
        struct llist_node *clean_tail;
        LIST_HEAD(unmap_list);
-       LIST_HEAD(fmr_list);
        unsigned long unpinned = 0;
        unsigned int nfreed = 0, dirty_to_clean = 0, free_goal;
-       int ret = 0;
 
        if (pool->pool_type == RDS_IB_MR_8K_POOL)
                rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_flush);
@@ -643,7 +353,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
        if (ibmr_ret) {
                DEFINE_WAIT(wait);
                while (!mutex_trylock(&pool->flush_lock)) {
-                       ibmr = rds_ib_reuse_fmr(pool);
+                       ibmr = rds_ib_reuse_mr(pool);
                        if (ibmr) {
                                *ibmr_ret = ibmr;
                                finish_wait(&pool->flush_wait, &wait);
@@ -655,7 +365,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
                        if (llist_empty(&pool->clean_list))
                                schedule();
 
-                       ibmr = rds_ib_reuse_fmr(pool);
+                       ibmr = rds_ib_reuse_mr(pool);
                        if (ibmr) {
                                *ibmr_ret = ibmr;
                                finish_wait(&pool->flush_wait, &wait);
@@ -667,7 +377,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
                mutex_lock(&pool->flush_lock);
 
        if (ibmr_ret) {
-               ibmr = rds_ib_reuse_fmr(pool);
+               ibmr = rds_ib_reuse_mr(pool);
                if (ibmr) {
                        *ibmr_ret = ibmr;
                        goto out;
@@ -687,30 +397,10 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool,
        if (list_empty(&unmap_list))
                goto out;
 
-       /* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
-       list_for_each_entry(ibmr, &unmap_list, unmap_list)
-               list_add(&ibmr->fmr->list, &fmr_list);
-
-       ret = ib_unmap_fmr(&fmr_list);
-       if (ret)
-               printk(KERN_WARNING "RDS/IB: ib_unmap_fmr failed (err=%d)\n", ret);
-
-       /* Now we can destroy the DMA mapping and unpin any pages */
-       list_for_each_entry_safe(ibmr, next, &unmap_list, unmap_list) {
-               unpinned += ibmr->sg_len;
-               __rds_ib_teardown_mr(ibmr);
-               if (nfreed < free_goal ||
-                   ibmr->remap_count >= pool->fmr_attr.max_maps) {
-                       if (ibmr->pool->pool_type == RDS_IB_MR_8K_POOL)
-                               rds_ib_stats_inc(s_ib_rdma_mr_8k_free);
-                       else
-                               rds_ib_stats_inc(s_ib_rdma_mr_1m_free);
-                       list_del(&ibmr->unmap_list);
-                       ib_dealloc_fmr(ibmr->fmr);
-                       kfree(ibmr);
-                       nfreed++;
-               }
-       }
+       if (pool->use_fastreg)
+               rds_ib_unreg_frmr(&unmap_list, &nfreed, &unpinned, free_goal);
+       else
+               rds_ib_unreg_fmr(&unmap_list, &nfreed, &unpinned, free_goal);
 
        if (!list_empty(&unmap_list)) {
                /* we have to make sure that none of the things we're about
@@ -743,7 +433,47 @@ out:
        if (waitqueue_active(&pool->flush_wait))
                wake_up(&pool->flush_wait);
 out_nolock:
-       return ret;
+       return 0;
+}
+
+struct rds_ib_mr *rds_ib_try_reuse_ibmr(struct rds_ib_mr_pool *pool)
+{
+       struct rds_ib_mr *ibmr = NULL;
+       int iter = 0;
+
+       if (atomic_read(&pool->dirty_count) >= pool->max_items_soft / 10)
+               queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
+
+       while (1) {
+               ibmr = rds_ib_reuse_mr(pool);
+               if (ibmr)
+                       return ibmr;
+
+               if (atomic_inc_return(&pool->item_count) <= pool->max_items)
+                       break;
+
+               atomic_dec(&pool->item_count);
+
+               if (++iter > 2) {
+                       if (pool->pool_type == RDS_IB_MR_8K_POOL)
+                               rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_depleted);
+                       else
+                               rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_depleted);
+                       return ERR_PTR(-EAGAIN);
+               }
+
+               /* We do have some empty MRs. Flush them out. */
+               if (pool->pool_type == RDS_IB_MR_8K_POOL)
+                       rds_ib_stats_inc(s_ib_rdma_mr_8k_pool_wait);
+               else
+                       rds_ib_stats_inc(s_ib_rdma_mr_1m_pool_wait);
+
+               rds_ib_flush_mr_pool(pool, 0, &ibmr);
+               if (ibmr)
+                       return ibmr;
+       }
+
+       return ibmr;
 }
 
 static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
@@ -762,10 +492,10 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
        rdsdebug("RDS/IB: free_mr nents %u\n", ibmr->sg_len);
 
        /* Return it to the pool's free list */
-       if (ibmr->remap_count >= pool->fmr_attr.max_maps)
-               llist_add(&ibmr->llnode, &pool->drop_list);
+       if (rds_ibdev->use_fastreg)
+               rds_ib_free_frmr_list(ibmr);
        else
-               llist_add(&ibmr->llnode, &pool->free_list);
+               rds_ib_free_fmr_list(ibmr);
 
        atomic_add(ibmr->sg_len, &pool->free_pinned);
        atomic_inc(&pool->dirty_count);
@@ -773,7 +503,7 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
        /* If we've pinned too many pages, request a flush */
        if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
            atomic_read(&pool->dirty_count) >= pool->max_items / 5)
-               queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10);
+               queue_delayed_work(rds_ib_mr_wq, &pool->flush_worker, 10);
 
        if (invalidate) {
                if (likely(!in_interrupt())) {
@@ -782,7 +512,7 @@ void rds_ib_free_mr(void *trans_private, int invalidate)
                        /* We get here if the user created a MR marked
                         * as use_once and invalidate at the same time.
                         */
-                       queue_delayed_work(rds_ib_fmr_wq,
+                       queue_delayed_work(rds_ib_mr_wq,
                                           &pool->flush_worker, 10);
                }
        }
@@ -810,6 +540,7 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
 {
        struct rds_ib_device *rds_ibdev;
        struct rds_ib_mr *ibmr = NULL;
+       struct rds_ib_connection *ic = rs->rs_conn->c_transport_data;
        int ret;
 
        rds_ibdev = rds_ib_get_device(rs->rs_bound_addr);
@@ -823,29 +554,81 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
                goto out;
        }
 
-       ibmr = rds_ib_alloc_fmr(rds_ibdev, nents);
-       if (IS_ERR(ibmr)) {
-               rds_ib_dev_put(rds_ibdev);
-               return ibmr;
-       }
-
-       ret = rds_ib_map_fmr(rds_ibdev, ibmr, sg, nents);
-       if (ret == 0)
-               *key_ret = ibmr->fmr->rkey;
+       if (rds_ibdev->use_fastreg)
+               ibmr = rds_ib_reg_frmr(rds_ibdev, ic, sg, nents, key_ret);
        else
-               printk(KERN_WARNING "RDS/IB: map_fmr failed (errno=%d)\n", ret);
-
-       ibmr->device = rds_ibdev;
-       rds_ibdev = NULL;
+               ibmr = rds_ib_reg_fmr(rds_ibdev, sg, nents, key_ret);
+       if (ibmr)
+               rds_ibdev = NULL;
 
  out:
-       if (ret) {
-               if (ibmr)
-                       rds_ib_free_mr(ibmr, 0);
-               ibmr = ERR_PTR(ret);
-       }
+       if (!ibmr)
+               pr_warn("RDS/IB: rds_ib_get_mr failed (errno=%d)\n", ret);
+
        if (rds_ibdev)
                rds_ib_dev_put(rds_ibdev);
+
        return ibmr;
 }
 
+void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
+{
+       cancel_delayed_work_sync(&pool->flush_worker);
+       rds_ib_flush_mr_pool(pool, 1, NULL);
+       WARN_ON(atomic_read(&pool->item_count));
+       WARN_ON(atomic_read(&pool->free_pinned));
+       kfree(pool);
+}
+
+struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev,
+                                            int pool_type)
+{
+       struct rds_ib_mr_pool *pool;
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool)
+               return ERR_PTR(-ENOMEM);
+
+       pool->pool_type = pool_type;
+       init_llist_head(&pool->free_list);
+       init_llist_head(&pool->drop_list);
+       init_llist_head(&pool->clean_list);
+       mutex_init(&pool->flush_lock);
+       init_waitqueue_head(&pool->flush_wait);
+       INIT_DELAYED_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
+
+       if (pool_type == RDS_IB_MR_1M_POOL) {
+               /* +1 allows for unaligned MRs */
+               pool->fmr_attr.max_pages = RDS_MR_1M_MSG_SIZE + 1;
+               pool->max_items = RDS_MR_1M_POOL_SIZE;
+       } else {
+               /* pool_type == RDS_IB_MR_8K_POOL */
+               pool->fmr_attr.max_pages = RDS_MR_8K_MSG_SIZE + 1;
+               pool->max_items = RDS_MR_8K_POOL_SIZE;
+       }
+
+       pool->max_free_pinned = pool->max_items * pool->fmr_attr.max_pages / 4;
+       pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
+       pool->fmr_attr.page_shift = PAGE_SHIFT;
+       pool->max_items_soft = rds_ibdev->max_mrs * 3 / 4;
+       pool->use_fastreg = rds_ibdev->use_fastreg;
+
+       return pool;
+}
+
+int rds_ib_mr_init(void)
+{
+       rds_ib_mr_wq = create_workqueue("rds_mr_flushd");
+       if (!rds_ib_mr_wq)
+               return -ENOMEM;
+       return 0;
+}
+
+/* By the time this is called all the IB devices should have been torn down and
+ * had their pools freed.  As each pool is freed its work struct is waited on,
+ * so the pool flushing work queue should be idle by the time we get here.
+ */
+void rds_ib_mr_exit(void)
+{
+       destroy_workqueue(rds_ib_mr_wq);
+}
index eac30bf486d747ce5a78f001de2d65cc5fc7d891..f27d2c82b036f207a06b3b54193e43eded88757f 100644 (file)
@@ -195,7 +195,7 @@ void rds_ib_send_init_ring(struct rds_ib_connection *ic)
 
                send->s_op = NULL;
 
-               send->s_wr.wr_id = i | RDS_IB_SEND_OP;
+               send->s_wr.wr_id = i;
                send->s_wr.sg_list = send->s_sge;
                send->s_wr.ex.imm_data = 0;
 
@@ -263,9 +263,7 @@ void rds_ib_send_cqe_handler(struct rds_ib_connection *ic, struct ib_wc *wc)
 
        oldest = rds_ib_ring_oldest(&ic->i_send_ring);
 
-       completed = rds_ib_ring_completed(&ic->i_send_ring,
-                                         (wc->wr_id & ~RDS_IB_SEND_OP),
-                                         oldest);
+       completed = rds_ib_ring_completed(&ic->i_send_ring, wc->wr_id, oldest);
 
        for (i = 0; i < completed; i++) {
                send = &ic->i_sends[oldest];
index d77e0447305630d721760542ced368f86a9e15f9..7e78dca1f252c671741443cdf660f38da6c575a0 100644 (file)
@@ -73,6 +73,8 @@ static const char *const rds_ib_stat_names[] = {
        "ib_rdma_mr_1m_pool_flush",
        "ib_rdma_mr_1m_pool_wait",
        "ib_rdma_mr_1m_pool_depleted",
+       "ib_rdma_mr_8k_reused",
+       "ib_rdma_mr_1m_reused",
        "ib_atomic_cswp",
        "ib_atomic_fadd",
 };
diff --git a/net/rds/iw.c b/net/rds/iw.c
deleted file mode 100644 (file)
index f4a9fff..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/in.h>
-#include <linux/if.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include "rds.h"
-#include "iw.h"
-
-unsigned int fastreg_pool_size = RDS_FASTREG_POOL_SIZE;
-unsigned int fastreg_message_size = RDS_FASTREG_SIZE + 1; /* +1 allows for unaligned MRs */
-
-module_param(fastreg_pool_size, int, 0444);
-MODULE_PARM_DESC(fastreg_pool_size, " Max number of fastreg MRs per device");
-module_param(fastreg_message_size, int, 0444);
-MODULE_PARM_DESC(fastreg_message_size, " Max size of a RDMA transfer (fastreg MRs)");
-
-struct list_head rds_iw_devices;
-
-/* NOTE: if also grabbing iwdev lock, grab this first */
-DEFINE_SPINLOCK(iw_nodev_conns_lock);
-LIST_HEAD(iw_nodev_conns);
-
-static void rds_iw_add_one(struct ib_device *device)
-{
-       struct rds_iw_device *rds_iwdev;
-
-       /* Only handle iwarp devices */
-       if (device->node_type != RDMA_NODE_RNIC)
-               return;
-
-       rds_iwdev = kmalloc(sizeof *rds_iwdev, GFP_KERNEL);
-       if (!rds_iwdev)
-               return;
-
-       spin_lock_init(&rds_iwdev->spinlock);
-
-       rds_iwdev->dma_local_lkey = !!(device->attrs.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY);
-       rds_iwdev->max_wrs = device->attrs.max_qp_wr;
-       rds_iwdev->max_sge = min(device->attrs.max_sge, RDS_IW_MAX_SGE);
-
-       rds_iwdev->dev = device;
-       rds_iwdev->pd = ib_alloc_pd(device);
-       if (IS_ERR(rds_iwdev->pd))
-               goto free_dev;
-
-       if (!rds_iwdev->dma_local_lkey) {
-               rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
-                                       IB_ACCESS_REMOTE_READ |
-                                       IB_ACCESS_REMOTE_WRITE |
-                                       IB_ACCESS_LOCAL_WRITE);
-               if (IS_ERR(rds_iwdev->mr))
-                       goto err_pd;
-       } else
-               rds_iwdev->mr = NULL;
-
-       rds_iwdev->mr_pool = rds_iw_create_mr_pool(rds_iwdev);
-       if (IS_ERR(rds_iwdev->mr_pool)) {
-               rds_iwdev->mr_pool = NULL;
-               goto err_mr;
-       }
-
-       INIT_LIST_HEAD(&rds_iwdev->cm_id_list);
-       INIT_LIST_HEAD(&rds_iwdev->conn_list);
-       list_add_tail(&rds_iwdev->list, &rds_iw_devices);
-
-       ib_set_client_data(device, &rds_iw_client, rds_iwdev);
-       return;
-
-err_mr:
-       if (rds_iwdev->mr)
-               ib_dereg_mr(rds_iwdev->mr);
-err_pd:
-       ib_dealloc_pd(rds_iwdev->pd);
-free_dev:
-       kfree(rds_iwdev);
-}
-
-static void rds_iw_remove_one(struct ib_device *device, void *client_data)
-{
-       struct rds_iw_device *rds_iwdev = client_data;
-       struct rds_iw_cm_id *i_cm_id, *next;
-
-       if (!rds_iwdev)
-               return;
-
-       spin_lock_irq(&rds_iwdev->spinlock);
-       list_for_each_entry_safe(i_cm_id, next, &rds_iwdev->cm_id_list, list) {
-               list_del(&i_cm_id->list);
-               kfree(i_cm_id);
-       }
-       spin_unlock_irq(&rds_iwdev->spinlock);
-
-       rds_iw_destroy_conns(rds_iwdev);
-
-       if (rds_iwdev->mr_pool)
-               rds_iw_destroy_mr_pool(rds_iwdev->mr_pool);
-
-       if (rds_iwdev->mr)
-               ib_dereg_mr(rds_iwdev->mr);
-
-       ib_dealloc_pd(rds_iwdev->pd);
-
-       list_del(&rds_iwdev->list);
-       kfree(rds_iwdev);
-}
-
-struct ib_client rds_iw_client = {
-       .name   = "rds_iw",
-       .add    = rds_iw_add_one,
-       .remove = rds_iw_remove_one
-};
-
-static int rds_iw_conn_info_visitor(struct rds_connection *conn,
-                                   void *buffer)
-{
-       struct rds_info_rdma_connection *iinfo = buffer;
-       struct rds_iw_connection *ic;
-
-       /* We will only ever look at IB transports */
-       if (conn->c_trans != &rds_iw_transport)
-               return 0;
-
-       iinfo->src_addr = conn->c_laddr;
-       iinfo->dst_addr = conn->c_faddr;
-
-       memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
-       memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
-       if (rds_conn_state(conn) == RDS_CONN_UP) {
-               struct rds_iw_device *rds_iwdev;
-               struct rdma_dev_addr *dev_addr;
-
-               ic = conn->c_transport_data;
-               dev_addr = &ic->i_cm_id->route.addr.dev_addr;
-
-               rdma_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid);
-               rdma_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid);
-
-               rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
-               iinfo->max_send_wr = ic->i_send_ring.w_nr;
-               iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
-               iinfo->max_send_sge = rds_iwdev->max_sge;
-               rds_iw_get_mr_info(rds_iwdev, iinfo);
-       }
-       return 1;
-}
-
-static void rds_iw_ic_info(struct socket *sock, unsigned int len,
-                          struct rds_info_iterator *iter,
-                          struct rds_info_lengths *lens)
-{
-       rds_for_each_conn_info(sock, len, iter, lens,
-                               rds_iw_conn_info_visitor,
-                               sizeof(struct rds_info_rdma_connection));
-}
-
-
-/*
- * Early RDS/IB was built to only bind to an address if there is an IPoIB
- * device with that address set.
- *
- * If it were me, I'd advocate for something more flexible.  Sending and
- * receiving should be device-agnostic.  Transports would try and maintain
- * connections between peers who have messages queued.  Userspace would be
- * allowed to influence which paths have priority.  We could call userspace
- * asserting this policy "routing".
- */
-static int rds_iw_laddr_check(struct net *net, __be32 addr)
-{
-       int ret;
-       struct rdma_cm_id *cm_id;
-       struct sockaddr_in sin;
-
-       /* Create a CMA ID and try to bind it. This catches both
-        * IB and iWARP capable NICs.
-        */
-       cm_id = rdma_create_id(&init_net, NULL, NULL, RDMA_PS_TCP, IB_QPT_RC);
-       if (IS_ERR(cm_id))
-               return PTR_ERR(cm_id);
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = addr;
-
-       /* rdma_bind_addr will only succeed for IB & iWARP devices */
-       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
-       /* due to this, we will claim to support IB devices unless we
-          check node_type. */
-       if (ret || !cm_id->device ||
-           cm_id->device->node_type != RDMA_NODE_RNIC)
-               ret = -EADDRNOTAVAIL;
-
-       rdsdebug("addr %pI4 ret %d node type %d\n",
-               &addr, ret,
-               cm_id->device ? cm_id->device->node_type : -1);
-
-       rdma_destroy_id(cm_id);
-
-       return ret;
-}
-
-void rds_iw_exit(void)
-{
-       rds_info_deregister_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info);
-       rds_iw_destroy_nodev_conns();
-       ib_unregister_client(&rds_iw_client);
-       rds_iw_sysctl_exit();
-       rds_iw_recv_exit();
-       rds_trans_unregister(&rds_iw_transport);
-}
-
-struct rds_transport rds_iw_transport = {
-       .laddr_check            = rds_iw_laddr_check,
-       .xmit_complete          = rds_iw_xmit_complete,
-       .xmit                   = rds_iw_xmit,
-       .xmit_rdma              = rds_iw_xmit_rdma,
-       .recv                   = rds_iw_recv,
-       .conn_alloc             = rds_iw_conn_alloc,
-       .conn_free              = rds_iw_conn_free,
-       .conn_connect           = rds_iw_conn_connect,
-       .conn_shutdown          = rds_iw_conn_shutdown,
-       .inc_copy_to_user       = rds_iw_inc_copy_to_user,
-       .inc_free               = rds_iw_inc_free,
-       .cm_initiate_connect    = rds_iw_cm_initiate_connect,
-       .cm_handle_connect      = rds_iw_cm_handle_connect,
-       .cm_connect_complete    = rds_iw_cm_connect_complete,
-       .stats_info_copy        = rds_iw_stats_info_copy,
-       .exit                   = rds_iw_exit,
-       .get_mr                 = rds_iw_get_mr,
-       .sync_mr                = rds_iw_sync_mr,
-       .free_mr                = rds_iw_free_mr,
-       .flush_mrs              = rds_iw_flush_mrs,
-       .t_owner                = THIS_MODULE,
-       .t_name                 = "iwarp",
-       .t_type                 = RDS_TRANS_IWARP,
-       .t_prefer_loopback      = 1,
-};
-
-int rds_iw_init(void)
-{
-       int ret;
-
-       INIT_LIST_HEAD(&rds_iw_devices);
-
-       ret = ib_register_client(&rds_iw_client);
-       if (ret)
-               goto out;
-
-       ret = rds_iw_sysctl_init();
-       if (ret)
-               goto out_ibreg;
-
-       ret = rds_iw_recv_init();
-       if (ret)
-               goto out_sysctl;
-
-       ret = rds_trans_register(&rds_iw_transport);
-       if (ret)
-               goto out_recv;
-
-       rds_info_register_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info);
-
-       goto out;
-
-out_recv:
-       rds_iw_recv_exit();
-out_sysctl:
-       rds_iw_sysctl_exit();
-out_ibreg:
-       ib_unregister_client(&rds_iw_client);
-out:
-       return ret;
-}
-
-MODULE_LICENSE("GPL");
-
diff --git a/net/rds/iw.h b/net/rds/iw.h
deleted file mode 100644 (file)
index 5af01d1..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-#ifndef _RDS_IW_H
-#define _RDS_IW_H
-
-#include <linux/interrupt.h>
-#include <rdma/ib_verbs.h>
-#include <rdma/rdma_cm.h>
-#include "rds.h"
-#include "rdma_transport.h"
-
-#define RDS_FASTREG_SIZE               20
-#define RDS_FASTREG_POOL_SIZE          2048
-
-#define RDS_IW_MAX_SGE                 8
-#define RDS_IW_RECV_SGE                2
-
-#define RDS_IW_DEFAULT_RECV_WR         1024
-#define RDS_IW_DEFAULT_SEND_WR         256
-
-#define RDS_IW_SUPPORTED_PROTOCOLS     0x00000003      /* minor versions supported */
-
-extern struct list_head rds_iw_devices;
-
-/*
- * IB posts RDS_FRAG_SIZE fragments of pages to the receive queues to
- * try and minimize the amount of memory tied up both the device and
- * socket receive queues.
- */
-/* page offset of the final full frag that fits in the page */
-#define RDS_PAGE_LAST_OFF (((PAGE_SIZE  / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)
-struct rds_page_frag {
-       struct list_head        f_item;
-       struct page             *f_page;
-       unsigned long           f_offset;
-       dma_addr_t              f_mapped;
-};
-
-struct rds_iw_incoming {
-       struct list_head        ii_frags;
-       struct rds_incoming     ii_inc;
-};
-
-struct rds_iw_connect_private {
-       /* Add new fields at the end, and don't permute existing fields. */
-       __be32                  dp_saddr;
-       __be32                  dp_daddr;
-       u8                      dp_protocol_major;
-       u8                      dp_protocol_minor;
-       __be16                  dp_protocol_minor_mask; /* bitmask */
-       __be32                  dp_reserved1;
-       __be64                  dp_ack_seq;
-       __be32                  dp_credit;              /* non-zero enables flow ctl */
-};
-
-struct rds_iw_scatterlist {
-       struct scatterlist      *list;
-       unsigned int            len;
-       int                     dma_len;
-       unsigned int            dma_npages;
-       unsigned int            bytes;
-};
-
-struct rds_iw_mapping {
-       spinlock_t              m_lock; /* protect the mapping struct */
-       struct list_head        m_list;
-       struct rds_iw_mr        *m_mr;
-       uint32_t                m_rkey;
-       struct rds_iw_scatterlist m_sg;
-};
-
-struct rds_iw_send_work {
-       struct rds_message      *s_rm;
-
-       /* We should really put these into a union: */
-       struct rm_rdma_op       *s_op;
-       struct rds_iw_mapping   *s_mapping;
-       struct ib_mr            *s_mr;
-       unsigned char           s_remap_count;
-
-       union {
-               struct ib_send_wr       s_send_wr;
-               struct ib_rdma_wr       s_rdma_wr;
-               struct ib_reg_wr        s_reg_wr;
-       };
-       struct ib_sge           s_sge[RDS_IW_MAX_SGE];
-       unsigned long           s_queued;
-};
-
-struct rds_iw_recv_work {
-       struct rds_iw_incoming  *r_iwinc;
-       struct rds_page_frag    *r_frag;
-       struct ib_recv_wr       r_wr;
-       struct ib_sge           r_sge[2];
-};
-
-struct rds_iw_work_ring {
-       u32             w_nr;
-       u32             w_alloc_ptr;
-       u32             w_alloc_ctr;
-       u32             w_free_ptr;
-       atomic_t        w_free_ctr;
-};
-
-struct rds_iw_device;
-
-struct rds_iw_connection {
-
-       struct list_head        iw_node;
-       struct rds_iw_device    *rds_iwdev;
-       struct rds_connection   *conn;
-
-       /* alphabet soup, IBTA style */
-       struct rdma_cm_id       *i_cm_id;
-       struct ib_pd            *i_pd;
-       struct ib_mr            *i_mr;
-       struct ib_cq            *i_send_cq;
-       struct ib_cq            *i_recv_cq;
-
-       /* tx */
-       struct rds_iw_work_ring i_send_ring;
-       struct rds_message      *i_rm;
-       struct rds_header       *i_send_hdrs;
-       u64                     i_send_hdrs_dma;
-       struct rds_iw_send_work *i_sends;
-
-       /* rx */
-       struct tasklet_struct   i_recv_tasklet;
-       struct mutex            i_recv_mutex;
-       struct rds_iw_work_ring i_recv_ring;
-       struct rds_iw_incoming  *i_iwinc;
-       u32                     i_recv_data_rem;
-       struct rds_header       *i_recv_hdrs;
-       u64                     i_recv_hdrs_dma;
-       struct rds_iw_recv_work *i_recvs;
-       struct rds_page_frag    i_frag;
-       u64                     i_ack_recv;     /* last ACK received */
-
-       /* sending acks */
-       unsigned long           i_ack_flags;
-#ifdef KERNEL_HAS_ATOMIC64
-       atomic64_t              i_ack_next;     /* next ACK to send */
-#else
-       spinlock_t              i_ack_lock;     /* protect i_ack_next */
-       u64                     i_ack_next;     /* next ACK to send */
-#endif
-       struct rds_header       *i_ack;
-       struct ib_send_wr       i_ack_wr;
-       struct ib_sge           i_ack_sge;
-       u64                     i_ack_dma;
-       unsigned long           i_ack_queued;
-
-       /* Flow control related information
-        *
-        * Our algorithm uses a pair variables that we need to access
-        * atomically - one for the send credits, and one posted
-        * recv credits we need to transfer to remote.
-        * Rather than protect them using a slow spinlock, we put both into
-        * a single atomic_t and update it using cmpxchg
-        */
-       atomic_t                i_credits;
-
-       /* Protocol version specific information */
-       unsigned int            i_flowctl:1;    /* enable/disable flow ctl */
-       unsigned int            i_dma_local_lkey:1;
-       unsigned int            i_fastreg_posted:1; /* fastreg posted on this connection */
-       /* Batched completions */
-       unsigned int            i_unsignaled_wrs;
-       long                    i_unsignaled_bytes;
-};
-
-/* This assumes that atomic_t is at least 32 bits */
-#define IB_GET_SEND_CREDITS(v) ((v) & 0xffff)
-#define IB_GET_POST_CREDITS(v) ((v) >> 16)
-#define IB_SET_SEND_CREDITS(v) ((v) & 0xffff)
-#define IB_SET_POST_CREDITS(v) ((v) << 16)
-
-struct rds_iw_cm_id {
-       struct list_head        list;
-       struct rdma_cm_id       *cm_id;
-};
-
-struct rds_iw_device {
-       struct list_head        list;
-       struct list_head        cm_id_list;
-       struct list_head        conn_list;
-       struct ib_device        *dev;
-       struct ib_pd            *pd;
-       struct ib_mr            *mr;
-       struct rds_iw_mr_pool   *mr_pool;
-       int                     max_sge;
-       unsigned int            max_wrs;
-       unsigned int            dma_local_lkey:1;
-       spinlock_t              spinlock;       /* protect the above */
-};
-
-/* bits for i_ack_flags */
-#define IB_ACK_IN_FLIGHT       0
-#define IB_ACK_REQUESTED       1
-
-/* Magic WR_ID for ACKs */
-#define RDS_IW_ACK_WR_ID       ((u64)0xffffffffffffffffULL)
-#define RDS_IW_REG_WR_ID       ((u64)0xefefefefefefefefULL)
-#define RDS_IW_LOCAL_INV_WR_ID ((u64)0xdfdfdfdfdfdfdfdfULL)
-
-struct rds_iw_statistics {
-       uint64_t        s_iw_connect_raced;
-       uint64_t        s_iw_listen_closed_stale;
-       uint64_t        s_iw_tx_cq_call;
-       uint64_t        s_iw_tx_cq_event;
-       uint64_t        s_iw_tx_ring_full;
-       uint64_t        s_iw_tx_throttle;
-       uint64_t        s_iw_tx_sg_mapping_failure;
-       uint64_t        s_iw_tx_stalled;
-       uint64_t        s_iw_tx_credit_updates;
-       uint64_t        s_iw_rx_cq_call;
-       uint64_t        s_iw_rx_cq_event;
-       uint64_t        s_iw_rx_ring_empty;
-       uint64_t        s_iw_rx_refill_from_cq;
-       uint64_t        s_iw_rx_refill_from_thread;
-       uint64_t        s_iw_rx_alloc_limit;
-       uint64_t        s_iw_rx_credit_updates;
-       uint64_t        s_iw_ack_sent;
-       uint64_t        s_iw_ack_send_failure;
-       uint64_t        s_iw_ack_send_delayed;
-       uint64_t        s_iw_ack_send_piggybacked;
-       uint64_t        s_iw_ack_received;
-       uint64_t        s_iw_rdma_mr_alloc;
-       uint64_t        s_iw_rdma_mr_free;
-       uint64_t        s_iw_rdma_mr_used;
-       uint64_t        s_iw_rdma_mr_pool_flush;
-       uint64_t        s_iw_rdma_mr_pool_wait;
-       uint64_t        s_iw_rdma_mr_pool_depleted;
-};
-
-extern struct workqueue_struct *rds_iw_wq;
-
-/*
- * Fake ib_dma_sync_sg_for_{cpu,device} as long as ib_verbs.h
- * doesn't define it.
- */
-static inline void rds_iw_dma_sync_sg_for_cpu(struct ib_device *dev,
-               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
-{
-       unsigned int i;
-
-       for (i = 0; i < sg_dma_len; ++i) {
-               ib_dma_sync_single_for_cpu(dev,
-                               ib_sg_dma_address(dev, &sg[i]),
-                               ib_sg_dma_len(dev, &sg[i]),
-                               direction);
-       }
-}
-#define ib_dma_sync_sg_for_cpu rds_iw_dma_sync_sg_for_cpu
-
-static inline void rds_iw_dma_sync_sg_for_device(struct ib_device *dev,
-               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
-{
-       unsigned int i;
-
-       for (i = 0; i < sg_dma_len; ++i) {
-               ib_dma_sync_single_for_device(dev,
-                               ib_sg_dma_address(dev, &sg[i]),
-                               ib_sg_dma_len(dev, &sg[i]),
-                               direction);
-       }
-}
-#define ib_dma_sync_sg_for_device      rds_iw_dma_sync_sg_for_device
-
-static inline u32 rds_iw_local_dma_lkey(struct rds_iw_connection *ic)
-{
-       return ic->i_dma_local_lkey ? ic->i_cm_id->device->local_dma_lkey : ic->i_mr->lkey;
-}
-
-/* ib.c */
-extern struct rds_transport rds_iw_transport;
-extern struct ib_client rds_iw_client;
-
-extern unsigned int fastreg_pool_size;
-extern unsigned int fastreg_message_size;
-
-extern spinlock_t iw_nodev_conns_lock;
-extern struct list_head iw_nodev_conns;
-
-/* ib_cm.c */
-int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp);
-void rds_iw_conn_free(void *arg);
-int rds_iw_conn_connect(struct rds_connection *conn);
-void rds_iw_conn_shutdown(struct rds_connection *conn);
-void rds_iw_state_change(struct sock *sk);
-int rds_iw_listen_init(void);
-void rds_iw_listen_stop(void);
-void __rds_iw_conn_error(struct rds_connection *conn, const char *, ...);
-int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
-                            struct rdma_cm_event *event);
-int rds_iw_cm_initiate_connect(struct rdma_cm_id *cm_id);
-void rds_iw_cm_connect_complete(struct rds_connection *conn,
-                               struct rdma_cm_event *event);
-
-
-#define rds_iw_conn_error(conn, fmt...) \
-       __rds_iw_conn_error(conn, KERN_WARNING "RDS/IW: " fmt)
-
-/* ib_rdma.c */
-int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
-void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
-void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
-void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock);
-static inline void rds_iw_destroy_nodev_conns(void)
-{
-       __rds_iw_destroy_conns(&iw_nodev_conns, &iw_nodev_conns_lock);
-}
-static inline void rds_iw_destroy_conns(struct rds_iw_device *rds_iwdev)
-{
-       __rds_iw_destroy_conns(&rds_iwdev->conn_list, &rds_iwdev->spinlock);
-}
-struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *);
-void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo);
-void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *);
-void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
-                   struct rds_sock *rs, u32 *key_ret);
-void rds_iw_sync_mr(void *trans_private, int dir);
-void rds_iw_free_mr(void *trans_private, int invalidate);
-void rds_iw_flush_mrs(void);
-
-/* ib_recv.c */
-int rds_iw_recv_init(void);
-void rds_iw_recv_exit(void);
-int rds_iw_recv(struct rds_connection *conn);
-int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
-                      gfp_t page_gfp, int prefill);
-void rds_iw_inc_free(struct rds_incoming *inc);
-int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iov_iter *to);
-void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context);
-void rds_iw_recv_tasklet_fn(unsigned long data);
-void rds_iw_recv_init_ring(struct rds_iw_connection *ic);
-void rds_iw_recv_clear_ring(struct rds_iw_connection *ic);
-void rds_iw_recv_init_ack(struct rds_iw_connection *ic);
-void rds_iw_attempt_ack(struct rds_iw_connection *ic);
-void rds_iw_ack_send_complete(struct rds_iw_connection *ic);
-u64 rds_iw_piggyb_ack(struct rds_iw_connection *ic);
-
-/* ib_ring.c */
-void rds_iw_ring_init(struct rds_iw_work_ring *ring, u32 nr);
-void rds_iw_ring_resize(struct rds_iw_work_ring *ring, u32 nr);
-u32 rds_iw_ring_alloc(struct rds_iw_work_ring *ring, u32 val, u32 *pos);
-void rds_iw_ring_free(struct rds_iw_work_ring *ring, u32 val);
-void rds_iw_ring_unalloc(struct rds_iw_work_ring *ring, u32 val);
-int rds_iw_ring_empty(struct rds_iw_work_ring *ring);
-int rds_iw_ring_low(struct rds_iw_work_ring *ring);
-u32 rds_iw_ring_oldest(struct rds_iw_work_ring *ring);
-u32 rds_iw_ring_completed(struct rds_iw_work_ring *ring, u32 wr_id, u32 oldest);
-extern wait_queue_head_t rds_iw_ring_empty_wait;
-
-/* ib_send.c */
-void rds_iw_xmit_complete(struct rds_connection *conn);
-int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
-               unsigned int hdr_off, unsigned int sg, unsigned int off);
-void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context);
-void rds_iw_send_init_ring(struct rds_iw_connection *ic);
-void rds_iw_send_clear_ring(struct rds_iw_connection *ic);
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op);
-void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits);
-void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted);
-int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted,
-                            u32 *adv_credits, int need_posted, int max_posted);
-
-/* ib_stats.c */
-DECLARE_PER_CPU(struct rds_iw_statistics, rds_iw_stats);
-#define rds_iw_stats_inc(member) rds_stats_inc_which(rds_iw_stats, member)
-unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
-                                   unsigned int avail);
-
-/* ib_sysctl.c */
-int rds_iw_sysctl_init(void);
-void rds_iw_sysctl_exit(void);
-extern unsigned long rds_iw_sysctl_max_send_wr;
-extern unsigned long rds_iw_sysctl_max_recv_wr;
-extern unsigned long rds_iw_sysctl_max_unsig_wrs;
-extern unsigned long rds_iw_sysctl_max_unsig_bytes;
-extern unsigned long rds_iw_sysctl_max_recv_allocation;
-extern unsigned int rds_iw_sysctl_flow_control;
-
-/*
- * Helper functions for getting/setting the header and data SGEs in
- * RDS packets (not RDMA)
- */
-static inline struct ib_sge *
-rds_iw_header_sge(struct rds_iw_connection *ic, struct ib_sge *sge)
-{
-       return &sge[0];
-}
-
-static inline struct ib_sge *
-rds_iw_data_sge(struct rds_iw_connection *ic, struct ib_sge *sge)
-{
-       return &sge[1];
-}
-
-#endif
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
deleted file mode 100644 (file)
index aea4c91..0000000
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/ratelimit.h>
-
-#include "rds.h"
-#include "iw.h"
-
-/*
- * Set the selected protocol version
- */
-static void rds_iw_set_protocol(struct rds_connection *conn, unsigned int version)
-{
-       conn->c_version = version;
-}
-
-/*
- * Set up flow control
- */
-static void rds_iw_set_flow_control(struct rds_connection *conn, u32 credits)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       if (rds_iw_sysctl_flow_control && credits != 0) {
-               /* We're doing flow control */
-               ic->i_flowctl = 1;
-               rds_iw_send_add_credits(conn, credits);
-       } else {
-               ic->i_flowctl = 0;
-       }
-}
-
-/*
- * Connection established.
- * We get here for both outgoing and incoming connection.
- */
-void rds_iw_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_event *event)
-{
-       const struct rds_iw_connect_private *dp = NULL;
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rds_iw_device *rds_iwdev;
-       int err;
-
-       if (event->param.conn.private_data_len) {
-               dp = event->param.conn.private_data;
-
-               rds_iw_set_protocol(conn,
-                               RDS_PROTOCOL(dp->dp_protocol_major,
-                                       dp->dp_protocol_minor));
-               rds_iw_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
-       }
-
-       /* update ib_device with this local ipaddr & conn */
-       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
-       err = rds_iw_update_cm_id(rds_iwdev, ic->i_cm_id);
-       if (err)
-               printk(KERN_ERR "rds_iw_update_ipaddr failed (%d)\n", err);
-       rds_iw_add_conn(rds_iwdev, conn);
-
-       /* If the peer gave us the last packet it saw, process this as if
-        * we had received a regular ACK. */
-       if (dp && dp->dp_ack_seq)
-               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
-
-       printk(KERN_NOTICE "RDS/IW: connected to %pI4<->%pI4 version %u.%u%s\n",
-                       &conn->c_laddr, &conn->c_faddr,
-                       RDS_PROTOCOL_MAJOR(conn->c_version),
-                       RDS_PROTOCOL_MINOR(conn->c_version),
-                       ic->i_flowctl ? ", flow control" : "");
-
-       rds_connect_complete(conn);
-}
-
-static void rds_iw_cm_fill_conn_param(struct rds_connection *conn,
-                       struct rdma_conn_param *conn_param,
-                       struct rds_iw_connect_private *dp,
-                       u32 protocol_version)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       memset(conn_param, 0, sizeof(struct rdma_conn_param));
-       /* XXX tune these? */
-       conn_param->responder_resources = 1;
-       conn_param->initiator_depth = 1;
-
-       if (dp) {
-               memset(dp, 0, sizeof(*dp));
-               dp->dp_saddr = conn->c_laddr;
-               dp->dp_daddr = conn->c_faddr;
-               dp->dp_protocol_major = RDS_PROTOCOL_MAJOR(protocol_version);
-               dp->dp_protocol_minor = RDS_PROTOCOL_MINOR(protocol_version);
-               dp->dp_protocol_minor_mask = cpu_to_be16(RDS_IW_SUPPORTED_PROTOCOLS);
-               dp->dp_ack_seq = rds_iw_piggyb_ack(ic);
-
-               /* Advertise flow control */
-               if (ic->i_flowctl) {
-                       unsigned int credits;
-
-                       credits = IB_GET_POST_CREDITS(atomic_read(&ic->i_credits));
-                       dp->dp_credit = cpu_to_be32(credits);
-                       atomic_sub(IB_SET_POST_CREDITS(credits), &ic->i_credits);
-               }
-
-               conn_param->private_data = dp;
-               conn_param->private_data_len = sizeof(*dp);
-       }
-}
-
-static void rds_iw_cq_event_handler(struct ib_event *event, void *data)
-{
-       rdsdebug("event %u data %p\n", event->event, data);
-}
-
-static void rds_iw_qp_event_handler(struct ib_event *event, void *data)
-{
-       struct rds_connection *conn = data;
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       rdsdebug("conn %p ic %p event %u\n", conn, ic, event->event);
-
-       switch (event->event) {
-       case IB_EVENT_COMM_EST:
-               rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
-               break;
-       case IB_EVENT_QP_REQ_ERR:
-       case IB_EVENT_QP_FATAL:
-       default:
-               rdsdebug("Fatal QP Event %u "
-                       "- connection %pI4->%pI4, reconnecting\n",
-                       event->event, &conn->c_laddr,
-                       &conn->c_faddr);
-               rds_conn_drop(conn);
-               break;
-       }
-}
-
-/*
- * Create a QP
- */
-static int rds_iw_init_qp_attrs(struct ib_qp_init_attr *attr,
-               struct rds_iw_device *rds_iwdev,
-               struct rds_iw_work_ring *send_ring,
-               void (*send_cq_handler)(struct ib_cq *, void *),
-               struct rds_iw_work_ring *recv_ring,
-               void (*recv_cq_handler)(struct ib_cq *, void *),
-               void *context)
-{
-       struct ib_device *dev = rds_iwdev->dev;
-       struct ib_cq_init_attr cq_attr = {};
-       unsigned int send_size, recv_size;
-       int ret;
-
-       /* The offset of 1 is to accommodate the additional ACK WR. */
-       send_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_send_wr + 1);
-       recv_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_recv_wr + 1);
-       rds_iw_ring_resize(send_ring, send_size - 1);
-       rds_iw_ring_resize(recv_ring, recv_size - 1);
-
-       memset(attr, 0, sizeof(*attr));
-       attr->event_handler = rds_iw_qp_event_handler;
-       attr->qp_context = context;
-       attr->cap.max_send_wr = send_size;
-       attr->cap.max_recv_wr = recv_size;
-       attr->cap.max_send_sge = rds_iwdev->max_sge;
-       attr->cap.max_recv_sge = RDS_IW_RECV_SGE;
-       attr->sq_sig_type = IB_SIGNAL_REQ_WR;
-       attr->qp_type = IB_QPT_RC;
-
-       cq_attr.cqe = send_size;
-       attr->send_cq = ib_create_cq(dev, send_cq_handler,
-                                    rds_iw_cq_event_handler,
-                                    context, &cq_attr);
-       if (IS_ERR(attr->send_cq)) {
-               ret = PTR_ERR(attr->send_cq);
-               attr->send_cq = NULL;
-               rdsdebug("ib_create_cq send failed: %d\n", ret);
-               goto out;
-       }
-
-       cq_attr.cqe = recv_size;
-       attr->recv_cq = ib_create_cq(dev, recv_cq_handler,
-                                    rds_iw_cq_event_handler,
-                                    context, &cq_attr);
-       if (IS_ERR(attr->recv_cq)) {
-               ret = PTR_ERR(attr->recv_cq);
-               attr->recv_cq = NULL;
-               rdsdebug("ib_create_cq send failed: %d\n", ret);
-               goto out;
-       }
-
-       ret = ib_req_notify_cq(attr->send_cq, IB_CQ_NEXT_COMP);
-       if (ret) {
-               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
-               goto out;
-       }
-
-       ret = ib_req_notify_cq(attr->recv_cq, IB_CQ_SOLICITED);
-       if (ret) {
-               rdsdebug("ib_req_notify_cq recv failed: %d\n", ret);
-               goto out;
-       }
-
-out:
-       if (ret) {
-               if (attr->send_cq)
-                       ib_destroy_cq(attr->send_cq);
-               if (attr->recv_cq)
-                       ib_destroy_cq(attr->recv_cq);
-       }
-       return ret;
-}
-
-/*
- * This needs to be very careful to not leave IS_ERR pointers around for
- * cleanup to trip over.
- */
-static int rds_iw_setup_qp(struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct ib_device *dev = ic->i_cm_id->device;
-       struct ib_qp_init_attr attr;
-       struct rds_iw_device *rds_iwdev;
-       int ret;
-
-       /* rds_iw_add_one creates a rds_iw_device object per IB device,
-        * and allocates a protection domain, memory range and MR pool
-        * for each.  If that fails for any reason, it will not register
-        * the rds_iwdev at all.
-        */
-       rds_iwdev = ib_get_client_data(dev, &rds_iw_client);
-       if (!rds_iwdev) {
-               printk_ratelimited(KERN_NOTICE "RDS/IW: No client_data for device %s\n",
-                                       dev->name);
-               return -EOPNOTSUPP;
-       }
-
-       /* Protection domain and memory range */
-       ic->i_pd = rds_iwdev->pd;
-       ic->i_mr = rds_iwdev->mr;
-
-       ret = rds_iw_init_qp_attrs(&attr, rds_iwdev,
-                       &ic->i_send_ring, rds_iw_send_cq_comp_handler,
-                       &ic->i_recv_ring, rds_iw_recv_cq_comp_handler,
-                       conn);
-       if (ret < 0)
-               goto out;
-
-       ic->i_send_cq = attr.send_cq;
-       ic->i_recv_cq = attr.recv_cq;
-
-       /*
-        * XXX this can fail if max_*_wr is too large?  Are we supposed
-        * to back off until we get a value that the hardware can support?
-        */
-       ret = rdma_create_qp(ic->i_cm_id, ic->i_pd, &attr);
-       if (ret) {
-               rdsdebug("rdma_create_qp failed: %d\n", ret);
-               goto out;
-       }
-
-       ic->i_send_hdrs = ib_dma_alloc_coherent(dev,
-                                          ic->i_send_ring.w_nr *
-                                               sizeof(struct rds_header),
-                                          &ic->i_send_hdrs_dma, GFP_KERNEL);
-       if (!ic->i_send_hdrs) {
-               ret = -ENOMEM;
-               rdsdebug("ib_dma_alloc_coherent send failed\n");
-               goto out;
-       }
-
-       ic->i_recv_hdrs = ib_dma_alloc_coherent(dev,
-                                          ic->i_recv_ring.w_nr *
-                                               sizeof(struct rds_header),
-                                          &ic->i_recv_hdrs_dma, GFP_KERNEL);
-       if (!ic->i_recv_hdrs) {
-               ret = -ENOMEM;
-               rdsdebug("ib_dma_alloc_coherent recv failed\n");
-               goto out;
-       }
-
-       ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
-                                      &ic->i_ack_dma, GFP_KERNEL);
-       if (!ic->i_ack) {
-               ret = -ENOMEM;
-               rdsdebug("ib_dma_alloc_coherent ack failed\n");
-               goto out;
-       }
-
-       ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_iw_send_work));
-       if (!ic->i_sends) {
-               ret = -ENOMEM;
-               rdsdebug("send allocation failed\n");
-               goto out;
-       }
-       rds_iw_send_init_ring(ic);
-
-       ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_iw_recv_work));
-       if (!ic->i_recvs) {
-               ret = -ENOMEM;
-               rdsdebug("recv allocation failed\n");
-               goto out;
-       }
-
-       rds_iw_recv_init_ring(ic);
-       rds_iw_recv_init_ack(ic);
-
-       /* Post receive buffers - as a side effect, this will update
-        * the posted credit count. */
-       rds_iw_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
-
-       rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr,
-                ic->i_send_cq, ic->i_recv_cq);
-
-out:
-       return ret;
-}
-
-static u32 rds_iw_protocol_compatible(const struct rds_iw_connect_private *dp)
-{
-       u16 common;
-       u32 version = 0;
-
-       /* rdma_cm private data is odd - when there is any private data in the
-        * request, we will be given a pretty large buffer without telling us the
-        * original size. The only way to tell the difference is by looking at
-        * the contents, which are initialized to zero.
-        * If the protocol version fields aren't set, this is a connection attempt
-        * from an older version. This could could be 3.0 or 2.0 - we can't tell.
-        * We really should have changed this for OFED 1.3 :-( */
-       if (dp->dp_protocol_major == 0)
-               return RDS_PROTOCOL_3_0;
-
-       common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IW_SUPPORTED_PROTOCOLS;
-       if (dp->dp_protocol_major == 3 && common) {
-               version = RDS_PROTOCOL_3_0;
-               while ((common >>= 1) != 0)
-                       version++;
-       }
-       printk_ratelimited(KERN_NOTICE "RDS: Connection from %pI4 using "
-                       "incompatible protocol version %u.%u\n",
-                       &dp->dp_saddr,
-                       dp->dp_protocol_major,
-                       dp->dp_protocol_minor);
-       return version;
-}
-
-int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
-                                   struct rdma_cm_event *event)
-{
-       const struct rds_iw_connect_private *dp = event->param.conn.private_data;
-       struct rds_iw_connect_private dp_rep;
-       struct rds_connection *conn = NULL;
-       struct rds_iw_connection *ic = NULL;
-       struct rdma_conn_param conn_param;
-       struct rds_iw_device *rds_iwdev;
-       u32 version;
-       int err, destroy = 1;
-
-       /* Check whether the remote protocol version matches ours. */
-       version = rds_iw_protocol_compatible(dp);
-       if (!version)
-               goto out;
-
-       rdsdebug("saddr %pI4 daddr %pI4 RDSv%u.%u\n",
-                &dp->dp_saddr, &dp->dp_daddr,
-                RDS_PROTOCOL_MAJOR(version), RDS_PROTOCOL_MINOR(version));
-
-       /* RDS/IW is not currently netns aware, thus init_net */
-       conn = rds_conn_create(&init_net, dp->dp_daddr, dp->dp_saddr,
-                              &rds_iw_transport, GFP_KERNEL);
-       if (IS_ERR(conn)) {
-               rdsdebug("rds_conn_create failed (%ld)\n", PTR_ERR(conn));
-               conn = NULL;
-               goto out;
-       }
-
-       /*
-        * The connection request may occur while the
-        * previous connection exist, e.g. in case of failover.
-        * But as connections may be initiated simultaneously
-        * by both hosts, we have a random backoff mechanism -
-        * see the comment above rds_queue_reconnect()
-        */
-       mutex_lock(&conn->c_cm_lock);
-       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) {
-               if (rds_conn_state(conn) == RDS_CONN_UP) {
-                       rdsdebug("incoming connect while connecting\n");
-                       rds_conn_drop(conn);
-                       rds_iw_stats_inc(s_iw_listen_closed_stale);
-               } else
-               if (rds_conn_state(conn) == RDS_CONN_CONNECTING) {
-                       /* Wait and see - our connect may still be succeeding */
-                       rds_iw_stats_inc(s_iw_connect_raced);
-               }
-               mutex_unlock(&conn->c_cm_lock);
-               goto out;
-       }
-
-       ic = conn->c_transport_data;
-
-       rds_iw_set_protocol(conn, version);
-       rds_iw_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
-
-       /* If the peer gave us the last packet it saw, process this as if
-        * we had received a regular ACK. */
-       if (dp->dp_ack_seq)
-               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
-
-       BUG_ON(cm_id->context);
-       BUG_ON(ic->i_cm_id);
-
-       ic->i_cm_id = cm_id;
-       cm_id->context = conn;
-
-       rds_iwdev = ib_get_client_data(cm_id->device, &rds_iw_client);
-       ic->i_dma_local_lkey = rds_iwdev->dma_local_lkey;
-
-       /* We got halfway through setting up the ib_connection, if we
-        * fail now, we have to take the long route out of this mess. */
-       destroy = 0;
-
-       err = rds_iw_setup_qp(conn);
-       if (err) {
-               rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", err);
-               mutex_unlock(&conn->c_cm_lock);
-               goto out;
-       }
-
-       rds_iw_cm_fill_conn_param(conn, &conn_param, &dp_rep, version);
-
-       /* rdma_accept() calls rdma_reject() internally if it fails */
-       err = rdma_accept(cm_id, &conn_param);
-       mutex_unlock(&conn->c_cm_lock);
-       if (err) {
-               rds_iw_conn_error(conn, "rdma_accept failed (%d)\n", err);
-               goto out;
-       }
-
-       return 0;
-
-out:
-       rdma_reject(cm_id, NULL, 0);
-       return destroy;
-}
-
-
-int rds_iw_cm_initiate_connect(struct rdma_cm_id *cm_id)
-{
-       struct rds_connection *conn = cm_id->context;
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rdma_conn_param conn_param;
-       struct rds_iw_connect_private dp;
-       int ret;
-
-       /* If the peer doesn't do protocol negotiation, we must
-        * default to RDSv3.0 */
-       rds_iw_set_protocol(conn, RDS_PROTOCOL_3_0);
-       ic->i_flowctl = rds_iw_sysctl_flow_control;     /* advertise flow control */
-
-       ret = rds_iw_setup_qp(conn);
-       if (ret) {
-               rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", ret);
-               goto out;
-       }
-
-       rds_iw_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION);
-
-       ret = rdma_connect(cm_id, &conn_param);
-       if (ret)
-               rds_iw_conn_error(conn, "rdma_connect failed (%d)\n", ret);
-
-out:
-       /* Beware - returning non-zero tells the rdma_cm to destroy
-        * the cm_id. We should certainly not do it as long as we still
-        * "own" the cm_id. */
-       if (ret) {
-               struct rds_iw_connection *ic = conn->c_transport_data;
-
-               if (ic->i_cm_id == cm_id)
-                       ret = 0;
-       }
-       return ret;
-}
-
-int rds_iw_conn_connect(struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rds_iw_device *rds_iwdev;
-       struct sockaddr_in src, dest;
-       int ret;
-
-       /* XXX I wonder what affect the port space has */
-       /* delegate cm event handler to rdma_transport */
-       ic->i_cm_id = rdma_create_id(&init_net, rds_rdma_cm_event_handler, conn,
-                                    RDMA_PS_TCP, IB_QPT_RC);
-       if (IS_ERR(ic->i_cm_id)) {
-               ret = PTR_ERR(ic->i_cm_id);
-               ic->i_cm_id = NULL;
-               rdsdebug("rdma_create_id() failed: %d\n", ret);
-               goto out;
-       }
-
-       rdsdebug("created cm id %p for conn %p\n", ic->i_cm_id, conn);
-
-       src.sin_family = AF_INET;
-       src.sin_addr.s_addr = (__force u32)conn->c_laddr;
-       src.sin_port = (__force u16)htons(0);
-
-       /* First, bind to the local address and device. */
-       ret = rdma_bind_addr(ic->i_cm_id, (struct sockaddr *) &src);
-       if (ret) {
-               rdsdebug("rdma_bind_addr(%pI4) failed: %d\n",
-                               &conn->c_laddr, ret);
-               rdma_destroy_id(ic->i_cm_id);
-               ic->i_cm_id = NULL;
-               goto out;
-       }
-
-       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
-       ic->i_dma_local_lkey = rds_iwdev->dma_local_lkey;
-
-       dest.sin_family = AF_INET;
-       dest.sin_addr.s_addr = (__force u32)conn->c_faddr;
-       dest.sin_port = (__force u16)htons(RDS_PORT);
-
-       ret = rdma_resolve_addr(ic->i_cm_id, (struct sockaddr *)&src,
-                               (struct sockaddr *)&dest,
-                               RDS_RDMA_RESOLVE_TIMEOUT_MS);
-       if (ret) {
-               rdsdebug("addr resolve failed for cm id %p: %d\n", ic->i_cm_id,
-                        ret);
-               rdma_destroy_id(ic->i_cm_id);
-               ic->i_cm_id = NULL;
-       }
-
-out:
-       return ret;
-}
-
-/*
- * This is so careful about only cleaning up resources that were built up
- * so that it can be called at any point during startup.  In fact it
- * can be called multiple times for a given connection.
- */
-void rds_iw_conn_shutdown(struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       int err = 0;
-       struct ib_qp_attr qp_attr;
-
-       rdsdebug("cm %p pd %p cq %p %p qp %p\n", ic->i_cm_id,
-                ic->i_pd, ic->i_send_cq, ic->i_recv_cq,
-                ic->i_cm_id ? ic->i_cm_id->qp : NULL);
-
-       if (ic->i_cm_id) {
-               struct ib_device *dev = ic->i_cm_id->device;
-
-               rdsdebug("disconnecting cm %p\n", ic->i_cm_id);
-               err = rdma_disconnect(ic->i_cm_id);
-               if (err) {
-                       /* Actually this may happen quite frequently, when
-                        * an outgoing connect raced with an incoming connect.
-                        */
-                       rdsdebug("failed to disconnect, cm: %p err %d\n",
-                                ic->i_cm_id, err);
-               }
-
-               if (ic->i_cm_id->qp) {
-                       qp_attr.qp_state = IB_QPS_ERR;
-                       ib_modify_qp(ic->i_cm_id->qp, &qp_attr, IB_QP_STATE);
-               }
-
-               wait_event(rds_iw_ring_empty_wait,
-                       rds_iw_ring_empty(&ic->i_send_ring) &&
-                       rds_iw_ring_empty(&ic->i_recv_ring));
-
-               if (ic->i_send_hdrs)
-                       ib_dma_free_coherent(dev,
-                                          ic->i_send_ring.w_nr *
-                                               sizeof(struct rds_header),
-                                          ic->i_send_hdrs,
-                                          ic->i_send_hdrs_dma);
-
-               if (ic->i_recv_hdrs)
-                       ib_dma_free_coherent(dev,
-                                          ic->i_recv_ring.w_nr *
-                                               sizeof(struct rds_header),
-                                          ic->i_recv_hdrs,
-                                          ic->i_recv_hdrs_dma);
-
-               if (ic->i_ack)
-                       ib_dma_free_coherent(dev, sizeof(struct rds_header),
-                                            ic->i_ack, ic->i_ack_dma);
-
-               if (ic->i_sends)
-                       rds_iw_send_clear_ring(ic);
-               if (ic->i_recvs)
-                       rds_iw_recv_clear_ring(ic);
-
-               if (ic->i_cm_id->qp)
-                       rdma_destroy_qp(ic->i_cm_id);
-               if (ic->i_send_cq)
-                       ib_destroy_cq(ic->i_send_cq);
-               if (ic->i_recv_cq)
-                       ib_destroy_cq(ic->i_recv_cq);
-
-               /*
-                * If associated with an rds_iw_device:
-                *      Move connection back to the nodev list.
-                *      Remove cm_id from the device cm_id list.
-                */
-               if (ic->rds_iwdev)
-                       rds_iw_remove_conn(ic->rds_iwdev, conn);
-
-               rdma_destroy_id(ic->i_cm_id);
-
-               ic->i_cm_id = NULL;
-               ic->i_pd = NULL;
-               ic->i_mr = NULL;
-               ic->i_send_cq = NULL;
-               ic->i_recv_cq = NULL;
-               ic->i_send_hdrs = NULL;
-               ic->i_recv_hdrs = NULL;
-               ic->i_ack = NULL;
-       }
-       BUG_ON(ic->rds_iwdev);
-
-       /* Clear pending transmit */
-       if (ic->i_rm) {
-               rds_message_put(ic->i_rm);
-               ic->i_rm = NULL;
-       }
-
-       /* Clear the ACK state */
-       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-#ifdef KERNEL_HAS_ATOMIC64
-       atomic64_set(&ic->i_ack_next, 0);
-#else
-       ic->i_ack_next = 0;
-#endif
-       ic->i_ack_recv = 0;
-
-       /* Clear flow control state */
-       ic->i_flowctl = 0;
-       atomic_set(&ic->i_credits, 0);
-
-       rds_iw_ring_init(&ic->i_send_ring, rds_iw_sysctl_max_send_wr);
-       rds_iw_ring_init(&ic->i_recv_ring, rds_iw_sysctl_max_recv_wr);
-
-       if (ic->i_iwinc) {
-               rds_inc_put(&ic->i_iwinc->ii_inc);
-               ic->i_iwinc = NULL;
-       }
-
-       vfree(ic->i_sends);
-       ic->i_sends = NULL;
-       vfree(ic->i_recvs);
-       ic->i_recvs = NULL;
-       rdsdebug("shutdown complete\n");
-}
-
-int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
-{
-       struct rds_iw_connection *ic;
-       unsigned long flags;
-
-       /* XXX too lazy? */
-       ic = kzalloc(sizeof(struct rds_iw_connection), gfp);
-       if (!ic)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&ic->iw_node);
-       tasklet_init(&ic->i_recv_tasklet, rds_iw_recv_tasklet_fn,
-                    (unsigned long) ic);
-       mutex_init(&ic->i_recv_mutex);
-#ifndef KERNEL_HAS_ATOMIC64
-       spin_lock_init(&ic->i_ack_lock);
-#endif
-
-       /*
-        * rds_iw_conn_shutdown() waits for these to be emptied so they
-        * must be initialized before it can be called.
-        */
-       rds_iw_ring_init(&ic->i_send_ring, rds_iw_sysctl_max_send_wr);
-       rds_iw_ring_init(&ic->i_recv_ring, rds_iw_sysctl_max_recv_wr);
-
-       ic->conn = conn;
-       conn->c_transport_data = ic;
-
-       spin_lock_irqsave(&iw_nodev_conns_lock, flags);
-       list_add_tail(&ic->iw_node, &iw_nodev_conns);
-       spin_unlock_irqrestore(&iw_nodev_conns_lock, flags);
-
-
-       rdsdebug("conn %p conn ic %p\n", conn, conn->c_transport_data);
-       return 0;
-}
-
-/*
- * Free a connection. Connection must be shut down and not set for reconnect.
- */
-void rds_iw_conn_free(void *arg)
-{
-       struct rds_iw_connection *ic = arg;
-       spinlock_t      *lock_ptr;
-
-       rdsdebug("ic %p\n", ic);
-
-       /*
-        * Conn is either on a dev's list or on the nodev list.
-        * A race with shutdown() or connect() would cause problems
-        * (since rds_iwdev would change) but that should never happen.
-        */
-       lock_ptr = ic->rds_iwdev ? &ic->rds_iwdev->spinlock : &iw_nodev_conns_lock;
-
-       spin_lock_irq(lock_ptr);
-       list_del(&ic->iw_node);
-       spin_unlock_irq(lock_ptr);
-
-       kfree(ic);
-}
-
-/*
- * An error occurred on the connection
- */
-void
-__rds_iw_conn_error(struct rds_connection *conn, const char *fmt, ...)
-{
-       va_list ap;
-
-       rds_conn_drop(conn);
-
-       va_start(ap, fmt);
-       vprintk(fmt, ap);
-       va_end(ap);
-}
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
deleted file mode 100644 (file)
index b09a40c..0000000
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/ratelimit.h>
-
-#include "rds.h"
-#include "iw.h"
-
-
-/*
- * This is stored as mr->r_trans_private.
- */
-struct rds_iw_mr {
-       struct rds_iw_device    *device;
-       struct rds_iw_mr_pool   *pool;
-       struct rdma_cm_id       *cm_id;
-
-       struct ib_mr    *mr;
-
-       struct rds_iw_mapping   mapping;
-       unsigned char           remap_count;
-};
-
-/*
- * Our own little MR pool
- */
-struct rds_iw_mr_pool {
-       struct rds_iw_device    *device;                /* back ptr to the device that owns us */
-
-       struct mutex            flush_lock;             /* serialize fmr invalidate */
-       struct work_struct      flush_worker;           /* flush worker */
-
-       spinlock_t              list_lock;              /* protect variables below */
-       atomic_t                item_count;             /* total # of MRs */
-       atomic_t                dirty_count;            /* # dirty of MRs */
-       struct list_head        dirty_list;             /* dirty mappings */
-       struct list_head        clean_list;             /* unused & unamapped MRs */
-       atomic_t                free_pinned;            /* memory pinned by free MRs */
-       unsigned long           max_message_size;       /* in pages */
-       unsigned long           max_items;
-       unsigned long           max_items_soft;
-       unsigned long           max_free_pinned;
-       int                     max_pages;
-};
-
-static void rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all);
-static void rds_iw_mr_pool_flush_worker(struct work_struct *work);
-static int rds_iw_init_reg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
-static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
-                         struct rds_iw_mr *ibmr,
-                         struct scatterlist *sg, unsigned int nents);
-static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
-static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
-                       struct list_head *unmap_list,
-                       struct list_head *kill_list,
-                       int *unpinned);
-static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
-
-static int rds_iw_get_device(struct sockaddr_in *src, struct sockaddr_in *dst,
-                            struct rds_iw_device **rds_iwdev,
-                            struct rdma_cm_id **cm_id)
-{
-       struct rds_iw_device *iwdev;
-       struct rds_iw_cm_id *i_cm_id;
-
-       *rds_iwdev = NULL;
-       *cm_id = NULL;
-
-       list_for_each_entry(iwdev, &rds_iw_devices, list) {
-               spin_lock_irq(&iwdev->spinlock);
-               list_for_each_entry(i_cm_id, &iwdev->cm_id_list, list) {
-                       struct sockaddr_in *src_addr, *dst_addr;
-
-                       src_addr = (struct sockaddr_in *)&i_cm_id->cm_id->route.addr.src_addr;
-                       dst_addr = (struct sockaddr_in *)&i_cm_id->cm_id->route.addr.dst_addr;
-
-                       rdsdebug("local ipaddr = %x port %d, "
-                                "remote ipaddr = %x port %d"
-                                "..looking for %x port %d, "
-                                "remote ipaddr = %x port %d\n",
-                               src_addr->sin_addr.s_addr,
-                               src_addr->sin_port,
-                               dst_addr->sin_addr.s_addr,
-                               dst_addr->sin_port,
-                               src->sin_addr.s_addr,
-                               src->sin_port,
-                               dst->sin_addr.s_addr,
-                               dst->sin_port);
-#ifdef WORKING_TUPLE_DETECTION
-                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr &&
-                           src_addr->sin_port == src->sin_port &&
-                           dst_addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
-                           dst_addr->sin_port == dst->sin_port) {
-#else
-                       /* FIXME - needs to compare the local and remote
-                        * ipaddr/port tuple, but the ipaddr is the only
-                        * available information in the rds_sock (as the rest are
-                        * zero'ed.  It doesn't appear to be properly populated
-                        * during connection setup...
-                        */
-                       if (src_addr->sin_addr.s_addr == src->sin_addr.s_addr) {
-#endif
-                               spin_unlock_irq(&iwdev->spinlock);
-                               *rds_iwdev = iwdev;
-                               *cm_id = i_cm_id->cm_id;
-                               return 0;
-                       }
-               }
-               spin_unlock_irq(&iwdev->spinlock);
-       }
-
-       return 1;
-}
-
-static int rds_iw_add_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
-{
-       struct rds_iw_cm_id *i_cm_id;
-
-       i_cm_id = kmalloc(sizeof *i_cm_id, GFP_KERNEL);
-       if (!i_cm_id)
-               return -ENOMEM;
-
-       i_cm_id->cm_id = cm_id;
-
-       spin_lock_irq(&rds_iwdev->spinlock);
-       list_add_tail(&i_cm_id->list, &rds_iwdev->cm_id_list);
-       spin_unlock_irq(&rds_iwdev->spinlock);
-
-       return 0;
-}
-
-static void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev,
-                               struct rdma_cm_id *cm_id)
-{
-       struct rds_iw_cm_id *i_cm_id;
-
-       spin_lock_irq(&rds_iwdev->spinlock);
-       list_for_each_entry(i_cm_id, &rds_iwdev->cm_id_list, list) {
-               if (i_cm_id->cm_id == cm_id) {
-                       list_del(&i_cm_id->list);
-                       kfree(i_cm_id);
-                       break;
-               }
-       }
-       spin_unlock_irq(&rds_iwdev->spinlock);
-}
-
-
-int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
-{
-       struct sockaddr_in *src_addr, *dst_addr;
-       struct rds_iw_device *rds_iwdev_old;
-       struct rdma_cm_id *pcm_id;
-       int rc;
-
-       src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
-       dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
-
-       rc = rds_iw_get_device(src_addr, dst_addr, &rds_iwdev_old, &pcm_id);
-       if (rc)
-               rds_iw_remove_cm_id(rds_iwdev, cm_id);
-
-       return rds_iw_add_cm_id(rds_iwdev, cm_id);
-}
-
-void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       /* conn was previously on the nodev_conns_list */
-       spin_lock_irq(&iw_nodev_conns_lock);
-       BUG_ON(list_empty(&iw_nodev_conns));
-       BUG_ON(list_empty(&ic->iw_node));
-       list_del(&ic->iw_node);
-
-       spin_lock(&rds_iwdev->spinlock);
-       list_add_tail(&ic->iw_node, &rds_iwdev->conn_list);
-       spin_unlock(&rds_iwdev->spinlock);
-       spin_unlock_irq(&iw_nodev_conns_lock);
-
-       ic->rds_iwdev = rds_iwdev;
-}
-
-void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       /* place conn on nodev_conns_list */
-       spin_lock(&iw_nodev_conns_lock);
-
-       spin_lock_irq(&rds_iwdev->spinlock);
-       BUG_ON(list_empty(&ic->iw_node));
-       list_del(&ic->iw_node);
-       spin_unlock_irq(&rds_iwdev->spinlock);
-
-       list_add_tail(&ic->iw_node, &iw_nodev_conns);
-
-       spin_unlock(&iw_nodev_conns_lock);
-
-       rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id);
-       ic->rds_iwdev = NULL;
-}
-
-void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock)
-{
-       struct rds_iw_connection *ic, *_ic;
-       LIST_HEAD(tmp_list);
-
-       /* avoid calling conn_destroy with irqs off */
-       spin_lock_irq(list_lock);
-       list_splice(list, &tmp_list);
-       INIT_LIST_HEAD(list);
-       spin_unlock_irq(list_lock);
-
-       list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node)
-               rds_conn_destroy(ic->conn);
-}
-
-static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg,
-               struct scatterlist *list, unsigned int sg_len)
-{
-       sg->list = list;
-       sg->len = sg_len;
-       sg->dma_len = 0;
-       sg->dma_npages = 0;
-       sg->bytes = 0;
-}
-
-static int rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
-                                 struct rds_iw_scatterlist *sg)
-{
-       struct ib_device *dev = rds_iwdev->dev;
-       int i, ret;
-
-       WARN_ON(sg->dma_len);
-
-       sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
-       if (unlikely(!sg->dma_len)) {
-               printk(KERN_WARNING "RDS/IW: dma_map_sg failed!\n");
-               return -EBUSY;
-       }
-
-       sg->bytes = 0;
-       sg->dma_npages = 0;
-
-       ret = -EINVAL;
-       for (i = 0; i < sg->dma_len; ++i) {
-               unsigned int dma_len = ib_sg_dma_len(dev, &sg->list[i]);
-               u64 dma_addr = ib_sg_dma_address(dev, &sg->list[i]);
-               u64 end_addr;
-
-               sg->bytes += dma_len;
-
-               end_addr = dma_addr + dma_len;
-               if (dma_addr & PAGE_MASK) {
-                       if (i > 0)
-                               goto out_unmap;
-                       dma_addr &= ~PAGE_MASK;
-               }
-               if (end_addr & PAGE_MASK) {
-                       if (i < sg->dma_len - 1)
-                               goto out_unmap;
-                       end_addr = (end_addr + PAGE_MASK) & ~PAGE_MASK;
-               }
-
-               sg->dma_npages += (end_addr - dma_addr) >> PAGE_SHIFT;
-       }
-
-       /* Now gather the dma addrs into one list */
-       if (sg->dma_npages > fastreg_message_size)
-               goto out_unmap;
-
-
-
-       return 0;
-
-out_unmap:
-       ib_dma_unmap_sg(rds_iwdev->dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
-       sg->dma_len = 0;
-       return ret;
-}
-
-
-struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *rds_iwdev)
-{
-       struct rds_iw_mr_pool *pool;
-
-       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-       if (!pool) {
-               printk(KERN_WARNING "RDS/IW: rds_iw_create_mr_pool alloc error\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       pool->device = rds_iwdev;
-       INIT_LIST_HEAD(&pool->dirty_list);
-       INIT_LIST_HEAD(&pool->clean_list);
-       mutex_init(&pool->flush_lock);
-       spin_lock_init(&pool->list_lock);
-       INIT_WORK(&pool->flush_worker, rds_iw_mr_pool_flush_worker);
-
-       pool->max_message_size = fastreg_message_size;
-       pool->max_items = fastreg_pool_size;
-       pool->max_free_pinned = pool->max_items * pool->max_message_size / 4;
-       pool->max_pages = fastreg_message_size;
-
-       /* We never allow more than max_items MRs to be allocated.
-        * When we exceed more than max_items_soft, we start freeing
-        * items more aggressively.
-        * Make sure that max_items > max_items_soft > max_items / 2
-        */
-       pool->max_items_soft = pool->max_items * 3 / 4;
-
-       return pool;
-}
-
-void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo)
-{
-       struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
-
-       iinfo->rdma_mr_max = pool->max_items;
-       iinfo->rdma_mr_size = pool->max_pages;
-}
-
-void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *pool)
-{
-       flush_workqueue(rds_wq);
-       rds_iw_flush_mr_pool(pool, 1);
-       BUG_ON(atomic_read(&pool->item_count));
-       BUG_ON(atomic_read(&pool->free_pinned));
-       kfree(pool);
-}
-
-static inline struct rds_iw_mr *rds_iw_reuse_fmr(struct rds_iw_mr_pool *pool)
-{
-       struct rds_iw_mr *ibmr = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pool->list_lock, flags);
-       if (!list_empty(&pool->clean_list)) {
-               ibmr = list_entry(pool->clean_list.next, struct rds_iw_mr, mapping.m_list);
-               list_del_init(&ibmr->mapping.m_list);
-       }
-       spin_unlock_irqrestore(&pool->list_lock, flags);
-
-       return ibmr;
-}
-
-static struct rds_iw_mr *rds_iw_alloc_mr(struct rds_iw_device *rds_iwdev)
-{
-       struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
-       struct rds_iw_mr *ibmr = NULL;
-       int err = 0, iter = 0;
-
-       while (1) {
-               ibmr = rds_iw_reuse_fmr(pool);
-               if (ibmr)
-                       return ibmr;
-
-               /* No clean MRs - now we have the choice of either
-                * allocating a fresh MR up to the limit imposed by the
-                * driver, or flush any dirty unused MRs.
-                * We try to avoid stalling in the send path if possible,
-                * so we allocate as long as we're allowed to.
-                *
-                * We're fussy with enforcing the FMR limit, though. If the driver
-                * tells us we can't use more than N fmrs, we shouldn't start
-                * arguing with it */
-               if (atomic_inc_return(&pool->item_count) <= pool->max_items)
-                       break;
-
-               atomic_dec(&pool->item_count);
-
-               if (++iter > 2) {
-                       rds_iw_stats_inc(s_iw_rdma_mr_pool_depleted);
-                       return ERR_PTR(-EAGAIN);
-               }
-
-               /* We do have some empty MRs. Flush them out. */
-               rds_iw_stats_inc(s_iw_rdma_mr_pool_wait);
-               rds_iw_flush_mr_pool(pool, 0);
-       }
-
-       ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
-       if (!ibmr) {
-               err = -ENOMEM;
-               goto out_no_cigar;
-       }
-
-       spin_lock_init(&ibmr->mapping.m_lock);
-       INIT_LIST_HEAD(&ibmr->mapping.m_list);
-       ibmr->mapping.m_mr = ibmr;
-
-       err = rds_iw_init_reg(pool, ibmr);
-       if (err)
-               goto out_no_cigar;
-
-       rds_iw_stats_inc(s_iw_rdma_mr_alloc);
-       return ibmr;
-
-out_no_cigar:
-       if (ibmr) {
-               rds_iw_destroy_fastreg(pool, ibmr);
-               kfree(ibmr);
-       }
-       atomic_dec(&pool->item_count);
-       return ERR_PTR(err);
-}
-
-void rds_iw_sync_mr(void *trans_private, int direction)
-{
-       struct rds_iw_mr *ibmr = trans_private;
-       struct rds_iw_device *rds_iwdev = ibmr->device;
-
-       switch (direction) {
-       case DMA_FROM_DEVICE:
-               ib_dma_sync_sg_for_cpu(rds_iwdev->dev, ibmr->mapping.m_sg.list,
-                       ibmr->mapping.m_sg.dma_len, DMA_BIDIRECTIONAL);
-               break;
-       case DMA_TO_DEVICE:
-               ib_dma_sync_sg_for_device(rds_iwdev->dev, ibmr->mapping.m_sg.list,
-                       ibmr->mapping.m_sg.dma_len, DMA_BIDIRECTIONAL);
-               break;
-       }
-}
-
-/*
- * Flush our pool of MRs.
- * At a minimum, all currently unused MRs are unmapped.
- * If the number of MRs allocated exceeds the limit, we also try
- * to free as many MRs as needed to get back to this limit.
- */
-static void rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
-{
-       struct rds_iw_mr *ibmr, *next;
-       LIST_HEAD(unmap_list);
-       LIST_HEAD(kill_list);
-       unsigned long flags;
-       unsigned int nfreed = 0, ncleaned = 0, unpinned = 0;
-
-       rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
-
-       mutex_lock(&pool->flush_lock);
-
-       spin_lock_irqsave(&pool->list_lock, flags);
-       /* Get the list of all mappings to be destroyed */
-       list_splice_init(&pool->dirty_list, &unmap_list);
-       if (free_all)
-               list_splice_init(&pool->clean_list, &kill_list);
-       spin_unlock_irqrestore(&pool->list_lock, flags);
-
-       /* Batched invalidate of dirty MRs.
-        * For FMR based MRs, the mappings on the unmap list are
-        * actually members of an ibmr (ibmr->mapping). They either
-        * migrate to the kill_list, or have been cleaned and should be
-        * moved to the clean_list.
-        * For fastregs, they will be dynamically allocated, and
-        * will be destroyed by the unmap function.
-        */
-       if (!list_empty(&unmap_list)) {
-               ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list,
-                                                    &kill_list, &unpinned);
-               /* If we've been asked to destroy all MRs, move those
-                * that were simply cleaned to the kill list */
-               if (free_all)
-                       list_splice_init(&unmap_list, &kill_list);
-       }
-
-       /* Destroy any MRs that are past their best before date */
-       list_for_each_entry_safe(ibmr, next, &kill_list, mapping.m_list) {
-               rds_iw_stats_inc(s_iw_rdma_mr_free);
-               list_del(&ibmr->mapping.m_list);
-               rds_iw_destroy_fastreg(pool, ibmr);
-               kfree(ibmr);
-               nfreed++;
-       }
-
-       /* Anything that remains are laundered ibmrs, which we can add
-        * back to the clean list. */
-       if (!list_empty(&unmap_list)) {
-               spin_lock_irqsave(&pool->list_lock, flags);
-               list_splice(&unmap_list, &pool->clean_list);
-               spin_unlock_irqrestore(&pool->list_lock, flags);
-       }
-
-       atomic_sub(unpinned, &pool->free_pinned);
-       atomic_sub(ncleaned, &pool->dirty_count);
-       atomic_sub(nfreed, &pool->item_count);
-
-       mutex_unlock(&pool->flush_lock);
-}
-
-static void rds_iw_mr_pool_flush_worker(struct work_struct *work)
-{
-       struct rds_iw_mr_pool *pool = container_of(work, struct rds_iw_mr_pool, flush_worker);
-
-       rds_iw_flush_mr_pool(pool, 0);
-}
-
-void rds_iw_free_mr(void *trans_private, int invalidate)
-{
-       struct rds_iw_mr *ibmr = trans_private;
-       struct rds_iw_mr_pool *pool = ibmr->device->mr_pool;
-
-       rdsdebug("RDS/IW: free_mr nents %u\n", ibmr->mapping.m_sg.len);
-       if (!pool)
-               return;
-
-       /* Return it to the pool's free list */
-       rds_iw_free_fastreg(pool, ibmr);
-
-       /* If we've pinned too many pages, request a flush */
-       if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned ||
-           atomic_read(&pool->dirty_count) >= pool->max_items / 10)
-               queue_work(rds_wq, &pool->flush_worker);
-
-       if (invalidate) {
-               if (likely(!in_interrupt())) {
-                       rds_iw_flush_mr_pool(pool, 0);
-               } else {
-                       /* We get here if the user created a MR marked
-                        * as use_once and invalidate at the same time. */
-                       queue_work(rds_wq, &pool->flush_worker);
-               }
-       }
-}
-
-void rds_iw_flush_mrs(void)
-{
-       struct rds_iw_device *rds_iwdev;
-
-       list_for_each_entry(rds_iwdev, &rds_iw_devices, list) {
-               struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
-
-               if (pool)
-                       rds_iw_flush_mr_pool(pool, 0);
-       }
-}
-
-void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
-                   struct rds_sock *rs, u32 *key_ret)
-{
-       struct rds_iw_device *rds_iwdev;
-       struct rds_iw_mr *ibmr = NULL;
-       struct rdma_cm_id *cm_id;
-       struct sockaddr_in src = {
-               .sin_addr.s_addr = rs->rs_bound_addr,
-               .sin_port = rs->rs_bound_port,
-       };
-       struct sockaddr_in dst = {
-               .sin_addr.s_addr = rs->rs_conn_addr,
-               .sin_port = rs->rs_conn_port,
-       };
-       int ret;
-
-       ret = rds_iw_get_device(&src, &dst, &rds_iwdev, &cm_id);
-       if (ret || !cm_id) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (!rds_iwdev->mr_pool) {
-               ret = -ENODEV;
-               goto out;
-       }
-
-       ibmr = rds_iw_alloc_mr(rds_iwdev);
-       if (IS_ERR(ibmr))
-               return ibmr;
-
-       ibmr->cm_id = cm_id;
-       ibmr->device = rds_iwdev;
-
-       ret = rds_iw_map_reg(rds_iwdev->mr_pool, ibmr, sg, nents);
-       if (ret == 0)
-               *key_ret = ibmr->mr->rkey;
-       else
-               printk(KERN_WARNING "RDS/IW: failed to map mr (errno=%d)\n", ret);
-
-out:
-       if (ret) {
-               if (ibmr)
-                       rds_iw_free_mr(ibmr, 0);
-               ibmr = ERR_PTR(ret);
-       }
-       return ibmr;
-}
-
-/*
- * iWARP reg handling
- *
- * The life cycle of a fastreg registration is a bit different from
- * FMRs.
- * The idea behind fastreg is to have one MR, to which we bind different
- * mappings over time. To avoid stalling on the expensive map and invalidate
- * operations, these operations are pipelined on the same send queue on
- * which we want to send the message containing the r_key.
- *
- * This creates a bit of a problem for us, as we do not have the destination
- * IP in GET_MR, so the connection must be setup prior to the GET_MR call for
- * RDMA to be correctly setup.  If a fastreg request is present, rds_iw_xmit
- * will try to queue a LOCAL_INV (if needed) and a REG_MR work request
- * before queuing the SEND. When completions for these arrive, they are
- * dispatched to the MR has a bit set showing that RDMa can be performed.
- *
- * There is another interesting aspect that's related to invalidation.
- * The application can request that a mapping is invalidated in FREE_MR.
- * The expectation there is that this invalidation step includes ALL
- * PREVIOUSLY FREED MRs.
- */
-static int rds_iw_init_reg(struct rds_iw_mr_pool *pool,
-                          struct rds_iw_mr *ibmr)
-{
-       struct rds_iw_device *rds_iwdev = pool->device;
-       struct ib_mr *mr;
-       int err;
-
-       mr = ib_alloc_mr(rds_iwdev->pd, IB_MR_TYPE_MEM_REG,
-                        pool->max_message_size);
-       if (IS_ERR(mr)) {
-               err = PTR_ERR(mr);
-
-               printk(KERN_WARNING "RDS/IW: ib_alloc_mr failed (err=%d)\n", err);
-               return err;
-       }
-
-       ibmr->mr = mr;
-       return 0;
-}
-
-static int rds_iw_rdma_reg_mr(struct rds_iw_mapping *mapping)
-{
-       struct rds_iw_mr *ibmr = mapping->m_mr;
-       struct rds_iw_scatterlist *m_sg = &mapping->m_sg;
-       struct ib_reg_wr reg_wr;
-       struct ib_send_wr *failed_wr;
-       int ret, n;
-
-       n = ib_map_mr_sg_zbva(ibmr->mr, m_sg->list, m_sg->len, PAGE_SIZE);
-       if (unlikely(n != m_sg->len))
-               return n < 0 ? n : -EINVAL;
-
-       reg_wr.wr.next = NULL;
-       reg_wr.wr.opcode = IB_WR_REG_MR;
-       reg_wr.wr.wr_id = RDS_IW_REG_WR_ID;
-       reg_wr.wr.num_sge = 0;
-       reg_wr.mr = ibmr->mr;
-       reg_wr.key = mapping->m_rkey;
-       reg_wr.access = IB_ACCESS_LOCAL_WRITE |
-                       IB_ACCESS_REMOTE_READ |
-                       IB_ACCESS_REMOTE_WRITE;
-
-       /*
-        * Perform a WR for the reg_mr. Each individual page
-        * in the sg list is added to the fast reg page list and placed
-        * inside the reg_mr WR.  The key used is a rolling 8bit
-        * counter, which should guarantee uniqueness.
-        */
-       ib_update_fast_reg_key(ibmr->mr, ibmr->remap_count++);
-       mapping->m_rkey = ibmr->mr->rkey;
-
-       failed_wr = &reg_wr.wr;
-       ret = ib_post_send(ibmr->cm_id->qp, &reg_wr.wr, &failed_wr);
-       BUG_ON(failed_wr != &reg_wr.wr);
-       if (ret)
-               printk_ratelimited(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
-                       __func__, __LINE__, ret);
-       return ret;
-}
-
-static int rds_iw_rdma_fastreg_inv(struct rds_iw_mr *ibmr)
-{
-       struct ib_send_wr s_wr, *failed_wr;
-       int ret = 0;
-
-       if (!ibmr->cm_id->qp || !ibmr->mr)
-               goto out;
-
-       memset(&s_wr, 0, sizeof(s_wr));
-       s_wr.wr_id = RDS_IW_LOCAL_INV_WR_ID;
-       s_wr.opcode = IB_WR_LOCAL_INV;
-       s_wr.ex.invalidate_rkey = ibmr->mr->rkey;
-       s_wr.send_flags = IB_SEND_SIGNALED;
-
-       failed_wr = &s_wr;
-       ret = ib_post_send(ibmr->cm_id->qp, &s_wr, &failed_wr);
-       if (ret) {
-               printk_ratelimited(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
-                       __func__, __LINE__, ret);
-               goto out;
-       }
-out:
-       return ret;
-}
-
-static int rds_iw_map_reg(struct rds_iw_mr_pool *pool,
-                         struct rds_iw_mr *ibmr,
-                         struct scatterlist *sg,
-                         unsigned int sg_len)
-{
-       struct rds_iw_device *rds_iwdev = pool->device;
-       struct rds_iw_mapping *mapping = &ibmr->mapping;
-       u64 *dma_pages;
-       int ret = 0;
-
-       rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len);
-
-       ret = rds_iw_map_scatterlist(rds_iwdev, &mapping->m_sg);
-       if (ret) {
-               dma_pages = NULL;
-               goto out;
-       }
-
-       if (mapping->m_sg.dma_len > pool->max_message_size) {
-               ret = -EMSGSIZE;
-               goto out;
-       }
-
-       ret = rds_iw_rdma_reg_mr(mapping);
-       if (ret)
-               goto out;
-
-       rds_iw_stats_inc(s_iw_rdma_mr_used);
-
-out:
-       kfree(dma_pages);
-
-       return ret;
-}
-
-/*
- * "Free" a fastreg MR.
- */
-static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool,
-               struct rds_iw_mr *ibmr)
-{
-       unsigned long flags;
-       int ret;
-
-       if (!ibmr->mapping.m_sg.dma_len)
-               return;
-
-       ret = rds_iw_rdma_fastreg_inv(ibmr);
-       if (ret)
-               return;
-
-       /* Try to post the LOCAL_INV WR to the queue. */
-       spin_lock_irqsave(&pool->list_lock, flags);
-
-       list_add_tail(&ibmr->mapping.m_list, &pool->dirty_list);
-       atomic_add(ibmr->mapping.m_sg.len, &pool->free_pinned);
-       atomic_inc(&pool->dirty_count);
-
-       spin_unlock_irqrestore(&pool->list_lock, flags);
-}
-
-static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
-                               struct list_head *unmap_list,
-                               struct list_head *kill_list,
-                               int *unpinned)
-{
-       struct rds_iw_mapping *mapping, *next;
-       unsigned int ncleaned = 0;
-       LIST_HEAD(laundered);
-
-       /* Batched invalidation of fastreg MRs.
-        * Why do we do it this way, even though we could pipeline unmap
-        * and remap? The reason is the application semantics - when the
-        * application requests an invalidation of MRs, it expects all
-        * previously released R_Keys to become invalid.
-        *
-        * If we implement MR reuse naively, we risk memory corruption
-        * (this has actually been observed). So the default behavior
-        * requires that a MR goes through an explicit unmap operation before
-        * we can reuse it again.
-        *
-        * We could probably improve on this a little, by allowing immediate
-        * reuse of a MR on the same socket (eg you could add small
-        * cache of unused MRs to strct rds_socket - GET_MR could grab one
-        * of these without requiring an explicit invalidate).
-        */
-       while (!list_empty(unmap_list)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&pool->list_lock, flags);
-               list_for_each_entry_safe(mapping, next, unmap_list, m_list) {
-                       *unpinned += mapping->m_sg.len;
-                       list_move(&mapping->m_list, &laundered);
-                       ncleaned++;
-               }
-               spin_unlock_irqrestore(&pool->list_lock, flags);
-       }
-
-       /* Move all laundered mappings back to the unmap list.
-        * We do not kill any WRs right now - it doesn't seem the
-        * fastreg API has a max_remap limit. */
-       list_splice_init(&laundered, unmap_list);
-
-       return ncleaned;
-}
-
-static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool,
-               struct rds_iw_mr *ibmr)
-{
-       if (ibmr->mr)
-               ib_dereg_mr(ibmr->mr);
-}
diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c
deleted file mode 100644 (file)
index a66d179..0000000
+++ /dev/null
@@ -1,904 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <rdma/rdma_cm.h>
-
-#include "rds.h"
-#include "iw.h"
-
-static struct kmem_cache *rds_iw_incoming_slab;
-static struct kmem_cache *rds_iw_frag_slab;
-static atomic_t        rds_iw_allocation = ATOMIC_INIT(0);
-
-static void rds_iw_frag_drop_page(struct rds_page_frag *frag)
-{
-       rdsdebug("frag %p page %p\n", frag, frag->f_page);
-       __free_page(frag->f_page);
-       frag->f_page = NULL;
-}
-
-static void rds_iw_frag_free(struct rds_page_frag *frag)
-{
-       rdsdebug("frag %p page %p\n", frag, frag->f_page);
-       BUG_ON(frag->f_page);
-       kmem_cache_free(rds_iw_frag_slab, frag);
-}
-
-/*
- * We map a page at a time.  Its fragments are posted in order.  This
- * is called in fragment order as the fragments get send completion events.
- * Only the last frag in the page performs the unmapping.
- *
- * It's OK for ring cleanup to call this in whatever order it likes because
- * DMA is not in flight and so we can unmap while other ring entries still
- * hold page references in their frags.
- */
-static void rds_iw_recv_unmap_page(struct rds_iw_connection *ic,
-                                  struct rds_iw_recv_work *recv)
-{
-       struct rds_page_frag *frag = recv->r_frag;
-
-       rdsdebug("recv %p frag %p page %p\n", recv, frag, frag->f_page);
-       if (frag->f_mapped)
-               ib_dma_unmap_page(ic->i_cm_id->device,
-                              frag->f_mapped,
-                              RDS_FRAG_SIZE, DMA_FROM_DEVICE);
-       frag->f_mapped = 0;
-}
-
-void rds_iw_recv_init_ring(struct rds_iw_connection *ic)
-{
-       struct rds_iw_recv_work *recv;
-       u32 i;
-
-       for (i = 0, recv = ic->i_recvs; i < ic->i_recv_ring.w_nr; i++, recv++) {
-               struct ib_sge *sge;
-
-               recv->r_iwinc = NULL;
-               recv->r_frag = NULL;
-
-               recv->r_wr.next = NULL;
-               recv->r_wr.wr_id = i;
-               recv->r_wr.sg_list = recv->r_sge;
-               recv->r_wr.num_sge = RDS_IW_RECV_SGE;
-
-               sge = rds_iw_data_sge(ic, recv->r_sge);
-               sge->addr = 0;
-               sge->length = RDS_FRAG_SIZE;
-               sge->lkey = 0;
-
-               sge = rds_iw_header_sge(ic, recv->r_sge);
-               sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
-               sge->length = sizeof(struct rds_header);
-               sge->lkey = 0;
-       }
-}
-
-static void rds_iw_recv_clear_one(struct rds_iw_connection *ic,
-                                 struct rds_iw_recv_work *recv)
-{
-       if (recv->r_iwinc) {
-               rds_inc_put(&recv->r_iwinc->ii_inc);
-               recv->r_iwinc = NULL;
-       }
-       if (recv->r_frag) {
-               rds_iw_recv_unmap_page(ic, recv);
-               if (recv->r_frag->f_page)
-                       rds_iw_frag_drop_page(recv->r_frag);
-               rds_iw_frag_free(recv->r_frag);
-               recv->r_frag = NULL;
-       }
-}
-
-void rds_iw_recv_clear_ring(struct rds_iw_connection *ic)
-{
-       u32 i;
-
-       for (i = 0; i < ic->i_recv_ring.w_nr; i++)
-               rds_iw_recv_clear_one(ic, &ic->i_recvs[i]);
-
-       if (ic->i_frag.f_page)
-               rds_iw_frag_drop_page(&ic->i_frag);
-}
-
-static int rds_iw_recv_refill_one(struct rds_connection *conn,
-                                 struct rds_iw_recv_work *recv,
-                                 gfp_t kptr_gfp, gfp_t page_gfp)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       dma_addr_t dma_addr;
-       struct ib_sge *sge;
-       int ret = -ENOMEM;
-
-       if (!recv->r_iwinc) {
-               if (!atomic_add_unless(&rds_iw_allocation, 1, rds_iw_sysctl_max_recv_allocation)) {
-                       rds_iw_stats_inc(s_iw_rx_alloc_limit);
-                       goto out;
-               }
-               recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab,
-                                                kptr_gfp);
-               if (!recv->r_iwinc) {
-                       atomic_dec(&rds_iw_allocation);
-                       goto out;
-               }
-               INIT_LIST_HEAD(&recv->r_iwinc->ii_frags);
-               rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr);
-       }
-
-       if (!recv->r_frag) {
-               recv->r_frag = kmem_cache_alloc(rds_iw_frag_slab, kptr_gfp);
-               if (!recv->r_frag)
-                       goto out;
-               INIT_LIST_HEAD(&recv->r_frag->f_item);
-               recv->r_frag->f_page = NULL;
-       }
-
-       if (!ic->i_frag.f_page) {
-               ic->i_frag.f_page = alloc_page(page_gfp);
-               if (!ic->i_frag.f_page)
-                       goto out;
-               ic->i_frag.f_offset = 0;
-       }
-
-       dma_addr = ib_dma_map_page(ic->i_cm_id->device,
-                                 ic->i_frag.f_page,
-                                 ic->i_frag.f_offset,
-                                 RDS_FRAG_SIZE,
-                                 DMA_FROM_DEVICE);
-       if (ib_dma_mapping_error(ic->i_cm_id->device, dma_addr))
-               goto out;
-
-       /*
-        * Once we get the RDS_PAGE_LAST_OFF frag then rds_iw_frag_unmap()
-        * must be called on this recv.  This happens as completions hit
-        * in order or on connection shutdown.
-        */
-       recv->r_frag->f_page = ic->i_frag.f_page;
-       recv->r_frag->f_offset = ic->i_frag.f_offset;
-       recv->r_frag->f_mapped = dma_addr;
-
-       sge = rds_iw_data_sge(ic, recv->r_sge);
-       sge->addr = dma_addr;
-       sge->length = RDS_FRAG_SIZE;
-
-       sge = rds_iw_header_sge(ic, recv->r_sge);
-       sge->addr = ic->i_recv_hdrs_dma + (recv - ic->i_recvs) * sizeof(struct rds_header);
-       sge->length = sizeof(struct rds_header);
-
-       get_page(recv->r_frag->f_page);
-
-       if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
-               ic->i_frag.f_offset += RDS_FRAG_SIZE;
-       } else {
-               put_page(ic->i_frag.f_page);
-               ic->i_frag.f_page = NULL;
-               ic->i_frag.f_offset = 0;
-       }
-
-       ret = 0;
-out:
-       return ret;
-}
-
-/*
- * This tries to allocate and post unused work requests after making sure that
- * they have all the allocations they need to queue received fragments into
- * sockets.  The i_recv_mutex is held here so that ring_alloc and _unalloc
- * pairs don't go unmatched.
- *
- * -1 is returned if posting fails due to temporary resource exhaustion.
- */
-int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
-                      gfp_t page_gfp, int prefill)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rds_iw_recv_work *recv;
-       struct ib_recv_wr *failed_wr;
-       unsigned int posted = 0;
-       int ret = 0;
-       u32 pos;
-
-       while ((prefill || rds_conn_up(conn)) &&
-              rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) {
-               if (pos >= ic->i_recv_ring.w_nr) {
-                       printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n",
-                                       pos);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               recv = &ic->i_recvs[pos];
-               ret = rds_iw_recv_refill_one(conn, recv, kptr_gfp, page_gfp);
-               if (ret) {
-                       ret = -1;
-                       break;
-               }
-
-               /* XXX when can this fail? */
-               ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
-               rdsdebug("recv %p iwinc %p page %p addr %lu ret %d\n", recv,
-                        recv->r_iwinc, recv->r_frag->f_page,
-                        (long) recv->r_frag->f_mapped, ret);
-               if (ret) {
-                       rds_iw_conn_error(conn, "recv post on "
-                              "%pI4 returned %d, disconnecting and "
-                              "reconnecting\n", &conn->c_faddr,
-                              ret);
-                       ret = -1;
-                       break;
-               }
-
-               posted++;
-       }
-
-       /* We're doing flow control - update the window. */
-       if (ic->i_flowctl && posted)
-               rds_iw_advertise_credits(conn, posted);
-
-       if (ret)
-               rds_iw_ring_unalloc(&ic->i_recv_ring, 1);
-       return ret;
-}
-
-static void rds_iw_inc_purge(struct rds_incoming *inc)
-{
-       struct rds_iw_incoming *iwinc;
-       struct rds_page_frag *frag;
-       struct rds_page_frag *pos;
-
-       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
-       rdsdebug("purging iwinc %p inc %p\n", iwinc, inc);
-
-       list_for_each_entry_safe(frag, pos, &iwinc->ii_frags, f_item) {
-               list_del_init(&frag->f_item);
-               rds_iw_frag_drop_page(frag);
-               rds_iw_frag_free(frag);
-       }
-}
-
-void rds_iw_inc_free(struct rds_incoming *inc)
-{
-       struct rds_iw_incoming *iwinc;
-
-       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
-
-       rds_iw_inc_purge(inc);
-       rdsdebug("freeing iwinc %p inc %p\n", iwinc, inc);
-       BUG_ON(!list_empty(&iwinc->ii_frags));
-       kmem_cache_free(rds_iw_incoming_slab, iwinc);
-       atomic_dec(&rds_iw_allocation);
-       BUG_ON(atomic_read(&rds_iw_allocation) < 0);
-}
-
-int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iov_iter *to)
-{
-       struct rds_iw_incoming *iwinc;
-       struct rds_page_frag *frag;
-       unsigned long to_copy;
-       unsigned long frag_off = 0;
-       int copied = 0;
-       int ret;
-       u32 len;
-
-       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
-       frag = list_entry(iwinc->ii_frags.next, struct rds_page_frag, f_item);
-       len = be32_to_cpu(inc->i_hdr.h_len);
-
-       while (iov_iter_count(to) && copied < len) {
-               if (frag_off == RDS_FRAG_SIZE) {
-                       frag = list_entry(frag->f_item.next,
-                                         struct rds_page_frag, f_item);
-                       frag_off = 0;
-               }
-               to_copy = min_t(unsigned long, iov_iter_count(to),
-                               RDS_FRAG_SIZE - frag_off);
-               to_copy = min_t(unsigned long, to_copy, len - copied);
-
-               /* XXX needs + offset for multiple recvs per page */
-               rds_stats_add(s_copy_to_user, to_copy);
-               ret = copy_page_to_iter(frag->f_page,
-                                       frag->f_offset + frag_off,
-                                       to_copy,
-                                       to);
-               if (ret != to_copy)
-                       return -EFAULT;
-
-               frag_off += to_copy;
-               copied += to_copy;
-       }
-
-       return copied;
-}
-
-/* ic starts out kzalloc()ed */
-void rds_iw_recv_init_ack(struct rds_iw_connection *ic)
-{
-       struct ib_send_wr *wr = &ic->i_ack_wr;
-       struct ib_sge *sge = &ic->i_ack_sge;
-
-       sge->addr = ic->i_ack_dma;
-       sge->length = sizeof(struct rds_header);
-       sge->lkey = rds_iw_local_dma_lkey(ic);
-
-       wr->sg_list = sge;
-       wr->num_sge = 1;
-       wr->opcode = IB_WR_SEND;
-       wr->wr_id = RDS_IW_ACK_WR_ID;
-       wr->send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-}
-
-/*
- * You'd think that with reliable IB connections you wouldn't need to ack
- * messages that have been received.  The problem is that IB hardware generates
- * an ack message before it has DMAed the message into memory.  This creates a
- * potential message loss if the HCA is disabled for any reason between when it
- * sends the ack and before the message is DMAed and processed.  This is only a
- * potential issue if another HCA is available for fail-over.
- *
- * When the remote host receives our ack they'll free the sent message from
- * their send queue.  To decrease the latency of this we always send an ack
- * immediately after we've received messages.
- *
- * For simplicity, we only have one ack in flight at a time.  This puts
- * pressure on senders to have deep enough send queues to absorb the latency of
- * a single ack frame being in flight.  This might not be good enough.
- *
- * This is implemented by have a long-lived send_wr and sge which point to a
- * statically allocated ack frame.  This ack wr does not fall under the ring
- * accounting that the tx and rx wrs do.  The QP attribute specifically makes
- * room for it beyond the ring size.  Send completion notices its special
- * wr_id and avoids working with the ring in that case.
- */
-#ifndef KERNEL_HAS_ATOMIC64
-static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq,
-                               int ack_required)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ic->i_ack_lock, flags);
-       ic->i_ack_next = seq;
-       if (ack_required)
-               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
-}
-
-static u64 rds_iw_get_ack(struct rds_iw_connection *ic)
-{
-       unsigned long flags;
-       u64 seq;
-
-       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-
-       spin_lock_irqsave(&ic->i_ack_lock, flags);
-       seq = ic->i_ack_next;
-       spin_unlock_irqrestore(&ic->i_ack_lock, flags);
-
-       return seq;
-}
-#else
-static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq,
-                               int ack_required)
-{
-       atomic64_set(&ic->i_ack_next, seq);
-       if (ack_required) {
-               smp_mb__before_atomic();
-               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-       }
-}
-
-static u64 rds_iw_get_ack(struct rds_iw_connection *ic)
-{
-       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-       smp_mb__after_atomic();
-
-       return atomic64_read(&ic->i_ack_next);
-}
-#endif
-
-
-static void rds_iw_send_ack(struct rds_iw_connection *ic, unsigned int adv_credits)
-{
-       struct rds_header *hdr = ic->i_ack;
-       struct ib_send_wr *failed_wr;
-       u64 seq;
-       int ret;
-
-       seq = rds_iw_get_ack(ic);
-
-       rdsdebug("send_ack: ic %p ack %llu\n", ic, (unsigned long long) seq);
-       rds_message_populate_header(hdr, 0, 0, 0);
-       hdr->h_ack = cpu_to_be64(seq);
-       hdr->h_credit = adv_credits;
-       rds_message_make_checksum(hdr);
-       ic->i_ack_queued = jiffies;
-
-       ret = ib_post_send(ic->i_cm_id->qp, &ic->i_ack_wr, &failed_wr);
-       if (unlikely(ret)) {
-               /* Failed to send. Release the WR, and
-                * force another ACK.
-                */
-               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-
-               rds_iw_stats_inc(s_iw_ack_send_failure);
-
-               rds_iw_conn_error(ic->conn, "sending ack failed\n");
-       } else
-               rds_iw_stats_inc(s_iw_ack_sent);
-}
-
-/*
- * There are 3 ways of getting acknowledgements to the peer:
- *  1. We call rds_iw_attempt_ack from the recv completion handler
- *     to send an ACK-only frame.
- *     However, there can be only one such frame in the send queue
- *     at any time, so we may have to postpone it.
- *  2. When another (data) packet is transmitted while there's
- *     an ACK in the queue, we piggyback the ACK sequence number
- *     on the data packet.
- *  3. If the ACK WR is done sending, we get called from the
- *     send queue completion handler, and check whether there's
- *     another ACK pending (postponed because the WR was on the
- *     queue). If so, we transmit it.
- *
- * We maintain 2 variables:
- *  -  i_ack_flags, which keeps track of whether the ACK WR
- *     is currently in the send queue or not (IB_ACK_IN_FLIGHT)
- *  -  i_ack_next, which is the last sequence number we received
- *
- * Potentially, send queue and receive queue handlers can run concurrently.
- * It would be nice to not have to use a spinlock to synchronize things,
- * but the one problem that rules this out is that 64bit updates are
- * not atomic on all platforms. Things would be a lot simpler if
- * we had atomic64 or maybe cmpxchg64 everywhere.
- *
- * Reconnecting complicates this picture just slightly. When we
- * reconnect, we may be seeing duplicate packets. The peer
- * is retransmitting them, because it hasn't seen an ACK for
- * them. It is important that we ACK these.
- *
- * ACK mitigation adds a header flag "ACK_REQUIRED"; any packet with
- * this flag set *MUST* be acknowledged immediately.
- */
-
-/*
- * When we get here, we're called from the recv queue handler.
- * Check whether we ought to transmit an ACK.
- */
-void rds_iw_attempt_ack(struct rds_iw_connection *ic)
-{
-       unsigned int adv_credits;
-
-       if (!test_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
-               return;
-
-       if (test_and_set_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags)) {
-               rds_iw_stats_inc(s_iw_ack_send_delayed);
-               return;
-       }
-
-       /* Can we get a send credit? */
-       if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0, RDS_MAX_ADV_CREDIT)) {
-               rds_iw_stats_inc(s_iw_tx_throttle);
-               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-               return;
-       }
-
-       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-       rds_iw_send_ack(ic, adv_credits);
-}
-
-/*
- * We get here from the send completion handler, when the
- * adapter tells us the ACK frame was sent.
- */
-void rds_iw_ack_send_complete(struct rds_iw_connection *ic)
-{
-       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
-       rds_iw_attempt_ack(ic);
-}
-
-/*
- * This is called by the regular xmit code when it wants to piggyback
- * an ACK on an outgoing frame.
- */
-u64 rds_iw_piggyb_ack(struct rds_iw_connection *ic)
-{
-       if (test_and_clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
-               rds_iw_stats_inc(s_iw_ack_send_piggybacked);
-       return rds_iw_get_ack(ic);
-}
-
-/*
- * It's kind of lame that we're copying from the posted receive pages into
- * long-lived bitmaps.  We could have posted the bitmaps and rdma written into
- * them.  But receiving new congestion bitmaps should be a *rare* event, so
- * hopefully we won't need to invest that complexity in making it more
- * efficient.  By copying we can share a simpler core with TCP which has to
- * copy.
- */
-static void rds_iw_cong_recv(struct rds_connection *conn,
-                             struct rds_iw_incoming *iwinc)
-{
-       struct rds_cong_map *map;
-       unsigned int map_off;
-       unsigned int map_page;
-       struct rds_page_frag *frag;
-       unsigned long frag_off;
-       unsigned long to_copy;
-       unsigned long copied;
-       uint64_t uncongested = 0;
-       void *addr;
-
-       /* catch completely corrupt packets */
-       if (be32_to_cpu(iwinc->ii_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES)
-               return;
-
-       map = conn->c_fcong;
-       map_page = 0;
-       map_off = 0;
-
-       frag = list_entry(iwinc->ii_frags.next, struct rds_page_frag, f_item);
-       frag_off = 0;
-
-       copied = 0;
-
-       while (copied < RDS_CONG_MAP_BYTES) {
-               uint64_t *src, *dst;
-               unsigned int k;
-
-               to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
-               BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
-
-               addr = kmap_atomic(frag->f_page);
-
-               src = addr + frag_off;
-               dst = (void *)map->m_page_addrs[map_page] + map_off;
-               for (k = 0; k < to_copy; k += 8) {
-                       /* Record ports that became uncongested, ie
-                        * bits that changed from 0 to 1. */
-                       uncongested |= ~(*src) & *dst;
-                       *dst++ = *src++;
-               }
-               kunmap_atomic(addr);
-
-               copied += to_copy;
-
-               map_off += to_copy;
-               if (map_off == PAGE_SIZE) {
-                       map_off = 0;
-                       map_page++;
-               }
-
-               frag_off += to_copy;
-               if (frag_off == RDS_FRAG_SIZE) {
-                       frag = list_entry(frag->f_item.next,
-                                         struct rds_page_frag, f_item);
-                       frag_off = 0;
-               }
-       }
-
-       /* the congestion map is in little endian order */
-       uncongested = le64_to_cpu(uncongested);
-
-       rds_cong_map_updated(map, uncongested);
-}
-
-/*
- * Rings are posted with all the allocations they'll need to queue the
- * incoming message to the receiving socket so this can't fail.
- * All fragments start with a header, so we can make sure we're not receiving
- * garbage, and we can tell a small 8 byte fragment from an ACK frame.
- */
-struct rds_iw_ack_state {
-       u64             ack_next;
-       u64             ack_recv;
-       unsigned int    ack_required:1;
-       unsigned int    ack_next_valid:1;
-       unsigned int    ack_recv_valid:1;
-};
-
-static void rds_iw_process_recv(struct rds_connection *conn,
-                               struct rds_iw_recv_work *recv, u32 byte_len,
-                               struct rds_iw_ack_state *state)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rds_iw_incoming *iwinc = ic->i_iwinc;
-       struct rds_header *ihdr, *hdr;
-
-       /* XXX shut down the connection if port 0,0 are seen? */
-
-       rdsdebug("ic %p iwinc %p recv %p byte len %u\n", ic, iwinc, recv,
-                byte_len);
-
-       if (byte_len < sizeof(struct rds_header)) {
-               rds_iw_conn_error(conn, "incoming message "
-                      "from %pI4 didn't include a "
-                      "header, disconnecting and "
-                      "reconnecting\n",
-                      &conn->c_faddr);
-               return;
-       }
-       byte_len -= sizeof(struct rds_header);
-
-       ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
-
-       /* Validate the checksum. */
-       if (!rds_message_verify_checksum(ihdr)) {
-               rds_iw_conn_error(conn, "incoming message "
-                      "from %pI4 has corrupted header - "
-                      "forcing a reconnect\n",
-                      &conn->c_faddr);
-               rds_stats_inc(s_recv_drop_bad_checksum);
-               return;
-       }
-
-       /* Process the ACK sequence which comes with every packet */
-       state->ack_recv = be64_to_cpu(ihdr->h_ack);
-       state->ack_recv_valid = 1;
-
-       /* Process the credits update if there was one */
-       if (ihdr->h_credit)
-               rds_iw_send_add_credits(conn, ihdr->h_credit);
-
-       if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) {
-               /* This is an ACK-only packet. The fact that it gets
-                * special treatment here is that historically, ACKs
-                * were rather special beasts.
-                */
-               rds_iw_stats_inc(s_iw_ack_received);
-
-               /*
-                * Usually the frags make their way on to incs and are then freed as
-                * the inc is freed.  We don't go that route, so we have to drop the
-                * page ref ourselves.  We can't just leave the page on the recv
-                * because that confuses the dma mapping of pages and each recv's use
-                * of a partial page.  We can leave the frag, though, it will be
-                * reused.
-                *
-                * FIXME: Fold this into the code path below.
-                */
-               rds_iw_frag_drop_page(recv->r_frag);
-               return;
-       }
-
-       /*
-        * If we don't already have an inc on the connection then this
-        * fragment has a header and starts a message.. copy its header
-        * into the inc and save the inc so we can hang upcoming fragments
-        * off its list.
-        */
-       if (!iwinc) {
-               iwinc = recv->r_iwinc;
-               recv->r_iwinc = NULL;
-               ic->i_iwinc = iwinc;
-
-               hdr = &iwinc->ii_inc.i_hdr;
-               memcpy(hdr, ihdr, sizeof(*hdr));
-               ic->i_recv_data_rem = be32_to_cpu(hdr->h_len);
-
-               rdsdebug("ic %p iwinc %p rem %u flag 0x%x\n", ic, iwinc,
-                        ic->i_recv_data_rem, hdr->h_flags);
-       } else {
-               hdr = &iwinc->ii_inc.i_hdr;
-               /* We can't just use memcmp here; fragments of a
-                * single message may carry different ACKs */
-               if (hdr->h_sequence != ihdr->h_sequence ||
-                   hdr->h_len != ihdr->h_len ||
-                   hdr->h_sport != ihdr->h_sport ||
-                   hdr->h_dport != ihdr->h_dport) {
-                       rds_iw_conn_error(conn,
-                               "fragment header mismatch; forcing reconnect\n");
-                       return;
-               }
-       }
-
-       list_add_tail(&recv->r_frag->f_item, &iwinc->ii_frags);
-       recv->r_frag = NULL;
-
-       if (ic->i_recv_data_rem > RDS_FRAG_SIZE)
-               ic->i_recv_data_rem -= RDS_FRAG_SIZE;
-       else {
-               ic->i_recv_data_rem = 0;
-               ic->i_iwinc = NULL;
-
-               if (iwinc->ii_inc.i_hdr.h_flags == RDS_FLAG_CONG_BITMAP)
-                       rds_iw_cong_recv(conn, iwinc);
-               else {
-                       rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr,
-                                         &iwinc->ii_inc, GFP_ATOMIC);
-                       state->ack_next = be64_to_cpu(hdr->h_sequence);
-                       state->ack_next_valid = 1;
-               }
-
-               /* Evaluate the ACK_REQUIRED flag *after* we received
-                * the complete frame, and after bumping the next_rx
-                * sequence. */
-               if (hdr->h_flags & RDS_FLAG_ACK_REQUIRED) {
-                       rds_stats_inc(s_recv_ack_required);
-                       state->ack_required = 1;
-               }
-
-               rds_inc_put(&iwinc->ii_inc);
-       }
-}
-
-/*
- * Plucking the oldest entry from the ring can be done concurrently with
- * the thread refilling the ring.  Each ring operation is protected by
- * spinlocks and the transient state of refilling doesn't change the
- * recording of which entry is oldest.
- *
- * This relies on IB only calling one cq comp_handler for each cq so that
- * there will only be one caller of rds_recv_incoming() per RDS connection.
- */
-void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context)
-{
-       struct rds_connection *conn = context;
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       rdsdebug("conn %p cq %p\n", conn, cq);
-
-       rds_iw_stats_inc(s_iw_rx_cq_call);
-
-       tasklet_schedule(&ic->i_recv_tasklet);
-}
-
-static inline void rds_poll_cq(struct rds_iw_connection *ic,
-                              struct rds_iw_ack_state *state)
-{
-       struct rds_connection *conn = ic->conn;
-       struct ib_wc wc;
-       struct rds_iw_recv_work *recv;
-
-       while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) {
-               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
-                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
-                        be32_to_cpu(wc.ex.imm_data));
-               rds_iw_stats_inc(s_iw_rx_cq_event);
-
-               recv = &ic->i_recvs[rds_iw_ring_oldest(&ic->i_recv_ring)];
-
-               rds_iw_recv_unmap_page(ic, recv);
-
-               /*
-                * Also process recvs in connecting state because it is possible
-                * to get a recv completion _before_ the rdmacm ESTABLISHED
-                * event is processed.
-                */
-               if (rds_conn_up(conn) || rds_conn_connecting(conn)) {
-                       /* We expect errors as the qp is drained during shutdown */
-                       if (wc.status == IB_WC_SUCCESS) {
-                               rds_iw_process_recv(conn, recv, wc.byte_len, state);
-                       } else {
-                               rds_iw_conn_error(conn, "recv completion on "
-                                      "%pI4 had status %u, disconnecting and "
-                                      "reconnecting\n", &conn->c_faddr,
-                                      wc.status);
-                       }
-               }
-
-               rds_iw_ring_free(&ic->i_recv_ring, 1);
-       }
-}
-
-void rds_iw_recv_tasklet_fn(unsigned long data)
-{
-       struct rds_iw_connection *ic = (struct rds_iw_connection *) data;
-       struct rds_connection *conn = ic->conn;
-       struct rds_iw_ack_state state = { 0, };
-
-       rds_poll_cq(ic, &state);
-       ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED);
-       rds_poll_cq(ic, &state);
-
-       if (state.ack_next_valid)
-               rds_iw_set_ack(ic, state.ack_next, state.ack_required);
-       if (state.ack_recv_valid && state.ack_recv > ic->i_ack_recv) {
-               rds_send_drop_acked(conn, state.ack_recv, NULL);
-               ic->i_ack_recv = state.ack_recv;
-       }
-       if (rds_conn_up(conn))
-               rds_iw_attempt_ack(ic);
-
-       /* If we ever end up with a really empty receive ring, we're
-        * in deep trouble, as the sender will definitely see RNR
-        * timeouts. */
-       if (rds_iw_ring_empty(&ic->i_recv_ring))
-               rds_iw_stats_inc(s_iw_rx_ring_empty);
-
-       /*
-        * If the ring is running low, then schedule the thread to refill.
-        */
-       if (rds_iw_ring_low(&ic->i_recv_ring))
-               queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
-}
-
-int rds_iw_recv(struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       int ret = 0;
-
-       rdsdebug("conn %p\n", conn);
-
-       /*
-        * If we get a temporary posting failure in this context then
-        * we're really low and we want the caller to back off for a bit.
-        */
-       mutex_lock(&ic->i_recv_mutex);
-       if (rds_iw_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 0))
-               ret = -ENOMEM;
-       else
-               rds_iw_stats_inc(s_iw_rx_refill_from_thread);
-       mutex_unlock(&ic->i_recv_mutex);
-
-       if (rds_conn_up(conn))
-               rds_iw_attempt_ack(ic);
-
-       return ret;
-}
-
-int rds_iw_recv_init(void)
-{
-       struct sysinfo si;
-       int ret = -ENOMEM;
-
-       /* Default to 30% of all available RAM for recv memory */
-       si_meminfo(&si);
-       rds_iw_sysctl_max_recv_allocation = si.totalram / 3 * PAGE_SIZE / RDS_FRAG_SIZE;
-
-       rds_iw_incoming_slab = kmem_cache_create("rds_iw_incoming",
-                                       sizeof(struct rds_iw_incoming),
-                                       0, 0, NULL);
-       if (!rds_iw_incoming_slab)
-               goto out;
-
-       rds_iw_frag_slab = kmem_cache_create("rds_iw_frag",
-                                       sizeof(struct rds_page_frag),
-                                       0, 0, NULL);
-       if (!rds_iw_frag_slab)
-               kmem_cache_destroy(rds_iw_incoming_slab);
-       else
-               ret = 0;
-out:
-       return ret;
-}
-
-void rds_iw_recv_exit(void)
-{
-       kmem_cache_destroy(rds_iw_incoming_slab);
-       kmem_cache_destroy(rds_iw_frag_slab);
-}
diff --git a/net/rds/iw_ring.c b/net/rds/iw_ring.c
deleted file mode 100644 (file)
index da8e3b6..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-
-#include "rds.h"
-#include "iw.h"
-
-/*
- * Locking for IB rings.
- * We assume that allocation is always protected by a mutex
- * in the caller (this is a valid assumption for the current
- * implementation).
- *
- * Freeing always happens in an interrupt, and hence only
- * races with allocations, but not with other free()s.
- *
- * The interaction between allocation and freeing is that
- * the alloc code has to determine the number of free entries.
- * To this end, we maintain two counters; an allocation counter
- * and a free counter. Both are allowed to run freely, and wrap
- * around.
- * The number of used entries is always (alloc_ctr - free_ctr) % NR.
- *
- * The current implementation makes free_ctr atomic. When the
- * caller finds an allocation fails, it should set an "alloc fail"
- * bit and retry the allocation. The "alloc fail" bit essentially tells
- * the CQ completion handlers to wake it up after freeing some
- * more entries.
- */
-
-/*
- * This only happens on shutdown.
- */
-DECLARE_WAIT_QUEUE_HEAD(rds_iw_ring_empty_wait);
-
-void rds_iw_ring_init(struct rds_iw_work_ring *ring, u32 nr)
-{
-       memset(ring, 0, sizeof(*ring));
-       ring->w_nr = nr;
-       rdsdebug("ring %p nr %u\n", ring, ring->w_nr);
-}
-
-static inline u32 __rds_iw_ring_used(struct rds_iw_work_ring *ring)
-{
-       u32 diff;
-
-       /* This assumes that atomic_t has at least as many bits as u32 */
-       diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr);
-       BUG_ON(diff > ring->w_nr);
-
-       return diff;
-}
-
-void rds_iw_ring_resize(struct rds_iw_work_ring *ring, u32 nr)
-{
-       /* We only ever get called from the connection setup code,
-        * prior to creating the QP. */
-       BUG_ON(__rds_iw_ring_used(ring));
-       ring->w_nr = nr;
-}
-
-static int __rds_iw_ring_empty(struct rds_iw_work_ring *ring)
-{
-       return __rds_iw_ring_used(ring) == 0;
-}
-
-u32 rds_iw_ring_alloc(struct rds_iw_work_ring *ring, u32 val, u32 *pos)
-{
-       u32 ret = 0, avail;
-
-       avail = ring->w_nr - __rds_iw_ring_used(ring);
-
-       rdsdebug("ring %p val %u next %u free %u\n", ring, val,
-                ring->w_alloc_ptr, avail);
-
-       if (val && avail) {
-               ret = min(val, avail);
-               *pos = ring->w_alloc_ptr;
-
-               ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr;
-               ring->w_alloc_ctr += ret;
-       }
-
-       return ret;
-}
-
-void rds_iw_ring_free(struct rds_iw_work_ring *ring, u32 val)
-{
-       ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr;
-       atomic_add(val, &ring->w_free_ctr);
-
-       if (__rds_iw_ring_empty(ring) &&
-           waitqueue_active(&rds_iw_ring_empty_wait))
-               wake_up(&rds_iw_ring_empty_wait);
-}
-
-void rds_iw_ring_unalloc(struct rds_iw_work_ring *ring, u32 val)
-{
-       ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr;
-       ring->w_alloc_ctr -= val;
-}
-
-int rds_iw_ring_empty(struct rds_iw_work_ring *ring)
-{
-       return __rds_iw_ring_empty(ring);
-}
-
-int rds_iw_ring_low(struct rds_iw_work_ring *ring)
-{
-       return __rds_iw_ring_used(ring) <= (ring->w_nr >> 1);
-}
-
-
-/*
- * returns the oldest alloced ring entry.  This will be the next one
- * freed.  This can't be called if there are none allocated.
- */
-u32 rds_iw_ring_oldest(struct rds_iw_work_ring *ring)
-{
-       return ring->w_free_ptr;
-}
-
-/*
- * returns the number of completed work requests.
- */
-
-u32 rds_iw_ring_completed(struct rds_iw_work_ring *ring, u32 wr_id, u32 oldest)
-{
-       u32 ret;
-
-       if (oldest <= (unsigned long long)wr_id)
-               ret = (unsigned long long)wr_id - oldest + 1;
-       else
-               ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1;
-
-       rdsdebug("ring %p ret %u wr_id %u oldest %u\n", ring, ret,
-                wr_id, oldest);
-       return ret;
-}
diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c
deleted file mode 100644 (file)
index e20bd50..0000000
+++ /dev/null
@@ -1,981 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/in.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/ratelimit.h>
-
-#include "rds.h"
-#include "iw.h"
-
-static void rds_iw_send_rdma_complete(struct rds_message *rm,
-                                     int wc_status)
-{
-       int notify_status;
-
-       switch (wc_status) {
-       case IB_WC_WR_FLUSH_ERR:
-               return;
-
-       case IB_WC_SUCCESS:
-               notify_status = RDS_RDMA_SUCCESS;
-               break;
-
-       case IB_WC_REM_ACCESS_ERR:
-               notify_status = RDS_RDMA_REMOTE_ERROR;
-               break;
-
-       default:
-               notify_status = RDS_RDMA_OTHER_ERROR;
-               break;
-       }
-       rds_rdma_send_complete(rm, notify_status);
-}
-
-static void rds_iw_send_unmap_rdma(struct rds_iw_connection *ic,
-                                  struct rm_rdma_op *op)
-{
-       if (op->op_mapped) {
-               ib_dma_unmap_sg(ic->i_cm_id->device,
-                       op->op_sg, op->op_nents,
-                       op->op_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               op->op_mapped = 0;
-       }
-}
-
-static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
-                         struct rds_iw_send_work *send,
-                         int wc_status)
-{
-       struct rds_message *rm = send->s_rm;
-
-       rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
-
-       ib_dma_unmap_sg(ic->i_cm_id->device,
-                    rm->data.op_sg, rm->data.op_nents,
-                    DMA_TO_DEVICE);
-
-       if (rm->rdma.op_active) {
-               rds_iw_send_unmap_rdma(ic, &rm->rdma);
-
-               /* If the user asked for a completion notification on this
-                * message, we can implement three different semantics:
-                *  1.  Notify when we received the ACK on the RDS message
-                *      that was queued with the RDMA. This provides reliable
-                *      notification of RDMA status at the expense of a one-way
-                *      packet delay.
-                *  2.  Notify when the IB stack gives us the completion event for
-                *      the RDMA operation.
-                *  3.  Notify when the IB stack gives us the completion event for
-                *      the accompanying RDS messages.
-                * Here, we implement approach #3. To implement approach #2,
-                * call rds_rdma_send_complete from the cq_handler. To implement #1,
-                * don't call rds_rdma_send_complete at all, and fall back to the notify
-                * handling in the ACK processing code.
-                *
-                * Note: There's no need to explicitly sync any RDMA buffers using
-                * ib_dma_sync_sg_for_cpu - the completion for the RDMA
-                * operation itself unmapped the RDMA buffers, which takes care
-                * of synching.
-                */
-               rds_iw_send_rdma_complete(rm, wc_status);
-
-               if (rm->rdma.op_write)
-                       rds_stats_add(s_send_rdma_bytes, rm->rdma.op_bytes);
-               else
-                       rds_stats_add(s_recv_rdma_bytes, rm->rdma.op_bytes);
-       }
-
-       /* If anyone waited for this message to get flushed out, wake
-        * them up now */
-       rds_message_unmapped(rm);
-
-       rds_message_put(rm);
-       send->s_rm = NULL;
-}
-
-void rds_iw_send_init_ring(struct rds_iw_connection *ic)
-{
-       struct rds_iw_send_work *send;
-       u32 i;
-
-       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
-               struct ib_sge *sge;
-
-               send->s_rm = NULL;
-               send->s_op = NULL;
-               send->s_mapping = NULL;
-
-               send->s_send_wr.next = NULL;
-               send->s_send_wr.wr_id = i;
-               send->s_send_wr.sg_list = send->s_sge;
-               send->s_send_wr.num_sge = 1;
-               send->s_send_wr.opcode = IB_WR_SEND;
-               send->s_send_wr.send_flags = 0;
-               send->s_send_wr.ex.imm_data = 0;
-
-               sge = rds_iw_data_sge(ic, send->s_sge);
-               sge->lkey = 0;
-
-               sge = rds_iw_header_sge(ic, send->s_sge);
-               sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
-               sge->length = sizeof(struct rds_header);
-               sge->lkey = 0;
-
-               send->s_mr = ib_alloc_mr(ic->i_pd, IB_MR_TYPE_MEM_REG,
-                                        fastreg_message_size);
-               if (IS_ERR(send->s_mr)) {
-                       printk(KERN_WARNING "RDS/IW: ib_alloc_mr failed\n");
-                       break;
-               }
-       }
-}
-
-void rds_iw_send_clear_ring(struct rds_iw_connection *ic)
-{
-       struct rds_iw_send_work *send;
-       u32 i;
-
-       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
-               BUG_ON(!send->s_mr);
-               ib_dereg_mr(send->s_mr);
-               if (send->s_send_wr.opcode == 0xdead)
-                       continue;
-               if (send->s_rm)
-                       rds_iw_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
-               if (send->s_op)
-                       rds_iw_send_unmap_rdma(ic, send->s_op);
-       }
-}
-
-/*
- * The _oldest/_free ring operations here race cleanly with the alloc/unalloc
- * operations performed in the send path.  As the sender allocs and potentially
- * unallocs the next free entry in the ring it doesn't alter which is
- * the next to be freed, which is what this is concerned with.
- */
-void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
-{
-       struct rds_connection *conn = context;
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct ib_wc wc;
-       struct rds_iw_send_work *send;
-       u32 completed;
-       u32 oldest;
-       u32 i;
-       int ret;
-
-       rdsdebug("cq %p conn %p\n", cq, conn);
-       rds_iw_stats_inc(s_iw_tx_cq_call);
-       ret = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
-       if (ret)
-               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
-
-       while (ib_poll_cq(cq, 1, &wc) > 0) {
-               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
-                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
-                        be32_to_cpu(wc.ex.imm_data));
-               rds_iw_stats_inc(s_iw_tx_cq_event);
-
-               if (wc.status != IB_WC_SUCCESS) {
-                       printk(KERN_ERR "WC Error:  status = %d opcode = %d\n", wc.status, wc.opcode);
-                       break;
-               }
-
-               if (wc.opcode == IB_WC_LOCAL_INV && wc.wr_id == RDS_IW_LOCAL_INV_WR_ID) {
-                       ic->i_fastreg_posted = 0;
-                       continue;
-               }
-
-               if (wc.opcode == IB_WC_REG_MR && wc.wr_id == RDS_IW_REG_WR_ID) {
-                       ic->i_fastreg_posted = 1;
-                       continue;
-               }
-
-               if (wc.wr_id == RDS_IW_ACK_WR_ID) {
-                       if (time_after(jiffies, ic->i_ack_queued + HZ/2))
-                               rds_iw_stats_inc(s_iw_tx_stalled);
-                       rds_iw_ack_send_complete(ic);
-                       continue;
-               }
-
-               oldest = rds_iw_ring_oldest(&ic->i_send_ring);
-
-               completed = rds_iw_ring_completed(&ic->i_send_ring, wc.wr_id, oldest);
-
-               for (i = 0; i < completed; i++) {
-                       send = &ic->i_sends[oldest];
-
-                       /* In the error case, wc.opcode sometimes contains garbage */
-                       switch (send->s_send_wr.opcode) {
-                       case IB_WR_SEND:
-                               if (send->s_rm)
-                                       rds_iw_send_unmap_rm(ic, send, wc.status);
-                               break;
-                       case IB_WR_REG_MR:
-                       case IB_WR_RDMA_WRITE:
-                       case IB_WR_RDMA_READ:
-                       case IB_WR_RDMA_READ_WITH_INV:
-                               /* Nothing to be done - the SG list will be unmapped
-                                * when the SEND completes. */
-                               break;
-                       default:
-                               printk_ratelimited(KERN_NOTICE
-                                               "RDS/IW: %s: unexpected opcode 0x%x in WR!\n",
-                                               __func__, send->s_send_wr.opcode);
-                               break;
-                       }
-
-                       send->s_send_wr.opcode = 0xdead;
-                       send->s_send_wr.num_sge = 1;
-                       if (time_after(jiffies, send->s_queued + HZ/2))
-                               rds_iw_stats_inc(s_iw_tx_stalled);
-
-                       /* If a RDMA operation produced an error, signal this right
-                        * away. If we don't, the subsequent SEND that goes with this
-                        * RDMA will be canceled with ERR_WFLUSH, and the application
-                        * never learn that the RDMA failed. */
-                       if (unlikely(wc.status == IB_WC_REM_ACCESS_ERR && send->s_op)) {
-                               struct rds_message *rm;
-
-                               rm = rds_send_get_message(conn, send->s_op);
-                               if (rm)
-                                       rds_iw_send_rdma_complete(rm, wc.status);
-                       }
-
-                       oldest = (oldest + 1) % ic->i_send_ring.w_nr;
-               }
-
-               rds_iw_ring_free(&ic->i_send_ring, completed);
-
-               if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags) ||
-                   test_bit(0, &conn->c_map_queued))
-                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
-
-               /* We expect errors as the qp is drained during shutdown */
-               if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
-                       rds_iw_conn_error(conn,
-                               "send completion on %pI4 "
-                               "had status %u, disconnecting and reconnecting\n",
-                               &conn->c_faddr, wc.status);
-               }
-       }
-}
-
-/*
- * This is the main function for allocating credits when sending
- * messages.
- *
- * Conceptually, we have two counters:
- *  -  send credits: this tells us how many WRs we're allowed
- *     to submit without overruning the receiver's queue. For
- *     each SEND WR we post, we decrement this by one.
- *
- *  -  posted credits: this tells us how many WRs we recently
- *     posted to the receive queue. This value is transferred
- *     to the peer as a "credit update" in a RDS header field.
- *     Every time we transmit credits to the peer, we subtract
- *     the amount of transferred credits from this counter.
- *
- * It is essential that we avoid situations where both sides have
- * exhausted their send credits, and are unable to send new credits
- * to the peer. We achieve this by requiring that we send at least
- * one credit update to the peer before exhausting our credits.
- * When new credits arrive, we subtract one credit that is withheld
- * until we've posted new buffers and are ready to transmit these
- * credits (see rds_iw_send_add_credits below).
- *
- * The RDS send code is essentially single-threaded; rds_send_xmit
- * grabs c_send_lock to ensure exclusive access to the send ring.
- * However, the ACK sending code is independent and can race with
- * message SENDs.
- *
- * In the send path, we need to update the counters for send credits
- * and the counter of posted buffers atomically - when we use the
- * last available credit, we cannot allow another thread to race us
- * and grab the posted credits counter.  Hence, we have to use a
- * spinlock to protect the credit counter, or use atomics.
- *
- * Spinlocks shared between the send and the receive path are bad,
- * because they create unnecessary delays. An early implementation
- * using a spinlock showed a 5% degradation in throughput at some
- * loads.
- *
- * This implementation avoids spinlocks completely, putting both
- * counters into a single atomic, and updating that atomic using
- * atomic_add (in the receive path, when receiving fresh credits),
- * and using atomic_cmpxchg when updating the two counters.
- */
-int rds_iw_send_grab_credits(struct rds_iw_connection *ic,
-                            u32 wanted, u32 *adv_credits, int need_posted, int max_posted)
-{
-       unsigned int avail, posted, got = 0, advertise;
-       long oldval, newval;
-
-       *adv_credits = 0;
-       if (!ic->i_flowctl)
-               return wanted;
-
-try_again:
-       advertise = 0;
-       oldval = newval = atomic_read(&ic->i_credits);
-       posted = IB_GET_POST_CREDITS(oldval);
-       avail = IB_GET_SEND_CREDITS(oldval);
-
-       rdsdebug("wanted=%u credits=%u posted=%u\n",
-                       wanted, avail, posted);
-
-       /* The last credit must be used to send a credit update. */
-       if (avail && !posted)
-               avail--;
-
-       if (avail < wanted) {
-               struct rds_connection *conn = ic->i_cm_id->context;
-
-               /* Oops, there aren't that many credits left! */
-               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
-               got = avail;
-       } else {
-               /* Sometimes you get what you want, lalala. */
-               got = wanted;
-       }
-       newval -= IB_SET_SEND_CREDITS(got);
-
-       /*
-        * If need_posted is non-zero, then the caller wants
-        * the posted regardless of whether any send credits are
-        * available.
-        */
-       if (posted && (got || need_posted)) {
-               advertise = min_t(unsigned int, posted, max_posted);
-               newval -= IB_SET_POST_CREDITS(advertise);
-       }
-
-       /* Finally bill everything */
-       if (atomic_cmpxchg(&ic->i_credits, oldval, newval) != oldval)
-               goto try_again;
-
-       *adv_credits = advertise;
-       return got;
-}
-
-void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       if (credits == 0)
-               return;
-
-       rdsdebug("credits=%u current=%u%s\n",
-                       credits,
-                       IB_GET_SEND_CREDITS(atomic_read(&ic->i_credits)),
-                       test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ? ", ll_send_full" : "");
-
-       atomic_add(IB_SET_SEND_CREDITS(credits), &ic->i_credits);
-       if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags))
-               queue_delayed_work(rds_wq, &conn->c_send_w, 0);
-
-       WARN_ON(IB_GET_SEND_CREDITS(credits) >= 16384);
-
-       rds_iw_stats_inc(s_iw_rx_credit_updates);
-}
-
-void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       if (posted == 0)
-               return;
-
-       atomic_add(IB_SET_POST_CREDITS(posted), &ic->i_credits);
-
-       /* Decide whether to send an update to the peer now.
-        * If we would send a credit update for every single buffer we
-        * post, we would end up with an ACK storm (ACK arrives,
-        * consumes buffer, we refill the ring, send ACK to remote
-        * advertising the newly posted buffer... ad inf)
-        *
-        * Performance pretty much depends on how often we send
-        * credit updates - too frequent updates mean lots of ACKs.
-        * Too infrequent updates, and the peer will run out of
-        * credits and has to throttle.
-        * For the time being, 16 seems to be a good compromise.
-        */
-       if (IB_GET_POST_CREDITS(atomic_read(&ic->i_credits)) >= 16)
-               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
-}
-
-static inline void
-rds_iw_xmit_populate_wr(struct rds_iw_connection *ic,
-               struct rds_iw_send_work *send, unsigned int pos,
-               unsigned long buffer, unsigned int length,
-               int send_flags)
-{
-       struct ib_sge *sge;
-
-       WARN_ON(pos != send - ic->i_sends);
-
-       send->s_send_wr.send_flags = send_flags;
-       send->s_send_wr.opcode = IB_WR_SEND;
-       send->s_send_wr.num_sge = 2;
-       send->s_send_wr.next = NULL;
-       send->s_queued = jiffies;
-       send->s_op = NULL;
-
-       if (length != 0) {
-               sge = rds_iw_data_sge(ic, send->s_sge);
-               sge->addr = buffer;
-               sge->length = length;
-               sge->lkey = rds_iw_local_dma_lkey(ic);
-
-               sge = rds_iw_header_sge(ic, send->s_sge);
-       } else {
-               /* We're sending a packet with no payload. There is only
-                * one SGE */
-               send->s_send_wr.num_sge = 1;
-               sge = &send->s_sge[0];
-       }
-
-       sge->addr = ic->i_send_hdrs_dma + (pos * sizeof(struct rds_header));
-       sge->length = sizeof(struct rds_header);
-       sge->lkey = rds_iw_local_dma_lkey(ic);
-}
-
-/*
- * This can be called multiple times for a given message.  The first time
- * we see a message we map its scatterlist into the IB device so that
- * we can provide that mapped address to the IB scatter gather entries
- * in the IB work requests.  We translate the scatterlist into a series
- * of work requests that fragment the message.  These work requests complete
- * in order so we pass ownership of the message to the completion handler
- * once we send the final fragment.
- *
- * The RDS core uses the c_send_lock to only enter this function once
- * per connection.  This makes sure that the tx ring alloc/unalloc pairs
- * don't get out of sync and confuse the ring.
- */
-int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
-               unsigned int hdr_off, unsigned int sg, unsigned int off)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct ib_device *dev = ic->i_cm_id->device;
-       struct rds_iw_send_work *send = NULL;
-       struct rds_iw_send_work *first;
-       struct rds_iw_send_work *prev;
-       struct ib_send_wr *failed_wr;
-       struct scatterlist *scat;
-       u32 pos;
-       u32 i;
-       u32 work_alloc;
-       u32 credit_alloc;
-       u32 posted;
-       u32 adv_credits = 0;
-       int send_flags = 0;
-       int sent;
-       int ret;
-       int flow_controlled = 0;
-
-       BUG_ON(off % RDS_FRAG_SIZE);
-       BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
-
-       /* Fastreg support */
-       if (rds_rdma_cookie_key(rm->m_rdma_cookie) && !ic->i_fastreg_posted) {
-               ret = -EAGAIN;
-               goto out;
-       }
-
-       /* FIXME we may overallocate here */
-       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0)
-               i = 1;
-       else
-               i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE);
-
-       work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
-       if (work_alloc == 0) {
-               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
-               rds_iw_stats_inc(s_iw_tx_ring_full);
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       credit_alloc = work_alloc;
-       if (ic->i_flowctl) {
-               credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0, RDS_MAX_ADV_CREDIT);
-               adv_credits += posted;
-               if (credit_alloc < work_alloc) {
-                       rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
-                       work_alloc = credit_alloc;
-                       flow_controlled++;
-               }
-               if (work_alloc == 0) {
-                       set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
-                       rds_iw_stats_inc(s_iw_tx_throttle);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-       }
-
-       /* map the message the first time we see it */
-       if (!ic->i_rm) {
-               /*
-               printk(KERN_NOTICE "rds_iw_xmit prep msg dport=%u flags=0x%x len=%d\n",
-                               be16_to_cpu(rm->m_inc.i_hdr.h_dport),
-                               rm->m_inc.i_hdr.h_flags,
-                               be32_to_cpu(rm->m_inc.i_hdr.h_len));
-                  */
-               if (rm->data.op_nents) {
-                       rm->data.op_count = ib_dma_map_sg(dev,
-                                                         rm->data.op_sg,
-                                                         rm->data.op_nents,
-                                                         DMA_TO_DEVICE);
-                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->data.op_count);
-                       if (rm->data.op_count == 0) {
-                               rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
-                               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
-                               ret = -ENOMEM; /* XXX ? */
-                               goto out;
-                       }
-               } else {
-                       rm->data.op_count = 0;
-               }
-
-               ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
-               ic->i_unsignaled_bytes = rds_iw_sysctl_max_unsig_bytes;
-               rds_message_addref(rm);
-               rm->data.op_dmasg = 0;
-               rm->data.op_dmaoff = 0;
-               ic->i_rm = rm;
-
-               /* Finalize the header */
-               if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
-                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_ACK_REQUIRED;
-               if (test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags))
-                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_RETRANSMITTED;
-
-               /* If it has a RDMA op, tell the peer we did it. This is
-                * used by the peer to release use-once RDMA MRs. */
-               if (rm->rdma.op_active) {
-                       struct rds_ext_header_rdma ext_hdr;
-
-                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->rdma.op_rkey);
-                       rds_message_add_extension(&rm->m_inc.i_hdr,
-                                       RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
-               }
-               if (rm->m_rdma_cookie) {
-                       rds_message_add_rdma_dest_extension(&rm->m_inc.i_hdr,
-                                       rds_rdma_cookie_key(rm->m_rdma_cookie),
-                                       rds_rdma_cookie_offset(rm->m_rdma_cookie));
-               }
-
-               /* Note - rds_iw_piggyb_ack clears the ACK_REQUIRED bit, so
-                * we should not do this unless we have a chance of at least
-                * sticking the header into the send ring. Which is why we
-                * should call rds_iw_ring_alloc first. */
-               rm->m_inc.i_hdr.h_ack = cpu_to_be64(rds_iw_piggyb_ack(ic));
-               rds_message_make_checksum(&rm->m_inc.i_hdr);
-
-               /*
-                * Update adv_credits since we reset the ACK_REQUIRED bit.
-                */
-               rds_iw_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
-               adv_credits += posted;
-               BUG_ON(adv_credits > 255);
-       }
-
-       send = &ic->i_sends[pos];
-       first = send;
-       prev = NULL;
-       scat = &rm->data.op_sg[rm->data.op_dmasg];
-       sent = 0;
-       i = 0;
-
-       /* Sometimes you want to put a fence between an RDMA
-        * READ and the following SEND.
-        * We could either do this all the time
-        * or when requested by the user. Right now, we let
-        * the application choose.
-        */
-       if (rm->rdma.op_active && rm->rdma.op_fence)
-               send_flags = IB_SEND_FENCE;
-
-       /*
-        * We could be copying the header into the unused tail of the page.
-        * That would need to be changed in the future when those pages might
-        * be mapped userspace pages or page cache pages.  So instead we always
-        * use a second sge and our long-lived ring of mapped headers.  We send
-        * the header after the data so that the data payload can be aligned on
-        * the receiver.
-        */
-
-       /* handle a 0-len message */
-       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) {
-               rds_iw_xmit_populate_wr(ic, send, pos, 0, 0, send_flags);
-               goto add_header;
-       }
-
-       /* if there's data reference it with a chain of work reqs */
-       for (; i < work_alloc && scat != &rm->data.op_sg[rm->data.op_count]; i++) {
-               unsigned int len;
-
-               send = &ic->i_sends[pos];
-
-               len = min(RDS_FRAG_SIZE,
-                         ib_sg_dma_len(dev, scat) - rm->data.op_dmaoff);
-               rds_iw_xmit_populate_wr(ic, send, pos,
-                       ib_sg_dma_address(dev, scat) + rm->data.op_dmaoff, len,
-                       send_flags);
-
-               /*
-                * We want to delay signaling completions just enough to get
-                * the batching benefits but not so much that we create dead time
-                * on the wire.
-                */
-               if (ic->i_unsignaled_wrs-- == 0) {
-                       ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
-                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-               }
-
-               ic->i_unsignaled_bytes -= len;
-               if (ic->i_unsignaled_bytes <= 0) {
-                       ic->i_unsignaled_bytes = rds_iw_sysctl_max_unsig_bytes;
-                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-               }
-
-               /*
-                * Always signal the last one if we're stopping due to flow control.
-                */
-               if (flow_controlled && i == (work_alloc-1))
-                       send->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-
-               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                        &send->s_send_wr, send->s_send_wr.num_sge, send->s_send_wr.next);
-
-               sent += len;
-               rm->data.op_dmaoff += len;
-               if (rm->data.op_dmaoff == ib_sg_dma_len(dev, scat)) {
-                       scat++;
-                       rm->data.op_dmaoff = 0;
-                       rm->data.op_dmasg++;
-               }
-
-add_header:
-               /* Tack on the header after the data. The header SGE should already
-                * have been set up to point to the right header buffer. */
-               memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
-
-               if (0) {
-                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
-
-                       printk(KERN_NOTICE "send WR dport=%u flags=0x%x len=%d\n",
-                               be16_to_cpu(hdr->h_dport),
-                               hdr->h_flags,
-                               be32_to_cpu(hdr->h_len));
-               }
-               if (adv_credits) {
-                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
-
-                       /* add credit and redo the header checksum */
-                       hdr->h_credit = adv_credits;
-                       rds_message_make_checksum(hdr);
-                       adv_credits = 0;
-                       rds_iw_stats_inc(s_iw_tx_credit_updates);
-               }
-
-               if (prev)
-                       prev->s_send_wr.next = &send->s_send_wr;
-               prev = send;
-
-               pos = (pos + 1) % ic->i_send_ring.w_nr;
-       }
-
-       /* Account the RDS header in the number of bytes we sent, but just once.
-        * The caller has no concept of fragmentation. */
-       if (hdr_off == 0)
-               sent += sizeof(struct rds_header);
-
-       /* if we finished the message then send completion owns it */
-       if (scat == &rm->data.op_sg[rm->data.op_count]) {
-               prev->s_rm = ic->i_rm;
-               prev->s_send_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
-               ic->i_rm = NULL;
-       }
-
-       if (i < work_alloc) {
-               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - i);
-               work_alloc = i;
-       }
-       if (ic->i_flowctl && i < credit_alloc)
-               rds_iw_send_add_credits(conn, credit_alloc - i);
-
-       /* XXX need to worry about failed_wr and partial sends. */
-       failed_wr = &first->s_send_wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_send_wr, &failed_wr);
-       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_send_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_send_wr);
-       if (ret) {
-               printk(KERN_WARNING "RDS/IW: ib_post_send to %pI4 "
-                      "returned %d\n", &conn->c_faddr, ret);
-               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
-               if (prev->s_rm) {
-                       ic->i_rm = prev->s_rm;
-                       prev->s_rm = NULL;
-               }
-               goto out;
-       }
-
-       ret = sent;
-out:
-       BUG_ON(adv_credits);
-       return ret;
-}
-
-static int rds_iw_build_send_reg(struct rds_iw_send_work *send,
-                                struct scatterlist *sg,
-                                int sg_nents)
-{
-       int n;
-
-       n = ib_map_mr_sg(send->s_mr, sg, sg_nents, PAGE_SIZE);
-       if (unlikely(n != sg_nents))
-               return n < 0 ? n : -EINVAL;
-
-       send->s_reg_wr.wr.opcode = IB_WR_REG_MR;
-       send->s_reg_wr.wr.wr_id = 0;
-       send->s_reg_wr.wr.num_sge = 0;
-       send->s_reg_wr.mr = send->s_mr;
-       send->s_reg_wr.key = send->s_mr->rkey;
-       send->s_reg_wr.access = IB_ACCESS_REMOTE_WRITE;
-
-       ib_update_fast_reg_key(send->s_mr, send->s_remap_count++);
-
-       return 0;
-}
-
-int rds_iw_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-       struct rds_iw_send_work *send = NULL;
-       struct rds_iw_send_work *first;
-       struct rds_iw_send_work *prev;
-       struct ib_send_wr *failed_wr;
-       struct rds_iw_device *rds_iwdev;
-       struct scatterlist *scat;
-       unsigned long len;
-       u64 remote_addr = op->op_remote_addr;
-       u32 pos, fr_pos;
-       u32 work_alloc;
-       u32 i;
-       u32 j;
-       int sent;
-       int ret;
-       int num_sge;
-       int sg_nents;
-
-       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
-
-       /* map the message the first time we see it */
-       if (!op->op_mapped) {
-               op->op_count = ib_dma_map_sg(ic->i_cm_id->device,
-                                            op->op_sg, op->op_nents, (op->op_write) ?
-                                            DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->op_count);
-               if (op->op_count == 0) {
-                       rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
-                       ret = -ENOMEM; /* XXX ? */
-                       goto out;
-               }
-
-               op->op_mapped = 1;
-       }
-
-       if (!op->op_write) {
-               /* Alloc space on the send queue for the fastreg */
-               work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, 1, &fr_pos);
-               if (work_alloc != 1) {
-                       rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
-                       rds_iw_stats_inc(s_iw_tx_ring_full);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-       }
-
-       /*
-        * Instead of knowing how to return a partial rdma read/write we insist that there
-        * be enough work requests to send the entire message.
-        */
-       i = ceil(op->op_count, rds_iwdev->max_sge);
-
-       work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
-       if (work_alloc != i) {
-               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
-               rds_iw_stats_inc(s_iw_tx_ring_full);
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       send = &ic->i_sends[pos];
-       if (!op->op_write) {
-               first = prev = &ic->i_sends[fr_pos];
-       } else {
-               first = send;
-               prev = NULL;
-       }
-       scat = &op->op_sg[0];
-       sent = 0;
-       num_sge = op->op_count;
-       sg_nents = 0;
-
-       for (i = 0; i < work_alloc && scat != &op->op_sg[op->op_count]; i++) {
-               send->s_rdma_wr.wr.send_flags = 0;
-               send->s_queued = jiffies;
-
-               /*
-                * We want to delay signaling completions just enough to get
-                * the batching benefits but not so much that we create dead time on the wire.
-                */
-               if (ic->i_unsignaled_wrs-- == 0) {
-                       ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
-                       send->s_rdma_wr.wr.send_flags = IB_SEND_SIGNALED;
-               }
-
-               /* To avoid the need to have the plumbing to invalidate the fastreg_mr used
-                * for local access after RDS is finished with it, using
-                * IB_WR_RDMA_READ_WITH_INV will invalidate it after the read has completed.
-                */
-               if (op->op_write)
-                       send->s_rdma_wr.wr.opcode = IB_WR_RDMA_WRITE;
-               else
-                       send->s_rdma_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
-
-               send->s_rdma_wr.remote_addr = remote_addr;
-               send->s_rdma_wr.rkey = op->op_rkey;
-               send->s_op = op;
-
-               if (num_sge > rds_iwdev->max_sge) {
-                       send->s_rdma_wr.wr.num_sge = rds_iwdev->max_sge;
-                       num_sge -= rds_iwdev->max_sge;
-               } else
-                       send->s_rdma_wr.wr.num_sge = num_sge;
-
-               send->s_rdma_wr.wr.next = NULL;
-
-               if (prev)
-                       prev->s_send_wr.next = &send->s_rdma_wr.wr;
-
-               for (j = 0; j < send->s_rdma_wr.wr.num_sge &&
-                    scat != &op->op_sg[op->op_count]; j++) {
-                       len = ib_sg_dma_len(ic->i_cm_id->device, scat);
-
-                       if (send->s_rdma_wr.wr.opcode == IB_WR_RDMA_READ_WITH_INV)
-                               sg_nents++;
-                       else {
-                               send->s_sge[j].addr = ib_sg_dma_address(ic->i_cm_id->device, scat);
-                               send->s_sge[j].length = len;
-                               send->s_sge[j].lkey = rds_iw_local_dma_lkey(ic);
-                       }
-
-                       sent += len;
-                       rdsdebug("ic %p sent %d remote_addr %llu\n", ic, sent, remote_addr);
-                       remote_addr += len;
-
-                       scat++;
-               }
-
-               if (send->s_rdma_wr.wr.opcode == IB_WR_RDMA_READ_WITH_INV) {
-                       send->s_rdma_wr.wr.num_sge = 1;
-                       send->s_sge[0].addr = conn->c_xmit_rm->m_rs->rs_user_addr;
-                       send->s_sge[0].length = conn->c_xmit_rm->m_rs->rs_user_bytes;
-                       send->s_sge[0].lkey = ic->i_sends[fr_pos].s_mr->lkey;
-               }
-
-               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
-                       &send->s_rdma_wr,
-                       send->s_rdma_wr.wr.num_sge,
-                       send->s_rdma_wr.wr.next);
-
-               prev = send;
-               if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
-                       send = ic->i_sends;
-       }
-
-       /* if we finished the message then send completion owns it */
-       if (scat == &op->op_sg[op->op_count])
-               first->s_rdma_wr.wr.send_flags = IB_SEND_SIGNALED;
-
-       if (i < work_alloc) {
-               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - i);
-               work_alloc = i;
-       }
-
-       /* On iWARP, local memory access by a remote system (ie, RDMA Read) is not
-        * recommended.  Putting the lkey on the wire is a security hole, as it can
-        * allow for memory access to all of memory on the remote system.  Some
-        * adapters do not allow using the lkey for this at all.  To bypass this use a
-        * fastreg_mr (or possibly a dma_mr)
-        */
-       if (!op->op_write) {
-               ret = rds_iw_build_send_reg(&ic->i_sends[fr_pos],
-                                           &op->op_sg[0], sg_nents);
-               if (ret) {
-                       printk(KERN_WARNING "RDS/IW: failed to reg send mem\n");
-                       goto out;
-               }
-               work_alloc++;
-       }
-
-       failed_wr = &first->s_rdma_wr.wr;
-       ret = ib_post_send(ic->i_cm_id->qp, &first->s_rdma_wr.wr, &failed_wr);
-       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
-                first, &first->s_rdma_wr, ret, failed_wr);
-       BUG_ON(failed_wr != &first->s_rdma_wr.wr);
-       if (ret) {
-               printk(KERN_WARNING "RDS/IW: rdma ib_post_send to %pI4 "
-                      "returned %d\n", &conn->c_faddr, ret);
-               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
-               goto out;
-       }
-
-out:
-       return ret;
-}
-
-void rds_iw_xmit_complete(struct rds_connection *conn)
-{
-       struct rds_iw_connection *ic = conn->c_transport_data;
-
-       /* We may have a pending ACK or window update we were unable
-        * to send previously (due to flow control). Try again. */
-       rds_iw_attempt_ack(ic);
-}
diff --git a/net/rds/iw_stats.c b/net/rds/iw_stats.c
deleted file mode 100644 (file)
index 5fe67f6..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/percpu.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-
-#include "rds.h"
-#include "iw.h"
-
-DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_iw_statistics, rds_iw_stats);
-
-static const char *const rds_iw_stat_names[] = {
-       "iw_connect_raced",
-       "iw_listen_closed_stale",
-       "iw_tx_cq_call",
-       "iw_tx_cq_event",
-       "iw_tx_ring_full",
-       "iw_tx_throttle",
-       "iw_tx_sg_mapping_failure",
-       "iw_tx_stalled",
-       "iw_tx_credit_updates",
-       "iw_rx_cq_call",
-       "iw_rx_cq_event",
-       "iw_rx_ring_empty",
-       "iw_rx_refill_from_cq",
-       "iw_rx_refill_from_thread",
-       "iw_rx_alloc_limit",
-       "iw_rx_credit_updates",
-       "iw_ack_sent",
-       "iw_ack_send_failure",
-       "iw_ack_send_delayed",
-       "iw_ack_send_piggybacked",
-       "iw_ack_received",
-       "iw_rdma_mr_alloc",
-       "iw_rdma_mr_free",
-       "iw_rdma_mr_used",
-       "iw_rdma_mr_pool_flush",
-       "iw_rdma_mr_pool_wait",
-       "iw_rdma_mr_pool_depleted",
-};
-
-unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
-                                   unsigned int avail)
-{
-       struct rds_iw_statistics stats = {0, };
-       uint64_t *src;
-       uint64_t *sum;
-       size_t i;
-       int cpu;
-
-       if (avail < ARRAY_SIZE(rds_iw_stat_names))
-               goto out;
-
-       for_each_online_cpu(cpu) {
-               src = (uint64_t *)&(per_cpu(rds_iw_stats, cpu));
-               sum = (uint64_t *)&stats;
-               for (i = 0; i < sizeof(stats) / sizeof(uint64_t); i++)
-                       *(sum++) += *(src++);
-       }
-
-       rds_stats_info_copy(iter, (uint64_t *)&stats, rds_iw_stat_names,
-                           ARRAY_SIZE(rds_iw_stat_names));
-out:
-       return ARRAY_SIZE(rds_iw_stat_names);
-}
diff --git a/net/rds/iw_sysctl.c b/net/rds/iw_sysctl.c
deleted file mode 100644 (file)
index 139239d..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2006 Oracle.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
-#include <linux/kernel.h>
-#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-
-#include "iw.h"
-
-static struct ctl_table_header *rds_iw_sysctl_hdr;
-
-unsigned long rds_iw_sysctl_max_send_wr = RDS_IW_DEFAULT_SEND_WR;
-unsigned long rds_iw_sysctl_max_recv_wr = RDS_IW_DEFAULT_RECV_WR;
-unsigned long rds_iw_sysctl_max_recv_allocation = (128 * 1024 * 1024) / RDS_FRAG_SIZE;
-static unsigned long rds_iw_sysctl_max_wr_min = 1;
-/* hardware will fail CQ creation long before this */
-static unsigned long rds_iw_sysctl_max_wr_max = (u32)~0;
-
-unsigned long rds_iw_sysctl_max_unsig_wrs = 16;
-static unsigned long rds_iw_sysctl_max_unsig_wr_min = 1;
-static unsigned long rds_iw_sysctl_max_unsig_wr_max = 64;
-
-unsigned long rds_iw_sysctl_max_unsig_bytes = (16 << 20);
-static unsigned long rds_iw_sysctl_max_unsig_bytes_min = 1;
-static unsigned long rds_iw_sysctl_max_unsig_bytes_max = ~0UL;
-
-unsigned int rds_iw_sysctl_flow_control = 1;
-
-static struct ctl_table rds_iw_sysctl_table[] = {
-       {
-               .procname       = "max_send_wr",
-               .data           = &rds_iw_sysctl_max_send_wr,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &rds_iw_sysctl_max_wr_min,
-               .extra2         = &rds_iw_sysctl_max_wr_max,
-       },
-       {
-               .procname       = "max_recv_wr",
-               .data           = &rds_iw_sysctl_max_recv_wr,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &rds_iw_sysctl_max_wr_min,
-               .extra2         = &rds_iw_sysctl_max_wr_max,
-       },
-       {
-               .procname       = "max_unsignaled_wr",
-               .data           = &rds_iw_sysctl_max_unsig_wrs,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &rds_iw_sysctl_max_unsig_wr_min,
-               .extra2         = &rds_iw_sysctl_max_unsig_wr_max,
-       },
-       {
-               .procname       = "max_unsignaled_bytes",
-               .data           = &rds_iw_sysctl_max_unsig_bytes,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-               .extra1         = &rds_iw_sysctl_max_unsig_bytes_min,
-               .extra2         = &rds_iw_sysctl_max_unsig_bytes_max,
-       },
-       {
-               .procname       = "max_recv_allocation",
-               .data           = &rds_iw_sysctl_max_recv_allocation,
-               .maxlen         = sizeof(unsigned long),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
-       },
-       {
-               .procname       = "flow_control",
-               .data           = &rds_iw_sysctl_flow_control,
-               .maxlen         = sizeof(rds_iw_sysctl_flow_control),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
-       { }
-};
-
-void rds_iw_sysctl_exit(void)
-{
-       unregister_net_sysctl_table(rds_iw_sysctl_hdr);
-}
-
-int rds_iw_sysctl_init(void)
-{
-       rds_iw_sysctl_hdr = register_net_sysctl(&init_net, "net/rds/iw", rds_iw_sysctl_table);
-       if (!rds_iw_sysctl_hdr)
-               return -ENOMEM;
-       return 0;
-}
index 9c1fed81bf0f73927cc97a09c92e66fd926f288a..7220bebcf5586e0ad9c3a2ec03507017c0403e88 100644 (file)
@@ -49,9 +49,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
        rdsdebug("conn %p id %p handling event %u (%s)\n", conn, cm_id,
                 event->event, rdma_event_msg(event->event));
 
-       if (cm_id->device->node_type == RDMA_NODE_RNIC)
-               trans = &rds_iw_transport;
-       else
+       if (cm_id->device->node_type == RDMA_NODE_IB_CA)
                trans = &rds_ib_transport;
 
        /* Prevent shutdown from tearing down the connection
@@ -119,6 +117,14 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
                rds_conn_drop(conn);
                break;
 
+       case RDMA_CM_EVENT_TIMEWAIT_EXIT:
+               if (conn) {
+                       pr_info("RDS: RDMA_CM_EVENT_TIMEWAIT_EXIT event: dropping connection %pI4->%pI4\n",
+                               &conn->c_laddr, &conn->c_faddr);
+                       rds_conn_drop(conn);
+               }
+               break;
+
        default:
                /* things like device disconnect? */
                printk(KERN_ERR "RDS: unknown event %u (%s)!\n",
@@ -200,10 +206,6 @@ static int rds_rdma_init(void)
        if (ret)
                goto out;
 
-       ret = rds_iw_init();
-       if (ret)
-               goto err_iw_init;
-
        ret = rds_ib_init();
        if (ret)
                goto err_ib_init;
@@ -211,8 +213,6 @@ static int rds_rdma_init(void)
        goto out;
 
 err_ib_init:
-       rds_iw_exit();
-err_iw_init:
        rds_rdma_listen_stop();
 out:
        return ret;
@@ -224,11 +224,10 @@ static void rds_rdma_exit(void)
        /* stop listening first to ensure no new connections are attempted */
        rds_rdma_listen_stop();
        rds_ib_exit();
-       rds_iw_exit();
 }
 module_exit(rds_rdma_exit);
 
 MODULE_AUTHOR("Oracle Corporation <rds-devel@oss.oracle.com>");
-MODULE_DESCRIPTION("RDS: IB/iWARP transport");
+MODULE_DESCRIPTION("RDS: IB transport");
 MODULE_LICENSE("Dual BSD/GPL");
 
index faba4e382695e36c12c25f981b043077f4d7363c..ff2010e9d20ce0158a264b4e162270f4dbeea144 100644 (file)
@@ -16,9 +16,4 @@ extern struct rds_transport rds_ib_transport;
 int rds_ib_init(void);
 void rds_ib_exit(void);
 
-/* from iw.c */
-extern struct rds_transport rds_iw_transport;
-int rds_iw_init(void);
-void rds_iw_exit(void);
-
 #endif
index 0e2797bdc3162b26995aeee2974187fdea62f5bf..80256b08eac0388d702f5981f00703d2118f5cce 100644 (file)
@@ -222,6 +222,7 @@ struct rds_incoming {
        __be32                  i_saddr;
 
        rds_rdma_cookie_t       i_rdma_cookie;
+       struct timeval          i_rx_tstamp;
 };
 
 struct rds_mr {
index a00462b0d01de9ee2793d4fb273bf568b2eefc29..c0be1ecd11c99ce57360687fa2b34f312c0cf0d6 100644 (file)
@@ -35,6 +35,8 @@
 #include <net/sock.h>
 #include <linux/in.h>
 #include <linux/export.h>
+#include <linux/time.h>
+#include <linux/rds.h>
 
 #include "rds.h"
 
@@ -46,6 +48,8 @@ void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
        inc->i_conn = conn;
        inc->i_saddr = saddr;
        inc->i_rdma_cookie = 0;
+       inc->i_rx_tstamp.tv_sec = 0;
+       inc->i_rx_tstamp.tv_usec = 0;
 }
 EXPORT_SYMBOL_GPL(rds_inc_init);
 
@@ -228,6 +232,8 @@ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
                rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong,
                                      be32_to_cpu(inc->i_hdr.h_len),
                                      inc->i_hdr.h_dport);
+               if (sock_flag(sk, SOCK_RCVTSTAMP))
+                       do_gettimeofday(&inc->i_rx_tstamp);
                rds_inc_addref(inc);
                list_add_tail(&inc->i_item, &rs->rs_recv_queue);
                __rds_wake_sk_sleep(sk);
@@ -381,7 +387,8 @@ static int rds_notify_cong(struct rds_sock *rs, struct msghdr *msghdr)
 /*
  * Receive any control messages.
  */
-static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg)
+static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg,
+                        struct rds_sock *rs)
 {
        int ret = 0;
 
@@ -392,6 +399,15 @@ static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg)
                        return ret;
        }
 
+       if ((inc->i_rx_tstamp.tv_sec != 0) &&
+           sock_flag(rds_rs_to_sk(rs), SOCK_RCVTSTAMP)) {
+               ret = put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
+                              sizeof(struct timeval),
+                              &inc->i_rx_tstamp);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -474,7 +490,7 @@ int rds_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
                        msg->msg_flags |= MSG_TRUNC;
                }
 
-               if (rds_cmsg_recv(inc, msg)) {
+               if (rds_cmsg_recv(inc, msg, rs)) {
                        ret = -EFAULT;
                        goto out;
                }
index 598d374f6a35f714db4753efa7ab28d6782419a9..868f1ad0415a4ea728989908ed49858b6dfccc01 100644 (file)
@@ -41,5 +41,4 @@ config RFKILL_GPIO
        default n
        help
          If you say yes here you get support of a generic gpio RFKILL
-         driver. The platform should fill in the appropriate fields in the
-         rfkill_gpio_platform_data structure and pass that to the driver.
+         driver.
index cf5b69ab18294bb2fa36a00f2a19dbf02d0f3045..03f26e3a6f48afa0308d0ffbad0a3d740dab25b8 100644 (file)
@@ -57,6 +57,8 @@ struct rfkill {
 
        bool                    registered;
        bool                    persistent;
+       bool                    polling_paused;
+       bool                    suspended;
 
        const struct rfkill_ops *ops;
        void                    *data;
@@ -233,29 +235,6 @@ static void rfkill_event(struct rfkill *rfkill)
        rfkill_send_events(rfkill, RFKILL_OP_CHANGE);
 }
 
-static bool __rfkill_set_hw_state(struct rfkill *rfkill,
-                                 bool blocked, bool *change)
-{
-       unsigned long flags;
-       bool prev, any;
-
-       BUG_ON(!rfkill);
-
-       spin_lock_irqsave(&rfkill->lock, flags);
-       prev = !!(rfkill->state & RFKILL_BLOCK_HW);
-       if (blocked)
-               rfkill->state |= RFKILL_BLOCK_HW;
-       else
-               rfkill->state &= ~RFKILL_BLOCK_HW;
-       *change = prev != blocked;
-       any = !!(rfkill->state & RFKILL_BLOCK_ANY);
-       spin_unlock_irqrestore(&rfkill->lock, flags);
-
-       rfkill_led_trigger_event(rfkill);
-
-       return any;
-}
-
 /**
  * rfkill_set_block - wrapper for set_block method
  *
@@ -285,7 +264,7 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
        spin_lock_irqsave(&rfkill->lock, flags);
        prev = rfkill->state & RFKILL_BLOCK_SW;
 
-       if (rfkill->state & RFKILL_BLOCK_SW)
+       if (prev)
                rfkill->state |= RFKILL_BLOCK_SW_PREV;
        else
                rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
@@ -303,8 +282,8 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
        spin_lock_irqsave(&rfkill->lock, flags);
        if (err) {
                /*
-                * Failed -- reset status to _prev, this may be different
-                * from what set set _PREV to earlier in this function
+                * Failed -- reset status to _PREV, which may be different
+                * from what we have set _PREV to earlier in this function
                 * if rfkill_set_sw_state was invoked.
                 */
                if (rfkill->state & RFKILL_BLOCK_SW_PREV)
@@ -323,6 +302,19 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
                rfkill_event(rfkill);
 }
 
+static void rfkill_update_global_state(enum rfkill_type type, bool blocked)
+{
+       int i;
+
+       if (type != RFKILL_TYPE_ALL) {
+               rfkill_global_states[type].cur = blocked;
+               return;
+       }
+
+       for (i = 0; i < NUM_RFKILL_TYPES; i++)
+               rfkill_global_states[i].cur = blocked;
+}
+
 #ifdef CONFIG_RFKILL_INPUT
 static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
 
@@ -332,8 +324,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
  * @blocked: the new state
  *
  * This function sets the state of all switches of given type,
- * unless a specific switch is claimed by userspace (in which case,
- * that switch is left alone) or suspended.
+ * unless a specific switch is suspended.
  *
  * Caller must have acquired rfkill_global_mutex.
  */
@@ -341,15 +332,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
 {
        struct rfkill *rfkill;
 
-       if (type == RFKILL_TYPE_ALL) {
-               int i;
-
-               for (i = 0; i < NUM_RFKILL_TYPES; i++)
-                       rfkill_global_states[i].cur = blocked;
-       } else {
-               rfkill_global_states[type].cur = blocked;
-       }
-
+       rfkill_update_global_state(type, blocked);
        list_for_each_entry(rfkill, &rfkill_list, node) {
                if (rfkill->type != type && type != RFKILL_TYPE_ALL)
                        continue;
@@ -477,17 +460,28 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type)
 }
 #endif
 
-
 bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
 {
-       bool ret, change;
+       unsigned long flags;
+       bool ret, prev;
+
+       BUG_ON(!rfkill);
 
-       ret = __rfkill_set_hw_state(rfkill, blocked, &change);
+       spin_lock_irqsave(&rfkill->lock, flags);
+       prev = !!(rfkill->state & RFKILL_BLOCK_HW);
+       if (blocked)
+               rfkill->state |= RFKILL_BLOCK_HW;
+       else
+               rfkill->state &= ~RFKILL_BLOCK_HW;
+       ret = !!(rfkill->state & RFKILL_BLOCK_ANY);
+       spin_unlock_irqrestore(&rfkill->lock, flags);
+
+       rfkill_led_trigger_event(rfkill);
 
        if (!rfkill->registered)
                return ret;
 
-       if (change)
+       if (prev != blocked)
                schedule_work(&rfkill->uevent_work);
 
        return ret;
@@ -582,6 +576,34 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
 }
 EXPORT_SYMBOL(rfkill_set_states);
 
+static const char * const rfkill_types[] = {
+       NULL, /* RFKILL_TYPE_ALL */
+       "wlan",
+       "bluetooth",
+       "ultrawideband",
+       "wimax",
+       "wwan",
+       "gps",
+       "fm",
+       "nfc",
+};
+
+enum rfkill_type rfkill_find_type(const char *name)
+{
+       int i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(rfkill_types) != NUM_RFKILL_TYPES);
+
+       if (!name)
+               return RFKILL_TYPE_ALL;
+
+       for (i = 1; i < NUM_RFKILL_TYPES; i++)
+               if (!strcmp(name, rfkill_types[i]))
+                       return i;
+       return RFKILL_TYPE_ALL;
+}
+EXPORT_SYMBOL(rfkill_find_type);
+
 static ssize_t name_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
@@ -591,38 +613,12 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(name);
 
-static const char *rfkill_get_type_str(enum rfkill_type type)
-{
-       BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
-
-       switch (type) {
-       case RFKILL_TYPE_WLAN:
-               return "wlan";
-       case RFKILL_TYPE_BLUETOOTH:
-               return "bluetooth";
-       case RFKILL_TYPE_UWB:
-               return "ultrawideband";
-       case RFKILL_TYPE_WIMAX:
-               return "wimax";
-       case RFKILL_TYPE_WWAN:
-               return "wwan";
-       case RFKILL_TYPE_GPS:
-               return "gps";
-       case RFKILL_TYPE_FM:
-               return "fm";
-       case RFKILL_TYPE_NFC:
-               return "nfc";
-       default:
-               BUG();
-       }
-}
-
 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
        struct rfkill *rfkill = to_rfkill(dev);
 
-       return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
+       return sprintf(buf, "%s\n", rfkill_types[rfkill->type]);
 }
 static DEVICE_ATTR_RO(type);
 
@@ -730,20 +726,12 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RW(state);
 
-static ssize_t claim_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       return sprintf(buf, "%d\n", 0);
-}
-static DEVICE_ATTR_RO(claim);
-
 static struct attribute *rfkill_dev_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_type.attr,
        &dev_attr_index.attr,
        &dev_attr_persistent.attr,
        &dev_attr_state.attr,
-       &dev_attr_claim.attr,
        &dev_attr_soft.attr,
        &dev_attr_hard.attr,
        NULL,
@@ -768,7 +756,7 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
        if (error)
                return error;
        error = add_uevent_var(env, "RFKILL_TYPE=%s",
-                              rfkill_get_type_str(rfkill->type));
+                              rfkill_types[rfkill->type]);
        if (error)
                return error;
        spin_lock_irqsave(&rfkill->lock, flags);
@@ -786,6 +774,7 @@ void rfkill_pause_polling(struct rfkill *rfkill)
        if (!rfkill->ops->poll)
                return;
 
+       rfkill->polling_paused = true;
        cancel_delayed_work_sync(&rfkill->poll_work);
 }
 EXPORT_SYMBOL(rfkill_pause_polling);
@@ -797,6 +786,11 @@ void rfkill_resume_polling(struct rfkill *rfkill)
        if (!rfkill->ops->poll)
                return;
 
+       rfkill->polling_paused = false;
+
+       if (rfkill->suspended)
+               return;
+
        queue_delayed_work(system_power_efficient_wq,
                           &rfkill->poll_work, 0);
 }
@@ -807,7 +801,8 @@ static int rfkill_suspend(struct device *dev)
 {
        struct rfkill *rfkill = to_rfkill(dev);
 
-       rfkill_pause_polling(rfkill);
+       rfkill->suspended = true;
+       cancel_delayed_work_sync(&rfkill->poll_work);
 
        return 0;
 }
@@ -817,12 +812,16 @@ static int rfkill_resume(struct device *dev)
        struct rfkill *rfkill = to_rfkill(dev);
        bool cur;
 
+       rfkill->suspended = false;
+
        if (!rfkill->persistent) {
                cur = !!(rfkill->state & RFKILL_BLOCK_SW);
                rfkill_set_block(rfkill, cur);
        }
 
-       rfkill_resume_polling(rfkill);
+       if (rfkill->ops->poll && !rfkill->polling_paused)
+               queue_delayed_work(system_power_efficient_wq,
+                                  &rfkill->poll_work, 0);
 
        return 0;
 }
@@ -1164,15 +1163,8 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
 
        mutex_lock(&rfkill_global_mutex);
 
-       if (ev.op == RFKILL_OP_CHANGE_ALL) {
-               if (ev.type == RFKILL_TYPE_ALL) {
-                       enum rfkill_type i;
-                       for (i = 0; i < NUM_RFKILL_TYPES; i++)
-                               rfkill_global_states[i].cur = ev.soft;
-               } else {
-                       rfkill_global_states[ev.type].cur = ev.soft;
-               }
-       }
+       if (ev.op == RFKILL_OP_CHANGE_ALL)
+               rfkill_update_global_state(ev.type, ev.soft);
 
        list_for_each_entry(rfkill, &rfkill_list, node) {
                if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL)
@@ -1261,10 +1253,8 @@ static struct miscdevice rfkill_miscdev = {
 static int __init rfkill_init(void)
 {
        int error;
-       int i;
 
-       for (i = 0; i < NUM_RFKILL_TYPES; i++)
-               rfkill_global_states[i].cur = !rfkill_default_state;
+       rfkill_update_global_state(RFKILL_TYPE_ALL, !rfkill_default_state);
 
        error = class_register(&rfkill_class);
        if (error)
index 4b1e3f35f06cf39ecb9bb3f6a88d802a67a37bc3..76c01cbd56e35b209bf5e2599298471263f14ded 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/acpi.h>
 #include <linux/gpio/consumer.h>
 
-#include <linux/rfkill-gpio.h>
-
 struct rfkill_gpio_data {
        const char              *name;
        enum rfkill_type        type;
@@ -81,7 +79,6 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
        if (!id)
                return -ENODEV;
 
-       rfkill->name = dev_name(dev);
        rfkill->type = (unsigned)id->driver_data;
 
        return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
@@ -90,24 +87,27 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
 
 static int rfkill_gpio_probe(struct platform_device *pdev)
 {
-       struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
        struct rfkill_gpio_data *rfkill;
        struct gpio_desc *gpio;
+       const char *type_name;
        int ret;
 
        rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
        if (!rfkill)
                return -ENOMEM;
 
+       device_property_read_string(&pdev->dev, "name", &rfkill->name);
+       device_property_read_string(&pdev->dev, "type", &type_name);
+
+       if (!rfkill->name)
+               rfkill->name = dev_name(&pdev->dev);
+
+       rfkill->type = rfkill_find_type(type_name);
+
        if (ACPI_HANDLE(&pdev->dev)) {
                ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
                if (ret)
                        return ret;
-       } else if (pdata) {
-               rfkill->name = pdata->name;
-               rfkill->type = pdata->type;
-       } else {
-               return -ENODEV;
        }
 
        rfkill->clk = devm_clk_get(&pdev->dev, NULL);
@@ -124,10 +124,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
 
        rfkill->shutdown_gpio = gpio;
 
-       /* Make sure at-least one of the GPIO is defined and that
-        * a name is specified for this instance
-        */
-       if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) {
+       /* Make sure at-least one GPIO is defined for this instance */
+       if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) {
                dev_err(&pdev->dev, "invalid platform data\n");
                return -EINVAL;
        }
index 7e2d1057d8bc1cd89ed9041b4c658b58626f26aa..9d935fa5a2a98884beca08329433cf66dbafebdc 100644 (file)
@@ -37,7 +37,7 @@ static struct proto rxrpc_proto;
 static const struct proto_ops rxrpc_rpc_ops;
 
 /* local epoch for detecting local-end reset */
-__be32 rxrpc_epoch;
+u32 rxrpc_epoch;
 
 /* current debugging ID */
 atomic_t rxrpc_debug_id;
@@ -81,6 +81,8 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
                                  struct sockaddr_rxrpc *srx,
                                  int len)
 {
+       unsigned int tail;
+
        if (len < sizeof(struct sockaddr_rxrpc))
                return -EINVAL;
 
@@ -103,9 +105,7 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
                _debug("INET: %x @ %pI4",
                       ntohs(srx->transport.sin.sin_port),
                       &srx->transport.sin.sin_addr);
-               if (srx->transport_len > 8)
-                       memset((void *)&srx->transport + 8, 0,
-                              srx->transport_len - 8);
+               tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
                break;
 
        case AF_INET6:
@@ -113,6 +113,8 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
                return -EAFNOSUPPORT;
        }
 
+       if (tail < len)
+               memset((void *)srx + tail, 0, len - tail);
        return 0;
 }
 
@@ -121,11 +123,10 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
  */
 static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 {
-       struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *) saddr;
+       struct sockaddr_rxrpc *srx = (struct sockaddr_rxrpc *)saddr;
        struct sock *sk = sock->sk;
        struct rxrpc_local *local;
        struct rxrpc_sock *rx = rxrpc_sk(sk), *prx;
-       __be16 service_id;
        int ret;
 
        _enter("%p,%p,%d", rx, saddr, len);
@@ -143,7 +144,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 
        memcpy(&rx->srx, srx, sizeof(rx->srx));
 
-       /* find a local transport endpoint if we don't have one already */
+       /* Find or create a local transport endpoint to use */
        local = rxrpc_lookup_local(&rx->srx);
        if (IS_ERR(local)) {
                ret = PTR_ERR(local);
@@ -152,14 +153,12 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
 
        rx->local = local;
        if (srx->srx_service) {
-               service_id = htons(srx->srx_service);
                write_lock_bh(&local->services_lock);
                list_for_each_entry(prx, &local->services, listen_link) {
-                       if (prx->service_id == service_id)
+                       if (prx->srx.srx_service == srx->srx_service)
                                goto service_in_use;
                }
 
-               rx->service_id = service_id;
                list_add_tail(&rx->listen_link, &local->services);
                write_unlock_bh(&local->services_lock);
 
@@ -276,7 +275,6 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
        struct rxrpc_transport *trans;
        struct rxrpc_call *call;
        struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
-       __be16 service_id;
 
        _enter(",,%x,%lx", key_serial(key), user_call_ID);
 
@@ -299,16 +297,14 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                atomic_inc(&trans->usage);
        }
 
-       service_id = rx->service_id;
-       if (srx)
-               service_id = htons(srx->srx_service);
-
+       if (!srx)
+               srx = &rx->srx;
        if (!key)
                key = rx->key;
        if (key && !key->payload.data[0])
                key = NULL; /* a no-security key */
 
-       bundle = rxrpc_get_bundle(rx, trans, key, service_id, gfp);
+       bundle = rxrpc_get_bundle(rx, trans, key, srx->srx_service, gfp);
        if (IS_ERR(bundle)) {
                call = ERR_CAST(bundle);
                goto out;
@@ -324,7 +320,6 @@ out_notrans:
        _leave(" = %p", call);
        return call;
 }
-
 EXPORT_SYMBOL(rxrpc_kernel_begin_call);
 
 /**
@@ -340,7 +335,6 @@ void rxrpc_kernel_end_call(struct rxrpc_call *call)
        rxrpc_remove_user_ID(call->socket, call);
        rxrpc_put_call(call);
 }
-
 EXPORT_SYMBOL(rxrpc_kernel_end_call);
 
 /**
@@ -425,7 +419,6 @@ static int rxrpc_connect(struct socket *sock, struct sockaddr *addr,
        }
 
        rx->trans = trans;
-       rx->service_id = htons(srx->srx_service);
        rx->sk.sk_state = RXRPC_CLIENT_CONNECTED;
 
        release_sock(&rx->sk);
@@ -622,7 +615,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
        if (!net_eq(net, &init_net))
                return -EAFNOSUPPORT;
 
-       /* we support transport protocol UDP only */
+       /* we support transport protocol UDP/UDP6 only */
        if (protocol != PF_INET)
                return -EPROTONOSUPPORT;
 
@@ -754,7 +747,7 @@ static int rxrpc_release(struct socket *sock)
  * RxRPC network protocol
  */
 static const struct proto_ops rxrpc_rpc_ops = {
-       .family         = PF_UNIX,
+       .family         = PF_RXRPC,
        .owner          = THIS_MODULE,
        .release        = rxrpc_release,
        .bind           = rxrpc_bind,
@@ -778,7 +771,7 @@ static struct proto rxrpc_proto = {
        .name           = "RXRPC",
        .owner          = THIS_MODULE,
        .obj_size       = sizeof(struct rxrpc_sock),
-       .max_header     = sizeof(struct rxrpc_header),
+       .max_header     = sizeof(struct rxrpc_wire_header),
 };
 
 static const struct net_proto_family rxrpc_family_ops = {
@@ -796,7 +789,7 @@ static int __init af_rxrpc_init(void)
 
        BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb));
 
-       rxrpc_epoch = htonl(get_seconds());
+       rxrpc_epoch = get_seconds();
 
        ret = -ENOMEM;
        rxrpc_call_jar = kmem_cache_create(
index 6d79310fcaaeead0d6d0953f791e18385c794c03..277731a5e67a523988673d5f7dccfc8de6ac47a8 100644 (file)
@@ -27,7 +27,7 @@
  * generate a connection-level abort
  */
 static int rxrpc_busy(struct rxrpc_local *local, struct sockaddr_rxrpc *srx,
-                     struct rxrpc_header *hdr)
+                     struct rxrpc_wire_header *whdr)
 {
        struct msghdr msg;
        struct kvec iov[1];
@@ -36,25 +36,21 @@ static int rxrpc_busy(struct rxrpc_local *local, struct sockaddr_rxrpc *srx,
 
        _enter("%d,,", local->debug_id);
 
+       whdr->type      = RXRPC_PACKET_TYPE_BUSY;
+       whdr->serial    = htonl(1);
+
        msg.msg_name    = &srx->transport.sin;
        msg.msg_namelen = sizeof(srx->transport.sin);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr->seq        = 0;
-       hdr->type       = RXRPC_PACKET_TYPE_BUSY;
-       hdr->flags      = 0;
-       hdr->userStatus = 0;
-       hdr->_rsvd      = 0;
-
-       iov[0].iov_base = hdr;
-       iov[0].iov_len  = sizeof(*hdr);
+       iov[0].iov_base = whdr;
+       iov[0].iov_len  = sizeof(*whdr);
 
        len = iov[0].iov_len;
 
-       hdr->serial = htonl(1);
-       _proto("Tx BUSY %%%u", ntohl(hdr->serial));
+       _proto("Tx BUSY %%1");
 
        ret = kernel_sendmsg(local->socket, &msg, iov, 1, len);
        if (ret < 0) {
@@ -185,8 +181,8 @@ invalid_service:
        read_unlock_bh(&local->services_lock);
 
        read_lock_bh(&call->state_lock);
-       if (!test_bit(RXRPC_CALL_RELEASE, &call->flags) &&
-           !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events)) {
+       if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
+           !test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events)) {
                rxrpc_get_call(call);
                rxrpc_queue_call(call);
        }
@@ -211,8 +207,8 @@ void rxrpc_accept_incoming_calls(struct work_struct *work)
        struct rxrpc_skb_priv *sp;
        struct sockaddr_rxrpc srx;
        struct rxrpc_sock *rx;
+       struct rxrpc_wire_header whdr;
        struct sk_buff *skb;
-       __be16 service_id;
        int ret;
 
        _enter("%d", local->debug_id);
@@ -240,6 +236,19 @@ process_next_packet:
 
        sp = rxrpc_skb(skb);
 
+       /* Set up a response packet header in case we need it */
+       whdr.epoch      = htonl(sp->hdr.epoch);
+       whdr.cid        = htonl(sp->hdr.cid);
+       whdr.callNumber = htonl(sp->hdr.callNumber);
+       whdr.seq        = htonl(sp->hdr.seq);
+       whdr.serial     = 0;
+       whdr.flags      = 0;
+       whdr.type       = 0;
+       whdr.userStatus = 0;
+       whdr.securityIndex = sp->hdr.securityIndex;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(sp->hdr.serviceId);
+
        /* determine the remote address */
        memset(&srx, 0, sizeof(srx));
        srx.srx_family = AF_RXRPC;
@@ -256,10 +265,9 @@ process_next_packet:
        }
 
        /* get the socket providing the service */
-       service_id = sp->hdr.serviceId;
        read_lock_bh(&local->services_lock);
        list_for_each_entry(rx, &local->services, listen_link) {
-               if (rx->service_id == service_id &&
+               if (rx->srx.srx_service == sp->hdr.serviceId &&
                    rx->sk.sk_state != RXRPC_CLOSE)
                        goto found_service;
        }
@@ -267,7 +275,7 @@ process_next_packet:
        goto invalid_service;
 
 found_service:
-       _debug("found service %hd", ntohs(rx->service_id));
+       _debug("found service %hd", rx->srx.srx_service);
        if (sk_acceptq_is_full(&rx->sk))
                goto backlog_full;
        sk_acceptq_added(&rx->sk);
@@ -296,7 +304,7 @@ found_service:
 backlog_full:
        read_unlock_bh(&local->services_lock);
 busy:
-       rxrpc_busy(local, &srx, &sp->hdr);
+       rxrpc_busy(local, &srx, &whdr);
        rxrpc_free_skb(skb);
        goto process_next_packet;
 
@@ -379,7 +387,7 @@ struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
        rb_insert_color(&call->sock_node, &rx->calls);
        if (test_and_set_bit(RXRPC_CALL_HAS_USERID, &call->flags))
                BUG();
-       if (test_and_set_bit(RXRPC_CALL_ACCEPTED, &call->events))
+       if (test_and_set_bit(RXRPC_CALL_EV_ACCEPTED, &call->events))
                BUG();
        rxrpc_queue_call(call);
 
@@ -395,7 +403,7 @@ struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
 out_release:
        _debug("release %p", call);
        if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
-           !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+           !test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
                rxrpc_queue_call(call);
 out_discard:
        write_unlock_bh(&call->state_lock);
@@ -407,7 +415,7 @@ out:
 }
 
 /*
- * handle rejectance of a call by userspace
+ * Handle rejection of a call by userspace
  * - reject the call at the front of the queue
  */
 int rxrpc_reject_call(struct rxrpc_sock *rx)
@@ -434,7 +442,7 @@ int rxrpc_reject_call(struct rxrpc_sock *rx)
        switch (call->state) {
        case RXRPC_CALL_SERVER_ACCEPTING:
                call->state = RXRPC_CALL_SERVER_BUSY;
-               if (test_and_set_bit(RXRPC_CALL_REJECT_BUSY, &call->events))
+               if (test_and_set_bit(RXRPC_CALL_EV_REJECT_BUSY, &call->events))
                        rxrpc_queue_call(call);
                ret = 0;
                goto out_release;
@@ -458,7 +466,7 @@ int rxrpc_reject_call(struct rxrpc_sock *rx)
 out_release:
        _debug("release %p", call);
        if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
-           !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+           !test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
                rxrpc_queue_call(call);
 out_discard:
        write_unlock_bh(&call->state_lock);
@@ -487,7 +495,6 @@ struct rxrpc_call *rxrpc_kernel_accept_call(struct socket *sock,
        _leave(" = %p", call);
        return call;
 }
-
 EXPORT_SYMBOL(rxrpc_kernel_accept_call);
 
 /**
@@ -506,5 +513,4 @@ int rxrpc_kernel_reject_call(struct socket *sock)
        _leave(" = %d", ret);
        return ret;
 }
-
 EXPORT_SYMBOL(rxrpc_kernel_reject_call);
index adc555e0323d70b90d786c630f5a04dfddd60b32..16d967075eaf8f1c4cc15ea0ac926cd97277d2d8 100644 (file)
@@ -23,7 +23,7 @@
  * 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;
+unsigned int rxrpc_requested_ack_delay = 1;
 
 /*
  * How long to wait before scheduling an ACK with subtype DELAY (in jiffies).
@@ -32,7 +32,7 @@ unsigned rxrpc_requested_ack_delay = 1;
  * 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;
+unsigned int rxrpc_soft_ack_delay = 1 * HZ;
 
 /*
  * How long to wait before scheduling an ACK with subtype IDLE (in jiffies).
@@ -41,7 +41,7 @@ unsigned rxrpc_soft_ack_delay = 1 * HZ;
  * 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;
+unsigned int rxrpc_idle_ack_delay = 0.5 * HZ;
 
 /*
  * Receive window size in packets.  This indicates the maximum number of
@@ -49,19 +49,19 @@ unsigned rxrpc_idle_ack_delay = 0.5 * HZ;
  * limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further
  * packets.
  */
-unsigned rxrpc_rx_window_size = 32;
+unsigned int 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;
+unsigned int 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;
+unsigned int rxrpc_rx_jumbo_max = 4;
 
 static const char *rxrpc_acks(u8 reason)
 {
@@ -91,7 +91,7 @@ static const s8 rxrpc_ack_priority[] = {
  * propose an ACK be sent
  */
 void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                        __be32 serial, bool immediate)
+                        u32 serial, bool immediate)
 {
        unsigned long expiry;
        s8 prior = rxrpc_ack_priority[ack_reason];
@@ -99,8 +99,7 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
        ASSERTCMP(prior, >, 0);
 
        _enter("{%d},%s,%%%x,%u",
-              call->debug_id, rxrpc_acks(ack_reason), ntohl(serial),
-              immediate);
+              call->debug_id, rxrpc_acks(ack_reason), serial, immediate);
 
        if (prior < rxrpc_ack_priority[call->ackr_reason]) {
                if (immediate)
@@ -139,7 +138,7 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
                expiry = rxrpc_requested_ack_delay;
                if (!expiry)
                        goto cancel_timer;
-               if (!immediate || serial == cpu_to_be32(1)) {
+               if (!immediate || serial == 1) {
                        _debug("run defer timer");
                        goto run_timer;
                }
@@ -157,11 +156,11 @@ run_timer:
        return;
 
 cancel_timer:
-       _debug("cancel timer %%%u", ntohl(serial));
+       _debug("cancel timer %%%u", serial);
        try_to_del_timer_sync(&call->ack_timer);
        read_lock_bh(&call->state_lock);
        if (call->state <= RXRPC_CALL_COMPLETE &&
-           !test_and_set_bit(RXRPC_CALL_ACK, &call->events))
+           !test_and_set_bit(RXRPC_CALL_EV_ACK, &call->events))
                rxrpc_queue_call(call);
        read_unlock_bh(&call->state_lock);
 }
@@ -170,7 +169,7 @@ cancel_timer:
  * propose an ACK be sent, locking the call structure
  */
 void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
-                      __be32 serial, bool immediate)
+                      u32 serial, bool immediate)
 {
        s8 prior = rxrpc_ack_priority[ack_reason];
 
@@ -193,7 +192,7 @@ static void rxrpc_set_resend(struct rxrpc_call *call, u8 resend,
 
        if (resend & 1) {
                _debug("SET RESEND");
-               set_bit(RXRPC_CALL_RESEND, &call->events);
+               set_bit(RXRPC_CALL_EV_RESEND, &call->events);
        }
 
        if (resend & 2) {
@@ -203,7 +202,7 @@ static void rxrpc_set_resend(struct rxrpc_call *call, u8 resend,
        } else {
                _debug("KILL RESEND TIMER");
                del_timer_sync(&call->resend_timer);
-               clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+               clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
                clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
        }
        read_unlock_bh(&call->state_lock);
@@ -214,8 +213,8 @@ static void rxrpc_set_resend(struct rxrpc_call *call, u8 resend,
  */
 static void rxrpc_resend(struct rxrpc_call *call)
 {
+       struct rxrpc_wire_header *whdr;
        struct rxrpc_skb_priv *sp;
-       struct rxrpc_header *hdr;
        struct sk_buff *txb;
        unsigned long *p_txb, resend_at;
        bool stop;
@@ -247,14 +246,13 @@ static void rxrpc_resend(struct rxrpc_call *call)
                        sp->need_resend = false;
 
                        /* each Tx packet has a new serial number */
-                       sp->hdr.serial =
-                               htonl(atomic_inc_return(&call->conn->serial));
+                       sp->hdr.serial = atomic_inc_return(&call->conn->serial);
 
-                       hdr = (struct rxrpc_header *) txb->head;
-                       hdr->serial = sp->hdr.serial;
+                       whdr = (struct rxrpc_wire_header *)txb->head;
+                       whdr->serial = htonl(sp->hdr.serial);
 
                        _proto("Tx DATA %%%u { #%d }",
-                              ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+                              sp->hdr.serial, sp->hdr.seq);
                        if (rxrpc_send_packet(call->conn->trans, txb) < 0) {
                                stop = true;
                                sp->resend_at = jiffies + 3;
@@ -428,7 +426,7 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard)
        int tail = call->acks_tail, old_tail;
        int win = CIRC_CNT(call->acks_head, tail, call->acks_winsz);
 
-       _enter("{%u,%u},%u", call->acks_hard, win, hard);
+       kenter("{%u,%u},%u", call->acks_hard, win, hard);
 
        ASSERTCMP(hard - call->acks_hard, <=, win);
 
@@ -478,11 +476,11 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
                sp = rxrpc_skb(skb);
 
                _debug("drain OOS packet %d [%d]",
-                      ntohl(sp->hdr.seq), call->rx_first_oos);
+                      sp->hdr.seq, call->rx_first_oos);
 
-               if (ntohl(sp->hdr.seq) != call->rx_first_oos) {
+               if (sp->hdr.seq != call->rx_first_oos) {
                        skb_queue_head(&call->rx_oos_queue, skb);
-                       call->rx_first_oos = ntohl(rxrpc_skb(skb)->hdr.seq);
+                       call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
                        _debug("requeue %p {%u}", skb, call->rx_first_oos);
                } else {
                        skb->mark = RXRPC_SKB_MARK_DATA;
@@ -496,8 +494,7 @@ static int rxrpc_drain_rx_oos_queue(struct rxrpc_call *call)
                        /* find out what the next packet is */
                        skb = skb_peek(&call->rx_oos_queue);
                        if (skb)
-                               call->rx_first_oos =
-                                       ntohl(rxrpc_skb(skb)->hdr.seq);
+                               call->rx_first_oos = rxrpc_skb(skb)->hdr.seq;
                        else
                                call->rx_first_oos = 0;
                        _debug("peek %p {%u}", skb, call->rx_first_oos);
@@ -522,7 +519,7 @@ static void rxrpc_insert_oos_packet(struct rxrpc_call *call,
        u32 seq;
 
        sp = rxrpc_skb(skb);
-       seq = ntohl(sp->hdr.seq);
+       seq = sp->hdr.seq;
        _enter(",,{%u}", seq);
 
        skb->destructor = rxrpc_packet_destructor;
@@ -535,9 +532,8 @@ static void rxrpc_insert_oos_packet(struct rxrpc_call *call,
 
        skb_queue_walk(&call->rx_oos_queue, p) {
                psp = rxrpc_skb(p);
-               if (ntohl(psp->hdr.seq) > seq) {
-                       _debug("insert oos #%u before #%u",
-                              seq, ntohl(psp->hdr.seq));
+               if (psp->hdr.seq > seq) {
+                       _debug("insert oos #%u before #%u", seq, psp->hdr.seq);
                        skb_insert(p, skb, &call->rx_oos_queue);
                        goto inserted;
                }
@@ -555,7 +551,7 @@ inserted:
        if (call->state < RXRPC_CALL_COMPLETE &&
            call->rx_data_post == call->rx_first_oos) {
                _debug("drain rx oos now");
-               set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events);
+               set_bit(RXRPC_CALL_EV_DRAIN_RX_OOS, &call->events);
        }
        read_unlock(&call->state_lock);
 
@@ -586,7 +582,7 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)
 
                skb = (struct sk_buff *) _skb;
                sp = rxrpc_skb(skb);
-               _debug("+++ clear Tx %u", ntohl(sp->hdr.seq));
+               _debug("+++ clear Tx %u", sp->hdr.seq);
                rxrpc_free_skb(skb);
        }
 
@@ -657,8 +653,7 @@ process_further:
                /* data packets that wind up here have been received out of
                 * order, need security processing or are jumbo packets */
        case RXRPC_PACKET_TYPE_DATA:
-               _proto("OOSQ DATA %%%u { #%u }",
-                      ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+               _proto("OOSQ DATA %%%u { #%u }", sp->hdr.serial, sp->hdr.seq);
 
                /* secured packets must be verified and possibly decrypted */
                if (rxrpc_verify_packet(call, skb, _abort_code) < 0)
@@ -676,7 +671,7 @@ process_further:
                if (!skb_pull(skb, sizeof(ack)))
                        BUG();
 
-               latest = ntohl(sp->hdr.serial);
+               latest = sp->hdr.serial;
                hard = ntohl(ack.firstPacket);
                tx = atomic_read(&call->sequence);
 
@@ -793,7 +788,7 @@ all_acked:
 
        del_timer_sync(&call->resend_timer);
        clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
-       clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
+       clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
 
        if (call->acks_window)
                rxrpc_zap_tx_window(call);
@@ -881,16 +876,17 @@ void rxrpc_process_call(struct work_struct *work)
 {
        struct rxrpc_call *call =
                container_of(work, struct rxrpc_call, processor);
+       struct rxrpc_wire_header whdr;
        struct rxrpc_ackpacket ack;
        struct rxrpc_ackinfo ackinfo;
-       struct rxrpc_header hdr;
        struct msghdr msg;
        struct kvec iov[5];
+       enum rxrpc_call_event genbit;
        unsigned long bits;
        __be32 data, pad;
        size_t len;
-       int genbit, loop, nbit, ioc, ret, mtu;
-       u32 abort_code = RX_PROTOCOL_ERROR;
+       int loop, nbit, ioc, ret, mtu;
+       u32 serial, abort_code = RX_PROTOCOL_ERROR;
        u8 *acks = NULL;
 
        //printk("\n--------------------\n");
@@ -911,33 +907,33 @@ void rxrpc_process_call(struct work_struct *work)
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr.epoch       = call->conn->epoch;
-       hdr.cid         = call->cid;
-       hdr.callNumber  = call->call_id;
-       hdr.seq         = 0;
-       hdr.type        = RXRPC_PACKET_TYPE_ACK;
-       hdr.flags       = call->conn->out_clientflag;
-       hdr.userStatus  = 0;
-       hdr.securityIndex = call->conn->security_ix;
-       hdr._rsvd       = 0;
-       hdr.serviceId   = call->conn->service_id;
+       whdr.epoch      = htonl(call->conn->epoch);
+       whdr.cid        = htonl(call->cid);
+       whdr.callNumber = htonl(call->call_id);
+       whdr.seq        = 0;
+       whdr.type       = RXRPC_PACKET_TYPE_ACK;
+       whdr.flags      = call->conn->out_clientflag;
+       whdr.userStatus = 0;
+       whdr.securityIndex = call->conn->security_ix;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(call->service_id);
 
        memset(iov, 0, sizeof(iov));
-       iov[0].iov_base = &hdr;
-       iov[0].iov_len  = sizeof(hdr);
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
 
        /* deal with events of a final nature */
-       if (test_bit(RXRPC_CALL_RELEASE, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_RELEASE, &call->events)) {
                rxrpc_release_call(call);
-               clear_bit(RXRPC_CALL_RELEASE, &call->events);
+               clear_bit(RXRPC_CALL_EV_RELEASE, &call->events);
        }
 
-       if (test_bit(RXRPC_CALL_RCVD_ERROR, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events)) {
                int error;
 
-               clear_bit(RXRPC_CALL_CONN_ABORT, &call->events);
-               clear_bit(RXRPC_CALL_REJECT_BUSY, &call->events);
-               clear_bit(RXRPC_CALL_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_CONN_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_REJECT_BUSY, &call->events);
+               clear_bit(RXRPC_CALL_EV_ABORT, &call->events);
 
                error = call->conn->trans->peer->net_error;
                _debug("post net error %d", error);
@@ -945,47 +941,47 @@ void rxrpc_process_call(struct work_struct *work)
                if (rxrpc_post_message(call, RXRPC_SKB_MARK_NET_ERROR,
                                       error, true) < 0)
                        goto no_mem;
-               clear_bit(RXRPC_CALL_RCVD_ERROR, &call->events);
+               clear_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events);
                goto kill_ACKs;
        }
 
-       if (test_bit(RXRPC_CALL_CONN_ABORT, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_CONN_ABORT, &call->events)) {
                ASSERTCMP(call->state, >, RXRPC_CALL_COMPLETE);
 
-               clear_bit(RXRPC_CALL_REJECT_BUSY, &call->events);
-               clear_bit(RXRPC_CALL_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_REJECT_BUSY, &call->events);
+               clear_bit(RXRPC_CALL_EV_ABORT, &call->events);
 
                _debug("post conn abort");
 
                if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
                                       call->conn->error, true) < 0)
                        goto no_mem;
-               clear_bit(RXRPC_CALL_CONN_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_CONN_ABORT, &call->events);
                goto kill_ACKs;
        }
 
-       if (test_bit(RXRPC_CALL_REJECT_BUSY, &call->events)) {
-               hdr.type = RXRPC_PACKET_TYPE_BUSY;
-               genbit = RXRPC_CALL_REJECT_BUSY;
+       if (test_bit(RXRPC_CALL_EV_REJECT_BUSY, &call->events)) {
+               whdr.type = RXRPC_PACKET_TYPE_BUSY;
+               genbit = RXRPC_CALL_EV_REJECT_BUSY;
                goto send_message;
        }
 
-       if (test_bit(RXRPC_CALL_ABORT, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_ABORT, &call->events)) {
                ASSERTCMP(call->state, >, RXRPC_CALL_COMPLETE);
 
                if (rxrpc_post_message(call, RXRPC_SKB_MARK_LOCAL_ERROR,
                                       ECONNABORTED, true) < 0)
                        goto no_mem;
-               hdr.type = RXRPC_PACKET_TYPE_ABORT;
+               whdr.type = RXRPC_PACKET_TYPE_ABORT;
                data = htonl(call->abort_code);
                iov[1].iov_base = &data;
                iov[1].iov_len = sizeof(data);
-               genbit = RXRPC_CALL_ABORT;
+               genbit = RXRPC_CALL_EV_ABORT;
                goto send_message;
        }
 
-       if (test_bit(RXRPC_CALL_ACK_FINAL, &call->events)) {
-               genbit = RXRPC_CALL_ACK_FINAL;
+       if (test_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events)) {
+               genbit = RXRPC_CALL_EV_ACK_FINAL;
 
                ack.bufferSpace = htons(8);
                ack.maxSkew     = 0;
@@ -995,9 +991,9 @@ void rxrpc_process_call(struct work_struct *work)
                call->ackr_reason = 0;
 
                spin_lock_bh(&call->lock);
-               ack.serial = call->ackr_serial;
-               ack.previousPacket = call->ackr_prev_seq;
-               ack.firstPacket = htonl(call->rx_data_eaten + 1);
+               ack.serial      = htonl(call->ackr_serial);
+               ack.previousPacket = htonl(call->ackr_prev_seq);
+               ack.firstPacket = htonl(call->rx_data_eaten + 1);
                spin_unlock_bh(&call->lock);
 
                pad = 0;
@@ -1011,12 +1007,12 @@ void rxrpc_process_call(struct work_struct *work)
                goto send_ACK;
        }
 
-       if (call->events & ((1 << RXRPC_CALL_RCVD_BUSY) |
-                           (1 << RXRPC_CALL_RCVD_ABORT))
+       if (call->events & ((1 << RXRPC_CALL_EV_RCVD_BUSY) |
+                           (1 << RXRPC_CALL_EV_RCVD_ABORT))
            ) {
                u32 mark;
 
-               if (test_bit(RXRPC_CALL_RCVD_ABORT, &call->events))
+               if (test_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events))
                        mark = RXRPC_SKB_MARK_REMOTE_ABORT;
                else
                        mark = RXRPC_SKB_MARK_BUSY;
@@ -1026,22 +1022,22 @@ void rxrpc_process_call(struct work_struct *work)
                if (rxrpc_post_message(call, mark, ECONNABORTED, true) < 0)
                        goto no_mem;
 
-               clear_bit(RXRPC_CALL_RCVD_BUSY, &call->events);
-               clear_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_RCVD_BUSY, &call->events);
+               clear_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events);
                goto kill_ACKs;
        }
 
-       if (test_and_clear_bit(RXRPC_CALL_RCVD_ACKALL, &call->events)) {
+       if (test_and_clear_bit(RXRPC_CALL_EV_RCVD_ACKALL, &call->events)) {
                _debug("do implicit ackall");
                rxrpc_clear_tx_window(call);
        }
 
-       if (test_bit(RXRPC_CALL_LIFE_TIMER, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events)) {
                write_lock_bh(&call->state_lock);
                if (call->state <= RXRPC_CALL_COMPLETE) {
                        call->state = RXRPC_CALL_LOCALLY_ABORTED;
                        call->abort_code = RX_CALL_TIMEOUT;
-                       set_bit(RXRPC_CALL_ABORT, &call->events);
+                       set_bit(RXRPC_CALL_EV_ABORT, &call->events);
                }
                write_unlock_bh(&call->state_lock);
 
@@ -1050,7 +1046,7 @@ void rxrpc_process_call(struct work_struct *work)
                                       ETIME, true) < 0)
                        goto no_mem;
 
-               clear_bit(RXRPC_CALL_LIFE_TIMER, &call->events);
+               clear_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events);
                goto kill_ACKs;
        }
 
@@ -1071,13 +1067,13 @@ void rxrpc_process_call(struct work_struct *work)
        }
 
        /* handle resending */
-       if (test_and_clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+       if (test_and_clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events))
                rxrpc_resend_timer(call);
-       if (test_and_clear_bit(RXRPC_CALL_RESEND, &call->events))
+       if (test_and_clear_bit(RXRPC_CALL_EV_RESEND, &call->events))
                rxrpc_resend(call);
 
        /* consider sending an ordinary ACK */
-       if (test_bit(RXRPC_CALL_ACK, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_ACK, &call->events)) {
                _debug("send ACK: window: %d - %d { %lx }",
                       call->rx_data_eaten, call->ackr_win_top,
                       call->ackr_window[0]);
@@ -1085,11 +1081,11 @@ void rxrpc_process_call(struct work_struct *work)
                if (call->state > RXRPC_CALL_SERVER_ACK_REQUEST &&
                    call->ackr_reason != RXRPC_ACK_PING_RESPONSE) {
                        /* ACK by sending reply DATA packet in this state */
-                       clear_bit(RXRPC_CALL_ACK, &call->events);
+                       clear_bit(RXRPC_CALL_EV_ACK, &call->events);
                        goto maybe_reschedule;
                }
 
-               genbit = RXRPC_CALL_ACK;
+               genbit = RXRPC_CALL_EV_ACK;
 
                acks = kzalloc(call->ackr_win_top - call->rx_data_eaten,
                               GFP_NOFS);
@@ -1099,13 +1095,11 @@ void rxrpc_process_call(struct work_struct *work)
                //hdr.flags     = RXRPC_SLOW_START_OK;
                ack.bufferSpace = htons(8);
                ack.maxSkew     = 0;
-               ack.serial      = 0;
-               ack.reason      = 0;
 
                spin_lock_bh(&call->lock);
-               ack.reason = call->ackr_reason;
-               ack.serial = call->ackr_serial;
-               ack.previousPacket = call->ackr_prev_seq;
+               ack.reason      = call->ackr_reason;
+               ack.serial      = htonl(call->ackr_serial);
+               ack.previousPacket = htonl(call->ackr_prev_seq);
                ack.firstPacket = htonl(call->rx_data_eaten + 1);
 
                ack.nAcks = 0;
@@ -1152,7 +1146,7 @@ void rxrpc_process_call(struct work_struct *work)
 
        /* handle completion of security negotiations on an incoming
         * connection */
-       if (test_and_clear_bit(RXRPC_CALL_SECURED, &call->events)) {
+       if (test_and_clear_bit(RXRPC_CALL_EV_SECURED, &call->events)) {
                _debug("secured");
                spin_lock_bh(&call->lock);
 
@@ -1160,7 +1154,7 @@ void rxrpc_process_call(struct work_struct *work)
                        _debug("securing");
                        write_lock(&call->conn->lock);
                        if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
-                           !test_bit(RXRPC_CALL_RELEASE, &call->events)) {
+                           !test_bit(RXRPC_CALL_EV_RELEASE, &call->events)) {
                                _debug("not released");
                                call->state = RXRPC_CALL_SERVER_ACCEPTING;
                                list_move_tail(&call->accept_link,
@@ -1169,39 +1163,39 @@ void rxrpc_process_call(struct work_struct *work)
                        write_unlock(&call->conn->lock);
                        read_lock(&call->state_lock);
                        if (call->state < RXRPC_CALL_COMPLETE)
-                               set_bit(RXRPC_CALL_POST_ACCEPT, &call->events);
+                               set_bit(RXRPC_CALL_EV_POST_ACCEPT, &call->events);
                        read_unlock(&call->state_lock);
                }
 
                spin_unlock_bh(&call->lock);
-               if (!test_bit(RXRPC_CALL_POST_ACCEPT, &call->events))
+               if (!test_bit(RXRPC_CALL_EV_POST_ACCEPT, &call->events))
                        goto maybe_reschedule;
        }
 
        /* post a notification of an acceptable connection to the app */
-       if (test_bit(RXRPC_CALL_POST_ACCEPT, &call->events)) {
+       if (test_bit(RXRPC_CALL_EV_POST_ACCEPT, &call->events)) {
                _debug("post accept");
                if (rxrpc_post_message(call, RXRPC_SKB_MARK_NEW_CALL,
                                       0, false) < 0)
                        goto no_mem;
-               clear_bit(RXRPC_CALL_POST_ACCEPT, &call->events);
+               clear_bit(RXRPC_CALL_EV_POST_ACCEPT, &call->events);
                goto maybe_reschedule;
        }
 
        /* handle incoming call acceptance */
-       if (test_and_clear_bit(RXRPC_CALL_ACCEPTED, &call->events)) {
+       if (test_and_clear_bit(RXRPC_CALL_EV_ACCEPTED, &call->events)) {
                _debug("accepted");
                ASSERTCMP(call->rx_data_post, ==, 0);
                call->rx_data_post = 1;
                read_lock_bh(&call->state_lock);
                if (call->state < RXRPC_CALL_COMPLETE)
-                       set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events);
+                       set_bit(RXRPC_CALL_EV_DRAIN_RX_OOS, &call->events);
                read_unlock_bh(&call->state_lock);
        }
 
        /* drain the out of sequence received packet queue into the packet Rx
         * queue */
-       if (test_and_clear_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events)) {
+       if (test_and_clear_bit(RXRPC_CALL_EV_DRAIN_RX_OOS, &call->events)) {
                while (call->rx_data_post == call->rx_first_oos)
                        if (rxrpc_drain_rx_oos_queue(call) < 0)
                                break;
@@ -1224,9 +1218,10 @@ send_ACK:
        ackinfo.rxMTU   = htonl(rxrpc_rx_mtu);
        ackinfo.jumbo_max = htonl(rxrpc_rx_jumbo_max);
 
-       hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
+       serial = atomic_inc_return(&call->conn->serial);
+       whdr.serial = htonl(serial);
        _proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
-              ntohl(hdr.serial),
+              serial,
               ntohs(ack.maxSkew),
               ntohl(ack.firstPacket),
               ntohl(ack.previousPacket),
@@ -1242,8 +1237,9 @@ send_ACK:
 send_message:
        _debug("send message");
 
-       hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
-       _proto("Tx %s %%%u", rxrpc_pkts[hdr.type], ntohl(hdr.serial));
+       serial = atomic_inc_return(&call->conn->serial);
+       whdr.serial = htonl(serial);
+       _proto("Tx %s %%%u", rxrpc_pkts[whdr.type], serial);
 send_message_2:
 
        len = iov[0].iov_len;
@@ -1280,12 +1276,12 @@ send_message_2:
        }
 
        switch (genbit) {
-       case RXRPC_CALL_ABORT:
+       case RXRPC_CALL_EV_ABORT:
                clear_bit(genbit, &call->events);
-               clear_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+               clear_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events);
                goto kill_ACKs;
 
-       case RXRPC_CALL_ACK_FINAL:
+       case RXRPC_CALL_EV_ACK_FINAL:
                write_lock_bh(&call->state_lock);
                if (call->state == RXRPC_CALL_CLIENT_FINAL_ACK)
                        call->state = RXRPC_CALL_COMPLETE;
@@ -1310,9 +1306,9 @@ send_message_2:
 
 kill_ACKs:
        del_timer_sync(&call->ack_timer);
-       if (test_and_clear_bit(RXRPC_CALL_ACK_FINAL, &call->events))
+       if (test_and_clear_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events))
                rxrpc_put_call(call);
-       clear_bit(RXRPC_CALL_ACK, &call->events);
+       clear_bit(RXRPC_CALL_EV_ACK, &call->events);
 
 maybe_reschedule:
        if (call->events || !skb_queue_empty(&call->rx_queue)) {
@@ -1326,12 +1322,11 @@ maybe_reschedule:
        if (call->state >= RXRPC_CALL_COMPLETE &&
            !list_empty(&call->accept_link)) {
                _debug("X unlinking once-pending call %p { e=%lx f=%lx c=%x }",
-                      call, call->events, call->flags,
-                      ntohl(call->conn->cid));
+                      call, call->events, call->flags, call->conn->cid);
 
                read_lock_bh(&call->state_lock);
                if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
-                   !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+                   !test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
                        rxrpc_queue_call(call);
                read_unlock_bh(&call->state_lock);
        }
@@ -1345,7 +1340,7 @@ error:
         * this means there's a race between clearing the flag and setting the
         * work pending bit and the work item being processed again */
        if (call->events && !work_pending(&call->processor)) {
-               _debug("jumpstart %x", ntohl(call->conn->cid));
+               _debug("jumpstart %x", call->conn->cid);
                rxrpc_queue_call(call);
        }
 
index a9e05db0f5d5900e93f87a8567e7533a1745c82a..7c8d300ade9bb32079b716b4fced72dce51f585b 100644 (file)
 /*
  * Maximum lifetime of a call (in jiffies).
  */
-unsigned rxrpc_max_call_lifetime = 60 * HZ;
+unsigned int rxrpc_max_call_lifetime = 60 * HZ;
 
 /*
  * Time till dead call expires after last use (in jiffies).
  */
-unsigned rxrpc_dead_call_expiry = 2 * HZ;
+unsigned int rxrpc_dead_call_expiry = 2 * HZ;
 
-const char *const rxrpc_call_states[] = {
+const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
        [RXRPC_CALL_CLIENT_SEND_REQUEST]        = "ClSndReq",
        [RXRPC_CALL_CLIENT_AWAIT_REPLY]         = "ClAwtRpl",
        [RXRPC_CALL_CLIENT_RECV_REPLY]          = "ClRcvRpl",
@@ -64,11 +64,11 @@ 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,
+       u8              in_clientflag,
+       u32             cid,
+       u32             call_id,
+       u32             epoch,
+       u16             service_id,
        sa_family_t     proto,
        void            *localptr,
        unsigned int    addr_size,
@@ -77,7 +77,6 @@ static unsigned long rxrpc_call_hashfunc(
        const u16 *p;
        unsigned int i;
        unsigned long key;
-       u32 hcid = ntohl(cid);
 
        _enter("");
 
@@ -85,12 +84,12 @@ static unsigned long rxrpc_call_hashfunc(
        /* 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 += epoch;
+       key += service_id;
+       key += call_id;
+       key += (cid & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT;
+       key += cid & RXRPC_CHANNELMASK;
+       key += in_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++)
@@ -148,19 +147,16 @@ static void rxrpc_call_hash_del(struct rxrpc_call *call)
  * isn't there.
  */
 struct rxrpc_call *rxrpc_find_call_hash(
-       u8              clientflag,
-       __be32          cid,
-       __be32          call_id,
-       __be32          epoch,
-       __be16          service_id,
+       struct rxrpc_host_header *hdr,
        void            *localptr,
        sa_family_t     proto,
-       const u8        *peer_addr)
+       const void      *peer_addr)
 {
        unsigned long key;
        unsigned int addr_size = 0;
        struct rxrpc_call *call = NULL;
        struct rxrpc_call *ret = NULL;
+       u8 in_clientflag = hdr->flags & RXRPC_CLIENT_INITIATED;
 
        _enter("");
        switch (proto) {
@@ -174,20 +170,21 @@ struct rxrpc_call *rxrpc_find_call_hash(
                break;
        }
 
-       key = rxrpc_call_hashfunc(clientflag, cid, call_id, epoch,
-                                 service_id, proto, localptr, addr_size,
+       key = rxrpc_call_hashfunc(in_clientflag, hdr->cid, hdr->callNumber,
+                                 hdr->epoch, hdr->serviceId,
+                                 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->call_id == hdr->callNumber &&
+                   call->cid == hdr->cid &&
+                   call->in_clientflag == in_clientflag &&
+                   call->service_id == hdr->serviceId &&
                    call->proto == proto &&
                    call->local == localptr &&
                    memcmp(call->peer_ip.ipv6_addr, peer_addr,
-                             addr_size) == 0 &&
-                   call->epoch == epoch) {
+                          addr_size) == 0 &&
+                   call->epoch == hdr->epoch) {
                        ret = call;
                        break;
                }
@@ -414,12 +411,12 @@ found_extant_second:
  */
 struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
                                       struct rxrpc_connection *conn,
-                                      struct rxrpc_header *hdr,
+                                      struct rxrpc_host_header *hdr,
                                       gfp_t gfp)
 {
        struct rxrpc_call *call, *candidate;
        struct rb_node **p, *parent;
-       __be32 call_id;
+       u32 call_id;
 
        _enter(",%d,,%x", conn->debug_id, gfp);
 
@@ -433,7 +430,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
        candidate->conn = conn;
        candidate->cid = hdr->cid;
        candidate->call_id = hdr->callNumber;
-       candidate->channel = ntohl(hdr->cid) & RXRPC_CHANNELMASK;
+       candidate->channel = hdr->cid & RXRPC_CHANNELMASK;
        candidate->rx_data_post = 0;
        candidate->state = RXRPC_CALL_SERVER_ACCEPTING;
        if (conn->security_ix > 0)
@@ -452,7 +449,7 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
                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_EV_ABORT, &call->events))
                                rxrpc_queue_call(call);
                case RXRPC_CALL_REMOTELY_ABORTED:
                        read_unlock(&call->state_lock);
@@ -492,9 +489,9 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
                /* 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)
+               if (call_id < call->call_id)
                        p = &(*p)->rb_left;
-               else if ((__force u32)call_id > (__force u32)call->call_id)
+               else if (call_id > call->call_id)
                        p = &(*p)->rb_right;
                else
                        goto old_call;
@@ -686,7 +683,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
                _debug("+++ ABORTING STATE %d +++\n", call->state);
                call->state = RXRPC_CALL_LOCALLY_ABORTED;
                call->abort_code = RX_CALL_DEAD;
-               set_bit(RXRPC_CALL_ABORT, &call->events);
+               set_bit(RXRPC_CALL_EV_ABORT, &call->events);
                rxrpc_queue_call(call);
        }
        write_unlock(&call->state_lock);
@@ -714,8 +711,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
 
                        _debug("- zap %s %%%u #%u",
                               rxrpc_pkts[sp->hdr.type],
-                              ntohl(sp->hdr.serial),
-                              ntohl(sp->hdr.seq));
+                              sp->hdr.serial, sp->hdr.seq);
                        rxrpc_free_skb(skb);
                        spin_lock_bh(&call->lock);
                }
@@ -763,10 +759,10 @@ static void rxrpc_mark_call_released(struct rxrpc_call *call)
                        _debug("abort call %p", call);
                        call->state = RXRPC_CALL_LOCALLY_ABORTED;
                        call->abort_code = RX_CALL_DEAD;
-                       if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+                       if (!test_and_set_bit(RXRPC_CALL_EV_ABORT, &call->events))
                                sched = true;
                }
-               if (!test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+               if (!test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
                        sched = true;
                if (sched)
                        rxrpc_queue_call(call);
@@ -873,9 +869,9 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call)
                        unsigned long _skb;
 
                        _skb = call->acks_window[call->acks_tail] & ~1;
-                       sp = rxrpc_skb((struct sk_buff *) _skb);
-                       _debug("+++ clear Tx %u", ntohl(sp->hdr.seq));
-                       rxrpc_free_skb((struct sk_buff *) _skb);
+                       sp = rxrpc_skb((struct sk_buff *)_skb);
+                       _debug("+++ clear Tx %u", sp->hdr.seq);
+                       rxrpc_free_skb((struct sk_buff *)_skb);
                        call->acks_tail =
                                (call->acks_tail + 1) & (call->acks_winsz - 1);
                }
@@ -975,7 +971,7 @@ static void rxrpc_call_life_expired(unsigned long _call)
        _enter("{%d}", call->debug_id);
        read_lock_bh(&call->state_lock);
        if (call->state < RXRPC_CALL_COMPLETE) {
-               set_bit(RXRPC_CALL_LIFE_TIMER, &call->events);
+               set_bit(RXRPC_CALL_EV_LIFE_TIMER, &call->events);
                rxrpc_queue_call(call);
        }
        read_unlock_bh(&call->state_lock);
@@ -995,7 +991,7 @@ static void rxrpc_resend_time_expired(unsigned long _call)
                return;
 
        clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
-       if (!test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+       if (!test_and_set_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events))
                rxrpc_queue_call(call);
 }
 
@@ -1013,7 +1009,7 @@ static void rxrpc_ack_time_expired(unsigned long _call)
 
        read_lock_bh(&call->state_lock);
        if (call->state < RXRPC_CALL_COMPLETE &&
-           !test_and_set_bit(RXRPC_CALL_ACK, &call->events))
+           !test_and_set_bit(RXRPC_CALL_EV_ACK, &call->events))
                rxrpc_queue_call(call);
        read_unlock_bh(&call->state_lock);
 }
index 6c71ed1caf16727a587c90ff81dcd6a7abd3d10b..9942da1edbf6c00a4f5acee07de7c0c92069f121 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * Time till a connection expires after last use (in seconds).
  */
-unsigned rxrpc_connection_expiry = 10 * 60;
+unsigned int rxrpc_connection_expiry = 10 * 60;
 
 static void rxrpc_connection_reaper(struct work_struct *work);
 
@@ -57,10 +57,10 @@ static struct rxrpc_conn_bundle *rxrpc_alloc_bundle(gfp_t gfp)
  */
 static inline
 int rxrpc_cmp_bundle(const struct rxrpc_conn_bundle *bundle,
-                    struct key *key, __be16 service_id)
+                    struct key *key, u16 service_id)
 {
        return (bundle->service_id - service_id) ?:
-               ((unsigned long) bundle->key - (unsigned long) key);
+               ((unsigned long)bundle->key - (unsigned long)key);
 }
 
 /*
@@ -69,14 +69,14 @@ int rxrpc_cmp_bundle(const struct rxrpc_conn_bundle *bundle,
 struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *rx,
                                           struct rxrpc_transport *trans,
                                           struct key *key,
-                                          __be16 service_id,
+                                          u16 service_id,
                                           gfp_t gfp)
 {
        struct rxrpc_conn_bundle *bundle, *candidate;
        struct rb_node *p, *parent, **pp;
 
        _enter("%p{%x},%x,%hx,",
-              rx, key_serial(key), trans->debug_id, ntohs(service_id));
+              rx, key_serial(key), trans->debug_id, service_id);
 
        if (rx->trans == trans && rx->bundle) {
                atomic_inc(&rx->bundle->usage);
@@ -213,7 +213,7 @@ static struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
                conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
                conn->avail_calls = RXRPC_MAXCALLS;
                conn->size_align = 4;
-               conn->header_size = sizeof(struct rxrpc_header);
+               conn->header_size = sizeof(struct rxrpc_wire_header);
        }
 
        _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0);
@@ -230,7 +230,7 @@ static void rxrpc_assign_connection_id(struct rxrpc_connection *conn)
        struct rxrpc_connection *xconn;
        struct rb_node *parent, **p;
        __be32 epoch;
-       u32 real_conn_id;
+       u32 cid;
 
        _enter("");
 
@@ -241,7 +241,7 @@ static void rxrpc_assign_connection_id(struct rxrpc_connection *conn)
        conn->trans->conn_idcounter += RXRPC_CID_INC;
        if (conn->trans->conn_idcounter < RXRPC_CID_INC)
                conn->trans->conn_idcounter = RXRPC_CID_INC;
-       real_conn_id = conn->trans->conn_idcounter;
+       cid = conn->trans->conn_idcounter;
 
 attempt_insertion:
        parent = NULL;
@@ -255,9 +255,9 @@ attempt_insertion:
                        p = &(*p)->rb_left;
                else if (epoch > xconn->epoch)
                        p = &(*p)->rb_right;
-               else if (real_conn_id < xconn->real_conn_id)
+               else if (cid < xconn->cid)
                        p = &(*p)->rb_left;
-               else if (real_conn_id > xconn->real_conn_id)
+               else if (cid > xconn->cid)
                        p = &(*p)->rb_right;
                else
                        goto id_exists;
@@ -268,20 +268,19 @@ attempt_insertion:
        rb_link_node(&conn->node, parent, p);
        rb_insert_color(&conn->node, &conn->trans->client_conns);
 
-       conn->real_conn_id = real_conn_id;
-       conn->cid = htonl(real_conn_id);
+       conn->cid = cid;
        write_unlock_bh(&conn->trans->conn_lock);
-       _leave(" [CONNID %x CID %x]", real_conn_id, ntohl(conn->cid));
+       _leave(" [CID %x]", cid);
        return;
 
        /* we found a connection with the proposed ID - walk the tree from that
         * point looking for the next unused ID */
 id_exists:
        for (;;) {
-               real_conn_id += RXRPC_CID_INC;
-               if (real_conn_id < RXRPC_CID_INC) {
-                       real_conn_id = RXRPC_CID_INC;
-                       conn->trans->conn_idcounter = real_conn_id;
+               cid += RXRPC_CID_INC;
+               if (cid < RXRPC_CID_INC) {
+                       cid = RXRPC_CID_INC;
+                       conn->trans->conn_idcounter = cid;
                        goto attempt_insertion;
                }
 
@@ -291,7 +290,7 @@ id_exists:
 
                xconn = rb_entry(parent, struct rxrpc_connection, node);
                if (epoch < xconn->epoch ||
-                   real_conn_id < xconn->real_conn_id)
+                   cid < xconn->cid)
                        goto attempt_insertion;
        }
 }
@@ -334,7 +333,7 @@ static void rxrpc_add_call_ID_to_conn(struct rxrpc_connection *conn,
  */
 static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,
                                   struct rxrpc_transport *trans,
-                                  __be16 service_id,
+                                  u16 service_id,
                                   struct rxrpc_call *call,
                                   gfp_t gfp)
 {
@@ -404,11 +403,11 @@ found_channel:
        conn->channels[chan] = call;
        call->conn = conn;
        call->channel = chan;
-       call->cid = conn->cid | htonl(chan);
-       call->call_id = htonl(++conn->call_counter);
+       call->cid = conn->cid | chan;
+       call->call_id = ++conn->call_counter;
 
        _net("CONNECT client on conn %d chan %d as call %x",
-            conn->debug_id, chan, ntohl(call->call_id));
+            conn->debug_id, chan, call->call_id);
 
        spin_unlock(&trans->client_lock);
 
@@ -593,11 +592,11 @@ found_channel:
        conn->channels[chan] = call;
        call->conn = conn;
        call->channel = chan;
-       call->cid = conn->cid | htonl(chan);
-       call->call_id = htonl(++conn->call_counter);
+       call->cid = conn->cid | chan;
+       call->call_id = ++conn->call_counter;
 
        _net("CONNECT client on conn %d chan %d as call %x",
-            conn->debug_id, chan, ntohl(call->call_id));
+            conn->debug_id, chan, call->call_id);
 
        ASSERTCMP(conn->avail_calls, <, RXRPC_MAXCALLS);
        spin_unlock(&trans->client_lock);
@@ -620,21 +619,21 @@ interrupted:
  */
 struct rxrpc_connection *
 rxrpc_incoming_connection(struct rxrpc_transport *trans,
-                         struct rxrpc_header *hdr,
+                         struct rxrpc_host_header *hdr,
                          gfp_t gfp)
 {
        struct rxrpc_connection *conn, *candidate = NULL;
        struct rb_node *p, **pp;
        const char *new = "old";
        __be32 epoch;
-       u32 conn_id;
+       u32 cid;
 
        _enter("");
 
        ASSERT(hdr->flags & RXRPC_CLIENT_INITIATED);
 
        epoch = hdr->epoch;
-       conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
+       cid = hdr->cid & RXRPC_CIDMASK;
 
        /* search the connection list first */
        read_lock_bh(&trans->conn_lock);
@@ -643,15 +642,15 @@ rxrpc_incoming_connection(struct rxrpc_transport *trans,
        while (p) {
                conn = rb_entry(p, struct rxrpc_connection, node);
 
-               _debug("maybe %x", conn->real_conn_id);
+               _debug("maybe %x", conn->cid);
 
                if (epoch < conn->epoch)
                        p = p->rb_left;
                else if (epoch > conn->epoch)
                        p = p->rb_right;
-               else if (conn_id < conn->real_conn_id)
+               else if (cid < conn->cid)
                        p = p->rb_left;
-               else if (conn_id > conn->real_conn_id)
+               else if (cid > conn->cid)
                        p = p->rb_right;
                else
                        goto found_extant_connection;
@@ -668,12 +667,11 @@ rxrpc_incoming_connection(struct rxrpc_transport *trans,
 
        candidate->trans = trans;
        candidate->epoch = hdr->epoch;
-       candidate->cid = hdr->cid & cpu_to_be32(RXRPC_CIDMASK);
+       candidate->cid = hdr->cid & RXRPC_CIDMASK;
        candidate->service_id = hdr->serviceId;
        candidate->security_ix = hdr->securityIndex;
        candidate->in_clientflag = RXRPC_CLIENT_INITIATED;
        candidate->out_clientflag = 0;
-       candidate->real_conn_id = conn_id;
        candidate->state = RXRPC_CONN_SERVER;
        if (candidate->service_id)
                candidate->state = RXRPC_CONN_SERVER_UNSECURED;
@@ -690,9 +688,9 @@ rxrpc_incoming_connection(struct rxrpc_transport *trans,
                        pp = &(*pp)->rb_left;
                else if (epoch > conn->epoch)
                        pp = &(*pp)->rb_right;
-               else if (conn_id < conn->real_conn_id)
+               else if (cid < conn->cid)
                        pp = &(*pp)->rb_left;
-               else if (conn_id > conn->real_conn_id)
+               else if (cid > conn->cid)
                        pp = &(*pp)->rb_right;
                else
                        goto found_extant_second;
@@ -714,7 +712,7 @@ rxrpc_incoming_connection(struct rxrpc_transport *trans,
        new = "new";
 
 success:
-       _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->real_conn_id);
+       _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->cid);
 
        _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
        return conn;
@@ -751,18 +749,17 @@ security_mismatch:
  * packet
  */
 struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *trans,
-                                              struct rxrpc_header *hdr)
+                                              struct rxrpc_host_header *hdr)
 {
        struct rxrpc_connection *conn;
        struct rb_node *p;
-       __be32 epoch;
-       u32 conn_id;
+       u32 epoch, cid;
 
-       _enter(",{%x,%x}", ntohl(hdr->cid), hdr->flags);
+       _enter(",{%x,%x}", hdr->cid, hdr->flags);
 
        read_lock_bh(&trans->conn_lock);
 
-       conn_id = ntohl(hdr->cid) & RXRPC_CIDMASK;
+       cid = hdr->cid & RXRPC_CIDMASK;
        epoch = hdr->epoch;
 
        if (hdr->flags & RXRPC_CLIENT_INITIATED)
@@ -773,15 +770,15 @@ struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *trans,
        while (p) {
                conn = rb_entry(p, struct rxrpc_connection, node);
 
-               _debug("maybe %x", conn->real_conn_id);
+               _debug("maybe %x", conn->cid);
 
                if (epoch < conn->epoch)
                        p = p->rb_left;
                else if (epoch > conn->epoch)
                        p = p->rb_right;
-               else if (conn_id < conn->real_conn_id)
+               else if (cid < conn->cid)
                        p = p->rb_left;
-               else if (conn_id > conn->real_conn_id)
+               else if (cid > conn->cid)
                        p = p->rb_right;
                else
                        goto found;
index e7ed43a54c41f4e60461af753a68407dfb153bd6..1bdaaed8cdc456c419a9da5ce95412d1853ef06c 100644 (file)
@@ -42,9 +42,9 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state,
                        call->state = state;
                        call->abort_code = abort_code;
                        if (state == RXRPC_CALL_LOCALLY_ABORTED)
-                               set_bit(RXRPC_CALL_CONN_ABORT, &call->events);
+                               set_bit(RXRPC_CALL_EV_CONN_ABORT, &call->events);
                        else
-                               set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+                               set_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events);
                        rxrpc_queue_call(call);
                }
                write_unlock(&call->state_lock);
@@ -60,11 +60,12 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state,
 static int rxrpc_abort_connection(struct rxrpc_connection *conn,
                                  u32 error, u32 abort_code)
 {
-       struct rxrpc_header hdr;
+       struct rxrpc_wire_header whdr;
        struct msghdr msg;
        struct kvec iov[2];
        __be32 word;
        size_t len;
+       u32 serial;
        int ret;
 
        _enter("%d,,%u,%u", conn->debug_id, error, abort_code);
@@ -89,28 +90,29 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr.epoch       = conn->epoch;
-       hdr.cid         = conn->cid;
-       hdr.callNumber  = 0;
-       hdr.seq         = 0;
-       hdr.type        = RXRPC_PACKET_TYPE_ABORT;
-       hdr.flags       = conn->out_clientflag;
-       hdr.userStatus  = 0;
-       hdr.securityIndex = conn->security_ix;
-       hdr._rsvd       = 0;
-       hdr.serviceId   = conn->service_id;
+       whdr.epoch      = htonl(conn->epoch);
+       whdr.cid        = htonl(conn->cid);
+       whdr.callNumber = 0;
+       whdr.seq        = 0;
+       whdr.type       = RXRPC_PACKET_TYPE_ABORT;
+       whdr.flags      = conn->out_clientflag;
+       whdr.userStatus = 0;
+       whdr.securityIndex = conn->security_ix;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(conn->service_id);
 
        word = htonl(abort_code);
 
-       iov[0].iov_base = &hdr;
-       iov[0].iov_len  = sizeof(hdr);
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
        iov[1].iov_base = &word;
        iov[1].iov_len  = sizeof(word);
 
        len = iov[0].iov_len + iov[1].iov_len;
 
-       hdr.serial = htonl(atomic_inc_return(&conn->serial));
-       _proto("Tx CONN ABORT %%%u { %d }", ntohl(hdr.serial), abort_code);
+       serial = atomic_inc_return(&conn->serial);
+       whdr.serial = htonl(serial);
+       _proto("Tx CONN ABORT %%%u { %d }", serial, abort_code);
 
        ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 2, len);
        if (ret < 0) {
@@ -132,7 +134,7 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
        if (call) {
                read_lock(&call->state_lock);
                if (call->state < RXRPC_CALL_COMPLETE &&
-                   !test_and_set_bit(RXRPC_CALL_SECURED, &call->events))
+                   !test_and_set_bit(RXRPC_CALL_EV_SECURED, &call->events))
                        rxrpc_queue_call(call);
                read_unlock(&call->state_lock);
        }
@@ -146,8 +148,8 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                               u32 *_abort_code)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       __be32 tmp;
-       u32 serial;
+       __be32 wtmp;
+       u32 abort_code;
        int loop, ret;
 
        if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
@@ -155,19 +157,18 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                return -ECONNABORTED;
        }
 
-       serial = ntohl(sp->hdr.serial);
-
-       _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, serial);
+       _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, sp->hdr.serial);
 
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_ABORT:
-               if (skb_copy_bits(skb, 0, &tmp, sizeof(tmp)) < 0)
+               if (skb_copy_bits(skb, 0, &wtmp, sizeof(wtmp)) < 0)
                        return -EPROTO;
-               _proto("Rx ABORT %%%u { ac=%d }", serial, ntohl(tmp));
+               abort_code = ntohl(wtmp);
+               _proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);
 
                conn->state = RXRPC_CONN_REMOTELY_ABORTED;
                rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
-                                 ntohl(tmp));
+                                 abort_code);
                return -ECONNABORTED;
 
        case RXRPC_PACKET_TYPE_CHALLENGE:
@@ -335,7 +336,7 @@ void rxrpc_reject_packets(struct work_struct *work)
                struct sockaddr_in sin;
        } sa;
        struct rxrpc_skb_priv *sp;
-       struct rxrpc_header hdr;
+       struct rxrpc_wire_header whdr;
        struct rxrpc_local *local;
        struct sk_buff *skb;
        struct msghdr msg;
@@ -348,11 +349,11 @@ void rxrpc_reject_packets(struct work_struct *work)
 
        _enter("%d", local->debug_id);
 
-       iov[0].iov_base = &hdr;
-       iov[0].iov_len = sizeof(hdr);
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len = sizeof(whdr);
        iov[1].iov_base = &code;
        iov[1].iov_len = sizeof(code);
-       size = sizeof(hdr) + sizeof(code);
+       size = sizeof(whdr) + sizeof(code);
 
        msg.msg_name = &sa;
        msg.msg_control = NULL;
@@ -370,8 +371,8 @@ void rxrpc_reject_packets(struct work_struct *work)
                break;
        }
 
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.type = RXRPC_PACKET_TYPE_ABORT;
+       memset(&whdr, 0, sizeof(whdr));
+       whdr.type = RXRPC_PACKET_TYPE_ABORT;
 
        while ((skb = skb_dequeue(&local->reject_queue))) {
                sp = rxrpc_skb(skb);
@@ -381,13 +382,13 @@ void rxrpc_reject_packets(struct work_struct *work)
                        sa.sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
                        code = htonl(skb->priority);
 
-                       hdr.epoch = sp->hdr.epoch;
-                       hdr.cid = sp->hdr.cid;
-                       hdr.callNumber = sp->hdr.callNumber;
-                       hdr.serviceId = sp->hdr.serviceId;
-                       hdr.flags = sp->hdr.flags;
-                       hdr.flags ^= RXRPC_CLIENT_INITIATED;
-                       hdr.flags &= RXRPC_CLIENT_INITIATED;
+                       whdr.epoch      = htonl(sp->hdr.epoch);
+                       whdr.cid        = htonl(sp->hdr.cid);
+                       whdr.callNumber = htonl(sp->hdr.callNumber);
+                       whdr.serviceId  = htons(sp->hdr.serviceId);
+                       whdr.flags      = sp->hdr.flags;
+                       whdr.flags      ^= RXRPC_CLIENT_INITIATED;
+                       whdr.flags      &= RXRPC_CLIENT_INITIATED;
 
                        kernel_sendmsg(local->socket, &msg, iov, 2, size);
                        break;
index 0610efa83d721389fc0f2c3597f3e284fee341d7..3e82d6f0313c49563ecd10854985f84f676567f4 100644 (file)
@@ -115,7 +115,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
        /* pass the transport ref to error_handler to release */
        skb_queue_tail(&trans->error_queue, skb);
        rxrpc_queue_work(&trans->error_handler);
-
        _leave("");
 }
 
@@ -152,28 +151,18 @@ void rxrpc_UDP_error_handler(struct work_struct *work)
                        switch (ee->ee_code) {
                        case ICMP_NET_UNREACH:
                                _net("Rx Received ICMP Network Unreachable");
-                               err = ENETUNREACH;
                                break;
                        case ICMP_HOST_UNREACH:
                                _net("Rx Received ICMP Host Unreachable");
-                               err = EHOSTUNREACH;
                                break;
                        case ICMP_PORT_UNREACH:
                                _net("Rx Received ICMP Port Unreachable");
-                               err = ECONNREFUSED;
-                               break;
-                       case ICMP_FRAG_NEEDED:
-                               _net("Rx Received ICMP Fragmentation Needed (%d)",
-                                    ee->ee_info);
-                               err = 0; /* dealt with elsewhere */
                                break;
                        case ICMP_NET_UNKNOWN:
                                _net("Rx Received ICMP Unknown Network");
-                               err = ENETUNREACH;
                                break;
                        case ICMP_HOST_UNKNOWN:
                                _net("Rx Received ICMP Unknown Host");
-                               err = EHOSTUNREACH;
                                break;
                        default:
                                _net("Rx Received ICMP DestUnreach code=%u",
@@ -222,7 +211,7 @@ void rxrpc_UDP_error_handler(struct work_struct *work)
                        if (call->state != RXRPC_CALL_COMPLETE &&
                            call->state < RXRPC_CALL_NETWORK_ERROR) {
                                call->state = RXRPC_CALL_NETWORK_ERROR;
-                               set_bit(RXRPC_CALL_RCVD_ERROR, &call->events);
+                               set_bit(RXRPC_CALL_EV_RCVD_ERROR, &call->events);
                                rxrpc_queue_call(call);
                        }
                        write_unlock(&call->state_lock);
index 4505a691d88c283bbbd8038c2dd088825015bd32..63ed75c40e29a1739470f90e21d5f60d1bab8fe1 100644 (file)
@@ -231,7 +231,7 @@ static int rxrpc_fast_process_data(struct rxrpc_call *call,
                _debug("drain rx oos now");
                read_lock(&call->state_lock);
                if (call->state < RXRPC_CALL_COMPLETE &&
-                   !test_and_set_bit(RXRPC_CALL_DRAIN_RX_OOS, &call->events))
+                   !test_and_set_bit(RXRPC_CALL_EV_DRAIN_RX_OOS, &call->events))
                        rxrpc_queue_call(call);
                read_unlock(&call->state_lock);
        }
@@ -287,12 +287,12 @@ static void rxrpc_assume_implicit_ackall(struct rxrpc_call *call, u32 serial)
                call->acks_latest = serial;
 
                _debug("implicit ACKALL %%%u", call->acks_latest);
-               set_bit(RXRPC_CALL_RCVD_ACKALL, &call->events);
+               set_bit(RXRPC_CALL_EV_RCVD_ACKALL, &call->events);
                write_unlock_bh(&call->state_lock);
 
                if (try_to_del_timer_sync(&call->resend_timer) >= 0) {
-                       clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
-                       clear_bit(RXRPC_CALL_RESEND, &call->events);
+                       clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
+                       clear_bit(RXRPC_CALL_EV_RESEND, &call->events);
                        clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
                }
                break;
@@ -310,8 +310,8 @@ static void rxrpc_assume_implicit_ackall(struct rxrpc_call *call, u32 serial)
 void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
-       __be32 _abort_code;
-       u32 serial, hi_serial, seq, abort_code;
+       __be32 wtmp;
+       u32 hi_serial, abort_code;
 
        _enter("%p,%p", call, skb);
 
@@ -330,16 +330,15 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
 
        /* track the latest serial number on this connection for ACK packet
         * information */
-       serial = ntohl(sp->hdr.serial);
        hi_serial = atomic_read(&call->conn->hi_serial);
-       while (serial > hi_serial)
+       while (sp->hdr.serial > hi_serial)
                hi_serial = atomic_cmpxchg(&call->conn->hi_serial, hi_serial,
-                                          serial);
+                                          sp->hdr.serial);
 
        /* request ACK generation for any ACK or DATA packet that requests
         * it */
        if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
-               _proto("ACK Requested on %%%u", serial);
+               _proto("ACK Requested on %%%u", sp->hdr.serial);
                rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, false);
        }
 
@@ -347,24 +346,23 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
        case RXRPC_PACKET_TYPE_ABORT:
                _debug("abort");
 
-               if (skb_copy_bits(skb, 0, &_abort_code,
-                                 sizeof(_abort_code)) < 0)
+               if (skb_copy_bits(skb, 0, &wtmp, sizeof(wtmp)) < 0)
                        goto protocol_error;
 
-               abort_code = ntohl(_abort_code);
-               _proto("Rx ABORT %%%u { %x }", serial, abort_code);
+               abort_code = ntohl(wtmp);
+               _proto("Rx ABORT %%%u { %x }", sp->hdr.serial, abort_code);
 
                write_lock_bh(&call->state_lock);
                if (call->state < RXRPC_CALL_COMPLETE) {
                        call->state = RXRPC_CALL_REMOTELY_ABORTED;
                        call->abort_code = abort_code;
-                       set_bit(RXRPC_CALL_RCVD_ABORT, &call->events);
+                       set_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events);
                        rxrpc_queue_call(call);
                }
                goto free_packet_unlock;
 
        case RXRPC_PACKET_TYPE_BUSY:
-               _proto("Rx BUSY %%%u", serial);
+               _proto("Rx BUSY %%%u", sp->hdr.serial);
 
                if (call->conn->out_clientflag)
                        goto protocol_error;
@@ -373,7 +371,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
                switch (call->state) {
                case RXRPC_CALL_CLIENT_SEND_REQUEST:
                        call->state = RXRPC_CALL_SERVER_BUSY;
-                       set_bit(RXRPC_CALL_RCVD_BUSY, &call->events);
+                       set_bit(RXRPC_CALL_EV_RCVD_BUSY, &call->events);
                        rxrpc_queue_call(call);
                case RXRPC_CALL_SERVER_BUSY:
                        goto free_packet_unlock;
@@ -382,15 +380,13 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
                }
 
        default:
-               _proto("Rx %s %%%u", rxrpc_pkts[sp->hdr.type], serial);
+               _proto("Rx %s %%%u", rxrpc_pkts[sp->hdr.type], sp->hdr.serial);
                goto protocol_error;
 
        case RXRPC_PACKET_TYPE_DATA:
-               seq = ntohl(sp->hdr.seq);
+               _proto("Rx DATA %%%u { #%u }", sp->hdr.serial, sp->hdr.seq);
 
-               _proto("Rx DATA %%%u { #%u }", serial, seq);
-
-               if (seq == 0)
+               if (sp->hdr.seq == 0)
                        goto protocol_error;
 
                call->ackr_prev_seq = sp->hdr.seq;
@@ -398,9 +394,9 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
                /* received data implicitly ACKs all of the request packets we
                 * sent when we're acting as a client */
                if (call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY)
-                       rxrpc_assume_implicit_ackall(call, serial);
+                       rxrpc_assume_implicit_ackall(call, sp->hdr.serial);
 
-               switch (rxrpc_fast_process_data(call, skb, seq)) {
+               switch (rxrpc_fast_process_data(call, skb, sp->hdr.seq)) {
                case 0:
                        skb = NULL;
                        goto done;
@@ -433,7 +429,7 @@ protocol_error_locked:
        if (call->state <= RXRPC_CALL_COMPLETE) {
                call->state = RXRPC_CALL_LOCALLY_ABORTED;
                call->abort_code = RX_PROTOCOL_ERROR;
-               set_bit(RXRPC_CALL_ABORT, &call->events);
+               set_bit(RXRPC_CALL_EV_ABORT, &call->events);
                rxrpc_queue_call(call);
        }
 free_packet_unlock:
@@ -481,12 +477,12 @@ static void rxrpc_process_jumbo_packet(struct rxrpc_call *call,
                if (!pskb_pull(jumbo, sizeof(jhdr)))
                        BUG();
 
-               sp->hdr.seq     = htonl(ntohl(sp->hdr.seq) + 1);
-               sp->hdr.serial  = htonl(ntohl(sp->hdr.serial) + 1);
+               sp->hdr.seq     += 1;
+               sp->hdr.serial  += 1;
                sp->hdr.flags   = jhdr.flags;
                sp->hdr._rsvd   = jhdr._rsvd;
 
-               _proto("Rx DATA Jumbo %%%u", ntohl(sp->hdr.serial) - 1);
+               _proto("Rx DATA Jumbo %%%u", sp->hdr.serial - 1);
 
                rxrpc_fast_process_packet(call, part);
                part = NULL;
@@ -505,7 +501,7 @@ protocol_error:
        if (call->state <= RXRPC_CALL_COMPLETE) {
                call->state = RXRPC_CALL_LOCALLY_ABORTED;
                call->abort_code = RX_PROTOCOL_ERROR;
-               set_bit(RXRPC_CALL_ABORT, &call->events);
+               set_bit(RXRPC_CALL_EV_ABORT, &call->events);
                rxrpc_queue_call(call);
        }
        write_unlock_bh(&call->state_lock);
@@ -530,7 +526,7 @@ static void rxrpc_post_packet_to_call(struct rxrpc_call *call,
        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_EV_ABORT, &call->events)) {
                        rxrpc_queue_call(call);
                        goto free_unlock;
                }
@@ -546,7 +542,7 @@ static void rxrpc_post_packet_to_call(struct rxrpc_call *call,
                /* resend last packet of a completed call */
                _debug("final ack again");
                rxrpc_get_call(call);
-               set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+               set_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events);
                rxrpc_queue_call(call);
                goto free_unlock;
        default:
@@ -607,6 +603,35 @@ static void rxrpc_post_packet_to_local(struct rxrpc_local *local,
        rxrpc_queue_work(&local->event_processor);
 }
 
+/*
+ * Extract the wire header from a packet and translate the byte order.
+ */
+static noinline
+int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
+{
+       struct rxrpc_wire_header whdr;
+
+       /* dig out the RxRPC connection details */
+       if (skb_copy_bits(skb, sizeof(struct udphdr), &whdr, sizeof(whdr)) < 0)
+               return -EBADMSG;
+       if (!pskb_pull(skb, sizeof(struct udphdr) + sizeof(whdr)))
+               BUG();
+
+       memset(sp, 0, sizeof(*sp));
+       sp->hdr.epoch           = ntohl(whdr.epoch);
+       sp->hdr.cid             = ntohl(whdr.cid);
+       sp->hdr.callNumber      = ntohl(whdr.callNumber);
+       sp->hdr.seq             = ntohl(whdr.seq);
+       sp->hdr.serial          = ntohl(whdr.serial);
+       sp->hdr.flags           = whdr.flags;
+       sp->hdr.type            = whdr.type;
+       sp->hdr.userStatus      = whdr.userStatus;
+       sp->hdr.securityIndex   = whdr.securityIndex;
+       sp->hdr._rsvd           = ntohs(whdr._rsvd);
+       sp->hdr.serviceId       = ntohs(whdr.serviceId);
+       return 0;
+}
+
 static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local,
                                               struct sk_buff *skb,
                                               struct rxrpc_skb_priv *sp)
@@ -686,29 +711,25 @@ void rxrpc_data_ready(struct sock *sk)
 
        UDP_INC_STATS_BH(&init_net, UDP_MIB_INDATAGRAMS, 0);
 
-       /* the socket buffer we have is owned by UDP, with UDP's data all over
-        * it, but we really want our own */
+       /* The socket buffer we have is owned by UDP, with UDP's data all over
+        * it, but we really want our own data there.
+        */
        skb_orphan(skb);
        sp = rxrpc_skb(skb);
-       memset(sp, 0, sizeof(*sp));
 
        _net("Rx UDP packet from %08x:%04hu",
             ntohl(ip_hdr(skb)->saddr), ntohs(udp_hdr(skb)->source));
 
        /* dig out the RxRPC connection details */
-       if (skb_copy_bits(skb, sizeof(struct udphdr), &sp->hdr,
-                         sizeof(sp->hdr)) < 0)
+       if (rxrpc_extract_header(sp, skb) < 0)
                goto bad_message;
-       if (!pskb_pull(skb, sizeof(struct udphdr) + sizeof(sp->hdr)))
-               BUG();
 
        _net("Rx RxRPC %s ep=%x call=%x:%x",
             sp->hdr.flags & RXRPC_CLIENT_INITIATED ? "ToServer" : "ToClient",
-            ntohl(sp->hdr.epoch),
-            ntohl(sp->hdr.cid),
-            ntohl(sp->hdr.callNumber));
+            sp->hdr.epoch, sp->hdr.cid, sp->hdr.callNumber);
 
-       if (sp->hdr.type == 0 || sp->hdr.type >= RXRPC_N_PACKET_TYPES) {
+       if (sp->hdr.type >= RXRPC_N_PACKET_TYPES ||
+           !((RXRPC_SUPPORTED_PACKET_TYPES >> sp->hdr.type) & 1)) {
                _proto("Rx Bad Packet Type %u", sp->hdr.type);
                goto bad_message;
        }
@@ -737,14 +758,9 @@ void rxrpc_data_ready(struct sock *sk)
                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);
+
+               call = rxrpc_find_call_hash(&sp->hdr, local,
+                                           AF_INET, &ip_hdr(skb)->saddr);
                if (call)
                        rxrpc_post_packet_to_call(call, skb);
                else
@@ -759,7 +775,7 @@ cant_route_call:
        _debug("can't route call");
        if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
            sp->hdr.type == RXRPC_PACKET_TYPE_DATA) {
-               if (sp->hdr.seq == cpu_to_be32(1)) {
+               if (sp->hdr.seq == 1) {
                        _debug("first packet");
                        skb_queue_tail(&local->accept_queue, skb);
                        rxrpc_queue_work(&local->acceptor);
index 2934a73a5981ad154888904b67f8082fedac4a3c..a3002f4ddc906fda10953f1084793c0163ce13ff 100644 (file)
@@ -16,7 +16,7 @@
        BUG_ON(atomic_read((X)) >> (sizeof(atomic_t) - 2) == \
               (POISON_FREE << 8 | POISON_FREE))
 #else
-#define CHECK_SLAB_OKAY(X) do {} while(0)
+#define CHECK_SLAB_OKAY(X) do {} while (0)
 #endif
 
 #define FCRYPT_BSIZE 8
@@ -70,11 +70,30 @@ struct rxrpc_sock {
 #define RXRPC_SECURITY_MAX     RXRPC_SECURITY_ENCRYPT
        struct sockaddr_rxrpc   srx;            /* local address */
        sa_family_t             proto;          /* protocol created with */
-       __be16                  service_id;     /* service ID of local/remote service */
 };
 
 #define rxrpc_sk(__sk) container_of((__sk), struct rxrpc_sock, sk)
 
+/*
+ * CPU-byteorder normalised Rx packet header.
+ */
+struct rxrpc_host_header {
+       u32             epoch;          /* client boot timestamp */
+       u32             cid;            /* connection and channel ID */
+       u32             callNumber;     /* call ID (0 for connection-level packets) */
+       u32             seq;            /* sequence number of pkt in call stream */
+       u32             serial;         /* serial number of pkt sent to network */
+       u8              type;           /* packet type */
+       u8              flags;          /* packet flags */
+       u8              userStatus;     /* app-layer defined status */
+       u8              securityIndex;  /* security protocol ID */
+       union {
+               u16     _rsvd;          /* reserved */
+               u16     cksum;          /* kerberos security checksum */
+       };
+       u16             serviceId;      /* service ID */
+} __packed;
+
 /*
  * RxRPC socket buffer private variables
  * - max 48 bytes (struct sk_buff::cb)
@@ -89,7 +108,7 @@ struct rxrpc_skb_priv {
                bool            need_resend;    /* T if needs resending */
        };
 
-       struct rxrpc_header     hdr;            /* RxRPC packet header from this packet */
+       struct rxrpc_host_header hdr;           /* RxRPC packet header from this packet */
 };
 
 #define rxrpc_skb(__skb) ((struct rxrpc_skb_priv *) &(__skb)->cb)
@@ -230,7 +249,7 @@ struct rxrpc_conn_bundle {
        atomic_t                usage;
        int                     debug_id;       /* debug ID for printks */
        unsigned short          num_conns;      /* number of connections in this bundle */
-       __be16                  service_id;     /* service ID */
+       u16                     service_id;     /* Service ID for this bundle */
        u8                      security_ix;    /* security type */
 };
 
@@ -260,7 +279,6 @@ struct rxrpc_connection {
        rwlock_t                lock;           /* access lock */
        spinlock_t              state_lock;     /* state-change lock */
        atomic_t                usage;
-       u32                     real_conn_id;   /* connection ID (host-endian) */
        enum {                                  /* current state of connection */
                RXRPC_CONN_UNUSED,              /* - connection not yet attempted */
                RXRPC_CONN_CLIENT,              /* - client connection */
@@ -282,16 +300,75 @@ struct rxrpc_connection {
        u8                      security_size;  /* security header size */
        u32                     security_level; /* security level negotiated */
        u32                     security_nonce; /* response re-use preventer */
-
-       /* the following are all in net order */
-       __be32                  epoch;          /* epoch of this connection */
-       __be32                  cid;            /* connection ID */
-       __be16                  service_id;     /* service ID */
+       u32                     epoch;          /* epoch of this connection */
+       u32                     cid;            /* connection ID */
+       u16                     service_id;     /* service ID for this connection */
        u8                      security_ix;    /* security type */
        u8                      in_clientflag;  /* RXRPC_CLIENT_INITIATED if we are server */
        u8                      out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
 };
 
+/*
+ * Flags in call->flags.
+ */
+enum rxrpc_call_flag {
+       RXRPC_CALL_RELEASED,            /* call has been released - no more message to userspace */
+       RXRPC_CALL_TERMINAL_MSG,        /* call has given the socket its final message */
+       RXRPC_CALL_RCVD_LAST,           /* all packets received */
+       RXRPC_CALL_RUN_RTIMER,          /* Tx resend timer started */
+       RXRPC_CALL_TX_SOFT_ACK,         /* sent some soft ACKs */
+       RXRPC_CALL_PROC_BUSY,           /* the processor is busy */
+       RXRPC_CALL_INIT_ACCEPT,         /* acceptance was initiated */
+       RXRPC_CALL_HAS_USERID,          /* has a user ID attached */
+       RXRPC_CALL_EXPECT_OOS,          /* expect out of sequence packets */
+};
+
+/*
+ * Events that can be raised on a call.
+ */
+enum rxrpc_call_event {
+       RXRPC_CALL_EV_RCVD_ACKALL,      /* ACKALL or reply received */
+       RXRPC_CALL_EV_RCVD_BUSY,        /* busy packet received */
+       RXRPC_CALL_EV_RCVD_ABORT,       /* abort packet received */
+       RXRPC_CALL_EV_RCVD_ERROR,       /* network error received */
+       RXRPC_CALL_EV_ACK_FINAL,        /* need to generate final ACK (and release call) */
+       RXRPC_CALL_EV_ACK,              /* need to generate ACK */
+       RXRPC_CALL_EV_REJECT_BUSY,      /* need to generate busy message */
+       RXRPC_CALL_EV_ABORT,            /* need to generate abort */
+       RXRPC_CALL_EV_CONN_ABORT,       /* local connection abort generated */
+       RXRPC_CALL_EV_RESEND_TIMER,     /* Tx resend timer expired */
+       RXRPC_CALL_EV_RESEND,           /* Tx resend required */
+       RXRPC_CALL_EV_DRAIN_RX_OOS,     /* drain the Rx out of sequence queue */
+       RXRPC_CALL_EV_LIFE_TIMER,       /* call's lifetimer ran out */
+       RXRPC_CALL_EV_ACCEPTED,         /* incoming call accepted by userspace app */
+       RXRPC_CALL_EV_SECURED,          /* incoming call's connection is now secure */
+       RXRPC_CALL_EV_POST_ACCEPT,      /* need to post an "accept?" message to the app */
+       RXRPC_CALL_EV_RELEASE,          /* need to release the call's resources */
+};
+
+/*
+ * The states that a call can be in.
+ */
+enum rxrpc_call_state {
+       RXRPC_CALL_CLIENT_SEND_REQUEST, /* - client sending request phase */
+       RXRPC_CALL_CLIENT_AWAIT_REPLY,  /* - client awaiting reply */
+       RXRPC_CALL_CLIENT_RECV_REPLY,   /* - client receiving reply phase */
+       RXRPC_CALL_CLIENT_FINAL_ACK,    /* - client sending final ACK phase */
+       RXRPC_CALL_SERVER_SECURING,     /* - server securing request connection */
+       RXRPC_CALL_SERVER_ACCEPTING,    /* - server accepting request */
+       RXRPC_CALL_SERVER_RECV_REQUEST, /* - server receiving request */
+       RXRPC_CALL_SERVER_ACK_REQUEST,  /* - server pending ACK of request */
+       RXRPC_CALL_SERVER_SEND_REPLY,   /* - server sending reply */
+       RXRPC_CALL_SERVER_AWAIT_ACK,    /* - server awaiting final ACK */
+       RXRPC_CALL_COMPLETE,            /* - call completed */
+       RXRPC_CALL_SERVER_BUSY,         /* - call rejected by busy server */
+       RXRPC_CALL_REMOTELY_ABORTED,    /* - call aborted by peer */
+       RXRPC_CALL_LOCALLY_ABORTED,     /* - call aborted locally on error or close */
+       RXRPC_CALL_NETWORK_ERROR,       /* - call terminated by network error */
+       RXRPC_CALL_DEAD,                /* - call is dead */
+       NR__RXRPC_CALL_STATES
+};
+
 /*
  * RxRPC call definition
  * - matched by { connection, call_id }
@@ -317,57 +394,13 @@ struct rxrpc_call {
        unsigned long           user_call_ID;   /* user-defined call ID */
        unsigned long           creation_jif;   /* time of call creation */
        unsigned long           flags;
-#define RXRPC_CALL_RELEASED    0       /* call has been released - no more message to userspace */
-#define RXRPC_CALL_TERMINAL_MSG        1       /* call has given the socket its final message */
-#define RXRPC_CALL_RCVD_LAST   2       /* all packets received */
-#define RXRPC_CALL_RUN_RTIMER  3       /* Tx resend timer started */
-#define RXRPC_CALL_TX_SOFT_ACK 4       /* sent some soft ACKs */
-#define RXRPC_CALL_PROC_BUSY   5       /* the processor is busy */
-#define RXRPC_CALL_INIT_ACCEPT 6       /* acceptance was initiated */
-#define RXRPC_CALL_HAS_USERID  7       /* has a user ID attached */
-#define RXRPC_CALL_EXPECT_OOS  8       /* expect out of sequence packets */
        unsigned long           events;
-#define RXRPC_CALL_RCVD_ACKALL 0       /* ACKALL or reply received */
-#define RXRPC_CALL_RCVD_BUSY   1       /* busy packet received */
-#define RXRPC_CALL_RCVD_ABORT  2       /* abort packet received */
-#define RXRPC_CALL_RCVD_ERROR  3       /* network error received */
-#define RXRPC_CALL_ACK_FINAL   4       /* need to generate final ACK (and release call) */
-#define RXRPC_CALL_ACK         5       /* need to generate ACK */
-#define RXRPC_CALL_REJECT_BUSY 6       /* need to generate busy message */
-#define RXRPC_CALL_ABORT       7       /* need to generate abort */
-#define RXRPC_CALL_CONN_ABORT  8       /* local connection abort generated */
-#define RXRPC_CALL_RESEND_TIMER        9       /* Tx resend timer expired */
-#define RXRPC_CALL_RESEND      10      /* Tx resend required */
-#define RXRPC_CALL_DRAIN_RX_OOS        11      /* drain the Rx out of sequence queue */
-#define RXRPC_CALL_LIFE_TIMER  12      /* call's lifetimer ran out */
-#define RXRPC_CALL_ACCEPTED    13      /* incoming call accepted by userspace app */
-#define RXRPC_CALL_SECURED     14      /* incoming call's connection is now secure */
-#define RXRPC_CALL_POST_ACCEPT 15      /* need to post an "accept?" message to the app */
-#define RXRPC_CALL_RELEASE     16      /* need to release the call's resources */
-
        spinlock_t              lock;
        rwlock_t                state_lock;     /* lock for state transition */
        atomic_t                usage;
        atomic_t                sequence;       /* Tx data packet sequence counter */
        u32                     abort_code;     /* local/remote abort code */
-       enum {                                  /* current state of call */
-               RXRPC_CALL_CLIENT_SEND_REQUEST, /* - client sending request phase */
-               RXRPC_CALL_CLIENT_AWAIT_REPLY,  /* - client awaiting reply */
-               RXRPC_CALL_CLIENT_RECV_REPLY,   /* - client receiving reply phase */
-               RXRPC_CALL_CLIENT_FINAL_ACK,    /* - client sending final ACK phase */
-               RXRPC_CALL_SERVER_SECURING,     /* - server securing request connection */
-               RXRPC_CALL_SERVER_ACCEPTING,    /* - server accepting request */
-               RXRPC_CALL_SERVER_RECV_REQUEST, /* - server receiving request */
-               RXRPC_CALL_SERVER_ACK_REQUEST,  /* - server pending ACK of request */
-               RXRPC_CALL_SERVER_SEND_REPLY,   /* - server sending reply */
-               RXRPC_CALL_SERVER_AWAIT_ACK,    /* - server awaiting final ACK */
-               RXRPC_CALL_COMPLETE,            /* - call completed */
-               RXRPC_CALL_SERVER_BUSY,         /* - call rejected by busy server */
-               RXRPC_CALL_REMOTELY_ABORTED,    /* - call aborted by peer */
-               RXRPC_CALL_LOCALLY_ABORTED,     /* - call aborted locally on error or close */
-               RXRPC_CALL_NETWORK_ERROR,       /* - call terminated by network error */
-               RXRPC_CALL_DEAD,                /* - call is dead */
-       } state;
+       enum rxrpc_call_state   state : 8;      /* current state of call */
        int                     debug_id;       /* debug ID for printks */
        u8                      channel;        /* connection channel occupied by this call */
 
@@ -389,9 +422,9 @@ struct rxrpc_call {
        rxrpc_seq_t             rx_data_eaten;  /* last data seq ID consumed by recvmsg */
        rxrpc_seq_t             rx_first_oos;   /* first packet in rx_oos_queue (or 0) */
        rxrpc_seq_t             ackr_win_top;   /* top of ACK window (rx_data_eaten is bottom) */
-       rxrpc_seq_net_t         ackr_prev_seq;  /* previous sequence number received */
+       rxrpc_seq_t             ackr_prev_seq;  /* previous sequence number received */
        u8                      ackr_reason;    /* reason to ACK */
-       __be32                  ackr_serial;    /* serial of packet being ACK'd */
+       rxrpc_serial_t          ackr_serial;    /* serial of packet being ACK'd */
        atomic_t                ackr_not_idle;  /* number of packets in Rx queue */
 
        /* received packet records, 1 bit per record */
@@ -403,11 +436,10 @@ struct rxrpc_call {
        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 */
+       u32                     call_id;        /* call ID on connection  */
+       u32                     cid;            /* connection ID plus channel index */
+       u32                     epoch;          /* epoch of this connection */
+       u16                     service_id;     /* service ID */
        union {                                 /* Peer IP address for hashing */
                __be32  ipv4_addr;
                __u8    ipv6_addr[16];          /* Anticipates eventual IPv6 support */
@@ -423,7 +455,7 @@ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code)
        if (call->state < RXRPC_CALL_COMPLETE) {
                call->abort_code = abort_code;
                call->state = RXRPC_CALL_LOCALLY_ABORTED;
-               set_bit(RXRPC_CALL_ABORT, &call->events);
+               set_bit(RXRPC_CALL_EV_ABORT, &call->events);
        }
        write_unlock_bh(&call->state_lock);
 }
@@ -432,7 +464,7 @@ static inline void rxrpc_abort_call(struct rxrpc_call *call, u32 abort_code)
  * af_rxrpc.c
  */
 extern atomic_t rxrpc_n_skbs;
-extern __be32 rxrpc_epoch;
+extern u32 rxrpc_epoch;
 extern atomic_t rxrpc_debug_id;
 extern struct workqueue_struct *rxrpc_workqueue;
 
@@ -446,35 +478,35 @@ 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;
+extern unsigned int rxrpc_requested_ack_delay;
+extern unsigned int rxrpc_soft_ack_delay;
+extern unsigned int rxrpc_idle_ack_delay;
+extern unsigned int rxrpc_rx_window_size;
+extern unsigned int rxrpc_rx_mtu;
+extern unsigned int 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_propose_ACK(struct rxrpc_call *, u8, u32, bool);
+void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool);
 void rxrpc_process_call(struct work_struct *);
 
 /*
  * ar-call.c
  */
-extern unsigned rxrpc_max_call_lifetime;
-extern unsigned rxrpc_dead_call_expiry;
+extern unsigned int rxrpc_max_call_lifetime;
+extern unsigned int 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_find_call_hash(struct rxrpc_host_header *,
+                                       void *, sa_family_t, const void *);
 struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *,
                                         struct rxrpc_transport *,
                                         struct rxrpc_conn_bundle *,
                                         unsigned long, int, gfp_t);
 struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *,
                                       struct rxrpc_connection *,
-                                      struct rxrpc_header *, gfp_t);
+                                      struct rxrpc_host_header *, gfp_t);
 struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *, unsigned long);
 void rxrpc_release_call(struct rxrpc_call *);
 void rxrpc_release_calls_on_socket(struct rxrpc_sock *);
@@ -484,22 +516,22 @@ void __exit rxrpc_destroy_all_calls(void);
 /*
  * ar-connection.c
  */
-extern unsigned rxrpc_connection_expiry;
+extern unsigned int rxrpc_connection_expiry;
 extern struct list_head rxrpc_connections;
 extern rwlock_t rxrpc_connection_lock;
 
 struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *,
                                           struct rxrpc_transport *,
-                                          struct key *, __be16, gfp_t);
+                                          struct key *, u16, gfp_t);
 void rxrpc_put_bundle(struct rxrpc_transport *, struct rxrpc_conn_bundle *);
 int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_transport *,
                       struct rxrpc_conn_bundle *, struct rxrpc_call *, gfp_t);
 void rxrpc_put_connection(struct rxrpc_connection *);
 void __exit rxrpc_destroy_all_connections(void);
 struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *,
-                                              struct rxrpc_header *);
+                                              struct rxrpc_host_header *);
 extern struct rxrpc_connection *
-rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_header *,
+rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_host_header *,
                          gfp_t);
 
 /*
@@ -547,7 +579,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time_t,
 /*
  * ar-output.c
  */
-extern unsigned rxrpc_resend_timeout;
+extern unsigned int rxrpc_resend_timeout;
 
 int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *);
 int rxrpc_client_sendmsg(struct rxrpc_sock *, struct rxrpc_transport *,
@@ -595,7 +627,7 @@ void rxrpc_packet_destructor(struct sk_buff *);
 /*
  * ar-transport.c
  */
-extern unsigned rxrpc_transport_expiry;
+extern unsigned int rxrpc_transport_expiry;
 
 struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *,
                                            struct rxrpc_peer *, gfp_t);
@@ -694,7 +726,7 @@ do {                                                                \
                printk(KERN_ERR "RxRPC: Assertion failed\n");   \
                BUG();                                          \
        }                                                       \
-} while(0)
+} while (0)
 
 #define ASSERTCMP(X, OP, Y)                                            \
 do {                                                                   \
@@ -707,7 +739,7 @@ do {                                                                        \
                       (unsigned long)(X), (unsigned long)(Y));         \
                BUG();                                                  \
        }                                                               \
-} while(0)
+} while (0)
 
 #define ASSERTIF(C, X)                                         \
 do {                                                           \
@@ -716,7 +748,7 @@ do {                                                                \
                printk(KERN_ERR "RxRPC: Assertion failed\n");   \
                BUG();                                          \
        }                                                       \
-} while(0)
+} while (0)
 
 #define ASSERTIFCMP(C, X, OP, Y)                                       \
 do {                                                                   \
@@ -729,25 +761,25 @@ do {                                                                      \
                       (unsigned long)(X), (unsigned long)(Y));         \
                BUG();                                                  \
        }                                                               \
-} while(0)
+} while (0)
 
 #else
 
 #define ASSERT(X)                              \
 do {                                           \
-} while(0)
+} while (0)
 
 #define ASSERTCMP(X, OP, Y)                    \
 do {                                           \
-} while(0)
+} while (0)
 
 #define ASSERTIF(C, X)                         \
 do {                                           \
-} while(0)
+} while (0)
 
 #define ASSERTIFCMP(C, X, OP, Y)               \
 do {                                           \
-} while(0)
+} while (0)
 
 #endif /* __KDEBUGALL */
 
@@ -804,9 +836,9 @@ do {                                                        \
        CHECK_SLAB_OKAY(&(CALL)->usage);                \
        if (atomic_inc_return(&(CALL)->usage) == 1)     \
                BUG();                                  \
-} while(0)
+} while (0)
 
 #define rxrpc_put_call(CALL)                           \
 do {                                                   \
        __rxrpc_put_call(CALL);                         \
-} while(0)
+} while (0)
index 78483b4602bf729229c160b839ca723fe60242f3..4e1e6db0050b900a4afd9dfb2ff9a0b1974d1634 100644 (file)
@@ -323,9 +323,11 @@ void __exit rxrpc_destroy_all_locals(void)
  * Reply to a version request
  */
 static void rxrpc_send_version_request(struct rxrpc_local *local,
-                                      struct rxrpc_header *hdr,
+                                      struct rxrpc_host_header *hdr,
                                       struct sk_buff *skb)
 {
+       struct rxrpc_wire_header whdr;
+       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct sockaddr_in sin;
        struct msghdr msg;
        struct kvec iov[2];
@@ -344,15 +346,20 @@ static void rxrpc_send_version_request(struct rxrpc_local *local,
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr->seq        = 0;
-       hdr->serial     = 0;
-       hdr->type       = RXRPC_PACKET_TYPE_VERSION;
-       hdr->flags      = RXRPC_LAST_PACKET | (~hdr->flags & RXRPC_CLIENT_INITIATED);
-       hdr->userStatus = 0;
-       hdr->_rsvd      = 0;
-
-       iov[0].iov_base = hdr;
-       iov[0].iov_len  = sizeof(*hdr);
+       whdr.epoch      = htonl(sp->hdr.epoch);
+       whdr.cid        = htonl(sp->hdr.cid);
+       whdr.callNumber = htonl(sp->hdr.callNumber);
+       whdr.seq        = 0;
+       whdr.serial     = 0;
+       whdr.type       = RXRPC_PACKET_TYPE_VERSION;
+       whdr.flags      = RXRPC_LAST_PACKET | (~hdr->flags & RXRPC_CLIENT_INITIATED);
+       whdr.userStatus = 0;
+       whdr.securityIndex = 0;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(sp->hdr.serviceId);
+
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
        iov[1].iov_base = (char *)rxrpc_version_string;
        iov[1].iov_len  = sizeof(rxrpc_version_string);
 
@@ -383,7 +390,7 @@ static void rxrpc_process_local_events(struct work_struct *work)
        while ((skb = skb_dequeue(&local->event_queue))) {
                struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
 
-               kdebug("{%d},{%u}", local->debug_id, sp->hdr.type);
+               _debug("{%d},{%u}", local->debug_id, sp->hdr.type);
 
                switch (sp->hdr.type) {
                case RXRPC_PACKET_TYPE_VERSION:
index 14c4e12c47b0f87f1c560d752bbd897d3ae2f952..d36fb6e1a29ca64a7db3ecb1686738150bd8b50c 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * Time till packet resend (in jiffies).
  */
-unsigned rxrpc_resend_timeout = 4 * HZ;
+unsigned int rxrpc_resend_timeout = 4 * HZ;
 
 static int rxrpc_send_data(struct rxrpc_sock *rx,
                           struct rxrpc_call *call,
@@ -111,11 +111,11 @@ static void rxrpc_send_abort(struct rxrpc_call *call, u32 abort_code)
        if (call->state <= RXRPC_CALL_COMPLETE) {
                call->state = RXRPC_CALL_LOCALLY_ABORTED;
                call->abort_code = abort_code;
-               set_bit(RXRPC_CALL_ABORT, &call->events);
+               set_bit(RXRPC_CALL_EV_ABORT, &call->events);
                del_timer_sync(&call->resend_timer);
                del_timer_sync(&call->ack_timer);
-               clear_bit(RXRPC_CALL_RESEND_TIMER, &call->events);
-               clear_bit(RXRPC_CALL_ACK, &call->events);
+               clear_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events);
+               clear_bit(RXRPC_CALL_EV_ACK, &call->events);
                clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
                rxrpc_queue_call(call);
        }
@@ -136,7 +136,7 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans,
        struct rxrpc_call *call;
        unsigned long user_call_ID = 0;
        struct key *key;
-       __be16 service_id;
+       u16 service_id;
        u32 abort_code = 0;
        int ret;
 
@@ -151,11 +151,11 @@ int rxrpc_client_sendmsg(struct rxrpc_sock *rx, struct rxrpc_transport *trans,
 
        bundle = NULL;
        if (trans) {
-               service_id = rx->service_id;
+               service_id = rx->srx.srx_service;
                if (msg->msg_name) {
                        DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx,
                                         msg->msg_name);
-                       service_id = htons(srx->srx_service);
+                       service_id = srx->srx_service;
                }
                key = rx->key;
                if (key && !rx->key->payload.data[0])
@@ -348,7 +348,7 @@ int rxrpc_send_packet(struct rxrpc_transport *trans, struct sk_buff *skb)
 
        /* send the packet with the don't fragment bit set if we currently
         * think it's small enough */
-       if (skb->len - sizeof(struct rxrpc_header) < trans->peer->maxdata) {
+       if (skb->len - sizeof(struct rxrpc_wire_header) < trans->peer->maxdata) {
                down_read(&trans->local->defrag_sem);
                /* send the packet by UDP
                 * - returns -EMSGSIZE if UDP would have to fragment the packet
@@ -401,7 +401,8 @@ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
        int ret;
 
        _enter(",{%d},%ld",
-              CIRC_SPACE(call->acks_head, call->acks_tail, call->acks_winsz),
+              CIRC_SPACE(call->acks_head, ACCESS_ONCE(call->acks_tail),
+                         call->acks_winsz),
               *timeo);
 
        add_wait_queue(&call->tx_waitq, &myself);
@@ -409,7 +410,7 @@ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
                ret = 0;
-               if (CIRC_SPACE(call->acks_head, call->acks_tail,
+               if (CIRC_SPACE(call->acks_head, ACCESS_ONCE(call->acks_tail),
                               call->acks_winsz) > 0)
                        break;
                if (signal_pending(current)) {
@@ -437,7 +438,7 @@ static inline void rxrpc_instant_resend(struct rxrpc_call *call)
        if (try_to_del_timer_sync(&call->resend_timer) >= 0) {
                clear_bit(RXRPC_CALL_RUN_RTIMER, &call->flags);
                if (call->state < RXRPC_CALL_COMPLETE &&
-                   !test_and_set_bit(RXRPC_CALL_RESEND_TIMER, &call->events))
+                   !test_and_set_bit(RXRPC_CALL_EV_RESEND_TIMER, &call->events))
                        rxrpc_queue_call(call);
        }
        read_unlock_bh(&call->state_lock);
@@ -480,8 +481,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
                write_unlock_bh(&call->state_lock);
        }
 
-       _proto("Tx DATA %%%u { #%u }",
-              ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
+       _proto("Tx DATA %%%u { #%u }", sp->hdr.serial, sp->hdr.seq);
 
        sp->need_resend = false;
        sp->resend_at = jiffies + rxrpc_resend_timeout;
@@ -512,6 +512,29 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
        _leave("");
 }
 
+/*
+ * Convert a host-endian header into a network-endian header.
+ */
+static void rxrpc_insert_header(struct sk_buff *skb)
+{
+       struct rxrpc_wire_header whdr;
+       struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+
+       whdr.epoch      = htonl(sp->hdr.epoch);
+       whdr.cid        = htonl(sp->hdr.cid);
+       whdr.callNumber = htonl(sp->hdr.callNumber);
+       whdr.seq        = htonl(sp->hdr.seq);
+       whdr.serial     = htonl(sp->hdr.serial);
+       whdr.type       = sp->hdr.type;
+       whdr.flags      = sp->hdr.flags;
+       whdr.userStatus = sp->hdr.userStatus;
+       whdr.securityIndex = sp->hdr.securityIndex;
+       whdr._rsvd      = htons(sp->hdr._rsvd);
+       whdr.serviceId  = htons(sp->hdr.serviceId);
+
+       memcpy(skb->head, &whdr, sizeof(whdr));
+}
+
 /*
  * send data through a socket
  * - must be called in process context
@@ -548,7 +571,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
                        _debug("alloc");
 
-                       if (CIRC_SPACE(call->acks_head, call->acks_tail,
+                       if (CIRC_SPACE(call->acks_head,
+                                      ACCESS_ONCE(call->acks_tail),
                                       call->acks_winsz) <= 0) {
                                ret = -EAGAIN;
                                if (msg->msg_flags & MSG_DONTWAIT)
@@ -650,22 +674,22 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
                        seq = atomic_inc_return(&call->sequence);
 
-                       sp->hdr.epoch = conn->epoch;
-                       sp->hdr.cid = call->cid;
+                       sp->hdr.epoch   = conn->epoch;
+                       sp->hdr.cid     = call->cid;
                        sp->hdr.callNumber = call->call_id;
-                       sp->hdr.seq = htonl(seq);
-                       sp->hdr.serial =
-                               htonl(atomic_inc_return(&conn->serial));
-                       sp->hdr.type = RXRPC_PACKET_TYPE_DATA;
+                       sp->hdr.seq     = seq;
+                       sp->hdr.serial  = atomic_inc_return(&conn->serial);
+                       sp->hdr.type    = RXRPC_PACKET_TYPE_DATA;
                        sp->hdr.userStatus = 0;
                        sp->hdr.securityIndex = conn->security_ix;
-                       sp->hdr._rsvd = 0;
-                       sp->hdr.serviceId = conn->service_id;
+                       sp->hdr._rsvd   = 0;
+                       sp->hdr.serviceId = call->service_id;
 
                        sp->hdr.flags = conn->out_clientflag;
                        if (msg_data_left(msg) == 0 && !more)
                                sp->hdr.flags |= RXRPC_LAST_PACKET;
-                       else if (CIRC_SPACE(call->acks_head, call->acks_tail,
+                       else if (CIRC_SPACE(call->acks_head,
+                                           ACCESS_ONCE(call->acks_tail),
                                            call->acks_winsz) > 1)
                                sp->hdr.flags |= RXRPC_MORE_PACKETS;
                        if (more && seq & 1)
@@ -673,12 +697,11 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
                        ret = rxrpc_secure_packet(
                                call, skb, skb->mark,
-                               skb->head + sizeof(struct rxrpc_header));
+                               skb->head + sizeof(struct rxrpc_wire_header));
                        if (ret < 0)
                                goto out;
 
-                       memcpy(skb->head, &sp->hdr,
-                              sizeof(struct rxrpc_header));
+                       rxrpc_insert_header(skb);
                        rxrpc_queue_packet(call, skb, !msg_data_left(msg) && !more);
                        skb = NULL;
                }
index bebaa43484bcdbf72bbaaa764559051aeb8efb99..dc089b1976aa3d4b5a7a040a9ebe7ad2c0586e84 100644 (file)
@@ -92,7 +92,7 @@ static struct rxrpc_peer *rxrpc_alloc_peer(struct sockaddr_rxrpc *srx,
                        BUG();
                }
 
-               peer->hdrsize += sizeof(struct rxrpc_header);
+               peer->hdrsize += sizeof(struct rxrpc_wire_header);
                peer->maxdata = peer->mtu - peer->hdrsize;
        }
 
index 38047f713f2cf0fb2b60261039c475bd7fe19f7e..525b2ba5a8f4095105d27833dbb948cd26c75b7b 100644 (file)
@@ -74,9 +74,9 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
                   " %-8.8s %08x %lx\n",
                   lbuff,
                   rbuff,
-                  ntohs(call->conn->service_id),
-                  ntohl(call->conn->cid),
-                  ntohl(call->call_id),
+                  call->conn->service_id,
+                  call->cid,
+                  call->call_id,
                   call->conn->in_clientflag ? "Svc" : "Clt",
                   atomic_read(&call->usage),
                   rxrpc_call_states[call->state],
@@ -157,8 +157,8 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
                   " %s %08x %08x %08x\n",
                   lbuff,
                   rbuff,
-                  ntohs(conn->service_id),
-                  ntohl(conn->cid),
+                  conn->service_id,
+                  conn->cid,
                   conn->call_counter,
                   conn->in_clientflag ? "Svc" : "Clt",
                   atomic_read(&conn->usage),
index b92beded7459403910b2208ba4dd19a3a752c05c..64facba24a4507b97f7612497a2f18aa6ff19466 100644 (file)
@@ -33,7 +33,7 @@ void rxrpc_remove_user_ID(struct rxrpc_sock *rx, struct rxrpc_call *call)
 
        read_lock_bh(&call->state_lock);
        if (!test_bit(RXRPC_CALL_RELEASED, &call->flags) &&
-           !test_and_set_bit(RXRPC_CALL_RELEASE, &call->events))
+           !test_and_set_bit(RXRPC_CALL_EV_RELEASE, &call->events))
                rxrpc_queue_call(call);
        read_unlock_bh(&call->state_lock);
 }
@@ -158,7 +158,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                        goto receive_non_data_message;
 
                _debug("recvmsg DATA #%u { %d, %d }",
-                      ntohl(sp->hdr.seq), skb->len, sp->offset);
+                      sp->hdr.seq, skb->len, sp->offset);
 
                if (!continue_call) {
                        /* only set the control data once per recvmsg() */
@@ -169,11 +169,11 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                        ASSERT(test_bit(RXRPC_CALL_HAS_USERID, &call->flags));
                }
 
-               ASSERTCMP(ntohl(sp->hdr.seq), >=, call->rx_data_recv);
-               ASSERTCMP(ntohl(sp->hdr.seq), <=, call->rx_data_recv + 1);
-               call->rx_data_recv = ntohl(sp->hdr.seq);
+               ASSERTCMP(sp->hdr.seq, >=, call->rx_data_recv);
+               ASSERTCMP(sp->hdr.seq, <=, call->rx_data_recv + 1);
+               call->rx_data_recv = sp->hdr.seq;
 
-               ASSERTCMP(ntohl(sp->hdr.seq), >, call->rx_data_eaten);
+               ASSERTCMP(sp->hdr.seq, >, call->rx_data_eaten);
 
                offset = sp->offset;
                copy = skb->len - offset;
@@ -364,11 +364,11 @@ void rxrpc_kernel_data_delivered(struct sk_buff *skb)
        struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
        struct rxrpc_call *call = sp->call;
 
-       ASSERTCMP(ntohl(sp->hdr.seq), >=, call->rx_data_recv);
-       ASSERTCMP(ntohl(sp->hdr.seq), <=, call->rx_data_recv + 1);
-       call->rx_data_recv = ntohl(sp->hdr.seq);
+       ASSERTCMP(sp->hdr.seq, >=, call->rx_data_recv);
+       ASSERTCMP(sp->hdr.seq, <=, call->rx_data_recv + 1);
+       call->rx_data_recv = sp->hdr.seq;
 
-       ASSERTCMP(ntohl(sp->hdr.seq), >, call->rx_data_eaten);
+       ASSERTCMP(sp->hdr.seq, >, call->rx_data_eaten);
        rxrpc_free_skb(skb);
 }
 
index 8334474eb26c773664ae56bc8c064e9aa9249b45..ceff6394a65f62e118f56aa599ccafb82dfa6cad 100644 (file)
@@ -167,11 +167,11 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
        struct rxrpc_sock *rx;
        struct key *key;
        key_ref_t kref;
-       char kdesc[5+1+3+1];
+       char kdesc[5 + 1 + 3 + 1];
 
        _enter("");
 
-       sprintf(kdesc, "%u:%u", ntohs(conn->service_id), conn->security_ix);
+       sprintf(kdesc, "%u:%u", conn->service_id, conn->security_ix);
 
        sec = rxrpc_security_lookup(conn->security_ix);
        if (!sec) {
@@ -182,7 +182,7 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
        /* find the service */
        read_lock_bh(&local->services_lock);
        list_for_each_entry(rx, &local->services, listen_link) {
-               if (rx->service_id == conn->service_id)
+               if (rx->srx.srx_service == conn->service_id)
                        goto found_service;
        }
 
index 4cfab49e329dbba1a2cfa05c1faeff66fd016031..62a267472fceaee48db0149e64a911e4b17b4b53 100644 (file)
@@ -34,7 +34,7 @@ static void rxrpc_request_final_ACK(struct rxrpc_call *call)
                /* get an extra ref on the call for the final-ACK generator to
                 * release */
                rxrpc_get_call(call);
-               set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+               set_bit(RXRPC_CALL_EV_ACK_FINAL, &call->events);
                if (try_to_del_timer_sync(&call->ack_timer) >= 0)
                        rxrpc_queue_call(call);
                break;
@@ -59,7 +59,7 @@ static void rxrpc_hard_ACK_data(struct rxrpc_call *call,
 
        spin_lock_bh(&call->lock);
 
-       _debug("hard ACK #%u", ntohl(sp->hdr.seq));
+       _debug("hard ACK #%u", sp->hdr.seq);
 
        for (loop = 0; loop < RXRPC_ACKR_WINDOW_ASZ; loop++) {
                call->ackr_window[loop] >>= 1;
@@ -67,7 +67,7 @@ static void rxrpc_hard_ACK_data(struct rxrpc_call *call,
                        call->ackr_window[loop + 1] << (BITS_PER_LONG - 1);
        }
 
-       seq = ntohl(sp->hdr.seq);
+       seq = sp->hdr.seq;
        ASSERTCMP(seq, ==, call->rx_data_eaten + 1);
        call->rx_data_eaten = seq;
 
@@ -133,5 +133,4 @@ void rxrpc_kernel_free_skb(struct sk_buff *skb)
 {
        rxrpc_free_skb(skb);
 }
-
 EXPORT_SYMBOL(rxrpc_kernel_free_skb);
index 9946467f16b41a9f5acfc59865f085c04e007b77..66a1a56764462d40d3f89d8874fd861e35f4bf75 100644 (file)
@@ -20,7 +20,7 @@
 /*
  * Time after last use at which transport record is cleaned up.
  */
-unsigned rxrpc_transport_expiry = 3600 * 24;
+unsigned int rxrpc_transport_expiry = 3600 * 24;
 
 static void rxrpc_transport_reaper(struct work_struct *work);
 
@@ -51,6 +51,7 @@ static struct rxrpc_transport *rxrpc_alloc_transport(struct rxrpc_local *local,
                spin_lock_init(&trans->client_lock);
                rwlock_init(&trans->conn_lock);
                atomic_set(&trans->usage, 1);
+               trans->conn_idcounter = peer->srx.srx_service << 16;
                trans->debug_id = atomic_inc_return(&rxrpc_debug_id);
 
                if (peer->srx.transport.family == AF_INET) {
index d7a9ab5a9d9ce8c95d60b5230c476e41740db607..3106a0c4960be7db6e726ab70bf1ed6b891b9c2f 100644 (file)
@@ -132,8 +132,8 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
        desc.info = iv.x;
        desc.flags = 0;
 
-       tmpbuf.x[0] = conn->epoch;
-       tmpbuf.x[1] = conn->cid;
+       tmpbuf.x[0] = htonl(conn->epoch);
+       tmpbuf.x[1] = htonl(conn->cid);
        tmpbuf.x[2] = 0;
        tmpbuf.x[3] = htonl(conn->security_ix);
 
@@ -142,7 +142,7 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
        crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
 
        memcpy(&conn->csum_iv, &tmpbuf.x[2], sizeof(conn->csum_iv));
-       ASSERTCMP(conn->csum_iv.n[0], ==, tmpbuf.x[2]);
+       ASSERTCMP((u32 __force)conn->csum_iv.n[0], ==, (u32 __force)tmpbuf.x[2]);
 
        _leave("");
 }
@@ -169,8 +169,8 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
 
        _enter("");
 
-       check = ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
-       data_size |= (u32) check << 16;
+       check = sp->hdr.seq ^ sp->hdr.callNumber;
+       data_size |= (u32)check << 16;
 
        tmpbuf.hdr.data_size = htonl(data_size);
        memcpy(&tmpbuf.first, sechdr + 4, sizeof(tmpbuf.first));
@@ -195,9 +195,9 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
  * wholly encrypt a packet (level 2 security)
  */
 static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
-                                       struct sk_buff *skb,
-                                       u32 data_size,
-                                       void *sechdr)
+                                      struct sk_buff *skb,
+                                      u32 data_size,
+                                      void *sechdr)
 {
        const struct rxrpc_key_token *token;
        struct rxkad_level2_hdr rxkhdr
@@ -215,9 +215,9 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
 
        _enter("");
 
-       check = ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+       check = sp->hdr.seq ^ sp->hdr.callNumber;
 
-       rxkhdr.data_size = htonl(data_size | (u32) check << 16);
+       rxkhdr.data_size = htonl(data_size | (u32)check << 16);
        rxkhdr.checksum = 0;
 
        /* encrypt from the session key */
@@ -251,9 +251,9 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
  * checksum an RxRPC packet header
  */
 static int rxkad_secure_packet(const struct rxrpc_call *call,
-                               struct sk_buff *skb,
-                               size_t data_size,
-                               void *sechdr)
+                              struct sk_buff *skb,
+                              size_t data_size,
+                              void *sechdr)
 {
        struct rxrpc_skb_priv *sp;
        struct blkcipher_desc desc;
@@ -262,14 +262,13 @@ static int rxkad_secure_packet(const struct rxrpc_call *call,
        struct {
                __be32 x[2];
        } tmpbuf __attribute__((aligned(8))); /* must all be in same page */
-       __be32 x;
-       u32 y;
+       u32 x, y;
        int ret;
 
        sp = rxrpc_skb(skb);
 
        _enter("{%d{%x}},{#%u},%zu,",
-              call->debug_id, key_serial(call->conn->key), ntohl(sp->hdr.seq),
+              call->debug_id, key_serial(call->conn->key), sp->hdr.seq,
               data_size);
 
        if (!call->conn->cipher)
@@ -286,10 +285,10 @@ static int rxkad_secure_packet(const struct rxrpc_call *call,
        desc.flags = 0;
 
        /* calculate the security checksum */
-       x = htonl(call->channel << (32 - RXRPC_CIDSHIFT));
-       x |= sp->hdr.seq & cpu_to_be32(0x3fffffff);
-       tmpbuf.x[0] = sp->hdr.callNumber;
-       tmpbuf.x[1] = x;
+       x = call->channel << (32 - RXRPC_CIDSHIFT);
+       x |= sp->hdr.seq & 0x3fffffff;
+       tmpbuf.x[0] = htonl(sp->hdr.callNumber);
+       tmpbuf.x[1] = htonl(x);
 
        sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
        sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
@@ -299,7 +298,7 @@ static int rxkad_secure_packet(const struct rxrpc_call *call,
        y = (y >> 16) & 0xffff;
        if (y == 0)
                y = 1; /* zero checksums are not permitted */
-       sp->hdr.cksum = htons(y);
+       sp->hdr.cksum = y;
 
        switch (call->conn->security_level) {
        case RXRPC_SECURITY_PLAIN:
@@ -368,7 +367,7 @@ static int rxkad_verify_packet_auth(const struct rxrpc_call *call,
        data_size = buf & 0xffff;
 
        check = buf >> 16;
-       check ^= ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+       check ^= sp->hdr.seq ^ sp->hdr.callNumber;
        check &= 0xffff;
        if (check != 0) {
                *_abort_code = RXKADSEALEDINCON;
@@ -453,7 +452,7 @@ static int rxkad_verify_packet_encrypt(const struct rxrpc_call *call,
        data_size = buf & 0xffff;
 
        check = buf >> 16;
-       check ^= ntohl(sp->hdr.seq ^ sp->hdr.callNumber);
+       check ^= sp->hdr.seq ^ sp->hdr.callNumber;
        check &= 0xffff;
        if (check != 0) {
                *_abort_code = RXKADSEALEDINCON;
@@ -494,16 +493,14 @@ static int rxkad_verify_packet(const struct rxrpc_call *call,
        struct {
                __be32 x[2];
        } tmpbuf __attribute__((aligned(8))); /* must all be in same page */
-       __be32 x;
-       __be16 cksum;
-       u32 y;
+       u16 cksum;
+       u32 x, y;
        int ret;
 
        sp = rxrpc_skb(skb);
 
        _enter("{%d{%x}},{#%u}",
-              call->debug_id, key_serial(call->conn->key),
-              ntohl(sp->hdr.seq));
+              call->debug_id, key_serial(call->conn->key), sp->hdr.seq);
 
        if (!call->conn->cipher)
                return 0;
@@ -521,21 +518,20 @@ static int rxkad_verify_packet(const struct rxrpc_call *call,
        desc.flags = 0;
 
        /* validate the security checksum */
-       x = htonl(call->channel << (32 - RXRPC_CIDSHIFT));
-       x |= sp->hdr.seq & cpu_to_be32(0x3fffffff);
-       tmpbuf.x[0] = call->call_id;
-       tmpbuf.x[1] = x;
+       x = call->channel << (32 - RXRPC_CIDSHIFT);
+       x |= sp->hdr.seq & 0x3fffffff;
+       tmpbuf.x[0] = htonl(call->call_id);
+       tmpbuf.x[1] = htonl(x);
 
        sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
        sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
        crypto_blkcipher_encrypt_iv(&desc, &sg[0], &sg[1], sizeof(tmpbuf));
 
        y = ntohl(tmpbuf.x[1]);
-       y = (y >> 16) & 0xffff;
-       if (y == 0)
-               y = 1; /* zero checksums are not permitted */
+       cksum = (y >> 16) & 0xffff;
+       if (cksum == 0)
+               cksum = 1; /* zero checksums are not permitted */
 
-       cksum = htons(y);
        if (sp->hdr.cksum != cksum) {
                *_abort_code = RXKADSEALEDINCON;
                _leave(" = -EPROTO [csum failed]");
@@ -567,10 +563,11 @@ static int rxkad_verify_packet(const struct rxrpc_call *call,
 static int rxkad_issue_challenge(struct rxrpc_connection *conn)
 {
        struct rxkad_challenge challenge;
-       struct rxrpc_header hdr;
+       struct rxrpc_wire_header whdr;
        struct msghdr msg;
        struct kvec iov[2];
        size_t len;
+       u32 serial;
        int ret;
 
        _enter("{%d,%x}", conn->debug_id, key_serial(conn->key));
@@ -592,26 +589,27 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr.epoch       = conn->epoch;
-       hdr.cid         = conn->cid;
-       hdr.callNumber  = 0;
-       hdr.seq         = 0;
-       hdr.type        = RXRPC_PACKET_TYPE_CHALLENGE;
-       hdr.flags       = conn->out_clientflag;
-       hdr.userStatus  = 0;
-       hdr.securityIndex = conn->security_ix;
-       hdr._rsvd       = 0;
-       hdr.serviceId   = conn->service_id;
-
-       iov[0].iov_base = &hdr;
-       iov[0].iov_len  = sizeof(hdr);
+       whdr.epoch      = htonl(conn->epoch);
+       whdr.cid        = htonl(conn->cid);
+       whdr.callNumber = 0;
+       whdr.seq        = 0;
+       whdr.type       = RXRPC_PACKET_TYPE_CHALLENGE;
+       whdr.flags      = conn->out_clientflag;
+       whdr.userStatus = 0;
+       whdr.securityIndex = conn->security_ix;
+       whdr._rsvd      = 0;
+       whdr.serviceId  = htons(conn->service_id);
+
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
        iov[1].iov_base = &challenge;
        iov[1].iov_len  = sizeof(challenge);
 
        len = iov[0].iov_len + iov[1].iov_len;
 
-       hdr.serial = htonl(atomic_inc_return(&conn->serial));
-       _proto("Tx CHALLENGE %%%u", ntohl(hdr.serial));
+       serial = atomic_inc_return(&conn->serial);
+       whdr.serial = htonl(serial);
+       _proto("Tx CHALLENGE %%%u", serial);
 
        ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 2, len);
        if (ret < 0) {
@@ -627,13 +625,15 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn)
  * send a Kerberos security response
  */
 static int rxkad_send_response(struct rxrpc_connection *conn,
-                              struct rxrpc_header *hdr,
+                              struct rxrpc_host_header *hdr,
                               struct rxkad_response *resp,
                               const struct rxkad_key *s2)
 {
+       struct rxrpc_wire_header whdr;
        struct msghdr msg;
        struct kvec iov[3];
        size_t len;
+       u32 serial;
        int ret;
 
        _enter("");
@@ -644,24 +644,26 @@ static int rxkad_send_response(struct rxrpc_connection *conn,
        msg.msg_controllen = 0;
        msg.msg_flags   = 0;
 
-       hdr->epoch      = conn->epoch;
-       hdr->seq        = 0;
-       hdr->type       = RXRPC_PACKET_TYPE_RESPONSE;
-       hdr->flags      = conn->out_clientflag;
-       hdr->userStatus = 0;
-       hdr->_rsvd      = 0;
+       memset(&whdr, 0, sizeof(whdr));
+       whdr.epoch      = htonl(hdr->epoch);
+       whdr.cid        = htonl(hdr->cid);
+       whdr.type       = RXRPC_PACKET_TYPE_RESPONSE;
+       whdr.flags      = conn->out_clientflag;
+       whdr.securityIndex = hdr->securityIndex;
+       whdr.serviceId  = htons(hdr->serviceId);
 
-       iov[0].iov_base = hdr;
-       iov[0].iov_len  = sizeof(*hdr);
+       iov[0].iov_base = &whdr;
+       iov[0].iov_len  = sizeof(whdr);
        iov[1].iov_base = resp;
        iov[1].iov_len  = sizeof(*resp);
-       iov[2].iov_base = (void *) s2->ticket;
+       iov[2].iov_base = (void *)s2->ticket;
        iov[2].iov_len  = s2->ticket_len;
 
        len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
 
-       hdr->serial = htonl(atomic_inc_return(&conn->serial));
-       _proto("Tx RESPONSE %%%u", ntohl(hdr->serial));
+       serial = atomic_inc_return(&conn->serial);
+       whdr.serial = htonl(serial);
+       _proto("Tx RESPONSE %%%u", serial);
 
        ret = kernel_sendmsg(conn->trans->local->socket, &msg, iov, 3, len);
        if (ret < 0) {
@@ -770,7 +772,7 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
        min_level = ntohl(challenge.min_level);
 
        _proto("Rx CHALLENGE %%%u { v=%u n=%u ml=%u }",
-              ntohl(sp->hdr.serial), version, nonce, min_level);
+              sp->hdr.serial, version, nonce, min_level);
 
        abort_code = RXKADINCONSISTENCY;
        if (version != RXKAD_VERSION)
@@ -785,22 +787,23 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
        /* build the response packet */
        memset(&resp, 0, sizeof(resp));
 
-       resp.version = RXKAD_VERSION;
-       resp.encrypted.epoch = conn->epoch;
-       resp.encrypted.cid = conn->cid;
-       resp.encrypted.securityIndex = htonl(conn->security_ix);
+       resp.version                    = htonl(RXKAD_VERSION);
+       resp.encrypted.epoch            = htonl(conn->epoch);
+       resp.encrypted.cid              = htonl(conn->cid);
+       resp.encrypted.securityIndex    = htonl(conn->security_ix);
+       resp.encrypted.inc_nonce        = htonl(nonce + 1);
+       resp.encrypted.level            = htonl(conn->security_level);
+       resp.kvno                       = htonl(token->kad->kvno);
+       resp.ticket_len                 = htonl(token->kad->ticket_len);
+
        resp.encrypted.call_id[0] =
-               (conn->channels[0] ? conn->channels[0]->call_id : 0);
+               htonl(conn->channels[0] ? conn->channels[0]->call_id : 0);
        resp.encrypted.call_id[1] =
-               (conn->channels[1] ? conn->channels[1]->call_id : 0);
+               htonl(conn->channels[1] ? conn->channels[1]->call_id : 0);
        resp.encrypted.call_id[2] =
-               (conn->channels[2] ? conn->channels[2]->call_id : 0);
+               htonl(conn->channels[2] ? conn->channels[2]->call_id : 0);
        resp.encrypted.call_id[3] =
-               (conn->channels[3] ? conn->channels[3]->call_id : 0);
-       resp.encrypted.inc_nonce = htonl(nonce + 1);
-       resp.encrypted.level = htonl(conn->security_level);
-       resp.kvno = htonl(token->kad->kvno);
-       resp.ticket_len = htonl(token->kad->ticket_len);
+               htonl(conn->channels[3] ? conn->channels[3]->call_id : 0);
 
        /* calculate the response checksum and then do the encryption */
        rxkad_calc_response_checksum(&resp);
@@ -1022,7 +1025,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        kvno = ntohl(response.kvno);
        sp = rxrpc_skb(skb);
        _proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }",
-              ntohl(sp->hdr.serial), version, kvno, ticket_len);
+              sp->hdr.serial, version, kvno, ticket_len);
 
        abort_code = RXKADINCONSISTENCY;
        if (version != RXKAD_VERSION)
@@ -1058,9 +1061,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
        rxkad_decrypt_response(conn, &response, &session_key);
 
        abort_code = RXKADSEALEDINCON;
-       if (response.encrypted.epoch != conn->epoch)
+       if (ntohl(response.encrypted.epoch) != conn->epoch)
                goto protocol_error_free;
-       if (response.encrypted.cid != conn->cid)
+       if (ntohl(response.encrypted.cid) != conn->cid)
                goto protocol_error_free;
        if (ntohl(response.encrypted.securityIndex) != conn->security_ix)
                goto protocol_error_free;
@@ -1077,7 +1080,7 @@ static int rxkad_verify_response(struct rxrpc_connection *conn,
                goto protocol_error_free;
 
        abort_code = RXKADOUTOFSEQUENCE;
-       if (response.encrypted.inc_nonce != htonl(conn->security_nonce + 1))
+       if (ntohl(response.encrypted.inc_nonce) != conn->security_nonce + 1)
                goto protocol_error_free;
 
        abort_code = RXKADLEVELFAIL;
index 50a98a910eb16c61c0298aded08513c22a808c19..d20ed575acf40909b1c4dc02431a2e05d4d0eb5b 100644 (file)
 #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;
+static const unsigned int zero = 0;
+static const unsigned int one = 1;
+static const unsigned int four = 4;
+static const unsigned int n_65535 = 65535;
+static const unsigned int n_max_acks = RXRPC_MAXACKS;
 
 /*
  * RxRPC operating parameters.
@@ -32,7 +32,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "req_ack_delay",
                .data           = &rxrpc_requested_ack_delay,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
                .extra1         = (void *)&zero,
@@ -40,7 +40,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "soft_ack_delay",
                .data           = &rxrpc_soft_ack_delay,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
                .extra1         = (void *)&one,
@@ -48,7 +48,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "idle_ack_delay",
                .data           = &rxrpc_idle_ack_delay,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
                .extra1         = (void *)&one,
@@ -56,7 +56,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "resend_timeout",
                .data           = &rxrpc_resend_timeout,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_ms_jiffies,
                .extra1         = (void *)&one,
@@ -66,7 +66,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "max_call_lifetime",
                .data           = &rxrpc_max_call_lifetime,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
                .extra1         = (void *)&one,
@@ -74,7 +74,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "dead_call_expiry",
                .data           = &rxrpc_dead_call_expiry,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
                .extra1         = (void *)&one,
@@ -84,7 +84,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "connection_expiry",
                .data           = &rxrpc_connection_expiry,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *)&one,
@@ -92,7 +92,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "transport_expiry",
                .data           = &rxrpc_transport_expiry,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *)&one,
@@ -102,7 +102,7 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "rx_window_size",
                .data           = &rxrpc_rx_window_size,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *)&one,
@@ -111,16 +111,16 @@ static struct ctl_table rxrpc_sysctl_table[] = {
        {
                .procname       = "rx_mtu",
                .data           = &rxrpc_rx_mtu,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *)&one,
-               .extra1         = (void *)&n_65535,
+               .extra2         = (void *)&n_65535,
        },
        {
                .procname       = "rx_jumbo_max",
                .data           = &rxrpc_rx_jumbo_max,
-               .maxlen         = sizeof(unsigned),
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
                .extra1         = (void *)&one,
index 82830824fb1f26e5c7507e952c5b214fce79ea7b..b148302bbaf205c04a820c1a0adeda975b5057e8 100644 (file)
@@ -739,6 +739,28 @@ config NET_ACT_CONNMARK
          To compile this code as a module, choose M here: the
          module will be called act_connmark.
 
+config NET_ACT_IFE
+        tristate "Inter-FE action based on IETF ForCES InterFE LFB"
+        depends on NET_CLS_ACT
+        ---help---
+         Say Y here to allow for sourcing and terminating metadata
+         For details refer to netdev01 paper:
+         "Distributing Linux Traffic Control Classifier-Action Subsystem"
+          Authors: Jamal Hadi Salim and Damascene M. Joachimpillai
+
+         To compile this code as a module, choose M here: the
+         module will be called act_ife.
+
+config NET_IFE_SKBMARK
+        tristate "Support to encoding decoding skb mark on IFE action"
+        depends on NET_ACT_IFE
+        ---help---
+
+config NET_IFE_SKBPRIO
+        tristate "Support to encoding decoding skb prio on IFE action"
+        depends on NET_ACT_IFE
+        ---help---
+
 config NET_CLS_IND
        bool "Incoming device classification"
        depends on NET_CLS_U32 || NET_CLS_FW
index 690c1689e09020cd2dfb5fa64f000231a0980ef8..84bddb37351789ec4a2d7c27b94843146b8fdf6f 100644 (file)
@@ -19,6 +19,9 @@ obj-$(CONFIG_NET_ACT_CSUM)    += act_csum.o
 obj-$(CONFIG_NET_ACT_VLAN)     += act_vlan.o
 obj-$(CONFIG_NET_ACT_BPF)      += act_bpf.o
 obj-$(CONFIG_NET_ACT_CONNMARK) += act_connmark.o
+obj-$(CONFIG_NET_ACT_IFE)      += act_ife.o
+obj-$(CONFIG_NET_IFE_SKBMARK)  += act_meta_mark.o
+obj-$(CONFIG_NET_IFE_SKBPRIO)  += act_meta_skbprio.o
 obj-$(CONFIG_NET_SCH_FIFO)     += sch_fifo.o
 obj-$(CONFIG_NET_SCH_CBQ)      += sch_cbq.o
 obj-$(CONFIG_NET_SCH_HTB)      += sch_htb.o
index 06e7c4a372451916b77d81d32d94e2a20d96a527..96066665e3765d342fd1685ab32f0019c7455564 100644 (file)
@@ -36,10 +36,9 @@ static void free_tcf(struct rcu_head *head)
        kfree(p);
 }
 
-static void tcf_hash_destroy(struct tc_action *a)
+static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a)
 {
        struct tcf_common *p = a->priv;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
 
        spin_lock_bh(&hinfo->lock);
        hlist_del(&p->tcfc_head);
@@ -68,8 +67,8 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
                if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
                        if (a->ops->cleanup)
                                a->ops->cleanup(a, bind);
-                       tcf_hash_destroy(a);
-                       ret = 1;
+                       tcf_hash_destroy(a->hinfo, a);
+                       ret = ACT_P_DELETED;
                }
        }
 
@@ -77,10 +76,9 @@ int __tcf_hash_release(struct tc_action *a, bool bind, bool strict)
 }
 EXPORT_SYMBOL(__tcf_hash_release);
 
-static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                          struct tc_action *a)
+static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+                          struct netlink_callback *cb, struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct hlist_head *head;
        struct tcf_common *p;
        int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
@@ -126,9 +124,9 @@ nla_put_failure:
        goto done;
 }
 
-static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
+static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+                         struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct hlist_head *head;
        struct hlist_node *n;
        struct tcf_common *p;
@@ -163,18 +161,24 @@ nla_put_failure:
        return ret;
 }
 
-static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                             int type, struct tc_action *a)
+int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
+                      struct netlink_callback *cb, int type,
+                      struct tc_action *a)
 {
+       struct tcf_hashinfo *hinfo = tn->hinfo;
+
+       a->hinfo = hinfo;
+
        if (type == RTM_DELACTION) {
-               return tcf_del_walker(skb, a);
+               return tcf_del_walker(hinfo, skb, a);
        } else if (type == RTM_GETACTION) {
-               return tcf_dump_walker(skb, cb, a);
+               return tcf_dump_walker(hinfo, skb, cb, a);
        } else {
                WARN(1, "tcf_generic_walker: unknown action %d\n", type);
                return -EINVAL;
        }
 }
+EXPORT_SYMBOL(tcf_generic_walker);
 
 static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
 {
@@ -191,8 +195,9 @@ static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
        return p;
 }
 
-u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
+u32 tcf_hash_new_index(struct tc_action_net *tn)
 {
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        u32 val = hinfo->index;
 
        do {
@@ -205,28 +210,31 @@ u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
 }
 EXPORT_SYMBOL(tcf_hash_new_index);
 
-int tcf_hash_search(struct tc_action *a, u32 index)
+int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct tcf_common *p = tcf_hash_lookup(index, hinfo);
 
        if (p) {
                a->priv = p;
+               a->hinfo = hinfo;
                return 1;
        }
        return 0;
 }
 EXPORT_SYMBOL(tcf_hash_search);
 
-int tcf_hash_check(u32 index, struct tc_action *a, int bind)
+int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
+                  int bind)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct tcf_common *p = NULL;
        if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
                if (bind)
                        p->tcfc_bindcnt++;
                p->tcfc_refcnt++;
                a->priv = p;
+               a->hinfo = hinfo;
                return 1;
        }
        return 0;
@@ -243,11 +251,11 @@ void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
 }
 EXPORT_SYMBOL(tcf_hash_cleanup);
 
-int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
-                   int size, int bind, bool cpustats)
+int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+                   struct tc_action *a, int size, int bind, bool cpustats)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct tcf_common *p = kzalloc(size, GFP_KERNEL);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        int err = -ENOMEM;
 
        if (unlikely(!p))
@@ -272,7 +280,7 @@ err2:
        }
        spin_lock_init(&p->tcfc_lock);
        INIT_HLIST_NODE(&p->tcfc_head);
-       p->tcfc_index = index ? index : tcf_hash_new_index(hinfo);
+       p->tcfc_index = index ? index : tcf_hash_new_index(tn);
        p->tcfc_tm.install = jiffies;
        p->tcfc_tm.lastuse = jiffies;
        if (est) {
@@ -286,14 +294,15 @@ err2:
        }
 
        a->priv = (void *) p;
+       a->hinfo = hinfo;
        return 0;
 }
 EXPORT_SYMBOL(tcf_hash_create);
 
-void tcf_hash_insert(struct tc_action *a)
+void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a)
 {
        struct tcf_common *p = a->priv;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
 
        spin_lock_bh(&hinfo->lock);
@@ -302,59 +311,78 @@ void tcf_hash_insert(struct tc_action *a)
 }
 EXPORT_SYMBOL(tcf_hash_insert);
 
+void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
+                         struct tcf_hashinfo *hinfo)
+{
+       struct tc_action a = {
+               .ops = ops,
+               .hinfo = hinfo,
+       };
+       int i;
+
+       for (i = 0; i < hinfo->hmask + 1; i++) {
+               struct tcf_common *p;
+               struct hlist_node *n;
+
+               hlist_for_each_entry_safe(p, n, &hinfo->htab[i], tcfc_head) {
+                       int ret;
+
+                       a.priv = p;
+                       ret = __tcf_hash_release(&a, false, true);
+                       if (ret == ACT_P_DELETED)
+                               module_put(ops->owner);
+                       else if (ret < 0)
+                               return;
+               }
+       }
+       kfree(hinfo->htab);
+}
+EXPORT_SYMBOL(tcf_hashinfo_destroy);
+
 static LIST_HEAD(act_base);
 static DEFINE_RWLOCK(act_mod_lock);
 
-int tcf_register_action(struct tc_action_ops *act, unsigned int mask)
+int tcf_register_action(struct tc_action_ops *act,
+                       struct pernet_operations *ops)
 {
        struct tc_action_ops *a;
-       int err;
+       int ret;
 
-       /* Must supply act, dump and init */
-       if (!act->act || !act->dump || !act->init)
+       if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
                return -EINVAL;
 
-       /* Supply defaults */
-       if (!act->lookup)
-               act->lookup = tcf_hash_search;
-       if (!act->walk)
-               act->walk = tcf_generic_walker;
-
-       act->hinfo = kmalloc(sizeof(struct tcf_hashinfo), GFP_KERNEL);
-       if (!act->hinfo)
-               return -ENOMEM;
-       err = tcf_hashinfo_init(act->hinfo, mask);
-       if (err) {
-               kfree(act->hinfo);
-               return err;
-       }
-
        write_lock(&act_mod_lock);
        list_for_each_entry(a, &act_base, head) {
                if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
                        write_unlock(&act_mod_lock);
-                       tcf_hashinfo_destroy(act->hinfo);
-                       kfree(act->hinfo);
                        return -EEXIST;
                }
        }
        list_add_tail(&act->head, &act_base);
        write_unlock(&act_mod_lock);
+
+       ret = register_pernet_subsys(ops);
+       if (ret) {
+               tcf_unregister_action(act, ops);
+               return ret;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(tcf_register_action);
 
-int tcf_unregister_action(struct tc_action_ops *act)
+int tcf_unregister_action(struct tc_action_ops *act,
+                         struct pernet_operations *ops)
 {
        struct tc_action_ops *a;
        int err = -ENOENT;
 
+       unregister_pernet_subsys(ops);
+
        write_lock(&act_mod_lock);
        list_for_each_entry(a, &act_base, head) {
                if (a == act) {
                        list_del(&act->head);
-                       tcf_hashinfo_destroy(act->hinfo);
-                       kfree(act->hinfo);
                        err = 0;
                        break;
                }
@@ -721,8 +749,8 @@ static struct tc_action *create_a(int i)
        return act;
 }
 
-static struct tc_action *
-tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
+static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
+                                         struct nlmsghdr *n, u32 portid)
 {
        struct nlattr *tb[TCA_ACT_MAX + 1];
        struct tc_action *a;
@@ -749,7 +777,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
        if (a->ops == NULL) /* could happen in batch of actions */
                goto err_free;
        err = -ENOENT;
-       if (a->ops->lookup(a, index) == 0)
+       if (a->ops->lookup(net, a, index) == 0)
                goto err_mod;
 
        module_put(a->ops->owner);
@@ -819,7 +847,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
        if (nest == NULL)
                goto out_module_put;
 
-       err = a.ops->walk(skb, &dcb, RTM_DELACTION, &a);
+       err = a.ops->walk(net, skb, &dcb, RTM_DELACTION, &a);
        if (err < 0)
                goto out_module_put;
        if (err == 0)
@@ -897,7 +925,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
        }
 
        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
-               act = tcf_action_get_1(tb[i], n, portid);
+               act = tcf_action_get_1(net, tb[i], n, portid);
                if (IS_ERR(act)) {
                        ret = PTR_ERR(act);
                        goto err;
@@ -1044,6 +1072,7 @@ find_dump_kind(const struct nlmsghdr *n)
 static int
 tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = sock_net(skb->sk);
        struct nlmsghdr *nlh;
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
@@ -1078,7 +1107,7 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        if (nest == NULL)
                goto out_module_put;
 
-       ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
+       ret = a_o->walk(net, skb, cb, RTM_GETACTION, &a);
        if (ret < 0)
                goto out_module_put;
 
index 0bc6f912f870297a6d91ef04acca76f6e1915339..8c9f1f0459ab773139112c453fd1540af3a1b94f 100644 (file)
@@ -33,6 +33,8 @@ struct tcf_bpf_cfg {
        bool is_ebpf;
 };
 
+static int bpf_net_id;
+
 static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act,
                   struct tcf_result *res)
 {
@@ -275,6 +277,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act,
                        int replace, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
        struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
        struct tcf_bpf_cfg cfg, old;
        struct tc_act_bpf *parm;
@@ -294,8 +297,8 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
 
        parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
 
-       if (!tcf_hash_check(parm->index, act, bind)) {
-               ret = tcf_hash_create(parm->index, est, act,
+       if (!tcf_hash_check(tn, parm->index, act, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, act,
                                      sizeof(*prog), bind, true);
                if (ret < 0)
                        return ret;
@@ -344,7 +347,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        rcu_assign_pointer(prog->filter, cfg.filter);
 
        if (res == ACT_P_CREATED) {
-               tcf_hash_insert(act);
+               tcf_hash_insert(tn, act);
        } else {
                /* make sure the program being replaced is no longer executing */
                synchronize_rcu();
@@ -367,6 +370,22 @@ static void tcf_bpf_cleanup(struct tc_action *act, int bind)
        tcf_bpf_cfg_cleanup(&tmp);
 }
 
+static int tcf_bpf_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_bpf_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_bpf_ops __read_mostly = {
        .kind           =       "bpf",
        .type           =       TCA_ACT_BPF,
@@ -375,16 +394,39 @@ static struct tc_action_ops act_bpf_ops __read_mostly = {
        .dump           =       tcf_bpf_dump,
        .cleanup        =       tcf_bpf_cleanup,
        .init           =       tcf_bpf_init,
+       .walk           =       tcf_bpf_walker,
+       .lookup         =       tcf_bpf_search,
+};
+
+static __net_init int bpf_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tc_action_net_init(tn, &act_bpf_ops, BPF_TAB_MASK);
+}
+
+static void __net_exit bpf_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations bpf_net_ops = {
+       .init = bpf_init_net,
+       .exit = bpf_exit_net,
+       .id   = &bpf_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init bpf_init_module(void)
 {
-       return tcf_register_action(&act_bpf_ops, BPF_TAB_MASK);
+       return tcf_register_action(&act_bpf_ops, &bpf_net_ops);
 }
 
 static void __exit bpf_cleanup_module(void)
 {
-       tcf_unregister_action(&act_bpf_ops);
+       tcf_unregister_action(&act_bpf_ops, &bpf_net_ops);
 }
 
 module_init(bpf_init_module);
index bb41699c6c49eb4a40241d662a79ebd39cd6ff8f..c0ed93ce23910f8da64622f5f2df3eea867ee786 100644 (file)
@@ -30,6 +30,8 @@
 
 #define CONNMARK_TAB_MASK     3
 
+static int connmark_net_id;
+
 static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
                        struct tcf_result *res)
 {
@@ -97,6 +99,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
                             struct nlattr *est, struct tc_action *a,
                             int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
        struct nlattr *tb[TCA_CONNMARK_MAX + 1];
        struct tcf_connmark_info *ci;
        struct tc_connmark *parm;
@@ -111,9 +114,9 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
 
        parm = nla_data(tb[TCA_CONNMARK_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*ci),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*ci), bind, false);
                if (ret)
                        return ret;
 
@@ -122,7 +125,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
                ci->net = net;
                ci->zone = parm->zone;
 
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
                ret = ACT_P_CREATED;
        } else {
                ci = to_connmark(a);
@@ -169,6 +172,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_connmark_walker(struct net *net, struct sk_buff *skb,
+                              struct netlink_callback *cb, int type,
+                              struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_connmark_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_connmark_ops = {
        .kind           =       "connmark",
        .type           =       TCA_ACT_CONNMARK,
@@ -176,16 +195,39 @@ static struct tc_action_ops act_connmark_ops = {
        .act            =       tcf_connmark,
        .dump           =       tcf_connmark_dump,
        .init           =       tcf_connmark_init,
+       .walk           =       tcf_connmark_walker,
+       .lookup         =       tcf_connmark_search,
+};
+
+static __net_init int connmark_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tc_action_net_init(tn, &act_connmark_ops, CONNMARK_TAB_MASK);
+}
+
+static void __net_exit connmark_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations connmark_net_ops = {
+       .init = connmark_init_net,
+       .exit = connmark_exit_net,
+       .id   = &connmark_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init connmark_init_module(void)
 {
-       return tcf_register_action(&act_connmark_ops, CONNMARK_TAB_MASK);
+       return tcf_register_action(&act_connmark_ops, &connmark_net_ops);
 }
 
 static void __exit connmark_cleanup_module(void)
 {
-       tcf_unregister_action(&act_connmark_ops);
+       tcf_unregister_action(&act_connmark_ops, &connmark_net_ops);
 }
 
 module_init(connmark_init_module);
index b07c535ba8e7c6f8dcbc52f4eb69cf4a1ab3d0c2..d22426cdebc08b95357d3e7f38b237d5cd60915f 100644 (file)
@@ -42,9 +42,13 @@ static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
        [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
 };
 
-static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
-                        struct tc_action *a, int ovr, int bind)
+static int csum_net_id;
+
+static int tcf_csum_init(struct net *net, struct nlattr *nla,
+                        struct nlattr *est, struct tc_action *a, int ovr,
+                        int bind)
 {
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
        struct nlattr *tb[TCA_CSUM_MAX + 1];
        struct tc_csum *parm;
        struct tcf_csum *p;
@@ -61,9 +65,9 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        parm = nla_data(tb[TCA_CSUM_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
@@ -82,7 +86,7 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
        spin_unlock_bh(&p->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
 
        return ret;
 }
@@ -105,9 +109,7 @@ static void *tcf_csum_skb_nextlayer(struct sk_buff *skb,
        int hl = ihl + jhl;
 
        if (!pskb_may_pull(skb, ipl + ntkoff) || (ipl < hl) ||
-           (skb_cloned(skb) &&
-            !skb_clone_writable(skb, hl + ntkoff) &&
-            pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+           skb_try_make_writable(skb, hl + ntkoff))
                return NULL;
        else
                return (void *)(skb_network_header(skb) + ihl);
@@ -365,9 +367,7 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
        }
 
        if (update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
-               if (skb_cloned(skb) &&
-                   !skb_clone_writable(skb, sizeof(*iph) + ntkoff) &&
-                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+               if (skb_try_make_writable(skb, sizeof(*iph) + ntkoff))
                        goto fail;
 
                ip_send_check(ip_hdr(skb));
@@ -559,6 +559,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_csum_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_csum_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_csum_ops = {
        .kind           = "csum",
        .type           = TCA_ACT_CSUM,
@@ -566,6 +582,29 @@ static struct tc_action_ops act_csum_ops = {
        .act            = tcf_csum,
        .dump           = tcf_csum_dump,
        .init           = tcf_csum_init,
+       .walk           = tcf_csum_walker,
+       .lookup         = tcf_csum_search,
+};
+
+static __net_init int csum_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tc_action_net_init(tn, &act_csum_ops, CSUM_TAB_MASK);
+}
+
+static void __net_exit csum_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations csum_net_ops = {
+       .init = csum_init_net,
+       .exit = csum_exit_net,
+       .id   = &csum_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_DESCRIPTION("Checksum updating actions");
@@ -573,12 +612,12 @@ MODULE_LICENSE("GPL");
 
 static int __init csum_init_module(void)
 {
-       return tcf_register_action(&act_csum_ops, CSUM_TAB_MASK);
+       return tcf_register_action(&act_csum_ops, &csum_net_ops);
 }
 
 static void __exit csum_cleanup_module(void)
 {
-       tcf_unregister_action(&act_csum_ops);
+       tcf_unregister_action(&act_csum_ops, &csum_net_ops);
 }
 
 module_init(csum_init_module);
index 5c1b051707363e19a779fcca2de6ae38ba0239fe..887fc1f209ff6355ed4c83254a0ea56666942157 100644 (file)
@@ -25,6 +25,8 @@
 
 #define GACT_TAB_MASK  15
 
+static int gact_net_id;
+
 #ifdef CONFIG_GACT_PROB
 static int gact_net_rand(struct tcf_gact *gact)
 {
@@ -57,6 +59,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
        struct nlattr *tb[TCA_GACT_MAX + 1];
        struct tc_gact *parm;
        struct tcf_gact *gact;
@@ -88,9 +91,9 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        }
 #endif
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*gact),
-                                     bind, true);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*gact), bind, true);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
@@ -118,7 +121,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        }
 #endif
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
@@ -183,6 +186,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_gact_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_gact_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_gact_ops = {
        .kind           =       "gact",
        .type           =       TCA_ACT_GACT,
@@ -190,6 +209,29 @@ static struct tc_action_ops act_gact_ops = {
        .act            =       tcf_gact,
        .dump           =       tcf_gact_dump,
        .init           =       tcf_gact_init,
+       .walk           =       tcf_gact_walker,
+       .lookup         =       tcf_gact_search,
+};
+
+static __net_init int gact_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tc_action_net_init(tn, &act_gact_ops, GACT_TAB_MASK);
+}
+
+static void __net_exit gact_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations gact_net_ops = {
+       .init = gact_init_net,
+       .exit = gact_exit_net,
+       .id   = &gact_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
@@ -203,12 +245,13 @@ static int __init gact_init_module(void)
 #else
        pr_info("GACT probability NOT on\n");
 #endif
-       return tcf_register_action(&act_gact_ops, GACT_TAB_MASK);
+
+       return tcf_register_action(&act_gact_ops, &gact_net_ops);
 }
 
 static void __exit gact_cleanup_module(void)
 {
-       tcf_unregister_action(&act_gact_ops);
+       tcf_unregister_action(&act_gact_ops, &gact_net_ops);
 }
 
 module_init(gact_init_module);
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
new file mode 100644 (file)
index 0000000..c589a9b
--- /dev/null
@@ -0,0 +1,870 @@
+/*
+ * net/sched/ife.c     Inter-FE action based on ForCES WG InterFE LFB
+ *
+ *             Refer to:
+ *             draft-ietf-forces-interfelfb-03
+ *             and
+ *             netdev01 paper:
+ *             "Distributing Linux Traffic Control Classifier-Action
+ *             Subsystem"
+ *             Authors: Jamal Hadi Salim and Damascene M. Joachimpillai
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * copyright Jamal Hadi Salim (2015)
+ *
+*/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/net_namespace.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <uapi/linux/tc_act/tc_ife.h>
+#include <net/tc_act/tc_ife.h>
+#include <linux/etherdevice.h>
+
+#define IFE_TAB_MASK 15
+
+static int ife_net_id;
+static int max_metacnt = IFE_META_MAX + 1;
+
+static const struct nla_policy ife_policy[TCA_IFE_MAX + 1] = {
+       [TCA_IFE_PARMS] = { .len = sizeof(struct tc_ife)},
+       [TCA_IFE_DMAC] = { .len = ETH_ALEN},
+       [TCA_IFE_SMAC] = { .len = ETH_ALEN},
+       [TCA_IFE_TYPE] = { .type = NLA_U16},
+};
+
+/* Caller takes care of presenting data in network order
+*/
+int ife_tlv_meta_encode(void *skbdata, u16 attrtype, u16 dlen, const void *dval)
+{
+       u32 *tlv = (u32 *)(skbdata);
+       u16 totlen = nla_total_size(dlen);      /*alignment + hdr */
+       char *dptr = (char *)tlv + NLA_HDRLEN;
+       u32 htlv = attrtype << 16 | totlen;
+
+       *tlv = htonl(htlv);
+       memset(dptr, 0, totlen - NLA_HDRLEN);
+       memcpy(dptr, dval, dlen);
+
+       return totlen;
+}
+EXPORT_SYMBOL_GPL(ife_tlv_meta_encode);
+
+int ife_get_meta_u32(struct sk_buff *skb, struct tcf_meta_info *mi)
+{
+       if (mi->metaval)
+               return nla_put_u32(skb, mi->metaid, *(u32 *)mi->metaval);
+       else
+               return nla_put(skb, mi->metaid, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(ife_get_meta_u32);
+
+int ife_check_meta_u32(u32 metaval, struct tcf_meta_info *mi)
+{
+       if (metaval || mi->metaval)
+               return 8; /* T+L+V == 2+2+4 */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ife_check_meta_u32);
+
+int ife_encode_meta_u32(u32 metaval, void *skbdata, struct tcf_meta_info *mi)
+{
+       u32 edata = metaval;
+
+       if (mi->metaval)
+               edata = *(u32 *)mi->metaval;
+       else if (metaval)
+               edata = metaval;
+
+       if (!edata) /* will not encode */
+               return 0;
+
+       edata = htonl(edata);
+       return ife_tlv_meta_encode(skbdata, mi->metaid, 4, &edata);
+}
+EXPORT_SYMBOL_GPL(ife_encode_meta_u32);
+
+int ife_get_meta_u16(struct sk_buff *skb, struct tcf_meta_info *mi)
+{
+       if (mi->metaval)
+               return nla_put_u16(skb, mi->metaid, *(u16 *)mi->metaval);
+       else
+               return nla_put(skb, mi->metaid, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(ife_get_meta_u16);
+
+int ife_alloc_meta_u32(struct tcf_meta_info *mi, void *metaval)
+{
+       mi->metaval = kmemdup(metaval, sizeof(u32), GFP_KERNEL);
+       if (!mi->metaval)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ife_alloc_meta_u32);
+
+int ife_alloc_meta_u16(struct tcf_meta_info *mi, void *metaval)
+{
+       mi->metaval = kmemdup(metaval, sizeof(u16), GFP_KERNEL);
+       if (!mi->metaval)
+               return -ENOMEM;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ife_alloc_meta_u16);
+
+void ife_release_meta_gen(struct tcf_meta_info *mi)
+{
+       kfree(mi->metaval);
+}
+EXPORT_SYMBOL_GPL(ife_release_meta_gen);
+
+int ife_validate_meta_u32(void *val, int len)
+{
+       if (len == 4)
+               return 0;
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ife_validate_meta_u32);
+
+int ife_validate_meta_u16(void *val, int len)
+{
+       /* length will include padding */
+       if (len == NLA_ALIGN(2))
+               return 0;
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ife_validate_meta_u16);
+
+static LIST_HEAD(ifeoplist);
+static DEFINE_RWLOCK(ife_mod_lock);
+
+static struct tcf_meta_ops *find_ife_oplist(u16 metaid)
+{
+       struct tcf_meta_ops *o;
+
+       read_lock(&ife_mod_lock);
+       list_for_each_entry(o, &ifeoplist, list) {
+               if (o->metaid == metaid) {
+                       if (!try_module_get(o->owner))
+                               o = NULL;
+                       read_unlock(&ife_mod_lock);
+                       return o;
+               }
+       }
+       read_unlock(&ife_mod_lock);
+
+       return NULL;
+}
+
+int register_ife_op(struct tcf_meta_ops *mops)
+{
+       struct tcf_meta_ops *m;
+
+       if (!mops->metaid || !mops->metatype || !mops->name ||
+           !mops->check_presence || !mops->encode || !mops->decode ||
+           !mops->get || !mops->alloc)
+               return -EINVAL;
+
+       write_lock(&ife_mod_lock);
+
+       list_for_each_entry(m, &ifeoplist, list) {
+               if (m->metaid == mops->metaid ||
+                   (strcmp(mops->name, m->name) == 0)) {
+                       write_unlock(&ife_mod_lock);
+                       return -EEXIST;
+               }
+       }
+
+       if (!mops->release)
+               mops->release = ife_release_meta_gen;
+
+       list_add_tail(&mops->list, &ifeoplist);
+       write_unlock(&ife_mod_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_ife_op);
+
+int unregister_ife_op(struct tcf_meta_ops *mops)
+{
+       struct tcf_meta_ops *m;
+       int err = -ENOENT;
+
+       write_lock(&ife_mod_lock);
+       list_for_each_entry(m, &ifeoplist, list) {
+               if (m->metaid == mops->metaid) {
+                       list_del(&mops->list);
+                       err = 0;
+                       break;
+               }
+       }
+       write_unlock(&ife_mod_lock);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(register_ife_op);
+
+static int ife_validate_metatype(struct tcf_meta_ops *ops, void *val, int len)
+{
+       int ret = 0;
+       /* XXX: unfortunately cant use nla_policy at this point
+       * because a length of 0 is valid in the case of
+       * "allow". "use" semantics do enforce for proper
+       * length and i couldve use nla_policy but it makes it hard
+       * to use it just for that..
+       */
+       if (ops->validate)
+               return ops->validate(val, len);
+
+       if (ops->metatype == NLA_U32)
+               ret = ife_validate_meta_u32(val, len);
+       else if (ops->metatype == NLA_U16)
+               ret = ife_validate_meta_u16(val, len);
+
+       return ret;
+}
+
+/* called when adding new meta information
+ * under ife->tcf_lock
+*/
+static int load_metaops_and_vet(struct tcf_ife_info *ife, u32 metaid,
+                               void *val, int len)
+{
+       struct tcf_meta_ops *ops = find_ife_oplist(metaid);
+       int ret = 0;
+
+       if (!ops) {
+               ret = -ENOENT;
+#ifdef CONFIG_MODULES
+               spin_unlock_bh(&ife->tcf_lock);
+               rtnl_unlock();
+               request_module("ifemeta%u", metaid);
+               rtnl_lock();
+               spin_lock_bh(&ife->tcf_lock);
+               ops = find_ife_oplist(metaid);
+#endif
+       }
+
+       if (ops) {
+               ret = 0;
+               if (len)
+                       ret = ife_validate_metatype(ops, val, len);
+
+               module_put(ops->owner);
+       }
+
+       return ret;
+}
+
+/* called when adding new meta information
+ * under ife->tcf_lock
+*/
+static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
+                       int len)
+{
+       struct tcf_meta_info *mi = NULL;
+       struct tcf_meta_ops *ops = find_ife_oplist(metaid);
+       int ret = 0;
+
+       if (!ops)
+               return -ENOENT;
+
+       mi = kzalloc(sizeof(*mi), GFP_KERNEL);
+       if (!mi) {
+               /*put back what find_ife_oplist took */
+               module_put(ops->owner);
+               return -ENOMEM;
+       }
+
+       mi->metaid = metaid;
+       mi->ops = ops;
+       if (len > 0) {
+               ret = ops->alloc(mi, metaval);
+               if (ret != 0) {
+                       kfree(mi);
+                       module_put(ops->owner);
+                       return ret;
+               }
+       }
+
+       list_add_tail(&mi->metalist, &ife->metalist);
+
+       return ret;
+}
+
+static int use_all_metadata(struct tcf_ife_info *ife)
+{
+       struct tcf_meta_ops *o;
+       int rc = 0;
+       int installed = 0;
+
+       list_for_each_entry(o, &ifeoplist, list) {
+               rc = add_metainfo(ife, o->metaid, NULL, 0);
+               if (rc == 0)
+                       installed += 1;
+       }
+
+       if (installed)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int dump_metalist(struct sk_buff *skb, struct tcf_ife_info *ife)
+{
+       struct tcf_meta_info *e;
+       struct nlattr *nest;
+       unsigned char *b = skb_tail_pointer(skb);
+       int total_encoded = 0;
+
+       /*can only happen on decode */
+       if (list_empty(&ife->metalist))
+               return 0;
+
+       nest = nla_nest_start(skb, TCA_IFE_METALST);
+       if (!nest)
+               goto out_nlmsg_trim;
+
+       list_for_each_entry(e, &ife->metalist, metalist) {
+               if (!e->ops->get(skb, e))
+                       total_encoded += 1;
+       }
+
+       if (!total_encoded)
+               goto out_nlmsg_trim;
+
+       nla_nest_end(skb, nest);
+
+       return 0;
+
+out_nlmsg_trim:
+       nlmsg_trim(skb, b);
+       return -1;
+}
+
+/* under ife->tcf_lock */
+static void _tcf_ife_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_ife_info *ife = a->priv;
+       struct tcf_meta_info *e, *n;
+
+       list_for_each_entry_safe(e, n, &ife->metalist, metalist) {
+               module_put(e->ops->owner);
+               list_del(&e->metalist);
+               if (e->metaval) {
+                       if (e->ops->release)
+                               e->ops->release(e);
+                       else
+                               kfree(e->metaval);
+               }
+               kfree(e);
+       }
+}
+
+static void tcf_ife_cleanup(struct tc_action *a, int bind)
+{
+       struct tcf_ife_info *ife = a->priv;
+
+       spin_lock_bh(&ife->tcf_lock);
+       _tcf_ife_cleanup(a, bind);
+       spin_unlock_bh(&ife->tcf_lock);
+}
+
+/* under ife->tcf_lock */
+static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb)
+{
+       int len = 0;
+       int rc = 0;
+       int i = 0;
+       void *val;
+
+       for (i = 1; i < max_metacnt; i++) {
+               if (tb[i]) {
+                       val = nla_data(tb[i]);
+                       len = nla_len(tb[i]);
+
+                       rc = load_metaops_and_vet(ife, i, val, len);
+                       if (rc != 0)
+                               return rc;
+
+                       rc = add_metainfo(ife, i, val, len);
+                       if (rc)
+                               return rc;
+               }
+       }
+
+       return rc;
+}
+
+static int tcf_ife_init(struct net *net, struct nlattr *nla,
+                       struct nlattr *est, struct tc_action *a,
+                       int ovr, int bind)
+{
+       struct tc_action_net *tn = net_generic(net, ife_net_id);
+       struct nlattr *tb[TCA_IFE_MAX + 1];
+       struct nlattr *tb2[IFE_META_MAX + 1];
+       struct tcf_ife_info *ife;
+       struct tc_ife *parm;
+       u16 ife_type = 0;
+       u8 *daddr = NULL;
+       u8 *saddr = NULL;
+       int ret = 0;
+       int err;
+
+       err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy);
+       if (err < 0)
+               return err;
+
+       if (!tb[TCA_IFE_PARMS])
+               return -EINVAL;
+
+       parm = nla_data(tb[TCA_IFE_PARMS]);
+
+       if (parm->flags & IFE_ENCODE) {
+               /* Until we get issued the ethertype, we cant have
+                * a default..
+               **/
+               if (!tb[TCA_IFE_TYPE]) {
+                       pr_info("You MUST pass etherype for encoding\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a, sizeof(*ife),
+                                     bind, false);
+               if (ret)
+                       return ret;
+               ret = ACT_P_CREATED;
+       } else {
+               if (bind)       /* dont override defaults */
+                       return 0;
+               tcf_hash_release(a, bind);
+               if (!ovr)
+                       return -EEXIST;
+       }
+
+       ife = to_ife(a);
+       ife->flags = parm->flags;
+
+       if (parm->flags & IFE_ENCODE) {
+               ife_type = nla_get_u16(tb[TCA_IFE_TYPE]);
+               if (tb[TCA_IFE_DMAC])
+                       daddr = nla_data(tb[TCA_IFE_DMAC]);
+               if (tb[TCA_IFE_SMAC])
+                       saddr = nla_data(tb[TCA_IFE_SMAC]);
+       }
+
+       spin_lock_bh(&ife->tcf_lock);
+       ife->tcf_action = parm->action;
+
+       if (parm->flags & IFE_ENCODE) {
+               if (daddr)
+                       ether_addr_copy(ife->eth_dst, daddr);
+               else
+                       eth_zero_addr(ife->eth_dst);
+
+               if (saddr)
+                       ether_addr_copy(ife->eth_src, saddr);
+               else
+                       eth_zero_addr(ife->eth_src);
+
+               ife->eth_type = ife_type;
+       }
+
+       if (ret == ACT_P_CREATED)
+               INIT_LIST_HEAD(&ife->metalist);
+
+       if (tb[TCA_IFE_METALST]) {
+               err = nla_parse_nested(tb2, IFE_META_MAX, tb[TCA_IFE_METALST],
+                                      NULL);
+               if (err) {
+metadata_parse_err:
+                       if (ret == ACT_P_CREATED)
+                               _tcf_ife_cleanup(a, bind);
+
+                       spin_unlock_bh(&ife->tcf_lock);
+                       return err;
+               }
+
+               err = populate_metalist(ife, tb2);
+               if (err)
+                       goto metadata_parse_err;
+
+       } else {
+               /* if no passed metadata allow list or passed allow-all
+                * then here we process by adding as many supported metadatum
+                * as we can. You better have at least one else we are
+                * going to bail out
+                */
+               err = use_all_metadata(ife);
+               if (err) {
+                       if (ret == ACT_P_CREATED)
+                               _tcf_ife_cleanup(a, bind);
+
+                       spin_unlock_bh(&ife->tcf_lock);
+                       return err;
+               }
+       }
+
+       spin_unlock_bh(&ife->tcf_lock);
+
+       if (ret == ACT_P_CREATED)
+               tcf_hash_insert(tn, a);
+
+       return ret;
+}
+
+static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
+                       int ref)
+{
+       unsigned char *b = skb_tail_pointer(skb);
+       struct tcf_ife_info *ife = a->priv;
+       struct tc_ife opt = {
+               .index = ife->tcf_index,
+               .refcnt = ife->tcf_refcnt - ref,
+               .bindcnt = ife->tcf_bindcnt - bind,
+               .action = ife->tcf_action,
+               .flags = ife->flags,
+       };
+       struct tcf_t t;
+
+       if (nla_put(skb, TCA_IFE_PARMS, sizeof(opt), &opt))
+               goto nla_put_failure;
+
+       t.install = jiffies_to_clock_t(jiffies - ife->tcf_tm.install);
+       t.lastuse = jiffies_to_clock_t(jiffies - ife->tcf_tm.lastuse);
+       t.expires = jiffies_to_clock_t(ife->tcf_tm.expires);
+       if (nla_put(skb, TCA_IFE_TM, sizeof(t), &t))
+               goto nla_put_failure;
+
+       if (!is_zero_ether_addr(ife->eth_dst)) {
+               if (nla_put(skb, TCA_IFE_DMAC, ETH_ALEN, ife->eth_dst))
+                       goto nla_put_failure;
+       }
+
+       if (!is_zero_ether_addr(ife->eth_src)) {
+               if (nla_put(skb, TCA_IFE_SMAC, ETH_ALEN, ife->eth_src))
+                       goto nla_put_failure;
+       }
+
+       if (nla_put(skb, TCA_IFE_TYPE, 2, &ife->eth_type))
+               goto nla_put_failure;
+
+       if (dump_metalist(skb, ife)) {
+               /*ignore failure to dump metalist */
+               pr_info("Failed to dump metalist\n");
+       }
+
+       return skb->len;
+
+nla_put_failure:
+       nlmsg_trim(skb, b);
+       return -1;
+}
+
+int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife,
+                      u16 metaid, u16 mlen, void *mdata)
+{
+       struct tcf_meta_info *e;
+
+       /* XXX: use hash to speed up */
+       list_for_each_entry(e, &ife->metalist, metalist) {
+               if (metaid == e->metaid) {
+                       if (e->ops) {
+                               /* We check for decode presence already */
+                               return e->ops->decode(skb, mdata, mlen);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+struct ifeheadr {
+       __be16 metalen;
+       u8 tlv_data[];
+};
+
+struct meta_tlvhdr {
+       __be16 type;
+       __be16 len;
+};
+
+static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
+                         struct tcf_result *res)
+{
+       struct tcf_ife_info *ife = a->priv;
+       int action = ife->tcf_action;
+       struct ifeheadr *ifehdr = (struct ifeheadr *)skb->data;
+       u16 ifehdrln = ifehdr->metalen;
+       struct meta_tlvhdr *tlv = (struct meta_tlvhdr *)(ifehdr->tlv_data);
+
+       spin_lock(&ife->tcf_lock);
+       bstats_update(&ife->tcf_bstats, skb);
+       ife->tcf_tm.lastuse = jiffies;
+       spin_unlock(&ife->tcf_lock);
+
+       ifehdrln = ntohs(ifehdrln);
+       if (unlikely(!pskb_may_pull(skb, ifehdrln))) {
+               spin_lock(&ife->tcf_lock);
+               ife->tcf_qstats.drops++;
+               spin_unlock(&ife->tcf_lock);
+               return TC_ACT_SHOT;
+       }
+
+       skb_set_mac_header(skb, ifehdrln);
+       __skb_pull(skb, ifehdrln);
+       skb->protocol = eth_type_trans(skb, skb->dev);
+       ifehdrln -= IFE_METAHDRLEN;
+
+       while (ifehdrln > 0) {
+               u8 *tlvdata = (u8 *)tlv;
+               u16 mtype = tlv->type;
+               u16 mlen = tlv->len;
+
+               mtype = ntohs(mtype);
+               mlen = ntohs(mlen);
+
+               if (find_decode_metaid(skb, ife, mtype, (mlen - 4),
+                                      (void *)(tlvdata + 4))) {
+                       /* abuse overlimits to count when we receive metadata
+                        * but dont have an ops for it
+                        */
+                       pr_info_ratelimited("Unknown metaid %d alnlen %d\n",
+                                           mtype, mlen);
+                       ife->tcf_qstats.overlimits++;
+               }
+
+               tlvdata += mlen;
+               ifehdrln -= mlen;
+               tlv = (struct meta_tlvhdr *)tlvdata;
+       }
+
+       skb_reset_network_header(skb);
+       return action;
+}
+
+/*XXX: check if we can do this at install time instead of current
+ * send data path
+**/
+static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_info *ife)
+{
+       struct tcf_meta_info *e, *n;
+       int tot_run_sz = 0, run_sz = 0;
+
+       list_for_each_entry_safe(e, n, &ife->metalist, metalist) {
+               if (e->ops->check_presence) {
+                       run_sz = e->ops->check_presence(skb, e);
+                       tot_run_sz += run_sz;
+               }
+       }
+
+       return tot_run_sz;
+}
+
+static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
+                         struct tcf_result *res)
+{
+       struct tcf_ife_info *ife = a->priv;
+       int action = ife->tcf_action;
+       struct ethhdr *oethh;   /* outer ether header */
+       struct ethhdr *iethh;   /* inner eth header */
+       struct tcf_meta_info *e;
+       /*
+          OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA
+          where ORIGDATA = original ethernet header ...
+        */
+       u16 metalen = ife_get_sz(skb, ife);
+       int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN;
+       unsigned int skboff = skb->dev->hard_header_len;
+       u32 at = G_TC_AT(skb->tc_verd);
+       int new_len = skb->len + hdrm;
+       bool exceed_mtu = false;
+       int err;
+
+       if (at & AT_EGRESS) {
+               if (new_len > skb->dev->mtu)
+                       exceed_mtu = true;
+       }
+
+       spin_lock(&ife->tcf_lock);
+       bstats_update(&ife->tcf_bstats, skb);
+       ife->tcf_tm.lastuse = jiffies;
+
+       if (!metalen) {         /* no metadata to send */
+               /* abuse overlimits to count when we allow packet
+                * with no metadata
+                */
+               ife->tcf_qstats.overlimits++;
+               spin_unlock(&ife->tcf_lock);
+               return action;
+       }
+       /* could be stupid policy setup or mtu config
+        * so lets be conservative.. */
+       if ((action == TC_ACT_SHOT) || exceed_mtu) {
+               ife->tcf_qstats.drops++;
+               spin_unlock(&ife->tcf_lock);
+               return TC_ACT_SHOT;
+       }
+
+       iethh = eth_hdr(skb);
+
+       err = skb_cow_head(skb, hdrm);
+       if (unlikely(err)) {
+               ife->tcf_qstats.drops++;
+               spin_unlock(&ife->tcf_lock);
+               return TC_ACT_SHOT;
+       }
+
+       if (!(at & AT_EGRESS))
+               skb_push(skb, skb->dev->hard_header_len);
+
+       __skb_push(skb, hdrm);
+       memcpy(skb->data, iethh, skb->mac_len);
+       skb_reset_mac_header(skb);
+       oethh = eth_hdr(skb);
+
+       /*total metadata length */
+       metalen += IFE_METAHDRLEN;
+       metalen = htons(metalen);
+       memcpy((skb->data + skboff), &metalen, IFE_METAHDRLEN);
+       skboff += IFE_METAHDRLEN;
+
+       /* XXX: we dont have a clever way of telling encode to
+        * not repeat some of the computations that are done by
+        * ops->presence_check...
+        */
+       list_for_each_entry(e, &ife->metalist, metalist) {
+               if (e->ops->encode) {
+                       err = e->ops->encode(skb, (void *)(skb->data + skboff),
+                                            e);
+               }
+               if (err < 0) {
+                       /* too corrupt to keep around if overwritten */
+                       ife->tcf_qstats.drops++;
+                       spin_unlock(&ife->tcf_lock);
+                       return TC_ACT_SHOT;
+               }
+               skboff += err;
+       }
+
+       if (!is_zero_ether_addr(ife->eth_src))
+               ether_addr_copy(oethh->h_source, ife->eth_src);
+       else
+               ether_addr_copy(oethh->h_source, iethh->h_source);
+       if (!is_zero_ether_addr(ife->eth_dst))
+               ether_addr_copy(oethh->h_dest, ife->eth_dst);
+       else
+               ether_addr_copy(oethh->h_dest, iethh->h_dest);
+       oethh->h_proto = htons(ife->eth_type);
+
+       if (!(at & AT_EGRESS))
+               skb_pull(skb, skb->dev->hard_header_len);
+
+       spin_unlock(&ife->tcf_lock);
+
+       return action;
+}
+
+static int tcf_ife_act(struct sk_buff *skb, const struct tc_action *a,
+                      struct tcf_result *res)
+{
+       struct tcf_ife_info *ife = a->priv;
+
+       if (ife->flags & IFE_ENCODE)
+               return tcf_ife_encode(skb, a, res);
+
+       if (!(ife->flags & IFE_ENCODE))
+               return tcf_ife_decode(skb, a, res);
+
+       pr_info_ratelimited("unknown failure(policy neither de/encode\n");
+       spin_lock(&ife->tcf_lock);
+       bstats_update(&ife->tcf_bstats, skb);
+       ife->tcf_tm.lastuse = jiffies;
+       ife->tcf_qstats.drops++;
+       spin_unlock(&ife->tcf_lock);
+
+       return TC_ACT_SHOT;
+}
+
+static int tcf_ife_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, ife_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_ife_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, ife_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
+static struct tc_action_ops act_ife_ops = {
+       .kind = "ife",
+       .type = TCA_ACT_IFE,
+       .owner = THIS_MODULE,
+       .act = tcf_ife_act,
+       .dump = tcf_ife_dump,
+       .cleanup = tcf_ife_cleanup,
+       .init = tcf_ife_init,
+       .walk = tcf_ife_walker,
+       .lookup = tcf_ife_search,
+};
+
+static __net_init int ife_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ife_net_id);
+
+       return tc_action_net_init(tn, &act_ife_ops, IFE_TAB_MASK);
+}
+
+static void __net_exit ife_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ife_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations ife_net_ops = {
+       .init = ife_init_net,
+       .exit = ife_exit_net,
+       .id   = &ife_net_id,
+       .size = sizeof(struct tc_action_net),
+};
+
+static int __init ife_init_module(void)
+{
+       return tcf_register_action(&act_ife_ops, &ife_net_ops);
+}
+
+static void __exit ife_cleanup_module(void)
+{
+       tcf_unregister_action(&act_ife_ops, &ife_net_ops);
+}
+
+module_init(ife_init_module);
+module_exit(ife_cleanup_module);
+
+MODULE_AUTHOR("Jamal Hadi Salim(2015)");
+MODULE_DESCRIPTION("Inter-FE LFB action");
+MODULE_LICENSE("GPL");
index d05869646515dbabeb352361c9d58b9ccfc687d5..350e134cffb32b04f3e4c2b4b3917051cd55b456 100644 (file)
 
 #define IPT_TAB_MASK     15
 
+static int ipt_net_id;
+
+static int xt_net_id;
+
 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
 {
        struct xt_tgchk_param par;
@@ -62,6 +66,7 @@ static void ipt_destroy_target(struct xt_entry_target *t)
        struct xt_tgdtor_param par = {
                .target   = t->u.kernel.target,
                .targinfo = t->data,
+               .family   = NFPROTO_IPV4,
        };
        if (par.target->destroy != NULL)
                par.target->destroy(&par);
@@ -83,8 +88,9 @@ static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
        [TCA_IPT_TARG]  = { .len = sizeof(struct xt_entry_target) },
 };
 
-static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
-                       struct tc_action *a, int ovr, int bind)
+static int __tcf_ipt_init(struct tc_action_net *tn, struct nlattr *nla,
+                         struct nlattr *est, struct tc_action *a, int ovr,
+                         int bind)
 {
        struct nlattr *tb[TCA_IPT_MAX + 1];
        struct tcf_ipt *ipt;
@@ -113,8 +119,9 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        if (tb[TCA_IPT_INDEX] != NULL)
                index = nla_get_u32(tb[TCA_IPT_INDEX]);
 
-       if (!tcf_hash_check(index, a, bind) ) {
-               ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind, false);
+       if (!tcf_hash_check(tn, index, a, bind)) {
+               ret = tcf_hash_create(tn, index, est, a, sizeof(*ipt), bind,
+                                     false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
@@ -157,7 +164,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        ipt->tcfi_hook  = hook;
        spin_unlock_bh(&ipt->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 
 err3:
@@ -170,6 +177,24 @@ err1:
        return err;
 }
 
+static int tcf_ipt_init(struct net *net, struct nlattr *nla,
+                       struct nlattr *est, struct tc_action *a, int ovr,
+                       int bind)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return __tcf_ipt_init(tn, nla, est, a, ovr, bind);
+}
+
+static int tcf_xt_init(struct net *net, struct nlattr *nla,
+                      struct nlattr *est, struct tc_action *a, int ovr,
+                      int bind)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return __tcf_ipt_init(tn, nla, est, a, ovr, bind);
+}
+
 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
@@ -195,6 +220,7 @@ static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
        par.hooknum  = ipt->tcfi_hook;
        par.target   = ipt->tcfi_t->u.kernel.target;
        par.targinfo = ipt->tcfi_t->data;
+       par.family   = NFPROTO_IPV4;
        ret = par.target->target(skb, &par);
 
        switch (ret) {
@@ -260,6 +286,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_ipt_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_ipt_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_ipt_ops = {
        .kind           =       "ipt",
        .type           =       TCA_ACT_IPT,
@@ -268,8 +310,47 @@ static struct tc_action_ops act_ipt_ops = {
        .dump           =       tcf_ipt_dump,
        .cleanup        =       tcf_ipt_release,
        .init           =       tcf_ipt_init,
+       .walk           =       tcf_ipt_walker,
+       .lookup         =       tcf_ipt_search,
+};
+
+static __net_init int ipt_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tc_action_net_init(tn, &act_ipt_ops, IPT_TAB_MASK);
+}
+
+static void __net_exit ipt_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations ipt_net_ops = {
+       .init = ipt_init_net,
+       .exit = ipt_exit_net,
+       .id   = &ipt_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
+static int tcf_xt_walker(struct net *net, struct sk_buff *skb,
+                        struct netlink_callback *cb, int type,
+                        struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_xt_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_xt_ops = {
        .kind           =       "xt",
        .type           =       TCA_ACT_XT,
@@ -277,7 +358,30 @@ static struct tc_action_ops act_xt_ops = {
        .act            =       tcf_ipt,
        .dump           =       tcf_ipt_dump,
        .cleanup        =       tcf_ipt_release,
-       .init           =       tcf_ipt_init,
+       .init           =       tcf_xt_init,
+       .walk           =       tcf_xt_walker,
+       .lookup         =       tcf_xt_search,
+};
+
+static __net_init int xt_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tc_action_net_init(tn, &act_xt_ops, IPT_TAB_MASK);
+}
+
+static void __net_exit xt_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations xt_net_ops = {
+       .init = xt_init_net,
+       .exit = xt_exit_net,
+       .id   = &xt_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
@@ -289,12 +393,13 @@ static int __init ipt_init_module(void)
 {
        int ret1, ret2;
 
-       ret1 = tcf_register_action(&act_xt_ops, IPT_TAB_MASK);
+       ret1 = tcf_register_action(&act_xt_ops, &xt_net_ops);
        if (ret1 < 0)
-               printk("Failed to load xt action\n");
-       ret2 = tcf_register_action(&act_ipt_ops, IPT_TAB_MASK);
+               pr_err("Failed to load xt action\n");
+
+       ret2 = tcf_register_action(&act_ipt_ops, &ipt_net_ops);
        if (ret2 < 0)
-               printk("Failed to load ipt action\n");
+               pr_err("Failed to load ipt action\n");
 
        if (ret1 < 0 && ret2 < 0) {
                return ret1;
@@ -304,8 +409,8 @@ static int __init ipt_init_module(void)
 
 static void __exit ipt_cleanup_module(void)
 {
-       tcf_unregister_action(&act_xt_ops);
-       tcf_unregister_action(&act_ipt_ops);
+       tcf_unregister_action(&act_ipt_ops, &ipt_net_ops);
+       tcf_unregister_action(&act_xt_ops, &xt_net_ops);
 }
 
 module_init(ipt_init_module);
diff --git a/net/sched/act_meta_mark.c b/net/sched/act_meta_mark.c
new file mode 100644 (file)
index 0000000..8289217
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * net/sched/act_meta_mark.c IFE skb->mark metadata module
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * copyright Jamal Hadi Salim (2015)
+ *
+*/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <uapi/linux/tc_act/tc_ife.h>
+#include <net/tc_act/tc_ife.h>
+#include <linux/rtnetlink.h>
+
+static int skbmark_encode(struct sk_buff *skb, void *skbdata,
+                         struct tcf_meta_info *e)
+{
+       u32 ifemark = skb->mark;
+
+       return ife_encode_meta_u32(ifemark, skbdata, e);
+}
+
+static int skbmark_decode(struct sk_buff *skb, void *data, u16 len)
+{
+       u32 ifemark = *(u32 *)data;
+
+       skb->mark = ntohl(ifemark);
+       return 0;
+}
+
+static int skbmark_check(struct sk_buff *skb, struct tcf_meta_info *e)
+{
+       return ife_check_meta_u32(skb->mark, e);
+}
+
+static struct tcf_meta_ops ife_skbmark_ops = {
+       .metaid = IFE_META_SKBMARK,
+       .metatype = NLA_U32,
+       .name = "skbmark",
+       .synopsis = "skb mark 32 bit metadata",
+       .check_presence = skbmark_check,
+       .encode = skbmark_encode,
+       .decode = skbmark_decode,
+       .get = ife_get_meta_u32,
+       .alloc = ife_alloc_meta_u32,
+       .release = ife_release_meta_gen,
+       .validate = ife_validate_meta_u32,
+       .owner = THIS_MODULE,
+};
+
+static int __init ifemark_init_module(void)
+{
+       return register_ife_op(&ife_skbmark_ops);
+}
+
+static void __exit ifemark_cleanup_module(void)
+{
+       unregister_ife_op(&ife_skbmark_ops);
+}
+
+module_init(ifemark_init_module);
+module_exit(ifemark_cleanup_module);
+
+MODULE_AUTHOR("Jamal Hadi Salim(2015)");
+MODULE_DESCRIPTION("Inter-FE skb mark metadata module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_IFE_META(IFE_META_SKBMARK);
diff --git a/net/sched/act_meta_skbprio.c b/net/sched/act_meta_skbprio.c
new file mode 100644 (file)
index 0000000..26bf4d8
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * net/sched/act_meta_prio.c IFE skb->priority metadata module
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * copyright Jamal Hadi Salim (2015)
+ *
+*/
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <uapi/linux/tc_act/tc_ife.h>
+#include <net/tc_act/tc_ife.h>
+
+static int skbprio_check(struct sk_buff *skb, struct tcf_meta_info *e)
+{
+       return ife_check_meta_u32(skb->priority, e);
+}
+
+static int skbprio_encode(struct sk_buff *skb, void *skbdata,
+                         struct tcf_meta_info *e)
+{
+       u32 ifeprio = skb->priority; /* avoid having to cast skb->priority*/
+
+       return ife_encode_meta_u32(ifeprio, skbdata, e);
+}
+
+static int skbprio_decode(struct sk_buff *skb, void *data, u16 len)
+{
+       u32 ifeprio = *(u32 *)data;
+
+       skb->priority = ntohl(ifeprio);
+       return 0;
+}
+
+static struct tcf_meta_ops ife_prio_ops = {
+       .metaid = IFE_META_PRIO,
+       .metatype = NLA_U32,
+       .name = "skbprio",
+       .synopsis = "skb prio metadata",
+       .check_presence = skbprio_check,
+       .encode = skbprio_encode,
+       .decode = skbprio_decode,
+       .get = ife_get_meta_u32,
+       .alloc = ife_alloc_meta_u32,
+       .owner = THIS_MODULE,
+};
+
+static int __init ifeprio_init_module(void)
+{
+       return register_ife_op(&ife_prio_ops);
+}
+
+static void __exit ifeprio_cleanup_module(void)
+{
+       unregister_ife_op(&ife_prio_ops);
+}
+
+module_init(ifeprio_init_module);
+module_exit(ifeprio_cleanup_module);
+
+MODULE_AUTHOR("Jamal Hadi Salim(2015)");
+MODULE_DESCRIPTION("Inter-FE skb prio metadata action");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_IFE_META(IFE_META_PRIO);
index 32fcdecdb9e2074bad6f3e3002738e9c289317c3..e8a760cf7775ea1e3c9522376c3e3111a54a2ba6 100644 (file)
@@ -50,10 +50,13 @@ static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
        [TCA_MIRRED_PARMS]      = { .len = sizeof(struct tc_mirred) },
 };
 
+static int mirred_net_id;
+
 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                           struct nlattr *est, struct tc_action *a, int ovr,
                           int bind)
 {
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
        struct nlattr *tb[TCA_MIRRED_MAX + 1];
        struct tc_mirred *parm;
        struct tcf_mirred *m;
@@ -96,11 +99,11 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                dev = NULL;
        }
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
                if (dev == NULL)
                        return -EINVAL;
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*m),
-                                     bind, true);
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*m), bind, true);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
@@ -130,7 +133,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                spin_lock_bh(&mirred_list_lock);
                list_add(&m->tcfm_list, &mirred_list);
                spin_unlock_bh(&mirred_list_lock);
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        }
 
        return ret;
@@ -179,7 +182,6 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
 
        skb2->skb_iif = skb->dev->ifindex;
        skb2->dev = dev;
-       skb_sender_cpu_clear(skb2);
        err = dev_queue_xmit(skb2);
 
        if (err) {
@@ -221,6 +223,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
+                            struct netlink_callback *cb, int type,
+                            struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_mirred_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static int mirred_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
@@ -257,6 +275,29 @@ static struct tc_action_ops act_mirred_ops = {
        .dump           =       tcf_mirred_dump,
        .cleanup        =       tcf_mirred_release,
        .init           =       tcf_mirred_init,
+       .walk           =       tcf_mirred_walker,
+       .lookup         =       tcf_mirred_search,
+};
+
+static __net_init int mirred_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
+}
+
+static void __net_exit mirred_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations mirred_net_ops = {
+       .init = mirred_init_net,
+       .exit = mirred_exit_net,
+       .id   = &mirred_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002)");
@@ -270,12 +311,12 @@ static int __init mirred_init_module(void)
                return err;
 
        pr_info("Mirror/redirect action on\n");
-       return tcf_register_action(&act_mirred_ops, MIRRED_TAB_MASK);
+       return tcf_register_action(&act_mirred_ops, &mirred_net_ops);
 }
 
 static void __exit mirred_cleanup_module(void)
 {
-       tcf_unregister_action(&act_mirred_ops);
+       tcf_unregister_action(&act_mirred_ops, &mirred_net_ops);
        unregister_netdevice_notifier(&mirred_device_notifier);
 }
 
index b7c4ead8b5a8e863d87f8c1c4c1e37840fe50577..0f65cdfbfb1d364529feaf701f1c188bb9570973 100644 (file)
@@ -31,6 +31,8 @@
 
 #define NAT_TAB_MASK   15
 
+static int nat_net_id;
+
 static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
        [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) },
 };
@@ -38,6 +40,7 @@ static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                        struct tc_action *a, int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
        struct nlattr *tb[TCA_NAT_MAX + 1];
        struct tc_nat *parm;
        int ret = 0, err;
@@ -54,9 +57,9 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        parm = nla_data(tb[TCA_NAT_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
@@ -79,7 +82,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        spin_unlock_bh(&p->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
 
        return ret;
 }
@@ -126,9 +129,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
                addr = iph->daddr;
 
        if (!((old_addr ^ addr) & mask)) {
-               if (skb_cloned(skb) &&
-                   !skb_clone_writable(skb, sizeof(*iph) + noff) &&
-                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+               if (skb_try_make_writable(skb, sizeof(*iph) + noff))
                        goto drop;
 
                new_addr &= mask;
@@ -156,9 +157,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
                struct tcphdr *tcph;
 
                if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) ||
-                   (skb_cloned(skb) &&
-                    !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) &&
-                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+                   skb_try_make_writable(skb, ihl + sizeof(*tcph) + noff))
                        goto drop;
 
                tcph = (void *)(skb_network_header(skb) + ihl);
@@ -171,9 +170,7 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
                struct udphdr *udph;
 
                if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) ||
-                   (skb_cloned(skb) &&
-                    !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) &&
-                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+                   skb_try_make_writable(skb, ihl + sizeof(*udph) + noff))
                        goto drop;
 
                udph = (void *)(skb_network_header(skb) + ihl);
@@ -213,10 +210,8 @@ static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
                if ((old_addr ^ addr) & mask)
                        break;
 
-               if (skb_cloned(skb) &&
-                   !skb_clone_writable(skb, ihl + sizeof(*icmph) +
-                                            sizeof(*iph) + noff) &&
-                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+               if (skb_try_make_writable(skb, ihl + sizeof(*icmph) +
+                                         sizeof(*iph) + noff))
                        goto drop;
 
                icmph = (void *)(skb_network_header(skb) + ihl);
@@ -282,6 +277,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_nat_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_nat_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_nat_ops = {
        .kind           =       "nat",
        .type           =       TCA_ACT_NAT,
@@ -289,6 +300,29 @@ static struct tc_action_ops act_nat_ops = {
        .act            =       tcf_nat,
        .dump           =       tcf_nat_dump,
        .init           =       tcf_nat_init,
+       .walk           =       tcf_nat_walker,
+       .lookup         =       tcf_nat_search,
+};
+
+static __net_init int nat_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tc_action_net_init(tn, &act_nat_ops, NAT_TAB_MASK);
+}
+
+static void __net_exit nat_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations nat_net_ops = {
+       .init = nat_init_net,
+       .exit = nat_exit_net,
+       .id   = &nat_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_DESCRIPTION("Stateless NAT actions");
@@ -296,12 +330,12 @@ MODULE_LICENSE("GPL");
 
 static int __init nat_init_module(void)
 {
-       return tcf_register_action(&act_nat_ops, NAT_TAB_MASK);
+       return tcf_register_action(&act_nat_ops, &nat_net_ops);
 }
 
 static void __exit nat_cleanup_module(void)
 {
-       tcf_unregister_action(&act_nat_ops);
+       tcf_unregister_action(&act_nat_ops, &nat_net_ops);
 }
 
 module_init(nat_init_module);
index e38a7701f154c97db2070b1e0b8b54fabdb8b0f3..429c3ab65142671e1d6d12a92b991fa5aec55a04 100644 (file)
@@ -25,6 +25,8 @@
 
 #define PEDIT_TAB_MASK 15
 
+static int pedit_net_id;
+
 static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
        [TCA_PEDIT_PARMS]       = { .len = sizeof(struct tc_pedit) },
 };
@@ -33,6 +35,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                          struct nlattr *est, struct tc_action *a,
                          int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
        struct nlattr *tb[TCA_PEDIT_MAX + 1];
        struct tc_pedit *parm;
        int ret = 0, err;
@@ -54,11 +57,11 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize)
                return -EINVAL;
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
                if (!parm->nkeys)
                        return -EINVAL;
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                p = to_pedit(a);
@@ -93,7 +96,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        memcpy(p->tcfp_keys, parm->keys, ksize);
        spin_unlock_bh(&p->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
@@ -211,6 +214,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_pedit_walker(struct net *net, struct sk_buff *skb,
+                           struct netlink_callback *cb, int type,
+                           struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_pedit_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_pedit_ops = {
        .kind           =       "pedit",
        .type           =       TCA_ACT_PEDIT,
@@ -219,6 +238,29 @@ static struct tc_action_ops act_pedit_ops = {
        .dump           =       tcf_pedit_dump,
        .cleanup        =       tcf_pedit_cleanup,
        .init           =       tcf_pedit_init,
+       .walk           =       tcf_pedit_walker,
+       .lookup         =       tcf_pedit_search,
+};
+
+static __net_init int pedit_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tc_action_net_init(tn, &act_pedit_ops, PEDIT_TAB_MASK);
+}
+
+static void __net_exit pedit_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations pedit_net_ops = {
+       .init = pedit_init_net,
+       .exit = pedit_exit_net,
+       .id   = &pedit_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
@@ -227,12 +269,12 @@ MODULE_LICENSE("GPL");
 
 static int __init pedit_init_module(void)
 {
-       return tcf_register_action(&act_pedit_ops, PEDIT_TAB_MASK);
+       return tcf_register_action(&act_pedit_ops, &pedit_net_ops);
 }
 
 static void __exit pedit_cleanup_module(void)
 {
-       tcf_unregister_action(&act_pedit_ops);
+       tcf_unregister_action(&act_pedit_ops, &pedit_net_ops);
 }
 
 module_init(pedit_init_module);
index 9a1c42a43f92e7d1015fcf153cb2a761abfe2263..330f14e302e884fa65fc1eea895b8ea4a123d783 100644 (file)
@@ -55,10 +55,14 @@ struct tc_police_compat {
 
 /* Each policer is serialized by its individual spinlock */
 
-static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                             int type, struct tc_action *a)
+static int police_net_id;
+
+static int tcf_act_police_walker(struct net *net, struct sk_buff *skb,
+                                struct netlink_callback *cb, int type,
+                                struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct hlist_head *head;
        struct tcf_common *p;
        int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
@@ -121,7 +125,8 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla,
        struct tc_police *parm;
        struct tcf_police *police;
        struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        int size;
 
        if (nla == NULL)
@@ -139,7 +144,7 @@ static int tcf_act_police_locate(struct net *net, struct nlattr *nla,
        parm = nla_data(tb[TCA_POLICE_TBF]);
 
        if (parm->index) {
-               if (tcf_hash_search(a, parm->index)) {
+               if (tcf_hash_search(tn, a, parm->index)) {
                        police = to_police(a->priv);
                        if (bind) {
                                police->tcf_bindcnt += 1;
@@ -233,7 +238,7 @@ override:
 
        police->tcfp_t_c = ktime_get_ns();
        police->tcf_index = parm->index ? parm->index :
-               tcf_hash_new_index(hinfo);
+               tcf_hash_new_index(tn);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
        spin_lock_bh(&hinfo->lock);
        hlist_add_head(&police->tcf_head, &hinfo->htab[h]);
@@ -342,6 +347,13 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_police_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 MODULE_AUTHOR("Alexey Kuznetsov");
 MODULE_DESCRIPTION("Policing actions");
 MODULE_LICENSE("GPL");
@@ -353,19 +365,41 @@ static struct tc_action_ops act_police_ops = {
        .act            =       tcf_act_police,
        .dump           =       tcf_act_police_dump,
        .init           =       tcf_act_police_locate,
-       .walk           =       tcf_act_police_walker
+       .walk           =       tcf_act_police_walker,
+       .lookup         =       tcf_police_search,
+};
+
+static __net_init int police_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       return tc_action_net_init(tn, &act_police_ops, POL_TAB_MASK);
+}
+
+static void __net_exit police_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations police_net_ops = {
+       .init = police_init_net,
+       .exit = police_exit_net,
+       .id   = &police_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init
 police_init_module(void)
 {
-       return tcf_register_action(&act_police_ops, POL_TAB_MASK);
+       return tcf_register_action(&act_police_ops, &police_net_ops);
 }
 
 static void __exit
 police_cleanup_module(void)
 {
-       tcf_unregister_action(&act_police_ops);
+       tcf_unregister_action(&act_police_ops, &police_net_ops);
 }
 
 module_init(police_init_module);
index d6b708d6afdf37e7c1af4e47873755fc84b1167f..75b2be13fbcc452da0a1379dd693fd9693b75e4d 100644 (file)
@@ -26,6 +26,8 @@
 
 #define SIMP_TAB_MASK     7
 
+static int simp_net_id;
+
 #define SIMP_MAX_DATA  32
 static int tcf_simp(struct sk_buff *skb, const struct tc_action *a,
                    struct tcf_result *res)
@@ -80,6 +82,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
        struct nlattr *tb[TCA_DEF_MAX + 1];
        struct tc_defact *parm;
        struct tcf_defact *d;
@@ -102,9 +105,9 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        parm = nla_data(tb[TCA_DEF_PARMS]);
        defdata = nla_data(tb[TCA_DEF_DATA]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*d), bind, false);
                if (ret)
                        return ret;
 
@@ -129,7 +132,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        }
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
@@ -161,6 +164,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_simp_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_simp_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_simp_ops = {
        .kind           =       "simple",
        .type           =       TCA_ACT_SIMP,
@@ -169,6 +188,29 @@ static struct tc_action_ops act_simp_ops = {
        .dump           =       tcf_simp_dump,
        .cleanup        =       tcf_simp_release,
        .init           =       tcf_simp_init,
+       .walk           =       tcf_simp_walker,
+       .lookup         =       tcf_simp_search,
+};
+
+static __net_init int simp_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tc_action_net_init(tn, &act_simp_ops, SIMP_TAB_MASK);
+}
+
+static void __net_exit simp_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations simp_net_ops = {
+       .init = simp_init_net,
+       .exit = simp_exit_net,
+       .id   = &simp_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2005)");
@@ -177,8 +219,7 @@ MODULE_LICENSE("GPL");
 
 static int __init simp_init_module(void)
 {
-       int ret;
-       ret = tcf_register_action(&act_simp_ops, SIMP_TAB_MASK);
+       int ret = tcf_register_action(&act_simp_ops, &simp_net_ops);
        if (!ret)
                pr_info("Simple TC action Loaded\n");
        return ret;
@@ -186,7 +227,7 @@ static int __init simp_init_module(void)
 
 static void __exit simp_cleanup_module(void)
 {
-       tcf_unregister_action(&act_simp_ops);
+       tcf_unregister_action(&act_simp_ops, &simp_net_ops);
 }
 
 module_init(simp_init_module);
index 6751b5f8c046a59912b78762855e51af8e6f29e7..cfcdbdc00c9bfef4702ae09875080cc0b3df11ea 100644 (file)
@@ -29,6 +29,8 @@
 
 #define SKBEDIT_TAB_MASK     15
 
+static int skbedit_net_id;
+
 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
                       struct tcf_result *res)
 {
@@ -61,6 +63,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
                            struct nlattr *est, struct tc_action *a,
                            int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
        struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
        struct tc_skbedit *parm;
        struct tcf_skbedit *d;
@@ -98,9 +101,9 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
 
        parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*d), bind, false);
                if (ret)
                        return ret;
 
@@ -130,7 +133,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        spin_unlock_bh(&d->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
@@ -173,6 +176,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb,
+                             struct netlink_callback *cb, int type,
+                             struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_skbedit_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
        .type           =       TCA_ACT_SKBEDIT,
@@ -180,6 +199,29 @@ static struct tc_action_ops act_skbedit_ops = {
        .act            =       tcf_skbedit,
        .dump           =       tcf_skbedit_dump,
        .init           =       tcf_skbedit_init,
+       .walk           =       tcf_skbedit_walker,
+       .lookup         =       tcf_skbedit_search,
+};
+
+static __net_init int skbedit_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tc_action_net_init(tn, &act_skbedit_ops, SKBEDIT_TAB_MASK);
+}
+
+static void __net_exit skbedit_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations skbedit_net_ops = {
+       .init = skbedit_init_net,
+       .exit = skbedit_exit_net,
+       .id   = &skbedit_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
@@ -188,12 +230,12 @@ MODULE_LICENSE("GPL");
 
 static int __init skbedit_init_module(void)
 {
-       return tcf_register_action(&act_skbedit_ops, SKBEDIT_TAB_MASK);
+       return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops);
 }
 
 static void __exit skbedit_cleanup_module(void)
 {
-       tcf_unregister_action(&act_skbedit_ops);
+       tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops);
 }
 
 module_init(skbedit_init_module);
index 796785e0bf96b0e65f598d3b2dad8256485d034a..bab8ae0cefc08800678415b163921c67a0e50e4e 100644 (file)
@@ -21,6 +21,8 @@
 
 #define VLAN_TAB_MASK     15
 
+static int vlan_net_id;
+
 static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
                    struct tcf_result *res)
 {
@@ -68,6 +70,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
        struct nlattr *tb[TCA_VLAN_MAX + 1];
        struct tc_vlan *parm;
        struct tcf_vlan *v;
@@ -115,9 +118,9 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        }
        action = parm->v_action;
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*v),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*v), bind, false);
                if (ret)
                        return ret;
 
@@ -143,7 +146,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        spin_unlock_bh(&v->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
@@ -181,6 +184,22 @@ nla_put_failure:
        return -1;
 }
 
+static int tcf_vlan_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_vlan_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_vlan_ops = {
        .kind           =       "vlan",
        .type           =       TCA_ACT_VLAN,
@@ -188,16 +207,39 @@ static struct tc_action_ops act_vlan_ops = {
        .act            =       tcf_vlan,
        .dump           =       tcf_vlan_dump,
        .init           =       tcf_vlan_init,
+       .walk           =       tcf_vlan_walker,
+       .lookup         =       tcf_vlan_search,
+};
+
+static __net_init int vlan_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tc_action_net_init(tn, &act_vlan_ops, VLAN_TAB_MASK);
+}
+
+static void __net_exit vlan_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations vlan_net_ops = {
+       .init = vlan_init_net,
+       .exit = vlan_exit_net,
+       .id   = &vlan_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init vlan_init_module(void)
 {
-       return tcf_register_action(&act_vlan_ops, VLAN_TAB_MASK);
+       return tcf_register_action(&act_vlan_ops, &vlan_net_ops);
 }
 
 static void __exit vlan_cleanup_module(void)
 {
-       tcf_unregister_action(&act_vlan_ops);
+       tcf_unregister_action(&act_vlan_ops, &vlan_net_ops);
 }
 
 module_init(vlan_init_module);
index 95b021243233bd46a9ef836b07b7c4671faa9e15..2181ffc76638035a93c077e7395d93892e82570e 100644 (file)
@@ -165,6 +165,51 @@ static void fl_destroy_filter(struct rcu_head *head)
        kfree(f);
 }
 
+static void fl_hw_destroy_filter(struct tcf_proto *tp, unsigned long cookie)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_flower_offload offload = {0};
+       struct tc_to_netdev tc;
+
+       if (!tc_should_offload(dev, 0))
+               return;
+
+       offload.command = TC_CLSFLOWER_DESTROY;
+       offload.cookie = cookie;
+
+       tc.type = TC_SETUP_CLSFLOWER;
+       tc.cls_flower = &offload;
+
+       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+}
+
+static void fl_hw_replace_filter(struct tcf_proto *tp,
+                                struct flow_dissector *dissector,
+                                struct fl_flow_key *mask,
+                                struct fl_flow_key *key,
+                                struct tcf_exts *actions,
+                                unsigned long cookie, u32 flags)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_flower_offload offload = {0};
+       struct tc_to_netdev tc;
+
+       if (!tc_should_offload(dev, flags))
+               return;
+
+       offload.command = TC_CLSFLOWER_REPLACE;
+       offload.cookie = cookie;
+       offload.dissector = dissector;
+       offload.mask = mask;
+       offload.key = key;
+       offload.exts = actions;
+
+       tc.type = TC_SETUP_CLSFLOWER;
+       tc.cls_flower = &offload;
+
+       dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol, &tc);
+}
+
 static bool fl_destroy(struct tcf_proto *tp, bool force)
 {
        struct cls_fl_head *head = rtnl_dereference(tp->root);
@@ -174,6 +219,7 @@ static bool fl_destroy(struct tcf_proto *tp, bool force)
                return false;
 
        list_for_each_entry_safe(f, next, &head->filters, list) {
+               fl_hw_destroy_filter(tp, (unsigned long)f);
                list_del_rcu(&f->list);
                call_rcu(&f->rcu, fl_destroy_filter);
        }
@@ -459,6 +505,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        struct cls_fl_filter *fnew;
        struct nlattr *tb[TCA_FLOWER_MAX + 1];
        struct fl_flow_mask mask = {};
+       u32 flags = 0;
        int err;
 
        if (!tca[TCA_OPTIONS])
@@ -486,6 +533,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
        }
        fnew->handle = handle;
 
+       if (tb[TCA_FLOWER_FLAGS])
+               flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
+
        err = fl_set_parms(net, tp, fnew, &mask, base, tb, tca[TCA_RATE], ovr);
        if (err)
                goto errout;
@@ -498,9 +548,20 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
                                     head->ht_params);
        if (err)
                goto errout;
-       if (fold)
+
+       fl_hw_replace_filter(tp,
+                            &head->dissector,
+                            &mask.key,
+                            &fnew->key,
+                            &fnew->exts,
+                            (unsigned long)fnew,
+                            flags);
+
+       if (fold) {
                rhashtable_remove_fast(&head->ht, &fold->ht_node,
                                       head->ht_params);
+               fl_hw_destroy_filter(tp, (unsigned long)fold);
+       }
 
        *arg = (unsigned long) fnew;
 
@@ -527,6 +588,7 @@ static int fl_delete(struct tcf_proto *tp, unsigned long arg)
        rhashtable_remove_fast(&head->ht, &f->ht_node,
                               head->ht_params);
        list_del_rcu(&f->list);
+       fl_hw_destroy_filter(tp, (unsigned long)f);
        tcf_unbind_filter(tp, &f->res);
        call_rcu(&f->rcu, fl_destroy_filter);
        return 0;
index 4fbb67430ce4821fd66576132afec2d7a301b379..563cdad764485a2fbce96dcf27c4f777ea7d186e 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/netlink.h>
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
+#include <linux/netdevice.h>
 
 struct tc_u_knode {
        struct tc_u_knode __rcu *next;
@@ -58,6 +59,7 @@ struct tc_u_knode {
 #ifdef CONFIG_CLS_U32_PERF
        struct tc_u32_pcnt __percpu *pf;
 #endif
+       u32                     flags;
 #ifdef CONFIG_CLS_U32_MARK
        u32                     val;
        u32                     mask;
@@ -424,6 +426,97 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
        return 0;
 }
 
+static void u32_remove_hw_knode(struct tcf_proto *tp, u32 handle)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_u32_offload u32_offload = {0};
+       struct tc_to_netdev offload;
+
+       offload.type = TC_SETUP_CLSU32;
+       offload.cls_u32 = &u32_offload;
+
+       if (tc_should_offload(dev, 0)) {
+               offload.cls_u32->command = TC_CLSU32_DELETE_KNODE;
+               offload.cls_u32->knode.handle = handle;
+               dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
+                                             tp->protocol, &offload);
+       }
+}
+
+static void u32_replace_hw_hnode(struct tcf_proto *tp,
+                                struct tc_u_hnode *h,
+                                u32 flags)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_u32_offload u32_offload = {0};
+       struct tc_to_netdev offload;
+
+       offload.type = TC_SETUP_CLSU32;
+       offload.cls_u32 = &u32_offload;
+
+       if (tc_should_offload(dev, flags)) {
+               offload.cls_u32->command = TC_CLSU32_NEW_HNODE;
+               offload.cls_u32->hnode.divisor = h->divisor;
+               offload.cls_u32->hnode.handle = h->handle;
+               offload.cls_u32->hnode.prio = h->prio;
+
+               dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
+                                             tp->protocol, &offload);
+       }
+}
+
+static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_u32_offload u32_offload = {0};
+       struct tc_to_netdev offload;
+
+       offload.type = TC_SETUP_CLSU32;
+       offload.cls_u32 = &u32_offload;
+
+       if (tc_should_offload(dev, 0)) {
+               offload.cls_u32->command = TC_CLSU32_DELETE_HNODE;
+               offload.cls_u32->hnode.divisor = h->divisor;
+               offload.cls_u32->hnode.handle = h->handle;
+               offload.cls_u32->hnode.prio = h->prio;
+
+               dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
+                                             tp->protocol, &offload);
+       }
+}
+
+static void u32_replace_hw_knode(struct tcf_proto *tp,
+                                struct tc_u_knode *n,
+                                u32 flags)
+{
+       struct net_device *dev = tp->q->dev_queue->dev;
+       struct tc_cls_u32_offload u32_offload = {0};
+       struct tc_to_netdev offload;
+
+       offload.type = TC_SETUP_CLSU32;
+       offload.cls_u32 = &u32_offload;
+
+       if (tc_should_offload(dev, flags)) {
+               offload.cls_u32->command = TC_CLSU32_REPLACE_KNODE;
+               offload.cls_u32->knode.handle = n->handle;
+               offload.cls_u32->knode.fshift = n->fshift;
+#ifdef CONFIG_CLS_U32_MARK
+               offload.cls_u32->knode.val = n->val;
+               offload.cls_u32->knode.mask = n->mask;
+#else
+               offload.cls_u32->knode.val = 0;
+               offload.cls_u32->knode.mask = 0;
+#endif
+               offload.cls_u32->knode.sel = &n->sel;
+               offload.cls_u32->knode.exts = &n->exts;
+               if (n->ht_down)
+                       offload.cls_u32->knode.link_handle = n->ht_down->handle;
+
+               dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle,
+                                             tp->protocol, &offload);
+       }
+}
+
 static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
 {
        struct tc_u_knode *n;
@@ -434,6 +527,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
                        RCU_INIT_POINTER(ht->ht[h],
                                         rtnl_dereference(n->next));
                        tcf_unbind_filter(tp, &n->res);
+                       u32_remove_hw_knode(tp, n->handle);
                        call_rcu(&n->rcu, u32_delete_key_freepf_rcu);
                }
        }
@@ -454,6 +548,7 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
             phn;
             hn = &phn->next, phn = rtnl_dereference(*hn)) {
                if (phn == ht) {
+                       u32_clear_hw_hnode(tp, ht);
                        RCU_INIT_POINTER(*hn, ht->next);
                        kfree_rcu(ht, rcu);
                        return 0;
@@ -540,8 +635,10 @@ static int u32_delete(struct tcf_proto *tp, unsigned long arg)
        if (ht == NULL)
                return 0;
 
-       if (TC_U32_KEY(ht->handle))
+       if (TC_U32_KEY(ht->handle)) {
+               u32_remove_hw_knode(tp, ht->handle);
                return u32_delete_key(tp, (struct tc_u_knode *)ht);
+       }
 
        if (root_ht == ht)
                return -EINVAL;
@@ -587,6 +684,7 @@ static const struct nla_policy u32_policy[TCA_U32_MAX + 1] = {
        [TCA_U32_SEL]           = { .len = sizeof(struct tc_u32_sel) },
        [TCA_U32_INDEV]         = { .type = NLA_STRING, .len = IFNAMSIZ },
        [TCA_U32_MARK]          = { .len = sizeof(struct tc_u32_mark) },
+       [TCA_U32_FLAGS]         = { .type = NLA_U32 },
 };
 
 static int u32_set_parms(struct net *net, struct tcf_proto *tp,
@@ -694,6 +792,7 @@ static struct tc_u_knode *u32_init_knode(struct tcf_proto *tp,
 #endif
        new->fshift = n->fshift;
        new->res = n->res;
+       new->flags = n->flags;
        RCU_INIT_POINTER(new->ht_down, n->ht_down);
 
        /* bump reference count as long as we hold pointer to structure */
@@ -733,7 +832,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        struct tc_u32_sel *s;
        struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_U32_MAX + 1];
-       u32 htid;
+       u32 htid, flags = 0;
        int err;
 #ifdef CONFIG_CLS_U32_PERF
        size_t size;
@@ -746,6 +845,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        if (err < 0)
                return err;
 
+       if (tb[TCA_U32_FLAGS])
+               flags = nla_get_u32(tb[TCA_U32_FLAGS]);
+
        n = (struct tc_u_knode *)*arg;
        if (n) {
                struct tc_u_knode *new;
@@ -753,6 +855,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                if (TC_U32_KEY(n->handle) == 0)
                        return -EINVAL;
 
+               if (n->flags != flags)
+                       return -EINVAL;
+
                new = u32_init_knode(tp, n);
                if (!new)
                        return -ENOMEM;
@@ -769,6 +874,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                u32_replace_knode(tp, tp_c, new);
                tcf_unbind_filter(tp, &n->res);
                call_rcu(&n->rcu, u32_delete_key_rcu);
+               u32_replace_hw_knode(tp, new, flags);
                return 0;
        }
 
@@ -795,6 +901,8 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
                RCU_INIT_POINTER(ht->next, tp_c->hlist);
                rcu_assign_pointer(tp_c->hlist, ht);
                *arg = (unsigned long)ht;
+
+               u32_replace_hw_hnode(tp, ht, flags);
                return 0;
        }
 
@@ -845,6 +953,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
        RCU_INIT_POINTER(n->ht_up, ht);
        n->handle = handle;
        n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
+       n->flags = flags;
        tcf_exts_init(&n->exts, TCA_U32_ACT, TCA_U32_POLICE);
        n->tp = tp;
 
@@ -877,7 +986,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
 
                RCU_INIT_POINTER(n->next, pins);
                rcu_assign_pointer(*ins, n);
-
+               u32_replace_hw_knode(tp, n, flags);
                *arg = (unsigned long)n;
                return 0;
        }
@@ -982,6 +1091,9 @@ static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                    nla_put_u32(skb, TCA_U32_LINK, ht_down->handle))
                        goto nla_put_failure;
 
+               if (n->flags && nla_put_u32(skb, TCA_U32_FLAGS, n->flags))
+                       goto nla_put_failure;
+
 #ifdef CONFIG_CLS_U32_MARK
                if ((n->val || n->mask)) {
                        struct tc_u32_mark mark = {.val = n->val,
index b5c2cf2aa6d4bc00e5c4bac2b3326db3d785c8be..3b180ff72f79f838deac16ce9fc69e9ef28b2c0c 100644 (file)
@@ -744,14 +744,15 @@ static u32 qdisc_alloc_handle(struct net_device *dev)
        return 0;
 }
 
-void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
+void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n,
+                              unsigned int len)
 {
        const struct Qdisc_class_ops *cops;
        unsigned long cl;
        u32 parentid;
        int drops;
 
-       if (n == 0)
+       if (n == 0 && len == 0)
                return;
        drops = max_t(int, n, 0);
        rcu_read_lock();
@@ -774,11 +775,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
                        cops->put(sch, cl);
                }
                sch->q.qlen -= n;
+               sch->qstats.backlog -= len;
                __qdisc_qstats_drop(sch, drops);
        }
        rcu_read_unlock();
 }
-EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
+EXPORT_SYMBOL(qdisc_tree_reduce_backlog);
 
 static void notify_and_destroy(struct net *net, struct sk_buff *skb,
                               struct nlmsghdr *n, u32 clid,
@@ -1841,7 +1843,7 @@ reclassify:
                        return err;
        }
 
-       return -1;
+       return TC_ACT_UNSPEC; /* signal: continue lookup */
 #ifdef CONFIG_NET_CLS_ACT
 reset:
        if (unlikely(limit++ >= MAX_REC_LOOP)) {
@@ -1852,6 +1854,7 @@ reset:
        }
 
        tp = old_tp;
+       protocol = tc_skb_protocol(skb);
        goto reclassify;
 #endif
 }
index c538d9e4a8f6c02b0f895fdb8de7951b41069be7..baafddf229ce98e8a4b4f2d1351845df269847fc 100644 (file)
@@ -1624,13 +1624,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                        new->reshape_fail = cbq_reshape_fail;
 #endif
        }
-       sch_tree_lock(sch);
-       *old = cl->q;
-       cl->q = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
 
+       *old = qdisc_replace(sch, new, &cl->q);
        return 0;
 }
 
@@ -1914,7 +1909,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct cbq_sched_data *q = qdisc_priv(sch);
        struct cbq_class *cl = (struct cbq_class *)arg;
-       unsigned int qlen;
+       unsigned int qlen, backlog;
 
        if (cl->filters || cl->children || cl == &q->link)
                return -EBUSY;
@@ -1922,8 +1917,9 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        qlen = cl->q->q.qlen;
+       backlog = cl->q->qstats.backlog;
        qdisc_reset(cl->q);
-       qdisc_tree_decrease_qlen(cl->q, qlen);
+       qdisc_tree_reduce_backlog(cl->q, qlen, backlog);
 
        if (cl->next_alive)
                cbq_deactivate_class(cl);
index 5ffb8b8337c7320368303e21a4bbd1fc0e4c5168..0a08c860eee4f35905907ce1eab38d6152c4487c 100644 (file)
@@ -128,8 +128,8 @@ static void choke_drop_by_idx(struct Qdisc *sch, unsigned int idx)
                choke_zap_tail_holes(q);
 
        qdisc_qstats_backlog_dec(sch, skb);
+       qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
        qdisc_drop(skb, sch);
-       qdisc_tree_decrease_qlen(sch, 1);
        --sch->q.qlen;
 }
 
@@ -456,6 +456,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                old = q->tab;
                if (old) {
                        unsigned int oqlen = sch->q.qlen, tail = 0;
+                       unsigned dropped = 0;
 
                        while (q->head != q->tail) {
                                struct sk_buff *skb = q->tab[q->head];
@@ -467,11 +468,12 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt)
                                        ntab[tail++] = skb;
                                        continue;
                                }
+                               dropped += qdisc_pkt_len(skb);
                                qdisc_qstats_backlog_dec(sch, skb);
                                --sch->q.qlen;
                                qdisc_drop(skb, sch);
                        }
-                       qdisc_tree_decrease_qlen(sch, oqlen - sch->q.qlen);
+                       qdisc_tree_reduce_backlog(sch, oqlen - sch->q.qlen, dropped);
                        q->head = 0;
                        q->tail = tail;
                }
index 535007d5f0b523b13bffac7e314710f58d9ce7ef..9b7e2980ee5c64c18477d003957fedd10c1718d5 100644 (file)
@@ -79,12 +79,13 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch)
 
        skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue);
 
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->stats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->stats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
                q->stats.drop_count = 0;
+               q->stats.drop_len = 0;
        }
        if (skb)
                qdisc_bstats_update(sch, skb);
@@ -116,7 +117,7 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct codel_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_CODEL_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -156,10 +157,11 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index a1cd778240cd7f2b14336c26ba6eec282c1c60b6..a63e879e89758fe954ab778fe776ddf6fc4e3536 100644 (file)
@@ -53,9 +53,10 @@ static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid)
 static void drr_purge_queue(struct drr_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = {
@@ -226,11 +227,7 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       drr_purge_queue(cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index f357f34d02d2a5e9f4ead0ebe77ec44dca79f89a..34b4ddaca27c7ca04ed1a6edb75adccd48e0c460 100644 (file)
@@ -73,13 +73,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       *old = p->q;
-       p->q = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &p->q);
        return 0;
 }
 
@@ -264,6 +258,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
        }
 
+       qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
 
        return NET_XMIT_SUCCESS;
@@ -281,11 +276,12 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch)
 
        pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
 
-       skb = p->q->ops->dequeue(p->q);
+       skb = qdisc_dequeue_peeked(p->q);
        if (skb == NULL)
                return NULL;
 
        qdisc_bstats_update(sch, skb);
+       qdisc_qstats_backlog_dec(sch, skb);
        sch->q.qlen--;
 
        index = skb->tc_index & (p->indices - 1);
@@ -401,6 +397,7 @@ static void dsmark_reset(struct Qdisc *sch)
 
        pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
        qdisc_reset(p->q);
+       sch->qstats.backlog = 0;
        sch->q.qlen = 0;
 }
 
index 109b2322778f2353d82ebfbc8e40578e80ae7099..3c6a47d66a047da8765c9e90b808629a87afc0ea 100644 (file)
@@ -662,6 +662,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
        struct fq_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_FQ_MAX + 1];
        int err, drop_count = 0;
+       unsigned drop_len = 0;
        u32 fq_log;
 
        if (!opt)
@@ -736,10 +737,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
 
                if (!skb)
                        break;
+               drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, drop_count);
+       qdisc_tree_reduce_backlog(sch, drop_count, drop_len);
 
        sch_tree_unlock(sch);
        return err;
index 4c834e93dafbe27bea51435113552819f7496d5b..d3fc8f9dd3d464a23f9ea924fc00154a861eda26 100644 (file)
@@ -175,7 +175,7 @@ static unsigned int fq_codel_qdisc_drop(struct Qdisc *sch)
 static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct fq_codel_sched_data *q = qdisc_priv(sch);
-       unsigned int idx;
+       unsigned int idx, prev_backlog;
        struct fq_codel_flow *flow;
        int uninitialized_var(ret);
 
@@ -203,6 +203,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
@@ -211,7 +212,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -241,6 +242,7 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)
        struct fq_codel_flow *flow;
        struct list_head *head;
        u32 prev_drop_count, prev_ecn_mark;
+       unsigned int prev_backlog;
 
 begin:
        head = &q->new_flows;
@@ -259,6 +261,7 @@ begin:
 
        prev_drop_count = q->cstats.drop_count;
        prev_ecn_mark = q->cstats.ecn_mark;
+       prev_backlog = sch->qstats.backlog;
 
        skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats,
                            dequeue);
@@ -276,12 +279,14 @@ begin:
        }
        qdisc_bstats_update(sch, skb);
        flow->deficit -= qdisc_pkt_len(skb);
-       /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0,
+       /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
         * or HTB crashes. Defer it for next round.
         */
        if (q->cstats.drop_count && sch->q.qlen) {
-               qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+               qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
+                                         q->cstats.drop_len);
                q->cstats.drop_count = 0;
+               q->cstats.drop_len = 0;
        }
        return skb;
 }
@@ -372,11 +377,13 @@ static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_codel_dequeue(sch);
 
+               q->cstats.drop_len += qdisc_pkt_len(skb);
                kfree_skb(skb);
                q->cstats.drop_count++;
        }
-       qdisc_tree_decrease_qlen(sch, q->cstats.drop_count);
+       qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, q->cstats.drop_len);
        q->cstats.drop_count = 0;
+       q->cstats.drop_len = 0;
 
        sch_tree_unlock(sch);
        return 0;
index 16bc83b2842a74616cd58dd923a5981942321f3e..f18c3502420730e87254a6b01f0a6c1e4fb96941 100644 (file)
@@ -567,6 +567,7 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = {
        .dump           =       pfifo_fast_dump,
        .owner          =       THIS_MODULE,
 };
+EXPORT_SYMBOL(pfifo_fast_ops);
 
 static struct lock_class_key qdisc_tx_busylock;
 
index b7ebe2c87586416d615a13ce470bdfddf117a80d..d783d7cc33487f284677e107f5083588f559f742 100644 (file)
@@ -895,9 +895,10 @@ static void
 hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static void
@@ -1215,11 +1216,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       hfsc_purge_queue(sch, cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index 86b04e31e60b76027214b85ee0c4c0e0de1b04c4..13d6f83ec4913f6eb8cdefa1bf3c363792c0a510 100644 (file)
@@ -382,6 +382,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        struct hhf_sched_data *q = qdisc_priv(sch);
        enum wdrr_bucket_idx idx;
        struct wdrr_bucket *bucket;
+       unsigned int prev_backlog;
 
        idx = hhf_classify(skb, sch);
 
@@ -409,6 +410,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
+       prev_backlog = sch->qstats.backlog;
        q->drop_overlimit++;
        /* Return Congestion Notification only if we dropped a packet from this
         * bucket.
@@ -417,7 +419,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this. */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, prev_backlog - sch->qstats.backlog);
        return NET_XMIT_SUCCESS;
 }
 
@@ -527,7 +529,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct hhf_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_HHF_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, prev_backlog;
        int err;
        u64 non_hh_quantum;
        u32 new_quantum = q->quantum;
@@ -577,12 +579,14 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
        }
 
        qlen = sch->q.qlen;
+       prev_backlog = sch->qstats.backlog;
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = hhf_dequeue(sch);
 
                kfree_skb(skb);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen,
+                                 prev_backlog - sch->qstats.backlog);
 
        sch_tree_unlock(sch);
        return 0;
index 15ccd7f8fb2ae35d940119e203259bb67e6e807d..87b02ed3d5f212cee3e5bf871c71b72b6329a8aa 100644 (file)
@@ -600,6 +600,7 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                htb_activate(q, cl);
        }
 
+       qdisc_qstats_backlog_inc(sch, skb);
        sch->q.qlen++;
        return NET_XMIT_SUCCESS;
 }
@@ -889,6 +890,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch)
 ok:
                qdisc_bstats_update(sch, skb);
                qdisc_unthrottled(sch);
+               qdisc_qstats_backlog_dec(sch, skb);
                sch->q.qlen--;
                return skb;
        }
@@ -955,6 +957,7 @@ static unsigned int htb_drop(struct Qdisc *sch)
                        unsigned int len;
                        if (cl->un.leaf.q->ops->drop &&
                            (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
+                               sch->qstats.backlog -= len;
                                sch->q.qlen--;
                                if (!cl->un.leaf.q->q.qlen)
                                        htb_deactivate(q, cl);
@@ -984,12 +987,12 @@ static void htb_reset(struct Qdisc *sch)
                        }
                        cl->prio_activity = 0;
                        cl->cmode = HTB_CAN_SEND;
-
                }
        }
        qdisc_watchdog_cancel(&q->watchdog);
        __skb_queue_purge(&q->direct_queue);
        sch->q.qlen = 0;
+       sch->qstats.backlog = 0;
        memset(q->hlevel, 0, sizeof(q->hlevel));
        memset(q->row_mask, 0, sizeof(q->row_mask));
        for (i = 0; i < TC_HTB_NUMPRIO; i++)
@@ -1163,14 +1166,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
                                     cl->common.classid)) == NULL)
                return -ENOBUFS;
 
-       sch_tree_lock(sch);
-       *old = cl->un.leaf.q;
-       cl->un.leaf.q = new;
-       if (*old != NULL) {
-               qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-               qdisc_reset(*old);
-       }
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->un.leaf.q);
        return 0;
 }
 
@@ -1272,7 +1268,6 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
 {
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)arg;
-       unsigned int qlen;
        struct Qdisc *new_q = NULL;
        int last_child = 0;
 
@@ -1292,9 +1287,11 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
        sch_tree_lock(sch);
 
        if (!cl->level) {
-               qlen = cl->un.leaf.q->q.qlen;
+               unsigned int qlen = cl->un.leaf.q->q.qlen;
+               unsigned int backlog = cl->un.leaf.q->qstats.backlog;
+
                qdisc_reset(cl->un.leaf.q);
-               qdisc_tree_decrease_qlen(cl->un.leaf.q, qlen);
+               qdisc_tree_reduce_backlog(cl->un.leaf.q, qlen, backlog);
        }
 
        /* delete from hash and active; remainder in destroy_class */
@@ -1428,10 +1425,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                sch_tree_lock(sch);
                if (parent && !parent->level) {
                        unsigned int qlen = parent->un.leaf.q->q.qlen;
+                       unsigned int backlog = parent->un.leaf.q->qstats.backlog;
 
                        /* turn parent into inner node */
                        qdisc_reset(parent->un.leaf.q);
-                       qdisc_tree_decrease_qlen(parent->un.leaf.q, qlen);
+                       qdisc_tree_reduce_backlog(parent->un.leaf.q, qlen, backlog);
                        qdisc_destroy(parent->un.leaf.q);
                        if (parent->prio_activity)
                                htb_deactivate(q, parent);
index 3e82f047caaf40461c9f408bd0572a64147e1a8f..56a77b878eb350f30b70561b593fc5ed36951abd 100644 (file)
@@ -57,7 +57,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
 
        for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
                dev_queue = netdev_get_tx_queue(dev, ntx);
-               qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
+               qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx),
                                          TC_H_MAKE(TC_H_MAJ(sch->handle),
                                                    TC_H_MIN(ntx + 1)));
                if (qdisc == NULL)
index ad70ecf57ce793d7b50b50e9220c24fa4ab30ab5..b8002ce3d0108263fd0c4ab4cd1b9946820dd4d6 100644 (file)
@@ -28,6 +28,7 @@ static void mqprio_destroy(struct Qdisc *sch)
 {
        struct net_device *dev = qdisc_dev(sch);
        struct mqprio_sched *priv = qdisc_priv(sch);
+       struct tc_to_netdev tc = {.type = TC_SETUP_MQPRIO};
        unsigned int ntx;
 
        if (priv->qdiscs) {
@@ -39,7 +40,7 @@ static void mqprio_destroy(struct Qdisc *sch)
        }
 
        if (priv->hw_owned && dev->netdev_ops->ndo_setup_tc)
-               dev->netdev_ops->ndo_setup_tc(dev, 0);
+               dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc);
        else
                netdev_set_num_tc(dev, 0);
 }
@@ -124,7 +125,8 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                dev_queue = netdev_get_tx_queue(dev, i);
-               qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops,
+               qdisc = qdisc_create_dflt(dev_queue,
+                                         get_default_qdisc_ops(dev, i),
                                          TC_H_MAKE(TC_H_MAJ(sch->handle),
                                                    TC_H_MIN(i + 1)));
                if (qdisc == NULL) {
@@ -140,8 +142,11 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
         * supplied and verified mapping
         */
        if (qopt->hw) {
+               struct tc_to_netdev tc = {.type = TC_SETUP_MQPRIO,
+                                         { .tc = qopt->num_tc }};
+
                priv->hw_owned = 1;
-               err = dev->netdev_ops->ndo_setup_tc(dev, qopt->num_tc);
+               err = dev->netdev_ops->ndo_setup_tc(dev, sch->handle, 0, &tc);
                if (err)
                        goto err;
        } else {
index 4e904ca0af9d1630c4828a6316025c781daae38b..bcdd54bb101cc8f25c1b6202a7aaef9b3293d996 100644 (file)
@@ -218,7 +218,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                if (q->queues[i] != &noop_qdisc) {
                        struct Qdisc *child = q->queues[i];
                        q->queues[i] = &noop_qdisc;
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen,
+                                                 child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -238,8 +239,9 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
@@ -303,13 +305,7 @@ static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->queues[band];
-       q->queues[band] = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->queues[band]);
        return 0;
 }
 
index 5abd1d9de989e6c9777a225c03e42f8194ebda33..9640bb39a5d293d55a96edc5164d369c1cded127 100644 (file)
@@ -598,7 +598,8 @@ deliver:
                                if (unlikely(err != NET_XMIT_SUCCESS)) {
                                        if (net_xmit_drop_count(err)) {
                                                qdisc_qstats_drop(sch);
-                                               qdisc_tree_decrease_qlen(sch, 1);
+                                               qdisc_tree_reduce_backlog(sch, 1,
+                                                                         qdisc_pkt_len(skb));
                                        }
                                }
                                goto tfifo_dequeue;
@@ -1037,15 +1038,7 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 {
        struct netem_sched_data *q = qdisc_priv(sch);
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       if (*old) {
-               qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-               qdisc_reset(*old);
-       }
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index b783a446d884d85af054c9a139f91a63a162bc9f..71ae3b9629f94f8520e557f21962fc9ab34366fb 100644 (file)
@@ -183,7 +183,7 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
 {
        struct pie_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_PIE_MAX + 1];
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        int err;
 
        if (!opt)
@@ -232,10 +232,11 @@ static int pie_change(struct Qdisc *sch, struct nlattr *opt)
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = __skb_dequeue(&sch->q);
 
+               dropped += qdisc_pkt_len(skb);
                qdisc_qstats_backlog_dec(sch, skb);
                qdisc_drop(skb, sch);
        }
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        sch_tree_unlock(sch);
        return 0;
index ba6487f2741f9fb20e55d39eeab4e7448b76cdac..fee1b15506b299755c685502a4a33283b458fef5 100644 (file)
@@ -191,7 +191,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                struct Qdisc *child = q->queues[i];
                q->queues[i] = &noop_qdisc;
                if (child != &noop_qdisc) {
-                       qdisc_tree_decrease_qlen(child, child->q.qlen);
+                       qdisc_tree_reduce_backlog(child, child->q.qlen, child->qstats.backlog);
                        qdisc_destroy(child);
                }
        }
@@ -210,8 +210,9 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
                                q->queues[i] = child;
 
                                if (old != &noop_qdisc) {
-                                       qdisc_tree_decrease_qlen(old,
-                                                                old->q.qlen);
+                                       qdisc_tree_reduce_backlog(old,
+                                                                 old->q.qlen,
+                                                                 old->qstats.backlog);
                                        qdisc_destroy(old);
                                }
                                sch_tree_unlock(sch);
@@ -268,13 +269,7 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->queues[band];
-       q->queues[band] = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->queues[band]);
        return 0;
 }
 
index 3dc3a6e560520a6f3b9b3bdf3bfa88277a08c266..8d2d8d953432e83d8523cc42923793eb852f599c 100644 (file)
@@ -220,9 +220,10 @@ static struct qfq_class *qfq_find_class(struct Qdisc *sch, u32 classid)
 static void qfq_purge_queue(struct qfq_class *cl)
 {
        unsigned int len = cl->qdisc->q.qlen;
+       unsigned int backlog = cl->qdisc->qstats.backlog;
 
        qdisc_reset(cl->qdisc);
-       qdisc_tree_decrease_qlen(cl->qdisc, len);
+       qdisc_tree_reduce_backlog(cl->qdisc, len, backlog);
 }
 
 static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
@@ -617,11 +618,7 @@ static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
                        new = &noop_qdisc;
        }
 
-       sch_tree_lock(sch);
-       qfq_purge_queue(cl);
-       *old = cl->qdisc;
-       cl->qdisc = new;
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &cl->qdisc);
        return 0;
 }
 
index 6c0534cc77582881fecb7b9276659f6d921e6daa..8c0508c0e287742a8fbbcbf49134e76e9e52b807 100644 (file)
@@ -210,7 +210,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
        q->flags = ctl->flags;
        q->limit = ctl->limit;
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }
@@ -313,12 +314,7 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index 5bbb6332ec5746dd1f33a04f4e22bcde5eb787c0..c69611640fa528f340ac7948b25ae24432df6343 100644 (file)
@@ -510,7 +510,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
 
-       qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+       qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                 q->qdisc->qstats.backlog);
        qdisc_destroy(q->qdisc);
        q->qdisc = child;
 
@@ -606,12 +607,7 @@ static int sfb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index 3abab534eb5cd3646ea476b77433b10215602099..498f0a2cb47fca72bf504a712fdc8742cc947a1d 100644 (file)
@@ -346,7 +346,7 @@ static int
 sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
-       unsigned int hash;
+       unsigned int hash, dropped;
        sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
@@ -461,7 +461,7 @@ enqueue:
                return NET_XMIT_SUCCESS;
 
        qlen = slot->qlen;
-       sfq_drop(sch);
+       dropped = sfq_drop(sch);
        /* Return Congestion Notification only if we dropped a packet
         * from this flow.
         */
@@ -469,7 +469,7 @@ enqueue:
                return NET_XMIT_CN;
 
        /* As we dropped a packet, better let upper stack know this */
-       qdisc_tree_decrease_qlen(sch, 1);
+       qdisc_tree_reduce_backlog(sch, 1, dropped);
        return NET_XMIT_SUCCESS;
 }
 
@@ -537,6 +537,7 @@ static void sfq_rehash(struct Qdisc *sch)
        struct sfq_slot *slot;
        struct sk_buff_head list;
        int dropped = 0;
+       unsigned int drop_len = 0;
 
        __skb_queue_head_init(&list);
 
@@ -565,6 +566,7 @@ static void sfq_rehash(struct Qdisc *sch)
                        if (x >= SFQ_MAX_FLOWS) {
 drop:
                                qdisc_qstats_backlog_dec(sch, skb);
+                               drop_len += qdisc_pkt_len(skb);
                                kfree_skb(skb);
                                dropped++;
                                continue;
@@ -594,7 +596,7 @@ drop:
                }
        }
        sch->q.qlen -= dropped;
-       qdisc_tree_decrease_qlen(sch, dropped);
+       qdisc_tree_reduce_backlog(sch, dropped, drop_len);
 }
 
 static void sfq_perturbation(unsigned long arg)
@@ -618,7 +620,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        struct sfq_sched_data *q = qdisc_priv(sch);
        struct tc_sfq_qopt *ctl = nla_data(opt);
        struct tc_sfq_qopt_v1 *ctl_v1 = NULL;
-       unsigned int qlen;
+       unsigned int qlen, dropped = 0;
        struct red_parms *p = NULL;
 
        if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
@@ -667,8 +669,8 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
 
        qlen = sch->q.qlen;
        while (sch->q.qlen > q->limit)
-               sfq_drop(sch);
-       qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen);
+               dropped += sfq_drop(sch);
+       qdisc_tree_reduce_backlog(sch, qlen - sch->q.qlen, dropped);
 
        del_timer(&q->perturb_timer);
        if (q->perturb_period) {
index a4afde14e8656cca6c0688bc2d092334edaf69df..c2fbde742f37347d6974ed87368fd3af4425de74 100644 (file)
@@ -160,6 +160,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        struct tbf_sched_data *q = qdisc_priv(sch);
        struct sk_buff *segs, *nskb;
        netdev_features_t features = netif_skb_features(skb);
+       unsigned int len = 0, prev_len = qdisc_pkt_len(skb);
        int ret, nb;
 
        segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
@@ -172,6 +173,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
                nskb = segs->next;
                segs->next = NULL;
                qdisc_skb_cb(segs)->pkt_len = segs->len;
+               len += segs->len;
                ret = qdisc_enqueue(segs, q->qdisc);
                if (ret != NET_XMIT_SUCCESS) {
                        if (net_xmit_drop_count(ret))
@@ -183,7 +185,7 @@ static int tbf_segment(struct sk_buff *skb, struct Qdisc *sch)
        }
        sch->q.qlen += nb;
        if (nb > 1)
-               qdisc_tree_decrease_qlen(sch, 1 - nb);
+               qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len);
        consume_skb(skb);
        return nb > 0 ? NET_XMIT_SUCCESS : NET_XMIT_DROP;
 }
@@ -399,7 +401,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
 
        sch_tree_lock(sch);
        if (child) {
-               qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
+               qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
+                                         q->qdisc->qstats.backlog);
                qdisc_destroy(q->qdisc);
                q->qdisc = child;
        }
@@ -502,13 +505,7 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
        if (new == NULL)
                new = &noop_qdisc;
 
-       sch_tree_lock(sch);
-       *old = q->qdisc;
-       q->qdisc = new;
-       qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-       qdisc_reset(*old);
-       sch_tree_unlock(sch);
-
+       *old = qdisc_replace(sch, new, &q->qdisc);
        return 0;
 }
 
index 2bf8ec92dde482ed6ab59275aad492d5abc5385e..a19b3e60770382507050a56a172ffc5adb2f497a 100644 (file)
@@ -1263,7 +1263,7 @@ static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
        if (score_curr > score_best)
                return curr;
        else if (score_curr == score_best)
-               return sctp_trans_elect_tie(curr, best);
+               return sctp_trans_elect_tie(best, curr);
        else
                return best;
 }
@@ -1493,7 +1493,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
 
                asoc->peer.sack_needed = 0;
 
-               sctp_outq_tail(&asoc->outqueue, sack);
+               sctp_outq_tail(&asoc->outqueue, sack, GFP_ATOMIC);
 
                /* Stop the SACK timer.  */
                timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
index a3380917f1973dba6c43507bc16b4f3fbc090c8a..958ef5f33f4b8165592f1631cb6c4bf035dcc702 100644 (file)
@@ -70,19 +70,6 @@ static struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
        return msg;
 }
 
-void sctp_datamsg_free(struct sctp_datamsg *msg)
-{
-       struct sctp_chunk *chunk;
-
-       /* This doesn't have to be a _safe vairant because
-        * sctp_chunk_free() only drops the refs.
-        */
-       list_for_each_entry(chunk, &msg->chunks, frag_list)
-               sctp_chunk_free(chunk);
-
-       sctp_datamsg_put(msg);
-}
-
 /* Final destructruction of datamsg memory. */
 static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
 {
@@ -273,7 +260,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                                frag |= SCTP_DATA_SACK_IMM;
                }
 
-               chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
+               chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag,
+                                                0, GFP_KERNEL);
 
                if (!chunk) {
                        err = -ENOMEM;
@@ -309,7 +297,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
                    (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
                        frag |= SCTP_DATA_SACK_IMM;
 
-               chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
+               chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag,
+                                                0, GFP_KERNEL);
 
                if (!chunk) {
                        err = -ENOMEM;
index 49d2cc751386f3208c67eed17ec9c3f15b801f50..db76f1ab4ac2cb16b4568f0d9fbe4e3b90deaa1c 100644 (file)
@@ -221,7 +221,7 @@ int sctp_rcv(struct sk_buff *skb)
                goto discard_release;
 
        /* Create an SCTP packet structure. */
-       chunk = sctp_chunkify(skb, asoc, sk);
+       chunk = sctp_chunkify(skb, asoc, sk, GFP_ATOMIC);
        if (!chunk)
                goto discard_release;
        SCTP_INPUT_CB(skb)->chunk = chunk;
@@ -937,7 +937,6 @@ static struct sctp_association *__sctp_lookup_association(
        struct sctp_transport *t;
        struct sctp_association *asoc = NULL;
 
-       rcu_read_lock();
        t = sctp_addrs_lookup_transport(net, local, peer);
        if (!t || !sctp_transport_hold(t))
                goto out;
@@ -949,7 +948,6 @@ static struct sctp_association *__sctp_lookup_association(
        sctp_transport_put(t);
 
 out:
-       rcu_read_unlock();
        return asoc;
 }
 
@@ -962,7 +960,9 @@ struct sctp_association *sctp_lookup_association(struct net *net,
 {
        struct sctp_association *asoc;
 
+       rcu_read_lock();
        asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
+       rcu_read_unlock();
 
        return asoc;
 }
index ec529121f38a03c4b3e2317249cd0694fd619d3f..ce46f1c7f133ad5b114e4c2cd571d26c2b9ee901 100644 (file)
@@ -526,6 +526,8 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
                }
                return 0;
        }
+       if (addr1->v6.sin6_port != addr2->v6.sin6_port)
+               return 0;
        if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
                return 0;
        /* If this is a linklocal address, compare the scope_id. */
index 9d610eddd19ef2320fc34ae9d91e7426ae5f50f9..736c004abfbc2787a3c50fa85168ebdf3b112787 100644 (file)
@@ -153,7 +153,7 @@ void sctp_packet_free(struct sctp_packet *packet)
  */
 sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
                                       struct sctp_chunk *chunk,
-                                      int one_packet)
+                                      int one_packet, gfp_t gfp)
 {
        sctp_xmit_t retval;
        int error = 0;
@@ -163,7 +163,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
        switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
        case SCTP_XMIT_PMTU_FULL:
                if (!packet->has_cookie_echo) {
-                       error = sctp_packet_transmit(packet);
+                       error = sctp_packet_transmit(packet, gfp);
                        if (error < 0)
                                chunk->skb->sk->sk_err = -error;
 
@@ -376,7 +376,7 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk)
  *
  * The return value is a normal kernel error return value.
  */
-int sctp_packet_transmit(struct sctp_packet *packet)
+int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
 {
        struct sctp_transport *tp = packet->transport;
        struct sctp_association *asoc = tp->asoc;
index c0380cfb16ae4eb77bdab457e8310c0cb15a1c4a..f03541d0f12d052d1f58901d57852be46f18a15a 100644 (file)
@@ -68,7 +68,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
 static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
 
-static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout);
+static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
 
 /* Add data to the front of the queue. */
 static inline void sctp_outq_head_data(struct sctp_outq *q,
@@ -285,7 +285,7 @@ void sctp_outq_free(struct sctp_outq *q)
 }
 
 /* Put a new chunk in an sctp_outq.  */
-int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
+int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk, gfp_t gfp)
 {
        struct net *net = sock_net(q->asoc->base.sk);
        int error = 0;
@@ -341,7 +341,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
                return error;
 
        if (!q->cork)
-               error = sctp_outq_flush(q, 0);
+               error = sctp_outq_flush(q, 0, gfp);
 
        return error;
 }
@@ -510,7 +510,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
         * will be flushed at the end.
         */
        if (reason != SCTP_RTXR_FAST_RTX)
-               error = sctp_outq_flush(q, /* rtx_timeout */ 1);
+               error = sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC);
 
        if (error)
                q->asoc->base.sk->sk_err = -error;
@@ -601,12 +601,12 @@ redo:
                                 * control chunks are already freed so there
                                 * is nothing we can do.
                                 */
-                               sctp_packet_transmit(pkt);
+                               sctp_packet_transmit(pkt, GFP_ATOMIC);
                                goto redo;
                        }
 
                        /* Send this packet.  */
-                       error = sctp_packet_transmit(pkt);
+                       error = sctp_packet_transmit(pkt, GFP_ATOMIC);
 
                        /* If we are retransmitting, we should only
                         * send a single packet.
@@ -622,7 +622,7 @@ redo:
 
                case SCTP_XMIT_RWND_FULL:
                        /* Send this packet. */
-                       error = sctp_packet_transmit(pkt);
+                       error = sctp_packet_transmit(pkt, GFP_ATOMIC);
 
                        /* Stop sending DATA as there is no more room
                         * at the receiver.
@@ -632,7 +632,7 @@ redo:
 
                case SCTP_XMIT_DELAY:
                        /* Send this packet. */
-                       error = sctp_packet_transmit(pkt);
+                       error = sctp_packet_transmit(pkt, GFP_ATOMIC);
 
                        /* Stop sending DATA because of nagle delay. */
                        done = 1;
@@ -685,12 +685,12 @@ redo:
 }
 
 /* Cork the outqueue so queued chunks are really queued. */
-int sctp_outq_uncork(struct sctp_outq *q)
+int sctp_outq_uncork(struct sctp_outq *q, gfp_t gfp)
 {
        if (q->cork)
                q->cork = 0;
 
-       return sctp_outq_flush(q, 0);
+       return sctp_outq_flush(q, 0, gfp);
 }
 
 
@@ -703,7 +703,7 @@ int sctp_outq_uncork(struct sctp_outq *q)
  * locking concerns must be made.  Today we use the sock lock to protect
  * this function.
  */
-static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
+static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
 {
        struct sctp_packet *packet;
        struct sctp_packet singleton;
@@ -825,7 +825,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                        sctp_packet_init(&singleton, transport, sport, dport);
                        sctp_packet_config(&singleton, vtag, 0);
                        sctp_packet_append_chunk(&singleton, chunk);
-                       error = sctp_packet_transmit(&singleton);
+                       error = sctp_packet_transmit(&singleton, gfp);
                        if (error < 0)
                                return error;
                        break;
@@ -856,7 +856,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                case SCTP_CID_ASCONF:
                case SCTP_CID_FWD_TSN:
                        status = sctp_packet_transmit_chunk(packet, chunk,
-                                                           one_packet);
+                                                           one_packet, gfp);
                        if (status  != SCTP_XMIT_OK) {
                                /* put the chunk back */
                                list_add(&chunk->list, &q->control_chunk_list);
@@ -1011,7 +1011,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                                 atomic_read(&chunk->skb->users) : -1);
 
                        /* Add the chunk to the packet.  */
-                       status = sctp_packet_transmit_chunk(packet, chunk, 0);
+                       status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
 
                        switch (status) {
                        case SCTP_XMIT_PMTU_FULL:
@@ -1088,7 +1088,7 @@ sctp_flush_out:
                                                      send_ready);
                packet = &t->packet;
                if (!sctp_packet_empty(packet))
-                       error = sctp_packet_transmit(packet);
+                       error = sctp_packet_transmit(packet, gfp);
 
                /* Clear the burst limited state, if any */
                sctp_transport_burst_reset(t);
index 5e68b94ee64012571bc4d5f277a9cc594467cc3b..6cc2152e074047024436e55292b39342a2eaa51f 100644 (file)
@@ -65,7 +65,7 @@ static struct {
        struct kfifo      fifo;
        spinlock_t        lock;
        wait_queue_head_t wait;
-       struct timespec   tstart;
+       struct timespec64 tstart;
 } sctpw;
 
 static __printf(1, 2) void printl(const char *fmt, ...)
@@ -85,7 +85,7 @@ static __printf(1, 2) void printl(const char *fmt, ...)
 static int sctpprobe_open(struct inode *inode, struct file *file)
 {
        kfifo_reset(&sctpw.fifo);
-       getnstimeofday(&sctpw.tstart);
+       ktime_get_ts64(&sctpw.tstart);
 
        return 0;
 }
@@ -138,7 +138,7 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
        struct sk_buff *skb = chunk->skb;
        struct sctp_transport *sp;
        static __u32 lcwnd = 0;
-       struct timespec now;
+       struct timespec64 now;
 
        sp = asoc->peer.primary_path;
 
@@ -149,8 +149,8 @@ static sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
            (full || sp->cwnd != lcwnd)) {
                lcwnd = sp->cwnd;
 
-               getnstimeofday(&now);
-               now = timespec_sub(now, sctpw.tstart);
+               ktime_get_ts64(&now);
+               now = timespec64_sub(now, sctpw.tstart);
 
                printl("%lu.%06lu ", (unsigned long) now.tv_sec,
                       (unsigned long) now.tv_nsec / NSEC_PER_USEC);
index ded7d931a6a5b218c7bbd4481acdea1d2bc29325..5cfac8d5d3b39b7f1aa1b82812dd02eaca45f337 100644 (file)
@@ -161,7 +161,6 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
        struct sctp_af *af;
 
        primary = &assoc->peer.primary_addr;
-       rcu_read_lock();
        list_for_each_entry_rcu(transport, &assoc->peer.transport_addr_list,
                        transports) {
                addr = &transport->ipaddr;
@@ -172,7 +171,6 @@ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_associa
                }
                af->seq_dump_addr(seq, addr);
        }
-       rcu_read_unlock();
 }
 
 static void *sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
@@ -482,7 +480,7 @@ static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
 static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
 {
        struct sctp_association *assoc;
-       struct sctp_transport *tsp;
+       struct sctp_transport *transport, *tsp;
 
        if (v == SEQ_START_TOKEN) {
                seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
@@ -490,10 +488,10 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
                return 0;
        }
 
-       tsp = (struct sctp_transport *)v;
-       if (!sctp_transport_hold(tsp))
+       transport = (struct sctp_transport *)v;
+       if (!sctp_transport_hold(transport))
                return 0;
-       assoc = tsp->asoc;
+       assoc = transport->asoc;
 
        list_for_each_entry_rcu(tsp, &assoc->peer.transport_addr_list,
                                transports) {
@@ -546,7 +544,7 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
                seq_printf(seq, "\n");
        }
 
-       sctp_transport_put(tsp);
+       sctp_transport_put(transport);
 
        return 0;
 }
index ab0d538a74ed593571cfaef02cd1bb7ce872abe6..1099e99a53c485402ddd9c0693ff5cdd707accca 100644 (file)
@@ -60,6 +60,8 @@
 #include <net/inet_common.h>
 #include <net/inet_ecn.h>
 
+#define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024)
+
 /* Global data structures. */
 struct sctp_globals sctp_globals __read_mostly;
 
@@ -1355,6 +1357,8 @@ static __init int sctp_init(void)
        unsigned long limit;
        int max_share;
        int order;
+       int num_entries;
+       int max_entry_order;
 
        sock_skb_cb_check_size(sizeof(struct sctp_ulpevent));
 
@@ -1407,14 +1411,24 @@ static __init int sctp_init(void)
 
        /* Size and allocate the association hash table.
         * The methodology is similar to that of the tcp hash tables.
+        * Though not identical.  Start by getting a goal size
         */
        if (totalram_pages >= (128 * 1024))
                goal = totalram_pages >> (22 - PAGE_SHIFT);
        else
                goal = totalram_pages >> (24 - PAGE_SHIFT);
 
-       for (order = 0; (1UL << order) < goal; order++)
-               ;
+       /* Then compute the page order for said goal */
+       order = get_order(goal);
+
+       /* Now compute the required page order for the maximum sized table we
+        * want to create
+        */
+       max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES *
+                                   sizeof(struct sctp_bind_hashbucket));
+
+       /* Limit the page order by that maximum hash table size */
+       order = min(order, max_entry_order);
 
        /* Allocate and initialize the endpoint hash table.  */
        sctp_ep_hashsize = 64;
@@ -1430,20 +1444,35 @@ static __init int sctp_init(void)
                INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain);
        }
 
-       /* Allocate and initialize the SCTP port hash table.  */
+       /* Allocate and initialize the SCTP port hash table.
+        * Note that order is initalized to start at the max sized
+        * table we want to support.  If we can't get that many pages
+        * reduce the order and try again
+        */
        do {
-               sctp_port_hashsize = (1UL << order) * PAGE_SIZE /
-                                       sizeof(struct sctp_bind_hashbucket);
-               if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
-                       continue;
                sctp_port_hashtable = (struct sctp_bind_hashbucket *)
                        __get_free_pages(GFP_KERNEL | __GFP_NOWARN, order);
        } while (!sctp_port_hashtable && --order > 0);
+
        if (!sctp_port_hashtable) {
                pr_err("Failed bind hash alloc\n");
                status = -ENOMEM;
                goto err_bhash_alloc;
        }
+
+       /* Now compute the number of entries that will fit in the
+        * port hash space we allocated
+        */
+       num_entries = (1UL << order) * PAGE_SIZE /
+                     sizeof(struct sctp_bind_hashbucket);
+
+       /* And finish by rounding it down to the nearest power of two
+        * this wastes some memory of course, but its needed because
+        * the hash function operates based on the assumption that
+        * that the number of entries is a power of two
+        */
+       sctp_port_hashsize = rounddown_pow_of_two(num_entries);
+
        for (i = 0; i < sctp_port_hashsize; i++) {
                spin_lock_init(&sctp_port_hashtable[i].lock);
                INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
@@ -1452,7 +1481,8 @@ static __init int sctp_init(void)
        if (sctp_transport_hashtable_init())
                goto err_thash_alloc;
 
-       pr_info("Hash tables configured (bind %d)\n", sctp_port_hashsize);
+       pr_info("Hash tables configured (bind %d/%d)\n", sctp_port_hashsize,
+               num_entries);
 
        sctp_sysctl_register();
 
index 5d6a03fad3789a12290f5f14c5a7efa69c98f41a..8449ca26aa0bfd9e787670e5a2eea5afd85773b6 100644 (file)
 #include <net/sctp/sm.h>
 
 static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
-                                           __u8 type, __u8 flags, int paylen);
+                                           __u8 type, __u8 flags, int paylen,
+                                           gfp_t gfp);
 static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
-                                        __u8 flags, int paylen);
+                                        __u8 flags, int paylen, gfp_t gfp);
 static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
-                                          __u8 type, __u8 flags, int paylen);
+                                          __u8 type, __u8 flags, int paylen,
+                                          gfp_t gfp);
 static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const struct sctp_chunk *init_chunk,
@@ -318,7 +320,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
         * PLEASE DO NOT FIXME [This version does not support Host Name.]
         */
 
-       retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize);
+       retval = sctp_make_control(asoc, SCTP_CID_INIT, 0, chunksize, gfp);
        if (!retval)
                goto nodata;
 
@@ -465,7 +467,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
                                        num_ext);
 
        /* Now allocate and fill out the chunk.  */
-       retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize);
+       retval = sctp_make_control(asoc, SCTP_CID_INIT_ACK, 0, chunksize, gfp);
        if (!retval)
                goto nomem_chunk;
 
@@ -570,7 +572,8 @@ struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
        cookie_len = asoc->peer.cookie_len;
 
        /* Build a cookie echo chunk.  */
-       retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0, cookie_len);
+       retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ECHO, 0,
+                                  cookie_len, GFP_ATOMIC);
        if (!retval)
                goto nodata;
        retval->subh.cookie_hdr =
@@ -615,7 +618,7 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
 {
        struct sctp_chunk *retval;
 
-       retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0);
+       retval = sctp_make_control(asoc, SCTP_CID_COOKIE_ACK, 0, 0, GFP_ATOMIC);
 
        /* RFC 2960 6.4 Multi-homed SCTP Endpoints
         *
@@ -664,7 +667,7 @@ struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
 
        cwr.lowest_tsn = htonl(lowest_tsn);
        retval = sctp_make_control(asoc, SCTP_CID_ECN_CWR, 0,
-                                  sizeof(sctp_cwrhdr_t));
+                                  sizeof(sctp_cwrhdr_t), GFP_ATOMIC);
 
        if (!retval)
                goto nodata;
@@ -698,7 +701,7 @@ struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
 
        ecne.lowest_tsn = htonl(lowest_tsn);
        retval = sctp_make_control(asoc, SCTP_CID_ECN_ECNE, 0,
-                                  sizeof(sctp_ecnehdr_t));
+                                  sizeof(sctp_ecnehdr_t), GFP_ATOMIC);
        if (!retval)
                goto nodata;
        retval->subh.ecne_hdr =
@@ -713,7 +716,8 @@ nodata:
  */
 struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
                                       const struct sctp_sndrcvinfo *sinfo,
-                                      int data_len, __u8 flags, __u16 ssn)
+                                      int data_len, __u8 flags, __u16 ssn,
+                                      gfp_t gfp)
 {
        struct sctp_chunk *retval;
        struct sctp_datahdr dp;
@@ -734,7 +738,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
                dp.ssn = htons(ssn);
 
        chunk_len = sizeof(dp) + data_len;
-       retval = sctp_make_data(asoc, flags, chunk_len);
+       retval = sctp_make_data(asoc, flags, chunk_len, gfp);
        if (!retval)
                goto nodata;
 
@@ -781,7 +785,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
                + sizeof(__u32) * num_dup_tsns;
 
        /* Create the chunk.  */
-       retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len);
+       retval = sctp_make_control(asoc, SCTP_CID_SACK, 0, len, GFP_ATOMIC);
        if (!retval)
                goto nodata;
 
@@ -861,7 +865,7 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc,
        shut.cum_tsn_ack = htonl(ctsn);
 
        retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN, 0,
-                                  sizeof(sctp_shutdownhdr_t));
+                                  sizeof(sctp_shutdownhdr_t), GFP_ATOMIC);
        if (!retval)
                goto nodata;
 
@@ -879,7 +883,8 @@ struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
 {
        struct sctp_chunk *retval;
 
-       retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);
+       retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0,
+                                  GFP_ATOMIC);
 
        /* RFC 2960 6.4 Multi-homed SCTP Endpoints
         *
@@ -908,7 +913,8 @@ struct sctp_chunk *sctp_make_shutdown_complete(
         */
        flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;
 
-       retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0);
+       retval = sctp_make_control(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags,
+                                  0, GFP_ATOMIC);
 
        /* RFC 2960 6.4 Multi-homed SCTP Endpoints
         *
@@ -947,7 +953,8 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
                        flags = SCTP_CHUNK_FLAG_T;
        }
 
-       retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint);
+       retval = sctp_make_control(asoc, SCTP_CID_ABORT, flags, hint,
+                                  GFP_ATOMIC);
 
        /* RFC 2960 6.4 Multi-homed SCTP Endpoints
         *
@@ -1139,7 +1146,8 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
        struct sctp_chunk *retval;
        sctp_sender_hb_info_t hbinfo;
 
-       retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));
+       retval = sctp_make_control(asoc, SCTP_CID_HEARTBEAT, 0,
+                                  sizeof(hbinfo), GFP_ATOMIC);
 
        if (!retval)
                goto nodata;
@@ -1167,7 +1175,8 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
 {
        struct sctp_chunk *retval;
 
-       retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);
+       retval  = sctp_make_control(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen,
+                                   GFP_ATOMIC);
        if (!retval)
                goto nodata;
 
@@ -1200,7 +1209,7 @@ static struct sctp_chunk *sctp_make_op_error_space(
        struct sctp_chunk *retval;
 
        retval = sctp_make_control(asoc, SCTP_CID_ERROR, 0,
-                                  sizeof(sctp_errhdr_t) + size);
+                                  sizeof(sctp_errhdr_t) + size, GFP_ATOMIC);
        if (!retval)
                goto nodata;
 
@@ -1271,7 +1280,8 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
                return NULL;
 
        retval = sctp_make_control(asoc, SCTP_CID_AUTH, 0,
-                       hmac_desc->hmac_len + sizeof(sctp_authhdr_t));
+                       hmac_desc->hmac_len + sizeof(sctp_authhdr_t),
+                       GFP_ATOMIC);
        if (!retval)
                return NULL;
 
@@ -1309,11 +1319,11 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
  */
 struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
                            const struct sctp_association *asoc,
-                           struct sock *sk)
+                           struct sock *sk, gfp_t gfp)
 {
        struct sctp_chunk *retval;
 
-       retval = kmem_cache_zalloc(sctp_chunk_cachep, GFP_ATOMIC);
+       retval = kmem_cache_zalloc(sctp_chunk_cachep, gfp);
 
        if (!retval)
                goto nodata;
@@ -1361,7 +1371,8 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
  * arguments, reserving enough space for a 'paylen' byte payload.
  */
 static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
-                                           __u8 type, __u8 flags, int paylen)
+                                           __u8 type, __u8 flags, int paylen,
+                                           gfp_t gfp)
 {
        struct sctp_chunk *retval;
        sctp_chunkhdr_t *chunk_hdr;
@@ -1369,8 +1380,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
        struct sock *sk;
 
        /* No need to allocate LL here, as this is only a chunk. */
-       skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),
-                       GFP_ATOMIC);
+       skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), gfp);
        if (!skb)
                goto nodata;
 
@@ -1381,7 +1391,7 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc,
        chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));
 
        sk = asoc ? asoc->base.sk : NULL;
-       retval = sctp_chunkify(skb, asoc, sk);
+       retval = sctp_chunkify(skb, asoc, sk, gfp);
        if (!retval) {
                kfree_skb(skb);
                goto nodata;
@@ -1400,16 +1410,18 @@ nodata:
 }
 
 static struct sctp_chunk *sctp_make_data(const struct sctp_association *asoc,
-                                        __u8 flags, int paylen)
+                                        __u8 flags, int paylen, gfp_t gfp)
 {
-       return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen);
+       return _sctp_make_chunk(asoc, SCTP_CID_DATA, flags, paylen, gfp);
 }
 
 static struct sctp_chunk *sctp_make_control(const struct sctp_association *asoc,
-                                           __u8 type, __u8 flags, int paylen)
+                                           __u8 type, __u8 flags, int paylen,
+                                           gfp_t gfp)
 {
-       struct sctp_chunk *chunk = _sctp_make_chunk(asoc, type, flags, paylen);
+       struct sctp_chunk *chunk;
 
+       chunk = _sctp_make_chunk(asoc, type, flags, paylen, gfp);
        if (chunk)
                sctp_control_set_owner_w(chunk);
 
@@ -2756,7 +2768,8 @@ static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
        length += addrlen;
 
        /* Create the chunk.  */
-       retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length);
+       retval = sctp_make_control(asoc, SCTP_CID_ASCONF, 0, length,
+                                  GFP_ATOMIC);
        if (!retval)
                return NULL;
 
@@ -2940,7 +2953,8 @@ static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *as
        int                     length = sizeof(asconf) + vparam_len;
 
        /* Create the chunk.  */
-       retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length);
+       retval = sctp_make_control(asoc, SCTP_CID_ASCONF_ACK, 0, length,
+                                  GFP_ATOMIC);
        if (!retval)
                return NULL;
 
@@ -3500,7 +3514,7 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
 
        hint = (nstreams + 1) * sizeof(__u32);
 
-       retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint);
+       retval = sctp_make_control(asoc, SCTP_CID_FWD_TSN, 0, hint, GFP_ATOMIC);
 
        if (!retval)
                return NULL;
index b5327bb77458f3ae68e0098c45d00307a56ed2c5..3c22c41a2bc2dc128d651f64b1a81036be22b9b3 100644 (file)
@@ -1019,13 +1019,13 @@ static void sctp_cmd_t1_timer_update(struct sctp_association *asoc,
  * encouraged for small fragments.
  */
 static int sctp_cmd_send_msg(struct sctp_association *asoc,
-                               struct sctp_datamsg *msg)
+                               struct sctp_datamsg *msg, gfp_t gfp)
 {
        struct sctp_chunk *chunk;
        int error = 0;
 
        list_for_each_entry(chunk, &msg->chunks, frag_list) {
-               error = sctp_outq_tail(&asoc->outqueue, chunk);
+               error = sctp_outq_tail(&asoc->outqueue, chunk, gfp);
                if (error)
                        break;
        }
@@ -1249,7 +1249,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_NEW_ASOC:
                        /* Register a new association.  */
                        if (local_cork) {
-                               sctp_outq_uncork(&asoc->outqueue);
+                               sctp_outq_uncork(&asoc->outqueue, gfp);
                                local_cork = 0;
                        }
 
@@ -1269,7 +1269,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 
                case SCTP_CMD_DELETE_TCB:
                        if (local_cork) {
-                               sctp_outq_uncork(&asoc->outqueue);
+                               sctp_outq_uncork(&asoc->outqueue, gfp);
                                local_cork = 0;
                        }
                        /* Delete the current association.  */
@@ -1423,13 +1423,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                                local_cork = 1;
                        }
                        /* Send a chunk to our peer.  */
-                       error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk);
+                       error = sctp_outq_tail(&asoc->outqueue, cmd->obj.chunk,
+                                              gfp);
                        break;
 
                case SCTP_CMD_SEND_PKT:
                        /* Send a full packet to our peer.  */
                        packet = cmd->obj.packet;
-                       sctp_packet_transmit(packet);
+                       sctp_packet_transmit(packet, gfp);
                        sctp_ootb_pkt_free(packet);
                        break;
 
@@ -1639,7 +1640,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                         */
                        chunk->pdiscard = 1;
                        if (asoc) {
-                               sctp_outq_uncork(&asoc->outqueue);
+                               sctp_outq_uncork(&asoc->outqueue, gfp);
                                local_cork = 0;
                        }
                        break;
@@ -1677,7 +1678,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_FORCE_PRIM_RETRAN:
                        t = asoc->peer.retran_path;
                        asoc->peer.retran_path = asoc->peer.primary_path;
-                       error = sctp_outq_uncork(&asoc->outqueue);
+                       error = sctp_outq_uncork(&asoc->outqueue, gfp);
                        local_cork = 0;
                        asoc->peer.retran_path = t;
                        break;
@@ -1704,7 +1705,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                                sctp_outq_cork(&asoc->outqueue);
                                local_cork = 1;
                        }
-                       error = sctp_cmd_send_msg(asoc, cmd->obj.msg);
+                       error = sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp);
                        break;
                case SCTP_CMD_SEND_NEXT_ASCONF:
                        sctp_cmd_send_asconf(asoc);
@@ -1734,9 +1735,9 @@ out:
         */
        if (asoc && SCTP_EVENT_T_CHUNK == event_type && chunk) {
                if (chunk->end_of_packet || chunk->singleton)
-                       error = sctp_outq_uncork(&asoc->outqueue);
+                       error = sctp_outq_uncork(&asoc->outqueue, gfp);
        } else if (local_cork)
-               error = sctp_outq_uncork(&asoc->outqueue);
+               error = sctp_outq_uncork(&asoc->outqueue, gfp);
        return error;
 nomem:
        error = -ENOMEM;
index 6427b9d1197eedbdb974c665feba8a21ea769fdc..b89501e5c1a1ecef29f4ca6cceb2ecd064f595bb 100644 (file)
@@ -5538,6 +5538,7 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
        struct sctp_hmac_algo_param *hmacs;
        __u16 data_len = 0;
        u32 num_idents;
+       int i;
 
        if (!ep->auth_enable)
                return -EACCES;
@@ -5555,8 +5556,12 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
                return -EFAULT;
        if (put_user(num_idents, &p->shmac_num_idents))
                return -EFAULT;
-       if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len))
-               return -EFAULT;
+       for (i = 0; i < num_idents; i++) {
+               __u16 hmacid = ntohs(hmacs->hmac_ids[i]);
+
+               if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16)))
+                       return -EFAULT;
+       }
        return 0;
 }
 
index a431c14044a46f98e9b73f66e28f229690ef3c01..d517153891a6efca6242ce1a4b3d86afb9026542 100644 (file)
@@ -72,7 +72,7 @@ static struct sctp_transport *sctp_transport_init(struct net *net,
         */
        peer->rto = msecs_to_jiffies(net->sctp.rto_initial);
 
-       peer->last_time_heard = ktime_get();
+       peer->last_time_heard = ktime_set(0, 0);
        peer->last_time_ecne_reduced = jiffies;
 
        peer->param_flags = SPP_HB_DISABLE |
index c044d1e8508cc2ba147c001897e4c9c26cc1a7e5..c5ddc52cf2b29b7ec0de0c792697ee1edecaca5c 100644 (file)
@@ -533,7 +533,7 @@ static const struct inode_operations sockfs_inode_ops = {
  *     NULL is returned.
  */
 
-static struct socket *sock_alloc(void)
+struct socket *sock_alloc(void)
 {
        struct inode *inode;
        struct socket *sock;
@@ -554,6 +554,7 @@ static struct socket *sock_alloc(void)
        this_cpu_add(sockets_in_use, 1);
        return sock;
 }
+EXPORT_SYMBOL(sock_alloc);
 
 /**
  *     sock_release    -       close a socket
@@ -1106,12 +1107,8 @@ int __sock_create(struct net *net, int family, int type, int protocol,
           deadlock in module load.
         */
        if (family == PF_INET && type == SOCK_PACKET) {
-               static int warned;
-               if (!warned) {
-                       warned = 1;
-                       pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
-                               current->comm);
-               }
+               pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
+                            current->comm);
                family = PF_PACKET;
        }
 
@@ -1874,7 +1871,8 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 
 static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
                         struct msghdr *msg_sys, unsigned int flags,
-                        struct used_address *used_address)
+                        struct used_address *used_address,
+                        unsigned int allowed_msghdr_flags)
 {
        struct compat_msghdr __user *msg_compat =
            (struct compat_msghdr __user *)msg;
@@ -1900,6 +1898,7 @@ static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg,
 
        if (msg_sys->msg_controllen > INT_MAX)
                goto out_freeiov;
+       flags |= (msg_sys->msg_flags & allowed_msghdr_flags);
        ctl_len = msg_sys->msg_controllen;
        if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
                err =
@@ -1978,7 +1977,7 @@ long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags)
        if (!sock)
                goto out;
 
-       err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
+       err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0);
 
        fput_light(sock->file, fput_needed);
 out:
@@ -2005,6 +2004,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        struct compat_mmsghdr __user *compat_entry;
        struct msghdr msg_sys;
        struct used_address used_address;
+       unsigned int oflags = flags;
 
        if (vlen > UIO_MAXIOV)
                vlen = UIO_MAXIOV;
@@ -2019,11 +2019,15 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        entry = mmsg;
        compat_entry = (struct compat_mmsghdr __user *)mmsg;
        err = 0;
+       flags |= MSG_BATCH;
 
        while (datagrams < vlen) {
+               if (datagrams == vlen - 1)
+                       flags = oflags;
+
                if (MSG_CMSG_COMPAT & flags) {
                        err = ___sys_sendmsg(sock, (struct user_msghdr __user *)compat_entry,
-                                            &msg_sys, flags, &used_address);
+                                            &msg_sys, flags, &used_address, MSG_EOR);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
@@ -2031,7 +2035,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                } else {
                        err = ___sys_sendmsg(sock,
                                             (struct user_msghdr __user *)entry,
-                                            &msg_sys, flags, &used_address);
+                                            &msg_sys, flags, &used_address, MSG_EOR);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
index 799e65b944b9019cf7eee177f90f6d67a0fb66dd..cabf586f47d7d0d75a8cb77b44d497e76a34abd7 100644 (file)
@@ -740,7 +740,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
                default:
                        printk(KERN_CRIT "%s: bad return from "
                                "gss_fill_context: %zd\n", __func__, err);
-                       BUG();
+                       gss_msg->msg.errno = -EIO;
                }
                goto err_release_msg;
        }
index 2b32fd602669f1fbc1aa96d61ad076fe688713e1..273bc3a35425ba99351eedb3f99244f0f9c07ab7 100644 (file)
@@ -1225,7 +1225,7 @@ int qword_get(char **bpp, char *dest, int bufsize)
        if (bp[0] == '\\' && bp[1] == 'x') {
                /* HEX STRING */
                bp += 2;
-               while (len < bufsize) {
+               while (len < bufsize - 1) {
                        int h, l;
 
                        h = hex_to_bin(bp[0]);
index cc1251d0729707751d87537e1cbc6567aef1596c..2dcd7640eeb525d6a7f1ba8bd3eab047cda30f75 100644 (file)
@@ -341,6 +341,8 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt,
        rqst->rq_reply_bytes_recvd = 0;
        rqst->rq_bytes_sent = 0;
        rqst->rq_xid = headerp->rm_xid;
+
+       rqst->rq_private_buf.len = size;
        set_bit(RPC_BC_PA_IN_USE, &rqst->rq_bc_pa_state);
 
        buf = &rqst->rq_rcv_buf;
index 47f7da58a7f0e93e3ffd632396a5a8db65c7f7c3..8b5833c1ff2e8695030587749c8c72d86d334323 100644 (file)
@@ -1093,8 +1093,11 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
                .cb = cb,
                .idx = idx,
        };
+       int err;
 
-       switchdev_port_obj_dump(dev, &dump.fdb.obj, switchdev_port_fdb_dump_cb);
+       err = switchdev_port_obj_dump(dev, &dump.fdb.obj,
+                                     switchdev_port_fdb_dump_cb);
+       cb->args[1] = err;
        return dump.idx;
 }
 EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump);
index e401108360a2bd3974d6c32dacb4d6040e3e3318..ae469b37d85262e89e99f22784c7fa10b3d4bcb7 100644 (file)
@@ -412,11 +412,6 @@ enomem:
        return -ENOMEM;
 }
 
-void tipc_bcast_reinit(struct net *net)
-{
-       tipc_link_reinit(tipc_bc_sndlink(net), tipc_own_addr(net));
-}
-
 void tipc_bcast_stop(struct net *net)
 {
        struct tipc_net *tn = net_generic(net, tipc_net_id);
index 1944c6c00bb91ebc296baf439738475e2de100f6..d5e79b3767fd7747f8d7389bfd7ebe7d702ea6c0 100644 (file)
@@ -46,7 +46,6 @@ struct tipc_node_map;
 extern const char tipc_bclink_name[];
 
 int tipc_bcast_init(struct net *net);
-void tipc_bcast_reinit(struct net *net);
 void tipc_bcast_stop(struct net *net);
 void tipc_bcast_add_peer(struct net *net, struct tipc_link *l,
                         struct sk_buff_head *xmitq);
index 802ffad3200da61405b348314b9b48eb11580583..27a5406213c650239de192c423f28a88912a42d2 100644 (file)
@@ -40,6 +40,7 @@
 #include "link.h"
 #include "discover.h"
 #include "bcast.h"
+#include "netlink.h"
 
 #define MAX_ADDR_STR 60
 
@@ -54,23 +55,6 @@ static struct tipc_media * const media_info_array[] = {
        NULL
 };
 
-static const struct nla_policy
-tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = {
-       [TIPC_NLA_BEARER_UNSPEC]                = { .type = NLA_UNSPEC },
-       [TIPC_NLA_BEARER_NAME] = {
-               .type = NLA_STRING,
-               .len = TIPC_MAX_BEARER_NAME
-       },
-       [TIPC_NLA_BEARER_PROP]                  = { .type = NLA_NESTED },
-       [TIPC_NLA_BEARER_DOMAIN]                = { .type = NLA_U32 }
-};
-
-static const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = {
-       [TIPC_NLA_MEDIA_UNSPEC]         = { .type = NLA_UNSPEC },
-       [TIPC_NLA_MEDIA_NAME]           = { .type = NLA_STRING },
-       [TIPC_NLA_MEDIA_PROP]           = { .type = NLA_NESTED }
-};
-
 static void bearer_disable(struct net *net, struct tipc_bearer *b);
 
 /**
index 6f4a6d9b014989f29ff378d3e84cb60fd809aabe..7d2bb3e70baa8b673922a8d2e58a67304244e5e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/link.c: TIPC link code
  *
- * Copyright (c) 1996-2007, 2012-2015, Ericsson AB
+ * Copyright (c) 1996-2007, 2012-2016, Ericsson AB
  * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -127,6 +127,7 @@ struct tipc_link {
 
        /* Management and link supervision data */
        u32 peer_session;
+       u32 session;
        u32 peer_bearer_id;
        u32 bearer_id;
        u32 tolerance;
@@ -136,11 +137,7 @@ struct tipc_link {
        u16 peer_caps;
        bool active;
        u32 silent_intv_cnt;
-       struct {
-               unchar hdr[INT_H_SIZE];
-               unchar body[TIPC_MAX_IF_NAME];
-       } proto_msg;
-       struct tipc_msg *pmsg;
+       char if_name[TIPC_MAX_IF_NAME];
        u32 priority;
        char net_plane;
 
@@ -195,14 +192,6 @@ struct tipc_link {
 static const char *link_co_err = "Link tunneling error, ";
 static const char *link_rst_msg = "Resetting link ";
 
-/* Properties valid for media, bearar and link */
-static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
-       [TIPC_NLA_PROP_UNSPEC]          = { .type = NLA_UNSPEC },
-       [TIPC_NLA_PROP_PRIO]            = { .type = NLA_U32 },
-       [TIPC_NLA_PROP_TOL]             = { .type = NLA_U32 },
-       [TIPC_NLA_PROP_WIN]             = { .type = NLA_U32 }
-};
-
 /* Send states for broadcast NACKs
  */
 enum {
@@ -215,10 +204,11 @@ enum {
  * Interval between NACKs when packets arrive out of order
  */
 #define TIPC_NACK_INTV (TIPC_MIN_LINK_WIN * 2)
-/*
- * Out-of-range value for link session numbers
+
+/* Wildcard value for link session numbers. When it is known that
+ * peer endpoint is down, any session number must be accepted.
  */
-#define WILDCARD_SESSION 0x10000
+#define ANY_SESSION 0x10000
 
 /* Link FSM states:
  */
@@ -398,16 +388,6 @@ char *tipc_link_name(struct tipc_link *l)
        return l->name;
 }
 
-static u32 link_own_addr(struct tipc_link *l)
-{
-       return msg_prevnode(l->pmsg);
-}
-
-void tipc_link_reinit(struct tipc_link *l, u32 addr)
-{
-       msg_set_prevnode(l->pmsg, addr);
-}
-
 /**
  * tipc_link_create - create a new link
  * @n: pointer to associated node
@@ -441,29 +421,22 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
                      struct tipc_link **link)
 {
        struct tipc_link *l;
-       struct tipc_msg *hdr;
 
        l = kzalloc(sizeof(*l), GFP_ATOMIC);
        if (!l)
                return false;
        *link = l;
-       l->pmsg = (struct tipc_msg *)&l->proto_msg;
-       hdr = l->pmsg;
-       tipc_msg_init(ownnode, hdr, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, peer);
-       msg_set_size(hdr, sizeof(l->proto_msg));
-       msg_set_session(hdr, session);
-       msg_set_bearer_id(hdr, l->bearer_id);
+       l->session = session;
 
        /* Note: peer i/f name is completed by reset/activate message */
        sprintf(l->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
                tipc_zone(ownnode), tipc_cluster(ownnode), tipc_node(ownnode),
                if_name, tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
-       strcpy((char *)msg_data(hdr), if_name);
-
+       strcpy(l->if_name, if_name);
        l->addr = peer;
        l->peer_caps = peer_caps;
        l->net = net;
-       l->peer_session = WILDCARD_SESSION;
+       l->peer_session = ANY_SESSION;
        l->bearer_id = bearer_id;
        l->tolerance = tolerance;
        l->net_plane = net_plane;
@@ -790,7 +763,7 @@ static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list)
        struct tipc_msg *msg = buf_msg(skb_peek(list));
        int imp = msg_importance(msg);
        u32 oport = msg_origport(msg);
-       u32 addr = link_own_addr(link);
+       u32 addr = tipc_own_addr(link->net);
        struct sk_buff *skb;
 
        /* This really cannot happen...  */
@@ -839,16 +812,9 @@ void link_prepare_wakeup(struct tipc_link *l)
 
 void tipc_link_reset(struct tipc_link *l)
 {
-       /* Link is down, accept any session */
-       l->peer_session = WILDCARD_SESSION;
-
-       /* If peer is up, it only accepts an incremented session number */
-       msg_set_session(l->pmsg, msg_session(l->pmsg) + 1);
-
-       /* Prepare for renewed mtu size negotiation */
+       l->peer_session = ANY_SESSION;
+       l->session++;
        l->mtu = l->advertised_mtu;
-
-       /* Clean up all queues and counters: */
        __skb_queue_purge(&l->transmq);
        __skb_queue_purge(&l->deferdq);
        skb_queue_splice_init(&l->wakeupq, l->inputq);
@@ -903,8 +869,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
                if (unlikely(l->backlog[i].len >= l->backlog[i].limit))
                        return link_schedule_user(l, list);
        }
-       if (unlikely(msg_size(hdr) > mtu))
+       if (unlikely(msg_size(hdr) > mtu)) {
+               skb_queue_purge(list);
                return -EMSGSIZE;
+       }
 
        /* Prepare each packet for sending, and add to relevant queue: */
        while (skb_queue_len(list)) {
@@ -916,8 +884,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
 
                if (likely(skb_queue_len(transmq) < maxwin)) {
                        _skb = skb_clone(skb, GFP_ATOMIC);
-                       if (!_skb)
+                       if (!_skb) {
+                               skb_queue_purge(list);
                                return -ENOBUFS;
+                       }
                        __skb_dequeue(list);
                        __skb_queue_tail(transmq, skb);
                        __skb_queue_tail(xmitq, _skb);
@@ -1152,7 +1122,7 @@ int tipc_link_build_ack_msg(struct tipc_link *l, struct sk_buff_head *xmitq)
 
        /* Broadcast ACK must be sent via a unicast link => defer to caller */
        if (link_is_bc_rcvlink(l)) {
-               if (((l->rcv_nxt ^ link_own_addr(l)) & 0xf) != 0xf)
+               if (((l->rcv_nxt ^ tipc_own_addr(l->net)) & 0xf) != 0xf)
                        return 0;
                l->rcv_unacked = 0;
                return TIPC_LINK_SND_BC_ACK;
@@ -1264,15 +1234,30 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
                                      u16 rcvgap, int tolerance, int priority,
                                      struct sk_buff_head *xmitq)
 {
-       struct sk_buff *skb = NULL;
-       struct tipc_msg *hdr = l->pmsg;
+       struct sk_buff *skb;
+       struct tipc_msg *hdr;
+       struct sk_buff_head *dfq = &l->deferdq;
        bool node_up = link_is_up(l->bc_rcvlink);
 
        /* Don't send protocol message during reset or link failover */
        if (tipc_link_is_blocked(l))
                return;
 
-       msg_set_type(hdr, mtyp);
+       if (!tipc_link_is_up(l) && (mtyp == STATE_MSG))
+               return;
+
+       if (!skb_queue_empty(dfq))
+               rcvgap = buf_seqno(skb_peek(dfq)) - l->rcv_nxt;
+
+       skb = tipc_msg_create(LINK_PROTOCOL, mtyp, INT_H_SIZE,
+                             TIPC_MAX_IF_NAME, l->addr,
+                             tipc_own_addr(l->net), 0, 0, 0);
+       if (!skb)
+               return;
+
+       hdr = buf_msg(skb);
+       msg_set_session(hdr, l->session);
+       msg_set_bearer_id(hdr, l->bearer_id);
        msg_set_net_plane(hdr, l->net_plane);
        msg_set_next_sent(hdr, l->snd_nxt);
        msg_set_ack(hdr, l->rcv_nxt - 1);
@@ -1282,36 +1267,23 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,
        msg_set_linkprio(hdr, priority);
        msg_set_redundant_link(hdr, node_up);
        msg_set_seq_gap(hdr, 0);
-
-       /* Compatibility: created msg must not be in sequence with pkt flow */
        msg_set_seqno(hdr, l->snd_nxt + U16_MAX / 2);
 
        if (mtyp == STATE_MSG) {
-               if (!tipc_link_is_up(l))
-                       return;
-
-               /* Override rcvgap if there are packets in deferred queue */
-               if (!skb_queue_empty(&l->deferdq))
-                       rcvgap = buf_seqno(skb_peek(&l->deferdq)) - l->rcv_nxt;
-               if (rcvgap) {
-                       msg_set_seq_gap(hdr, rcvgap);
-                       l->stats.sent_nacks++;
-               }
+               msg_set_seq_gap(hdr, rcvgap);
+               msg_set_size(hdr, INT_H_SIZE);
                msg_set_probe(hdr, probe);
-               if (probe)
-                       l->stats.sent_probes++;
                l->stats.sent_states++;
                l->rcv_unacked = 0;
        } else {
                /* RESET_MSG or ACTIVATE_MSG */
                msg_set_max_pkt(hdr, l->advertised_mtu);
-               msg_set_ack(hdr, l->rcv_nxt - 1);
-               msg_set_next_sent(hdr, 1);
+               strcpy(msg_data(hdr), l->if_name);
        }
-       skb = tipc_buf_acquire(msg_size(hdr));
-       if (!skb)
-               return;
-       skb_copy_to_linear_data(skb, hdr, msg_size(hdr));
+       if (probe)
+               l->stats.sent_probes++;
+       if (rcvgap)
+               l->stats.sent_nacks++;
        skb->priority = TC_PRIO_CONTROL;
        __skb_queue_tail(xmitq, skb);
 }
@@ -1336,7 +1308,7 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
 
        /* At least one packet required for safe algorithm => add dummy */
        skb = tipc_msg_create(TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG,
-                             BASIC_H_SIZE, 0, l->addr, link_own_addr(l),
+                             BASIC_H_SIZE, 0, l->addr, tipc_own_addr(l->net),
                              0, 0, TIPC_ERR_NO_PORT);
        if (!skb) {
                pr_warn("%sunable to create tunnel packet\n", link_co_err);
@@ -1347,7 +1319,7 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
        __skb_queue_purge(&tmpxq);
 
        /* Initialize reusable tunnel packet header */
-       tipc_msg_init(link_own_addr(l), &tnlhdr, TUNNEL_PROTOCOL,
+       tipc_msg_init(tipc_own_addr(l->net), &tnlhdr, TUNNEL_PROTOCOL,
                      mtyp, INT_H_SIZE, l->addr);
        pktcnt = skb_queue_len(&l->transmq) + skb_queue_len(&l->backlogq);
        msg_set_msgcnt(&tnlhdr, pktcnt);
@@ -1406,7 +1378,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
        if (tipc_link_is_blocked(l) || !xmitq)
                goto exit;
 
-       if (link_own_addr(l) > msg_prevnode(hdr))
+       if (tipc_own_addr(l->net) > msg_prevnode(hdr))
                l->net_plane = msg_net_plane(hdr);
 
        switch (mtyp) {
@@ -1414,7 +1386,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,
 
                /* Ignore duplicate RESET with old session number */
                if ((less_eq(msg_session(hdr), l->peer_session)) &&
-                   (l->peer_session != WILDCARD_SESSION))
+                   (l->peer_session != ANY_SESSION))
                        break;
                /* fall thru' */
 
@@ -1511,7 +1483,7 @@ static bool tipc_link_build_bc_proto_msg(struct tipc_link *l, bool bcast,
        u16 gap_to = peers_snd_nxt - 1;
 
        skb = tipc_msg_create(BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE,
-                             0, l->addr, link_own_addr(l), 0, 0, 0);
+                             0, l->addr, tipc_own_addr(l->net), 0, 0, 0);
        if (!skb)
                return false;
        hdr = buf_msg(skb);
@@ -1666,7 +1638,7 @@ int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,
        if (mtyp != STATE_MSG)
                return 0;
 
-       if (dnode == link_own_addr(l)) {
+       if (dnode == tipc_own_addr(l->net)) {
                tipc_link_bc_ack_rcv(l, acked, xmitq);
                rc = tipc_link_retrans(l->bc_sndlink, from, to, xmitq);
                l->stats.recv_nacks++;
@@ -1958,8 +1930,10 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)
 
        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
                          NLM_F_MULTI, TIPC_NL_LINK_GET);
-       if (!hdr)
+       if (!hdr) {
+               tipc_bcast_unlock(net);
                return -EMSGSIZE;
+       }
 
        attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK);
        if (!attrs)
index b4ee9d6e181d2c2b2a17eefa865dae9c7071f543..6a94175ee20a983bbf6816f6c488a54066d85e78 100644 (file)
@@ -86,7 +86,6 @@ bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer,
                         struct sk_buff_head *namedq,
                         struct tipc_link *bc_sndlink,
                         struct tipc_link **link);
-void tipc_link_reinit(struct tipc_link *l, u32 addr);
 void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
                           int mtyp, struct sk_buff_head *xmitq);
 void tipc_link_build_reset_msg(struct tipc_link *l, struct sk_buff_head *xmitq);
index 777b979b84634fbd98aa3ed49388c33e0a9472c7..e190460fe0d396e795da064c9c3fe4523177879c 100644 (file)
 
 #define TIPC_NAMETBL_SIZE 1024         /* must be a power of 2 */
 
-static const struct nla_policy
-tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
-       [TIPC_NLA_NAME_TABLE_UNSPEC]    = { .type = NLA_UNSPEC },
-       [TIPC_NLA_NAME_TABLE_PUBL]      = { .type = NLA_NESTED }
-};
-
 /**
  * struct name_info - name sequence publication info
  * @node_list: circular list of publications made by own node
index 77bf9113c7a76be7cfc5173bc41b84664eb658e6..28bf4feeb81c25d0761177dc049100989640cdc5 100644 (file)
 #include "socket.h"
 #include "node.h"
 #include "bcast.h"
-
-static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
-       [TIPC_NLA_NET_UNSPEC]   = { .type = NLA_UNSPEC },
-       [TIPC_NLA_NET_ID]       = { .type = NLA_U32 }
-};
+#include "netlink.h"
 
 /*
  * The TIPC locking policy is designed to ensure a very fine locking
@@ -116,7 +112,6 @@ int tipc_net_start(struct net *net, u32 addr)
        tn->own_addr = addr;
        tipc_named_reinit(net);
        tipc_sk_reinit(net);
-       tipc_bcast_reinit(net);
 
        tipc_nametbl_publish(net, TIPC_CFG_SRV, tn->own_addr, tn->own_addr,
                             TIPC_ZONE_SCOPE, 0, tn->own_addr);
index 8975b0135b764d2d0947ee469ad3a08f24e2eee3..56935df2167aee189b8aaa1a8b5e8ec7fd29ddae 100644 (file)
@@ -55,6 +55,75 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
        [TIPC_NLA_NAME_TABLE]   = { .type = NLA_NESTED, }
 };
 
+const struct nla_policy
+tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
+       [TIPC_NLA_NAME_TABLE_UNSPEC]    = { .type = NLA_UNSPEC },
+       [TIPC_NLA_NAME_TABLE_PUBL]      = { .type = NLA_NESTED }
+};
+
+const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
+       [TIPC_NLA_SOCK_UNSPEC]          = { .type = NLA_UNSPEC },
+       [TIPC_NLA_SOCK_ADDR]            = { .type = NLA_U32 },
+       [TIPC_NLA_SOCK_REF]             = { .type = NLA_U32 },
+       [TIPC_NLA_SOCK_CON]             = { .type = NLA_NESTED },
+       [TIPC_NLA_SOCK_HAS_PUBL]        = { .type = NLA_FLAG }
+};
+
+const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
+       [TIPC_NLA_NET_UNSPEC]           = { .type = NLA_UNSPEC },
+       [TIPC_NLA_NET_ID]               = { .type = NLA_U32 }
+};
+
+const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
+       [TIPC_NLA_LINK_UNSPEC]          = { .type = NLA_UNSPEC },
+       [TIPC_NLA_LINK_NAME]            = { .type = NLA_STRING,
+                                           .len = TIPC_MAX_LINK_NAME },
+       [TIPC_NLA_LINK_MTU]             = { .type = NLA_U32 },
+       [TIPC_NLA_LINK_BROADCAST]       = { .type = NLA_FLAG },
+       [TIPC_NLA_LINK_UP]              = { .type = NLA_FLAG },
+       [TIPC_NLA_LINK_ACTIVE]          = { .type = NLA_FLAG },
+       [TIPC_NLA_LINK_PROP]            = { .type = NLA_NESTED },
+       [TIPC_NLA_LINK_STATS]           = { .type = NLA_NESTED },
+       [TIPC_NLA_LINK_RX]              = { .type = NLA_U32 },
+       [TIPC_NLA_LINK_TX]              = { .type = NLA_U32 }
+};
+
+const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
+       [TIPC_NLA_NODE_UNSPEC]          = { .type = NLA_UNSPEC },
+       [TIPC_NLA_NODE_ADDR]            = { .type = NLA_U32 },
+       [TIPC_NLA_NODE_UP]              = { .type = NLA_FLAG }
+};
+
+/* Properties valid for media, bearer and link */
+const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
+       [TIPC_NLA_PROP_UNSPEC]          = { .type = NLA_UNSPEC },
+       [TIPC_NLA_PROP_PRIO]            = { .type = NLA_U32 },
+       [TIPC_NLA_PROP_TOL]             = { .type = NLA_U32 },
+       [TIPC_NLA_PROP_WIN]             = { .type = NLA_U32 }
+};
+
+const struct nla_policy tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = {
+       [TIPC_NLA_BEARER_UNSPEC]        = { .type = NLA_UNSPEC },
+       [TIPC_NLA_BEARER_NAME]          = { .type = NLA_STRING,
+                                           .len = TIPC_MAX_BEARER_NAME },
+       [TIPC_NLA_BEARER_PROP]          = { .type = NLA_NESTED },
+       [TIPC_NLA_BEARER_DOMAIN]        = { .type = NLA_U32 }
+};
+
+const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = {
+       [TIPC_NLA_MEDIA_UNSPEC]         = { .type = NLA_UNSPEC },
+       [TIPC_NLA_MEDIA_NAME]           = { .type = NLA_STRING },
+       [TIPC_NLA_MEDIA_PROP]           = { .type = NLA_NESTED }
+};
+
+const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
+       [TIPC_NLA_UDP_UNSPEC]   = {.type = NLA_UNSPEC},
+       [TIPC_NLA_UDP_LOCAL]    = {.type = NLA_BINARY,
+                                  .len = sizeof(struct sockaddr_storage)},
+       [TIPC_NLA_UDP_REMOTE]   = {.type = NLA_BINARY,
+                                  .len = sizeof(struct sockaddr_storage)},
+};
+
 /* Users of the legacy API (tipc-config) can't handle that we add operations,
  * so we have a separate genl handling for the new API.
  */
index 08a1db67b9272df1f5dc23c96c31847a0b84ed59..ed1dbcb4afbddef0855a385fe8d5e9a4da2b5eeb 100644 (file)
@@ -35,6 +35,7 @@
 
 #ifndef _TIPC_NETLINK_H
 #define _TIPC_NETLINK_H
+#include <net/netlink.h>
 
 extern struct genl_family tipc_genl_family;
 int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***buf);
@@ -45,6 +46,16 @@ struct tipc_nl_msg {
        u32 seq;
 };
 
+extern const struct nla_policy tipc_nl_name_table_policy[];
+extern const struct nla_policy tipc_nl_sock_policy[];
+extern const struct nla_policy tipc_nl_net_policy[];
+extern const struct nla_policy tipc_nl_link_policy[];
+extern const struct nla_policy tipc_nl_node_policy[];
+extern const struct nla_policy tipc_nl_prop_policy[];
+extern const struct nla_policy tipc_nl_bearer_policy[];
+extern const struct nla_policy tipc_nl_media_policy[];
+extern const struct nla_policy tipc_nl_udp_policy[];
+
 int tipc_netlink_start(void);
 int tipc_netlink_compat_start(void);
 void tipc_netlink_stop(void);
index 2c016fdefe977e1fa4f9700a6d44a9ad53c0b75c..d7d050f44fc131942b5e87ab3ce23edbc8376684 100644 (file)
@@ -1104,8 +1104,8 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
        req_nlh = (struct nlmsghdr *)skb->data;
        msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
        msg.cmd = req_userhdr->cmd;
-       msg.dst_sk = info->dst_sk;
        msg.net = genl_info_net(info);
+       msg.dst_sk = skb->sk;
 
        if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
                msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
index f8a8255a7182905ffa3af8e83bf5fd716db38400..ace178fd385038523bc498222e9497245ccae4b0 100644 (file)
@@ -41,6 +41,7 @@
 #include "socket.h"
 #include "bcast.h"
 #include "discover.h"
+#include "netlink.h"
 
 #define INVALID_NODE_SIG       0x10000
 
@@ -164,28 +165,6 @@ struct tipc_sock_conn {
        struct list_head list;
 };
 
-static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
-       [TIPC_NLA_LINK_UNSPEC]          = { .type = NLA_UNSPEC },
-       [TIPC_NLA_LINK_NAME] = {
-               .type = NLA_STRING,
-               .len = TIPC_MAX_LINK_NAME
-       },
-       [TIPC_NLA_LINK_MTU]             = { .type = NLA_U32 },
-       [TIPC_NLA_LINK_BROADCAST]       = { .type = NLA_FLAG },
-       [TIPC_NLA_LINK_UP]              = { .type = NLA_FLAG },
-       [TIPC_NLA_LINK_ACTIVE]          = { .type = NLA_FLAG },
-       [TIPC_NLA_LINK_PROP]            = { .type = NLA_NESTED },
-       [TIPC_NLA_LINK_STATS]           = { .type = NLA_NESTED },
-       [TIPC_NLA_LINK_RX]              = { .type = NLA_U32 },
-       [TIPC_NLA_LINK_TX]              = { .type = NLA_U32 }
-};
-
-static const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
-       [TIPC_NLA_NODE_UNSPEC]          = { .type = NLA_UNSPEC },
-       [TIPC_NLA_NODE_ADDR]            = { .type = NLA_U32 },
-       [TIPC_NLA_NODE_UP]              = { .type = NLA_FLAG }
-};
-
 static struct tipc_link *node_active_link(struct tipc_node *n, int sel)
 {
        int bearer_id = n->active_links[sel & 1];
@@ -225,9 +204,10 @@ static unsigned int tipc_hashfn(u32 addr)
 
 static void tipc_node_kref_release(struct kref *kref)
 {
-       struct tipc_node *node = container_of(kref, struct tipc_node, kref);
+       struct tipc_node *n = container_of(kref, struct tipc_node, kref);
 
-       tipc_node_delete(node);
+       kfree(n->bc_entry.link);
+       kfree_rcu(n, rcu);
 }
 
 static void tipc_node_put(struct tipc_node *node)
@@ -245,23 +225,23 @@ static void tipc_node_get(struct tipc_node *node)
  */
 static struct tipc_node *tipc_node_find(struct net *net, u32 addr)
 {
-       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct tipc_net *tn = tipc_net(net);
        struct tipc_node *node;
+       unsigned int thash = tipc_hashfn(addr);
 
        if (unlikely(!in_own_cluster_exact(net, addr)))
                return NULL;
 
        rcu_read_lock();
-       hlist_for_each_entry_rcu(node, &tn->node_htable[tipc_hashfn(addr)],
-                                hash) {
-               if (node->addr == addr) {
-                       tipc_node_get(node);
-                       rcu_read_unlock();
-                       return node;
-               }
+       hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) {
+               if (node->addr != addr)
+                       continue;
+               if (!kref_get_unless_zero(&node->kref))
+                       node = NULL;
+               break;
        }
        rcu_read_unlock();
-       return NULL;
+       return node;
 }
 
 static void tipc_node_read_lock(struct tipc_node *n)
@@ -346,12 +326,6 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
        skb_queue_head_init(&n->bc_entry.inputq2);
        for (i = 0; i < MAX_BEARERS; i++)
                spin_lock_init(&n->links[i].lock);
-       hlist_add_head_rcu(&n->hash, &tn->node_htable[tipc_hashfn(addr)]);
-       list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
-               if (n->addr < temp_node->addr)
-                       break;
-       }
-       list_add_tail_rcu(&n->list, &temp_node->list);
        n->state = SELF_DOWN_PEER_LEAVING;
        n->signature = INVALID_NODE_SIG;
        n->active_links[0] = INVALID_BEARER_ID;
@@ -372,6 +346,12 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)
        tipc_node_get(n);
        setup_timer(&n->timer, tipc_node_timeout, (unsigned long)n);
        n->keepalive_intv = U32_MAX;
+       hlist_add_head_rcu(&n->hash, &tn->node_htable[tipc_hashfn(addr)]);
+       list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
+               if (n->addr < temp_node->addr)
+                       break;
+       }
+       list_add_tail_rcu(&n->list, &temp_node->list);
 exit:
        spin_unlock_bh(&tn->node_list_lock);
        return n;
@@ -395,21 +375,20 @@ static void tipc_node_delete(struct tipc_node *node)
 {
        list_del_rcu(&node->list);
        hlist_del_rcu(&node->hash);
-       kfree(node->bc_entry.link);
-       kfree_rcu(node, rcu);
+       tipc_node_put(node);
+
+       del_timer_sync(&node->timer);
+       tipc_node_put(node);
 }
 
 void tipc_node_stop(struct net *net)
 {
-       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct tipc_net *tn = tipc_net(net);
        struct tipc_node *node, *t_node;
 
        spin_lock_bh(&tn->node_list_lock);
-       list_for_each_entry_safe(node, t_node, &tn->node_list, list) {
-               if (del_timer(&node->timer))
-                       tipc_node_put(node);
-               tipc_node_put(node);
-       }
+       list_for_each_entry_safe(node, t_node, &tn->node_list, list)
+               tipc_node_delete(node);
        spin_unlock_bh(&tn->node_list_lock);
 }
 
@@ -530,9 +509,7 @@ static void tipc_node_timeout(unsigned long data)
                if (rc & TIPC_LINK_DOWN_EVT)
                        tipc_node_link_down(n, bearer_id, false);
        }
-       if (!mod_timer(&n->timer, jiffies + n->keepalive_intv))
-               tipc_node_get(n);
-       tipc_node_put(n);
+       mod_timer(&n->timer, jiffies + n->keepalive_intv);
 }
 
 /**
@@ -845,7 +822,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,
        memcpy(&le->maddr, maddr, sizeof(*maddr));
 exit:
        tipc_node_write_unlock(n);
-       if (reset && !tipc_link_is_reset(l))
+       if (reset && l && !tipc_link_is_reset(l))
                tipc_node_link_down(n, b->identity, false);
        tipc_node_put(n);
 }
@@ -1166,7 +1143,7 @@ msg_full:
  * @dnode: address of destination node
  * @selector: a number used for deterministic link selection
  * Consumes the buffer chain, except when returning -ELINKCONG
- * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
+ * Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF
  */
 int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
                   u32 dnode, int selector)
@@ -1174,33 +1151,43 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
        struct tipc_link_entry *le = NULL;
        struct tipc_node *n;
        struct sk_buff_head xmitq;
-       int bearer_id = -1;
-       int rc = -EHOSTUNREACH;
+       int bearer_id;
+       int rc;
+
+       if (in_own_node(net, dnode)) {
+               tipc_sk_rcv(net, list);
+               return 0;
+       }
 
-       __skb_queue_head_init(&xmitq);
        n = tipc_node_find(net, dnode);
-       if (likely(n)) {
-               tipc_node_read_lock(n);
-               bearer_id = n->active_links[selector & 1];
-               if (bearer_id >= 0) {
-                       le = &n->links[bearer_id];
-                       spin_lock_bh(&le->lock);
-                       rc = tipc_link_xmit(le->link, list, &xmitq);
-                       spin_unlock_bh(&le->lock);
-               }
+       if (unlikely(!n)) {
+               skb_queue_purge(list);
+               return -EHOSTUNREACH;
+       }
+
+       tipc_node_read_lock(n);
+       bearer_id = n->active_links[selector & 1];
+       if (unlikely(bearer_id == INVALID_BEARER_ID)) {
                tipc_node_read_unlock(n);
-               if (likely(!rc))
-                       tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
-               else if (rc == -ENOBUFS)
-                       tipc_node_link_down(n, bearer_id, false);
                tipc_node_put(n);
-               return rc;
+               skb_queue_purge(list);
+               return -EHOSTUNREACH;
        }
 
-       if (likely(in_own_node(net, dnode))) {
-               tipc_sk_rcv(net, list);
-               return 0;
-       }
+       __skb_queue_head_init(&xmitq);
+       le = &n->links[bearer_id];
+       spin_lock_bh(&le->lock);
+       rc = tipc_link_xmit(le->link, list, &xmitq);
+       spin_unlock_bh(&le->lock);
+       tipc_node_read_unlock(n);
+
+       if (likely(rc == 0))
+               tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
+       else if (rc == -ENOBUFS)
+               tipc_node_link_down(n, bearer_id, false);
+
+       tipc_node_put(n);
+
        return rc;
 }
 
index 69c29050f14abe8c926db671dfa05c96f2ddc3bc..3eeb50a27b89b6d9607b51b80a5ed5ce715235e4 100644 (file)
@@ -42,6 +42,7 @@
 #include "name_distr.h"
 #include "socket.h"
 #include "bcast.h"
+#include "netlink.h"
 
 #define SS_LISTENING           -1      /* socket is listening */
 #define SS_READY               -2      /* socket is connectionless */
@@ -126,14 +127,6 @@ static const struct proto_ops stream_ops;
 static const struct proto_ops msg_ops;
 static struct proto tipc_proto;
 
-static const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
-       [TIPC_NLA_SOCK_UNSPEC]          = { .type = NLA_UNSPEC },
-       [TIPC_NLA_SOCK_ADDR]            = { .type = NLA_U32 },
-       [TIPC_NLA_SOCK_REF]             = { .type = NLA_U32 },
-       [TIPC_NLA_SOCK_CON]             = { .type = NLA_NESTED },
-       [TIPC_NLA_SOCK_HAS_PUBL]        = { .type = NLA_FLAG }
-};
-
 static const struct rhashtable_params tsk_rht_params;
 
 /*
@@ -673,7 +666,7 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
        struct tipc_sock *tsk = tipc_sk(sk);
        struct net *net = sock_net(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        struct iov_iter save = msg->msg_iter;
        uint mtu;
        int rc;
@@ -687,14 +680,16 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
        msg_set_nameupper(mhdr, seq->upper);
        msg_set_hdr_sz(mhdr, MCAST_H_SIZE);
 
+       skb_queue_head_init(&pktchain);
+
 new_mtu:
        mtu = tipc_bcast_get_mtu(net);
-       rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, msg, 0, dsz, mtu, &pktchain);
        if (unlikely(rc < 0))
                return rc;
 
        do {
-               rc = tipc_bcast_xmit(net, pktchain);
+               rc = tipc_bcast_xmit(net, &pktchain);
                if (likely(!rc))
                        return dsz;
 
@@ -704,7 +699,7 @@ new_mtu:
                        if (!rc)
                                continue;
                }
-               __skb_queue_purge(pktchain);
+               __skb_queue_purge(&pktchain);
                if (rc == -EMSGSIZE) {
                        msg->msg_iter = save;
                        goto new_mtu;
@@ -863,7 +858,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
        struct net *net = sock_net(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
        u32 dnode, dport;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        struct sk_buff *skb;
        struct tipc_name_seq *seq;
        struct iov_iter save;
@@ -924,17 +919,18 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)
                msg_set_hdr_sz(mhdr, BASIC_H_SIZE);
        }
 
+       skb_queue_head_init(&pktchain);
        save = m->msg_iter;
 new_mtu:
        mtu = tipc_node_get_mtu(net, dnode, tsk->portid);
-       rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, m, 0, dsz, mtu, &pktchain);
        if (rc < 0)
                return rc;
 
        do {
-               skb = skb_peek(pktchain);
+               skb = skb_peek(&pktchain);
                TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;
-               rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid);
+               rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid);
                if (likely(!rc)) {
                        if (sock->state != SS_READY)
                                sock->state = SS_CONNECTING;
@@ -946,7 +942,7 @@ new_mtu:
                        if (!rc)
                                continue;
                }
-               __skb_queue_purge(pktchain);
+               __skb_queue_purge(&pktchain);
                if (rc == -EMSGSIZE) {
                        m->msg_iter = save;
                        goto new_mtu;
@@ -1016,7 +1012,7 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
        struct net *net = sock_net(sk);
        struct tipc_sock *tsk = tipc_sk(sk);
        struct tipc_msg *mhdr = &tsk->phdr;
-       struct sk_buff_head *pktchain = &sk->sk_write_queue;
+       struct sk_buff_head pktchain;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        u32 portid = tsk->portid;
        int rc = -EINVAL;
@@ -1044,17 +1040,19 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
        dnode = tsk_peer_node(tsk);
+       skb_queue_head_init(&pktchain);
 
 next:
        save = m->msg_iter;
        mtu = tsk->max_pkt;
        send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
-       rc = tipc_msg_build(mhdr, m, sent, send, mtu, pktchain);
+       rc = tipc_msg_build(mhdr, m, sent, send, mtu, &pktchain);
        if (unlikely(rc < 0))
                return rc;
+
        do {
                if (likely(!tsk_conn_cong(tsk))) {
-                       rc = tipc_node_xmit(net, pktchain, dnode, portid);
+                       rc = tipc_node_xmit(net, &pktchain, dnode, portid);
                        if (likely(!rc)) {
                                tsk->sent_unacked++;
                                sent += send;
@@ -1063,7 +1061,7 @@ next:
                                goto next;
                        }
                        if (rc == -EMSGSIZE) {
-                               __skb_queue_purge(pktchain);
+                               __skb_queue_purge(&pktchain);
                                tsk->max_pkt = tipc_node_get_mtu(net, dnode,
                                                                 portid);
                                m->msg_iter = save;
@@ -1077,7 +1075,7 @@ next:
                rc = tipc_wait_for_sndpkt(sock, &timeo);
        } while (!rc);
 
-       __skb_queue_purge(pktchain);
+       __skb_queue_purge(&pktchain);
        return sent ? sent : rc;
 }
 
index 22963cafd5ede27d59ecb772d1cd5c4257cacb98..e6cb386fbf3469017f805e5db135d04b86a30d78 100644 (file)
@@ -326,7 +326,8 @@ static void tipc_subscrb_rcv_cb(struct net *net, int conid,
                return tipc_subscrp_cancel(s, subscriber);
        }
 
-       tipc_subscrp_subscribe(net, s, subscriber, swap);
+       if (s)
+               tipc_subscrp_subscribe(net, s, subscriber, swap);
 }
 
 /* Handle one request to establish a new subscriber */
index d63a911e7fe29b2f4ef9c1795e47cf5feb006be0..c94f9a15e2cd663d83d22ce205fd2a937d111228 100644 (file)
 #include <linux/tipc_netlink.h>
 #include "core.h"
 #include "bearer.h"
+#include "netlink.h"
 
 /* IANA assigned UDP port */
 #define UDP_PORT_DEFAULT       6118
 
 #define UDP_MIN_HEADROOM        28
 
-static const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
-       [TIPC_NLA_UDP_UNSPEC]   = {.type = NLA_UNSPEC},
-       [TIPC_NLA_UDP_LOCAL]    = {.type = NLA_BINARY,
-                                  .len = sizeof(struct sockaddr_storage)},
-       [TIPC_NLA_UDP_REMOTE]   = {.type = NLA_BINARY,
-                                  .len = sizeof(struct sockaddr_storage)},
-};
-
 /**
  * struct udp_media_addr - IP/UDP addressing information
  *
@@ -181,6 +174,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
                        err = PTR_ERR(rt);
                        goto tx_error;
                }
+
+               skb->dev = rt->dst.dev;
                ttl = ip4_dst_hoplimit(&rt->dst);
                udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
                                    dst->ipv4.s_addr, 0, ttl, 0, src->udp_port,
@@ -201,7 +196,7 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
                ttl = ip6_dst_hoplimit(ndst);
                err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb,
                                           ndst->dev, &src->ipv6,
-                                          &dst->ipv6, 0, ttl, src->udp_port,
+                                          &dst->ipv6, 0, ttl, 0, src->udp_port,
                                           dst->udp_port, false);
 #endif
        }
@@ -274,7 +269,7 @@ static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub,
                         struct udp_media_addr *remote)
 {
        struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
-       struct sockaddr_storage *sa_local, *sa_remote;
+       struct sockaddr_storage sa_local, sa_remote;
 
        if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
                goto err;
@@ -283,41 +278,48 @@ static int parse_options(struct nlattr *attrs[], struct udp_bearer *ub,
                             tipc_nl_udp_policy))
                goto err;
        if (opts[TIPC_NLA_UDP_LOCAL] && opts[TIPC_NLA_UDP_REMOTE]) {
-               sa_local = nla_data(opts[TIPC_NLA_UDP_LOCAL]);
-               sa_remote = nla_data(opts[TIPC_NLA_UDP_REMOTE]);
+               nla_memcpy(&sa_local, opts[TIPC_NLA_UDP_LOCAL],
+                          sizeof(sa_local));
+               nla_memcpy(&sa_remote, opts[TIPC_NLA_UDP_REMOTE],
+                          sizeof(sa_remote));
        } else {
 err:
                pr_err("Invalid UDP bearer configuration");
                return -EINVAL;
        }
-       if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET) {
+       if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET) {
                struct sockaddr_in *ip4;
 
-               ip4 = (struct sockaddr_in *)sa_local;
+               ip4 = (struct sockaddr_in *)&sa_local;
                local->proto = htons(ETH_P_IP);
                local->udp_port = ip4->sin_port;
                local->ipv4.s_addr = ip4->sin_addr.s_addr;
 
-               ip4 = (struct sockaddr_in *)sa_remote;
+               ip4 = (struct sockaddr_in *)&sa_remote;
                remote->proto = htons(ETH_P_IP);
                remote->udp_port = ip4->sin_port;
                remote->ipv4.s_addr = ip4->sin_addr.s_addr;
                return 0;
 
 #if IS_ENABLED(CONFIG_IPV6)
-       } else if ((sa_local->ss_family & sa_remote->ss_family) == AF_INET6) {
+       } else if ((sa_local.ss_family & sa_remote.ss_family) == AF_INET6) {
+               int atype;
                struct sockaddr_in6 *ip6;
 
-               ip6 = (struct sockaddr_in6 *)sa_local;
+               ip6 = (struct sockaddr_in6 *)&sa_local;
+               atype = ipv6_addr_type(&ip6->sin6_addr);
+               if (__ipv6_addr_needs_scope_id(atype) && !ip6->sin6_scope_id)
+                       return -EINVAL;
+
                local->proto = htons(ETH_P_IPV6);
                local->udp_port = ip6->sin6_port;
-               local->ipv6 = ip6->sin6_addr;
+               memcpy(&local->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
                ub->ifindex = ip6->sin6_scope_id;
 
-               ip6 = (struct sockaddr_in6 *)sa_remote;
+               ip6 = (struct sockaddr_in6 *)&sa_remote;
                remote->proto = htons(ETH_P_IPV6);
                remote->udp_port = ip6->sin6_port;
-               remote->ipv6 = ip6->sin6_addr;
+               memcpy(&remote->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
                return 0;
 #endif
        }
index b3745557fc89b35703d683431336f6a6bf2e629f..8269da73e9e5f1753f293f79149d5d4216fc0d30 100644 (file)
@@ -1496,7 +1496,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
        UNIXCB(skb).fp = NULL;
 
        for (i = scm->fp->count-1; i >= 0; i--)
-               unix_notinflight(scm->fp->fp[i]);
+               unix_notinflight(scm->fp->user, scm->fp->fp[i]);
 }
 
 static void unix_destruct_scm(struct sk_buff *skb)
@@ -1558,7 +1558,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
                return -ENOMEM;
 
        for (i = scm->fp->count - 1; i >= 0; i--)
-               unix_inflight(scm->fp->fp[i]);
+               unix_inflight(scm->fp->user, scm->fp->fp[i]);
        return max_level;
 }
 
@@ -1778,7 +1778,12 @@ restart_locked:
                        goto out_unlock;
        }
 
-       if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+       /* other == sk && unix_peer(other) != sk if
+        * - unix_peer(sk) == NULL, destination address bound to sk
+        * - unix_peer(sk) == sk by time of get but disconnected before lock
+        */
+       if (other != sk &&
+           unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
                if (timeo) {
                        timeo = unix_wait_for_peer(other, timeo);
 
@@ -2274,13 +2279,15 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
        size_t size = state->size;
        unsigned int last_len;
 
-       err = -EINVAL;
-       if (sk->sk_state != TCP_ESTABLISHED)
+       if (unlikely(sk->sk_state != TCP_ESTABLISHED)) {
+               err = -EINVAL;
                goto out;
+       }
 
-       err = -EOPNOTSUPP;
-       if (flags & MSG_OOB)
+       if (unlikely(flags & MSG_OOB)) {
+               err = -EOPNOTSUPP;
                goto out;
+       }
 
        target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
        timeo = sock_rcvtimeo(sk, noblock);
@@ -2302,6 +2309,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
                bool drop_skb;
                struct sk_buff *skb, *last;
 
+redo:
                unix_state_lock(sk);
                if (sock_flag(sk, SOCK_DEAD)) {
                        err = -ECONNRESET;
@@ -2326,9 +2334,11 @@ again:
                                goto unlock;
 
                        unix_state_unlock(sk);
-                       err = -EAGAIN;
-                       if (!timeo)
+                       if (!timeo) {
+                               err = -EAGAIN;
                                break;
+                       }
+
                        mutex_unlock(&u->readlock);
 
                        timeo = unix_stream_data_wait(sk, timeo, last,
@@ -2341,7 +2351,7 @@ again:
                        }
 
                        mutex_lock(&u->readlock);
-                       continue;
+                       goto redo;
 unlock:
                        unix_state_unlock(sk);
                        break;
index c512f64d528766f940b30236bf3e3c8fa2047661..4d9679701a6df5113df3e24a1c9b86e2a63b3710 100644 (file)
@@ -220,7 +220,7 @@ done:
        return skb->len;
 }
 
-static struct sock *unix_lookup_by_ino(int ino)
+static struct sock *unix_lookup_by_ino(unsigned int ino)
 {
        int i;
        struct sock *sk;
index 8fcdc2283af50c5caecd409b79cae6028ca2c836..6a0d48525fcf9a71f54bb43495b200b300f5341e 100644 (file)
@@ -116,7 +116,7 @@ struct sock *unix_get_socket(struct file *filp)
  * descriptor if it is for an AF_UNIX socket.
  */
 
-void unix_inflight(struct file *fp)
+void unix_inflight(struct user_struct *user, struct file *fp)
 {
        struct sock *s = unix_get_socket(fp);
 
@@ -133,11 +133,11 @@ void unix_inflight(struct file *fp)
                }
                unix_tot_inflight++;
        }
-       fp->f_cred->user->unix_inflight++;
+       user->unix_inflight++;
        spin_unlock(&unix_gc_lock);
 }
 
-void unix_notinflight(struct file *fp)
+void unix_notinflight(struct user_struct *user, struct file *fp)
 {
        struct sock *s = unix_get_socket(fp);
 
@@ -152,7 +152,7 @@ void unix_notinflight(struct file *fp)
                        list_del_init(&u->link);
                unix_tot_inflight--;
        }
-       fp->f_cred->user->unix_inflight--;
+       user->unix_inflight--;
        spin_unlock(&unix_gc_lock);
 }
 
index 7fd1220fbfa0bb2477e2b7e6edcf714a5ae6a097..bbe65dcb973834761c30cef249a537ba498898fb 100644 (file)
@@ -1557,8 +1557,6 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
        if (err < 0)
                goto out;
 
-       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-
        while (total_written < len) {
                ssize_t written;
 
@@ -1578,7 +1576,9 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
                                goto out_wait;
 
                        release_sock(sk);
+                       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                        timeout = schedule_timeout(timeout);
+                       finish_wait(sk_sleep(sk), &wait);
                        lock_sock(sk);
                        if (signal_pending(current)) {
                                err = sock_intr_errno(timeout);
@@ -1588,8 +1588,6 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
                                goto out_wait;
                        }
 
-                       prepare_to_wait(sk_sleep(sk), &wait,
-                                       TASK_INTERRUPTIBLE);
                }
 
                /* These checks occur both as part of and after the loop
@@ -1635,7 +1633,6 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 out_wait:
        if (total_written > 0)
                err = total_written;
-       finish_wait(sk_sleep(sk), &wait);
 out:
        release_sock(sk);
        return err;
@@ -1716,7 +1713,6 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
        if (err < 0)
                goto out;
 
-       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        while (1) {
                s64 ready = vsock_stream_has_data(vsk);
@@ -1727,7 +1723,7 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                         */
 
                        err = -ENOMEM;
-                       goto out_wait;
+                       goto out;
                } else if (ready > 0) {
                        ssize_t read;
 
@@ -1750,7 +1746,7 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                                        vsk, target, read,
                                        !(flags & MSG_PEEK), &recv_data);
                        if (err < 0)
-                               goto out_wait;
+                               goto out;
 
                        if (read >= target || flags & MSG_PEEK)
                                break;
@@ -1773,7 +1769,9 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                                break;
 
                        release_sock(sk);
+                       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                        timeout = schedule_timeout(timeout);
+                       finish_wait(sk_sleep(sk), &wait);
                        lock_sock(sk);
 
                        if (signal_pending(current)) {
@@ -1783,9 +1781,6 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                                err = -EAGAIN;
                                break;
                        }
-
-                       prepare_to_wait(sk_sleep(sk), &wait,
-                                       TASK_INTERRUPTIBLE);
                }
        }
 
@@ -1816,8 +1811,6 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                err = copied;
        }
 
-out_wait:
-       finish_wait(sk_sleep(sk), &wait);
 out:
        release_sock(sk);
        return err;
index da72ed32f14385c3e218cda196e5b4c3511c896e..6c606120abfed96fe7fe4cdb23beb204e5ea109a 100644 (file)
@@ -50,8 +50,8 @@ config CFG80211_DEVELOPER_WARNINGS
        default n
        help
          This option enables some additional warnings that help
-         cfg80211 developers and driver developers, but that can
-         trigger due to races with userspace.
+         cfg80211 developers and driver developers, but beware that
+         they can also trigger due to races with userspace.
 
          For example, when a driver reports that it was disconnected
          from the AP, but the user disconnects manually at the same
@@ -61,19 +61,6 @@ config CFG80211_DEVELOPER_WARNINGS
          on it (or mac80211).
 
 
-config CFG80211_REG_DEBUG
-       bool "cfg80211 regulatory debugging"
-       depends on CFG80211
-       default n
-       ---help---
-         You can enable this if you want to debug regulatory changes.
-         For more information on cfg80211 regulatory refer to the wireless
-         wiki:
-
-         http://wireless.kernel.org/en/developers/Regulatory
-
-         If unsure, say N.
-
 config CFG80211_CERTIFICATION_ONUS
        bool "cfg80211 certification onus"
        depends on CFG80211 && EXPERT
@@ -123,7 +110,7 @@ config CFG80211_REG_RELAX_NO_IR
         interface which associated to an AP which userspace assumes or confirms
         to be an authorized master, i.e., with radar detection support and DFS
         capabilities. However, note that in order to not create daisy chain
-        scenarios, this relaxation is not allowed in cases that the BSS client
+        scenarios, this relaxation is not allowed in cases where the BSS client
         is associated to P2P GO and in addition the P2P GO instantiated on
         a channel due to this relaxation should not allow connection from
         non P2P clients.
@@ -148,7 +135,7 @@ config CFG80211_DEBUGFS
        depends on CFG80211
        depends on DEBUG_FS
        ---help---
-         You can enable this if you want to debugfs entries for cfg80211.
+         You can enable this if you want debugfs entries for cfg80211.
 
          If unsure, say N.
 
@@ -159,7 +146,7 @@ config CFG80211_INTERNAL_REGDB
        ---help---
          This option generates an internal data structure representing
          the wireless regulatory rules described in net/wireless/db.txt
-         and includes code to query that database.  This is an alternative
+         and includes code to query that database. This is an alternative
          to using CRDA for defining regulatory rules for the kernel.
 
          Using this option requires some parsing of the db.txt at build time,
@@ -172,7 +159,7 @@ config CFG80211_INTERNAL_REGDB
 
          http://wireless.kernel.org/en/developers/Regulatory
 
-         Most distributions have a CRDA package.  So if unsure, say N.
+         Most distributions have a CRDA package. So if unsure, say N.
 
 config CFG80211_CRDA_SUPPORT
        bool "support CRDA" if CFG80211_INTERNAL_REGDB
index b0915515640efed1ff4795103c0572aba48c38f4..9f1c4aa851efdf55ab81044b10ef58b7bd73ecf6 100644 (file)
@@ -352,6 +352,16 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
        WARN_ON(ops->add_station && !ops->del_station);
        WARN_ON(ops->add_mpath && !ops->del_mpath);
        WARN_ON(ops->join_mesh && !ops->leave_mesh);
+       WARN_ON(ops->start_p2p_device && !ops->stop_p2p_device);
+       WARN_ON(ops->start_ap && !ops->stop_ap);
+       WARN_ON(ops->join_ocb && !ops->leave_ocb);
+       WARN_ON(ops->suspend && !ops->resume);
+       WARN_ON(ops->sched_scan_start && !ops->sched_scan_stop);
+       WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
+       WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
+       WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
+       WARN_ON(ops->set_tx_power && !ops->get_tx_power);
+       WARN_ON(ops->set_antenna && !ops->get_antenna);
 
        alloc_size = sizeof(*rdev) + sizeof_priv;
 
@@ -1147,6 +1157,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                return NOTIFY_DONE;
        }
 
+       wireless_nlevent_flush();
+
        return NOTIFY_OK;
 }
 
index fb44fa3bf4efa750298163a15534572c43229b2e..ff328250bc442db6a9e8e5136496098d4270bf6f 100644 (file)
@@ -711,7 +711,7 @@ EXPORT_SYMBOL(cfg80211_rx_mgmt);
 
 void cfg80211_dfs_channels_update_work(struct work_struct *work)
 {
-       struct delayed_work *delayed_work;
+       struct delayed_work *delayed_work = to_delayed_work(work);
        struct cfg80211_registered_device *rdev;
        struct cfg80211_chan_def chandef;
        struct ieee80211_supported_band *sband;
@@ -721,7 +721,6 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
        unsigned long timeout, next_time = 0;
        int bandid, i;
 
-       delayed_work = container_of(work, struct delayed_work, work);
        rdev = container_of(delayed_work, struct cfg80211_registered_device,
                            dfs_update_channels_wk);
        wiphy = &rdev->wiphy;
index d4786f2802aa3c94f0a9bfcba846c98ec5b2b249..98c924260b3d312055c598255cff8478bccba1e9 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright 2015      Intel Deutschland GmbH
+ * Copyright 2015-2016 Intel Deutschland GmbH
  */
 
 #include <linux/if.h>
@@ -401,6 +401,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
        [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
        [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
+       [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3461,6 +3462,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                        return PTR_ERR(params.acl);
        }
 
+       params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
+       if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
+               return -EOPNOTSUPP;
+
        wdev_lock(wdev);
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
@@ -7281,9 +7286,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
-               if (!(rdev->wiphy.features &
-                     NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
-                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+               if (!((rdev->wiphy.features &
+                       NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
+                      (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
+                   !wiphy_ext_feature_isset(&rdev->wiphy,
+                                            NL80211_EXT_FEATURE_RRM))
                        return -EINVAL;
                req.flags |= ASSOC_REQ_USE_RRM;
        }
@@ -7547,7 +7554,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 
                if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
                    no_ht) {
-                       kfree(connkeys);
+                       kzfree(connkeys);
                        return -EINVAL;
                }
        }
@@ -7971,15 +7978,23 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
-               if (!(rdev->wiphy.features &
-                     NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
-                   !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
+               if (!((rdev->wiphy.features &
+                       NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
+                      (rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
+                   !wiphy_ext_feature_isset(&rdev->wiphy,
+                                            NL80211_EXT_FEATURE_RRM)) {
                        kzfree(connkeys);
                        return -EINVAL;
                }
                connect.flags |= ASSOC_REQ_USE_RRM;
        }
 
+       connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
+       if (connect.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) {
+               kzfree(connkeys);
+               return -EOPNOTSUPP;
+       }
+
        wdev_lock(dev->ieee80211_ptr);
        err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
        wdev_unlock(dev->ieee80211_ptr);
index 722da616438cd1e933fb4d5e60a2c4846f44d186..6582d155e2fce5417bc498a438ae9a19a3eca35f 100644 (file)
@@ -43,6 +43,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
        [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
        [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
        [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+       [IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
        /*
         * add more here as they are defined in radiotap.h
         */
index 547ceecc052310f3db3be04d827dff22d567dc1e..c5fb317eee68f15a4665a090f7aee16b08ec6765 100644 (file)
 #include "regdb.h"
 #include "nl80211.h"
 
-#ifdef CONFIG_CFG80211_REG_DEBUG
-#define REG_DBG_PRINT(format, args...)                 \
-       printk(KERN_DEBUG pr_fmt(format), ##args)
-#else
-#define REG_DBG_PRINT(args...)
-#endif
-
 /*
  * Grace period we give before making sure all current interfaces reside on
  * channels allowed by the current regulatory domain.
@@ -178,12 +171,10 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
        if (wiphy_regd->dfs_region == regd->dfs_region)
                goto out;
 
-       REG_DBG_PRINT("%s: device specific dfs_region "
-                     "(%s) disagrees with cfg80211's "
-                     "central dfs_region (%s)\n",
-                     dev_name(&wiphy->dev),
-                     reg_dfs_region_str(wiphy_regd->dfs_region),
-                     reg_dfs_region_str(regd->dfs_region));
+       pr_debug("%s: device specific dfs_region (%s) disagrees with cfg80211's central dfs_region (%s)\n",
+                dev_name(&wiphy->dev),
+                reg_dfs_region_str(wiphy_regd->dfs_region),
+                reg_dfs_region_str(regd->dfs_region));
 
 out:
        return regd->dfs_region;
@@ -543,7 +534,7 @@ static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work);
 
 static void crda_timeout_work(struct work_struct *work)
 {
-       REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
        rtnl_lock();
        reg_crda_timeouts++;
        restore_regulatory_settings(true);
@@ -585,7 +576,7 @@ static int call_crda(const char *alpha2)
 
        if (!is_world_regdom((char *) alpha2))
                pr_debug("Calling CRDA for country: %c%c\n",
-                       alpha2[0], alpha2[1]);
+                        alpha2[0], alpha2[1]);
        else
                pr_debug("Calling CRDA to update world regulatory domain\n");
 
@@ -1132,42 +1123,6 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
 }
 EXPORT_SYMBOL(reg_initiator_name);
 
-static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
-                                   struct ieee80211_channel *chan,
-                                   const struct ieee80211_reg_rule *reg_rule)
-{
-#ifdef CONFIG_CFG80211_REG_DEBUG
-       const struct ieee80211_power_rule *power_rule;
-       const struct ieee80211_freq_range *freq_range;
-       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, sizeof(max_antenna_gain), "N/A");
-       else
-               snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d mBi",
-                        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(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 @ %s), (%s, %d mBm)\n",
-                     freq_range->start_freq_khz, freq_range->end_freq_khz,
-                     bw, max_antenna_gain,
-                     power_rule->max_eirp);
-#endif
-}
-
 static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd,
                                          const struct ieee80211_reg_rule *reg_rule,
                                          const struct ieee80211_channel *chan)
@@ -1242,20 +1197,19 @@ static void handle_channel(struct wiphy *wiphy,
                if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
                    request_wiphy && request_wiphy == wiphy &&
                    request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
-                       REG_DBG_PRINT("Disabling freq %d MHz for good\n",
-                                     chan->center_freq);
+                       pr_debug("Disabling freq %d MHz for good\n",
+                                chan->center_freq);
                        chan->orig_flags |= IEEE80211_CHAN_DISABLED;
                        chan->flags = chan->orig_flags;
                } else {
-                       REG_DBG_PRINT("Disabling freq %d MHz\n",
-                                     chan->center_freq);
+                       pr_debug("Disabling freq %d MHz\n",
+                                chan->center_freq);
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                }
                return;
        }
 
        regd = reg_get_regdomain(wiphy);
-       chan_reg_rule_print_dbg(regd, chan, reg_rule);
 
        power_rule = &reg_rule->power_rule;
        bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
@@ -1393,18 +1347,15 @@ static bool ignore_reg_update(struct wiphy *wiphy,
                return true;
 
        if (!lr) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since last_request is not set\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since last_request is not set\n",
+                        reg_initiator_name(initiator));
                return true;
        }
 
        if (initiator == NL80211_REGDOM_SET_BY_CORE &&
            wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since the driver uses its own custom "
-                             "regulatory domain\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since the driver uses its own custom regulatory domain\n",
+                        reg_initiator_name(initiator));
                return true;
        }
 
@@ -1415,10 +1366,8 @@ static bool ignore_reg_update(struct wiphy *wiphy,
        if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
            initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
            !is_world_regdom(lr->alpha2)) {
-               REG_DBG_PRINT("Ignoring regulatory request set by %s "
-                             "since the driver requires its own regulatory "
-                             "domain to be set first\n",
-                             reg_initiator_name(initiator));
+               pr_debug("Ignoring regulatory request set by %s since the driver requires its own regulatory domain to be set first\n",
+                        reg_initiator_name(initiator));
                return true;
        }
 
@@ -1699,7 +1648,7 @@ static void reg_check_chans_work(struct work_struct *work)
 {
        struct cfg80211_registered_device *rdev;
 
-       REG_DBG_PRINT("Verifying active interfaces after reg change\n");
+       pr_debug("Verifying active interfaces after reg change\n");
        rtnl_lock();
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list)
@@ -1781,8 +1730,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
        }
 
        if (IS_ERR(reg_rule)) {
-               REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
-                             chan->center_freq);
+               pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
+                        chan->center_freq);
                if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
                        chan->flags |= IEEE80211_CHAN_DISABLED;
                } else {
@@ -1792,8 +1741,6 @@ static void handle_channel_custom(struct wiphy *wiphy,
                return;
        }
 
-       chan_reg_rule_print_dbg(regd, chan, reg_rule);
-
        power_rule = &reg_rule->power_rule;
        bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
 
@@ -2524,7 +2471,7 @@ static void restore_alpha2(char *alpha2, bool reset_user)
        if (is_user_regdom_saved()) {
                /* Unless we're asked to ignore it and reset it */
                if (reset_user) {
-                       REG_DBG_PRINT("Restoring regulatory settings including user preference\n");
+                       pr_debug("Restoring regulatory settings including user preference\n");
                        user_alpha2[0] = '9';
                        user_alpha2[1] = '7';
 
@@ -2534,24 +2481,24 @@ static void restore_alpha2(char *alpha2, bool reset_user)
                         * back as they were for a full restore.
                         */
                        if (!is_world_regdom(ieee80211_regdom)) {
-                               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
-                                             ieee80211_regdom[0], ieee80211_regdom[1]);
+                               pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                                        ieee80211_regdom[0], ieee80211_regdom[1]);
                                alpha2[0] = ieee80211_regdom[0];
                                alpha2[1] = ieee80211_regdom[1];
                        }
                } else {
-                       REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n",
-                                     user_alpha2[0], user_alpha2[1]);
+                       pr_debug("Restoring regulatory settings while preserving user preference for: %c%c\n",
+                                user_alpha2[0], user_alpha2[1]);
                        alpha2[0] = user_alpha2[0];
                        alpha2[1] = user_alpha2[1];
                }
        } else if (!is_world_regdom(ieee80211_regdom)) {
-               REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
-                             ieee80211_regdom[0], ieee80211_regdom[1]);
+               pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
+                        ieee80211_regdom[0], ieee80211_regdom[1]);
                alpha2[0] = ieee80211_regdom[0];
                alpha2[1] = ieee80211_regdom[1];
        } else
-               REG_DBG_PRINT("Restoring regulatory settings\n");
+               pr_debug("Restoring regulatory settings\n");
 }
 
 static void restore_custom_reg_settings(struct wiphy *wiphy)
@@ -2663,14 +2610,14 @@ static void restore_regulatory_settings(bool reset_user)
        list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);
        spin_unlock(&reg_requests_lock);
 
-       REG_DBG_PRINT("Kicking the queue\n");
+       pr_debug("Kicking the queue\n");
 
        schedule_work(&reg_work);
 }
 
 void regulatory_hint_disconnect(void)
 {
-       REG_DBG_PRINT("All devices are disconnected, going to restore regulatory settings\n");
+       pr_debug("All devices are disconnected, going to restore regulatory settings\n");
        restore_regulatory_settings(false);
 }
 
@@ -2718,10 +2665,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
        if (!reg_beacon)
                return -ENOMEM;
 
-       REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
-                     beacon_chan->center_freq,
-                     ieee80211_frequency_to_channel(beacon_chan->center_freq),
-                     wiphy_name(wiphy));
+       pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
+                beacon_chan->center_freq,
+                ieee80211_frequency_to_channel(beacon_chan->center_freq),
+                wiphy_name(wiphy));
 
        memcpy(&reg_beacon->chan, beacon_chan,
               sizeof(struct ieee80211_channel));
@@ -2800,8 +2747,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
        case NL80211_DFS_JP:
                return true;
        default:
-               REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
-                             dfs_region);
+               pr_debug("Ignoring uknown DFS master region: %d\n", dfs_region);
                return false;
        }
 }
index 8020b5b094d4c8fba0c0f2431f8af7d8ecc40dca..5445581717874e1409d994f24c9ca7263e62ab38 100644 (file)
@@ -264,7 +264,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
                               wdev->conn->params.bssid,
                               wdev->conn->params.ssid,
                               wdev->conn->params.ssid_len,
-                              IEEE80211_BSS_TYPE_ESS,
+                              wdev->conn_bss_type,
                               IEEE80211_PRIVACY(wdev->conn->params.privacy));
        if (!bss)
                return NULL;
@@ -687,7 +687,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
                bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
                                       wdev->ssid, wdev->ssid_len,
-                                      IEEE80211_BSS_TYPE_ESS,
+                                      wdev->conn_bss_type,
                                       IEEE80211_PRIVACY_ANY);
                if (bss)
                        cfg80211_hold_bss(bss_from_pub(bss));
@@ -846,7 +846,7 @@ void cfg80211_roamed(struct net_device *dev,
 
        bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
                               wdev->ssid_len,
-                              IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
+                              wdev->conn_bss_type, IEEE80211_PRIVACY_ANY);
        if (WARN_ON(!bss))
                return;
 
@@ -917,6 +917,12 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 
        nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
+       /* stop critical protocol if supported */
+       if (rdev->ops->crit_proto_stop && rdev->crit_proto_nlportid) {
+               rdev->crit_proto_nlportid = 0;
+               rdev_crit_proto_stop(rdev, wdev);
+       }
+
        /*
         * Delete all the keys ... pairwise keys can't really
         * exist any more anyway, but default keys might.
@@ -1017,6 +1023,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
        memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
        wdev->ssid_len = connect->ssid_len;
 
+       wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
+                                             IEEE80211_BSS_TYPE_ESS;
+
        if (!rdev->ops->connect)
                err = cfg80211_sme_connect(wdev, connect, prev_bssid);
        else
index 92770427b211f559be4735584d74043ec6301802..9f440a9de63b486e5fd565533fa01975621abbbb 100644 (file)
@@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
 {
-       int ae = meshhdr->flags & MESH_FLAGS_AE;
+       int ae = flags & MESH_FLAGS_AE;
        /* 802.11-2012, 8.2.4.7.3 */
        switch (ae) {
        default:
@@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
                return 18;
        }
 }
+
+unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+{
+       return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
+}
 EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
 
-int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
-                          enum nl80211_iftype iftype)
+static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
+                                   const u8 *addr, enum nl80211_iftype iftype)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       u16 hdrlen, ethertype;
-       u8 *payload;
-       u8 dst[ETH_ALEN];
-       u8 src[ETH_ALEN] __aligned(2);
+       struct {
+               u8 hdr[ETH_ALEN] __aligned(2);
+               __be16 proto;
+       } payload;
+       struct ethhdr tmp;
+       u16 hdrlen;
+       u8 mesh_flags = 0;
 
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
                return -1;
 
        hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       if (skb->len < hdrlen + 8)
+               return -1;
 
        /* convert IEEE 802.11 header + possible LLC headers into Ethernet
         * header
@@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
         *   1     0   BSSID SA    DA    n/a
         *   1     1   RA    TA    DA    SA
         */
-       memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
-       memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
+       memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
+       memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
+
+       if (iftype == NL80211_IFTYPE_MESH_POINT)
+               skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
 
        switch (hdr->frame_control &
                cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
@@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                             iftype != NL80211_IFTYPE_STATION))
                        return -1;
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
-                       struct ieee80211s_hdr *meshdr =
-                               (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       /* make sure meshdr->flags is on the linear part */
-                       if (!pskb_may_pull(skb, hdrlen + 1))
-                               return -1;
-                       if (meshdr->flags & MESH_FLAGS_AE_A4)
+                       if (mesh_flags & MESH_FLAGS_AE_A4)
                                return -1;
-                       if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
+                       if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
                                skb_copy_bits(skb, hdrlen +
                                        offsetof(struct ieee80211s_hdr, eaddr1),
-                                       dst, ETH_ALEN);
-                               skb_copy_bits(skb, hdrlen +
-                                       offsetof(struct ieee80211s_hdr, eaddr2),
-                                       src, ETH_ALEN);
+                                       tmp.h_dest, 2 * ETH_ALEN);
                        }
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                       hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
                }
                break;
        case cpu_to_le16(IEEE80211_FCTL_FROMDS):
                if ((iftype != NL80211_IFTYPE_STATION &&
                     iftype != NL80211_IFTYPE_P2P_CLIENT &&
                     iftype != NL80211_IFTYPE_MESH_POINT) ||
-                   (is_multicast_ether_addr(dst) &&
-                    ether_addr_equal(src, addr)))
+                   (is_multicast_ether_addr(tmp.h_dest) &&
+                    ether_addr_equal(tmp.h_source, addr)))
                        return -1;
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
-                       struct ieee80211s_hdr *meshdr =
-                               (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       /* make sure meshdr->flags is on the linear part */
-                       if (!pskb_may_pull(skb, hdrlen + 1))
-                               return -1;
-                       if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
+                       if (mesh_flags & MESH_FLAGS_AE_A5_A6)
                                return -1;
-                       if (meshdr->flags & MESH_FLAGS_AE_A4)
+                       if (mesh_flags & MESH_FLAGS_AE_A4)
                                skb_copy_bits(skb, hdrlen +
                                        offsetof(struct ieee80211s_hdr, eaddr1),
-                                       src, ETH_ALEN);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                                       tmp.h_source, ETH_ALEN);
+                       hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
                }
                break;
        case cpu_to_le16(0):
@@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                break;
        }
 
-       if (!pskb_may_pull(skb, hdrlen + 8))
-               return -1;
-
-       payload = skb->data + hdrlen;
-       ethertype = (payload[6] << 8) | payload[7];
+       skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
+       tmp.h_proto = payload.proto;
 
-       if (likely((ether_addr_equal(payload, rfc1042_header) &&
-                   ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-                  ether_addr_equal(payload, bridge_tunnel_header))) {
+       if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
+                   tmp.h_proto != htons(ETH_P_AARP) &&
+                   tmp.h_proto != htons(ETH_P_IPX)) ||
+                  ether_addr_equal(payload.hdr, bridge_tunnel_header)))
                /* remove RFC1042 or Bridge-Tunnel encapsulation and
                 * replace EtherType */
-               skb_pull(skb, hdrlen + 6);
-               memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
-               memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
-       } else {
-               struct ethhdr *ehdr;
-               __be16 len;
+               hdrlen += ETH_ALEN + 2;
+       else
+               tmp.h_proto = htons(skb->len);
 
-               skb_pull(skb, hdrlen);
-               len = htons(skb->len);
+       pskb_pull(skb, hdrlen);
+
+       if (!ehdr)
                ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
-               memcpy(ehdr->h_dest, dst, ETH_ALEN);
-               memcpy(ehdr->h_source, src, ETH_ALEN);
-               ehdr->h_proto = len;
-       }
+       memcpy(ehdr, &tmp, sizeof(tmp));
+
        return 0;
 }
+
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
+                          enum nl80211_iftype iftype)
+{
+       return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
+}
 EXPORT_SYMBOL(ieee80211_data_to_8023);
 
 int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
@@ -636,7 +636,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
        /* Update skb pointers to various headers since this modified frame
         * is going to go through Linux networking code that may potentially
         * need things like pointer to IP header. */
-       skb_set_mac_header(skb, 0);
+       skb_reset_mac_header(skb);
        skb_set_network_header(skb, nh_pos);
        skb_set_transport_header(skb, h_pos);
 
@@ -644,70 +644,147 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_from_8023);
 
+static void
+__frame_add_frag(struct sk_buff *skb, struct page *page,
+                void *ptr, int len, int size)
+{
+       struct skb_shared_info *sh = skb_shinfo(skb);
+       int page_offset;
+
+       atomic_inc(&page->_count);
+       page_offset = ptr - page_address(page);
+       skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
+}
+
+static void
+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
+                           int offset, int len)
+{
+       struct skb_shared_info *sh = skb_shinfo(skb);
+       const skb_frag_t *frag = &sh->frags[-1];
+       struct page *frag_page;
+       void *frag_ptr;
+       int frag_len, frag_size;
+       int head_size = skb->len - skb->data_len;
+       int cur_len;
+
+       frag_page = virt_to_head_page(skb->head);
+       frag_ptr = skb->data;
+       frag_size = head_size;
+
+       while (offset >= frag_size) {
+               offset -= frag_size;
+               frag++;
+               frag_page = skb_frag_page(frag);
+               frag_ptr = skb_frag_address(frag);
+               frag_size = skb_frag_size(frag);
+       }
+
+       frag_ptr += offset;
+       frag_len = frag_size - offset;
+
+       cur_len = min(len, frag_len);
+
+       __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
+       len -= cur_len;
+
+       while (len > 0) {
+               frag++;
+               frag_len = skb_frag_size(frag);
+               cur_len = min(len, frag_len);
+               __frame_add_frag(frame, skb_frag_page(frag),
+                                skb_frag_address(frag), cur_len, frag_len);
+               len -= cur_len;
+       }
+}
+
+static struct sk_buff *
+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
+                      int offset, int len, bool reuse_frag)
+{
+       struct sk_buff *frame;
+       int cur_len = len;
+
+       if (skb->len - offset < len)
+               return NULL;
+
+       /*
+        * When reusing framents, copy some data to the head to simplify
+        * ethernet header handling and speed up protocol header processing
+        * in the stack later.
+        */
+       if (reuse_frag)
+               cur_len = min_t(int, len, 32);
+
+       /*
+        * Allocate and reserve two bytes more for payload
+        * alignment since sizeof(struct ethhdr) is 14.
+        */
+       frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
+
+       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
+       skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
+
+       len -= cur_len;
+       if (!len)
+               return frame;
+
+       offset += cur_len;
+       __ieee80211_amsdu_copy_frag(skb, frame, offset, len);
+
+       return frame;
+}
 
 void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
                              const u8 *addr, enum nl80211_iftype iftype,
                              const unsigned int extra_headroom,
                              bool has_80211_header)
 {
+       unsigned int hlen = ALIGN(extra_headroom, 4);
        struct sk_buff *frame = NULL;
        u16 ethertype;
        u8 *payload;
-       const struct ethhdr *eth;
-       int remaining, err;
-       u8 dst[ETH_ALEN], src[ETH_ALEN];
+       int offset = 0, remaining, err;
+       struct ethhdr eth;
+       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
+       bool reuse_skb = false;
+       bool last = false;
 
        if (has_80211_header) {
-               err = ieee80211_data_to_8023(skb, addr, iftype);
+               err = __ieee80211_data_to_8023(skb, &eth, addr, iftype);
                if (err)
                        goto out;
-
-               /* skip the wrapping header */
-               eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-               if (!eth)
-                       goto out;
-       } else {
-               eth = (struct ethhdr *) skb->data;
        }
 
-       while (skb != frame) {
+       while (!last) {
+               unsigned int subframe_len;
+               int len;
                u8 padding;
-               __be16 len = eth->h_proto;
-               unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
-
-               remaining = skb->len;
-               memcpy(dst, eth->h_dest, ETH_ALEN);
-               memcpy(src, eth->h_source, ETH_ALEN);
 
+               skb_copy_bits(skb, offset, &eth, sizeof(eth));
+               len = ntohs(eth.h_proto);
+               subframe_len = sizeof(struct ethhdr) + len;
                padding = (4 - subframe_len) & 0x3;
+
                /* the last MSDU has no padding */
+               remaining = skb->len - offset;
                if (subframe_len > remaining)
                        goto purge;
 
-               skb_pull(skb, sizeof(struct ethhdr));
+               offset += sizeof(struct ethhdr);
                /* reuse skb for the last subframe */
-               if (remaining <= subframe_len + padding)
+               last = remaining <= subframe_len + padding;
+               if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
+                       skb_pull(skb, offset);
                        frame = skb;
-               else {
-                       unsigned int hlen = ALIGN(extra_headroom, 4);
-                       /*
-                        * Allocate and reserve two bytes more for payload
-                        * alignment since sizeof(struct ethhdr) is 14.
-                        */
-                       frame = dev_alloc_skb(hlen + subframe_len + 2);
+                       reuse_skb = true;
+               } else {
+                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
+                                                      reuse_frag);
                        if (!frame)
                                goto purge;
 
-                       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-                       memcpy(skb_put(frame, ntohs(len)), skb->data,
-                               ntohs(len));
-
-                       eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
-                                                       padding);
-                       if (!eth) {
-                               dev_kfree_skb(frame);
-                               goto purge;
-                       }
+                       offset += len + padding;
                }
 
                skb_reset_network_header(frame);
@@ -716,24 +793,20 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 
                payload = frame->data;
                ethertype = (payload[6] << 8) | payload[7];
-
                if (likely((ether_addr_equal(payload, rfc1042_header) &&
                            ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
                           ether_addr_equal(payload, bridge_tunnel_header))) {
-                       /* remove RFC1042 or Bridge-Tunnel
-                        * encapsulation and replace EtherType */
-                       skb_pull(frame, 6);
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-               } else {
-                       memcpy(skb_push(frame, sizeof(__be16)), &len,
-                               sizeof(__be16));
-                       memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-                       memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+                       eth.h_proto = htons(ethertype);
+                       skb_pull(frame, ETH_ALEN + 2);
                }
+
+               memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
                __skb_queue_tail(list, frame);
        }
 
+       if (!reuse_skb)
+               dev_kfree_skb(skb);
+
        return;
 
  purge:
index c8717c1d082e702f9b071c480e873b408b400daf..b50ee5d622e14d4fb486ce0c533757e958702f54 100644 (file)
@@ -342,6 +342,40 @@ static const int compat_event_type_size[] = {
 
 /* IW event code */
 
+void wireless_nlevent_flush(void)
+{
+       struct sk_buff *skb;
+       struct net *net;
+
+       ASSERT_RTNL();
+
+       for_each_net(net) {
+               while ((skb = skb_dequeue(&net->wext_nlevents)))
+                       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
+                                   GFP_KERNEL);
+       }
+}
+EXPORT_SYMBOL_GPL(wireless_nlevent_flush);
+
+static int wext_netdev_notifier_call(struct notifier_block *nb,
+                                    unsigned long state, void *ptr)
+{
+       /*
+        * When a netdev changes state in any way, flush all pending messages
+        * to avoid them going out in a strange order, e.g. RTM_NEWLINK after
+        * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close()
+        * or similar - all of which could otherwise happen due to delays from
+        * schedule_work().
+        */
+       wireless_nlevent_flush();
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block wext_netdev_notifier = {
+       .notifier_call = wext_netdev_notifier_call,
+};
+
 static int __net_init wext_pernet_init(struct net *net)
 {
        skb_queue_head_init(&net->wext_nlevents);
@@ -360,7 +394,12 @@ static struct pernet_operations wext_pernet_ops = {
 
 static int __init wireless_nlevent_init(void)
 {
-       return register_pernet_subsys(&wext_pernet_ops);
+       int err = register_pernet_subsys(&wext_pernet_ops);
+
+       if (err)
+               return err;
+
+       return register_netdevice_notifier(&wext_netdev_notifier);
 }
 
 subsys_initcall(wireless_nlevent_init);
@@ -368,17 +407,8 @@ subsys_initcall(wireless_nlevent_init);
 /* Process events generated by the wireless layer or the driver. */
 static void wireless_nlevent_process(struct work_struct *work)
 {
-       struct sk_buff *skb;
-       struct net *net;
-
        rtnl_lock();
-
-       for_each_net(net) {
-               while ((skb = skb_dequeue(&net->wext_nlevents)))
-                       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
-                                   GFP_KERNEL);
-       }
-
+       wireless_nlevent_flush();
        rtnl_unlock();
 }
 
index edd638b5825f8a96e6f6e16fe47f58c4262ca6f1..502c9fc8db85d013e9e39ff7008765a0ba79ccfd 100644 (file)
@@ -16,6 +16,9 @@ hostprogs-y += tracex5
 hostprogs-y += tracex6
 hostprogs-y += trace_output
 hostprogs-y += lathist
+hostprogs-y += offwaketime
+hostprogs-y += spintest
+hostprogs-y += map_perf_test
 
 test_verifier-objs := test_verifier.o libbpf.o
 test_maps-objs := test_maps.o libbpf.o
@@ -32,6 +35,9 @@ tracex5-objs := bpf_load.o libbpf.o tracex5_user.o
 tracex6-objs := bpf_load.o libbpf.o tracex6_user.o
 trace_output-objs := bpf_load.o libbpf.o trace_output_user.o
 lathist-objs := bpf_load.o libbpf.o lathist_user.o
+offwaketime-objs := bpf_load.o libbpf.o offwaketime_user.o
+spintest-objs := bpf_load.o libbpf.o spintest_user.o
+map_perf_test-objs := bpf_load.o libbpf.o map_perf_test_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -47,6 +53,9 @@ always += tracex6_kern.o
 always += trace_output_kern.o
 always += tcbpf1_kern.o
 always += lathist_kern.o
+always += offwaketime_kern.o
+always += spintest_kern.o
+always += map_perf_test_kern.o
 
 HOSTCFLAGS += -I$(objtree)/usr/include
 
@@ -63,6 +72,9 @@ HOSTLOADLIBES_tracex5 += -lelf
 HOSTLOADLIBES_tracex6 += -lelf
 HOSTLOADLIBES_trace_output += -lelf -lrt
 HOSTLOADLIBES_lathist += -lelf
+HOSTLOADLIBES_offwaketime += -lelf
+HOSTLOADLIBES_spintest += -lelf
+HOSTLOADLIBES_map_perf_test += -lelf -lrt
 
 # point this to your LLVM backend with bpf support
 LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
index 7ad19e1dbaf45fc6f1951a896c2ebdb427ae6805..9363500131a777f98cd7016a35b9cf9858dbf9a6 100644 (file)
@@ -39,6 +39,8 @@ static int (*bpf_redirect)(int ifindex, int flags) =
        (void *) BPF_FUNC_redirect;
 static int (*bpf_perf_event_output)(void *ctx, void *map, int index, void *data, int size) =
        (void *) BPF_FUNC_perf_event_output;
+static int (*bpf_get_stackid)(void *ctx, void *map, int flags) =
+       (void *) BPF_FUNC_get_stackid;
 
 /* llvm builtin functions that eBPF C program may use to
  * emit BPF_LD_ABS and BPF_LD_IND instructions
@@ -59,6 +61,7 @@ struct bpf_map_def {
        unsigned int key_size;
        unsigned int value_size;
        unsigned int max_entries;
+       unsigned int map_flags;
 };
 
 static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
index da86a8e0a95afb0fcc79f96d310115803b5a9d55..58f86bd11b3d239022d75a6c2c3a607bbb2ff61a 100644 (file)
@@ -157,9 +157,13 @@ static int load_maps(struct bpf_map_def *maps, int len)
                map_fd[i] = bpf_create_map(maps[i].type,
                                           maps[i].key_size,
                                           maps[i].value_size,
-                                          maps[i].max_entries);
-               if (map_fd[i] < 0)
+                                          maps[i].max_entries,
+                                          maps[i].map_flags);
+               if (map_fd[i] < 0) {
+                       printf("failed to create a map: %d %s\n",
+                              errno, strerror(errno));
                        return 1;
+               }
 
                if (maps[i].type == BPF_MAP_TYPE_PROG_ARRAY)
                        prog_array_fd = map_fd[i];
@@ -343,3 +347,65 @@ void read_trace_pipe(void)
                }
        }
 }
+
+#define MAX_SYMS 300000
+static struct ksym syms[MAX_SYMS];
+static int sym_cnt;
+
+static int ksym_cmp(const void *p1, const void *p2)
+{
+       return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
+}
+
+int load_kallsyms(void)
+{
+       FILE *f = fopen("/proc/kallsyms", "r");
+       char func[256], buf[256];
+       char symbol;
+       void *addr;
+       int i = 0;
+
+       if (!f)
+               return -ENOENT;
+
+       while (!feof(f)) {
+               if (!fgets(buf, sizeof(buf), f))
+                       break;
+               if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
+                       break;
+               if (!addr)
+                       continue;
+               syms[i].addr = (long) addr;
+               syms[i].name = strdup(func);
+               i++;
+       }
+       sym_cnt = i;
+       qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
+       return 0;
+}
+
+struct ksym *ksym_search(long key)
+{
+       int start = 0, end = sym_cnt;
+       int result;
+
+       while (start < end) {
+               size_t mid = start + (end - start) / 2;
+
+               result = key - syms[mid].addr;
+               if (result < 0)
+                       end = mid;
+               else if (result > 0)
+                       start = mid + 1;
+               else
+                       return &syms[mid];
+       }
+
+       if (start >= 1 && syms[start - 1].addr < key &&
+           key < syms[start].addr)
+               /* valid ksym */
+               return &syms[start - 1];
+
+       /* out of range. return _stext */
+       return &syms[0];
+}
index cbd7c2b532b9a1a8e842c863f91b80d9bc79f42e..dfa57fe65c8e0f2eb67ae251705b631b1403fc55 100644 (file)
@@ -23,5 +23,11 @@ extern int event_fd[MAX_PROGS];
 int load_bpf_file(char *path);
 
 void read_trace_pipe(void);
+struct ksym {
+       long addr;
+       char *name;
+};
 
+int load_kallsyms(void);
+struct ksym *ksym_search(long key);
 #endif
index e2fd16c3d0f07ca4461a0ad239d0c2426d880b97..625e797be6ef897f929adebffe9dcbf71cd59e03 100644 (file)
@@ -44,7 +44,7 @@ static void usage(void)
 static int bpf_map_create(void)
 {
        return bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
-                             sizeof(uint32_t), 1024);
+                             sizeof(uint32_t), 1024, 0);
 }
 
 static int bpf_prog_create(const char *object)
index 65a8d48d2799e43a1cfbd57ba13e353b1fa3856a..9969e35550c3dd3c9702e7e99dab35b3df9fb7f6 100644 (file)
@@ -19,13 +19,14 @@ static __u64 ptr_to_u64(void *ptr)
 }
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
-                  int max_entries)
+                  int max_entries, int map_flags)
 {
        union bpf_attr attr = {
                .map_type = map_type,
                .key_size = key_size,
                .value_size = value_size,
-               .max_entries = max_entries
+               .max_entries = max_entries,
+               .map_flags = map_flags,
        };
 
        return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
index 014aacf916e4063c28227da658e38e7c011c8c46..364582b778882f782684ea1bbd675cb801ff290b 100644 (file)
@@ -5,7 +5,7 @@
 struct bpf_insn;
 
 int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
-                  int max_entries);
+                  int max_entries, int map_flags);
 int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
 int bpf_lookup_elem(int fd, void *key, void *value);
 int bpf_delete_elem(int fd, void *key);
diff --git a/samples/bpf/map_perf_test_kern.c b/samples/bpf/map_perf_test_kern.c
new file mode 100644 (file)
index 0000000..311538e
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <uapi/linux/bpf.h>
+#include "bpf_helpers.h"
+
+#define MAX_ENTRIES 1000
+
+struct bpf_map_def SEC("maps") hash_map = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(long),
+       .max_entries = MAX_ENTRIES,
+};
+
+struct bpf_map_def SEC("maps") percpu_hash_map = {
+       .type = BPF_MAP_TYPE_PERCPU_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(long),
+       .max_entries = MAX_ENTRIES,
+};
+
+struct bpf_map_def SEC("maps") hash_map_alloc = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(long),
+       .max_entries = MAX_ENTRIES,
+       .map_flags = BPF_F_NO_PREALLOC,
+};
+
+struct bpf_map_def SEC("maps") percpu_hash_map_alloc = {
+       .type = BPF_MAP_TYPE_PERCPU_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(long),
+       .max_entries = MAX_ENTRIES,
+       .map_flags = BPF_F_NO_PREALLOC,
+};
+
+SEC("kprobe/sys_getuid")
+int stress_hmap(struct pt_regs *ctx)
+{
+       u32 key = bpf_get_current_pid_tgid();
+       long init_val = 1;
+       long *value;
+
+       bpf_map_update_elem(&hash_map, &key, &init_val, BPF_ANY);
+       value = bpf_map_lookup_elem(&hash_map, &key);
+       if (value)
+               bpf_map_delete_elem(&hash_map, &key);
+       return 0;
+}
+
+SEC("kprobe/sys_geteuid")
+int stress_percpu_hmap(struct pt_regs *ctx)
+{
+       u32 key = bpf_get_current_pid_tgid();
+       long init_val = 1;
+       long *value;
+
+       bpf_map_update_elem(&percpu_hash_map, &key, &init_val, BPF_ANY);
+       value = bpf_map_lookup_elem(&percpu_hash_map, &key);
+       if (value)
+               bpf_map_delete_elem(&percpu_hash_map, &key);
+       return 0;
+}
+SEC("kprobe/sys_getgid")
+int stress_hmap_alloc(struct pt_regs *ctx)
+{
+       u32 key = bpf_get_current_pid_tgid();
+       long init_val = 1;
+       long *value;
+
+       bpf_map_update_elem(&hash_map_alloc, &key, &init_val, BPF_ANY);
+       value = bpf_map_lookup_elem(&hash_map_alloc, &key);
+       if (value)
+               bpf_map_delete_elem(&hash_map_alloc, &key);
+       return 0;
+}
+
+SEC("kprobe/sys_getegid")
+int stress_percpu_hmap_alloc(struct pt_regs *ctx)
+{
+       u32 key = bpf_get_current_pid_tgid();
+       long init_val = 1;
+       long *value;
+
+       bpf_map_update_elem(&percpu_hash_map_alloc, &key, &init_val, BPF_ANY);
+       value = bpf_map_lookup_elem(&percpu_hash_map_alloc, &key);
+       if (value)
+               bpf_map_delete_elem(&percpu_hash_map_alloc, &key);
+       return 0;
+}
+char _license[] SEC("license") = "GPL";
+u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/map_perf_test_user.c b/samples/bpf/map_perf_test_user.c
new file mode 100644 (file)
index 0000000..95af56e
--- /dev/null
@@ -0,0 +1,155 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#define _GNU_SOURCE
+#include <sched.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <asm/unistd.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <linux/bpf.h>
+#include <string.h>
+#include <time.h>
+#include "libbpf.h"
+#include "bpf_load.h"
+
+#define MAX_CNT 1000000
+
+static __u64 time_get_ns(void)
+{
+       struct timespec ts;
+
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+       return ts.tv_sec * 1000000000ull + ts.tv_nsec;
+}
+
+#define HASH_PREALLOC          (1 << 0)
+#define PERCPU_HASH_PREALLOC   (1 << 1)
+#define HASH_KMALLOC           (1 << 2)
+#define PERCPU_HASH_KMALLOC    (1 << 3)
+
+static int test_flags = ~0;
+
+static void test_hash_prealloc(int cpu)
+{
+       __u64 start_time;
+       int i;
+
+       start_time = time_get_ns();
+       for (i = 0; i < MAX_CNT; i++)
+               syscall(__NR_getuid);
+       printf("%d:hash_map_perf pre-alloc %lld events per sec\n",
+              cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
+}
+
+static void test_percpu_hash_prealloc(int cpu)
+{
+       __u64 start_time;
+       int i;
+
+       start_time = time_get_ns();
+       for (i = 0; i < MAX_CNT; i++)
+               syscall(__NR_geteuid);
+       printf("%d:percpu_hash_map_perf pre-alloc %lld events per sec\n",
+              cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
+}
+
+static void test_hash_kmalloc(int cpu)
+{
+       __u64 start_time;
+       int i;
+
+       start_time = time_get_ns();
+       for (i = 0; i < MAX_CNT; i++)
+               syscall(__NR_getgid);
+       printf("%d:hash_map_perf kmalloc %lld events per sec\n",
+              cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
+}
+
+static void test_percpu_hash_kmalloc(int cpu)
+{
+       __u64 start_time;
+       int i;
+
+       start_time = time_get_ns();
+       for (i = 0; i < MAX_CNT; i++)
+               syscall(__NR_getegid);
+       printf("%d:percpu_hash_map_perf kmalloc %lld events per sec\n",
+              cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time));
+}
+
+static void loop(int cpu)
+{
+       cpu_set_t cpuset;
+
+       CPU_ZERO(&cpuset);
+       CPU_SET(cpu, &cpuset);
+       sched_setaffinity(0, sizeof(cpuset), &cpuset);
+
+       if (test_flags & HASH_PREALLOC)
+               test_hash_prealloc(cpu);
+
+       if (test_flags & PERCPU_HASH_PREALLOC)
+               test_percpu_hash_prealloc(cpu);
+
+       if (test_flags & HASH_KMALLOC)
+               test_hash_kmalloc(cpu);
+
+       if (test_flags & PERCPU_HASH_KMALLOC)
+               test_percpu_hash_kmalloc(cpu);
+}
+
+static void run_perf_test(int tasks)
+{
+       pid_t pid[tasks];
+       int i;
+
+       for (i = 0; i < tasks; i++) {
+               pid[i] = fork();
+               if (pid[i] == 0) {
+                       loop(i);
+                       exit(0);
+               } else if (pid[i] == -1) {
+                       printf("couldn't spawn #%d process\n", i);
+                       exit(1);
+               }
+       }
+       for (i = 0; i < tasks; i++) {
+               int status;
+
+               assert(waitpid(pid[i], &status, 0) == pid[i]);
+               assert(status == 0);
+       }
+}
+
+int main(int argc, char **argv)
+{
+       struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
+       char filename[256];
+       int num_cpu = 8;
+
+       snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+       setrlimit(RLIMIT_MEMLOCK, &r);
+
+       if (argc > 1)
+               test_flags = atoi(argv[1]) ? : test_flags;
+
+       if (argc > 2)
+               num_cpu = atoi(argv[2]) ? : num_cpu;
+
+       if (load_bpf_file(filename)) {
+               printf("%s", bpf_log_buf);
+               return 1;
+       }
+
+       run_perf_test(num_cpu);
+
+       return 0;
+}
diff --git a/samples/bpf/offwaketime_kern.c b/samples/bpf/offwaketime_kern.c
new file mode 100644 (file)
index 0000000..c0aa5a9
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#include <uapi/linux/bpf.h>
+#include "bpf_helpers.h"
+#include <uapi/linux/ptrace.h>
+#include <uapi/linux/perf_event.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+
+#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
+
+#define MINBLOCK_US    1
+
+struct key_t {
+       char waker[TASK_COMM_LEN];
+       char target[TASK_COMM_LEN];
+       u32 wret;
+       u32 tret;
+};
+
+struct bpf_map_def SEC("maps") counts = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(struct key_t),
+       .value_size = sizeof(u64),
+       .max_entries = 10000,
+};
+
+struct bpf_map_def SEC("maps") start = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(u64),
+       .max_entries = 10000,
+};
+
+struct wokeby_t {
+       char name[TASK_COMM_LEN];
+       u32 ret;
+};
+
+struct bpf_map_def SEC("maps") wokeby = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(u32),
+       .value_size = sizeof(struct wokeby_t),
+       .max_entries = 10000,
+};
+
+struct bpf_map_def SEC("maps") stackmap = {
+       .type = BPF_MAP_TYPE_STACK_TRACE,
+       .key_size = sizeof(u32),
+       .value_size = PERF_MAX_STACK_DEPTH * sizeof(u64),
+       .max_entries = 10000,
+};
+
+#define STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP)
+
+SEC("kprobe/try_to_wake_up")
+int waker(struct pt_regs *ctx)
+{
+       struct task_struct *p = (void *) PT_REGS_PARM1(ctx);
+       struct wokeby_t woke = {};
+       u32 pid;
+
+       pid = _(p->pid);
+
+       bpf_get_current_comm(&woke.name, sizeof(woke.name));
+       woke.ret = bpf_get_stackid(ctx, &stackmap, STACKID_FLAGS);
+
+       bpf_map_update_elem(&wokeby, &pid, &woke, BPF_ANY);
+       return 0;
+}
+
+static inline int update_counts(struct pt_regs *ctx, u32 pid, u64 delta)
+{
+       struct key_t key = {};
+       struct wokeby_t *woke;
+       u64 zero = 0, *val;
+
+       bpf_get_current_comm(&key.target, sizeof(key.target));
+       key.tret = bpf_get_stackid(ctx, &stackmap, STACKID_FLAGS);
+
+       woke = bpf_map_lookup_elem(&wokeby, &pid);
+       if (woke) {
+               key.wret = woke->ret;
+               __builtin_memcpy(&key.waker, woke->name, TASK_COMM_LEN);
+               bpf_map_delete_elem(&wokeby, &pid);
+       }
+
+       val = bpf_map_lookup_elem(&counts, &key);
+       if (!val) {
+               bpf_map_update_elem(&counts, &key, &zero, BPF_NOEXIST);
+               val = bpf_map_lookup_elem(&counts, &key);
+               if (!val)
+                       return 0;
+       }
+       (*val) += delta;
+       return 0;
+}
+
+SEC("kprobe/finish_task_switch")
+int oncpu(struct pt_regs *ctx)
+{
+       struct task_struct *p = (void *) PT_REGS_PARM1(ctx);
+       u64 delta, ts, *tsp;
+       u32 pid;
+
+       /* record previous thread sleep time */
+       pid = _(p->pid);
+       ts = bpf_ktime_get_ns();
+       bpf_map_update_elem(&start, &pid, &ts, BPF_ANY);
+
+       /* calculate current thread's delta time */
+       pid = bpf_get_current_pid_tgid();
+       tsp = bpf_map_lookup_elem(&start, &pid);
+       if (!tsp)
+               /* missed start or filtered */
+               return 0;
+
+       delta = bpf_ktime_get_ns() - *tsp;
+       bpf_map_delete_elem(&start, &pid);
+       delta = delta / 1000;
+       if (delta < MINBLOCK_US)
+               return 0;
+
+       return update_counts(ctx, pid, delta);
+}
+char _license[] SEC("license") = "GPL";
+u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/offwaketime_user.c b/samples/bpf/offwaketime_user.c
new file mode 100644 (file)
index 0000000..6f002a9
--- /dev/null
@@ -0,0 +1,120 @@
+/* Copyright (c) 2016 Facebook
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <linux/bpf.h>
+#include <string.h>
+#include <linux/perf_event.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdbool.h>
+#include <sys/resource.h>
+#include "libbpf.h"
+#include "bpf_load.h"
+
+#define PRINT_RAW_ADDR 0
+
+static void print_ksym(__u64 addr)
+{
+       struct ksym *sym;
+
+       if (!addr)
+               return;
+       sym = ksym_search(addr);
+       if (PRINT_RAW_ADDR)
+               printf("%s/%llx;", sym->name, addr);
+       else
+               printf("%s;", sym->name);
+}
+
+#define TASK_COMM_LEN 16
+
+struct key_t {
+       char waker[TASK_COMM_LEN];
+       char target[TASK_COMM_LEN];
+       __u32 wret;
+       __u32 tret;
+};
+
+static void print_stack(struct key_t *key, __u64 count)
+{
+       __u64 ip[PERF_MAX_STACK_DEPTH] = {};
+       static bool warned;
+       int i;
+
+       printf("%s;", key->target);
+       if (bpf_lookup_elem(map_fd[3], &key->tret, ip) != 0) {
+               printf("---;");
+       } else {
+               for (i = PERF_MAX_STACK_DEPTH - 1; i >= 0; i--)
+                       print_ksym(ip[i]);
+       }
+       printf("-;");
+       if (bpf_lookup_elem(map_fd[3], &key->wret, ip) != 0) {
+               printf("---;");
+       } else {
+               for (i = 0; i < PERF_MAX_STACK_DEPTH; i++)
+                       print_ksym(ip[i]);
+       }
+       printf(";%s %lld\n", key->waker, count);
+
+       if ((key->tret == -EEXIST || key->wret == -EEXIST) && !warned) {
+               printf("stackmap collisions seen. Consider increasing size\n");
+               warned = true;
+       } else if (((int)(key->tret) < 0 || (int)(key->wret) < 0)) {
+               printf("err stackid %d %d\n", key->tret, key->wret);
+       }
+}
+
+static void print_stacks(int fd)
+{
+       struct key_t key = {}, next_key;
+       __u64 value;
+
+       while (bpf_get_next_key(fd, &key, &next_key) == 0) {
+               bpf_lookup_elem(fd, &next_key, &value);
+               print_stack(&next_key, value);
+               key = next_key;
+       }
+}
+
+static void int_exit(int sig)
+{
+       print_stacks(map_fd[0]);
+       exit(0);
+}
+
+int main(int argc, char **argv)
+{
+       struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
+       char filename[256];
+       int delay = 1;
+
+       snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+       setrlimit(RLIMIT_MEMLOCK, &r);
+
+       signal(SIGINT, int_exit);
+
+       if (load_kallsyms()) {
+               printf("failed to process /proc/kallsyms\n");
+               return 2;
+       }
+
+       if (load_bpf_file(filename)) {
+               printf("%s", bpf_log_buf);
+               return 1;
+       }
+
+       if (argc > 1)
+               delay = atoi(argv[1]);
+       sleep(delay);
+       print_stacks(map_fd[0]);
+
+       return 0;
+}
index a0ce251c53900e08617740633cc726b045c8fcc1..28b60baa9fa82b4fbb0db4526aeddec65459bf96 100644 (file)
@@ -34,7 +34,7 @@ static int test_sock(void)
        long long value = 0, tcp_cnt, udp_cnt, icmp_cnt;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
-                               256);
+                               256, 0);
        if (map_fd < 0) {
                printf("failed to create map '%s'\n", strerror(errno));
                goto cleanup;
diff --git a/samples/bpf/spintest_kern.c b/samples/bpf/spintest_kern.c
new file mode 100644 (file)
index 0000000..4b27619
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (c) 2016, Facebook
+ *
+ * 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.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <uapi/linux/bpf.h>
+#include <uapi/linux/perf_event.h>
+#include "bpf_helpers.h"
+
+struct bpf_map_def SEC("maps") my_map = {
+       .type = BPF_MAP_TYPE_HASH,
+       .key_size = sizeof(long),
+       .value_size = sizeof(long),
+       .max_entries = 1024,
+};
+struct bpf_map_def SEC("maps") my_map2 = {
+       .type = BPF_MAP_TYPE_PERCPU_HASH,
+       .key_size = sizeof(long),
+       .value_size = sizeof(long),
+       .max_entries = 1024,
+};
+
+struct bpf_map_def SEC("maps") stackmap = {
+       .type = BPF_MAP_TYPE_STACK_TRACE,
+       .key_size = sizeof(u32),
+       .value_size = PERF_MAX_STACK_DEPTH * sizeof(u64),
+       .max_entries = 10000,
+};
+
+#define PROG(foo) \
+int foo(struct pt_regs *ctx) \
+{ \
+       long v = ctx->ip, *val; \
+\
+       val = bpf_map_lookup_elem(&my_map, &v); \
+       bpf_map_update_elem(&my_map, &v, &v, BPF_ANY); \
+       bpf_map_update_elem(&my_map2, &v, &v, BPF_ANY); \
+       bpf_map_delete_elem(&my_map2, &v); \
+       bpf_get_stackid(ctx, &stackmap, BPF_F_REUSE_STACKID); \
+       return 0; \
+}
+
+/* add kprobes to all possible *spin* functions */
+SEC("kprobe/spin_unlock")PROG(p1)
+SEC("kprobe/spin_lock")PROG(p2)
+SEC("kprobe/mutex_spin_on_owner")PROG(p3)
+SEC("kprobe/rwsem_spin_on_owner")PROG(p4)
+SEC("kprobe/spin_unlock_irqrestore")PROG(p5)
+SEC("kprobe/_raw_spin_unlock_irqrestore")PROG(p6)
+SEC("kprobe/_raw_spin_unlock_bh")PROG(p7)
+SEC("kprobe/_raw_spin_unlock")PROG(p8)
+SEC("kprobe/_raw_spin_lock_irqsave")PROG(p9)
+SEC("kprobe/_raw_spin_trylock_bh")PROG(p10)
+SEC("kprobe/_raw_spin_lock_irq")PROG(p11)
+SEC("kprobe/_raw_spin_trylock")PROG(p12)
+SEC("kprobe/_raw_spin_lock")PROG(p13)
+SEC("kprobe/_raw_spin_lock_bh")PROG(p14)
+/* and to inner bpf helpers */
+SEC("kprobe/htab_map_update_elem")PROG(p15)
+SEC("kprobe/__htab_percpu_map_update_elem")PROG(p16)
+SEC("kprobe/htab_map_alloc")PROG(p17)
+
+char _license[] SEC("license") = "GPL";
+u32 _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/samples/bpf/spintest_user.c b/samples/bpf/spintest_user.c
new file mode 100644 (file)
index 0000000..311ede5
--- /dev/null
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/bpf.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/resource.h>
+#include "libbpf.h"
+#include "bpf_load.h"
+
+int main(int ac, char **argv)
+{
+       struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
+       long key, next_key, value;
+       char filename[256];
+       struct ksym *sym;
+       int i;
+
+       snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+       setrlimit(RLIMIT_MEMLOCK, &r);
+
+       if (load_kallsyms()) {
+               printf("failed to process /proc/kallsyms\n");
+               return 2;
+       }
+
+       if (load_bpf_file(filename)) {
+               printf("%s", bpf_log_buf);
+               return 1;
+       }
+
+       for (i = 0; i < 5; i++) {
+               key = 0;
+               printf("kprobing funcs:");
+               while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0) {
+                       bpf_lookup_elem(map_fd[0], &next_key, &value);
+                       assert(next_key == value);
+                       sym = ksym_search(value);
+                       printf(" %s", sym->name);
+                       key = next_key;
+               }
+               if (key)
+                       printf("\n");
+               key = 0;
+               while (bpf_get_next_key(map_fd[0], &key, &next_key) == 0)
+                       bpf_delete_elem(map_fd[0], &next_key);
+               sleep(1);
+       }
+
+       return 0;
+}
index ad466ed3309307c79a7d393359f74a6c558eef1b..47bf0858f9e47d1b85a908ab94518c46b11ffecd 100644 (file)
@@ -2,6 +2,7 @@
  * Testsuite for eBPF maps
  *
  * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
+ * Copyright (c) 2016 Facebook
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of version 2 of the GNU General Public
 #include <stdlib.h>
 #include "libbpf.h"
 
+static int map_flags;
+
 /* sanity tests for map API */
 static void test_hashmap_sanity(int i, void *data)
 {
        long long key, next_key, value;
        int map_fd;
 
-       map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 2);
+       map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
+                               2, map_flags);
        if (map_fd < 0) {
                printf("failed to create hashmap '%s'\n", strerror(errno));
                exit(1);
@@ -99,7 +103,7 @@ static void test_percpu_hashmap_sanity(int task, void *data)
        int map_fd, i;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
-                               sizeof(value[0]), 2);
+                               sizeof(value[0]), 2, map_flags);
        if (map_fd < 0) {
                printf("failed to create hashmap '%s'\n", strerror(errno));
                exit(1);
@@ -188,7 +192,8 @@ static void test_arraymap_sanity(int i, void *data)
        int key, next_key, map_fd;
        long long value;
 
-       map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 2);
+       map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
+                               2, 0);
        if (map_fd < 0) {
                printf("failed to create arraymap '%s'\n", strerror(errno));
                exit(1);
@@ -244,7 +249,7 @@ static void test_percpu_arraymap_many_keys(void)
        int key, map_fd, i;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
-                               sizeof(values[0]), nr_keys);
+                               sizeof(values[0]), nr_keys, 0);
        if (map_fd < 0) {
                printf("failed to create per-cpu arraymap '%s'\n",
                       strerror(errno));
@@ -275,7 +280,7 @@ static void test_percpu_arraymap_sanity(int i, void *data)
        int key, next_key, map_fd;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
-                               sizeof(values[0]), 2);
+                               sizeof(values[0]), 2, 0);
        if (map_fd < 0) {
                printf("failed to create arraymap '%s'\n", strerror(errno));
                exit(1);
@@ -336,7 +341,7 @@ static void test_map_large(void)
 
        /* allocate 4Mbyte of memory */
        map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
-                               MAP_SIZE);
+                               MAP_SIZE, map_flags);
        if (map_fd < 0) {
                printf("failed to create large map '%s'\n", strerror(errno));
                exit(1);
@@ -421,7 +426,7 @@ static void test_map_parallel(void)
        int data[2];
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
-                               MAP_SIZE);
+                               MAP_SIZE, map_flags);
        if (map_fd < 0) {
                printf("failed to create map for parallel test '%s'\n",
                       strerror(errno));
@@ -463,7 +468,7 @@ static void test_map_parallel(void)
        assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
 }
 
-int main(void)
+static void run_all_tests(void)
 {
        test_hashmap_sanity(0, NULL);
        test_percpu_hashmap_sanity(0, NULL);
@@ -474,6 +479,14 @@ int main(void)
        test_map_large();
        test_map_parallel();
        test_map_stress();
+}
+
+int main(void)
+{
+       map_flags = 0;
+       run_all_tests();
+       map_flags = BPF_F_NO_PREALLOC;
+       run_all_tests();
        printf("test_maps: OK\n");
        return 0;
 }
index 563c507c0a09f3868827ce6ce1e0e88669803016..4b51a9039c0d4abd9a4995b2df0d178e0422ff19 100644 (file)
@@ -1198,7 +1198,7 @@ static int create_map(void)
        int map_fd;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_HASH,
-                               sizeof(long long), sizeof(long long), 1024);
+                               sizeof(long long), sizeof(long long), 1024, 0);
        if (map_fd < 0)
                printf("failed to create map '%s'\n", strerror(errno));
 
@@ -1210,7 +1210,7 @@ static int create_prog_array(void)
        int map_fd;
 
        map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY,
-                               sizeof(int), sizeof(int), 4);
+                               sizeof(int), sizeof(int), 4, 0);
        if (map_fd < 0)
                printf("failed to create prog_array '%s'\n", strerror(errno));
 
diff --git a/scripts/prune-kernel b/scripts/prune-kernel
new file mode 100755 (executable)
index 0000000..ab5034e
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# because I use CONFIG_LOCALVERSION_AUTO, not the same version again and
+# again, /boot and /lib/modules/ eventually fill up.
+# Dumb script to purge that stuff:
+
+for f in "$@"
+do
+        if rpm -qf "/lib/modules/$f" >/dev/null; then
+                echo "keeping $f (installed from rpm)"
+        elif [ $(uname -r) = "$f" ]; then
+                echo "keeping $f (running kernel) "
+        else
+                echo "removing $f"
+                rm -f "/boot/initramfs-$f.img" "/boot/System.map-$f"
+                rm -f "/boot/vmlinuz-$f"   "/boot/config-$f"
+                rm -rf "/lib/modules/$f"
+                new-kernel-pkg --remove $f
+        fi
+done
index f7160253f17faad71c17a86b19833123a2edebd4..e6ea9d4b1de91a8d58e3ccab0fd3cef222ea6fcd 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/integrity.h>
 #include <linux/evm.h>
 #include <crypto/hash.h>
+#include <crypto/algapi.h>
 #include "evm.h"
 
 int evm_initialized;
@@ -148,7 +149,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
                                   xattr_value_len, calc.digest);
                if (rc)
                        break;
-               rc = memcmp(xattr_data->digest, calc.digest,
+               rc = crypto_memneq(xattr_data->digest, calc.digest,
                            sizeof(calc.digest));
                if (rc)
                        rc = -EINVAL;
index f8110cfd80ff64bf05ef428f03dff935e6d704c4..f1ab71504e1d59e1c6aaa7c0d22870e371ec85b3 100644 (file)
@@ -3249,7 +3249,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
 
 static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
 {
-       struct inode_security_struct *isec = inode_security(inode);
+       struct inode_security_struct *isec = inode_security_novalidate(inode);
        *secid = isec->sid;
 }
 
index 2bbb41822d8ec8882f8dacbbb4c5f8a1feac59ca..8495b93681906bd39f4065723461cddac2e7d347 100644 (file)
@@ -83,6 +83,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
        { TCPDIAG_GETSOCK,      NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
        { DCCPDIAG_GETSOCK,     NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
        { SOCK_DIAG_BY_FAMILY,  NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+       { SOCK_DESTROY,         NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
 };
 
 static struct nlmsg_perm nlmsg_xfrm_perms[] =
index b9c0910fb8c4ead97559c7f9c1737e76b2d5cf7f..0608f216f3592fc597c85c2c92594b891e499647 100644 (file)
@@ -170,6 +170,19 @@ struct snd_ctl_elem_value32 {
         unsigned char reserved[128];
 };
 
+#ifdef CONFIG_X86_X32
+/* x32 has a different alignment for 64bit values from ia32 */
+struct snd_ctl_elem_value_x32 {
+       struct snd_ctl_elem_id id;
+       unsigned int indirect;  /* bit-field causes misalignment */
+       union {
+               s32 integer[128];
+               unsigned char data[512];
+               s64 integer64[64];
+       } value;
+       unsigned char reserved[128];
+};
+#endif /* CONFIG_X86_X32 */
 
 /* get the value type and count of the control */
 static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
@@ -219,9 +232,11 @@ static int get_elem_size(int type, int count)
 
 static int copy_ctl_value_from_user(struct snd_card *card,
                                    struct snd_ctl_elem_value *data,
-                                   struct snd_ctl_elem_value32 __user *data32,
+                                   void __user *userdata,
+                                   void __user *valuep,
                                    int *typep, int *countp)
 {
+       struct snd_ctl_elem_value32 __user *data32 = userdata;
        int i, type, size;
        int uninitialized_var(count);
        unsigned int indirect;
@@ -239,8 +254,9 @@ static int copy_ctl_value_from_user(struct snd_card *card,
        if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
            type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
                for (i = 0; i < count; i++) {
+                       s32 __user *intp = valuep;
                        int val;
-                       if (get_user(val, &data32->value.integer[i]))
+                       if (get_user(val, &intp[i]))
                                return -EFAULT;
                        data->value.integer.value[i] = val;
                }
@@ -250,8 +266,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
                        dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
                        return -EINVAL;
                }
-               if (copy_from_user(data->value.bytes.data,
-                                  data32->value.data, size))
+               if (copy_from_user(data->value.bytes.data, valuep, size))
                        return -EFAULT;
        }
 
@@ -261,7 +276,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
 }
 
 /* restore the value to 32bit */
-static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32,
+static int copy_ctl_value_to_user(void __user *userdata,
+                                 void __user *valuep,
                                  struct snd_ctl_elem_value *data,
                                  int type, int count)
 {
@@ -270,22 +286,22 @@ static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32,
        if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
            type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
                for (i = 0; i < count; i++) {
+                       s32 __user *intp = valuep;
                        int val;
                        val = data->value.integer.value[i];
-                       if (put_user(val, &data32->value.integer[i]))
+                       if (put_user(val, &intp[i]))
                                return -EFAULT;
                }
        } else {
                size = get_elem_size(type, count);
-               if (copy_to_user(data32->value.data,
-                                data->value.bytes.data, size))
+               if (copy_to_user(valuep, data->value.bytes.data, size))
                        return -EFAULT;
        }
        return 0;
 }
 
-static int snd_ctl_elem_read_user_compat(struct snd_card *card, 
-                                        struct snd_ctl_elem_value32 __user *data32)
+static int ctl_elem_read_user(struct snd_card *card,
+                             void __user *userdata, void __user *valuep)
 {
        struct snd_ctl_elem_value *data;
        int err, type, count;
@@ -294,7 +310,9 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card,
        if (data == NULL)
                return -ENOMEM;
 
-       if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
+       err = copy_ctl_value_from_user(card, data, userdata, valuep,
+                                      &type, &count);
+       if (err < 0)
                goto error;
 
        snd_power_lock(card);
@@ -303,14 +321,15 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card,
                err = snd_ctl_elem_read(card, data);
        snd_power_unlock(card);
        if (err >= 0)
-               err = copy_ctl_value_to_user(data32, data, type, count);
+               err = copy_ctl_value_to_user(userdata, valuep, data,
+                                            type, count);
  error:
        kfree(data);
        return err;
 }
 
-static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
-                                         struct snd_ctl_elem_value32 __user *data32)
+static int ctl_elem_write_user(struct snd_ctl_file *file,
+                              void __user *userdata, void __user *valuep)
 {
        struct snd_ctl_elem_value *data;
        struct snd_card *card = file->card;
@@ -320,7 +339,9 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
        if (data == NULL)
                return -ENOMEM;
 
-       if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
+       err = copy_ctl_value_from_user(card, data, userdata, valuep,
+                                      &type, &count);
+       if (err < 0)
                goto error;
 
        snd_power_lock(card);
@@ -329,12 +350,39 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
                err = snd_ctl_elem_write(card, file, data);
        snd_power_unlock(card);
        if (err >= 0)
-               err = copy_ctl_value_to_user(data32, data, type, count);
+               err = copy_ctl_value_to_user(userdata, valuep, data,
+                                            type, count);
  error:
        kfree(data);
        return err;
 }
 
+static int snd_ctl_elem_read_user_compat(struct snd_card *card,
+                                        struct snd_ctl_elem_value32 __user *data32)
+{
+       return ctl_elem_read_user(card, data32, &data32->value);
+}
+
+static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
+                                         struct snd_ctl_elem_value32 __user *data32)
+{
+       return ctl_elem_write_user(file, data32, &data32->value);
+}
+
+#ifdef CONFIG_X86_X32
+static int snd_ctl_elem_read_user_x32(struct snd_card *card,
+                                     struct snd_ctl_elem_value_x32 __user *data32)
+{
+       return ctl_elem_read_user(card, data32, &data32->value);
+}
+
+static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file,
+                                      struct snd_ctl_elem_value_x32 __user *data32)
+{
+       return ctl_elem_write_user(file, data32, &data32->value);
+}
+#endif /* CONFIG_X86_X32 */
+
 /* add or replace a user control */
 static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
                                   struct snd_ctl_elem_info32 __user *data32,
@@ -393,6 +441,10 @@ enum {
        SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
        SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
        SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
+#ifdef CONFIG_X86_X32
+       SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32),
+       SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32),
+#endif /* CONFIG_X86_X32 */
 };
 
 static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@@ -431,6 +483,12 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
                return snd_ctl_elem_add_compat(ctl, argp, 0);
        case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
                return snd_ctl_elem_add_compat(ctl, argp, 1);
+#ifdef CONFIG_X86_X32
+       case SNDRV_CTL_IOCTL_ELEM_READ_X32:
+               return snd_ctl_elem_read_user_x32(ctl->card, argp);
+       case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
+               return snd_ctl_elem_write_user_x32(ctl, argp);
+#endif /* CONFIG_X86_X32 */
        }
 
        down_read(&snd_ioctl_rwsem);
index 0e73d03b30e3f0d712b26f65453346e419caa96d..ebc9fdfe64df618088a8d55efff8b5312af3385d 100644 (file)
@@ -835,7 +835,8 @@ static int choose_rate(struct snd_pcm_substream *substream,
        return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
 }
 
-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
+static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
+                                    bool trylock)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_pcm_hw_params *params, *sparams;
@@ -849,7 +850,10 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
        struct snd_mask sformat_mask;
        struct snd_mask mask;
 
-       if (mutex_lock_interruptible(&runtime->oss.params_lock))
+       if (trylock) {
+               if (!(mutex_trylock(&runtime->oss.params_lock)))
+                       return -EAGAIN;
+       } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
                return -EINTR;
        sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
        params = kmalloc(sizeof(*params), GFP_KERNEL);
@@ -1092,7 +1096,7 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil
                if (asubstream == NULL)
                        asubstream = substream;
                if (substream->runtime->oss.params) {
-                       err = snd_pcm_oss_change_params(substream);
+                       err = snd_pcm_oss_change_params(substream, false);
                        if (err < 0)
                                return err;
                }
@@ -1132,7 +1136,7 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream)
                return 0;
        runtime = substream->runtime;
        if (runtime->oss.params) {
-               err = snd_pcm_oss_change_params(substream);
+               err = snd_pcm_oss_change_params(substream, false);
                if (err < 0)
                        return err;
        }
@@ -2163,7 +2167,7 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
        runtime = substream->runtime;
 
        if (runtime->oss.params &&
-           (err = snd_pcm_oss_change_params(substream)) < 0)
+           (err = snd_pcm_oss_change_params(substream, false)) < 0)
                return err;
 
        info.fragsize = runtime->oss.period_bytes;
@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
                return -EIO;
        
        if (runtime->oss.params) {
-               if ((err = snd_pcm_oss_change_params(substream)) < 0)
+               /* use mutex_trylock() for params_lock for avoiding a deadlock
+                * between mmap_sem and params_lock taken by
+                * copy_from/to_user() in snd_pcm_oss_write/read()
+                */
+               err = snd_pcm_oss_change_params(substream, true);
+               if (err < 0)
                        return err;
        }
 #ifdef CONFIG_SND_PCM_OSS_PLUGINS
index 9630e9f72b7ba2ad77f50a516ecc559c0c200975..1f64ab0c2a95a291638406e62daa15ad6a172db3 100644 (file)
@@ -183,6 +183,14 @@ static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream
        return err;
 }
 
+#ifdef CONFIG_X86_X32
+/* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */
+static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
+                                    struct snd_pcm_channel_info __user *src);
+#define snd_pcm_ioctl_channel_info_x32(s, p)   \
+       snd_pcm_channel_info_user(s, p)
+#endif /* CONFIG_X86_X32 */
+
 struct snd_pcm_status32 {
        s32 state;
        struct compat_timespec trigger_tstamp;
@@ -243,6 +251,71 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
        return err;
 }
 
+#ifdef CONFIG_X86_X32
+/* X32 ABI has 64bit timespec and 64bit alignment */
+struct snd_pcm_status_x32 {
+       s32 state;
+       u32 rsvd; /* alignment */
+       struct timespec trigger_tstamp;
+       struct timespec tstamp;
+       u32 appl_ptr;
+       u32 hw_ptr;
+       s32 delay;
+       u32 avail;
+       u32 avail_max;
+       u32 overrange;
+       s32 suspended_state;
+       u32 audio_tstamp_data;
+       struct timespec audio_tstamp;
+       struct timespec driver_tstamp;
+       u32 audio_tstamp_accuracy;
+       unsigned char reserved[52-2*sizeof(struct timespec)];
+} __packed;
+
+#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
+
+static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
+                                  struct snd_pcm_status_x32 __user *src,
+                                  bool ext)
+{
+       struct snd_pcm_status status;
+       int err;
+
+       memset(&status, 0, sizeof(status));
+       /*
+        * with extension, parameters are read/write,
+        * get audio_tstamp_data from user,
+        * ignore rest of status structure
+        */
+       if (ext && get_user(status.audio_tstamp_data,
+                               (u32 __user *)(&src->audio_tstamp_data)))
+               return -EFAULT;
+       err = snd_pcm_status(substream, &status);
+       if (err < 0)
+               return err;
+
+       if (clear_user(src, sizeof(*src)))
+               return -EFAULT;
+       if (put_user(status.state, &src->state) ||
+           put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
+           put_timespec(&status.tstamp, &src->tstamp) ||
+           put_user(status.appl_ptr, &src->appl_ptr) ||
+           put_user(status.hw_ptr, &src->hw_ptr) ||
+           put_user(status.delay, &src->delay) ||
+           put_user(status.avail, &src->avail) ||
+           put_user(status.avail_max, &src->avail_max) ||
+           put_user(status.overrange, &src->overrange) ||
+           put_user(status.suspended_state, &src->suspended_state) ||
+           put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
+           put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
+           put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
+           put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
+               return -EFAULT;
+
+       return err;
+}
+#endif /* CONFIG_X86_X32 */
+
 /* both for HW_PARAMS and HW_REFINE */
 static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
                                          int refine, 
@@ -469,6 +542,93 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
        return 0;
 }
 
+#ifdef CONFIG_X86_X32
+/* X32 ABI has 64bit timespec and 64bit alignment */
+struct snd_pcm_mmap_status_x32 {
+       s32 state;
+       s32 pad1;
+       u32 hw_ptr;
+       u32 pad2; /* alignment */
+       struct timespec tstamp;
+       s32 suspended_state;
+       struct timespec audio_tstamp;
+} __packed;
+
+struct snd_pcm_mmap_control_x32 {
+       u32 appl_ptr;
+       u32 avail_min;
+};
+
+struct snd_pcm_sync_ptr_x32 {
+       u32 flags;
+       u32 rsvd; /* alignment */
+       union {
+               struct snd_pcm_mmap_status_x32 status;
+               unsigned char reserved[64];
+       } s;
+       union {
+               struct snd_pcm_mmap_control_x32 control;
+               unsigned char reserved[64];
+       } c;
+} __packed;
+
+static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
+                                     struct snd_pcm_sync_ptr_x32 __user *src)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       volatile struct snd_pcm_mmap_status *status;
+       volatile struct snd_pcm_mmap_control *control;
+       u32 sflags;
+       struct snd_pcm_mmap_control scontrol;
+       struct snd_pcm_mmap_status sstatus;
+       snd_pcm_uframes_t boundary;
+       int err;
+
+       if (snd_BUG_ON(!runtime))
+               return -EINVAL;
+
+       if (get_user(sflags, &src->flags) ||
+           get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+           get_user(scontrol.avail_min, &src->c.control.avail_min))
+               return -EFAULT;
+       if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
+               err = snd_pcm_hwsync(substream);
+               if (err < 0)
+                       return err;
+       }
+       status = runtime->status;
+       control = runtime->control;
+       boundary = recalculate_boundary(runtime);
+       if (!boundary)
+               boundary = 0x7fffffff;
+       snd_pcm_stream_lock_irq(substream);
+       /* FIXME: we should consider the boundary for the sync from app */
+       if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
+               control->appl_ptr = scontrol.appl_ptr;
+       else
+               scontrol.appl_ptr = control->appl_ptr % boundary;
+       if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
+               control->avail_min = scontrol.avail_min;
+       else
+               scontrol.avail_min = control->avail_min;
+       sstatus.state = status->state;
+       sstatus.hw_ptr = status->hw_ptr % boundary;
+       sstatus.tstamp = status->tstamp;
+       sstatus.suspended_state = status->suspended_state;
+       sstatus.audio_tstamp = status->audio_tstamp;
+       snd_pcm_stream_unlock_irq(substream);
+       if (put_user(sstatus.state, &src->s.status.state) ||
+           put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
+           put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
+           put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
+           put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) ||
+           put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
+           put_user(scontrol.avail_min, &src->c.control.avail_min))
+               return -EFAULT;
+
+       return 0;
+}
+#endif /* CONFIG_X86_X32 */
 
 /*
  */
@@ -487,7 +647,12 @@ enum {
        SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
        SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
        SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
-
+#ifdef CONFIG_X86_X32
+       SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
+       SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
+       SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
+       SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
+#endif /* CONFIG_X86_X32 */
 };
 
 static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@@ -559,6 +724,16 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
                return snd_pcm_ioctl_rewind_compat(substream, argp);
        case SNDRV_PCM_IOCTL_FORWARD32:
                return snd_pcm_ioctl_forward_compat(substream, argp);
+#ifdef CONFIG_X86_X32
+       case SNDRV_PCM_IOCTL_STATUS_X32:
+               return snd_pcm_status_user_x32(substream, argp, false);
+       case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
+               return snd_pcm_status_user_x32(substream, argp, true);
+       case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
+               return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
+       case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
+               return snd_pcm_ioctl_channel_info_x32(substream, argp);
+#endif /* CONFIG_X86_X32 */
        }
 
        return -ENOIOCTLCMD;
index fadd3eb8e8bb2d77264fafec9be05ba54e36af85..9106d8e2300eab3e566f9a3807c469ee02aa7bcd 100644 (file)
@@ -74,6 +74,18 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
 static DEFINE_RWLOCK(snd_pcm_link_rwlock);
 static DECLARE_RWSEM(snd_pcm_link_rwsem);
 
+/* Writer in rwsem may block readers even during its waiting in queue,
+ * and this may lead to a deadlock when the code path takes read sem
+ * twice (e.g. one in snd_pcm_action_nonatomic() and another in
+ * snd_pcm_stream_lock()).  As a (suboptimal) workaround, let writer to
+ * spin until it gets the lock.
+ */
+static inline void down_write_nonblock(struct rw_semaphore *lock)
+{
+       while (!down_write_trylock(lock))
+               cond_resched();
+}
+
 /**
  * snd_pcm_stream_lock - Lock the PCM stream
  * @substream: PCM substream
@@ -1813,7 +1825,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
                res = -ENOMEM;
                goto _nolock;
        }
-       down_write(&snd_pcm_link_rwsem);
+       down_write_nonblock(&snd_pcm_link_rwsem);
        write_lock_irq(&snd_pcm_link_rwlock);
        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
            substream->runtime->status->state != substream1->runtime->status->state ||
@@ -1860,7 +1872,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
        struct snd_pcm_substream *s;
        int res = 0;
 
-       down_write(&snd_pcm_link_rwsem);
+       down_write_nonblock(&snd_pcm_link_rwsem);
        write_lock_irq(&snd_pcm_link_rwlock);
        if (!snd_pcm_stream_linked(substream)) {
                res = -EALREADY;
index a7759846fbaadff0c9493760ce7b14eff7ca8ad9..795437b1008200cd534f9a46ad0272f3dbc20ca4 100644 (file)
@@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(struct snd_rawmidi_substream *substream,
        unsigned long flags;
        long result = 0, count1;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
+       unsigned long appl_ptr;
 
+       spin_lock_irqsave(&runtime->lock, flags);
        while (count > 0 && runtime->avail) {
                count1 = runtime->buffer_size - runtime->appl_ptr;
                if (count1 > count)
                        count1 = count;
-               spin_lock_irqsave(&runtime->lock, flags);
                if (count1 > (int)runtime->avail)
                        count1 = runtime->avail;
+
+               /* update runtime->appl_ptr before unlocking for userbuf */
+               appl_ptr = runtime->appl_ptr;
+               runtime->appl_ptr += count1;
+               runtime->appl_ptr %= runtime->buffer_size;
+               runtime->avail -= count1;
+
                if (kernelbuf)
-                       memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1);
+                       memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1);
                if (userbuf) {
                        spin_unlock_irqrestore(&runtime->lock, flags);
                        if (copy_to_user(userbuf + result,
-                                        runtime->buffer + runtime->appl_ptr, count1)) {
+                                        runtime->buffer + appl_ptr, count1)) {
                                return result > 0 ? result : -EFAULT;
                        }
                        spin_lock_irqsave(&runtime->lock, flags);
                }
-               runtime->appl_ptr += count1;
-               runtime->appl_ptr %= runtime->buffer_size;
-               runtime->avail -= count1;
-               spin_unlock_irqrestore(&runtime->lock, flags);
                result += count1;
                count -= count1;
        }
+       spin_unlock_irqrestore(&runtime->lock, flags);
        return result;
 }
 
@@ -1055,23 +1060,16 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
 EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
 
 /**
- * snd_rawmidi_transmit_peek - copy data from the internal buffer
+ * __snd_rawmidi_transmit_peek - copy data from the internal buffer
  * @substream: the rawmidi substream
  * @buffer: the buffer pointer
  * @count: data size to transfer
  *
- * Copies data from the internal output buffer to the given buffer.
- *
- * Call this in the interrupt handler when the midi output is ready,
- * and call snd_rawmidi_transmit_ack() after the transmission is
- * finished.
- *
- * Return: The size of copied data, or a negative error code on failure.
+ * This is a variant of snd_rawmidi_transmit_peek() without spinlock.
  */
-int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                              unsigned char *buffer, int count)
 {
-       unsigned long flags;
        int result, count1;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
@@ -1081,7 +1079,6 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                return -EINVAL;
        }
        result = 0;
-       spin_lock_irqsave(&runtime->lock, flags);
        if (runtime->avail >= runtime->buffer_size) {
                /* warning: lowlevel layer MUST trigger down the hardware */
                goto __skip;
@@ -1106,25 +1103,47 @@ int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
                }
        }
       __skip:
+       return result;
+}
+EXPORT_SYMBOL(__snd_rawmidi_transmit_peek);
+
+/**
+ * snd_rawmidi_transmit_peek - copy data from the internal buffer
+ * @substream: the rawmidi substream
+ * @buffer: the buffer pointer
+ * @count: data size to transfer
+ *
+ * Copies data from the internal output buffer to the given buffer.
+ *
+ * Call this in the interrupt handler when the midi output is ready,
+ * and call snd_rawmidi_transmit_ack() after the transmission is
+ * finished.
+ *
+ * Return: The size of copied data, or a negative error code on failure.
+ */
+int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
+                             unsigned char *buffer, int count)
+{
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       int result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&runtime->lock, flags);
+       result = __snd_rawmidi_transmit_peek(substream, buffer, count);
        spin_unlock_irqrestore(&runtime->lock, flags);
        return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
 
 /**
- * snd_rawmidi_transmit_ack - acknowledge the transmission
+ * __snd_rawmidi_transmit_ack - acknowledge the transmission
  * @substream: the rawmidi substream
  * @count: the transferred count
  *
- * Advances the hardware pointer for the internal output buffer with
- * the given size and updates the condition.
- * Call after the transmission is finished.
- *
- * Return: The advanced size if successful, or a negative error code on failure.
+ * This is a variant of __snd_rawmidi_transmit_ack() without spinlock.
  */
-int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
+int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
 {
-       unsigned long flags;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
 
        if (runtime->buffer == NULL) {
@@ -1132,7 +1151,6 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
                          "snd_rawmidi_transmit_ack: output is not active!!!\n");
                return -EINVAL;
        }
-       spin_lock_irqsave(&runtime->lock, flags);
        snd_BUG_ON(runtime->avail + count > runtime->buffer_size);
        runtime->hw_ptr += count;
        runtime->hw_ptr %= runtime->buffer_size;
@@ -1142,9 +1160,32 @@ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
                if (runtime->drain || snd_rawmidi_ready(substream))
                        wake_up(&runtime->sleep);
        }
-       spin_unlock_irqrestore(&runtime->lock, flags);
        return count;
 }
+EXPORT_SYMBOL(__snd_rawmidi_transmit_ack);
+
+/**
+ * snd_rawmidi_transmit_ack - acknowledge the transmission
+ * @substream: the rawmidi substream
+ * @count: the transferred count
+ *
+ * Advances the hardware pointer for the internal output buffer with
+ * the given size and updates the condition.
+ * Call after the transmission is finished.
+ *
+ * Return: The advanced size if successful, or a negative error code on failure.
+ */
+int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count)
+{
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       int result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&runtime->lock, flags);
+       result = __snd_rawmidi_transmit_ack(substream, count);
+       spin_unlock_irqrestore(&runtime->lock, flags);
+       return result;
+}
 EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 
 /**
@@ -1160,12 +1201,22 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
 int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
                         unsigned char *buffer, int count)
 {
+       struct snd_rawmidi_runtime *runtime = substream->runtime;
+       int result;
+       unsigned long flags;
+
+       spin_lock_irqsave(&runtime->lock, flags);
        if (!substream->opened)
-               return -EBADFD;
-       count = snd_rawmidi_transmit_peek(substream, buffer, count);
-       if (count < 0)
-               return count;
-       return snd_rawmidi_transmit_ack(substream, count);
+               result = -EBADFD;
+       else {
+               count = __snd_rawmidi_transmit_peek(substream, buffer, count);
+               if (count <= 0)
+                       result = count;
+               else
+                       result = __snd_rawmidi_transmit_ack(substream, count);
+       }
+       spin_unlock_irqrestore(&runtime->lock, flags);
+       return result;
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit);
 
@@ -1177,8 +1228,9 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
        unsigned long flags;
        long count1, result;
        struct snd_rawmidi_runtime *runtime = substream->runtime;
+       unsigned long appl_ptr;
 
-       if (snd_BUG_ON(!kernelbuf && !userbuf))
+       if (!kernelbuf && !userbuf)
                return -EINVAL;
        if (snd_BUG_ON(!runtime->buffer))
                return -EINVAL;
@@ -1197,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                        count1 = count;
                if (count1 > (long)runtime->avail)
                        count1 = runtime->avail;
+
+               /* update runtime->appl_ptr before unlocking for userbuf */
+               appl_ptr = runtime->appl_ptr;
+               runtime->appl_ptr += count1;
+               runtime->appl_ptr %= runtime->buffer_size;
+               runtime->avail -= count1;
+
                if (kernelbuf)
-                       memcpy(runtime->buffer + runtime->appl_ptr,
+                       memcpy(runtime->buffer + appl_ptr,
                               kernelbuf + result, count1);
                else if (userbuf) {
                        spin_unlock_irqrestore(&runtime->lock, flags);
-                       if (copy_from_user(runtime->buffer + runtime->appl_ptr,
+                       if (copy_from_user(runtime->buffer + appl_ptr,
                                           userbuf + result, count1)) {
                                spin_lock_irqsave(&runtime->lock, flags);
                                result = result > 0 ? result : -EFAULT;
@@ -1210,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
                        }
                        spin_lock_irqsave(&runtime->lock, flags);
                }
-               runtime->appl_ptr += count1;
-               runtime->appl_ptr %= runtime->buffer_size;
-               runtime->avail -= count1;
                result += count1;
                count -= count1;
        }
index 5268c1f58c25b7e143b5713a45dac36220558cc5..f69764d7cdd7025d3935143883c162372e3c0c7c 100644 (file)
@@ -85,8 +85,7 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
        if (err < 0)
                return err;
 
-       if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
-           put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
+       if (compat_put_timespec(&status.tstamp, &src->tstamp) ||
            put_user(status.avail, &src->avail) ||
            put_user(status.xruns, &src->xruns))
                return -EFAULT;
@@ -94,9 +93,58 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
        return 0;
 }
 
+#ifdef CONFIG_X86_X32
+/* X32 ABI has 64bit timespec and 64bit alignment */
+struct snd_rawmidi_status_x32 {
+       s32 stream;
+       u32 rsvd; /* alignment */
+       struct timespec tstamp;
+       u32 avail;
+       u32 xruns;
+       unsigned char reserved[16];
+} __attribute__((packed));
+
+#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
+
+static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
+                                       struct snd_rawmidi_status_x32 __user *src)
+{
+       int err;
+       struct snd_rawmidi_status status;
+
+       if (rfile->output == NULL)
+               return -EINVAL;
+       if (get_user(status.stream, &src->stream))
+               return -EFAULT;
+
+       switch (status.stream) {
+       case SNDRV_RAWMIDI_STREAM_OUTPUT:
+               err = snd_rawmidi_output_status(rfile->output, &status);
+               break;
+       case SNDRV_RAWMIDI_STREAM_INPUT:
+               err = snd_rawmidi_input_status(rfile->input, &status);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (err < 0)
+               return err;
+
+       if (put_timespec(&status.tstamp, &src->tstamp) ||
+           put_user(status.avail, &src->avail) ||
+           put_user(status.xruns, &src->xruns))
+               return -EFAULT;
+
+       return 0;
+}
+#endif /* CONFIG_X86_X32 */
+
 enum {
        SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
        SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
+#ifdef CONFIG_X86_X32
+       SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
+#endif /* CONFIG_X86_X32 */
 };
 
 static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@@ -115,6 +163,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
                return snd_rawmidi_ioctl_params_compat(rfile, argp);
        case SNDRV_RAWMIDI_IOCTL_STATUS32:
                return snd_rawmidi_ioctl_status_compat(rfile, argp);
+#ifdef CONFIG_X86_X32
+       case SNDRV_RAWMIDI_IOCTL_STATUS_X32:
+               return snd_rawmidi_ioctl_status_x32(rfile, argp);
+#endif /* CONFIG_X86_X32 */
        }
        return -ENOIOCTLCMD;
 }
index 8db156b207f187dfc821160cf39d92a8a5521085..8cdf489df80e03ee2cd5652aec627ffa73e9fcc3 100644 (file)
@@ -149,8 +149,6 @@ odev_release(struct inode *inode, struct file *file)
        if ((dp = file->private_data) == NULL)
                return 0;
 
-       snd_seq_oss_drain_write(dp);
-
        mutex_lock(&register_mutex);
        snd_seq_oss_release(dp);
        mutex_unlock(&register_mutex);
index b43924325249c01b0cdd11fc1164572a50369f98..d7b4d016b547584ed337c6d0e29502ad1b12c5bf 100644 (file)
@@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co
 unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait);
 
 void snd_seq_oss_reset(struct seq_oss_devinfo *dp);
-void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp);
 
 /* */
 void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time);
index 6779e82b46dd7060bd982137ca75cfcdbbfa989e..92c96a95a903abd82ace8256b77c2c3bb99ff620 100644 (file)
@@ -435,22 +435,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
 }
 
 
-/*
- * Wait until the queue is empty (if we don't have nonblock)
- */
-void
-snd_seq_oss_drain_write(struct seq_oss_devinfo *dp)
-{
-       if (! dp->timer->running)
-               return;
-       if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
-           dp->writeq) {
-               while (snd_seq_oss_writeq_sync(dp->writeq))
-                       ;
-       }
-}
-
-
 /*
  * reset sequencer devices
  */
index 13cfa815732db759935f2daaf4c997c73016eb8c..58e79e02f2174e29f409cf129030af87d240dfce 100644 (file)
@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
        else
                down_read(&grp->list_mutex);
        list_for_each_entry(subs, &grp->list_head, src_list) {
+               /* both ports ready? */
+               if (atomic_read(&subs->ref_count) != 2)
+                       continue;
                event->dest = subs->info.dest;
                if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
                        /* convert time according to flag with subscription */
index 801076687bb16f082a8780125c69e879bdef4019..c850345c43b53dd5616b155f34f741d0ca30701c 100644 (file)
@@ -383,15 +383,20 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
 
        if (snd_BUG_ON(!pool))
                return -EINVAL;
-       if (pool->ptr)                  /* should be atomic? */
-               return 0;
 
-       pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
-       if (!pool->ptr)
+       cellptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
+       if (!cellptr)
                return -ENOMEM;
 
        /* add new cells to the free cell list */
        spin_lock_irqsave(&pool->lock, flags);
+       if (pool->ptr) {
+               spin_unlock_irqrestore(&pool->lock, flags);
+               vfree(cellptr);
+               return 0;
+       }
+
+       pool->ptr = cellptr;
        pool->free = NULL;
 
        for (cell = 0; cell < pool->size; cell++) {
index 55170a20ae7237246f5560e14c5b5066bb52ba35..fe686ee41c6da064ad4e1aa43ce172e359da1184 100644 (file)
@@ -173,10 +173,6 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
 }
 
 /* */
-enum group_type {
-       SRC_LIST, DEST_LIST
-};
-
 static int subscribe_port(struct snd_seq_client *client,
                          struct snd_seq_client_port *port,
                          struct snd_seq_port_subs_info *grp,
@@ -203,6 +199,20 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
        return NULL;
 }
 
+static void delete_and_unsubscribe_port(struct snd_seq_client *client,
+                                       struct snd_seq_client_port *port,
+                                       struct snd_seq_subscribers *subs,
+                                       bool is_src, bool ack);
+
+static inline struct snd_seq_subscribers *
+get_subscriber(struct list_head *p, bool is_src)
+{
+       if (is_src)
+               return list_entry(p, struct snd_seq_subscribers, src_list);
+       else
+               return list_entry(p, struct snd_seq_subscribers, dest_list);
+}
+
 /*
  * remove all subscribers on the list
  * this is called from port_delete, for each src and dest list.
@@ -210,7 +220,7 @@ static struct snd_seq_client_port *get_client_port(struct snd_seq_addr *addr,
 static void clear_subscriber_list(struct snd_seq_client *client,
                                  struct snd_seq_client_port *port,
                                  struct snd_seq_port_subs_info *grp,
-                                 int grptype)
+                                 int is_src)
 {
        struct list_head *p, *n;
 
@@ -219,15 +229,13 @@ static void clear_subscriber_list(struct snd_seq_client *client,
                struct snd_seq_client *c;
                struct snd_seq_client_port *aport;
 
-               if (grptype == SRC_LIST) {
-                       subs = list_entry(p, struct snd_seq_subscribers, src_list);
+               subs = get_subscriber(p, is_src);
+               if (is_src)
                        aport = get_client_port(&subs->info.dest, &c);
-               } else {
-                       subs = list_entry(p, struct snd_seq_subscribers, dest_list);
+               else
                        aport = get_client_port(&subs->info.sender, &c);
-               }
-               list_del(p);
-               unsubscribe_port(client, port, grp, &subs->info, 0);
+               delete_and_unsubscribe_port(client, port, subs, is_src, false);
+
                if (!aport) {
                        /* looks like the connected port is being deleted.
                         * we decrease the counter, and when both ports are deleted
@@ -235,21 +243,14 @@ static void clear_subscriber_list(struct snd_seq_client *client,
                         */
                        if (atomic_dec_and_test(&subs->ref_count))
                                kfree(subs);
-               } else {
-                       /* ok we got the connected port */
-                       struct snd_seq_port_subs_info *agrp;
-                       agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src;
-                       down_write(&agrp->list_mutex);
-                       if (grptype == SRC_LIST)
-                               list_del(&subs->dest_list);
-                       else
-                               list_del(&subs->src_list);
-                       up_write(&agrp->list_mutex);
-                       unsubscribe_port(c, aport, agrp, &subs->info, 1);
-                       kfree(subs);
-                       snd_seq_port_unlock(aport);
-                       snd_seq_client_unlock(c);
+                       continue;
                }
+
+               /* ok we got the connected port */
+               delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
+               kfree(subs);
+               snd_seq_port_unlock(aport);
+               snd_seq_client_unlock(c);
        }
 }
 
@@ -262,8 +263,8 @@ static int port_delete(struct snd_seq_client *client,
        snd_use_lock_sync(&port->use_lock); 
 
        /* clear subscribers info */
-       clear_subscriber_list(client, port, &port->c_src, SRC_LIST);
-       clear_subscriber_list(client, port, &port->c_dest, DEST_LIST);
+       clear_subscriber_list(client, port, &port->c_src, true);
+       clear_subscriber_list(client, port, &port->c_dest, false);
 
        if (port->private_free)
                port->private_free(port->private_data);
@@ -479,85 +480,123 @@ static int match_subs_info(struct snd_seq_port_subscribe *r,
        return 0;
 }
 
-
-/* connect two ports */
-int snd_seq_port_connect(struct snd_seq_client *connector,
-                        struct snd_seq_client *src_client,
-                        struct snd_seq_client_port *src_port,
-                        struct snd_seq_client *dest_client,
-                        struct snd_seq_client_port *dest_port,
-                        struct snd_seq_port_subscribe *info)
+static int check_and_subscribe_port(struct snd_seq_client *client,
+                                   struct snd_seq_client_port *port,
+                                   struct snd_seq_subscribers *subs,
+                                   bool is_src, bool exclusive, bool ack)
 {
-       struct snd_seq_port_subs_info *src = &src_port->c_src;
-       struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
-       struct snd_seq_subscribers *subs, *s;
-       int err, src_called = 0;
-       unsigned long flags;
-       int exclusive;
-
-       subs = kzalloc(sizeof(*subs), GFP_KERNEL);
-       if (! subs)
-               return -ENOMEM;
-
-       subs->info = *info;
-       atomic_set(&subs->ref_count, 2);
+       struct snd_seq_port_subs_info *grp;
+       struct list_head *p;
+       struct snd_seq_subscribers *s;
+       int err;
 
-       down_write(&src->list_mutex);
-       down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
-
-       exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;
+       grp = is_src ? &port->c_src : &port->c_dest;
        err = -EBUSY;
+       down_write(&grp->list_mutex);
        if (exclusive) {
-               if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head))
+               if (!list_empty(&grp->list_head))
                        goto __error;
        } else {
-               if (src->exclusive || dest->exclusive)
+               if (grp->exclusive)
                        goto __error;
                /* check whether already exists */
-               list_for_each_entry(s, &src->list_head, src_list) {
-                       if (match_subs_info(info, &s->info))
-                               goto __error;
-               }
-               list_for_each_entry(s, &dest->list_head, dest_list) {
-                       if (match_subs_info(info, &s->info))
+               list_for_each(p, &grp->list_head) {
+                       s = get_subscriber(p, is_src);
+                       if (match_subs_info(&subs->info, &s->info))
                                goto __error;
                }
        }
 
-       if ((err = subscribe_port(src_client, src_port, src, info,
-                                 connector->number != src_client->number)) < 0)
-               goto __error;
-       src_called = 1;
-
-       if ((err = subscribe_port(dest_client, dest_port, dest, info,
-                                 connector->number != dest_client->number)) < 0)
+       err = subscribe_port(client, port, grp, &subs->info, ack);
+       if (err < 0) {
+               grp->exclusive = 0;
                goto __error;
+       }
 
        /* add to list */
-       write_lock_irqsave(&src->list_lock, flags);
-       // write_lock(&dest->list_lock); // no other lock yet
-       list_add_tail(&subs->src_list, &src->list_head);
-       list_add_tail(&subs->dest_list, &dest->list_head);
-       // write_unlock(&dest->list_lock); // no other lock yet
-       write_unlock_irqrestore(&src->list_lock, flags);
+       write_lock_irq(&grp->list_lock);
+       if (is_src)
+               list_add_tail(&subs->src_list, &grp->list_head);
+       else
+               list_add_tail(&subs->dest_list, &grp->list_head);
+       grp->exclusive = exclusive;
+       atomic_inc(&subs->ref_count);
+       write_unlock_irq(&grp->list_lock);
+       err = 0;
 
-       src->exclusive = dest->exclusive = exclusive;
+ __error:
+       up_write(&grp->list_mutex);
+       return err;
+}
+
+static void delete_and_unsubscribe_port(struct snd_seq_client *client,
+                                       struct snd_seq_client_port *port,
+                                       struct snd_seq_subscribers *subs,
+                                       bool is_src, bool ack)
+{
+       struct snd_seq_port_subs_info *grp;
+       struct list_head *list;
+       bool empty;
+
+       grp = is_src ? &port->c_src : &port->c_dest;
+       list = is_src ? &subs->src_list : &subs->dest_list;
+       down_write(&grp->list_mutex);
+       write_lock_irq(&grp->list_lock);
+       empty = list_empty(list);
+       if (!empty)
+               list_del_init(list);
+       grp->exclusive = 0;
+       write_unlock_irq(&grp->list_lock);
+       up_write(&grp->list_mutex);
+
+       if (!empty)
+               unsubscribe_port(client, port, grp, &subs->info, ack);
+}
+
+/* connect two ports */
+int snd_seq_port_connect(struct snd_seq_client *connector,
+                        struct snd_seq_client *src_client,
+                        struct snd_seq_client_port *src_port,
+                        struct snd_seq_client *dest_client,
+                        struct snd_seq_client_port *dest_port,
+                        struct snd_seq_port_subscribe *info)
+{
+       struct snd_seq_subscribers *subs;
+       bool exclusive;
+       int err;
+
+       subs = kzalloc(sizeof(*subs), GFP_KERNEL);
+       if (!subs)
+               return -ENOMEM;
+
+       subs->info = *info;
+       atomic_set(&subs->ref_count, 0);
+       INIT_LIST_HEAD(&subs->src_list);
+       INIT_LIST_HEAD(&subs->dest_list);
+
+       exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
+
+       err = check_and_subscribe_port(src_client, src_port, subs, true,
+                                      exclusive,
+                                      connector->number != src_client->number);
+       if (err < 0)
+               goto error;
+       err = check_and_subscribe_port(dest_client, dest_port, subs, false,
+                                      exclusive,
+                                      connector->number != dest_client->number);
+       if (err < 0)
+               goto error_dest;
 
-       up_write(&dest->list_mutex);
-       up_write(&src->list_mutex);
        return 0;
 
__error:
-       if (src_called)
-               unsubscribe_port(src_client, src_port, src, info,
-                                connector->number != src_client->number);
error_dest:
+       delete_and_unsubscribe_port(src_client, src_port, subs, true,
+                                   connector->number != src_client->number);
+ error:
        kfree(subs);
-       up_write(&dest->list_mutex);
-       up_write(&src->list_mutex);
        return err;
 }
 
-
 /* remove the connection */
 int snd_seq_port_disconnect(struct snd_seq_client *connector,
                            struct snd_seq_client *src_client,
@@ -567,37 +606,28 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
                            struct snd_seq_port_subscribe *info)
 {
        struct snd_seq_port_subs_info *src = &src_port->c_src;
-       struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
        struct snd_seq_subscribers *subs;
        int err = -ENOENT;
-       unsigned long flags;
 
        down_write(&src->list_mutex);
-       down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
-
        /* look for the connection */
        list_for_each_entry(subs, &src->list_head, src_list) {
                if (match_subs_info(info, &subs->info)) {
-                       write_lock_irqsave(&src->list_lock, flags);
-                       // write_lock(&dest->list_lock);  // no lock yet
-                       list_del(&subs->src_list);
-                       list_del(&subs->dest_list);
-                       // write_unlock(&dest->list_lock);
-                       write_unlock_irqrestore(&src->list_lock, flags);
-                       src->exclusive = dest->exclusive = 0;
-                       unsubscribe_port(src_client, src_port, src, info,
-                                        connector->number != src_client->number);
-                       unsubscribe_port(dest_client, dest_port, dest, info,
-                                        connector->number != dest_client->number);
-                       kfree(subs);
+                       atomic_dec(&subs->ref_count); /* mark as not ready */
                        err = 0;
                        break;
                }
        }
-
-       up_write(&dest->list_mutex);
        up_write(&src->list_mutex);
-       return err;
+       if (err < 0)
+               return err;
+
+       delete_and_unsubscribe_port(src_client, src_port, subs, true,
+                                   connector->number != src_client->number);
+       delete_and_unsubscribe_port(dest_client, dest_port, subs, false,
+                                   connector->number != dest_client->number);
+       kfree(subs);
+       return 0;
 }
 
 
index 82b220c769c131ecd05fea96fd0692c12d56642f..293104926098f7074001b6f6a4248d2a09ddd360 100644 (file)
@@ -90,6 +90,9 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
 
 void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&tmr->lock, flags);
        /* setup defaults */
        tmr->ppq = 96;          /* 96 PPQ */
        tmr->tempo = 500000;    /* 120 BPM */
@@ -105,21 +108,25 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
        tmr->preferred_resolution = seq_default_timer_resolution;
 
        tmr->skew = tmr->skew_base = SKEW_BASE;
+       spin_unlock_irqrestore(&tmr->lock, flags);
 }
 
-void snd_seq_timer_reset(struct snd_seq_timer * tmr)
+static void seq_timer_reset(struct snd_seq_timer *tmr)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&tmr->lock, flags);
-
        /* reset time & songposition */
        tmr->cur_time.tv_sec = 0;
        tmr->cur_time.tv_nsec = 0;
 
        tmr->tick.cur_tick = 0;
        tmr->tick.fraction = 0;
+}
+
+void snd_seq_timer_reset(struct snd_seq_timer *tmr)
+{
+       unsigned long flags;
 
+       spin_lock_irqsave(&tmr->lock, flags);
+       seq_timer_reset(tmr);
        spin_unlock_irqrestore(&tmr->lock, flags);
 }
 
@@ -138,8 +145,11 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
        tmr = q->timer;
        if (tmr == NULL)
                return;
-       if (!tmr->running)
+       spin_lock_irqsave(&tmr->lock, flags);
+       if (!tmr->running) {
+               spin_unlock_irqrestore(&tmr->lock, flags);
                return;
+       }
 
        resolution *= ticks;
        if (tmr->skew != tmr->skew_base) {
@@ -148,8 +158,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
                        (((resolution & 0xffff) * tmr->skew) >> 16);
        }
 
-       spin_lock_irqsave(&tmr->lock, flags);
-
        /* update timer */
        snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
 
@@ -296,26 +304,30 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
        t->callback = snd_seq_timer_interrupt;
        t->callback_data = q;
        t->flags |= SNDRV_TIMER_IFLG_AUTO;
+       spin_lock_irq(&tmr->lock);
        tmr->timeri = t;
+       spin_unlock_irq(&tmr->lock);
        return 0;
 }
 
 int snd_seq_timer_close(struct snd_seq_queue *q)
 {
        struct snd_seq_timer *tmr;
+       struct snd_timer_instance *t;
        
        tmr = q->timer;
        if (snd_BUG_ON(!tmr))
                return -EINVAL;
-       if (tmr->timeri) {
-               snd_timer_stop(tmr->timeri);
-               snd_timer_close(tmr->timeri);
-               tmr->timeri = NULL;
-       }
+       spin_lock_irq(&tmr->lock);
+       t = tmr->timeri;
+       tmr->timeri = NULL;
+       spin_unlock_irq(&tmr->lock);
+       if (t)
+               snd_timer_close(t);
        return 0;
 }
 
-int snd_seq_timer_stop(struct snd_seq_timer * tmr)
+static int seq_timer_stop(struct snd_seq_timer *tmr)
 {
        if (! tmr->timeri)
                return -EINVAL;
@@ -326,6 +338,17 @@ int snd_seq_timer_stop(struct snd_seq_timer * tmr)
        return 0;
 }
 
+int snd_seq_timer_stop(struct snd_seq_timer *tmr)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&tmr->lock, flags);
+       err = seq_timer_stop(tmr);
+       spin_unlock_irqrestore(&tmr->lock, flags);
+       return err;
+}
+
 static int initialize_timer(struct snd_seq_timer *tmr)
 {
        struct snd_timer *t;
@@ -358,13 +381,13 @@ static int initialize_timer(struct snd_seq_timer *tmr)
        return 0;
 }
 
-int snd_seq_timer_start(struct snd_seq_timer * tmr)
+static int seq_timer_start(struct snd_seq_timer *tmr)
 {
        if (! tmr->timeri)
                return -EINVAL;
        if (tmr->running)
-               snd_seq_timer_stop(tmr);
-       snd_seq_timer_reset(tmr);
+               seq_timer_stop(tmr);
+       seq_timer_reset(tmr);
        if (initialize_timer(tmr) < 0)
                return -EINVAL;
        snd_timer_start(tmr->timeri, tmr->ticks);
@@ -373,14 +396,25 @@ int snd_seq_timer_start(struct snd_seq_timer * tmr)
        return 0;
 }
 
-int snd_seq_timer_continue(struct snd_seq_timer * tmr)
+int snd_seq_timer_start(struct snd_seq_timer *tmr)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&tmr->lock, flags);
+       err = seq_timer_start(tmr);
+       spin_unlock_irqrestore(&tmr->lock, flags);
+       return err;
+}
+
+static int seq_timer_continue(struct snd_seq_timer *tmr)
 {
        if (! tmr->timeri)
                return -EINVAL;
        if (tmr->running)
                return -EBUSY;
        if (! tmr->initialized) {
-               snd_seq_timer_reset(tmr);
+               seq_timer_reset(tmr);
                if (initialize_timer(tmr) < 0)
                        return -EINVAL;
        }
@@ -390,11 +424,24 @@ int snd_seq_timer_continue(struct snd_seq_timer * tmr)
        return 0;
 }
 
+int snd_seq_timer_continue(struct snd_seq_timer *tmr)
+{
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&tmr->lock, flags);
+       err = seq_timer_continue(tmr);
+       spin_unlock_irqrestore(&tmr->lock, flags);
+       return err;
+}
+
 /* return current 'real' time. use timeofday() to get better granularity. */
 snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
 {
        snd_seq_real_time_t cur_time;
+       unsigned long flags;
 
+       spin_lock_irqsave(&tmr->lock, flags);
        cur_time = tmr->cur_time;
        if (tmr->running) { 
                struct timeval tm;
@@ -410,7 +457,7 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr)
                }
                snd_seq_sanity_real_time(&cur_time);
        }
-                
+       spin_unlock_irqrestore(&tmr->lock, flags);
        return cur_time;        
 }
 
index 3da2d48610b3a91e4b93b0967b1fac5afebe41f7..c82ed3e70506db65adcbd48f6bdd55bd9628633d 100644 (file)
@@ -155,21 +155,26 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
        struct snd_virmidi *vmidi = substream->runtime->private_data;
        int count, res;
        unsigned char buf[32], *pbuf;
+       unsigned long flags;
 
        if (up) {
                vmidi->trigger = 1;
                if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
                    !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
-                       snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail);
-                       return;         /* ignored */
+                       while (snd_rawmidi_transmit(substream, buf,
+                                                   sizeof(buf)) > 0) {
+                               /* ignored */
+                       }
+                       return;
                }
                if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
                        if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
                                return;
                        vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
                }
+               spin_lock_irqsave(&substream->runtime->lock, flags);
                while (1) {
-                       count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf));
+                       count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf));
                        if (count <= 0)
                                break;
                        pbuf = buf;
@@ -179,16 +184,18 @@ static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream,
                                        snd_midi_event_reset_encode(vmidi->parser);
                                        continue;
                                }
-                               snd_rawmidi_transmit_ack(substream, res);
+                               __snd_rawmidi_transmit_ack(substream, res);
                                pbuf += res;
                                count -= res;
                                if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
                                        if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
-                                               return;
+                                               goto out;
                                        vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
                                }
                        }
                }
+       out:
+               spin_unlock_irqrestore(&substream->runtime->lock, flags);
        } else {
                vmidi->trigger = 0;
        }
@@ -254,9 +261,13 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream)
  */
 static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
 {
+       struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
        struct snd_virmidi *vmidi = substream->runtime->private_data;
-       snd_midi_event_free(vmidi->parser);
+
+       write_lock_irq(&rdev->filelist_lock);
        list_del(&vmidi->list);
+       write_unlock_irq(&rdev->filelist_lock);
+       snd_midi_event_free(vmidi->parser);
        substream->runtime->private_data = NULL;
        kfree(vmidi);
        return 0;
index af1f68f7e315334202f191e3f049f044de9495f7..dca817fc78941b5f9109e8117b3fc5adb621562e 100644 (file)
@@ -422,7 +422,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
        spin_lock_irqsave(&timer->lock, flags);
        list_for_each_entry(ts, &ti->slave_active_head, active_list)
                if (ts->ccallback)
-                       ts->ccallback(ti, event + 100, &tstamp, resolution);
+                       ts->ccallback(ts, event + 100, &tstamp, resolution);
        spin_unlock_irqrestore(&timer->lock, flags);
 }
 
@@ -451,6 +451,10 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri)
        unsigned long flags;
 
        spin_lock_irqsave(&slave_active_lock, flags);
+       if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
+               spin_unlock_irqrestore(&slave_active_lock, flags);
+               return -EBUSY;
+       }
        timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
        if (timeri->master && timeri->timer) {
                spin_lock(&timeri->timer->lock);
@@ -475,7 +479,8 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
                return -EINVAL;
        if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
                result = snd_timer_start_slave(timeri);
-               snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+               if (result >= 0)
+                       snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
                return result;
        }
        timer = timeri->timer;
@@ -484,11 +489,18 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
        if (timer->card && timer->card->shutdown)
                return -ENODEV;
        spin_lock_irqsave(&timer->lock, flags);
+       if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
+                            SNDRV_TIMER_IFLG_START)) {
+               result = -EBUSY;
+               goto unlock;
+       }
        timeri->ticks = timeri->cticks = ticks;
        timeri->pticks = 0;
        result = snd_timer_start1(timer, timeri, ticks);
+ unlock:
        spin_unlock_irqrestore(&timer->lock, flags);
-       snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+       if (result >= 0)
+               snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
        return result;
 }
 
@@ -502,9 +514,17 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
 
        if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
                spin_lock_irqsave(&slave_active_lock, flags);
+               if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) {
+                       spin_unlock_irqrestore(&slave_active_lock, flags);
+                       return -EBUSY;
+               }
+               if (timeri->timer)
+                       spin_lock(&timeri->timer->lock);
                timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
                list_del_init(&timeri->ack_list);
                list_del_init(&timeri->active_list);
+               if (timeri->timer)
+                       spin_unlock(&timeri->timer->lock);
                spin_unlock_irqrestore(&slave_active_lock, flags);
                goto __end;
        }
@@ -512,6 +532,11 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
        if (!timer)
                return -EINVAL;
        spin_lock_irqsave(&timer->lock, flags);
+       if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
+                              SNDRV_TIMER_IFLG_START))) {
+               spin_unlock_irqrestore(&timer->lock, flags);
+               return -EBUSY;
+       }
        list_del_init(&timeri->ack_list);
        list_del_init(&timeri->active_list);
        if (timer->card && timer->card->shutdown) {
@@ -581,10 +606,15 @@ int snd_timer_continue(struct snd_timer_instance *timeri)
        if (timer->card && timer->card->shutdown)
                return -ENODEV;
        spin_lock_irqsave(&timer->lock, flags);
+       if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
+               result = -EBUSY;
+               goto unlock;
+       }
        if (!timeri->cticks)
                timeri->cticks = 1;
        timeri->pticks = 0;
        result = snd_timer_start1(timer, timeri, timer->sticks);
+ unlock:
        spin_unlock_irqrestore(&timer->lock, flags);
        snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
        return result;
@@ -718,8 +748,8 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
                        ti->cticks = ti->ticks;
                } else {
                        ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
-                       if (--timer->running)
-                               list_del_init(&ti->active_list);
+                       --timer->running;
+                       list_del_init(&ti->active_list);
                }
                if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
                    (ti->flags & SNDRV_TIMER_IFLG_FAST))
@@ -1032,11 +1062,21 @@ static int snd_timer_s_stop(struct snd_timer * timer)
        return 0;
 }
 
+static int snd_timer_s_close(struct snd_timer *timer)
+{
+       struct snd_timer_system_private *priv;
+
+       priv = (struct snd_timer_system_private *)timer->private_data;
+       del_timer_sync(&priv->tlist);
+       return 0;
+}
+
 static struct snd_timer_hardware snd_timer_system =
 {
        .flags =        SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
        .resolution =   1000000000L / HZ,
        .ticks =        10000000L,
+       .close =        snd_timer_s_close,
        .start =        snd_timer_s_start,
        .stop =         snd_timer_s_stop
 };
@@ -1893,6 +1933,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 {
        struct snd_timer_user *tu;
        long result = 0, unit;
+       int qhead;
        int err = 0;
 
        tu = file->private_data;
@@ -1904,7 +1945,7 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 
                        if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
                                err = -EAGAIN;
-                               break;
+                               goto _error;
                        }
 
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -1919,42 +1960,37 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 
                        if (tu->disconnected) {
                                err = -ENODEV;
-                               break;
+                               goto _error;
                        }
                        if (signal_pending(current)) {
                                err = -ERESTARTSYS;
-                               break;
+                               goto _error;
                        }
                }
 
+               qhead = tu->qhead++;
+               tu->qhead %= tu->queue_size;
                spin_unlock_irq(&tu->qlock);
-               if (err < 0)
-                       goto _error;
 
                if (tu->tread) {
-                       if (copy_to_user(buffer, &tu->tqueue[tu->qhead++],
-                                        sizeof(struct snd_timer_tread))) {
+                       if (copy_to_user(buffer, &tu->tqueue[qhead],
+                                        sizeof(struct snd_timer_tread)))
                                err = -EFAULT;
-                               goto _error;
-                       }
                } else {
-                       if (copy_to_user(buffer, &tu->queue[tu->qhead++],
-                                        sizeof(struct snd_timer_read))) {
+                       if (copy_to_user(buffer, &tu->queue[qhead],
+                                        sizeof(struct snd_timer_read)))
                                err = -EFAULT;
-                               goto _error;
-                       }
                }
 
-               tu->qhead %= tu->queue_size;
-
-               result += unit;
-               buffer += unit;
-
                spin_lock_irq(&tu->qlock);
                tu->qused--;
+               if (err < 0)
+                       goto _error;
+               result += unit;
+               buffer += unit;
        }
-       spin_unlock_irq(&tu->qlock);
  _error:
+       spin_unlock_irq(&tu->qlock);
        return result > 0 ? result : err;
 }
 
index e05802ae6e1b1e240a187a43c9f5308fcf7145c0..2e908225d754cfd4f4d23aa40abab01785351456 100644 (file)
@@ -70,13 +70,14 @@ static int snd_timer_user_status_compat(struct file *file,
                                        struct snd_timer_status32 __user *_status)
 {
        struct snd_timer_user *tu;
-       struct snd_timer_status status;
+       struct snd_timer_status32 status;
        
        tu = file->private_data;
        if (snd_BUG_ON(!tu->timeri))
                return -ENXIO;
        memset(&status, 0, sizeof(status));
-       status.tstamp = tu->tstamp;
+       status.tstamp.tv_sec = tu->tstamp.tv_sec;
+       status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
        status.resolution = snd_timer_resolution(tu->timeri);
        status.lost = tu->timeri->lost;
        status.overrun = tu->overrun;
@@ -88,12 +89,21 @@ static int snd_timer_user_status_compat(struct file *file,
        return 0;
 }
 
+#ifdef CONFIG_X86_X32
+/* X32 ABI has the same struct as x86-64 */
+#define snd_timer_user_status_x32(file, s) \
+       snd_timer_user_status(file, s)
+#endif /* CONFIG_X86_X32 */
+
 /*
  */
 
 enum {
        SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
        SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
+#ifdef CONFIG_X86_X32
+       SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status),
+#endif /* CONFIG_X86_X32 */
 };
 
 static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
@@ -122,6 +132,10 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
                return snd_timer_user_info_compat(file, argp);
        case SNDRV_TIMER_IOCTL_STATUS32:
                return snd_timer_user_status_compat(file, argp);
+#ifdef CONFIG_X86_X32
+       case SNDRV_TIMER_IOCTL_STATUS_X32:
+               return snd_timer_user_status_x32(file, argp);
+#endif /* CONFIG_X86_X32 */
        }
        return -ENOIOCTLCMD;
 }
index bde33308f0d6bc697035a627aef2cc24523b195c..c0f8f613f1f1b5e954ffa82b760c82353dd17c80 100644 (file)
@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
 module_param(fake_buffer, bool, 0444);
 MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
 #ifdef CONFIG_HIGH_RES_TIMERS
-module_param(hrtimer, bool, 0444);
+module_param(hrtimer, bool, 0644);
 MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
 #endif
 
@@ -109,6 +109,9 @@ struct dummy_timer_ops {
        snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
 };
 
+#define get_dummy_ops(substream) \
+       (*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
+
 struct dummy_model {
        const char *name;
        int (*playback_constraints)(struct snd_pcm_runtime *runtime);
@@ -137,7 +140,6 @@ struct snd_dummy {
        int iobox;
        struct snd_kcontrol *cd_volume_ctl;
        struct snd_kcontrol *cd_switch_ctl;
-       const struct dummy_timer_ops *timer_ops;
 };
 
 /*
@@ -231,6 +233,8 @@ static struct dummy_model *dummy_models[] = {
  */
 
 struct dummy_systimer_pcm {
+       /* ops must be the first item */
+       const struct dummy_timer_ops *timer_ops;
        spinlock_t lock;
        struct timer_list timer;
        unsigned long base_time;
@@ -366,6 +370,8 @@ static const struct dummy_timer_ops dummy_systimer_ops = {
  */
 
 struct dummy_hrtimer_pcm {
+       /* ops must be the first item */
+       const struct dummy_timer_ops *timer_ops;
        ktime_t base_time;
        ktime_t period_time;
        atomic_t running;
@@ -492,31 +498,25 @@ static const struct dummy_timer_ops dummy_hrtimer_ops = {
 
 static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
-
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
-               return dummy->timer_ops->start(substream);
+               return get_dummy_ops(substream)->start(substream);
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               return dummy->timer_ops->stop(substream);
+               return get_dummy_ops(substream)->stop(substream);
        }
        return -EINVAL;
 }
 
 static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
 {
-       struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
-
-       return dummy->timer_ops->prepare(substream);
+       return get_dummy_ops(substream)->prepare(substream);
 }
 
 static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
-
-       return dummy->timer_ops->pointer(substream);
+       return get_dummy_ops(substream)->pointer(substream);
 }
 
 static struct snd_pcm_hardware dummy_pcm_hardware = {
@@ -562,17 +562,19 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
        struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
        struct dummy_model *model = dummy->model;
        struct snd_pcm_runtime *runtime = substream->runtime;
+       const struct dummy_timer_ops *ops;
        int err;
 
-       dummy->timer_ops = &dummy_systimer_ops;
+       ops = &dummy_systimer_ops;
 #ifdef CONFIG_HIGH_RES_TIMERS
        if (hrtimer)
-               dummy->timer_ops = &dummy_hrtimer_ops;
+               ops = &dummy_hrtimer_ops;
 #endif
 
-       err = dummy->timer_ops->create(substream);
+       err = ops->create(substream);
        if (err < 0)
                return err;
+       get_dummy_ops(substream) = ops;
 
        runtime->hw = dummy->pcm_hw;
        if (substream->pcm->device & 1) {
@@ -594,7 +596,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
                        err = model->capture_constraints(substream->runtime);
        }
        if (err < 0) {
-               dummy->timer_ops->free(substream);
+               get_dummy_ops(substream)->free(substream);
                return err;
        }
        return 0;
@@ -602,8 +604,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream)
 
 static int dummy_pcm_close(struct snd_pcm_substream *substream)
 {
-       struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
-       dummy->timer_ops->free(substream);
+       get_dummy_ops(substream)->free(substream);
        return 0;
 }
 
index b02a5e8cad448c40368b9396dc1c0890c91a3a42..0ac92aba5bc1c9a4c01b1764a6f16a098e3bbae1 100644 (file)
@@ -63,7 +63,7 @@ struct amdtp_dot {
 #define BYTE_PER_SAMPLE (4)
 #define MAGIC_DOT_BYTE (2)
 #define MAGIC_BYTE_OFF(x) (((x) * BYTE_PER_SAMPLE) + MAGIC_DOT_BYTE)
-static const u8 dot_scrt(const u8 idx, const unsigned int off)
+static u8 dot_scrt(const u8 idx, const unsigned int off)
 {
        /*
         * the length of the added pattern only depends on the lower nibble
index 904ce0329fa1ac3d7e3364d66664d6ba60d6b6d8..040a96d1ba8ec1fa1dbfa4521a46e7efb865f435 100644 (file)
@@ -230,6 +230,7 @@ int snd_tscm_transaction_register(struct snd_tscm *tscm)
        return err;
 error:
        fw_core_remove_address_handler(&tscm->async_handler);
+       tscm->async_handler.callback_data = NULL;
        return err;
 }
 
@@ -276,6 +277,9 @@ void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
        __be32 reg;
        unsigned int i;
 
+       if (tscm->async_handler.callback_data == NULL)
+               return;
+
        /* Turn off FireWire LED. */
        reg = cpu_to_be32(0x0000008e);
        snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
@@ -297,6 +301,8 @@ void snd_tscm_transaction_unregister(struct snd_tscm *tscm)
                           &reg, sizeof(reg), 0);
 
        fw_core_remove_address_handler(&tscm->async_handler);
+       tscm->async_handler.callback_data = NULL;
+
        for (i = 0; i < TSCM_MIDI_OUT_PORT_MAX; i++)
                snd_fw_async_midi_port_destroy(&tscm->out_ports[i]);
 }
index ee0bc183950888ba6ade12bb8441fa81be41ec11..e281c338e562d59e861303789d82c319b9a2ae9c 100644 (file)
@@ -21,7 +21,6 @@ static struct snd_tscm_spec model_specs[] = {
                .pcm_playback_analog_channels = 8,
                .midi_capture_ports = 4,
                .midi_playback_ports = 4,
-               .is_controller = true,
        },
        {
                .name = "FW-1082",
@@ -31,9 +30,16 @@ static struct snd_tscm_spec model_specs[] = {
                .pcm_playback_analog_channels = 2,
                .midi_capture_ports = 2,
                .midi_playback_ports = 2,
-               .is_controller = true,
        },
-       /* FW-1804 may be supported. */
+       {
+               .name = "FW-1804",
+               .has_adat = true,
+               .has_spdif = true,
+               .pcm_capture_analog_channels = 8,
+               .pcm_playback_analog_channels = 2,
+               .midi_capture_ports = 2,
+               .midi_playback_ports = 4,
+       },
 };
 
 static int identify_model(struct snd_tscm *tscm)
index 2d028d2bd3bdcdcd8be15a184e555786726c94d8..30ab77e924f7f68f9b939a230109152722ad9057 100644 (file)
@@ -39,7 +39,6 @@ struct snd_tscm_spec {
        unsigned int pcm_playback_analog_channels;
        unsigned int midi_capture_ports;
        unsigned int midi_playback_ports;
-       bool is_controller;
 };
 
 #define TSCM_MIDI_IN_PORT_MAX  4
@@ -72,9 +71,6 @@ struct snd_tscm {
        struct snd_fw_async_midi_port out_ports[TSCM_MIDI_OUT_PORT_MAX];
        u8 running_status[TSCM_MIDI_OUT_PORT_MAX];
        bool on_sysex[TSCM_MIDI_OUT_PORT_MAX];
-
-       /* For control messages. */
-       struct snd_firewire_tascam_status *status;
 };
 
 #define TSCM_ADDR_BASE                 0xffff00000000ull
index b5a17cb510a0b4ee71115973a7d73309e9061b03..8c486235c905253ea0609183d813362a294e42f9 100644 (file)
@@ -426,18 +426,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_stop_chip);
  * @bus: HD-audio core bus
  * @status: INTSTS register value
  * @ask: callback to be called for woken streams
+ *
+ * Returns the bits of handled streams, or zero if no stream is handled.
  */
-void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
+int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
                                    void (*ack)(struct hdac_bus *,
                                                struct hdac_stream *))
 {
        struct hdac_stream *azx_dev;
        u8 sd_status;
+       int handled = 0;
 
        list_for_each_entry(azx_dev, &bus->stream_list, list) {
                if (status & azx_dev->sd_int_sta_mask) {
                        sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
                        snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
+                       handled |= 1 << azx_dev->index;
                        if (!azx_dev->substream || !azx_dev->running ||
                            !(sd_status & SD_INT_COMPLETE))
                                continue;
@@ -445,6 +449,7 @@ void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
                                ack(bus, azx_dev);
                }
        }
+       return handled;
 }
 EXPORT_SYMBOL_GPL(snd_hdac_bus_handle_stream_irq);
 
index 28e2f8b42f5e8e4e7f3aaaaa88f45d6834b02591..891453451543102994b7912584f00483b2c472f0 100644 (file)
@@ -1141,6 +1141,14 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
                emu->emu1010.firmware_thread =
                        kthread_create(emu1010_firmware_thread, emu,
                                       "emu1010_firmware");
+               if (IS_ERR(emu->emu1010.firmware_thread)) {
+                       err = PTR_ERR(emu->emu1010.firmware_thread);
+                       emu->emu1010.firmware_thread = NULL;
+                       dev_info(emu->card->dev,
+                                       "emu1010: Creating thread failed\n");
+                       return err;
+               }
+
                wake_up_process(emu->emu1010.firmware_thread);
        }
 
index 37cf9cee983555ad1a47e4bb43ff2e9db6de39e9..27de8015717d95fdf45ac512a77c60eb32202d67 100644 (file)
@@ -930,6 +930,8 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
        struct azx *chip = dev_id;
        struct hdac_bus *bus = azx_bus(chip);
        u32 status;
+       bool active, handled = false;
+       int repeat = 0; /* count for avoiding endless loop */
 
 #ifdef CONFIG_PM
        if (azx_has_pm_runtime(chip))
@@ -939,33 +941,36 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
 
        spin_lock(&bus->reg_lock);
 
-       if (chip->disabled) {
-               spin_unlock(&bus->reg_lock);
-               return IRQ_NONE;
-       }
-
-       status = azx_readl(chip, INTSTS);
-       if (status == 0 || status == 0xffffffff) {
-               spin_unlock(&bus->reg_lock);
-               return IRQ_NONE;
-       }
+       if (chip->disabled)
+               goto unlock;
 
-       snd_hdac_bus_handle_stream_irq(bus, status, stream_update);
+       do {
+               status = azx_readl(chip, INTSTS);
+               if (status == 0 || status == 0xffffffff)
+                       break;
 
-       /* clear rirb int */
-       status = azx_readb(chip, RIRBSTS);
-       if (status & RIRB_INT_MASK) {
-               if (status & RIRB_INT_RESPONSE) {
-                       if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
-                               udelay(80);
-                       snd_hdac_bus_update_rirb(bus);
+               handled = true;
+               active = false;
+               if (snd_hdac_bus_handle_stream_irq(bus, status, stream_update))
+                       active = true;
+
+               /* clear rirb int */
+               status = azx_readb(chip, RIRBSTS);
+               if (status & RIRB_INT_MASK) {
+                       active = true;
+                       if (status & RIRB_INT_RESPONSE) {
+                               if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND)
+                                       udelay(80);
+                               snd_hdac_bus_update_rirb(bus);
+                       }
+                       azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
                }
-               azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
-       }
+       } while (active && ++repeat < 10);
 
+ unlock:
        spin_unlock(&bus->reg_lock);
 
-       return IRQ_HANDLED;
+       return IRQ_RETVAL(handled);
 }
 EXPORT_SYMBOL_GPL(azx_interrupt);
 
index 30c8efe0f80a3a456bbbe09b6ce05abf810a8552..7ca5b89f088a6922e6acd09c12befae864994320 100644 (file)
@@ -4028,9 +4028,9 @@ static void pin_power_callback(struct hda_codec *codec,
                               struct hda_jack_callback *jack,
                               bool on)
 {
-       if (jack && jack->tbl->nid)
+       if (jack && jack->nid)
                sync_power_state_change(codec,
-                                       set_pin_power_jack(codec, jack->tbl->nid, on));
+                                       set_pin_power_jack(codec, jack->nid, on));
 }
 
 /* callback only doing power up -- called at first */
index 4045dca3d699edd13f06aa9ab7c095948c932a55..e5240cb3749f4186e79f70dfc9e2c6536eaaed1d 100644 (file)
@@ -363,7 +363,10 @@ enum {
                                        ((pci)->device == 0x0d0c) || \
                                        ((pci)->device == 0x160c))
 
-#define IS_BROXTON(pci)        ((pci)->device == 0x5a98)
+#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
+#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
+#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
 
 static char *driver_short_names[] = {
        [AZX_DRIVER_ICH] = "HDA Intel",
@@ -540,13 +543,13 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
 
        if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
                snd_hdac_set_codec_wakeup(bus, true);
-       if (IS_BROXTON(pci)) {
+       if (IS_SKL_PLUS(pci)) {
                pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
                val = val & ~INTEL_HDA_CGCTL_MISCBDCGE;
                pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
        }
        azx_init_chip(chip, full_reset);
-       if (IS_BROXTON(pci)) {
+       if (IS_SKL_PLUS(pci)) {
                pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val);
                val = val | INTEL_HDA_CGCTL_MISCBDCGE;
                pci_write_config_dword(pci, INTEL_HDA_CGCTL, val);
@@ -555,7 +558,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset)
                snd_hdac_set_codec_wakeup(bus, false);
 
        /* reduce dma latency to avoid noise */
-       if (IS_BROXTON(pci))
+       if (IS_BXT(pci))
                bxt_reduce_dma_latency(chip);
 }
 
@@ -977,11 +980,6 @@ static int azx_resume(struct device *dev)
 /* put codec down to D3 at hibernation for Intel SKL+;
  * otherwise BIOS may still access the codec and screw up the driver
  */
-#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
-#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
-#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
-#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
-
 static int azx_freeze_noirq(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2168,10 +2166,10 @@ static void azx_remove(struct pci_dev *pci)
        struct hda_intel *hda;
 
        if (card) {
-               /* flush the pending probing work */
+               /* cancel the pending probing work */
                chip = card->private_data;
                hda = container_of(chip, struct hda_intel, chip);
-               flush_work(&hda->probe_work);
+               cancel_work_sync(&hda->probe_work);
 
                snd_card_free(card);
        }
index c945e257d368890bcd3f72037568e566c0ba9221..a33234e04d4f7a1fe311ce7db50f1a56e9e1d7d4 100644 (file)
@@ -259,7 +259,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
                if (!callback)
                        return ERR_PTR(-ENOMEM);
                callback->func = func;
-               callback->tbl = jack;
+               callback->nid = jack->nid;
                callback->next = jack->callback;
                jack->callback = callback;
        }
index 858708a044f57ef563d79a100c5a92e5f3adaa3d..e9814c0168ea5d77da2922454ed4256d7ad2a30a 100644 (file)
@@ -21,7 +21,7 @@ struct hda_jack_callback;
 typedef void (*hda_jack_callback_fn) (struct hda_codec *, struct hda_jack_callback *);
 
 struct hda_jack_callback {
-       struct hda_jack_tbl *tbl;
+       hda_nid_t nid;
        hda_jack_callback_fn func;
        unsigned int private_data;      /* arbitrary data */
        struct hda_jack_callback *next;
index 4ef2259f88cae3b1cf328880447dbf528ad42a95..9ceb2bc36e68026bd02dfca8bdca4f9ffab2e849 100644 (file)
@@ -4427,13 +4427,16 @@ static void ca0132_process_dsp_response(struct hda_codec *codec,
 static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 {
        struct ca0132_spec *spec = codec->spec;
+       struct hda_jack_tbl *tbl;
 
        /* Delay enabling the HP amp, to let the mic-detection
         * state machine run.
         */
        cancel_delayed_work_sync(&spec->unsol_hp_work);
        schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
-       cb->tbl->block_report = 1;
+       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+       if (tbl)
+               tbl->block_report = 1;
 }
 
 static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
index a12ae8ac091451261a2ba613543677fabedb8cd0..c1c855a6c0af8199d03b04419d16d3494507ddeb 100644 (file)
@@ -614,6 +614,7 @@ enum {
        CS4208_MAC_AUTO,
        CS4208_MBA6,
        CS4208_MBP11,
+       CS4208_MACMINI,
        CS4208_GPIO0,
 };
 
@@ -621,6 +622,7 @@ static const struct hda_model_fixup cs4208_models[] = {
        { .id = CS4208_GPIO0, .name = "gpio0" },
        { .id = CS4208_MBA6, .name = "mba6" },
        { .id = CS4208_MBP11, .name = "mbp11" },
+       { .id = CS4208_MACMINI, .name = "macmini" },
        {}
 };
 
@@ -632,6 +634,7 @@ static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
 /* codec SSID matching */
 static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
+       SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
        SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
        SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
        SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
@@ -666,6 +669,24 @@ static void cs4208_fixup_mac(struct hda_codec *codec,
        snd_hda_apply_fixup(codec, action);
 }
 
+/* MacMini 7,1 has the inverted jack detection */
+static void cs4208_fixup_macmini(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
+               { 0x21, 0x004be140 }, /* SPDIF: disable detect */
+               { }
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* HP pin (0x10) has an inverted detection */
+               codec->inv_jack_detect = 1;
+               /* disable the bogus Mic and SPDIF jack detections */
+               snd_hda_apply_pincfgs(codec, pincfgs);
+       }
+}
+
 static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
@@ -709,6 +730,12 @@ static const struct hda_fixup cs4208_fixups[] = {
                .chained = true,
                .chain_id = CS4208_GPIO0,
        },
+       [CS4208_MACMINI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_macmini,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
        [CS4208_GPIO0] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = cs4208_fixup_gpio0,
index 1f52b55d77c92d7114ca375d79a43e8f798cc580..bcbc4ee10130a5ee86de2c23815eb85ec8684459 100644 (file)
@@ -448,7 +448,8 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
        eld = &per_pin->sink_eld;
 
        mutex_lock(&per_pin->lock);
-       if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
+       if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
+           eld->eld_size > ELD_MAX_SIZE) {
                mutex_unlock(&per_pin->lock);
                snd_BUG();
                return -EINVAL;
@@ -1193,7 +1194,7 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
 static void jack_callback(struct hda_codec *codec,
                          struct hda_jack_callback *jack)
 {
-       check_presence_and_report(codec, jack->tbl->nid);
+       check_presence_and_report(codec, jack->nid);
 }
 
 static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -2476,13 +2477,6 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                        is_broxton(codec))
                codec->core.link_power_control = 1;
 
-       if (codec_has_acomp(codec)) {
-               codec->depop_delay = 0;
-               spec->i915_audio_ops.audio_ptr = codec;
-               spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
-               snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
-       }
-
        if (hdmi_parse_codec(codec) < 0) {
                if (spec->i915_bound)
                        snd_hdac_i915_exit(&codec->bus->core);
@@ -2504,6 +2498,18 @@ static int patch_generic_hdmi(struct hda_codec *codec)
 
        init_channel_allocations();
 
+       if (codec_has_acomp(codec)) {
+               codec->depop_delay = 0;
+               spec->i915_audio_ops.audio_ptr = codec;
+               /* intel_audio_codec_enable() or intel_audio_codec_disable()
+                * will call pin_eld_notify with using audio_ptr pointer
+                * We need make sure audio_ptr is really setup
+                */
+               wmb();
+               spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
+               snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
+       }
+
        return 0;
 }
 
index 33753244f48fe98de3a57709de2793abb74f2ae0..93d2156b62410935f3c0f945f0d5d8a2fe182eba 100644 (file)
@@ -282,7 +282,7 @@ static void alc_update_knob_master(struct hda_codec *codec,
        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
        if (!uctl)
                return;
-       val = snd_hda_codec_read(codec, jack->tbl->nid, 0,
+       val = snd_hda_codec_read(codec, jack->nid, 0,
                                 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
        val &= HDA_AMP_VOLMASK;
        uctl->value.integer.value[0] = val;
@@ -327,6 +327,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
        case 0x10ec0292:
                alc_update_coef_idx(codec, 0x4, 1<<15, 0);
                break;
+       case 0x10ec0225:
        case 0x10ec0233:
        case 0x10ec0255:
        case 0x10ec0256:
@@ -900,6 +901,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
        { 0x10ec0899, 0x1028, 0, "ALC3861" },
        { 0x10ec0298, 0x1028, 0, "ALC3266" },
        { 0x10ec0256, 0x1028, 0, "ALC3246" },
+       { 0x10ec0225, 0x1028, 0, "ALC3253" },
        { 0x10ec0670, 0x1025, 0, "ALC669X" },
        { 0x10ec0676, 0x1025, 0, "ALC679X" },
        { 0x10ec0282, 0x1043, 0, "ALC3229" },
@@ -1785,7 +1787,6 @@ enum {
        ALC882_FIXUP_NO_PRIMARY_HP,
        ALC887_FIXUP_ASUS_BASS,
        ALC887_FIXUP_BASS_CHMAP,
-       ALC882_FIXUP_DISABLE_AAMIX,
 };
 
 static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1947,8 +1948,6 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
 
 static void alc_fixup_bass_chmap(struct hda_codec *codec,
                                 const struct hda_fixup *fix, int action);
-static void alc_fixup_disable_aamix(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action);
 
 static const struct hda_fixup alc882_fixups[] = {
        [ALC882_FIXUP_ABIT_AW9D_MAX] = {
@@ -2186,10 +2185,6 @@ static const struct hda_fixup alc882_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_bass_chmap,
        },
-       [ALC882_FIXUP_DISABLE_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-       },
 };
 
 static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2228,6 +2223,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
        SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
        SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
+       SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
 
        /* All Apple entries are in codec SSIDs */
        SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
@@ -2257,7 +2253,6 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
        SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1458, 0xa182, "Gigabyte Z170X-UD3", ALC882_FIXUP_DISABLE_AAMIX),
        SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
        SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -2651,6 +2646,7 @@ enum {
        ALC269_TYPE_ALC298,
        ALC269_TYPE_ALC255,
        ALC269_TYPE_ALC256,
+       ALC269_TYPE_ALC225,
 };
 
 /*
@@ -2680,6 +2676,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        case ALC269_TYPE_ALC298:
        case ALC269_TYPE_ALC255:
        case ALC269_TYPE_ALC256:
+       case ALC269_TYPE_ALC225:
                ssids = alc269_ssids;
                break;
        default:
@@ -3658,6 +3655,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                WRITE_COEF(0xb7, 0x802b),
                {}
        };
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x4a, 1<<8, 0),
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+               UPDATE_COEF(0x63, 3<<14, 3<<14),
+               UPDATE_COEF(0x4a, 3<<4, 2<<4),
+               UPDATE_COEF(0x4a, 3<<10, 3<<10),
+               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+               UPDATE_COEF(0x4a, 3<<10, 0),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3682,6 +3689,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
        case 0x10ec0668:
                alc_process_coef_fw(codec, coef0668);
                break;
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               break;
        }
        codec_dbg(codec, "Headset jack set to unplugged mode.\n");
 }
@@ -3727,6 +3737,13 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                UPDATE_COEF(0xc3, 0, 1<<12),
                {}
        };
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
+               UPDATE_COEF(0x4a, 3<<4, 2<<4),
+               UPDATE_COEF(0x63, 3<<14, 0),
+               {}
+       };
+
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3772,12 +3789,22 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                alc_process_coef_fw(codec, coef0688);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
                break;
+       case 0x10ec0225:
+               alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0225);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
        }
        codec_dbg(codec, "Headset jack set to mic-in mode.\n");
 }
 
 static void alc_headset_mode_default(struct hda_codec *codec)
 {
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+               {}
+       };
        static struct coef_fw coef0255[] = {
                WRITE_COEF(0x45, 0xc089),
                WRITE_COEF(0x45, 0xc489),
@@ -3819,6 +3846,9 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        };
 
        switch (codec->core.vendor_id) {
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               break;
        case 0x10ec0255:
        case 0x10ec0256:
                alc_process_coef_fw(codec, coef0255);
@@ -3884,6 +3914,13 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                WRITE_COEF(0xc3, 0x0000),
                {}
        };
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+               UPDATE_COEF(0x49, 1<<8, 1<<8),
+               UPDATE_COEF(0x4a, 7<<6, 7<<6),
+               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3912,6 +3949,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
        case 0x10ec0668:
                alc_process_coef_fw(codec, coef0688);
                break;
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               break;
        }
        codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
 }
@@ -3955,6 +3995,13 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
                WRITE_COEF(0xc3, 0x0000),
                {}
        };
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
+               UPDATE_COEF(0x49, 1<<8, 1<<8),
+               UPDATE_COEF(0x4a, 7<<6, 7<<6),
+               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -3983,6 +4030,9 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
        case 0x10ec0668:
                alc_process_coef_fw(codec, coef0688);
                break;
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               break;
        }
        codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
 }
@@ -4014,6 +4064,11 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                WRITE_COEF(0xc3, 0x0c00),
                {}
        };
+       static struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+               UPDATE_COEF(0x49, 1<<8, 1<<8),
+               {}
+       };
 
        switch (codec->core.vendor_id) {
        case 0x10ec0255:
@@ -4058,6 +4113,12 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                val = alc_read_coef_idx(codec, 0xbe);
                is_ctia = (val & 0x1c02) == 0x1c02;
                break;
+       case 0x10ec0225:
+               alc_process_coef_fw(codec, coef0225);
+               msleep(800);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x00f0) == 0x00f0;
+               break;
        }
 
        codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
@@ -4695,6 +4756,9 @@ enum {
        ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
        ALC293_FIXUP_LENOVO_SPK_NOISE,
        ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
+       ALC255_FIXUP_DELL_SPK_NOISE,
+       ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC280_FIXUP_HP_HEADSET_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5314,6 +5378,29 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
        },
+       [ALC255_FIXUP_DELL_SPK_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC225_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Disable pass-through path for FRONT 14h */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC280_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5325,6 +5412,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
+       SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
        SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
        SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
        SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
@@ -5356,6 +5444,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
        SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
        SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5416,6 +5505,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5560,6 +5650,9 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
        {}
 };
+#define ALC225_STANDARD_PINS \
+       {0x12, 0xb7a60130}, \
+       {0x21, 0x04211020}
 
 #define ALC256_STANDARD_PINS \
        {0x12, 0x90a60140}, \
@@ -5581,6 +5674,12 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {0x21, 0x03211020}
 
 static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x14, 0x901701a0}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x14, 0x901701b0}),
        SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
                {0x14, 0x90170110},
                {0x21, 0x02211020}),
@@ -5906,6 +6005,9 @@ static int patch_alc269(struct hda_codec *codec)
                spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
                alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
                break;
+       case 0x10ec0225:
+               spec->codec_variant = ALC269_TYPE_ALC225;
+               break;
        }
 
        if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
@@ -6796,6 +6898,7 @@ static int patch_alc680(struct hda_codec *codec)
  */
 static const struct hda_device_id snd_hda_id_realtek[] = {
        HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
index 2c7c5eb8b1e9514779b78bc278412803862062e9..37b70f8e878f715968c7496e01eeb493f8a2b7a4 100644 (file)
@@ -493,9 +493,9 @@ static void jack_update_power(struct hda_codec *codec,
        if (!spec->num_pwrs)
                return;
 
-       if (jack && jack->tbl->nid) {
-               stac_toggle_power_map(codec, jack->tbl->nid,
-                                     snd_hda_jack_detect(codec, jack->tbl->nid),
+       if (jack && jack->nid) {
+               stac_toggle_power_map(codec, jack->nid,
+                                     snd_hda_jack_detect(codec, jack->nid),
                                      true);
                return;
        }
index 2875b4f6d8c9e6a792638547d4b6850fa620a857..7c8941b8b2defd9b21b8159f1cef333659ce423d 100644 (file)
@@ -2879,7 +2879,7 @@ static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
 {
        struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
 
-       ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp);
+       ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp);
        return 0;
 }
 
@@ -2891,7 +2891,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
 
        if (!snd_hdsp_use_is_exclusive(hdsp))
                return -EBUSY;
-       val = ucontrol->value.enumerated.item[0];
+       val = ucontrol->value.integer.value[0];
        spin_lock_irq(&hdsp->lock);
        if (val != hdsp_dds_offset(hdsp))
                change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
index 8bc8016c173d6a6005e33222df1381272bb7819e..a4a999a0317eaefc30eeb2265fd38b784c4afd8a 100644 (file)
@@ -1601,6 +1601,9 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate)
 {
        u64 n;
 
+       if (snd_BUG_ON(rate <= 0))
+               return;
+
        if (rate >= 112000)
                rate /= 4;
        else if (rate >= 56000)
@@ -2215,6 +2218,8 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
                } else {
                        /* slave mode, return external sample rate */
                        rate = hdspm_external_sample_rate(hdspm);
+                       if (!rate)
+                               rate = hdspm->system_sample_rate;
                }
        }
 
@@ -2260,8 +2265,11 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
                                            ucontrol)
 {
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
+       int rate = ucontrol->value.integer.value[0];
 
-       hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]);
+       if (rate < 27000 || rate > 207000)
+               return -EINVAL;
+       hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]);
        return 0;
 }
 
@@ -4449,7 +4457,7 @@ static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol,
 {
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-       ucontrol->value.enumerated.item[0] = hdspm->tco->term;
+       ucontrol->value.integer.value[0] = hdspm->tco->term;
 
        return 0;
 }
@@ -4460,8 +4468,8 @@ static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol,
 {
        struct hdspm *hdspm = snd_kcontrol_chip(kcontrol);
 
-       if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) {
-               hdspm->tco->term = ucontrol->value.enumerated.item[0];
+       if (hdspm->tco->term != ucontrol->value.integer.value[0]) {
+               hdspm->tco->term = ucontrol->value.integer.value[0];
 
                hdspm_tco_write(hdspm);
 
index 3191e0a7d273213515ccd3e049e66c4f6ddc5f67..d1fb035f44db8fd7026d97e1148f0c09eb4d1679 100644 (file)
@@ -635,6 +635,7 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
                                            SNDRV_PCM_HW_PARAM_PERIODS);
        if (ret < 0) {
                dev_err(prtd->platform->dev, "set integer constraint failed\n");
+               kfree(adata);
                return ret;
        }
 
index 33143fe1de0bdeaa0c6b04bc9bfd159b49bf658b..91785318b2834f325b2ebfb55476ce591b5e377b 100644 (file)
@@ -1929,6 +1929,25 @@ static struct {
        { 1000000, 13500000, 0,  1 },
 };
 
+static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
+       13500000,
+        6144000,
+        6144000,
+        3072000,
+        3072000,
+        2822400,
+        2822400,
+        1536000,
+        1536000,
+        1536000,
+        1536000,
+        1536000,
+        1536000,
+        1536000,
+        1536000,
+         768000,
+};
+
 static struct {
        unsigned int min;
        unsigned int max;
@@ -2042,16 +2061,32 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
        /* Adjust FRATIO/refdiv to avoid integer mode if possible */
        refdiv = cfg->refdiv;
 
+       arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
+                       init_ratio, Fref, refdiv);
+
        while (div <= ARIZONA_FLL_MAX_REFDIV) {
                for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO;
                     ratio++) {
                        if ((ARIZONA_FLL_VCO_CORNER / 2) /
-                           (fll->vco_mult * ratio) < Fref)
+                           (fll->vco_mult * ratio) < Fref) {
+                               arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
                                break;
+                       }
+
+                       if (Fref > pseudo_fref_max[ratio - 1]) {
+                               arizona_fll_dbg(fll,
+                                       "pseudo: exceeded max fref(%u) for ratio=%u\n",
+                                       pseudo_fref_max[ratio - 1],
+                                       ratio);
+                               break;
+                       }
 
                        if (target % (ratio * Fref)) {
                                cfg->refdiv = refdiv;
                                cfg->fratio = ratio - 1;
+                               arizona_fll_dbg(fll,
+                                       "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+                                       Fref, refdiv, div, ratio);
                                return ratio;
                        }
                }
@@ -2060,6 +2095,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
                        if (target % (ratio * Fref)) {
                                cfg->refdiv = refdiv;
                                cfg->fratio = ratio - 1;
+                               arizona_fll_dbg(fll,
+                                       "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
+                                       Fref, refdiv, div, ratio);
                                return ratio;
                        }
                }
@@ -2068,6 +2106,9 @@ static int arizona_calc_fratio(struct arizona_fll *fll,
                Fref /= 2;
                refdiv++;
                init_ratio = arizona_find_fratio(Fref, NULL);
+               arizona_fll_dbg(fll,
+                               "pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
+                               Fref, refdiv, div, init_ratio);
        }
 
        arizona_fll_warn(fll, "Falling back to integer mode operation\n");
index bc08f0c5a5f69fe4a184ac86e611e4df56eabb5c..1bd31644a782eac26042fccf47bfbc65e380b63f 100644 (file)
@@ -266,6 +266,8 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
                } else {
                        *mic = false;
                        regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
+                       regmap_update_bits(rt286->regmap,
+                               RT286_CBJ_CTRL1, 0x0400, 0x0000);
                }
        } else {
                regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -470,24 +472,6 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int rt286_vref_event(struct snd_soc_dapm_widget *w,
-                            struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_update_bits(codec,
-                       RT286_CBJ_CTRL1, 0x0400, 0x0000);
-               mdelay(50);
-               break;
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
@@ -536,7 +520,7 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
                12, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
-               0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
+               0, 1, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
                2, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
@@ -910,8 +894,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_ON:
                mdelay(10);
-               snd_soc_update_bits(codec,
-                       RT286_CBJ_CTRL1, 0x0400, 0x0400);
                snd_soc_update_bits(codec,
                        RT286_DC_GAIN, 0x200, 0x0);
 
@@ -920,8 +902,6 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
        case SND_SOC_BIAS_STANDBY:
                snd_soc_write(codec,
                        RT286_SET_AUDIO_POWER, AC_PWRST_D3);
-               snd_soc_update_bits(codec,
-                       RT286_CBJ_CTRL1, 0x0400, 0x0000);
                break;
 
        default:
index c61d38b585fb06de6b6ca0f41370c3b78c10113c..93e8c9017633f97ed264cd9e54c4aaab606d54f3 100644 (file)
@@ -776,7 +776,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 
        /* IN1/IN2 Control */
        SOC_SINGLE_TLV("IN1 Boost", RT5645_IN1_CTRL1,
-               RT5645_BST_SFT1, 8, 0, bst_tlv),
+               RT5645_BST_SFT1, 12, 0, bst_tlv),
        SOC_SINGLE_TLV("IN2 Boost", RT5645_IN2_CTRL,
                RT5645_BST_SFT2, 8, 0, bst_tlv),
 
index 820d8fa62b5e5682fcdf52c823fa70f2f8b27631..fb8ea05c0de1d9ddb60134f68c1dc3b180a39c29 100644 (file)
@@ -3985,7 +3985,6 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
        if (rt5659 == NULL)
                return -ENOMEM;
 
-       rt5659->i2c = i2c;
        i2c_set_clientdata(i2c, rt5659);
 
        if (pdata)
@@ -4157,24 +4156,17 @@ static int rt5659_i2c_probe(struct i2c_client *i2c,
 
        INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work);
 
-       if (rt5659->i2c->irq) {
-               ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+       if (i2c->irq) {
+               ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+                       rt5659_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
                        | IRQF_ONESHOT, "rt5659", rt5659);
                if (ret)
                        dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
 
        }
 
-       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659,
                        rt5659_dai, ARRAY_SIZE(rt5659_dai));
-
-       if (ret) {
-               if (rt5659->i2c->irq)
-                       free_irq(rt5659->i2c->irq, rt5659);
-       }
-
-       return 0;
 }
 
 static int rt5659_i2c_remove(struct i2c_client *i2c)
@@ -4191,24 +4183,29 @@ void rt5659_i2c_shutdown(struct i2c_client *client)
        regmap_write(rt5659->regmap, RT5659_RESET, 0);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id rt5659_of_match[] = {
        { .compatible = "realtek,rt5658", },
        { .compatible = "realtek,rt5659", },
-       {},
+       { },
 };
+MODULE_DEVICE_TABLE(of, rt5659_of_match);
+#endif
 
+#ifdef CONFIG_ACPI
 static struct acpi_device_id rt5659_acpi_match[] = {
-               { "10EC5658", 0},
-               { "10EC5659", 0},
-               { },
+       { "10EC5658", 0, },
+       { "10EC5659", 0, },
+       { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
+#endif
 
 struct i2c_driver rt5659_i2c_driver = {
        .driver = {
                .name = "rt5659",
                .owner = THIS_MODULE,
-               .of_match_table = rt5659_of_match,
+               .of_match_table = of_match_ptr(rt5659_of_match),
                .acpi_match_table = ACPI_PTR(rt5659_acpi_match),
        },
        .probe = rt5659_i2c_probe,
index 8f07ee903eaadf29a769f71b9c219cf9ac5bb3b6..d31c9e5bcec8adf93731532b1ef036da70ac959c 100644 (file)
@@ -1792,7 +1792,6 @@ struct rt5659_priv {
        struct snd_soc_codec *codec;
        struct rt5659_platform_data pdata;
        struct regmap *regmap;
-       struct i2c_client *i2c;
        struct gpio_desc *gpiod_ldo1_en;
        struct gpio_desc *gpiod_reset;
        struct snd_soc_jack *hs_jack;
index 21ca3a5e9f6603299f15a9bd5da3b64fa93e0f95..d374c18d4db7f9939fbdc3a5891bbdcb4cbe9e76 100644 (file)
@@ -31,7 +31,10 @@ static int sigmadsp_write_i2c(void *control_data,
 
        kfree(buf);
 
-       return ret;
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 static int sigmadsp_read_i2c(void *control_data,
index 6088d30962a953cab19ee561ee288cca142dfccf..97c0f1e2388637dcdc686da1f1a5cf06037a6944 100644 (file)
@@ -2382,6 +2382,7 @@ error:
 
 static int wm5110_remove(struct platform_device *pdev)
 {
+       snd_soc_unregister_platform(&pdev->dev);
        snd_soc_unregister_codec(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
index ff237726775a16a4e66b8b104aaa878d9f187dab..d7f444f874604d7d8a6df4a05aa634fe5448fdfd 100644 (file)
@@ -240,13 +240,13 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
        7, 1, 1),
 
-SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
               WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
               WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
               WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv),
-SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
               WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv),
 SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume",
                WM8960_RINPATH, 4, 3, 0, micboost_tlv),
@@ -643,29 +643,31 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       /* check if the sysclk frequency is available. */
-       for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
-               if (sysclk_divs[i] == -1)
-                       continue;
-               sysclk = freq_out / sysclk_divs[i];
-               for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
-                       if (sysclk == dac_divs[j] * lrclk) {
+       if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
+               /* check if the sysclk frequency is available. */
+               for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+                       if (sysclk_divs[i] == -1)
+                               continue;
+                       sysclk = freq_out / sysclk_divs[i];
+                       for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+                               if (sysclk != dac_divs[j] * lrclk)
+                                       continue;
                                for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
                                        if (sysclk == bclk * bclk_divs[k] / 10)
                                                break;
                                if (k != ARRAY_SIZE(bclk_divs))
                                        break;
                        }
+                       if (j != ARRAY_SIZE(dac_divs))
+                               break;
                }
-               if (j != ARRAY_SIZE(dac_divs))
-                       break;
-       }
 
-       if (i != ARRAY_SIZE(sysclk_divs)) {
-               goto configure_clock;
-       } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
-               dev_err(codec->dev, "failed to configure clock\n");
-               return -EINVAL;
+               if (i != ARRAY_SIZE(sysclk_divs)) {
+                       goto configure_clock;
+               } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+                       dev_err(codec->dev, "failed to configure clock\n");
+                       return -EINVAL;
+               }
        }
        /* get a available pll out frequency and set pll */
        for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
index ce664c239be32fda4d269aea1722bb14631e3b22..bff258d7bcea1f380403df5b9380ac7c9aabf835 100644 (file)
@@ -645,6 +645,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
        dev->dev = &pdev->dev;
 
+       dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
+       dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
        if (pdata) {
                dev->capability = pdata->cap;
                clk_id = NULL;
@@ -652,9 +654,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
                if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) {
                        dev->i2s_reg_comp1 = pdata->i2s_reg_comp1;
                        dev->i2s_reg_comp2 = pdata->i2s_reg_comp2;
-               } else {
-                       dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
-                       dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
                }
                ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
        } else {
index 40dfd8a3648408a2cc76bb6e4c4c3872c8e28ac3..ed8de1035cda159d0d186f2cded0fb7a97fbceb4 100644 (file)
@@ -112,20 +112,6 @@ struct fsl_ssi_rxtx_reg_val {
        struct fsl_ssi_reg_val tx;
 };
 
-static const struct reg_default fsl_ssi_reg_defaults[] = {
-       {CCSR_SSI_SCR,     0x00000000},
-       {CCSR_SSI_SIER,    0x00003003},
-       {CCSR_SSI_STCR,    0x00000200},
-       {CCSR_SSI_SRCR,    0x00000200},
-       {CCSR_SSI_STCCR,   0x00040000},
-       {CCSR_SSI_SRCCR,   0x00040000},
-       {CCSR_SSI_SACNT,   0x00000000},
-       {CCSR_SSI_STMSK,   0x00000000},
-       {CCSR_SSI_SRMSK,   0x00000000},
-       {CCSR_SSI_SACCEN,  0x00000000},
-       {CCSR_SSI_SACCDIS, 0x00000000},
-};
-
 static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -190,8 +176,7 @@ static const struct regmap_config fsl_ssi_regconfig = {
        .val_bits = 32,
        .reg_stride = 4,
        .val_format_endian = REGMAP_ENDIAN_NATIVE,
-       .reg_defaults = fsl_ssi_reg_defaults,
-       .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults),
+       .num_reg_defaults_raw = CCSR_SSI_SACCDIS / sizeof(uint32_t) + 1,
        .readable_reg = fsl_ssi_readable_reg,
        .volatile_reg = fsl_ssi_volatile_reg,
        .precious_reg = fsl_ssi_precious_reg,
@@ -201,6 +186,7 @@ static const struct regmap_config fsl_ssi_regconfig = {
 
 struct fsl_ssi_soc_data {
        bool imx;
+       bool imx21regs; /* imx21-class SSI - no SACC{ST,EN,DIS} regs */
        bool offline_config;
        u32 sisr_write_mask;
 };
@@ -303,6 +289,7 @@ static struct fsl_ssi_soc_data fsl_ssi_mpc8610 = {
 
 static struct fsl_ssi_soc_data fsl_ssi_imx21 = {
        .imx = true,
+       .imx21regs = true,
        .offline_config = true,
        .sisr_write_mask = 0,
 };
@@ -586,8 +573,12 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
         */
        regmap_write(regs, CCSR_SSI_SACNT,
                        CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV);
-       regmap_write(regs, CCSR_SSI_SACCDIS, 0xff);
-       regmap_write(regs, CCSR_SSI_SACCEN, 0x300);
+
+       /* no SACC{ST,EN,DIS} regs on imx21-class SSI */
+       if (!ssi_private->soc->imx21regs) {
+               regmap_write(regs, CCSR_SSI_SACCDIS, 0xff);
+               regmap_write(regs, CCSR_SSI_SACCEN, 0x300);
+       }
 
        /*
         * Enable SSI, Transmit and Receive. AC97 has to communicate with the
@@ -1397,6 +1388,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *iomem;
        char name[64];
+       struct regmap_config regconfig = fsl_ssi_regconfig;
 
        of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
        if (!of_id || !of_id->data)
@@ -1444,15 +1436,25 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                return PTR_ERR(iomem);
        ssi_private->ssi_phys = res->start;
 
+       if (ssi_private->soc->imx21regs) {
+               /*
+                * According to datasheet imx21-class SSI
+                * don't have SACC{ST,EN,DIS} regs.
+                */
+               regconfig.max_register = CCSR_SSI_SRMSK;
+               regconfig.num_reg_defaults_raw =
+                       CCSR_SSI_SRMSK / sizeof(uint32_t) + 1;
+       }
+
        ret = of_property_match_string(np, "clock-names", "ipg");
        if (ret < 0) {
                ssi_private->has_ipg_clk_name = false;
                ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
-                       &fsl_ssi_regconfig);
+                       &regconfig);
        } else {
                ssi_private->has_ipg_clk_name = true;
                ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
-                       "ipg", iomem, &fsl_ssi_regconfig);
+                       "ipg", iomem, &regconfig);
        }
        if (IS_ERR(ssi_private->regs)) {
                dev_err(&pdev->dev, "Failed to init register map\n");
index a407e833c612523e90c07a732e9cc472b64252ee..fb896b2c9ba32a058eb097d97e7bd8732667ca47 100644 (file)
@@ -72,8 +72,6 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
                goto end;
        }
 
-       platform_set_drvdata(pdev, data);
-
 end:
        of_node_put(spdif_np);
 
index 1ded8811598ef4b05333e7b8e2204f72f0b8e142..2389ab47e25f68265c720ba3f4c4b52e5c321e59 100644 (file)
@@ -99,7 +99,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
                if (ret && ret != -ENOTSUPP)
                        goto err;
        }
-
+       return 0;
 err:
        return ret;
 }
index 803f95e40679def6a185c3131f838b210914b6c2..7d7c872c280dbd62b0b1b66209e1e1cfe75791ee 100644 (file)
@@ -30,11 +30,15 @@ config SND_SST_IPC_ACPI
 config SND_SOC_INTEL_SST
        tristate
        select SND_SOC_INTEL_SST_ACPI if ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
        depends on (X86 || COMPILE_TEST)
 
 config SND_SOC_INTEL_SST_ACPI
        tristate
 
+config SND_SOC_INTEL_SST_MATCH
+       tristate
+
 config SND_SOC_INTEL_HASWELL
        tristate
 
@@ -57,7 +61,7 @@ config SND_SOC_INTEL_HASWELL_MACH
 config SND_SOC_INTEL_BYT_RT5640_MACH
        tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
        depends on X86_INTEL_LPSS && I2C
-       depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n)
+       depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n)
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_BAYTRAIL
        select SND_SOC_RT5640
@@ -69,7 +73,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH
 config SND_SOC_INTEL_BYT_MAX98090_MACH
        tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
        depends on X86_INTEL_LPSS && I2C
-       depends on DW_DMAC_CORE=y
+       depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n)
        select SND_SOC_INTEL_SST
        select SND_SOC_INTEL_BAYTRAIL
        select SND_SOC_MAX98090
@@ -97,6 +101,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
        select SND_SOC_RT5640
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
        help
           This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
           platforms with RT5640 audio codec.
@@ -109,6 +114,7 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH
        select SND_SOC_RT5651
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
        help
           This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR
           platforms with RT5651 audio codec.
@@ -121,6 +127,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
         select SND_SOC_RT5670
         select SND_SST_MFLD_PLATFORM
         select SND_SST_IPC_ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
         help
           This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
           platforms with RT5672 audio codec.
@@ -133,6 +140,7 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH
        select SND_SOC_RT5645
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
        help
          This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
          platforms with RT5645/5650 audio codec.
@@ -145,6 +153,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH
        select SND_SOC_TS3A227E
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
+       select SND_SOC_INTEL_SST_MATCH if ACPI
        help
       This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
       platforms with MAX98090 audio codec it also can support TI jack chip as aux device.
index 55c33dc76ce44e2bd3d24de843ff552bb9bfaa30..52ed434cbca6a9e0a08ebc64bb8ee84111f479d9 100644 (file)
@@ -528,6 +528,7 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
        .ops = &sst_compr_dai_ops,
        .playback = {
                .stream_name = "Compress Playback",
+               .channels_min = 1,
        },
 },
 /* BE CPU  Dais */
index 7396ddb427d8f95a3491d144f597fcb9f2e382d3..2cbcbe4126611d0d1660d86279329da5bec504b1 100644 (file)
@@ -212,7 +212,10 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
 {
        struct snd_interval *channels = hw_param_interval(params,
                                                SNDRV_PCM_HW_PARAM_CHANNELS);
-       channels->min = channels->max = 4;
+       if (params_channels(params) == 2)
+               channels->min = channels->max = 2;
+       else
+               channels->min = channels->max = 4;
 
        return 0;
 }
index 668fdeee195e2f0343047c41b0b5210d5bdc4c07..fbbb25c2ceed2949bd909f4b2e2e152154493227 100644 (file)
@@ -1,13 +1,10 @@
 snd-soc-sst-dsp-objs := sst-dsp.o
-ifneq ($(CONFIG_SND_SST_IPC_ACPI),)
-snd-soc-sst-acpi-objs := sst-match-acpi.o
-else
-snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o
-endif
-
+snd-soc-sst-acpi-objs := sst-acpi.o
+snd-soc-sst-match-objs := sst-match-acpi.o
 snd-soc-sst-ipc-objs := sst-ipc.o
 
 snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o
 
 obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
 obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
+obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o
index 7a85c576dad33575efed4ca9eabb1ccf64970383..2c5eda14d51070947accc019b5d212e9adf0e6e3 100644 (file)
@@ -215,6 +215,7 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
        .dma_size = SST_LPT_DSP_DMA_SIZE,
 };
 
+#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
 static struct sst_acpi_mach baytrail_machines[] = {
        { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
        { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL },
@@ -231,11 +232,14 @@ static struct sst_acpi_desc sst_acpi_baytrail_desc = {
        .sst_id = SST_DEV_ID_BYT,
        .resindex_dma_base = -1,
 };
+#endif
 
 static const struct acpi_device_id sst_acpi_match[] = {
        { "INT33C8", (unsigned long)&sst_acpi_haswell_desc },
        { "INT3438", (unsigned long)&sst_acpi_broadwell_desc },
+#if !IS_ENABLED(CONFIG_SND_SST_IPC_ACPI)
        { "80860F28", (unsigned long)&sst_acpi_baytrail_desc },
+#endif
        { }
 };
 MODULE_DEVICE_TABLE(acpi, sst_acpi_match);
index dd077e116d259b6b60f509f2b3cc10b020a2cb12..3b4539d21492484ac2ba15cec78a36f4e135aee6 100644 (file)
@@ -41,3 +41,6 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines)
        return NULL;
 }
 EXPORT_SYMBOL_GPL(sst_acpi_find_machine);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
index de6dac496a0d8b611d4662864597e58ee20330f3..4629372d7c8e0b728c9ec0467ae34208532fa48b 100644 (file)
@@ -688,14 +688,14 @@ int skl_unbind_modules(struct skl_sst *ctx,
        /* get src queue index */
        src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max);
        if (src_index < 0)
-               return -EINVAL;
+               return 0;
 
        msg.src_queue = src_index;
 
        /* get dst queue index */
        dst_index  = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max);
        if (dst_index < 0)
-               return -EINVAL;
+               return 0;
 
        msg.dst_queue = dst_index;
 
@@ -747,7 +747,7 @@ int skl_bind_modules(struct skl_sst *ctx,
 
        skl_dump_bind_info(ctx, src_mcfg, dst_mcfg);
 
-       if (src_mcfg->m_state < SKL_MODULE_INIT_DONE &&
+       if (src_mcfg->m_state < SKL_MODULE_INIT_DONE ||
                dst_mcfg->m_state < SKL_MODULE_INIT_DONE)
                return 0;
 
index f3553258091a2bd7a78f2485aaee7c46fc667758..b6e6b61d10ec22349650ee5c1db3074068a180e4 100644 (file)
@@ -863,6 +863,7 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus,
                else
                        delay += hstream->bufsize;
        }
+       delay = (hstream->bufsize == delay) ? 0 : delay;
 
        if (delay >= hstream->period_bytes) {
                dev_info(bus->dev,
index 4624556f486de34c396a327a0d279a57a1fdbf96..a294fee431f07363f965a81b4c9ef42eb3a42f58 100644 (file)
@@ -54,12 +54,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w)
 
 /*
  * Each pipelines needs memory to be allocated. Check if we have free memory
- * from available pool. Then only add this to pool
- * This is freed when pipe is deleted
- * Note: DSP does actual memory management we only keep track for complete
- * pool
+ * from available pool.
  */
-static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
+static bool skl_is_pipe_mem_avail(struct skl *skl,
                                struct skl_module_cfg *mconfig)
 {
        struct skl_sst *ctx = skl->skl_sst;
@@ -74,10 +71,20 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
                                "exceeds ppl memory available %d mem %d\n",
                                skl->resource.max_mem, skl->resource.mem);
                return false;
+       } else {
+               return true;
        }
+}
 
+/*
+ * Add the mem to the mem pool. This is freed when pipe is deleted.
+ * Note: DSP does actual memory management we only keep track for complete
+ * pool
+ */
+static void skl_tplg_alloc_pipe_mem(struct skl *skl,
+                               struct skl_module_cfg *mconfig)
+{
        skl->resource.mem += mconfig->pipe->memory_pages;
-       return true;
 }
 
 /*
@@ -85,10 +92,10 @@ static bool skl_tplg_alloc_pipe_mem(struct skl *skl,
  * quantified in MCPS (Million Clocks Per Second) required for module/pipe
  *
  * Each pipelines needs mcps to be allocated. Check if we have mcps for this
- * pipe. This adds the mcps to driver counter
- * This is removed on pipeline delete
+ * pipe.
  */
-static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
+
+static bool skl_is_pipe_mcps_avail(struct skl *skl,
                                struct skl_module_cfg *mconfig)
 {
        struct skl_sst *ctx = skl->skl_sst;
@@ -98,13 +105,18 @@ static bool skl_tplg_alloc_pipe_mcps(struct skl *skl,
                        "%s: module_id %d instance %d\n", __func__,
                        mconfig->id.module_id, mconfig->id.instance_id);
                dev_err(ctx->dev,
-                       "exceeds ppl memory available %d > mem %d\n",
+                       "exceeds ppl mcps available %d > mem %d\n",
                        skl->resource.max_mcps, skl->resource.mcps);
                return false;
+       } else {
+               return true;
        }
+}
 
+static void skl_tplg_alloc_pipe_mcps(struct skl *skl,
+                               struct skl_module_cfg *mconfig)
+{
        skl->resource.mcps += mconfig->mcps;
-       return true;
 }
 
 /*
@@ -411,7 +423,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                mconfig = w->priv;
 
                /* check resource available */
-               if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+               if (!skl_is_pipe_mcps_avail(skl, mconfig))
                        return -ENOMEM;
 
                if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) {
@@ -435,6 +447,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe)
                ret = skl_tplg_set_module_params(w, ctx);
                if (ret < 0)
                        return ret;
+               skl_tplg_alloc_pipe_mcps(skl, mconfig);
        }
 
        return 0;
@@ -477,10 +490,10 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
        struct skl_sst *ctx = skl->skl_sst;
 
        /* check resource available */
-       if (!skl_tplg_alloc_pipe_mcps(skl, mconfig))
+       if (!skl_is_pipe_mcps_avail(skl, mconfig))
                return -EBUSY;
 
-       if (!skl_tplg_alloc_pipe_mem(skl, mconfig))
+       if (!skl_is_pipe_mem_avail(skl, mconfig))
                return -ENOMEM;
 
        /*
@@ -526,11 +539,15 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
                src_module = dst_module;
        }
 
+       skl_tplg_alloc_pipe_mem(skl, mconfig);
+       skl_tplg_alloc_pipe_mcps(skl, mconfig);
+
        return 0;
 }
 
 static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
                                struct skl *skl,
+                               struct snd_soc_dapm_widget *src_w,
                                struct skl_module_cfg *src_mconfig)
 {
        struct snd_soc_dapm_path *p;
@@ -547,6 +564,10 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
                dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name);
 
                next_sink = p->sink;
+
+               if (!is_skl_dsp_widget_type(p->sink))
+                       return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig);
+
                /*
                 * here we will check widgets in sink pipelines, so that
                 * can be any widgets type and we are only interested if
@@ -576,7 +597,7 @@ static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w,
        }
 
        if (!sink)
-               return skl_tplg_bind_sinks(next_sink, skl, src_mconfig);
+               return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig);
 
        return 0;
 }
@@ -605,7 +626,7 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w,
         * if sink is not started, start sink pipe first, then start
         * this pipe
         */
-       ret = skl_tplg_bind_sinks(w, skl, src_mconfig);
+       ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig);
        if (ret)
                return ret;
 
@@ -773,10 +794,7 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
                        continue;
                }
 
-               ret = skl_unbind_modules(ctx, src_module, dst_module);
-               if (ret < 0)
-                       return ret;
-
+               skl_unbind_modules(ctx, src_module, dst_module);
                src_module = dst_module;
        }
 
@@ -814,9 +832,6 @@ static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w,
                         * This is a connecter and if path is found that means
                         * unbind between source and sink has not happened yet
                         */
-                       ret = skl_stop_pipe(ctx, sink_mconfig->pipe);
-                       if (ret < 0)
-                               return ret;
                        ret = skl_unbind_modules(ctx, src_mconfig,
                                                        sink_mconfig);
                }
@@ -842,6 +857,12 @@ static int skl_tplg_vmixer_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_PRE_PMU:
                return skl_tplg_mixer_dapm_pre_pmu_event(w, skl);
 
+       case SND_SOC_DAPM_POST_PMU:
+               return skl_tplg_mixer_dapm_post_pmu_event(w, skl);
+
+       case SND_SOC_DAPM_PRE_PMD:
+               return skl_tplg_mixer_dapm_pre_pmd_event(w, skl);
+
        case SND_SOC_DAPM_POST_PMD:
                return skl_tplg_mixer_dapm_post_pmd_event(w, skl);
        }
@@ -916,6 +937,13 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
                skl_get_module_params(skl->skl_sst, (u32 *)bc->params,
                                      bc->max, bc->param_id, mconfig);
 
+       /* decrement size for TLV header */
+       size -= 2 * sizeof(u32);
+
+       /* check size as we don't want to send kernel data */
+       if (size > bc->max)
+               size = bc->max;
+
        if (bc->params) {
                if (copy_to_user(data, &bc->param_id, sizeof(u32)))
                        return -EFAULT;
@@ -1510,6 +1538,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
                                        &skl_tplg_ops, fw, 0);
        if (ret < 0) {
                dev_err(bus->dev, "tplg component load failed%d\n", ret);
+               release_firmware(fw);
                return -EINVAL;
        }
 
index 443a15de94b5fbc3813f126da74e4bb3781f6e15..092705e73db497fb1d75c1c9b45a3c2aaaa34507 100644 (file)
@@ -614,8 +614,6 @@ static int skl_probe(struct pci_dev *pci,
                goto out_unregister;
 
        /*configure PM */
-       pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY);
-       pm_runtime_use_autosuspend(bus->dev);
        pm_runtime_put_noidle(bus->dev);
        pm_runtime_allow(bus->dev);
 
index 15c04e2eae34a010d90abd645c8cdfb3bf07df41..9769676753878b833513d0e863dab776bdaae635 100644 (file)
@@ -9,7 +9,7 @@ config SND_SOC_MEDIATEK
 
 config SND_SOC_MT8173_MAX98090
        tristate "ASoC Audio driver for MT8173 with MAX98090 codec"
-       depends on SND_SOC_MEDIATEK
+       depends on SND_SOC_MEDIATEK && I2C
        select SND_SOC_MAX98090
        help
          This adds ASoC driver for Mediatek MT8173 boards
@@ -19,7 +19,7 @@ config SND_SOC_MT8173_MAX98090
 
 config SND_SOC_MT8173_RT5650_RT5676
        tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs"
-       depends on SND_SOC_MEDIATEK
+       depends on SND_SOC_MEDIATEK && I2C
        select SND_SOC_RT5645
        select SND_SOC_RT5677
        help
index c866ade28ad0a6a0005a9ec97e09c05bfa63a783..a6c7b8d87cd2f15198334840b9013980f87313c0 100644 (file)
@@ -381,9 +381,19 @@ static int mxs_saif_startup(struct snd_pcm_substream *substream,
        __raw_writel(BM_SAIF_CTRL_CLKGATE,
                saif->base + SAIF_CTRL + MXS_CLR_ADDR);
 
+       clk_prepare(saif->clk);
+
        return 0;
 }
 
+static void mxs_saif_shutdown(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *cpu_dai)
+{
+       struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       clk_unprepare(saif->clk);
+}
+
 /*
  * Should only be called when port is inactive.
  * although can be called multiple times by upper layers.
@@ -424,8 +434,6 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       /* prepare clk in hw_param, enable in trigger */
-       clk_prepare(saif->clk);
        if (saif != master_saif) {
                /*
                * Set an initial clock rate for the saif internal logic to work
@@ -611,6 +619,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static const struct snd_soc_dai_ops mxs_saif_dai_ops = {
        .startup = mxs_saif_startup,
+       .shutdown = mxs_saif_shutdown,
        .trigger = mxs_saif_trigger,
        .prepare = mxs_saif_prepare,
        .hw_params = mxs_saif_hw_params,
index 79688aa1941a5c4168c2c52924c79722ce6172c7..4aeb8e1a7160b812a6ab119cfec657b9f55b16cb 100644 (file)
@@ -440,18 +440,18 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 }
 
 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
-               struct snd_soc_pcm_runtime *soc_runtime)
+               struct snd_soc_pcm_runtime *rt)
 {
        struct snd_dma_buffer *buf = &substream->dma_buffer;
        size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
        buf->dev.type = SNDRV_DMA_TYPE_DEV;
-       buf->dev.dev = soc_runtime->dev;
+       buf->dev.dev = rt->platform->dev;
        buf->private_data = NULL;
-       buf->area = dma_alloc_coherent(soc_runtime->dev, size, &buf->addr,
+       buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr,
                        GFP_KERNEL);
        if (!buf->area) {
-               dev_err(soc_runtime->dev, "%s: Could not allocate DMA buffer\n",
+               dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n",
                                __func__);
                return -ENOMEM;
        }
@@ -461,12 +461,12 @@ static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
 }
 
 static void lpass_platform_free_buffer(struct snd_pcm_substream *substream,
-               struct snd_soc_pcm_runtime *soc_runtime)
+               struct snd_soc_pcm_runtime *rt)
 {
        struct snd_dma_buffer *buf = &substream->dma_buffer;
 
        if (buf->area) {
-               dma_free_coherent(soc_runtime->dev, buf->bytes, buf->area,
+               dma_free_coherent(rt->dev, buf->bytes, buf->area,
                                buf->addr);
        }
        buf->area = NULL;
@@ -499,9 +499,6 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 
        snd_soc_pcm_set_drvdata(soc_runtime, data);
 
-       soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-       soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
-
        ret = lpass_platform_alloc_buffer(substream, soc_runtime);
        if (ret)
                return ret;
index 5a2812fa8946071014d54f9c18ae8311be56fe4e..0d37079879002d472c538b69ccc3321c0d7772ad 100644 (file)
@@ -310,7 +310,7 @@ struct dapm_kcontrol_data {
 };
 
 static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
-       struct snd_kcontrol *kcontrol)
+       struct snd_kcontrol *kcontrol, const char *ctrl_name)
 {
        struct dapm_kcontrol_data *data;
        struct soc_mixer_control *mc;
@@ -333,7 +333,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                if (mc->autodisable) {
                        struct snd_soc_dapm_widget template;
 
-                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                       name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
                                         "Autodisable");
                        if (!name) {
                                ret = -ENOMEM;
@@ -371,7 +371,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
                if (e->autodisable) {
                        struct snd_soc_dapm_widget template;
 
-                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                       name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
                                         "Autodisable");
                        if (!name) {
                                ret = -ENOMEM;
@@ -871,7 +871,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
 
                kcontrol->private_free = dapm_kcontrol_free;
 
-               ret = dapm_kcontrol_data_alloc(w, kcontrol);
+               ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
                if (ret) {
                        snd_ctl_free_one(kcontrol);
                        goto exit_free;
index e898b427be7ee34961451b2d8b177848415436ed..1af4f23697a781416f89794050ab41fb631f0171 100644 (file)
@@ -1810,7 +1810,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
-                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
                        continue;
 
                dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
index cc39f63299ef0a1fe58572ab23139f46725f9587..007cf583112154bc56616234d25e92f4e5e8212c 100644 (file)
@@ -2455,7 +2455,6 @@ int snd_usbmidi_create(struct snd_card *card,
        else
                err = snd_usbmidi_create_endpoints(umidi, endpoints);
        if (err < 0) {
-               snd_usbmidi_free(umidi);
                return err;
        }
 
index a75d9ce7d77a73b2c022839825371d07d943dcec..c458d60d50300823e03e39109b715c94bf44cbbf 100644 (file)
@@ -1121,8 +1121,10 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
        switch (chip->usb_id) {
        case USB_ID(0x045E, 0x075D): /* MS Lifecam Cinema  */
        case USB_ID(0x045E, 0x076D): /* MS Lifecam HD-5000 */
+       case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */
        case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
        case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
+       case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
        case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
        case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
        case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */
@@ -1281,7 +1283,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */
        case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
        case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
-       case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/
+       case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */
                if (fp->altsetting == 2)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
@@ -1290,6 +1292,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
        case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
        case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */
        case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */
+       case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */
                if (fp->altsetting == 3)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
index 7cc72a336645124c095c9595782198a4006313a7..bd83149e7be04c3968f9e60d730aca4b1c40b331 100644 (file)
@@ -23,6 +23,9 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
+
+#include <linux/filter.h>
 
 #include "bpf_exp.yacc.h"
 
@@ -79,22 +82,71 @@ extern void yyerror(const char *str);
 "txa"          { return OP_TXA; }
 
 "#"?("len")    { return K_PKT_LEN; }
-"#"?("proto")  { return K_PROTO; }
-"#"?("type")   { return K_TYPE; }
-"#"?("poff")   { return K_POFF; }
-"#"?("ifidx")  { return K_IFIDX; }
-"#"?("nla")    { return K_NLATTR; }
-"#"?("nlan")   { return K_NLATTR_NEST; }
-"#"?("mark")   { return K_MARK; }
-"#"?("queue")  { return K_QUEUE; }
-"#"?("hatype") { return K_HATYPE; }
-"#"?("rxhash") { return K_RXHASH; }
-"#"?("cpu")    { return K_CPU; }
-"#"?("vlan_tci")       { return K_VLAN_TCI; }
-"#"?("vlan_pr")                { return K_VLAN_AVAIL; }
-"#"?("vlan_avail")     { return K_VLAN_AVAIL; }
-"#"?("vlan_tpid")      { return K_VLAN_TPID; }
-"#"?("rand")   { return K_RAND; }
+
+"#"?("proto")  {
+               yylval.number = SKF_AD_PROTOCOL;
+               return extension;
+       }
+"#"?("type")   {
+               yylval.number = SKF_AD_PKTTYPE;
+               return extension;
+       }
+"#"?("poff")   {
+               yylval.number = SKF_AD_PAY_OFFSET;
+               return extension;
+       }
+"#"?("ifidx")  {
+               yylval.number = SKF_AD_IFINDEX;
+               return extension;
+       }
+"#"?("nla")    {
+               yylval.number = SKF_AD_NLATTR;
+               return extension;
+       }
+"#"?("nlan")   {
+               yylval.number = SKF_AD_NLATTR_NEST;
+               return extension;
+       }
+"#"?("mark")   {
+               yylval.number = SKF_AD_MARK;
+               return extension;
+       }
+"#"?("queue")  {
+               yylval.number = SKF_AD_QUEUE;
+               return extension;
+       }
+"#"?("hatype") {
+               yylval.number = SKF_AD_HATYPE;
+               return extension;
+       }
+"#"?("rxhash") {
+               yylval.number = SKF_AD_RXHASH;
+               return extension;
+       }
+"#"?("cpu")    {
+               yylval.number = SKF_AD_CPU;
+               return extension;
+       }
+"#"?("vlan_tci") {
+               yylval.number = SKF_AD_VLAN_TAG;
+               return extension;
+       }
+"#"?("vlan_pr")        {
+               yylval.number = SKF_AD_VLAN_TAG_PRESENT;
+               return extension;
+       }
+"#"?("vlan_avail") {
+               yylval.number = SKF_AD_VLAN_TAG_PRESENT;
+               return extension;
+       }
+"#"?("vlan_tpid") {
+               yylval.number = SKF_AD_VLAN_TPID;
+               return extension;
+       }
+"#"?("rand")   {
+               yylval.number = SKF_AD_RANDOM;
+               return extension;
+       }
 
 ":"            { return ':'; }
 ","            { return ','; }
index e24eea1b0db539d8592247699b4f6697221cbb9d..56ba1de5078474d3cae21c46cc876bfe411014ec 100644 (file)
@@ -35,6 +35,7 @@
 enum jmp_type { JTL, JFL, JKL };
 
 extern FILE *yyin;
+extern int yylineno;
 extern int yylex(void);
 extern void yyerror(const char *str);
 
@@ -55,14 +56,14 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
 %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
 %token OP_LDXI
 
-%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
-%token K_RXHASH K_CPU K_IFIDX K_VLAN_TCI K_VLAN_AVAIL K_VLAN_TPID K_POFF K_RAND
+%token K_PKT_LEN
 
 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
 
-%token number label
+%token extension number label
 
 %type <label> label
+%type <number> extension
 %type <number> number
 
 %%
@@ -125,51 +126,9 @@ ldb
                bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
        | OP_LDB '[' number ']' {
                bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
-       | OP_LDB K_PROTO {
+       | OP_LDB extension {
                bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PROTOCOL); }
-       | OP_LDB K_TYPE {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PKTTYPE); }
-       | OP_LDB K_IFIDX {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_IFINDEX); }
-       | OP_LDB K_NLATTR {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR); }
-       | OP_LDB K_NLATTR_NEST {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
-       | OP_LDB K_MARK {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_MARK); }
-       | OP_LDB K_QUEUE {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_QUEUE); }
-       | OP_LDB K_HATYPE {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_HATYPE); }
-       | OP_LDB K_RXHASH {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RXHASH); }
-       | OP_LDB K_CPU {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_CPU); }
-       | OP_LDB K_VLAN_TCI {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG); }
-       | OP_LDB K_VLAN_AVAIL {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
-       | OP_LDB K_POFF {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
-       | OP_LDB K_RAND {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RANDOM); }
-       | OP_LDB K_VLAN_TPID {
-               bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TPID); }
+                                  SKF_AD_OFF + $2); }
        ;
 
 ldh
@@ -179,51 +138,9 @@ ldh
                bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
        | OP_LDH '[' number ']' {
                bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
-       | OP_LDH K_PROTO {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PROTOCOL); }
-       | OP_LDH K_TYPE {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PKTTYPE); }
-       | OP_LDH K_IFIDX {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_IFINDEX); }
-       | OP_LDH K_NLATTR {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR); }
-       | OP_LDH K_NLATTR_NEST {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
-       | OP_LDH K_MARK {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_MARK); }
-       | OP_LDH K_QUEUE {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_QUEUE); }
-       | OP_LDH K_HATYPE {
+       | OP_LDH extension {
                bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_HATYPE); }
-       | OP_LDH K_RXHASH {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RXHASH); }
-       | OP_LDH K_CPU {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_CPU); }
-       | OP_LDH K_VLAN_TCI {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG); }
-       | OP_LDH K_VLAN_AVAIL {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
-       | OP_LDH K_POFF {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
-       | OP_LDH K_RAND {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RANDOM); }
-       | OP_LDH K_VLAN_TPID {
-               bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TPID); }
+                                  SKF_AD_OFF + $2); }
        ;
 
 ldi
@@ -238,51 +155,9 @@ ld
                bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
        | OP_LD K_PKT_LEN {
                bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
-       | OP_LD K_PROTO {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PROTOCOL); }
-       | OP_LD K_TYPE {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PKTTYPE); }
-       | OP_LD K_IFIDX {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_IFINDEX); }
-       | OP_LD K_NLATTR {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR); }
-       | OP_LD K_NLATTR_NEST {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
-       | OP_LD K_MARK {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_MARK); }
-       | OP_LD K_QUEUE {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_QUEUE); }
-       | OP_LD K_HATYPE {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_HATYPE); }
-       | OP_LD K_RXHASH {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RXHASH); }
-       | OP_LD K_CPU {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_CPU); }
-       | OP_LD K_VLAN_TCI {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG); }
-       | OP_LD K_VLAN_AVAIL {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
-       | OP_LD K_POFF {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
-       | OP_LD K_RAND {
-               bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_RANDOM); }
-       | OP_LD K_VLAN_TPID {
+       | OP_LD extension {
                bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
-                                  SKF_AD_OFF + SKF_AD_VLAN_TPID); }
+                                  SKF_AD_OFF + $2); }
        | OP_LD 'M' '[' number ']' {
                bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
        | OP_LD '[' 'x' '+' number ']' {
@@ -776,5 +651,6 @@ void bpf_asm_compile(FILE *fp, bool cstyle)
 
 void yyerror(const char *str)
 {
+       fprintf(stderr, "error: %s at line %d\n", str, yylineno);
        exit(1);
 }
index 81a2eb77ba7ff56f7558328437fa32e8345051cd..05d815851be19bd40e00672c913a83ad2003175a 100644 (file)
@@ -2068,6 +2068,15 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
                err = -ENOMEM;
                goto err_free_queues;
        }
+
+       /*
+        * Since this thread will not be kept in any rbtree not in a
+        * list, initialize its list node so that at thread__put() the
+        * current thread lifetime assuption is kept and we don't segfault
+        * at list_del_init().
+        */
+       INIT_LIST_HEAD(&pt->unknown_thread->node);
+
        err = thread__set_comm(pt->unknown_thread, "unknown", 0);
        if (err)
                goto err_delete_thread;
index 4f7b0efdde2fa0c0c9f7cab32c6a20809ea47a4f..813d9b272c813b0dd749470f6209aa3a0a0607b4 100644 (file)
@@ -399,6 +399,9 @@ static void tracepoint_error(struct parse_events_error *e, int err,
 {
        char help[BUFSIZ];
 
+       if (!e)
+               return;
+
        /*
         * We get error directly from syscall errno ( > 0),
         * or from encoded pointer's error ( < 0).
index 2be10fb27172727fe15d5f3822ff194a5ad96d95..4ce5c5e18f48cd43777d2eb9c77aea35944440b8 100644 (file)
@@ -686,8 +686,9 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
                pf->fb_ops = NULL;
 #if _ELFUTILS_PREREQ(0, 142)
        } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
-                  pf->cfi != NULL) {
-               if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
+                  (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
+               if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
+                    (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) ||
                    dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
                        pr_warning("Failed to get call frame on 0x%jx\n",
                                   (uintmax_t)pf->addr);
@@ -1015,8 +1016,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
        return DWARF_CB_OK;
 }
 
-/* Find probe points from debuginfo */
-static int debuginfo__find_probes(struct debuginfo *dbg,
+static int debuginfo__find_probe_location(struct debuginfo *dbg,
                                  struct probe_finder *pf)
 {
        struct perf_probe_point *pp = &pf->pev->point;
@@ -1025,27 +1025,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        Dwarf_Die *diep;
        int ret = 0;
 
-#if _ELFUTILS_PREREQ(0, 142)
-       Elf *elf;
-       GElf_Ehdr ehdr;
-       GElf_Shdr shdr;
-
-       /* Get the call frame information from this dwarf */
-       elf = dwarf_getelf(dbg->dbg);
-       if (elf == NULL)
-               return -EINVAL;
-
-       if (gelf_getehdr(elf, &ehdr) == NULL)
-               return -EINVAL;
-
-       if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
-           shdr.sh_type == SHT_PROGBITS) {
-               pf->cfi = dwarf_getcfi_elf(elf);
-       } else {
-               pf->cfi = dwarf_getcfi(dbg->dbg);
-       }
-#endif
-
        off = 0;
        pf->lcache = intlist__new(NULL);
        if (!pf->lcache)
@@ -1108,6 +1087,39 @@ found:
        return ret;
 }
 
+/* Find probe points from debuginfo */
+static int debuginfo__find_probes(struct debuginfo *dbg,
+                                 struct probe_finder *pf)
+{
+       int ret = 0;
+
+#if _ELFUTILS_PREREQ(0, 142)
+       Elf *elf;
+       GElf_Ehdr ehdr;
+       GElf_Shdr shdr;
+
+       if (pf->cfi_eh || pf->cfi_dbg)
+               return debuginfo__find_probe_location(dbg, pf);
+
+       /* Get the call frame information from this dwarf */
+       elf = dwarf_getelf(dbg->dbg);
+       if (elf == NULL)
+               return -EINVAL;
+
+       if (gelf_getehdr(elf, &ehdr) == NULL)
+               return -EINVAL;
+
+       if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
+           shdr.sh_type == SHT_PROGBITS)
+               pf->cfi_eh = dwarf_getcfi_elf(elf);
+
+       pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
+#endif
+
+       ret = debuginfo__find_probe_location(dbg, pf);
+       return ret;
+}
+
 struct local_vars_finder {
        struct probe_finder *pf;
        struct perf_probe_arg *args;
index bed82716e1b44960a0ebc435d0ba1e94ed30730d..0aec7704e39540b51a449cdf395b6a16ab682fba 100644 (file)
@@ -76,7 +76,10 @@ struct probe_finder {
 
        /* For variable searching */
 #if _ELFUTILS_PREREQ(0, 142)
-       Dwarf_CFI               *cfi;           /* Call Frame Information */
+       /* Call Frame Information from .eh_frame */
+       Dwarf_CFI               *cfi_eh;
+       /* Call Frame Information from .debug_frame */
+       Dwarf_CFI               *cfi_dbg;
 #endif
        Dwarf_Op                *fb_ops;        /* Frame base attribute */
        struct perf_probe_arg   *pvar;          /* Current target variable */
index 2b58edccd56f8bf63c0364d17b5ada656f4f582c..afb0c45eba34ba8db7a6cb6d258326f545f7aca1 100644 (file)
@@ -311,6 +311,16 @@ int perf_stat_process_counter(struct perf_stat_config *config,
 
        aggr->val = aggr->ena = aggr->run = 0;
 
+       /*
+        * We calculate counter's data every interval,
+        * and the display code shows ps->res_stats
+        * avg value. We need to zero the stats for
+        * interval mode, otherwise overall avg running
+        * averages will be shown for each interval.
+        */
+       if (config->interval)
+               init_stats(ps->res_stats);
+
        if (counter->per_pkg)
                zero_per_pkg(counter);
 
index 90bd2ea4103232b68e29e167873ff21a3f76b262..b3281dcd4a5d5502af9f66720dfcdccb1aca4d58 100644 (file)
@@ -217,13 +217,16 @@ static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
        return rc;
 }
 
+#define NFIT_TEST_ARS_RECORDS 4
+
 static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
                unsigned int buf_len)
 {
        if (buf_len < sizeof(*nd_cmd))
                return -EINVAL;
 
-       nd_cmd->max_ars_out = 256;
+       nd_cmd->max_ars_out = sizeof(struct nd_cmd_ars_status)
+               + NFIT_TEST_ARS_RECORDS * sizeof(struct nd_ars_record);
        nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
 
        return 0;
@@ -246,7 +249,8 @@ static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
        if (buf_len < sizeof(*nd_cmd))
                return -EINVAL;
 
-       nd_cmd->out_length = 256;
+       nd_cmd->out_length = sizeof(struct nd_cmd_ars_status);
+       /* TODO: emit error records */
        nd_cmd->num_records = 0;
        nd_cmd->address = 0;
        nd_cmd->length = -1ULL;
index 77edcdcc016bbe9e891dbee8ce27c5824caaae63..057278448515a455a17ff2b48af2bf0902c2e7fb 100755 (executable)
@@ -88,7 +88,11 @@ test_delete()
                exit 1
        fi
 
-       rm $file
+       rm $file 2>/dev/null
+       if [ $? -ne 0 ]; then
+               chattr -i $file
+               rm $file
+       fi
 
        if [ -e $file ]; then
                echo "$file couldn't be deleted" >&2
@@ -111,6 +115,7 @@ test_zero_size_delete()
                exit 1
        fi
 
+       chattr -i $file
        printf "$attrs" > $file
 
        if [ -e $file ]; then
@@ -141,7 +146,11 @@ test_valid_filenames()
                        echo "$file could not be created" >&2
                        ret=1
                else
-                       rm $file
+                       rm $file 2>/dev/null
+                       if [ $? -ne 0 ]; then
+                               chattr -i $file
+                               rm $file
+                       fi
                fi
        done
 
@@ -174,7 +183,11 @@ test_invalid_filenames()
 
                if [ -e $file ]; then
                        echo "Creating $file should have failed" >&2
-                       rm $file
+                       rm $file 2>/dev/null
+                       if [ $? -ne 0 ]; then
+                               chattr -i $file
+                               rm $file
+                       fi
                        ret=1
                fi
        done
index 8c0764407b3c349431a6b78ca595e450e2661066..4af74f7330365e668d9e1379f6894f12d974374d 100644 (file)
@@ -1,10 +1,68 @@
+#include <errno.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <linux/fs.h>
+
+static int set_immutable(const char *path, int immutable)
+{
+       unsigned int flags;
+       int fd;
+       int rc;
+       int error;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return fd;
+
+       rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+       if (rc < 0) {
+               error = errno;
+               close(fd);
+               errno = error;
+               return rc;
+       }
+
+       if (immutable)
+               flags |= FS_IMMUTABLE_FL;
+       else
+               flags &= ~FS_IMMUTABLE_FL;
+
+       rc = ioctl(fd, FS_IOC_SETFLAGS, &flags);
+       error = errno;
+       close(fd);
+       errno = error;
+       return rc;
+}
+
+static int get_immutable(const char *path)
+{
+       unsigned int flags;
+       int fd;
+       int rc;
+       int error;
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return fd;
+
+       rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+       if (rc < 0) {
+               error = errno;
+               close(fd);
+               errno = error;
+               return rc;
+       }
+       close(fd);
+       if (flags & FS_IMMUTABLE_FL)
+               return 1;
+       return 0;
+}
 
 int main(int argc, char **argv)
 {
@@ -27,7 +85,7 @@ int main(int argc, char **argv)
        buf[4] = 0;
 
        /* create a test variable */
-       fd = open(path, O_WRONLY | O_CREAT);
+       fd = open(path, O_WRONLY | O_CREAT, 0600);
        if (fd < 0) {
                perror("open(O_WRONLY)");
                return EXIT_FAILURE;
@@ -41,6 +99,18 @@ int main(int argc, char **argv)
 
        close(fd);
 
+       rc = get_immutable(path);
+       if (rc < 0) {
+               perror("ioctl(FS_IOC_GETFLAGS)");
+               return EXIT_FAILURE;
+       } else if (rc) {
+               rc = set_immutable(path, 0);
+               if (rc < 0) {
+                       perror("ioctl(FS_IOC_SETFLAGS)");
+                       return EXIT_FAILURE;
+               }
+       }
+
        fd = open(path, O_RDONLY);
        if (fd < 0) {
                perror("open");
index 773e276ff90b982a2bf24a44388f76b6ccdf4e9e..1e1abe0ad354267507dc0514351d651e19fd1fb6 100644 (file)
@@ -39,28 +39,23 @@ instance_slam() {
 }
 
 instance_slam &
-x=`jobs -l`
-p1=`echo $x | cut -d' ' -f2`
+p1=$!
 echo $p1
 
 instance_slam &
-x=`jobs -l | tail -1`
-p2=`echo $x | cut -d' ' -f2`
+p2=$!
 echo $p2
 
 instance_slam &
-x=`jobs -l | tail -1`
-p3=`echo $x | cut -d' ' -f2`
+p3=$!
 echo $p3
 
 instance_slam &
-x=`jobs -l | tail -1`
-p4=`echo $x | cut -d' ' -f2`
+p4=$!
 echo $p4
 
 instance_slam &
-x=`jobs -l | tail -1`
-p5=`echo $x | cut -d' ' -f2`
+p5=$!
 echo $p5
 
 ls -lR >/dev/null
index 47147b9685140b3bdb5a8e9643966be28a069638..08360060ab146433974776b4a4c2fa868b589135 100644 (file)
@@ -3,6 +3,6 @@
 # No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
 all:
 
-TEST_PROGS := printf.sh
+TEST_PROGS := printf.sh bitmap.sh
 
 include ../lib.mk
diff --git a/tools/testing/selftests/lib/bitmap.sh b/tools/testing/selftests/lib/bitmap.sh
new file mode 100755 (executable)
index 0000000..2da187b
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+# Runs bitmap infrastructure tests using test_bitmap kernel module
+
+if /sbin/modprobe -q test_bitmap; then
+       /sbin/modprobe -q -r test_bitmap
+       echo "bitmap: ok"
+else
+       echo "bitmap: [FAIL]"
+       exit 1
+fi
index 69bca185c471d1dec971f02403ae9fd60851f5bd..ea6064696fe43867d1d1baee35059b276d84817b 100644 (file)
@@ -143,7 +143,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
  * Check if there was a change in the timer state (should we raise or lower
  * the line level to the GIC).
  */
-static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
+static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 
@@ -154,10 +154,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
         * until we call this function from kvm_timer_flush_hwstate.
         */
        if (!vgic_initialized(vcpu->kvm))
-           return;
+               return -ENODEV;
 
        if (kvm_timer_should_fire(vcpu) != timer->irq.level)
                kvm_timer_update_irq(vcpu, !timer->irq.level);
+
+       return 0;
 }
 
 /*
@@ -218,7 +220,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
        bool phys_active;
        int ret;
 
-       kvm_timer_update_state(vcpu);
+       if (kvm_timer_update_state(vcpu))
+               return;
 
        /*
        * If we enter the guest with the virtual input level to the VGIC
index 043032c6a5a4dc6944c5b2bc6277ad6398decd23..00429b392c61cbbd32203877405631f635fc61e3 100644 (file)
@@ -1875,8 +1875,8 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
 static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
 {
        struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
-
-       int sz = (nr_irqs - VGIC_NR_PRIVATE_IRQS) / 8;
+       int nr_longs = BITS_TO_LONGS(nr_irqs - VGIC_NR_PRIVATE_IRQS);
+       int sz = nr_longs * sizeof(unsigned long);
        vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL);
        vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL);
        vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL);
index 35315992245600a418874fd371e641ef336a0a22..db2dd3335c6a6de0c2f0dd9fe89e462d16f5ba81 100644 (file)
@@ -172,7 +172,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
         * do alloc nowait since if we are going to sleep anyway we
         * may as well sleep faulting in page
         */
-       work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT);
+       work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN);
        if (!work)
                return 0;